diff --git a/.env.example b/.env.example new file mode 100755 index 0000000..41a8fae --- /dev/null +++ b/.env.example @@ -0,0 +1,9 @@ +# API Keys (Required to enable respective provider) +ANTHROPIC_API_KEY="your_anthropic_api_key_here" # Required: Format: sk-ant-api03-... +PERPLEXITY_API_KEY="your_perplexity_api_key_here" # Optional: Format: pplx-... +OPENAI_API_KEY="your_openai_api_key_here" # Optional, for OpenAI/OpenRouter models. Format: sk-proj-... +GOOGLE_API_KEY="your_google_api_key_here" # Optional, for Google Gemini models. +MISTRAL_API_KEY="your_mistral_key_here" # Optional, for Mistral AI models. +XAI_API_KEY="YOUR_XAI_KEY_HERE" # Optional, for xAI AI models. +AZURE_OPENAI_API_KEY="your_azure_key_here" # Optional, for Azure OpenAI models (requires endpoint in .taskmaster/config.json). +OLLAMA_API_KEY="your_ollama_api_key_here" # Optional: For remote Ollama servers that require authentication. \ No newline at end of file diff --git a/.eslintrc.json b/.eslintrc.json old mode 100644 new mode 100755 diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 index 39c7e83..ee9ca4e --- a/.gitignore +++ b/.gitignore @@ -40,4 +40,24 @@ yarn-error.log* # Cache .cache/ -.temp/ \ No newline at end of file +.temp/ + +# Added by Task Master AI +logs +dev-debug.log +# Dependency directories +# Environment variables +# Editor directories and files +.idea +.vscode +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? +# OS specific +# Task files +tasks.json +tasks/ +.taskmaster/ +.cursor/ diff --git a/.npmignore b/.npmignore new file mode 100755 index 0000000..1990824 --- /dev/null +++ b/.npmignore @@ -0,0 +1,17 @@ +node_modules/ +src/ +examples/ +docs/ +playwright.config.ts +tsconfig.json +tsup.config.ts +typedoc.json +CONTRIBUTING.md +.gitignore +.github/ +.roo/ +.env +.env.example +.prettierrc +.roomodes + diff --git a/.prettierrc b/.prettierrc old mode 100644 new mode 100755 diff --git a/.roo/mcp.json b/.roo/mcp.json new file mode 100755 index 0000000..7001130 --- /dev/null +++ b/.roo/mcp.json @@ -0,0 +1,3 @@ +{ + "mcpServers": {} +} \ No newline at end of file diff --git a/.roo/rules-architect/architect-rules b/.roo/rules-architect/architect-rules new file mode 100755 index 0000000..c1a1ca1 --- /dev/null +++ b/.roo/rules-architect/architect-rules @@ -0,0 +1,93 @@ +**Core Directives & Agentivity:** +# 1. Adhere strictly to the rules defined below. +# 2. Use tools sequentially, one per message. Adhere strictly to the rules defined below. +# 3. CRITICAL: ALWAYS wait for user confirmation of success after EACH tool use before proceeding. Do not assume success. +# 4. Operate iteratively: Analyze task -> Plan steps -> Execute steps one by one. +# 5. Use tags for *internal* analysis before tool use (context, tool choice, required params). +# 6. **DO NOT DISPLAY XML TOOL TAGS IN THE OUTPUT.** +# 7. **DO NOT DISPLAY YOUR THINKING IN THE OUTPUT.** + +**Architectural Design & Planning Role (Delegated Tasks):** + +Your primary role when activated via `new_task` by the Boomerang orchestrator is to perform specific architectural, design, or planning tasks, focusing on the instructions provided in the delegation message and referencing the relevant `taskmaster-ai` task ID. + +1. **Analyze Delegated Task:** Carefully examine the `message` provided by Boomerang. This message contains the specific task scope, context (including the `taskmaster-ai` task ID), and constraints. +2. **Information Gathering (As Needed):** Use analysis tools to fulfill the task: + * `list_files`: Understand project structure. + * `read_file`: Examine specific code, configuration, or documentation files relevant to the architectural task. + * `list_code_definition_names`: Analyze code structure and relationships. + * `use_mcp_tool` (taskmaster-ai): Use `get_task` or `analyze_project_complexity` *only if explicitly instructed* by Boomerang in the delegation message to gather further context beyond what was provided. +3. **Task Execution (Design & Planning):** Focus *exclusively* on the delegated architectural task, which may involve: + * Designing system architecture, component interactions, or data models. + * Planning implementation steps or identifying necessary subtasks (to be reported back). + * Analyzing technical feasibility, complexity, or potential risks. + * Defining interfaces, APIs, or data contracts. + * Reviewing existing code/architecture against requirements or best practices. +4. **Reporting Completion:** Signal completion using `attempt_completion`. Provide a concise yet thorough summary of the outcome in the `result` parameter. This summary is **crucial** for Boomerang to update `taskmaster-ai`. Include: + * Summary of design decisions, plans created, analysis performed, or subtasks identified. + * Any relevant artifacts produced (e.g., diagrams described, markdown files written - if applicable and instructed). + * Completion status (success, failure, needs review). + * Any significant findings, potential issues, or context gathered relevant to the next steps. +5. **Handling Issues:** + * **Complexity/Review:** If you encounter significant complexity, uncertainty, or issues requiring further review (e.g., needing testing input, deeper debugging analysis), set the status to 'review' within your `attempt_completion` result and clearly state the reason. **Do not delegate directly.** Report back to Boomerang. + * **Failure:** If the task fails (e.g., requirements are contradictory, necessary information unavailable), clearly report the failure and the reason in the `attempt_completion` result. +6. **Taskmaster Interaction:** + * **Primary Responsibility:** Boomerang is primarily responsible for updating Taskmaster (`set_task_status`, `update_task`, `update_subtask`) after receiving your `attempt_completion` result. + * **Direct Updates (Rare):** Only update Taskmaster directly if operating autonomously (not under Boomerang's delegation) or if *explicitly* instructed by Boomerang within the `new_task` message. +7. **Autonomous Operation (Exceptional):** If operating outside of Boomerang's delegation (e.g., direct user request), ensure Taskmaster is initialized before attempting Taskmaster operations (see Taskmaster-AI Strategy below). + +**Context Reporting Strategy:** + +context_reporting: | + + Strategy: + - Focus on providing comprehensive information within the `attempt_completion` `result` parameter. + - Boomerang will use this information to update Taskmaster's `description`, `details`, or log via `update_task`/`update_subtask`. + - My role is to *report* accurately, not *log* directly to Taskmaster unless explicitly instructed or operating autonomously. + + - **Goal:** Ensure the `result` parameter in `attempt_completion` contains all necessary information for Boomerang to understand the outcome and update Taskmaster effectively. + - **Content:** Include summaries of architectural decisions, plans, analysis, identified subtasks, errors encountered, or new context discovered. Structure the `result` clearly. + - **Trigger:** Always provide a detailed `result` upon using `attempt_completion`. + - **Mechanism:** Boomerang receives the `result` and performs the necessary Taskmaster updates. + +**Taskmaster-AI Strategy (for Autonomous Operation):** + +# Only relevant if operating autonomously (not delegated by Boomerang). +taskmaster_strategy: + status_prefix: "Begin autonomous responses with either '[TASKMASTER: ON]' or '[TASKMASTER: OFF]'." + initialization: | + + - **CHECK FOR TASKMASTER (Autonomous Only):** + - Plan: If I need to use Taskmaster tools autonomously, first use `list_files` to check if `tasks/tasks.json` exists. + - If `tasks/tasks.json` is present = set TASKMASTER: ON, else TASKMASTER: OFF. + + *Execute the plan described above only if autonomous Taskmaster interaction is required.* + if_uninitialized: | + 1. **Inform:** "Task Master is not initialized. Autonomous Taskmaster operations cannot proceed." + 2. **Suggest:** "Consider switching to Boomerang mode to initialize and manage the project workflow." + if_ready: | + 1. **Verify & Load:** Optionally fetch tasks using `taskmaster-ai`'s `get_tasks` tool if needed for autonomous context. + 2. **Set Status:** Set status to '[TASKMASTER: ON]'. + 3. **Proceed:** Proceed with autonomous Taskmaster operations. + +**Mode Collaboration & Triggers (Architect Perspective):** + +mode_collaboration: | + # Architect Mode Collaboration (Focus on receiving from Boomerang and reporting back) + - Delegated Task Reception (FROM Boomerang via `new_task`): + * Receive specific architectural/planning task instructions referencing a `taskmaster-ai` ID. + * Analyze requirements, scope, and constraints provided by Boomerang. + - Completion Reporting (TO Boomerang via `attempt_completion`): + * Report design decisions, plans, analysis results, or identified subtasks in the `result`. + * Include completion status (success, failure, review) and context for Boomerang. + * Signal completion of the *specific delegated architectural task*. + +mode_triggers: + # Conditions that might trigger a switch TO Architect mode (typically orchestrated BY Boomerang based on needs identified by other modes or the user) + architect: + - condition: needs_architectural_design # e.g., New feature requires system design + - condition: needs_refactoring_plan # e.g., Code mode identifies complex refactoring needed + - condition: needs_complexity_analysis # e.g., Before breaking down a large feature + - condition: design_clarification_needed # e.g., Implementation details unclear + - condition: pattern_violation_found # e.g., Code deviates significantly from established patterns + - condition: review_architectural_decision # e.g., Boomerang requests review based on 'review' status from another mode \ No newline at end of file diff --git a/.roo/rules-ask/ask-rules b/.roo/rules-ask/ask-rules new file mode 100755 index 0000000..ccacc20 --- /dev/null +++ b/.roo/rules-ask/ask-rules @@ -0,0 +1,89 @@ +**Core Directives & Agentivity:** +# 1. Adhere strictly to the rules defined below. +# 2. Use tools sequentially, one per message. Adhere strictly to the rules defined below. +# 3. CRITICAL: ALWAYS wait for user confirmation of success after EACH tool use before proceeding. Do not assume success. +# 4. Operate iteratively: Analyze task -> Plan steps -> Execute steps one by one. +# 5. Use tags for *internal* analysis before tool use (context, tool choice, required params). +# 6. **DO NOT DISPLAY XML TOOL TAGS IN THE OUTPUT.** +# 7. **DO NOT DISPLAY YOUR THINKING IN THE OUTPUT.** + +**Information Retrieval & Explanation Role (Delegated Tasks):** + +Your primary role when activated via `new_task` by the Boomerang (orchestrator) mode is to act as a specialized technical assistant. Focus *exclusively* on fulfilling the specific instructions provided in the `new_task` message, referencing the relevant `taskmaster-ai` task ID. + +1. **Understand the Request:** Carefully analyze the `message` provided in the `new_task` delegation. This message will contain the specific question, information request, or analysis needed, referencing the `taskmaster-ai` task ID for context. +2. **Information Gathering:** Utilize appropriate tools to gather the necessary information based *only* on the delegation instructions: + * `read_file`: To examine specific file contents. + * `search_files`: To find patterns or specific text across the project. + * `list_code_definition_names`: To understand code structure in relevant directories. + * `use_mcp_tool` (with `taskmaster-ai`): *Only if explicitly instructed* by the Boomerang delegation message to retrieve specific task details (e.g., using `get_task`). +3. **Formulate Response:** Synthesize the gathered information into a clear, concise, and accurate answer or explanation addressing the specific request from the delegation message. +4. **Reporting Completion:** Signal completion using `attempt_completion`. Provide a concise yet thorough summary of the outcome in the `result` parameter. This summary is **crucial** for Boomerang to process and potentially update `taskmaster-ai`. Include: + * The complete answer, explanation, or analysis formulated in the previous step. + * Completion status (success, failure - e.g., if information could not be found). + * Any significant findings or context gathered relevant to the question. + * Cited sources (e.g., file paths, specific task IDs if used) where appropriate. +5. **Strict Scope:** Execute *only* the delegated information-gathering/explanation task. Do not perform code changes, execute unrelated commands, switch modes, or attempt to manage the overall workflow. Your responsibility ends with reporting the answer via `attempt_completion`. + +**Context Reporting Strategy:** + +context_reporting: | + + Strategy: + - Focus on providing comprehensive information (the answer/analysis) within the `attempt_completion` `result` parameter. + - Boomerang will use this information to potentially update Taskmaster's `description`, `details`, or log via `update_task`/`update_subtask`. + - My role is to *report* accurately, not *log* directly to Taskmaster. + + - **Goal:** Ensure the `result` parameter in `attempt_completion` contains the complete and accurate answer/analysis requested by Boomerang. + - **Content:** Include the full answer, explanation, or analysis results. Cite sources if applicable. Structure the `result` clearly. + - **Trigger:** Always provide a detailed `result` upon using `attempt_completion`. + - **Mechanism:** Boomerang receives the `result` and performs any necessary Taskmaster updates or decides the next workflow step. + +**Taskmaster Interaction:** + +* **Primary Responsibility:** Boomerang is primarily responsible for updating Taskmaster (`set_task_status`, `update_task`, `update_subtask`) after receiving your `attempt_completion` result. +* **Direct Use (Rare & Specific):** Only use Taskmaster tools (`use_mcp_tool` with `taskmaster-ai`) if *explicitly instructed* by Boomerang within the `new_task` message, and *only* for retrieving information (e.g., `get_task`). Do not update Taskmaster status or content directly. + +**Taskmaster-AI Strategy (for Autonomous Operation):** + +# Only relevant if operating autonomously (not delegated by Boomerang), which is highly exceptional for Ask mode. +taskmaster_strategy: + status_prefix: "Begin autonomous responses with either '[TASKMASTER: ON]' or '[TASKMASTER: OFF]'." + initialization: | + + - **CHECK FOR TASKMASTER (Autonomous Only):** + - Plan: If I need to use Taskmaster tools autonomously (extremely rare), first use `list_files` to check if `tasks/tasks.json` exists. + - If `tasks/tasks.json` is present = set TASKMASTER: ON, else TASKMASTER: OFF. + + *Execute the plan described above only if autonomous Taskmaster interaction is required.* + if_uninitialized: | + 1. **Inform:** "Task Master is not initialized. Autonomous Taskmaster operations cannot proceed." + 2. **Suggest:** "Consider switching to Boomerang mode to initialize and manage the project workflow." + if_ready: | + 1. **Verify & Load:** Optionally fetch tasks using `taskmaster-ai`'s `get_tasks` tool if needed for autonomous context (again, very rare for Ask). + 2. **Set Status:** Set status to '[TASKMASTER: ON]'. + 3. **Proceed:** Proceed with autonomous operations (likely just answering a direct question without workflow context). + +**Mode Collaboration & Triggers:** + +mode_collaboration: | + # Ask Mode Collaboration: Focuses on receiving tasks from Boomerang and reporting back findings. + - Delegated Task Reception (FROM Boomerang via `new_task`): + * Understand question/analysis request from Boomerang (referencing taskmaster-ai task ID). + * Research information or analyze provided context using appropriate tools (`read_file`, `search_files`, etc.) as instructed. + * Formulate answers/explanations strictly within the subtask scope. + * Use `taskmaster-ai` tools *only* if explicitly instructed in the delegation message for information retrieval. + - Completion Reporting (TO Boomerang via `attempt_completion`): + * Provide the complete answer, explanation, or analysis results in the `result` parameter. + * Report completion status (success/failure) of the information-gathering subtask. + * Cite sources or relevant context found. + +mode_triggers: + # Ask mode does not typically trigger switches TO other modes. + # It receives tasks via `new_task` and reports completion via `attempt_completion`. + # Triggers defining when OTHER modes might switch TO Ask remain relevant for the overall system, + # but Ask mode itself does not initiate these switches. + ask: + - condition: documentation_needed + - condition: implementation_explanation + - condition: pattern_documentation \ No newline at end of file diff --git a/.roo/rules-boomerang/boomerang-rules b/.roo/rules-boomerang/boomerang-rules new file mode 100755 index 0000000..636a090 --- /dev/null +++ b/.roo/rules-boomerang/boomerang-rules @@ -0,0 +1,181 @@ +**Core Directives & Agentivity:** +# 1. Adhere strictly to the rules defined below. +# 2. Use tools sequentially, one per message. Adhere strictly to the rules defined below. +# 3. CRITICAL: ALWAYS wait for user confirmation of success after EACH tool use before proceeding. Do not assume success. +# 4. Operate iteratively: Analyze task -> Plan steps -> Execute steps one by one. +# 5. Use tags for *internal* analysis before tool use (context, tool choice, required params). +# 6. **DO NOT DISPLAY XML TOOL TAGS IN THE OUTPUT.** +# 7. **DO NOT DISPLAY YOUR THINKING IN THE OUTPUT.** + +**Workflow Orchestration Role:** + +Your role is to coordinate complex workflows by delegating tasks to specialized modes, using `taskmaster-ai` as the central hub for task definition, progress tracking, and context management. As an orchestrator, you should always delegate tasks: + +1. **Task Decomposition:** When given a complex task, analyze it and break it down into logical subtasks suitable for delegation. If TASKMASTER IS ON Leverage `taskmaster-ai` (`get_tasks`, `analyze_project_complexity`, `expand_task`) to understand the existing task structure and identify areas needing updates and/or breakdown. +2. **Delegation via `new_task`:** For each subtask identified (or if creating new top-level tasks via `add_task` is needed first), use the `new_task` tool to delegate. + * Choose the most appropriate mode for the subtask's specific goal. + * Provide comprehensive instructions in the `message` parameter, including: + * All necessary context from the parent task (retrieved via `get_task` or `get_tasks` from `taskmaster-ai`) or previous subtasks. + * A clearly defined scope, specifying exactly what the subtask should accomplish. Reference the relevant `taskmaster-ai` task/subtask ID. + * An explicit statement that the subtask should *only* perform the work outlined and not deviate. + * An instruction for the subtask to signal completion using `attempt_completion`, providing a concise yet thorough summary of the outcome in the `result` parameter. This summary is crucial for updating `taskmaster-ai`. + * A statement that these specific instructions supersede any conflicting general instructions the subtask's mode might have. +3. **Progress Tracking & Context Management (using `taskmaster-ai`):** + * Track and manage the progress of all subtasks primarily through `taskmaster-ai`. + * When a subtask completes (signaled via `attempt_completion`), **process its `result` directly**. Update the relevant task/subtask status and details in `taskmaster-ai` using `set_task_status`, `update_task`, or `update_subtask`. Handle failures explicitly (see Result Reception below). + * After processing the result and updating Taskmaster, determine the next steps based on the updated task statuses and dependencies managed by `taskmaster-ai` (use `next_task`). This might involve delegating the next task, asking the user for clarification (`ask_followup_question`), or proceeding to synthesis. + * Use `taskmaster-ai`'s `set_task_status` tool when starting to work on a new task to mark tasks/subtasks as 'in-progress'. If a subtask reports back with a 'review' status via `attempt_completion`, update Taskmaster accordingly, and then decide the next step: delegate to Architect/Test/Debug for specific review, or use `ask_followup_question` to consult the user directly. +4. **User Communication:** Help the user understand the workflow, the status of tasks (using info from `get_tasks` or `get_task`), and how subtasks fit together. Provide clear reasoning for delegation choices. +5. **Synthesis:** When all relevant tasks managed by `taskmaster-ai` for the user's request are 'done' (confirm via `get_tasks`), **perform the final synthesis yourself**. Compile the summary based on the information gathered and logged in Taskmaster throughout the workflow and present it using `attempt_completion`. +6. **Clarification:** Ask clarifying questions (using `ask_followup_question`) when necessary to better understand how to break down or manage tasks within `taskmaster-ai`. + +Use subtasks (`new_task`) to maintain clarity. If a request significantly shifts focus or requires different expertise, create a subtask. + +**Taskmaster-AI Strategy:** + +taskmaster_strategy: + status_prefix: "Begin EVERY response with either '[TASKMASTER: ON]' or '[TASKMASTER: OFF]', indicating if the Task Master project structure (e.g., `tasks/tasks.json`) appears to be set up." + initialization: | + + - **CHECK FOR TASKMASTER:** + - Plan: Use `list_files` to check if `tasks/tasks.json` is PRESENT in the project root, then TASKMASTER has been initialized. + - if `tasks/tasks.json` is present = set TASKMASTER: ON, else TASKMASTER: OFF + + *Execute the plan described above.* + if_uninitialized: | + 1. **Inform & Suggest:** + "It seems Task Master hasn't been initialized in this project yet. TASKMASTER helps manage tasks and context effectively. Would you like me to delegate to the code mode to run the `initialize_project` command for TASKMASTER?" + 2. **Conditional Actions:** + * If the user declines: + + I need to proceed without TASKMASTER functionality. I will inform the user and set the status accordingly. + + a. Inform the user: "Ok, I will proceed without initializing TASKMASTER." + b. Set status to '[TASKMASTER: OFF]'. + c. Attempt to handle the user's request directly if possible. + * If the user agrees: + + I will use `new_task` to delegate project initialization to the `code` mode using the `taskmaster-ai` `initialize_project` tool. I need to ensure the `projectRoot` argument is correctly set. + + a. Use `new_task` with `mode: code`` and instructions to execute the `taskmaster-ai` `initialize_project` tool via `use_mcp_tool`. Provide necessary details like `projectRoot`. Instruct Code mode to report completion via `attempt_completion`. + if_ready: | + + Plan: Use `use_mcp_tool` with `server_name: taskmaster-ai`, `tool_name: get_tasks`, and required arguments (`projectRoot`). This verifies connectivity and loads initial task context. + + 1. **Verify & Load:** Attempt to fetch tasks using `taskmaster-ai`'s `get_tasks` tool. + 2. **Set Status:** Set status to '[TASKMASTER: ON]'. + 3. **Inform User:** "TASKMASTER is ready. I have loaded the current task list." + 4. **Proceed:** Proceed with the user's request, utilizing `taskmaster-ai` tools for task management and context as described in the 'Workflow Orchestration Role'. + +**Mode Collaboration & Triggers:** + +mode_collaboration: | + # Collaboration definitions for how Boomerang orchestrates and interacts. + # Boomerang delegates via `new_task` using taskmaster-ai for task context, + # receives results via `attempt_completion`, processes them, updates taskmaster-ai, and determines the next step. + + 1. Architect Mode Collaboration: # Interaction initiated BY Boomerang + - Delegation via `new_task`: + * Provide clear architectural task scope (referencing taskmaster-ai task ID). + * Request design, structure, planning based on taskmaster context. + - Completion Reporting TO Boomerang: # Receiving results FROM Architect via attempt_completion + * Expect design decisions, artifacts created, completion status (taskmaster-ai task ID). + * Expect context needed for subsequent implementation delegation. + + 2. Test Mode Collaboration: # Interaction initiated BY Boomerang + - Delegation via `new_task`: + * Provide clear testing scope (referencing taskmaster-ai task ID). + * Request test plan development, execution, verification based on taskmaster context. + - Completion Reporting TO Boomerang: # Receiving results FROM Test via attempt_completion + * Expect summary of test results (pass/fail, coverage), completion status (taskmaster-ai task ID). + * Expect details on bugs or validation issues. + + 3. Debug Mode Collaboration: # Interaction initiated BY Boomerang + - Delegation via `new_task`: + * Provide clear debugging scope (referencing taskmaster-ai task ID). + * Request investigation, root cause analysis based on taskmaster context. + - Completion Reporting TO Boomerang: # Receiving results FROM Debug via attempt_completion + * Expect summary of findings (root cause, affected areas), completion status (taskmaster-ai task ID). + * Expect recommended fixes or next diagnostic steps. + + 4. Ask Mode Collaboration: # Interaction initiated BY Boomerang + - Delegation via `new_task`: + * Provide clear question/analysis request (referencing taskmaster-ai task ID). + * Request research, context analysis, explanation based on taskmaster context. + - Completion Reporting TO Boomerang: # Receiving results FROM Ask via attempt_completion + * Expect answers, explanations, analysis results, completion status (taskmaster-ai task ID). + * Expect cited sources or relevant context found. + + 5. Code Mode Collaboration: # Interaction initiated BY Boomerang + - Delegation via `new_task`: + * Provide clear coding requirements (referencing taskmaster-ai task ID). + * Request implementation, fixes, documentation, command execution based on taskmaster context. + - Completion Reporting TO Boomerang: # Receiving results FROM Code via attempt_completion + * Expect outcome of commands/tool usage, summary of code changes/operations, completion status (taskmaster-ai task ID). + * Expect links to commits or relevant code sections if relevant. + + 7. Boomerang Mode Collaboration: # Boomerang's Internal Orchestration Logic + # Boomerang orchestrates via delegation, using taskmaster-ai as the source of truth. + - Task Decomposition & Planning: + * Analyze complex user requests, potentially delegating initial analysis to Architect mode. + * Use `taskmaster-ai` (`get_tasks`, `analyze_project_complexity`) to understand current state. + * Break down into logical, delegate-able subtasks (potentially creating new tasks/subtasks in `taskmaster-ai` via `add_task`, `expand_task` delegated to Code mode if needed). + * Identify appropriate specialized mode for each subtask. + - Delegation via `new_task`: + * Formulate clear instructions referencing `taskmaster-ai` task IDs and context. + * Use `new_task` tool to assign subtasks to chosen modes. + * Track initiated subtasks (implicitly via `taskmaster-ai` status, e.g., setting to 'in-progress'). + - Result Reception & Processing: + * Receive completion reports (`attempt_completion` results) from subtasks. + * **Process the result:** Analyze success/failure and content. + * **Update Taskmaster:** Use `set_task_status`, `update_task`, or `update_subtask` to reflect the outcome (e.g., 'done', 'failed', 'review') and log key details/context from the result. + * **Handle Failures:** If a subtask fails, update status to 'failed', log error details using `update_task`/`update_subtask`, inform the user, and decide next step (e.g., delegate to Debug, ask user). + * **Handle Review Status:** If status is 'review', update Taskmaster, then decide whether to delegate further review (Architect/Test/Debug) or consult the user (`ask_followup_question`). + - Workflow Management & User Interaction: + * **Determine Next Step:** After processing results and updating Taskmaster, use `taskmaster-ai` (`next_task`) to identify the next task based on dependencies and status. + * Communicate workflow plan and progress (based on `taskmaster-ai` data) to the user. + * Ask clarifying questions if needed for decomposition/delegation (`ask_followup_question`). + - Synthesis: + * When `get_tasks` confirms all relevant tasks are 'done', compile the final summary from Taskmaster data. + * Present the overall result using `attempt_completion`. + +mode_triggers: + # Conditions that trigger a switch TO the specified mode via switch_mode. + # Note: Boomerang mode is typically initiated for complex tasks or explicitly chosen by the user, + # and receives results via attempt_completion, not standard switch_mode triggers from other modes. + # These triggers remain the same as they define inter-mode handoffs, not Boomerang's internal logic. + + architect: + - condition: needs_architectural_changes + - condition: needs_further_scoping + - condition: needs_analyze_complexity + - condition: design_clarification_needed + - condition: pattern_violation_found + test: + - condition: tests_need_update + - condition: coverage_check_needed + - condition: feature_ready_for_testing + debug: + - condition: error_investigation_needed + - condition: performance_issue_found + - condition: system_analysis_required + ask: + - condition: documentation_needed + - condition: implementation_explanation + - condition: pattern_documentation + code: + - condition: global_mode_access + - condition: mode_independent_actions + - condition: system_wide_commands + - condition: implementation_needed # From Architect + - condition: code_modification_needed # From Architect + - condition: refactoring_required # From Architect + - condition: test_fixes_required # From Test + - condition: coverage_gaps_found # From Test (Implies coding needed) + - condition: validation_failed # From Test (Implies coding needed) + - condition: fix_implementation_ready # From Debug + - condition: performance_fix_needed # From Debug + - condition: error_pattern_found # From Debug (Implies preventative coding) + - condition: clarification_received # From Ask (Allows coding to proceed) + - condition: code_task_identified # From code + - condition: mcp_result_needs_coding # From code \ No newline at end of file diff --git a/.roo/rules-code/code-rules b/.roo/rules-code/code-rules new file mode 100755 index 0000000..e050cb4 --- /dev/null +++ b/.roo/rules-code/code-rules @@ -0,0 +1,61 @@ +**Core Directives & Agentivity:** +# 1. Adhere strictly to the rules defined below. +# 2. Use tools sequentially, one per message. Adhere strictly to the rules defined below. +# 3. CRITICAL: ALWAYS wait for user confirmation of success after EACH tool use before proceeding. Do not assume success. +# 4. Operate iteratively: Analyze task -> Plan steps -> Execute steps one by one. +# 5. Use tags for *internal* analysis before tool use (context, tool choice, required params). +# 6. **DO NOT DISPLAY XML TOOL TAGS IN THE OUTPUT.** +# 7. **DO NOT DISPLAY YOUR THINKING IN THE OUTPUT.** + +**Execution Role (Delegated Tasks):** + +Your primary role is to **execute** tasks delegated to you by the Boomerang orchestrator mode. Focus on fulfilling the specific instructions provided in the `new_task` message, referencing the relevant `taskmaster-ai` task ID. + +1. **Task Execution:** Implement the requested code changes, run commands, use tools, or perform system operations as specified in the delegated task instructions. +2. **Reporting Completion:** Signal completion using `attempt_completion`. Provide a concise yet thorough summary of the outcome in the `result` parameter. This summary is **crucial** for Boomerang to update `taskmaster-ai`. Include: + * Outcome of commands/tool usage. + * Summary of code changes made or system operations performed. + * Completion status (success, failure, needs review). + * Any significant findings, errors encountered, or context gathered. + * Links to commits or relevant code sections if applicable. +3. **Handling Issues:** + * **Complexity/Review:** If you encounter significant complexity, uncertainty, or issues requiring review (architectural, testing, debugging), set the status to 'review' within your `attempt_completion` result and clearly state the reason. **Do not delegate directly.** Report back to Boomerang. + * **Failure:** If the task fails, clearly report the failure and any relevant error information in the `attempt_completion` result. +4. **Taskmaster Interaction:** + * **Primary Responsibility:** Boomerang is primarily responsible for updating Taskmaster (`set_task_status`, `update_task`, `update_subtask`) after receiving your `attempt_completion` result. + * **Direct Updates (Rare):** Only update Taskmaster directly if operating autonomously (not under Boomerang's delegation) or if *explicitly* instructed by Boomerang within the `new_task` message. +5. **Autonomous Operation (Exceptional):** If operating outside of Boomerang's delegation (e.g., direct user request), ensure Taskmaster is initialized before attempting Taskmaster operations (see Taskmaster-AI Strategy below). + +**Context Reporting Strategy:** + +context_reporting: | + + Strategy: + - Focus on providing comprehensive information within the `attempt_completion` `result` parameter. + - Boomerang will use this information to update Taskmaster's `description`, `details`, or log via `update_task`/`update_subtask`. + - My role is to *report* accurately, not *log* directly to Taskmaster unless explicitly instructed or operating autonomously. + + - **Goal:** Ensure the `result` parameter in `attempt_completion` contains all necessary information for Boomerang to understand the outcome and update Taskmaster effectively. + - **Content:** Include summaries of actions taken, results achieved, errors encountered, decisions made during execution (if relevant to the outcome), and any new context discovered. Structure the `result` clearly. + - **Trigger:** Always provide a detailed `result` upon using `attempt_completion`. + - **Mechanism:** Boomerang receives the `result` and performs the necessary Taskmaster updates. + +**Taskmaster-AI Strategy (for Autonomous Operation):** + +# Only relevant if operating autonomously (not delegated by Boomerang). +taskmaster_strategy: + status_prefix: "Begin autonomous responses with either '[TASKMASTER: ON]' or '[TASKMASTER: OFF]'." + initialization: | + + - **CHECK FOR TASKMASTER (Autonomous Only):** + - Plan: If I need to use Taskmaster tools autonomously, first use `list_files` to check if `tasks/tasks.json` exists. + - If `tasks/tasks.json` is present = set TASKMASTER: ON, else TASKMASTER: OFF. + + *Execute the plan described above only if autonomous Taskmaster interaction is required.* + if_uninitialized: | + 1. **Inform:** "Task Master is not initialized. Autonomous Taskmaster operations cannot proceed." + 2. **Suggest:** "Consider switching to Boomerang mode to initialize and manage the project workflow." + if_ready: | + 1. **Verify & Load:** Optionally fetch tasks using `taskmaster-ai`'s `get_tasks` tool if needed for autonomous context. + 2. **Set Status:** Set status to '[TASKMASTER: ON]'. + 3. **Proceed:** Proceed with autonomous Taskmaster operations. \ No newline at end of file diff --git a/.roo/rules-debug/debug-rules b/.roo/rules-debug/debug-rules new file mode 100755 index 0000000..6affdb6 --- /dev/null +++ b/.roo/rules-debug/debug-rules @@ -0,0 +1,68 @@ +**Core Directives & Agentivity:** +# 1. Adhere strictly to the rules defined below. +# 2. Use tools sequentially, one per message. Adhere strictly to the rules defined below. +# 3. CRITICAL: ALWAYS wait for user confirmation of success after EACH tool use before proceeding. Do not assume success. +# 4. Operate iteratively: Analyze task -> Plan steps -> Execute steps one by one. +# 5. Use tags for *internal* analysis before tool use (context, tool choice, required params). +# 6. **DO NOT DISPLAY XML TOOL TAGS IN THE OUTPUT.** +# 7. **DO NOT DISPLAY YOUR THINKING IN THE OUTPUT.** + +**Execution Role (Delegated Tasks):** + +Your primary role is to **execute diagnostic tasks** delegated to you by the Boomerang orchestrator mode. Focus on fulfilling the specific instructions provided in the `new_task` message, referencing the relevant `taskmaster-ai` task ID. + +1. **Task Execution:** + * Carefully analyze the `message` from Boomerang, noting the `taskmaster-ai` ID, error details, and specific investigation scope. + * Perform the requested diagnostics using appropriate tools: + * `read_file`: Examine specified code or log files. + * `search_files`: Locate relevant code, errors, or patterns. + * `execute_command`: Run specific diagnostic commands *only if explicitly instructed* by Boomerang. + * `taskmaster-ai` `get_task`: Retrieve additional task context *only if explicitly instructed* by Boomerang. + * Focus on identifying the root cause of the issue described in the delegated task. +2. **Reporting Completion:** Signal completion using `attempt_completion`. Provide a concise yet thorough summary of the outcome in the `result` parameter. This summary is **crucial** for Boomerang to update `taskmaster-ai`. Include: + * Summary of diagnostic steps taken and findings (e.g., identified root cause, affected areas). + * Recommended next steps (e.g., specific code changes for Code mode, further tests for Test mode). + * Completion status (success, failure, needs review). Reference the original `taskmaster-ai` task ID. + * Any significant context gathered during the investigation. + * **Crucially:** Execute *only* the delegated diagnostic task. Do *not* attempt to fix code or perform actions outside the scope defined by Boomerang. +3. **Handling Issues:** + * **Needs Review:** If the root cause is unclear, requires architectural input, or needs further specialized testing, set the status to 'review' within your `attempt_completion` result and clearly state the reason. **Do not delegate directly.** Report back to Boomerang. + * **Failure:** If the diagnostic task cannot be completed (e.g., required files missing, commands fail), clearly report the failure and any relevant error information in the `attempt_completion` result. +4. **Taskmaster Interaction:** + * **Primary Responsibility:** Boomerang is primarily responsible for updating Taskmaster (`set_task_status`, `update_task`, `update_subtask`) after receiving your `attempt_completion` result. + * **Direct Updates (Rare):** Only update Taskmaster directly if operating autonomously (not under Boomerang's delegation) or if *explicitly* instructed by Boomerang within the `new_task` message. +5. **Autonomous Operation (Exceptional):** If operating outside of Boomerang's delegation (e.g., direct user request), ensure Taskmaster is initialized before attempting Taskmaster operations (see Taskmaster-AI Strategy below). + +**Context Reporting Strategy:** + +context_reporting: | + + Strategy: + - Focus on providing comprehensive diagnostic findings within the `attempt_completion` `result` parameter. + - Boomerang will use this information to update Taskmaster's `description`, `details`, or log via `update_task`/`update_subtask` and decide the next step (e.g., delegate fix to Code mode). + - My role is to *report* diagnostic findings accurately, not *log* directly to Taskmaster unless explicitly instructed or operating autonomously. + + - **Goal:** Ensure the `result` parameter in `attempt_completion` contains all necessary diagnostic information for Boomerang to understand the issue, update Taskmaster, and plan the next action. + - **Content:** Include summaries of diagnostic actions, root cause analysis, recommended next steps, errors encountered during diagnosis, and any relevant context discovered. Structure the `result` clearly. + - **Trigger:** Always provide a detailed `result` upon using `attempt_completion`. + - **Mechanism:** Boomerang receives the `result` and performs the necessary Taskmaster updates and subsequent delegation. + +**Taskmaster-AI Strategy (for Autonomous Operation):** + +# Only relevant if operating autonomously (not delegated by Boomerang). +taskmaster_strategy: + status_prefix: "Begin autonomous responses with either '[TASKMASTER: ON]' or '[TASKMASTER: OFF]'." + initialization: | + + - **CHECK FOR TASKMASTER (Autonomous Only):** + - Plan: If I need to use Taskmaster tools autonomously, first use `list_files` to check if `tasks/tasks.json` exists. + - If `tasks/tasks.json` is present = set TASKMASTER: ON, else TASKMASTER: OFF. + + *Execute the plan described above only if autonomous Taskmaster interaction is required.* + if_uninitialized: | + 1. **Inform:** "Task Master is not initialized. Autonomous Taskmaster operations cannot proceed." + 2. **Suggest:** "Consider switching to Boomerang mode to initialize and manage the project workflow." + if_ready: | + 1. **Verify & Load:** Optionally fetch tasks using `taskmaster-ai`'s `get_tasks` tool if needed for autonomous context. + 2. **Set Status:** Set status to '[TASKMASTER: ON]'. + 3. **Proceed:** Proceed with autonomous Taskmaster operations. \ No newline at end of file diff --git a/.roo/rules-test/test-rules b/.roo/rules-test/test-rules new file mode 100755 index 0000000..ac13ff2 --- /dev/null +++ b/.roo/rules-test/test-rules @@ -0,0 +1,61 @@ +**Core Directives & Agentivity:** +# 1. Adhere strictly to the rules defined below. +# 2. Use tools sequentially, one per message. Adhere strictly to the rules defined below. +# 3. CRITICAL: ALWAYS wait for user confirmation of success after EACH tool use before proceeding. Do not assume success. +# 4. Operate iteratively: Analyze task -> Plan steps -> Execute steps one by one. +# 5. Use tags for *internal* analysis before tool use (context, tool choice, required params). +# 6. **DO NOT DISPLAY XML TOOL TAGS IN THE OUTPUT.** +# 7. **DO NOT DISPLAY YOUR THINKING IN THE OUTPUT.** + +**Execution Role (Delegated Tasks):** + +Your primary role is to **execute** testing tasks delegated to you by the Boomerang orchestrator mode. Focus on fulfilling the specific instructions provided in the `new_task` message, referencing the relevant `taskmaster-ai` task ID and its associated context (e.g., `testStrategy`). + +1. **Task Execution:** Perform the requested testing activities as specified in the delegated task instructions. This involves understanding the scope, retrieving necessary context (like `testStrategy` from the referenced `taskmaster-ai` task), planning/preparing tests if needed, executing tests using appropriate tools (`execute_command`, `read_file`, etc.), and analyzing results, strictly adhering to the work outlined in the `new_task` message. +2. **Reporting Completion:** Signal completion using `attempt_completion`. Provide a concise yet thorough summary of the outcome in the `result` parameter. This summary is **crucial** for Boomerang to update `taskmaster-ai`. Include: + * Summary of testing activities performed (e.g., tests planned, executed). + * Concise results/outcome (e.g., pass/fail counts, overall status, coverage information if applicable). + * Completion status (success, failure, needs review - e.g., if tests reveal significant issues needing broader attention). + * Any significant findings (e.g., details of bugs, errors, or validation issues found). + * Confirmation that the delegated testing subtask (mentioning the taskmaster-ai ID if provided) is complete. +3. **Handling Issues:** + * **Review Needed:** If tests reveal significant issues requiring architectural review, further debugging, or broader discussion beyond simple bug fixes, set the status to 'review' within your `attempt_completion` result and clearly state the reason (e.g., "Tests failed due to unexpected interaction with Module X, recommend architectural review"). **Do not delegate directly.** Report back to Boomerang. + * **Failure:** If the testing task itself cannot be completed (e.g., unable to run tests due to environment issues), clearly report the failure and any relevant error information in the `attempt_completion` result. +4. **Taskmaster Interaction:** + * **Primary Responsibility:** Boomerang is primarily responsible for updating Taskmaster (`set_task_status`, `update_task`, `update_subtask`) after receiving your `attempt_completion` result. + * **Direct Updates (Rare):** Only update Taskmaster directly if operating autonomously (not under Boomerang's delegation) or if *explicitly* instructed by Boomerang within the `new_task` message. +5. **Autonomous Operation (Exceptional):** If operating outside of Boomerang's delegation (e.g., direct user request), ensure Taskmaster is initialized before attempting Taskmaster operations (see Taskmaster-AI Strategy below). + +**Context Reporting Strategy:** + +context_reporting: | + + Strategy: + - Focus on providing comprehensive information within the `attempt_completion` `result` parameter. + - Boomerang will use this information to update Taskmaster's `description`, `details`, or log via `update_task`/`update_subtask`. + - My role is to *report* accurately, not *log* directly to Taskmaster unless explicitly instructed or operating autonomously. + + - **Goal:** Ensure the `result` parameter in `attempt_completion` contains all necessary information for Boomerang to understand the outcome and update Taskmaster effectively. + - **Content:** Include summaries of actions taken (test execution), results achieved (pass/fail, bugs found), errors encountered during testing, decisions made (if any), and any new context discovered relevant to the testing task. Structure the `result` clearly. + - **Trigger:** Always provide a detailed `result` upon using `attempt_completion`. + - **Mechanism:** Boomerang receives the `result` and performs the necessary Taskmaster updates. + +**Taskmaster-AI Strategy (for Autonomous Operation):** + +# Only relevant if operating autonomously (not delegated by Boomerang). +taskmaster_strategy: + status_prefix: "Begin autonomous responses with either '[TASKMASTER: ON]' or '[TASKMASTER: OFF]'." + initialization: | + + - **CHECK FOR TASKMASTER (Autonomous Only):** + - Plan: If I need to use Taskmaster tools autonomously, first use `list_files` to check if `tasks/tasks.json` exists. + - If `tasks/tasks.json` is present = set TASKMASTER: ON, else TASKMASTER: OFF. + + *Execute the plan described above only if autonomous Taskmaster interaction is required.* + if_uninitialized: | + 1. **Inform:** "Task Master is not initialized. Autonomous Taskmaster operations cannot proceed." + 2. **Suggest:** "Consider switching to Boomerang mode to initialize and manage the project workflow." + if_ready: | + 1. **Verify & Load:** Optionally fetch tasks using `taskmaster-ai`'s `get_tasks` tool if needed for autonomous context. + 2. **Set Status:** Set status to '[TASKMASTER: ON]'. + 3. **Proceed:** Proceed with autonomous Taskmaster operations. \ No newline at end of file diff --git a/.roo/rules/dev_workflow.md b/.roo/rules/dev_workflow.md new file mode 100755 index 0000000..f892fc4 --- /dev/null +++ b/.roo/rules/dev_workflow.md @@ -0,0 +1,239 @@ +--- +description: Guide for using Task Master to manage task-driven development workflows +globs: **/* +alwaysApply: true +--- +# Task Master Development Workflow + +This guide outlines the typical process for using Task Master to manage software development projects. + +## Primary Interaction: MCP Server vs. CLI + +Task Master offers two primary ways to interact: + +1. **MCP Server (Recommended for Integrated Tools)**: + - For AI agents and integrated development environments (like Roo Code), interacting via the **MCP server is the preferred method**. + - The MCP server exposes Task Master functionality through a set of tools (e.g., `get_tasks`, `add_subtask`). + - This method offers better performance, structured data exchange, and richer error handling compared to CLI parsing. + - Refer to [`mcp.md`](mdc:.roo/rules/mcp.md) for details on the MCP architecture and available tools. + - A comprehensive list and description of MCP tools and their corresponding CLI commands can be found in [`taskmaster.md`](mdc:.roo/rules/taskmaster.md). + - **Restart the MCP server** if core logic in `scripts/modules` or MCP tool/direct function definitions change. + +2. **`task-master` CLI (For Users & Fallback)**: + - The global `task-master` command provides a user-friendly interface for direct terminal interaction. + - It can also serve as a fallback if the MCP server is inaccessible or a specific function isn't exposed via MCP. + - Install globally with `npm install -g task-master-ai` or use locally via `npx task-master-ai ...`. + - The CLI commands often mirror the MCP tools (e.g., `task-master list` corresponds to `get_tasks`). + - Refer to [`taskmaster.md`](mdc:.roo/rules/taskmaster.md) for a detailed command reference. + +## Standard Development Workflow Process + +- Start new projects by running `initialize_project` tool / `task-master init` or `parse_prd` / `task-master parse-prd --input=''` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)) to generate initial tasks.json +- Begin coding sessions with `get_tasks` / `task-master list` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)) to see current tasks, status, and IDs +- Determine the next task to work on using `next_task` / `task-master next` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)). +- Analyze task complexity with `analyze_project_complexity` / `task-master analyze-complexity --research` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)) before breaking down tasks +- Review complexity report using `complexity_report` / `task-master complexity-report` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)). +- Select tasks based on dependencies (all marked 'done'), priority level, and ID order +- Clarify tasks by checking task files in tasks/ directory or asking for user input +- View specific task details using `get_task` / `task-master show ` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)) to understand implementation requirements +- Break down complex tasks using `expand_task` / `task-master expand --id= --force --research` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)) with appropriate flags like `--force` (to replace existing subtasks) and `--research`. +- Clear existing subtasks if needed using `clear_subtasks` / `task-master clear-subtasks --id=` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)) before regenerating +- Implement code following task details, dependencies, and project standards +- Verify tasks according to test strategies before marking as complete (See [`tests.md`](mdc:.roo/rules/tests.md)) +- Mark completed tasks with `set_task_status` / `task-master set-status --id= --status=done` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)) +- Update dependent tasks when implementation differs from original plan using `update` / `task-master update --from= --prompt="..."` or `update_task` / `task-master update-task --id= --prompt="..."` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)) +- Add new tasks discovered during implementation using `add_task` / `task-master add-task --prompt="..." --research` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)). +- Add new subtasks as needed using `add_subtask` / `task-master add-subtask --parent= --title="..."` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)). +- Append notes or details to subtasks using `update_subtask` / `task-master update-subtask --id= --prompt='Add implementation notes here...\nMore details...'` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)). +- Generate task files with `generate` / `task-master generate` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)) after updating tasks.json +- Maintain valid dependency structure with `add_dependency`/`remove_dependency` tools or `task-master add-dependency`/`remove-dependency` commands, `validate_dependencies` / `task-master validate-dependencies`, and `fix_dependencies` / `task-master fix-dependencies` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)) when needed +- Respect dependency chains and task priorities when selecting work +- Report progress regularly using `get_tasks` / `task-master list` +- Reorganize tasks as needed using `move_task` / `task-master move --from= --to=` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)) to change task hierarchy or ordering + +## Task Complexity Analysis + +- Run `analyze_project_complexity` / `task-master analyze-complexity --research` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)) for comprehensive analysis +- Review complexity report via `complexity_report` / `task-master complexity-report` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)) for a formatted, readable version. +- Focus on tasks with highest complexity scores (8-10) for detailed breakdown +- Use analysis results to determine appropriate subtask allocation +- Note that reports are automatically used by the `expand_task` tool/command + +## Task Breakdown Process + +- Use `expand_task` / `task-master expand --id=`. It automatically uses the complexity report if found, otherwise generates default number of subtasks. +- Use `--num=` to specify an explicit number of subtasks, overriding defaults or complexity report recommendations. +- Add `--research` flag to leverage Perplexity AI for research-backed expansion. +- Add `--force` flag to clear existing subtasks before generating new ones (default is to append). +- Use `--prompt=""` to provide additional context when needed. +- Review and adjust generated subtasks as necessary. +- Use `expand_all` tool or `task-master expand --all` to expand multiple pending tasks at once, respecting flags like `--force` and `--research`. +- If subtasks need complete replacement (regardless of the `--force` flag on `expand`), clear them first with `clear_subtasks` / `task-master clear-subtasks --id=`. + +## Implementation Drift Handling + +- When implementation differs significantly from planned approach +- When future tasks need modification due to current implementation choices +- When new dependencies or requirements emerge +- Use `update` / `task-master update --from= --prompt='\nUpdate context...' --research` to update multiple future tasks. +- Use `update_task` / `task-master update-task --id= --prompt='\nUpdate context...' --research` to update a single specific task. + +## Task Status Management + +- Use 'pending' for tasks ready to be worked on +- Use 'done' for completed and verified tasks +- Use 'deferred' for postponed tasks +- Add custom status values as needed for project-specific workflows + +## Task Structure Fields + +- **id**: Unique identifier for the task (Example: `1`, `1.1`) +- **title**: Brief, descriptive title (Example: `"Initialize Repo"`) +- **description**: Concise summary of what the task involves (Example: `"Create a new repository, set up initial structure."`) +- **status**: Current state of the task (Example: `"pending"`, `"done"`, `"deferred"`) +- **dependencies**: IDs of prerequisite tasks (Example: `[1, 2.1]`) + - Dependencies are displayed with status indicators (✅ for completed, ⏱️ for pending) + - This helps quickly identify which prerequisite tasks are blocking work +- **priority**: Importance level (Example: `"high"`, `"medium"`, `"low"`) +- **details**: In-depth implementation instructions (Example: `"Use GitHub client ID/secret, handle callback, set session token."`) +- **testStrategy**: Verification approach (Example: `"Deploy and call endpoint to confirm 'Hello World' response."`) +- **subtasks**: List of smaller, more specific tasks (Example: `[{"id": 1, "title": "Configure OAuth", ...}]`) +- Refer to task structure details (previously linked to `tasks.md`). + +## Configuration Management (Updated) + +Taskmaster configuration is managed through two main mechanisms: + +1. **`.taskmaster/config.json` File (Primary):** + * Located in the project root directory. + * Stores most configuration settings: AI model selections (main, research, fallback), parameters (max tokens, temperature), logging level, default subtasks/priority, project name, etc. + * **Managed via `task-master models --setup` command.** Do not edit manually unless you know what you are doing. + * **View/Set specific models via `task-master models` command or `models` MCP tool.** + * Created automatically when you run `task-master models --setup` for the first time. + +2. **Environment Variables (`.env` / `mcp.json`):** + * Used **only** for sensitive API keys and specific endpoint URLs. + * Place API keys (one per provider) in a `.env` file in the project root for CLI usage. + * For MCP/Roo Code integration, configure these keys in the `env` section of `.roo/mcp.json`. + * Available keys/variables: See `assets/env.example` or the Configuration section in the command reference (previously linked to `taskmaster.md`). + +**Important:** Non-API key settings (like model selections, `MAX_TOKENS`, `TASKMASTER_LOG_LEVEL`) are **no longer configured via environment variables**. Use the `task-master models` command (or `--setup` for interactive configuration) or the `models` MCP tool. +**If AI commands FAIL in MCP** verify that the API key for the selected provider is present in the `env` section of `.roo/mcp.json`. +**If AI commands FAIL in CLI** verify that the API key for the selected provider is present in the `.env` file in the root of the project. + +## Determining the Next Task + +- Run `next_task` / `task-master next` to show the next task to work on. +- The command identifies tasks with all dependencies satisfied +- Tasks are prioritized by priority level, dependency count, and ID +- The command shows comprehensive task information including: + - Basic task details and description + - Implementation details + - Subtasks (if they exist) + - Contextual suggested actions +- Recommended before starting any new development work +- Respects your project's dependency structure +- Ensures tasks are completed in the appropriate sequence +- Provides ready-to-use commands for common task actions + +## Viewing Specific Task Details + +- Run `get_task` / `task-master show ` to view a specific task. +- Use dot notation for subtasks: `task-master show 1.2` (shows subtask 2 of task 1) +- Displays comprehensive information similar to the next command, but for a specific task +- For parent tasks, shows all subtasks and their current status +- For subtasks, shows parent task information and relationship +- Provides contextual suggested actions appropriate for the specific task +- Useful for examining task details before implementation or checking status + +## Managing Task Dependencies + +- Use `add_dependency` / `task-master add-dependency --id= --depends-on=` to add a dependency. +- Use `remove_dependency` / `task-master remove-dependency --id= --depends-on=` to remove a dependency. +- The system prevents circular dependencies and duplicate dependency entries +- Dependencies are checked for existence before being added or removed +- Task files are automatically regenerated after dependency changes +- Dependencies are visualized with status indicators in task listings and files + +## Task Reorganization + +- Use `move_task` / `task-master move --from= --to=` to move tasks or subtasks within the hierarchy +- This command supports several use cases: + - Moving a standalone task to become a subtask (e.g., `--from=5 --to=7`) + - Moving a subtask to become a standalone task (e.g., `--from=5.2 --to=7`) + - Moving a subtask to a different parent (e.g., `--from=5.2 --to=7.3`) + - Reordering subtasks within the same parent (e.g., `--from=5.2 --to=5.4`) + - Moving a task to a new, non-existent ID position (e.g., `--from=5 --to=25`) + - Moving multiple tasks at once using comma-separated IDs (e.g., `--from=10,11,12 --to=16,17,18`) +- The system includes validation to prevent data loss: + - Allows moving to non-existent IDs by creating placeholder tasks + - Prevents moving to existing task IDs that have content (to avoid overwriting) + - Validates source tasks exist before attempting to move them +- The system maintains proper parent-child relationships and dependency integrity +- Task files are automatically regenerated after the move operation +- This provides greater flexibility in organizing and refining your task structure as project understanding evolves +- This is especially useful when dealing with potential merge conflicts arising from teams creating tasks on separate branches. Solve these conflicts very easily by moving your tasks and keeping theirs. + +## Iterative Subtask Implementation + +Once a task has been broken down into subtasks using `expand_task` or similar methods, follow this iterative process for implementation: + +1. **Understand the Goal (Preparation):** + * Use `get_task` / `task-master show ` (see [`taskmaster.md`](mdc:.roo/rules/taskmaster.md)) to thoroughly understand the specific goals and requirements of the subtask. + +2. **Initial Exploration & Planning (Iteration 1):** + * This is the first attempt at creating a concrete implementation plan. + * Explore the codebase to identify the precise files, functions, and even specific lines of code that will need modification. + * Determine the intended code changes (diffs) and their locations. + * Gather *all* relevant details from this exploration phase. + +3. **Log the Plan:** + * Run `update_subtask` / `task-master update-subtask --id= --prompt=''`. + * Provide the *complete and detailed* findings from the exploration phase in the prompt. Include file paths, line numbers, proposed diffs, reasoning, and any potential challenges identified. Do not omit details. The goal is to create a rich, timestamped log within the subtask's `details`. + +4. **Verify the Plan:** + * Run `get_task` / `task-master show ` again to confirm that the detailed implementation plan has been successfully appended to the subtask's details. + +5. **Begin Implementation:** + * Set the subtask status using `set_task_status` / `task-master set-status --id= --status=in-progress`. + * Start coding based on the logged plan. + +6. **Refine and Log Progress (Iteration 2+):** + * As implementation progresses, you will encounter challenges, discover nuances, or confirm successful approaches. + * **Before appending new information**: Briefly review the *existing* details logged in the subtask (using `get_task` or recalling from context) to ensure the update adds fresh insights and avoids redundancy. + * **Regularly** use `update_subtask` / `task-master update-subtask --id= --prompt='\n- What worked...\n- What didn't work...'` to append new findings. + * **Crucially, log:** + * What worked ("fundamental truths" discovered). + * What didn't work and why (to avoid repeating mistakes). + * Specific code snippets or configurations that were successful. + * Decisions made, especially if confirmed with user input. + * Any deviations from the initial plan and the reasoning. + * The objective is to continuously enrich the subtask's details, creating a log of the implementation journey that helps the AI (and human developers) learn, adapt, and avoid repeating errors. + +7. **Review & Update Rules (Post-Implementation):** + * Once the implementation for the subtask is functionally complete, review all code changes and the relevant chat history. + * Identify any new or modified code patterns, conventions, or best practices established during the implementation. + * Create new or update existing rules following internal guidelines (previously linked to `cursor_rules.md` and `self_improve.md`). + +8. **Mark Task Complete:** + * After verifying the implementation and updating any necessary rules, mark the subtask as completed: `set_task_status` / `task-master set-status --id= --status=done`. + +9. **Commit Changes (If using Git):** + * Stage the relevant code changes and any updated/new rule files (`git add .`). + * Craft a comprehensive Git commit message summarizing the work done for the subtask, including both code implementation and any rule adjustments. + * Execute the commit command directly in the terminal (e.g., `git commit -m 'feat(module): Implement feature X for subtask \n\n- Details about changes...\n- Updated rule Y for pattern Z'`). + * Consider if a Changeset is needed according to internal versioning guidelines (previously linked to `changeset.md`). If so, run `npm run changeset`, stage the generated file, and amend the commit or create a new one. + +10. **Proceed to Next Subtask:** + * Identify the next subtask (e.g., using `next_task` / `task-master next`). + +## Code Analysis & Refactoring Techniques + +- **Top-Level Function Search**: + - Useful for understanding module structure or planning refactors. + - Use grep/ripgrep to find exported functions/constants: + `rg "export (async function|function|const) \w+"` or similar patterns. + - Can help compare functions between files during migrations or identify potential naming conflicts. + +--- +*This workflow provides a general guideline. Adapt it based on your specific project needs and team practices.* \ No newline at end of file diff --git a/.roo/rules/roo_rules.md b/.roo/rules/roo_rules.md new file mode 100755 index 0000000..cec3c64 --- /dev/null +++ b/.roo/rules/roo_rules.md @@ -0,0 +1,53 @@ +--- +description: Guidelines for creating and maintaining Roo Code rules to ensure consistency and effectiveness. +globs: .roo/rules/*.md +alwaysApply: true +--- + +- **Required Rule Structure:** + ```markdown + --- + description: Clear, one-line description of what the rule enforces + globs: path/to/files/*.ext, other/path/**/* + alwaysApply: boolean + --- + + - **Main Points in Bold** + - Sub-points with details + - Examples and explanations + ``` + +- **File References:** + - Use `[filename](mdc:path/to/file)` ([filename](mdc:filename)) to reference files + - Example: [prisma.md](mdc:.roo/rules/prisma.md) for rule references + - Example: [schema.prisma](mdc:prisma/schema.prisma) for code references + +- **Code Examples:** + - Use language-specific code blocks + ```typescript + // ✅ DO: Show good examples + const goodExample = true; + + // ❌ DON'T: Show anti-patterns + const badExample = false; + ``` + +- **Rule Content Guidelines:** + - Start with high-level overview + - Include specific, actionable requirements + - Show examples of correct implementation + - Reference existing code when possible + - Keep rules DRY by referencing other rules + +- **Rule Maintenance:** + - Update rules when new patterns emerge + - Add examples from actual codebase + - Remove outdated patterns + - Cross-reference related rules + +- **Best Practices:** + - Use bullet points for clarity + - Keep descriptions concise + - Include both DO and DON'T examples + - Reference actual code over theoretical examples + - Use consistent formatting across rules \ No newline at end of file diff --git a/.roo/rules/self_improve.md b/.roo/rules/self_improve.md new file mode 100755 index 0000000..e3af95e --- /dev/null +++ b/.roo/rules/self_improve.md @@ -0,0 +1,72 @@ +--- +description: Guidelines for continuously improving Roo Code rules based on emerging code patterns and best practices. +globs: **/* +alwaysApply: true +--- + +- **Rule Improvement Triggers:** + - New code patterns not covered by existing rules + - Repeated similar implementations across files + - Common error patterns that could be prevented + - New libraries or tools being used consistently + - Emerging best practices in the codebase + +- **Analysis Process:** + - Compare new code with existing rules + - Identify patterns that should be standardized + - Look for references to external documentation + - Check for consistent error handling patterns + - Monitor test patterns and coverage + +- **Rule Updates:** + - **Add New Rules When:** + - A new technology/pattern is used in 3+ files + - Common bugs could be prevented by a rule + - Code reviews repeatedly mention the same feedback + - New security or performance patterns emerge + + - **Modify Existing Rules When:** + - Better examples exist in the codebase + - Additional edge cases are discovered + - Related rules have been updated + - Implementation details have changed + +- **Example Pattern Recognition:** + ```typescript + // If you see repeated patterns like: + const data = await prisma.user.findMany({ + select: { id: true, email: true }, + where: { status: 'ACTIVE' } + }); + + // Consider adding to [prisma.md](mdc:.roo/rules/prisma.md): + // - Standard select fields + // - Common where conditions + // - Performance optimization patterns + ``` + +- **Rule Quality Checks:** + - Rules should be actionable and specific + - Examples should come from actual code + - References should be up to date + - Patterns should be consistently enforced + +- **Continuous Improvement:** + - Monitor code review comments + - Track common development questions + - Update rules after major refactors + - Add links to relevant documentation + - Cross-reference related rules + +- **Rule Deprecation:** + - Mark outdated patterns as deprecated + - Remove rules that no longer apply + - Update references to deprecated rules + - Document migration paths for old patterns + +- **Documentation Updates:** + - Keep examples synchronized with code + - Update references to external docs + - Maintain links between related rules + - Document breaking changes +Follow [cursor_rules.md](mdc:.roo/rules/cursor_rules.md) for proper rule formatting and structure. diff --git a/.roo/rules/taskmaster.md b/.roo/rules/taskmaster.md new file mode 100755 index 0000000..7365374 --- /dev/null +++ b/.roo/rules/taskmaster.md @@ -0,0 +1,407 @@ +--- +description: Comprehensive reference for Taskmaster MCP tools and CLI commands. +globs: **/* +alwaysApply: true +--- +# Taskmaster Tool & Command Reference + +This document provides a detailed reference for interacting with Taskmaster, covering both the recommended MCP tools, suitable for integrations like Roo Code, and the corresponding `task-master` CLI commands, designed for direct user interaction or fallback. + +**Note:** For interacting with Taskmaster programmatically or via integrated tools, using the **MCP tools is strongly recommended** due to better performance, structured data, and error handling. The CLI commands serve as a user-friendly alternative and fallback. + +**Important:** Several MCP tools involve AI processing... The AI-powered tools include `parse_prd`, `analyze_project_complexity`, `update_subtask`, `update_task`, `update`, `expand_all`, `expand_task`, and `add_task`. + +--- + +## Initialization & Setup + +### 1. Initialize Project (`init`) + +* **MCP Tool:** `initialize_project` +* **CLI Command:** `task-master init [options]` +* **Description:** `Set up the basic Taskmaster file structure and configuration in the current directory for a new project.` +* **Key CLI Options:** + * `--name `: `Set the name for your project in Taskmaster's configuration.` + * `--description `: `Provide a brief description for your project.` + * `--version `: `Set the initial version for your project, e.g., '0.1.0'.` + * `-y, --yes`: `Initialize Taskmaster quickly using default settings without interactive prompts.` +* **Usage:** Run this once at the beginning of a new project. +* **MCP Variant Description:** `Set up the basic Taskmaster file structure and configuration in the current directory for a new project by running the 'task-master init' command.` +* **Key MCP Parameters/Options:** + * `projectName`: `Set the name for your project.` (CLI: `--name `) + * `projectDescription`: `Provide a brief description for your project.` (CLI: `--description `) + * `projectVersion`: `Set the initial version for your project, e.g., '0.1.0'.` (CLI: `--version `) + * `authorName`: `Author name.` (CLI: `--author `) + * `skipInstall`: `Skip installing dependencies. Default is false.` (CLI: `--skip-install`) + * `addAliases`: `Add shell aliases tm and taskmaster. Default is false.` (CLI: `--aliases`) + * `yes`: `Skip prompts and use defaults/provided arguments. Default is false.` (CLI: `-y, --yes`) +* **Usage:** Run this once at the beginning of a new project, typically via an integrated tool like Roo Code. Operates on the current working directory of the MCP server. +* **Important:** Once complete, you *MUST* parse a prd in order to generate tasks. There will be no tasks files until then. The next step after initializing should be to create a PRD using the example PRD in .taskmaster/templates/example_prd.txt. + +### 2. Parse PRD (`parse_prd`) + +* **MCP Tool:** `parse_prd` +* **CLI Command:** `task-master parse-prd [file] [options]` +* **Description:** `Parse a Product Requirements Document, PRD, or text file with Taskmaster to automatically generate an initial set of tasks in tasks.json.` +* **Key Parameters/Options:** + * `input`: `Path to your PRD or requirements text file that Taskmaster should parse for tasks.` (CLI: `[file]` positional or `-i, --input `) + * `output`: `Specify where Taskmaster should save the generated 'tasks.json' file. Defaults to '.taskmaster/tasks/tasks.json'.` (CLI: `-o, --output `) + * `numTasks`: `Approximate number of top-level tasks Taskmaster should aim to generate from the document.` (CLI: `-n, --num-tasks `) + * `force`: `Use this to allow Taskmaster to overwrite an existing 'tasks.json' without asking for confirmation.` (CLI: `-f, --force`) +* **Usage:** Useful for bootstrapping a project from an existing requirements document. +* **Notes:** Task Master will strictly adhere to any specific requirements mentioned in the PRD, such as libraries, database schemas, frameworks, tech stacks, etc., while filling in any gaps where the PRD isn't fully specified. Tasks are designed to provide the most direct implementation path while avoiding over-engineering. +* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress. If the user does not have a PRD, suggest discussing their idea and then use the example PRD in `.taskmaster/templates/example_prd.txt` as a template for creating the PRD based on their idea, for use with `parse-prd`. + +--- + +## AI Model Configuration + +### 2. Manage Models (`models`) +* **MCP Tool:** `models` +* **CLI Command:** `task-master models [options]` +* **Description:** `View the current AI model configuration or set specific models for different roles (main, research, fallback). Allows setting custom model IDs for Ollama and OpenRouter.` +* **Key MCP Parameters/Options:** + * `setMain `: `Set the primary model ID for task generation/updates.` (CLI: `--set-main `) + * `setResearch `: `Set the model ID for research-backed operations.` (CLI: `--set-research `) + * `setFallback `: `Set the model ID to use if the primary fails.` (CLI: `--set-fallback `) + * `ollama `: `Indicates the set model ID is a custom Ollama model.` (CLI: `--ollama`) + * `openrouter `: `Indicates the set model ID is a custom OpenRouter model.` (CLI: `--openrouter`) + * `listAvailableModels `: `If true, lists available models not currently assigned to a role.` (CLI: No direct equivalent; CLI lists available automatically) + * `projectRoot `: `Optional. Absolute path to the project root directory.` (CLI: Determined automatically) +* **Key CLI Options:** + * `--set-main `: `Set the primary model.` + * `--set-research `: `Set the research model.` + * `--set-fallback `: `Set the fallback model.` + * `--ollama`: `Specify that the provided model ID is for Ollama (use with --set-*).` + * `--openrouter`: `Specify that the provided model ID is for OpenRouter (use with --set-*). Validates against OpenRouter API.` + * `--setup`: `Run interactive setup to configure models, including custom Ollama/OpenRouter IDs.` +* **Usage (MCP):** Call without set flags to get current config. Use `setMain`, `setResearch`, or `setFallback` with a valid model ID to update the configuration. Use `listAvailableModels: true` to get a list of unassigned models. To set a custom model, provide the model ID and set `ollama: true` or `openrouter: true`. +* **Usage (CLI):** Run without flags to view current configuration and available models. Use set flags to update specific roles. Use `--setup` for guided configuration, including custom models. To set a custom model via flags, use `--set-=` along with either `--ollama` or `--openrouter`. +* **Notes:** Configuration is stored in `.taskmaster/config.json` in the project root. This command/tool modifies that file. Use `listAvailableModels` or `task-master models` to see internally supported models. OpenRouter custom models are validated against their live API. Ollama custom models are not validated live. +* **API note:** API keys for selected AI providers (based on their model) need to exist in the mcp.json file to be accessible in MCP context. The API keys must be present in the local .env file for the CLI to be able to read them. +* **Model costs:** The costs in supported models are expressed in dollars. An input/output value of 3 is $3.00. A value of 0.8 is $0.80. +* **Warning:** DO NOT MANUALLY EDIT THE .taskmaster/config.json FILE. Use the included commands either in the MCP or CLI format as needed. Always prioritize MCP tools when available and use the CLI as a fallback. + +--- + +## Task Listing & Viewing + +### 3. Get Tasks (`get_tasks`) + +* **MCP Tool:** `get_tasks` +* **CLI Command:** `task-master list [options]` +* **Description:** `List your Taskmaster tasks, optionally filtering by status and showing subtasks.` +* **Key Parameters/Options:** + * `status`: `Show only Taskmaster tasks matching this status, e.g., 'pending' or 'done'.` (CLI: `-s, --status `) + * `withSubtasks`: `Include subtasks indented under their parent tasks in the list.` (CLI: `--with-subtasks`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file `) +* **Usage:** Get an overview of the project status, often used at the start of a work session. + +### 4. Get Next Task (`next_task`) + +* **MCP Tool:** `next_task` +* **CLI Command:** `task-master next [options]` +* **Description:** `Ask Taskmaster to show the next available task you can work on, based on status and completed dependencies.` +* **Key Parameters/Options:** + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file `) +* **Usage:** Identify what to work on next according to the plan. + +### 5. Get Task Details (`get_task`) + +* **MCP Tool:** `get_task` +* **CLI Command:** `task-master show [id] [options]` +* **Description:** `Display detailed information for a specific Taskmaster task or subtask by its ID.` +* **Key Parameters/Options:** + * `id`: `Required. The ID of the Taskmaster task, e.g., '15', or subtask, e.g., '15.2', you want to view.` (CLI: `[id]` positional or `-i, --id `) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file `) +* **Usage:** Understand the full details, implementation notes, and test strategy for a specific task before starting work. + +--- + +## Task Creation & Modification + +### 6. Add Task (`add_task`) + +* **MCP Tool:** `add_task` +* **CLI Command:** `task-master add-task [options]` +* **Description:** `Add a new task to Taskmaster by describing it; AI will structure it.` +* **Key Parameters/Options:** + * `prompt`: `Required. Describe the new task you want Taskmaster to create, e.g., "Implement user authentication using JWT".` (CLI: `-p, --prompt `) + * `dependencies`: `Specify the IDs of any Taskmaster tasks that must be completed before this new one can start, e.g., '12,14'.` (CLI: `-d, --dependencies `) + * `priority`: `Set the priority for the new task: 'high', 'medium', or 'low'. Default is 'medium'.` (CLI: `--priority `) + * `research`: `Enable Taskmaster to use the research role for potentially more informed task creation.` (CLI: `-r, --research`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file `) +* **Usage:** Quickly add newly identified tasks during development. +* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress. + +### 7. Add Subtask (`add_subtask`) + +* **MCP Tool:** `add_subtask` +* **CLI Command:** `task-master add-subtask [options]` +* **Description:** `Add a new subtask to a Taskmaster parent task, or convert an existing task into a subtask.` +* **Key Parameters/Options:** + * `id` / `parent`: `Required. The ID of the Taskmaster task that will be the parent.` (MCP: `id`, CLI: `-p, --parent `) + * `taskId`: `Use this if you want to convert an existing top-level Taskmaster task into a subtask of the specified parent.` (CLI: `-i, --task-id `) + * `title`: `Required if not using taskId. The title for the new subtask Taskmaster should create.` (CLI: `-t, --title `) + * `description`: `A brief description for the new subtask.` (CLI: `-d, --description <text>`) + * `details`: `Provide implementation notes or details for the new subtask.` (CLI: `--details <text>`) + * `dependencies`: `Specify IDs of other tasks or subtasks, e.g., '15' or '16.1', that must be done before this new subtask.` (CLI: `--dependencies <ids>`) + * `status`: `Set the initial status for the new subtask. Default is 'pending'.` (CLI: `-s, --status <status>`) + * `skipGenerate`: `Prevent Taskmaster from automatically regenerating markdown task files after adding the subtask.` (CLI: `--skip-generate`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`) +* **Usage:** Break down tasks manually or reorganize existing tasks. + +### 8. Update Tasks (`update`) + +* **MCP Tool:** `update` +* **CLI Command:** `task-master update [options]` +* **Description:** `Update multiple upcoming tasks in Taskmaster based on new context or changes, starting from a specific task ID.` +* **Key Parameters/Options:** + * `from`: `Required. The ID of the first task Taskmaster should update. All tasks with this ID or higher that are not 'done' will be considered.` (CLI: `--from <id>`) + * `prompt`: `Required. Explain the change or new context for Taskmaster to apply to the tasks, e.g., "We are now using React Query instead of Redux Toolkit for data fetching".` (CLI: `-p, --prompt <text>`) + * `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`) +* **Usage:** Handle significant implementation changes or pivots that affect multiple future tasks. Example CLI: `task-master update --from='18' --prompt='Switching to React Query.\nNeed to refactor data fetching...'` +* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress. + +### 9. Update Task (`update_task`) + +* **MCP Tool:** `update_task` +* **CLI Command:** `task-master update-task [options]` +* **Description:** `Modify a specific Taskmaster task or subtask by its ID, incorporating new information or changes.` +* **Key Parameters/Options:** + * `id`: `Required. The specific ID of the Taskmaster task, e.g., '15', or subtask, e.g., '15.2', you want to update.` (CLI: `-i, --id <id>`) + * `prompt`: `Required. Explain the specific changes or provide the new information Taskmaster should incorporate into this task.` (CLI: `-p, --prompt <text>`) + * `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`) +* **Usage:** Refine a specific task based on new understanding or feedback. Example CLI: `task-master update-task --id='15' --prompt='Clarification: Use PostgreSQL instead of MySQL.\nUpdate schema details...'` +* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress. + +### 10. Update Subtask (`update_subtask`) + +* **MCP Tool:** `update_subtask` +* **CLI Command:** `task-master update-subtask [options]` +* **Description:** `Append timestamped notes or details to a specific Taskmaster subtask without overwriting existing content. Intended for iterative implementation logging.` +* **Key Parameters/Options:** + * `id`: `Required. The specific ID of the Taskmaster subtask, e.g., '15.2', you want to add information to.` (CLI: `-i, --id <id>`) + * `prompt`: `Required. Provide the information or notes Taskmaster should append to the subtask's details. Ensure this adds *new* information not already present.` (CLI: `-p, --prompt <text>`) + * `research`: `Enable Taskmaster to use the research role for more informed updates. Requires appropriate API key.` (CLI: `-r, --research`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`) +* **Usage:** Add implementation notes, code snippets, or clarifications to a subtask during development. Before calling, review the subtask's current details to append only fresh insights, helping to build a detailed log of the implementation journey and avoid redundancy. Example CLI: `task-master update-subtask --id='15.2' --prompt='Discovered that the API requires header X.\nImplementation needs adjustment...'` +* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress. + +### 11. Set Task Status (`set_task_status`) + +* **MCP Tool:** `set_task_status` +* **CLI Command:** `task-master set-status [options]` +* **Description:** `Update the status of one or more Taskmaster tasks or subtasks, e.g., 'pending', 'in-progress', 'done'.` +* **Key Parameters/Options:** + * `id`: `Required. The ID(s) of the Taskmaster task(s) or subtask(s), e.g., '15', '15.2', or '16,17.1', to update.` (CLI: `-i, --id <id>`) + * `status`: `Required. The new status to set, e.g., 'done', 'pending', 'in-progress', 'review', 'cancelled'.` (CLI: `-s, --status <status>`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`) +* **Usage:** Mark progress as tasks move through the development cycle. + +### 12. Remove Task (`remove_task`) + +* **MCP Tool:** `remove_task` +* **CLI Command:** `task-master remove-task [options]` +* **Description:** `Permanently remove a task or subtask from the Taskmaster tasks list.` +* **Key Parameters/Options:** + * `id`: `Required. The ID of the Taskmaster task, e.g., '5', or subtask, e.g., '5.2', to permanently remove.` (CLI: `-i, --id <id>`) + * `yes`: `Skip the confirmation prompt and immediately delete the task.` (CLI: `-y, --yes`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`) +* **Usage:** Permanently delete tasks or subtasks that are no longer needed in the project. +* **Notes:** Use with caution as this operation cannot be undone. Consider using 'blocked', 'cancelled', or 'deferred' status instead if you just want to exclude a task from active planning but keep it for reference. The command automatically cleans up dependency references in other tasks. + +--- + +## Task Structure & Breakdown + +### 13. Expand Task (`expand_task`) + +* **MCP Tool:** `expand_task` +* **CLI Command:** `task-master expand [options]` +* **Description:** `Use Taskmaster's AI to break down a complex task into smaller, manageable subtasks. Appends subtasks by default.` +* **Key Parameters/Options:** + * `id`: `The ID of the specific Taskmaster task you want to break down into subtasks.` (CLI: `-i, --id <id>`) + * `num`: `Optional: Suggests how many subtasks Taskmaster should aim to create. Uses complexity analysis/defaults otherwise.` (CLI: `-n, --num <number>`) + * `research`: `Enable Taskmaster to use the research role for more informed subtask generation. Requires appropriate API key.` (CLI: `-r, --research`) + * `prompt`: `Optional: Provide extra context or specific instructions to Taskmaster for generating the subtasks.` (CLI: `-p, --prompt <text>`) + * `force`: `Optional: If true, clear existing subtasks before generating new ones. Default is false (append).` (CLI: `--force`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`) +* **Usage:** Generate a detailed implementation plan for a complex task before starting coding. Automatically uses complexity report recommendations if available and `num` is not specified. +* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress. + +### 14. Expand All Tasks (`expand_all`) + +* **MCP Tool:** `expand_all` +* **CLI Command:** `task-master expand --all [options]` (Note: CLI uses the `expand` command with the `--all` flag) +* **Description:** `Tell Taskmaster to automatically expand all eligible pending/in-progress tasks based on complexity analysis or defaults. Appends subtasks by default.` +* **Key Parameters/Options:** + * `num`: `Optional: Suggests how many subtasks Taskmaster should aim to create per task.` (CLI: `-n, --num <number>`) + * `research`: `Enable research role for more informed subtask generation. Requires appropriate API key.` (CLI: `-r, --research`) + * `prompt`: `Optional: Provide extra context for Taskmaster to apply generally during expansion.` (CLI: `-p, --prompt <text>`) + * `force`: `Optional: If true, clear existing subtasks before generating new ones for each eligible task. Default is false (append).` (CLI: `--force`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`) +* **Usage:** Useful after initial task generation or complexity analysis to break down multiple tasks at once. +* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress. + +### 15. Clear Subtasks (`clear_subtasks`) + +* **MCP Tool:** `clear_subtasks` +* **CLI Command:** `task-master clear-subtasks [options]` +* **Description:** `Remove all subtasks from one or more specified Taskmaster parent tasks.` +* **Key Parameters/Options:** + * `id`: `The ID(s) of the Taskmaster parent task(s) whose subtasks you want to remove, e.g., '15' or '16,18'. Required unless using `all`.) (CLI: `-i, --id <ids>`) + * `all`: `Tell Taskmaster to remove subtasks from all parent tasks.` (CLI: `--all`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`) +* **Usage:** Used before regenerating subtasks with `expand_task` if the previous breakdown needs replacement. + +### 16. Remove Subtask (`remove_subtask`) + +* **MCP Tool:** `remove_subtask` +* **CLI Command:** `task-master remove-subtask [options]` +* **Description:** `Remove a subtask from its Taskmaster parent, optionally converting it into a standalone task.` +* **Key Parameters/Options:** + * `id`: `Required. The ID(s) of the Taskmaster subtask(s) to remove, e.g., '15.2' or '16.1,16.3'.` (CLI: `-i, --id <id>`) + * `convert`: `If used, Taskmaster will turn the subtask into a regular top-level task instead of deleting it.` (CLI: `-c, --convert`) + * `skipGenerate`: `Prevent Taskmaster from automatically regenerating markdown task files after removing the subtask.` (CLI: `--skip-generate`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`) +* **Usage:** Delete unnecessary subtasks or promote a subtask to a top-level task. + +### 17. Move Task (`move_task`) + +* **MCP Tool:** `move_task` +* **CLI Command:** `task-master move [options]` +* **Description:** `Move a task or subtask to a new position within the task hierarchy.` +* **Key Parameters/Options:** + * `from`: `Required. ID of the task/subtask to move (e.g., "5" or "5.2"). Can be comma-separated for multiple tasks.` (CLI: `--from <id>`) + * `to`: `Required. ID of the destination (e.g., "7" or "7.3"). Must match the number of source IDs if comma-separated.` (CLI: `--to <id>`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`) +* **Usage:** Reorganize tasks by moving them within the hierarchy. Supports various scenarios like: + * Moving a task to become a subtask + * Moving a subtask to become a standalone task + * Moving a subtask to a different parent + * Reordering subtasks within the same parent + * Moving a task to a new, non-existent ID (automatically creates placeholders) + * Moving multiple tasks at once with comma-separated IDs +* **Validation Features:** + * Allows moving tasks to non-existent destination IDs (creates placeholder tasks) + * Prevents moving to existing task IDs that already have content (to avoid overwriting) + * Validates that source tasks exist before attempting to move them + * Maintains proper parent-child relationships +* **Example CLI:** `task-master move --from=5.2 --to=7.3` to move subtask 5.2 to become subtask 7.3. +* **Example Multi-Move:** `task-master move --from=10,11,12 --to=16,17,18` to move multiple tasks to new positions. +* **Common Use:** Resolving merge conflicts in tasks.json when multiple team members create tasks on different branches. + +--- + +## Dependency Management + +### 18. Add Dependency (`add_dependency`) + +* **MCP Tool:** `add_dependency` +* **CLI Command:** `task-master add-dependency [options]` +* **Description:** `Define a dependency in Taskmaster, making one task a prerequisite for another.` +* **Key Parameters/Options:** + * `id`: `Required. The ID of the Taskmaster task that will depend on another.` (CLI: `-i, --id <id>`) + * `dependsOn`: `Required. The ID of the Taskmaster task that must be completed first, the prerequisite.` (CLI: `-d, --depends-on <id>`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <path>`) +* **Usage:** Establish the correct order of execution between tasks. + +### 19. Remove Dependency (`remove_dependency`) + +* **MCP Tool:** `remove_dependency` +* **CLI Command:** `task-master remove-dependency [options]` +* **Description:** `Remove a dependency relationship between two Taskmaster tasks.` +* **Key Parameters/Options:** + * `id`: `Required. The ID of the Taskmaster task you want to remove a prerequisite from.` (CLI: `-i, --id <id>`) + * `dependsOn`: `Required. The ID of the Taskmaster task that should no longer be a prerequisite.` (CLI: `-d, --depends-on <id>`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`) +* **Usage:** Update task relationships when the order of execution changes. + +### 20. Validate Dependencies (`validate_dependencies`) + +* **MCP Tool:** `validate_dependencies` +* **CLI Command:** `task-master validate-dependencies [options]` +* **Description:** `Check your Taskmaster tasks for dependency issues (like circular references or links to non-existent tasks) without making changes.` +* **Key Parameters/Options:** + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`) +* **Usage:** Audit the integrity of your task dependencies. + +### 21. Fix Dependencies (`fix_dependencies`) + +* **MCP Tool:** `fix_dependencies` +* **CLI Command:** `task-master fix-dependencies [options]` +* **Description:** `Automatically fix dependency issues (like circular references or links to non-existent tasks) in your Taskmaster tasks.` +* **Key Parameters/Options:** + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`) +* **Usage:** Clean up dependency errors automatically. + +--- + +## Analysis & Reporting + +### 22. Analyze Project Complexity (`analyze_project_complexity`) + +* **MCP Tool:** `analyze_project_complexity` +* **CLI Command:** `task-master analyze-complexity [options]` +* **Description:** `Have Taskmaster analyze your tasks to determine their complexity and suggest which ones need to be broken down further.` +* **Key Parameters/Options:** + * `output`: `Where to save the complexity analysis report (default: '.taskmaster/reports/task-complexity-report.json').` (CLI: `-o, --output <file>`) + * `threshold`: `The minimum complexity score (1-10) that should trigger a recommendation to expand a task.` (CLI: `-t, --threshold <number>`) + * `research`: `Enable research role for more accurate complexity analysis. Requires appropriate API key.` (CLI: `-r, --research`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`) +* **Usage:** Used before breaking down tasks to identify which ones need the most attention. +* **Important:** This MCP tool makes AI calls and can take up to a minute to complete. Please inform users to hang tight while the operation is in progress. + +### 23. View Complexity Report (`complexity_report`) + +* **MCP Tool:** `complexity_report` +* **CLI Command:** `task-master complexity-report [options]` +* **Description:** `Display the task complexity analysis report in a readable format.` +* **Key Parameters/Options:** + * `file`: `Path to the complexity report (default: '.taskmaster/reports/task-complexity-report.json').` (CLI: `-f, --file <file>`) +* **Usage:** Review and understand the complexity analysis results after running analyze-complexity. + +--- + +## File Management + +### 24. Generate Task Files (`generate`) + +* **MCP Tool:** `generate` +* **CLI Command:** `task-master generate [options]` +* **Description:** `Create or update individual Markdown files for each task based on your tasks.json.` +* **Key Parameters/Options:** + * `output`: `The directory where Taskmaster should save the task files (default: in a 'tasks' directory).` (CLI: `-o, --output <directory>`) + * `file`: `Path to your Taskmaster 'tasks.json' file. Default relies on auto-detection.` (CLI: `-f, --file <file>`) +* **Usage:** Run this after making changes to tasks.json to keep individual task files up to date. + +--- + +## Environment Variables Configuration (Updated) + +Taskmaster primarily uses the **`.taskmaster/config.json`** file (in project root) for configuration (models, parameters, logging level, etc.), managed via `task-master models --setup`. + +Environment variables are used **only** for sensitive API keys related to AI providers and specific overrides like the Ollama base URL: + +* **API Keys (Required for corresponding provider):** + * `ANTHROPIC_API_KEY` + * `PERPLEXITY_API_KEY` + * `OPENAI_API_KEY` + * `GOOGLE_API_KEY` + * `MISTRAL_API_KEY` + * `AZURE_OPENAI_API_KEY` (Requires `AZURE_OPENAI_ENDPOINT` too) + * `OPENROUTER_API_KEY` + * `XAI_API_KEY` + * `OLLAMA_API_KEY` (Requires `OLLAMA_BASE_URL` too) +* **Endpoints (Optional/Provider Specific inside .taskmaster/config.json):** + * `AZURE_OPENAI_ENDPOINT` + * `OLLAMA_BASE_URL` (Default: `http://localhost:11434/api`) + +**Set API keys** in your **`.env`** file in the project root (for CLI use) or within the `env` section of your **`.roo/mcp.json`** file (for MCP/Roo Code integration). All other settings (model choice, max tokens, temperature, log level, custom endpoints) are managed in `.taskmaster/config.json` via `task-master models` command or `models` MCP tool. + +--- + +For details on how these commands fit into the development process, see the [Development Workflow Guide](mdc:.roo/rules/dev_workflow.md). diff --git a/.roomodes b/.roomodes new file mode 100755 index 0000000..289a422 --- /dev/null +++ b/.roomodes @@ -0,0 +1,63 @@ +{ + "customModes": [ + { + "slug": "boomerang", + "name": "Boomerang", + "roleDefinition": "You are Roo, a strategic workflow orchestrator who coordinates complex tasks by delegating them to appropriate specialized modes. You have a comprehensive understanding of each mode's capabilities and limitations, also your own, and with the information given by the user and other modes in shared context you are enabled to effectively break down complex problems into discrete tasks that can be solved by different specialists using the `taskmaster-ai` system for task and context management.", + "customInstructions": "Your role is to coordinate complex workflows by delegating tasks to specialized modes, using `taskmaster-ai` as the central hub for task definition, progress tracking, and context management. \nAs an orchestrator, you should:\nn1. When given a complex task, use contextual information (which gets updated frequently) to break it down into logical subtasks that can be delegated to appropriate specialized modes.\nn2. For each subtask, use the `new_task` tool to delegate. Choose the most appropriate mode for the subtask's specific goal and provide comprehensive instructions in the `message` parameter. \nThese instructions must include:\n* All necessary context from the parent task or previous subtasks required to complete the work.\n* A clearly defined scope, specifying exactly what the subtask should accomplish.\n* An explicit statement that the subtask should *only* perform the work outlined in these instructions and not deviate.\n* An instruction for the subtask to signal completion by using the `attempt_completion` tool, providing a thorough summary of the outcome in the `result` parameter, keeping in mind that this summary will be the source of truth used to further relay this information to other tasks and for you to keep track of what was completed on this project.\nn3. Track and manage the progress of all subtasks. When a subtask is completed, acknowledge its results and determine the next steps.\nn4. Help the user understand how the different subtasks fit together in the overall workflow. Provide clear reasoning about why you're delegating specific tasks to specific modes.\nn5. Ask clarifying questions when necessary to better understand how to break down complex tasks effectively. If it seems complex delegate to architect to accomplish that \nn6. Use subtasks to maintain clarity. If a request significantly shifts focus or requires a different expertise (mode), consider creating a subtask rather than overloading the current one.", + "groups": [ + "read", + "edit", + "browser", + "command", + "mcp" + ] + }, + { + "slug": "architect", + "name": "Architect", + "roleDefinition": "You are Roo, an expert technical leader operating in Architect mode. When activated via a delegated task, your focus is solely on analyzing requirements, designing system architecture, planning implementation steps, and performing technical analysis as specified in the task message. You utilize analysis tools as needed and report your findings and designs back using `attempt_completion`. You do not deviate from the delegated task scope.", + "customInstructions": "1. Do some information gathering (for example using read_file or search_files) to get more context about the task.\n\n2. You should also ask the user clarifying questions to get a better understanding of the task.\n\n3. Once you've gained more context about the user's request, you should create a detailed plan for how to accomplish the task. Include Mermaid diagrams if they help make your plan clearer.\n\n4. Ask the user if they are pleased with this plan, or if they would like to make any changes. Think of this as a brainstorming session where you can discuss the task and plan the best way to accomplish it.\n\n5. Once the user confirms the plan, ask them if they'd like you to write it to a markdown file.\n\n6. Use the switch_mode tool to request that the user switch to another mode to implement the solution.", + "groups": [ + "read", + ["edit", { "fileRegex": "\\.md$", "description": "Markdown files only" }], + "command", + "mcp" + ] + }, + { + "slug": "ask", + "name": "Ask", + "roleDefinition": "You are Roo, a knowledgeable technical assistant.\nWhen activated by another mode via a delegated task, your focus is to research, analyze, and provide clear, concise answers or explanations based *only* on the specific information requested in the delegation message. Use available tools for information gathering and report your findings back using `attempt_completion`.", + "customInstructions": "You can analyze code, explain concepts, and access external resources. Make sure to answer the user's questions and don't rush to switch to implementing code. Include Mermaid diagrams if they help make your response clearer.", + "groups": [ + "read", + "browser", + "mcp" + ] + }, + { + "slug": "debug", + "name": "Debug", + "roleDefinition": "You are Roo, an expert software debugger specializing in systematic problem diagnosis and resolution. When activated by another mode, your task is to meticulously analyze the provided debugging request (potentially referencing Taskmaster tasks, logs, or metrics), use diagnostic tools as instructed to investigate the issue, identify the root cause, and report your findings and recommended next steps back via `attempt_completion`. You focus solely on diagnostics within the scope defined by the delegated task.", + "customInstructions": "Reflect on 5-7 different possible sources of the problem, distill those down to 1-2 most likely sources, and then add logs to validate your assumptions. Explicitly ask the user to confirm the diagnosis before fixing the problem.", + "groups": [ + "read", + "edit", + "command", + "mcp" + ] + }, + { + "slug": "test", + "name": "Test", + "roleDefinition": "You are Roo, an expert software tester. Your primary focus is executing testing tasks delegated to you by other modes.\nAnalyze the provided scope and context (often referencing a Taskmaster task ID and its `testStrategy`), develop test plans if needed, execute tests diligently, and report comprehensive results (pass/fail, bugs, coverage) back using `attempt_completion`. You operate strictly within the delegated task's boundaries.", + "customInstructions": "Focus on the `testStrategy` defined in the Taskmaster task. Develop and execute test plans accordingly. Report results clearly, including pass/fail status, bug details, and coverage information.", + "groups": [ + "read", + "command", + "mcp" + ] + } + ] +} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100755 index 0000000..8f8644c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,27 @@ +# Contributing to ART + +First off, thank you for considering contributing to the Agentic Runtime Framework (ART)! Your help is invaluable in making this project better. + +We welcome contributions in various forms, including: +- Reporting bugs and issues +- Suggesting new features or enhancements +- Improving documentation +- Submitting pull requests for bug fixes or new features + +## How to Contribute + +*(This is a placeholder. A more detailed guide on our development process, coding standards, and pull request guidelines will be added here soon.)* + +### Reporting Issues + +If you encounter a bug or have a suggestion, please open an issue on our GitHub repository. Provide as much detail as possible to help us understand and address the problem quickly. + +### Submitting Pull Requests + +1. Fork the repository and create your branch from `main`. +2. If you've added code that should be tested, add tests. +3. Ensure the test suite passes. +4. Make sure your code lints. +5. Issue that pull request! + +We look forward to your contributions! diff --git a/Docs/API/README.md b/Docs/API/README.md deleted file mode 100644 index 89425eb..0000000 --- a/Docs/API/README.md +++ /dev/null @@ -1,107 +0,0 @@ -**ART Framework API Reference** - -*** - -# ART Framework API Reference - -## Enumerations - -- [ErrorCode](enumerations/ErrorCode.md) -- [LogLevel](enumerations/LogLevel.md) -- [MessageRole](enumerations/MessageRole.md) -- [ModelCapability](enumerations/ModelCapability.md) -- [ObservationType](enumerations/ObservationType.md) - -## Classes - -- [AdapterInstantiationError](classes/AdapterInstantiationError.md) -- [AnthropicAdapter](classes/AnthropicAdapter.md) -- [ApiQueueTimeoutError](classes/ApiQueueTimeoutError.md) -- [ARTError](classes/ARTError.md) -- [CalculatorTool](classes/CalculatorTool.md) -- [DeepSeekAdapter](classes/DeepSeekAdapter.md) -- [GeminiAdapter](classes/GeminiAdapter.md) -- [IndexedDBStorageAdapter](classes/IndexedDBStorageAdapter.md) -- [InMemoryStorageAdapter](classes/InMemoryStorageAdapter.md) -- [LLMStreamSocket](classes/LLMStreamSocket.md) -- [LocalInstanceBusyError](classes/LocalInstanceBusyError.md) -- [LocalProviderConflictError](classes/LocalProviderConflictError.md) -- [Logger](classes/Logger.md) -- [OllamaAdapter](classes/OllamaAdapter.md) -- [OpenAIAdapter](classes/OpenAIAdapter.md) -- [OpenRouterAdapter](classes/OpenRouterAdapter.md) -- [PESAgent](classes/PESAgent.md) -- [TypedSocket](classes/TypedSocket.md) -- [UnknownProviderError](classes/UnknownProviderError.md) - -## Interfaces - -- [AgentFinalResponse](interfaces/AgentFinalResponse.md) -- [AgentOptions](interfaces/AgentOptions.md) -- [AgentProps](interfaces/AgentProps.md) -- [AgentState](interfaces/AgentState.md) -- [ArtInstance](interfaces/ArtInstance.md) -- [ArtInstanceConfig](interfaces/ArtInstanceConfig.md) -- [ArtStandardMessage](interfaces/ArtStandardMessage.md) -- [AvailableProviderEntry](interfaces/AvailableProviderEntry.md) -- [CallOptions](interfaces/CallOptions.md) -- [ConversationManager](interfaces/ConversationManager.md) -- [ConversationMessage](interfaces/ConversationMessage.md) -- [ConversationSocket](interfaces/ConversationSocket.md) -- [ExecutionContext](interfaces/ExecutionContext.md) -- [ExecutionMetadata](interfaces/ExecutionMetadata.md) -- [FilterOptions](interfaces/FilterOptions.md) -- [IAgentCore](interfaces/IAgentCore.md) -- [IConversationRepository](interfaces/IConversationRepository.md) -- [IObservationRepository](interfaces/IObservationRepository.md) -- [IProviderManager](interfaces/IProviderManager.md) -- [IStateRepository](interfaces/IStateRepository.md) -- [IToolExecutor](interfaces/IToolExecutor.md) -- [ITypedSocket](interfaces/ITypedSocket.md) -- [JsonObjectSchema](interfaces/JsonObjectSchema.md) -- [LLMMetadata](interfaces/LLMMetadata.md) -- [ManagedAdapterAccessor](interfaces/ManagedAdapterAccessor.md) -- [MessageOptions](interfaces/MessageOptions.md) -- [Observation](interfaces/Observation.md) -- [ObservationFilter](interfaces/ObservationFilter.md) -- [ObservationManager](interfaces/ObservationManager.md) -- [ObservationSocket](interfaces/ObservationSocket.md) -- [OllamaAdapterOptions](interfaces/OllamaAdapterOptions.md) -- [OutputParser](interfaces/OutputParser.md) -- [ParsedToolCall](interfaces/ParsedToolCall.md) -- [PromptContext](interfaces/PromptContext.md) -- [PromptManager](interfaces/PromptManager.md) -- [ProviderAdapter](interfaces/ProviderAdapter.md) -- [ProviderManagerConfig](interfaces/ProviderManagerConfig.md) -- [ReasoningEngine](interfaces/ReasoningEngine.md) -- [RuntimeProviderConfig](interfaces/RuntimeProviderConfig.md) -- [StateManager](interfaces/StateManager.md) -- [StorageAdapter](interfaces/StorageAdapter.md) -- [StreamEvent](interfaces/StreamEvent.md) -- [ThreadConfig](interfaces/ThreadConfig.md) -- [ThreadContext](interfaces/ThreadContext.md) -- [ToolRegistry](interfaces/ToolRegistry.md) -- [ToolResult](interfaces/ToolResult.md) -- [ToolSchema](interfaces/ToolSchema.md) -- [ToolSystem](interfaces/ToolSystem.md) -- [UISystem](interfaces/UISystem.md) - -## Type Aliases - -- [ArtStandardMessageRole](type-aliases/ArtStandardMessageRole.md) -- [ArtStandardPrompt](type-aliases/ArtStandardPrompt.md) -- [~~FormattedPrompt~~](type-aliases/FormattedPrompt.md) -- [JsonSchema](type-aliases/JsonSchema.md) -- [StateSavingStrategy](type-aliases/StateSavingStrategy.md) -- [UnsubscribeFunction](type-aliases/UnsubscribeFunction.md) - -## Variables - -- [ArtStandardMessageSchema](variables/ArtStandardMessageSchema.md) -- [ArtStandardPromptSchema](variables/ArtStandardPromptSchema.md) -- [VERSION](variables/VERSION.md) - -## Functions - -- [createArtInstance](functions/createArtInstance.md) -- [generateUUID](functions/generateUUID.md) diff --git a/Docs/API/classes/ARTError.md b/Docs/API/classes/ARTError.md deleted file mode 100644 index 450e91e..0000000 --- a/Docs/API/classes/ARTError.md +++ /dev/null @@ -1,83 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ARTError - -# Class: ARTError - -Defined in: [src/errors.ts:53](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L53) - -Custom error class for ART framework specific errors. - -## Extends - -- `Error` - -## Extended by - -- [`UnknownProviderError`](UnknownProviderError.md) -- [`LocalProviderConflictError`](LocalProviderConflictError.md) -- [`LocalInstanceBusyError`](LocalInstanceBusyError.md) -- [`ApiQueueTimeoutError`](ApiQueueTimeoutError.md) -- [`AdapterInstantiationError`](AdapterInstantiationError.md) - -## Constructors - -### Constructor - -> **new ARTError**(`message`, `code`, `originalError`?): `ARTError` - -Defined in: [src/errors.ts:57](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L57) - -#### Parameters - -##### message - -`string` - -##### code - -[`ErrorCode`](../enumerations/ErrorCode.md) - -##### originalError? - -`Error` - -#### Returns - -`ARTError` - -#### Overrides - -`Error.constructor` - -## Properties - -### code - -> `readonly` **code**: [`ErrorCode`](../enumerations/ErrorCode.md) - -Defined in: [src/errors.ts:54](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L54) - -*** - -### originalError? - -> `readonly` `optional` **originalError**: `Error` - -Defined in: [src/errors.ts:55](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L55) - -## Methods - -### toString() - -> **toString**(): `string` - -Defined in: [src/errors.ts:69](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L69) - -Returns a string representation of an object. - -#### Returns - -`string` diff --git a/Docs/API/classes/AdapterInstantiationError.md b/Docs/API/classes/AdapterInstantiationError.md deleted file mode 100644 index e903f01..0000000 --- a/Docs/API/classes/AdapterInstantiationError.md +++ /dev/null @@ -1,83 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / AdapterInstantiationError - -# Class: AdapterInstantiationError - -Defined in: [src/errors.ts:107](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L107) - -Custom error class for ART framework specific errors. - -## Extends - -- [`ARTError`](ARTError.md) - -## Constructors - -### Constructor - -> **new AdapterInstantiationError**(`providerName`, `originalError`): `AdapterInstantiationError` - -Defined in: [src/errors.ts:108](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L108) - -#### Parameters - -##### providerName - -`string` - -##### originalError - -`Error` - -#### Returns - -`AdapterInstantiationError` - -#### Overrides - -[`ARTError`](ARTError.md).[`constructor`](ARTError.md#constructor) - -## Properties - -### code - -> `readonly` **code**: [`ErrorCode`](../enumerations/ErrorCode.md) - -Defined in: [src/errors.ts:54](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L54) - -#### Inherited from - -[`ARTError`](ARTError.md).[`code`](ARTError.md#code) - -*** - -### originalError? - -> `readonly` `optional` **originalError**: `Error` - -Defined in: [src/errors.ts:55](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L55) - -#### Inherited from - -[`ARTError`](ARTError.md).[`originalError`](ARTError.md#originalerror) - -## Methods - -### toString() - -> **toString**(): `string` - -Defined in: [src/errors.ts:69](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L69) - -Returns a string representation of an object. - -#### Returns - -`string` - -#### Inherited from - -[`ARTError`](ARTError.md).[`toString`](ARTError.md#tostring) diff --git a/Docs/API/classes/AnthropicAdapter.md b/Docs/API/classes/AnthropicAdapter.md deleted file mode 100644 index 1574df0..0000000 --- a/Docs/API/classes/AnthropicAdapter.md +++ /dev/null @@ -1,97 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / AnthropicAdapter - -# Class: AnthropicAdapter - -Defined in: [src/adapters/reasoning/anthropic.ts:55](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/anthropic.ts#L55) - -Implements the `ProviderAdapter` interface for interacting with Anthropic's -Messages API (Claude models) using the official SDK. - -Handles formatting requests, parsing responses, streaming, and tool use. - -## Implements - -## Implements - -- [`ProviderAdapter`](../interfaces/ProviderAdapter.md) - -## Constructors - -### Constructor - -> **new AnthropicAdapter**(`options`): `AnthropicAdapter` - -Defined in: [src/adapters/reasoning/anthropic.ts:67](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/anthropic.ts#L67) - -Creates an instance of the AnthropicAdapter. - -#### Parameters - -##### options - -`AnthropicAdapterOptions` - -Configuration options including the API key and optional model/baseURL/defaults. - -#### Returns - -`AnthropicAdapter` - -#### Throws - -If the API key is missing. - -## Properties - -### providerName - -> `readonly` **providerName**: `"anthropic"` = `'anthropic'` - -Defined in: [src/adapters/reasoning/anthropic.ts:56](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/anthropic.ts#L56) - -The unique identifier name for this provider (e.g., 'openai', 'anthropic'). - -#### Implementation of - -[`ProviderAdapter`](../interfaces/ProviderAdapter.md).[`providerName`](../interfaces/ProviderAdapter.md#providername) - -## Methods - -### call() - -> **call**(`prompt`, `options`): `Promise`\<`AsyncIterable`\<[`StreamEvent`](../interfaces/StreamEvent.md), `any`, `any`\>\> - -Defined in: [src/adapters/reasoning/anthropic.ts:94](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/anthropic.ts#L94) - -Sends a request to the Anthropic Messages API. -Translates `ArtStandardPrompt` to the Anthropic format and handles streaming and tool use. - -#### Parameters - -##### prompt - -[`ArtStandardPrompt`](../type-aliases/ArtStandardPrompt.md) - -The standardized prompt messages. - -##### options - -[`CallOptions`](../interfaces/CallOptions.md) - -Call options, including `threadId`, `traceId`, `stream`, `callContext`, - `model` (override), `tools` (available tools), and Anthropic-specific - generation parameters from `providerConfig.adapterOptions`. - -#### Returns - -`Promise`\<`AsyncIterable`\<[`StreamEvent`](../interfaces/StreamEvent.md), `any`, `any`\>\> - -A promise resolving to an AsyncIterable of StreamEvent objects. - -#### Implementation of - -[`ProviderAdapter`](../interfaces/ProviderAdapter.md).[`call`](../interfaces/ProviderAdapter.md#call) diff --git a/Docs/API/classes/ApiQueueTimeoutError.md b/Docs/API/classes/ApiQueueTimeoutError.md deleted file mode 100644 index 72462e3..0000000 --- a/Docs/API/classes/ApiQueueTimeoutError.md +++ /dev/null @@ -1,79 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ApiQueueTimeoutError - -# Class: ApiQueueTimeoutError - -Defined in: [src/errors.ts:100](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L100) - -Custom error class for ART framework specific errors. - -## Extends - -- [`ARTError`](ARTError.md) - -## Constructors - -### Constructor - -> **new ApiQueueTimeoutError**(`providerName`): `ApiQueueTimeoutError` - -Defined in: [src/errors.ts:101](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L101) - -#### Parameters - -##### providerName - -`string` - -#### Returns - -`ApiQueueTimeoutError` - -#### Overrides - -[`ARTError`](ARTError.md).[`constructor`](ARTError.md#constructor) - -## Properties - -### code - -> `readonly` **code**: [`ErrorCode`](../enumerations/ErrorCode.md) - -Defined in: [src/errors.ts:54](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L54) - -#### Inherited from - -[`ARTError`](ARTError.md).[`code`](ARTError.md#code) - -*** - -### originalError? - -> `readonly` `optional` **originalError**: `Error` - -Defined in: [src/errors.ts:55](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L55) - -#### Inherited from - -[`ARTError`](ARTError.md).[`originalError`](ARTError.md#originalerror) - -## Methods - -### toString() - -> **toString**(): `string` - -Defined in: [src/errors.ts:69](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L69) - -Returns a string representation of an object. - -#### Returns - -`string` - -#### Inherited from - -[`ARTError`](ARTError.md).[`toString`](ARTError.md#tostring) diff --git a/Docs/API/classes/CalculatorTool.md b/Docs/API/classes/CalculatorTool.md deleted file mode 100644 index 0d676f4..0000000 --- a/Docs/API/classes/CalculatorTool.md +++ /dev/null @@ -1,92 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / CalculatorTool - -# Class: CalculatorTool - -Defined in: [src/tools/CalculatorTool.ts:62](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/tools/CalculatorTool.ts#L62) - -An ART Framework tool that safely evaluates mathematical expressions using the mathjs library. -It supports basic arithmetic, variables via a scope, complex numbers, and a predefined list of safe functions. - -## Implements - -## Implements - -- [`IToolExecutor`](../interfaces/IToolExecutor.md) - -## Constructors - -### Constructor - -> **new CalculatorTool**(): `CalculatorTool` - -#### Returns - -`CalculatorTool` - -## Properties - -### schema - -> `readonly` **schema**: [`ToolSchema`](../interfaces/ToolSchema.md) - -Defined in: [src/tools/CalculatorTool.ts:75](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/tools/CalculatorTool.ts#L75) - -The schema definition for the CalculatorTool, conforming to the `ToolSchema` interface. -It defines the tool's name, description, input parameters (expression and optional scope), -and provides examples for the LLM. - -#### Implementation of - -[`IToolExecutor`](../interfaces/IToolExecutor.md).[`schema`](../interfaces/IToolExecutor.md#schema) - -*** - -### toolName - -> `readonly` `static` **toolName**: `"calculator"` = `"calculator"` - -Defined in: [src/tools/CalculatorTool.ts:64](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/tools/CalculatorTool.ts#L64) - -The unique name identifier for this tool. - -## Methods - -### execute() - -> **execute**(`input`, `context`): `Promise`\<[`ToolResult`](../interfaces/ToolResult.md)\> - -Defined in: [src/tools/CalculatorTool.ts:128](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/tools/CalculatorTool.ts#L128) - -Executes the calculator tool by evaluating the provided mathematical expression. -It uses a restricted scope including only allowed mathjs functions and any variables -passed in the `input.scope`. Handles basic number and complex number results. - -#### Parameters - -##### input - -`any` - -An object containing the `expression` (string) and optional `scope` (object). Must match `inputSchema`. - -##### context - -[`ExecutionContext`](../interfaces/ExecutionContext.md) - -The execution context containing `threadId`, `traceId`, etc. - -#### Returns - -`Promise`\<[`ToolResult`](../interfaces/ToolResult.md)\> - -A promise resolving to a `ToolResult` object. - On success, `status` is 'success' and `output` is `{ result: number | string }`. - On failure, `status` is 'error' and `error` contains the error message. - -#### Implementation of - -[`IToolExecutor`](../interfaces/IToolExecutor.md).[`execute`](../interfaces/IToolExecutor.md#execute) diff --git a/Docs/API/classes/DeepSeekAdapter.md b/Docs/API/classes/DeepSeekAdapter.md deleted file mode 100644 index 6592c93..0000000 --- a/Docs/API/classes/DeepSeekAdapter.md +++ /dev/null @@ -1,98 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / DeepSeekAdapter - -# Class: DeepSeekAdapter - -Defined in: [src/adapters/reasoning/deepseek.ts:87](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/deepseek.ts#L87) - -Implements the `ProviderAdapter` interface for interacting with the DeepSeek API, -which uses an OpenAI-compatible Chat Completions endpoint. - -Handles formatting requests and parsing responses for DeepSeek models. -Note: Streaming is **not yet implemented** for this adapter. Calls requesting streaming will yield an error and end. - -## Implements - -## Implements - -- [`ProviderAdapter`](../interfaces/ProviderAdapter.md) - -## Constructors - -### Constructor - -> **new DeepSeekAdapter**(`options`): `DeepSeekAdapter` - -Defined in: [src/adapters/reasoning/deepseek.ts:98](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/deepseek.ts#L98) - -Creates an instance of the DeepSeekAdapter. - -#### Parameters - -##### options - -`DeepSeekAdapterOptions` - -Configuration options including the API key and optional model/baseURL overrides. - -#### Returns - -`DeepSeekAdapter` - -#### Throws - -If the API key is missing. - -## Properties - -### providerName - -> `readonly` **providerName**: `"deepseek"` = `'deepseek'` - -Defined in: [src/adapters/reasoning/deepseek.ts:88](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/deepseek.ts#L88) - -The unique identifier name for this provider (e.g., 'openai', 'anthropic'). - -#### Implementation of - -[`ProviderAdapter`](../interfaces/ProviderAdapter.md).[`providerName`](../interfaces/ProviderAdapter.md#providername) - -## Methods - -### call() - -> **call**(`prompt`, `options`): `Promise`\<`AsyncIterable`\<[`StreamEvent`](../interfaces/StreamEvent.md), `any`, `any`\>\> - -Defined in: [src/adapters/reasoning/deepseek.ts:118](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/deepseek.ts#L118) - -Sends a request to the DeepSeek Chat Completions API endpoint. -Translates `ArtStandardPrompt` to the OpenAI-compatible format. - -**Note:** Streaming is **not yet implemented**. - -#### Parameters - -##### prompt - -[`ArtStandardPrompt`](../type-aliases/ArtStandardPrompt.md) - -The standardized prompt messages. - -##### options - -[`CallOptions`](../interfaces/CallOptions.md) - -Call options, including `threadId`, `traceId`, `stream`, and any OpenAI-compatible generation parameters. - -#### Returns - -`Promise`\<`AsyncIterable`\<[`StreamEvent`](../interfaces/StreamEvent.md), `any`, `any`\>\> - -A promise resolving to an AsyncIterable of StreamEvent objects. If streaming is requested, it yields an error event and ends. - -#### Implementation of - -[`ProviderAdapter`](../interfaces/ProviderAdapter.md).[`call`](../interfaces/ProviderAdapter.md#call) diff --git a/Docs/API/classes/GeminiAdapter.md b/Docs/API/classes/GeminiAdapter.md deleted file mode 100644 index 214a26f..0000000 --- a/Docs/API/classes/GeminiAdapter.md +++ /dev/null @@ -1,106 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / GeminiAdapter - -# Class: GeminiAdapter - -Defined in: [src/adapters/reasoning/gemini.ts:33](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/gemini.ts#L33) - -Base interface for LLM Provider Adapters, extending the core ReasoningEngine. -Implementations will handle provider-specific API calls, authentication, etc. - -## Implements - -- [`ProviderAdapter`](../interfaces/ProviderAdapter.md) - -## Constructors - -### Constructor - -> **new GeminiAdapter**(`options`): `GeminiAdapter` - -Defined in: [src/adapters/reasoning/gemini.ts:44](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/gemini.ts#L44) - -Creates an instance of GeminiAdapter. - -#### Parameters - -##### options - -`GeminiAdapterOptions` - -Configuration options for the adapter. - -#### Returns - -`GeminiAdapter` - -#### Throws - -If `apiKey` is missing in the options. - -## Properties - -### providerName - -> `readonly` **providerName**: `"gemini"` = `'gemini'` - -Defined in: [src/adapters/reasoning/gemini.ts:34](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/gemini.ts#L34) - -The unique identifier name for this provider (e.g., 'openai', 'anthropic'). - -#### Implementation of - -[`ProviderAdapter`](../interfaces/ProviderAdapter.md).[`providerName`](../interfaces/ProviderAdapter.md#providername) - -## Methods - -### call() - -> **call**(`prompt`, `options`): `Promise`\<`AsyncIterable`\<[`StreamEvent`](../interfaces/StreamEvent.md), `any`, `any`\>\> - -Defined in: [src/adapters/reasoning/gemini.ts:78](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/gemini.ts#L78) - -Makes a call to the configured Gemini model. -Translates the `ArtStandardPrompt` into the Gemini API format, sends the request -using the `@google/genai` SDK, and yields `StreamEvent` objects representing -the response (tokens, metadata, errors, end signal). - -Handles both streaming and non-streaming requests based on `options.stream`. - -#### Parameters - -##### prompt - -[`ArtStandardPrompt`](../type-aliases/ArtStandardPrompt.md) - -The standardized prompt messages. - -##### options - -[`CallOptions`](../interfaces/CallOptions.md) - -Options for the LLM call, including streaming preference, model override, and execution context. - -#### Returns - -`Promise`\<`AsyncIterable`\<[`StreamEvent`](../interfaces/StreamEvent.md), `any`, `any`\>\> - -An async iterable that yields `StreamEvent` objects. - - `TOKEN`: Contains a chunk of the response text. `tokenType` indicates if it's part of agent thought or final synthesis. - - `METADATA`: Contains information like stop reason, token counts, and timing, yielded once at the end. - - `ERROR`: Contains any error encountered during translation, SDK call, or response processing. - - `END`: Signals the completion of the stream. - -#### See - - - - - - - - - - -#### Implementation of - -[`ProviderAdapter`](../interfaces/ProviderAdapter.md).[`call`](../interfaces/ProviderAdapter.md#call) diff --git a/Docs/API/classes/InMemoryStorageAdapter.md b/Docs/API/classes/InMemoryStorageAdapter.md deleted file mode 100644 index 668c6b2..0000000 --- a/Docs/API/classes/InMemoryStorageAdapter.md +++ /dev/null @@ -1,283 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / InMemoryStorageAdapter - -# Class: InMemoryStorageAdapter - -Defined in: [src/adapters/storage/inMemory.ts:16](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/inMemory.ts#L16) - -An in-memory implementation of the `StorageAdapter` interface. -Stores all data in JavaScript Maps within the current process memory. -Data is **not persisted** and will be lost when the application session ends. - -Useful for: -- Unit and integration testing (fast, no external dependencies). -- Simple demos or examples where persistence isn't needed. -- Ephemeral agents that don't require long-term memory. - -## Implements - -## Implements - -- [`StorageAdapter`](../interfaces/StorageAdapter.md) - -## Constructors - -### Constructor - -> **new InMemoryStorageAdapter**(): `InMemoryStorageAdapter` - -#### Returns - -`InMemoryStorageAdapter` - -## Methods - -### clearAll() - -> **clearAll**(): `Promise`\<`void`\> - -Defined in: [src/adapters/storage/inMemory.ts:139](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/inMemory.ts#L139) - -Removes all collections and all data stored within the adapter instance. -Use with caution, especially during testing. - -#### Returns - -`Promise`\<`void`\> - -A promise that resolves when all data is cleared. - -#### Implementation of - -[`StorageAdapter`](../interfaces/StorageAdapter.md).[`clearAll`](../interfaces/StorageAdapter.md#clearall) - -*** - -### clearCollection() - -> **clearCollection**(`collection`): `Promise`\<`void`\> - -Defined in: [src/adapters/storage/inMemory.ts:129](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/inMemory.ts#L129) - -Removes all items from a specific collection within the in-memory store. - -#### Parameters - -##### collection - -`string` - -The name of the collection to clear. - -#### Returns - -`Promise`\<`void`\> - -A promise that resolves when the collection is cleared. - -#### Implementation of - -[`StorageAdapter`](../interfaces/StorageAdapter.md).[`clearCollection`](../interfaces/StorageAdapter.md#clearcollection) - -*** - -### delete() - -> **delete**(`collection`, `id`): `Promise`\<`void`\> - -Defined in: [src/adapters/storage/inMemory.ts:72](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/inMemory.ts#L72) - -Deletes an item from a specified collection using its ID. -If the collection or item does not exist, the operation completes silently. - -#### Parameters - -##### collection - -`string` - -The name of the collection. - -##### id - -`string` - -The unique ID of the item to delete. - -#### Returns - -`Promise`\<`void`\> - -A promise that resolves when the deletion attempt is complete. - -#### Implementation of - -[`StorageAdapter`](../interfaces/StorageAdapter.md).[`delete`](../interfaces/StorageAdapter.md#delete) - -*** - -### get() - -> **get**\<`T`\>(`collection`, `id`): `Promise`\<`null` \| `T`\> - -Defined in: [src/adapters/storage/inMemory.ts:36](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/inMemory.ts#L36) - -Retrieves a single item (as a deep copy) from a specified collection by its ID. - -#### Type Parameters - -##### T - -`T` - -The expected type of the retrieved item. - -#### Parameters - -##### collection - -`string` - -The name of the data collection (e.g., 'messages', 'observations'). - -##### id - -`string` - -The unique ID of the item within the collection. - -#### Returns - -`Promise`\<`null` \| `T`\> - -A promise resolving to a deep copy of the item if found, or `null` otherwise. - -#### Implementation of - -[`StorageAdapter`](../interfaces/StorageAdapter.md).[`get`](../interfaces/StorageAdapter.md#get) - -*** - -### init() - -> **init**(`_config`?): `Promise`\<`void`\> - -Defined in: [src/adapters/storage/inMemory.ts:24](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/inMemory.ts#L24) - -Initializes the adapter. This is a no-op for the in-memory adapter. - -#### Parameters - -##### \_config? - -`any` - -Optional configuration (ignored by this adapter). - -#### Returns - -`Promise`\<`void`\> - -A promise that resolves immediately. - -#### Implementation of - -[`StorageAdapter`](../interfaces/StorageAdapter.md).[`init`](../interfaces/StorageAdapter.md#init) - -*** - -### query() - -> **query**\<`T`\>(`collection`, `filterOptions`): `Promise`\<`T`[]\> - -Defined in: [src/adapters/storage/inMemory.ts:91](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/inMemory.ts#L91) - -Queries items within a collection based on provided filter options. -**Note:** This in-memory implementation provides basic filtering capabilities: -- Supports exact matches on top-level properties specified in `filterOptions.filter`. -- Supports limiting results via `filterOptions.limit`. -- **Does not** support sorting (`filterOptions.sort`), skipping (`filterOptions.skip`), complex operators (like $gt, $in), or nested property filtering. - -#### Type Parameters - -##### T - -`T` - -The expected type of the items in the collection. - -#### Parameters - -##### collection - -`string` - -The name of the collection to query. - -##### filterOptions - -[`FilterOptions`](../interfaces/FilterOptions.md) - -Options for filtering and limiting the results. - -#### Returns - -`Promise`\<`T`[]\> - -A promise resolving to an array of deep copies of the matching items. - -#### Implementation of - -[`StorageAdapter`](../interfaces/StorageAdapter.md).[`query`](../interfaces/StorageAdapter.md#query) - -*** - -### set() - -> **set**\<`T`\>(`collection`, `id`, `data`): `Promise`\<`void`\> - -Defined in: [src/adapters/storage/inMemory.ts:55](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/inMemory.ts#L55) - -Saves (creates or updates) an item in a specified collection. -Stores a deep copy of the provided data to prevent external mutations. - -#### Type Parameters - -##### T - -`T` - -The type of the data being saved. - -#### Parameters - -##### collection - -`string` - -The name of the collection. - -##### id - -`string` - -The unique ID for the item. - -##### data - -`T` - -The data object to save. - -#### Returns - -`Promise`\<`void`\> - -A promise that resolves when the data is saved in memory. - -#### Implementation of - -[`StorageAdapter`](../interfaces/StorageAdapter.md).[`set`](../interfaces/StorageAdapter.md#set) diff --git a/Docs/API/classes/IndexedDBStorageAdapter.md b/Docs/API/classes/IndexedDBStorageAdapter.md deleted file mode 100644 index cccdd2a..0000000 --- a/Docs/API/classes/IndexedDBStorageAdapter.md +++ /dev/null @@ -1,317 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / IndexedDBStorageAdapter - -# Class: IndexedDBStorageAdapter - -Defined in: [src/adapters/storage/indexedDB.ts:33](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/indexedDB.ts#L33) - -An implementation of the `StorageAdapter` interface that uses the browser's -IndexedDB API for persistent, client-side storage. - -This adapter is suitable for web applications where conversation history, -agent state, and observations need to persist across sessions. - -**Important:** The `init()` method *must* be called and awaited before performing -any other database operations (get, set, delete, query). - -## Implements - -## Implements - -- [`StorageAdapter`](../interfaces/StorageAdapter.md) - -## Constructors - -### Constructor - -> **new IndexedDBStorageAdapter**(`config`): `IndexedDBStorageAdapter` - -Defined in: [src/adapters/storage/indexedDB.ts:45](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/indexedDB.ts#L45) - -Creates an instance of IndexedDBStorageAdapter. -Note: The database connection is not opened until `init()` is called. - -#### Parameters - -##### config - -`IndexedDBConfig` - -Configuration options including database name, version, and required object stores. - -#### Returns - -`IndexedDBStorageAdapter` - -## Methods - -### clearAll() - -> **clearAll**(): `Promise`\<`void`\> - -Defined in: [src/adapters/storage/indexedDB.ts:421](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/indexedDB.ts#L421) - -Removes all data from all object stores managed by this adapter instance within the database. -Use with caution as this is destructive. - -#### Returns - -`Promise`\<`void`\> - -A promise that resolves when all specified object stores have been cleared. - -#### Throws - -If the database is not initialized or a transaction error occurs. - -#### Implementation of - -[`StorageAdapter`](../interfaces/StorageAdapter.md).[`clearAll`](../interfaces/StorageAdapter.md#clearall) - -*** - -### clearCollection() - -> **clearCollection**(`collection`): `Promise`\<`void`\> - -Defined in: [src/adapters/storage/indexedDB.ts:388](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/indexedDB.ts#L388) - -Removes all items from a specific object store (collection). - -#### Parameters - -##### collection - -`string` - -The name of the object store to clear. - -#### Returns - -`Promise`\<`void`\> - -A promise that resolves when the collection is successfully cleared. - -#### Throws - -If the database is not initialized, the store doesn't exist, or a database error occurs. - -#### Implementation of - -[`StorageAdapter`](../interfaces/StorageAdapter.md).[`clearCollection`](../interfaces/StorageAdapter.md#clearcollection) - -*** - -### delete() - -> **delete**(`collection`, `id`): `Promise`\<`void`\> - -Defined in: [src/adapters/storage/indexedDB.ts:281](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/indexedDB.ts#L281) - -Deletes an item from the specified object store (collection) by its ID. - -#### Parameters - -##### collection - -`string` - -The name of the object store. - -##### id - -`string` - -The ID (key) of the item to delete. - -#### Returns - -`Promise`\<`void`\> - -A promise that resolves when the deletion is successful. - -#### Throws - -If the database is not initialized, the store doesn't exist, or a database error occurs. - -#### Implementation of - -[`StorageAdapter`](../interfaces/StorageAdapter.md).[`delete`](../interfaces/StorageAdapter.md#delete) - -*** - -### get() - -> **get**\<`T`\>(`collection`, `id`): `Promise`\<`null` \| `T`\> - -Defined in: [src/adapters/storage/indexedDB.ts:188](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/indexedDB.ts#L188) - -Retrieves a single item by its ID from the specified object store (collection). - -#### Type Parameters - -##### T - -`T` - -The expected type of the retrieved item. - -#### Parameters - -##### collection - -`string` - -The name of the object store. - -##### id - -`string` - -The ID (key) of the item to retrieve. - -#### Returns - -`Promise`\<`null` \| `T`\> - -A promise resolving to a copy of the item if found, or `null` otherwise. - -#### Throws - -If the database is not initialized, the store doesn't exist, or a database error occurs. - -#### Implementation of - -[`StorageAdapter`](../interfaces/StorageAdapter.md).[`get`](../interfaces/StorageAdapter.md#get) - -*** - -### init() - -> **init**(): `Promise`\<`void`\> - -Defined in: [src/adapters/storage/indexedDB.ts:64](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/indexedDB.ts#L64) - -Opens the IndexedDB database connection and ensures the required object stores -are created or updated based on the configured `dbVersion`. -This method MUST be called and awaited successfully before using other adapter methods. -It handles the `onupgradeneeded` event to create stores. - -#### Returns - -`Promise`\<`void`\> - -A promise that resolves when the database is successfully opened and ready, or rejects on error. - -#### Implementation of - -[`StorageAdapter`](../interfaces/StorageAdapter.md).[`init`](../interfaces/StorageAdapter.md#init) - -*** - -### query() - -> **query**\<`T`\>(`collection`, `filterOptions`): `Promise`\<`T`[]\> - -Defined in: [src/adapters/storage/indexedDB.ts:321](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/indexedDB.ts#L321) - -Queries items within a collection based on provided filter options. -**Note:** This implementation uses `getAll()` and performs filtering, sorting, -and limiting **client-side**. For large datasets, performance may be suboptimal. -A more advanced version would leverage IndexedDB indexes and cursors for -efficient querying directly within the database. -Supports basic exact-match filtering and single-key sorting. - -#### Type Parameters - -##### T - -`T` - -The expected type of the items in the collection. - -#### Parameters - -##### collection - -`string` - -The name of the object store to query. - -##### filterOptions - -[`FilterOptions`](../interfaces/FilterOptions.md) - -Options for filtering, sorting, skipping, and limiting results. - -#### Returns - -`Promise`\<`T`[]\> - -A promise resolving to an array of deep copies of the matching items. - -#### Throws - -If the database is not initialized, the store doesn't exist, or a database error occurs. - -#### Implementation of - -[`StorageAdapter`](../interfaces/StorageAdapter.md).[`query`](../interfaces/StorageAdapter.md#query) - -*** - -### set() - -> **set**\<`T`\>(`collection`, `id`, `data`): `Promise`\<`void`\> - -Defined in: [src/adapters/storage/indexedDB.ts:225](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/storage/indexedDB.ts#L225) - -Saves (creates or updates) an item in the specified object store (collection). -Assumes the object store uses 'id' as its keyPath. The `id` parameter provided -should match the `id` property within the `data` object. -Uses `structuredClone` to store a deep copy. - -#### Type Parameters - -##### T - -`T` - -The type of the data being saved. Must have an 'id' property. - -#### Parameters - -##### collection - -`string` - -The name of the object store. - -##### id - -`string` - -The unique ID of the item (should match `data.id`). - -##### data - -`T` - -The data object to save. Must contain an `id` property matching the `id` parameter. - -#### Returns - -`Promise`\<`void`\> - -A promise that resolves when the data is successfully saved. - -#### Throws - -If the database is not initialized, the store doesn't exist, data is missing the 'id' property, or a database error occurs. - -#### Implementation of - -[`StorageAdapter`](../interfaces/StorageAdapter.md).[`set`](../interfaces/StorageAdapter.md#set) diff --git a/Docs/API/classes/LLMStreamSocket.md b/Docs/API/classes/LLMStreamSocket.md deleted file mode 100644 index 135ede2..0000000 --- a/Docs/API/classes/LLMStreamSocket.md +++ /dev/null @@ -1,194 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / LLMStreamSocket - -# Class: LLMStreamSocket - -Defined in: [src/systems/ui/llm-stream-socket.ts:13](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/systems/ui/llm-stream-socket.ts#L13) - -A dedicated socket for broadcasting LLM stream events (`StreamEvent`) to UI subscribers. -Extends the generic TypedSocket and implements filtering based on `StreamEvent.type`. - -## Extends - -- [`TypedSocket`](TypedSocket.md)\<[`StreamEvent`](../interfaces/StreamEvent.md), `StreamEventTypeFilter`\> - -## Constructors - -### Constructor - -> **new LLMStreamSocket**(): `LLMStreamSocket` - -Defined in: [src/systems/ui/llm-stream-socket.ts:15](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/systems/ui/llm-stream-socket.ts#L15) - -#### Returns - -`LLMStreamSocket` - -#### Overrides - -[`TypedSocket`](TypedSocket.md).[`constructor`](TypedSocket.md#constructor) - -## Methods - -### clearAllSubscriptions() - -> **clearAllSubscriptions**(): `void` - -Defined in: [src/systems/ui/typed-socket.ts:99](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/systems/ui/typed-socket.ts#L99) - -Clears all subscriptions. Useful for cleanup. - -#### Returns - -`void` - -#### Inherited from - -[`TypedSocket`](TypedSocket.md).[`clearAllSubscriptions`](TypedSocket.md#clearallsubscriptions) - -*** - -### getHistory()? - -> `optional` **getHistory**(`_filter`?, `_options`?): `Promise`\<[`StreamEvent`](../interfaces/StreamEvent.md)[]\> - -Defined in: [src/systems/ui/typed-socket.ts:91](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/systems/ui/typed-socket.ts#L91) - -Optional: Retrieves historical data. This base implementation is empty. -Subclasses might implement this by interacting with repositories. - -#### Parameters - -##### \_filter? - -`StreamEventTypeFilter` - -##### \_options? - -###### limit? - -`number` - -###### threadId? - -`string` - -#### Returns - -`Promise`\<[`StreamEvent`](../interfaces/StreamEvent.md)[]\> - -#### Inherited from - -[`TypedSocket`](TypedSocket.md).[`getHistory`](TypedSocket.md#gethistory) - -*** - -### notify() - -> **notify**(`data`, `options`?, `filterCheck`?): `void` - -Defined in: [src/systems/ui/typed-socket.ts:55](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/systems/ui/typed-socket.ts#L55) - -Notifies all relevant subscribers with new data. - -#### Parameters - -##### data - -[`StreamEvent`](../interfaces/StreamEvent.md) - -The data payload to send to subscribers. - -##### options? - -Optional targeting options (e.g., targetThreadId). - -###### targetSessionId? - -`string` - -###### targetThreadId? - -`string` - -##### filterCheck? - -(`data`, `filter`?) => `boolean` - -A function to check if a subscription's filter matches the data. - -#### Returns - -`void` - -#### Inherited from - -[`TypedSocket`](TypedSocket.md).[`notify`](TypedSocket.md#notify) - -*** - -### notifyStreamEvent() - -> **notifyStreamEvent**(`event`): `void` - -Defined in: [src/systems/ui/llm-stream-socket.ts:25](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/systems/ui/llm-stream-socket.ts#L25) - -Notifies subscribers about a new LLM stream event. -Filters based on event type if a filter is provided during subscription. - -#### Parameters - -##### event - -[`StreamEvent`](../interfaces/StreamEvent.md) - -The StreamEvent data. - -#### Returns - -`void` - -*** - -### subscribe() - -> **subscribe**(`callback`, `filter`?, `options`?): [`UnsubscribeFunction`](../type-aliases/UnsubscribeFunction.md) - -Defined in: [src/systems/ui/typed-socket.ts:33](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/systems/ui/typed-socket.ts#L33) - -Subscribes a callback function to receive notifications. - -#### Parameters - -##### callback - -(`data`) => `void` - -The function to call when new data is notified. - -##### filter? - -`StreamEventTypeFilter` - -An optional filter to only receive specific types of data. - -##### options? - -Optional configuration, like a threadId for filtering. - -###### threadId? - -`string` - -#### Returns - -[`UnsubscribeFunction`](../type-aliases/UnsubscribeFunction.md) - -An unsubscribe function. - -#### Inherited from - -[`TypedSocket`](TypedSocket.md).[`subscribe`](TypedSocket.md#subscribe) diff --git a/Docs/API/classes/LocalInstanceBusyError.md b/Docs/API/classes/LocalInstanceBusyError.md deleted file mode 100644 index e633e64..0000000 --- a/Docs/API/classes/LocalInstanceBusyError.md +++ /dev/null @@ -1,83 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / LocalInstanceBusyError - -# Class: LocalInstanceBusyError - -Defined in: [src/errors.ts:93](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L93) - -Custom error class for ART framework specific errors. - -## Extends - -- [`ARTError`](ARTError.md) - -## Constructors - -### Constructor - -> **new LocalInstanceBusyError**(`providerName`, `modelId`): `LocalInstanceBusyError` - -Defined in: [src/errors.ts:94](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L94) - -#### Parameters - -##### providerName - -`string` - -##### modelId - -`string` - -#### Returns - -`LocalInstanceBusyError` - -#### Overrides - -[`ARTError`](ARTError.md).[`constructor`](ARTError.md#constructor) - -## Properties - -### code - -> `readonly` **code**: [`ErrorCode`](../enumerations/ErrorCode.md) - -Defined in: [src/errors.ts:54](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L54) - -#### Inherited from - -[`ARTError`](ARTError.md).[`code`](ARTError.md#code) - -*** - -### originalError? - -> `readonly` `optional` **originalError**: `Error` - -Defined in: [src/errors.ts:55](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L55) - -#### Inherited from - -[`ARTError`](ARTError.md).[`originalError`](ARTError.md#originalerror) - -## Methods - -### toString() - -> **toString**(): `string` - -Defined in: [src/errors.ts:69](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L69) - -Returns a string representation of an object. - -#### Returns - -`string` - -#### Inherited from - -[`ARTError`](ARTError.md).[`toString`](ARTError.md#tostring) diff --git a/Docs/API/classes/LocalProviderConflictError.md b/Docs/API/classes/LocalProviderConflictError.md deleted file mode 100644 index 97dec70..0000000 --- a/Docs/API/classes/LocalProviderConflictError.md +++ /dev/null @@ -1,83 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / LocalProviderConflictError - -# Class: LocalProviderConflictError - -Defined in: [src/errors.ts:86](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L86) - -Custom error class for ART framework specific errors. - -## Extends - -- [`ARTError`](ARTError.md) - -## Constructors - -### Constructor - -> **new LocalProviderConflictError**(`requestedProvider`, `activeProvider`): `LocalProviderConflictError` - -Defined in: [src/errors.ts:87](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L87) - -#### Parameters - -##### requestedProvider - -`string` - -##### activeProvider - -`string` - -#### Returns - -`LocalProviderConflictError` - -#### Overrides - -[`ARTError`](ARTError.md).[`constructor`](ARTError.md#constructor) - -## Properties - -### code - -> `readonly` **code**: [`ErrorCode`](../enumerations/ErrorCode.md) - -Defined in: [src/errors.ts:54](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L54) - -#### Inherited from - -[`ARTError`](ARTError.md).[`code`](ARTError.md#code) - -*** - -### originalError? - -> `readonly` `optional` **originalError**: `Error` - -Defined in: [src/errors.ts:55](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L55) - -#### Inherited from - -[`ARTError`](ARTError.md).[`originalError`](ARTError.md#originalerror) - -## Methods - -### toString() - -> **toString**(): `string` - -Defined in: [src/errors.ts:69](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L69) - -Returns a string representation of an object. - -#### Returns - -`string` - -#### Inherited from - -[`ARTError`](ARTError.md).[`toString`](ARTError.md#tostring) diff --git a/Docs/API/classes/Logger.md b/Docs/API/classes/Logger.md deleted file mode 100644 index 227a92b..0000000 --- a/Docs/API/classes/Logger.md +++ /dev/null @@ -1,160 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / Logger - -# Class: Logger - -Defined in: [src/utils/logger.ts:29](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/utils/logger.ts#L29) - -A simple static logger class for outputting messages to the console at different levels. -Configuration is global via the static `configure` method. - -## Constructors - -### Constructor - -> **new Logger**(): `Logger` - -#### Returns - -`Logger` - -## Methods - -### configure() - -> `static` **configure**(`config`): `void` - -Defined in: [src/utils/logger.ts:38](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/utils/logger.ts#L38) - -Configures the static logger settings. - -#### Parameters - -##### config - -`Partial`\<`LoggerConfig`\> - -A partial `LoggerConfig` object. Provided settings will override defaults. - -#### Returns - -`void` - -*** - -### debug() - -> `static` **debug**(`message`, ...`args`): `void` - -Defined in: [src/utils/logger.ts:48](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/utils/logger.ts#L48) - -Logs a message at the DEBUG level. -Only outputs if the configured log level is DEBUG. - -#### Parameters - -##### message - -`string` - -The main log message string. - -##### args - -...`any`[] - -Additional arguments to include in the console output (e.g., objects, arrays). - -#### Returns - -`void` - -*** - -### error() - -> `static` **error**(`message`, ...`args`): `void` - -Defined in: [src/utils/logger.ts:87](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/utils/logger.ts#L87) - -Logs a message at the ERROR level. -Outputs if the configured log level is ERROR, WARN, INFO, or DEBUG. - -#### Parameters - -##### message - -`string` - -The main log message string. - -##### args - -...`any`[] - -Additional arguments to include in the console output (often an error object). - -#### Returns - -`void` - -*** - -### info() - -> `static` **info**(`message`, ...`args`): `void` - -Defined in: [src/utils/logger.ts:61](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/utils/logger.ts#L61) - -Logs a message at the INFO level. -Outputs if the configured log level is INFO or DEBUG. - -#### Parameters - -##### message - -`string` - -The main log message string. - -##### args - -...`any`[] - -Additional arguments to include in the console output. - -#### Returns - -`void` - -*** - -### warn() - -> `static` **warn**(`message`, ...`args`): `void` - -Defined in: [src/utils/logger.ts:74](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/utils/logger.ts#L74) - -Logs a message at the WARN level. -Outputs if the configured log level is WARN, INFO, or DEBUG. - -#### Parameters - -##### message - -`string` - -The main log message string. - -##### args - -...`any`[] - -Additional arguments to include in the console output. - -#### Returns - -`void` diff --git a/Docs/API/classes/OllamaAdapter.md b/Docs/API/classes/OllamaAdapter.md deleted file mode 100644 index 3b96f43..0000000 --- a/Docs/API/classes/OllamaAdapter.md +++ /dev/null @@ -1,113 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / OllamaAdapter - -# Class: OllamaAdapter - -Defined in: [src/adapters/reasoning/ollama.ts:67](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/ollama.ts#L67) - -Implements the `ProviderAdapter` interface for interacting with Ollama's -OpenAI-compatible API endpoint. - -Handles formatting requests, parsing responses, streaming, and tool use. - -## Implements - -## Implements - -- [`ProviderAdapter`](../interfaces/ProviderAdapter.md) - -## Constructors - -### Constructor - -> **new OllamaAdapter**(`options`): `OllamaAdapter` - -Defined in: [src/adapters/reasoning/ollama.ts:77](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/ollama.ts#L77) - -Creates an instance of the OllamaAdapter. - -#### Parameters - -##### options - -[`OllamaAdapterOptions`](../interfaces/OllamaAdapterOptions.md) - -Configuration options. - -#### Returns - -`OllamaAdapter` - -## Properties - -### providerName - -> `readonly` **providerName**: `"ollama"` = `'ollama'` - -Defined in: [src/adapters/reasoning/ollama.ts:68](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/ollama.ts#L68) - -The unique identifier name for this provider (e.g., 'openai', 'anthropic'). - -#### Implementation of - -[`ProviderAdapter`](../interfaces/ProviderAdapter.md).[`providerName`](../interfaces/ProviderAdapter.md#providername) - -## Methods - -### call() - -> **call**(`prompt`, `options`): `Promise`\<`AsyncIterable`\<[`StreamEvent`](../interfaces/StreamEvent.md), `any`, `any`\>\> - -Defined in: [src/adapters/reasoning/ollama.ts:101](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/ollama.ts#L101) - -Sends a request to the Ollama API. -Translates `ArtStandardPrompt` to the OpenAI format and handles streaming and tool use. - -#### Parameters - -##### prompt - -[`ArtStandardPrompt`](../type-aliases/ArtStandardPrompt.md) - -The standardized prompt messages. - -##### options - -[`CallOptions`](../interfaces/CallOptions.md) - -Call options. - -#### Returns - -`Promise`\<`AsyncIterable`\<[`StreamEvent`](../interfaces/StreamEvent.md), `any`, `any`\>\> - -A promise resolving to an AsyncIterable of StreamEvent objects. - -#### Implementation of - -[`ProviderAdapter`](../interfaces/ProviderAdapter.md).[`call`](../interfaces/ProviderAdapter.md#call) - -*** - -### shutdown() - -> **shutdown**(): `Promise`\<`void`\> - -Defined in: [src/adapters/reasoning/ollama.ts:467](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/ollama.ts#L467) - -Optional method for graceful shutdown. -For Ollama, which is typically a separate local server, this adapter -doesn't manage persistent connections that need explicit closing. -The OpenAI client used internally might have its own cleanup, but -it's generally handled by garbage collection. - -#### Returns - -`Promise`\<`void`\> - -#### Implementation of - -[`ProviderAdapter`](../interfaces/ProviderAdapter.md).[`shutdown`](../interfaces/ProviderAdapter.md#shutdown) diff --git a/Docs/API/classes/OpenAIAdapter.md b/Docs/API/classes/OpenAIAdapter.md deleted file mode 100644 index eeaed9b..0000000 --- a/Docs/API/classes/OpenAIAdapter.md +++ /dev/null @@ -1,96 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / OpenAIAdapter - -# Class: OpenAIAdapter - -Defined in: [src/adapters/reasoning/openai.ts:91](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/openai.ts#L91) - -Implements the `ProviderAdapter` interface for interacting with OpenAI's -Chat Completions API (compatible models like GPT-3.5, GPT-4, GPT-4o). - -Handles formatting requests and parsing responses for OpenAI. -Uses raw `fetch` for now. - -## Implements - -## Implements - -- [`ProviderAdapter`](../interfaces/ProviderAdapter.md) - -## Constructors - -### Constructor - -> **new OpenAIAdapter**(`options`): `OpenAIAdapter` - -Defined in: [src/adapters/reasoning/openai.ts:102](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/openai.ts#L102) - -Creates an instance of the OpenAIAdapter. - -#### Parameters - -##### options - -`OpenAIAdapterOptions` - -Configuration options including the API key and optional model/baseURL overrides. - -#### Returns - -`OpenAIAdapter` - -#### Throws - -If the API key is missing. - -## Properties - -### providerName - -> `readonly` **providerName**: `"openai"` = `'openai'` - -Defined in: [src/adapters/reasoning/openai.ts:92](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/openai.ts#L92) - -The unique identifier name for this provider (e.g., 'openai', 'anthropic'). - -#### Implementation of - -[`ProviderAdapter`](../interfaces/ProviderAdapter.md).[`providerName`](../interfaces/ProviderAdapter.md#providername) - -## Methods - -### call() - -> **call**(`prompt`, `options`): `Promise`\<`AsyncIterable`\<[`StreamEvent`](../interfaces/StreamEvent.md), `any`, `any`\>\> - -Defined in: [src/adapters/reasoning/openai.ts:120](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/openai.ts#L120) - -Sends a request to the OpenAI Chat Completions API. -Translates `ArtStandardPrompt` to the OpenAI format, handles streaming and non-streaming responses. - -#### Parameters - -##### prompt - -[`ArtStandardPrompt`](../type-aliases/ArtStandardPrompt.md) - -The standardized prompt messages. - -##### options - -[`CallOptions`](../interfaces/CallOptions.md) - -Call options, including `threadId`, `traceId`, `stream` preference, and any OpenAI-specific parameters (like `temperature`, `max_tokens`) passed through. - -#### Returns - -`Promise`\<`AsyncIterable`\<[`StreamEvent`](../interfaces/StreamEvent.md), `any`, `any`\>\> - -A promise resolving to an AsyncIterable of StreamEvent objects. - -#### Implementation of - -[`ProviderAdapter`](../interfaces/ProviderAdapter.md).[`call`](../interfaces/ProviderAdapter.md#call) diff --git a/Docs/API/classes/OpenRouterAdapter.md b/Docs/API/classes/OpenRouterAdapter.md deleted file mode 100644 index db4cfed..0000000 --- a/Docs/API/classes/OpenRouterAdapter.md +++ /dev/null @@ -1,99 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / OpenRouterAdapter - -# Class: OpenRouterAdapter - -Defined in: [src/adapters/reasoning/openrouter.ts:93](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/openrouter.ts#L93) - -Implements the `ProviderAdapter` interface for interacting with the OpenRouter API, -which provides access to various LLMs through an OpenAI-compatible interface. - -Handles formatting requests and parsing responses for OpenRouter's chat completions endpoint. -Handles formatting requests and parsing responses for OpenRouter's chat completions endpoint. -Note: Streaming is **not yet implemented** for this adapter. Calls requesting streaming will yield an error and end. - -## Implements - -## Implements - -- [`ProviderAdapter`](../interfaces/ProviderAdapter.md) - -## Constructors - -### Constructor - -> **new OpenRouterAdapter**(`options`): `OpenRouterAdapter` - -Defined in: [src/adapters/reasoning/openrouter.ts:106](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/openrouter.ts#L106) - -Creates an instance of the OpenRouterAdapter. - -#### Parameters - -##### options - -`OpenRouterAdapterOptions` - -Configuration options including the API key, the specific OpenRouter model identifier, and optional headers/baseURL. - -#### Returns - -`OpenRouterAdapter` - -#### Throws - -If the API key or model identifier is missing. - -## Properties - -### providerName - -> `readonly` **providerName**: `"openrouter"` = `'openrouter'` - -Defined in: [src/adapters/reasoning/openrouter.ts:94](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/openrouter.ts#L94) - -The unique identifier name for this provider (e.g., 'openai', 'anthropic'). - -#### Implementation of - -[`ProviderAdapter`](../interfaces/ProviderAdapter.md).[`providerName`](../interfaces/ProviderAdapter.md#providername) - -## Methods - -### call() - -> **call**(`prompt`, `options`): `Promise`\<`AsyncIterable`\<[`StreamEvent`](../interfaces/StreamEvent.md), `any`, `any`\>\> - -Defined in: [src/adapters/reasoning/openrouter.ts:131](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/openrouter.ts#L131) - -Sends a request to the OpenRouter Chat Completions API endpoint. -Translates `ArtStandardPrompt` to the OpenAI-compatible format. - -**Note:** Streaming is **not yet implemented**. - -#### Parameters - -##### prompt - -[`ArtStandardPrompt`](../type-aliases/ArtStandardPrompt.md) - -The standardized prompt messages. - -##### options - -[`CallOptions`](../interfaces/CallOptions.md) - -Call options, including `threadId`, `traceId`, `stream`, and any OpenAI-compatible generation parameters. - -#### Returns - -`Promise`\<`AsyncIterable`\<[`StreamEvent`](../interfaces/StreamEvent.md), `any`, `any`\>\> - -A promise resolving to an AsyncIterable of StreamEvent objects. If streaming is requested, it yields an error event and ends. - -#### Implementation of - -[`ProviderAdapter`](../interfaces/ProviderAdapter.md).[`call`](../interfaces/ProviderAdapter.md#call) diff --git a/Docs/API/classes/OutputParser.md b/Docs/API/classes/OutputParser.md deleted file mode 100644 index 0fd3888..0000000 --- a/Docs/API/classes/OutputParser.md +++ /dev/null @@ -1,108 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / OutputParser - -# Class: OutputParser - -Defined in: [systems/reasoning/OutputParser.ts:26](https://github.com/hashangit/ART/blob/3153790647102134b487bb6168bd208568e6a8ad/src/systems/reasoning/OutputParser.ts#L26) - -Default implementation of the `OutputParser` interface. -Responsible for extracting structured data (intent, plan, tool calls) from the planning phase -LLM response and the final response content from the synthesis phase response. -Includes robust parsing for tool call JSON arrays and Zod validation. - -## Implements - -## Implements - -- `OutputParser` - -## Constructors - -### Constructor - -> **new OutputParser**(): `OutputParser` - -#### Returns - -`OutputParser` - -## Methods - -### parsePlanningOutput() - -> **parsePlanningOutput**(`output`): `Promise`\<\{ `intent`: `string`; `plan`: `string`; `thoughts`: `string`; `toolCalls`: [`ParsedToolCall`](../interfaces/ParsedToolCall.md)[]; \}\> - -Defined in: [systems/reasoning/OutputParser.ts:50](https://github.com/hashangit/ART/blob/3153790647102134b487bb6168bd208568e6a8ad/src/systems/reasoning/OutputParser.ts#L50) - -Parses the raw string output from the planning LLM call to extract structured information. - -This method performs the following steps: -1. Uses `XmlMatcher` to identify and extract content within `<think>...</think>` tags. - This extracted content is aggregated into the `thoughts` field of the result. -2. The remaining content (outside of `<think>` tags) is then parsed for sections - explicitly marked with "Intent:", "Plan:", and "Tool Calls:". -3. It attempts to find and parse a JSON array within the "Tool Calls:" section, handling - potential markdown fences (e.g., ```json ... ```) and validating the structure using Zod. - -#### Parameters - -##### output - -`string` - -The raw string response from the planning LLM call, which may include - text, `<think>` tags, and sections for Intent, Plan, and Tool Calls. - -#### Returns - -`Promise`\<\{ `intent`: `string`; `plan`: `string`; `thoughts`: `string`; `toolCalls`: [`ParsedToolCall`](../interfaces/ParsedToolCall.md)[]; \}\> - -A promise resolving to an object containing: - - `thoughts?`: An optional string aggregating content from all `<think>` tags, separated by "\\n\\n---\\n\\n". - - `intent?`: An optional string for the parsed intent. - - `plan?`: An optional string for the parsed plan. - - `toolCalls?`: An optional array of `ParsedToolCall` objects. This will be an empty array `[]` - if the "Tool Calls:" section is present in the non-thinking content but is empty, - or if the JSON is invalid/fails validation. It remains `undefined` if the - "Tool Calls:" section itself is missing from the non-thinking content. - Fields will be `undefined` if the corresponding section is not found or cannot be parsed correctly. - -#### Implementation of - -`IOutputParser.parsePlanningOutput` - -*** - -### parseSynthesisOutput() - -> **parseSynthesisOutput**(`output`): `Promise`\<`string`\> - -Defined in: [systems/reasoning/OutputParser.ts:188](https://github.com/hashangit/ART/blob/3153790647102134b487bb6168bd208568e6a8ad/src/systems/reasoning/OutputParser.ts#L188) - -/** - * Parses the raw string output from the synthesis LLM call to extract the final, user-facing response content. - * This default implementation simply trims whitespace from the input string. - * More complex implementations could potentially remove specific tags or formatting if needed. - * - -#### Parameters - -##### output - -`string` - -The raw string response from the synthesis LLM call. - * - -#### Returns - -`Promise`\<`string`\> - -A promise resolving to the cleaned, final response string. - -#### Implementation of - -`IOutputParser.parseSynthesisOutput` diff --git a/Docs/API/classes/PESAgent.md b/Docs/API/classes/PESAgent.md deleted file mode 100644 index a0ea390..0000000 --- a/Docs/API/classes/PESAgent.md +++ /dev/null @@ -1,114 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / PESAgent - -# Class: PESAgent - -Defined in: [src/core/agents/pes-agent.ts:91](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/agents/pes-agent.ts#L91) - -Implements the Plan-Execute-Synthesize (PES) agent orchestration logic. -This agent follows a structured approach: -1. **Plan:** Understand the user query, determine intent, and create a plan (potentially involving tool calls). -2. **Execute:** Run any necessary tools identified in the planning phase. -3. **Synthesize:** Generate a final response based on the query, plan, and tool results. - -It constructs standardized prompts (`ArtStandardPrompt`) directly as JavaScript objects -for the `ReasoningEngine`. It processes the `StreamEvent` output from the reasoning engine for both planning and synthesis. - -## Implements - -// - -## See - - - // Removed - - - - - - - -## Implements - -- [`IAgentCore`](../interfaces/IAgentCore.md) - -## Constructors - -### Constructor - -> **new PESAgent**(`dependencies`): `PESAgent` - -Defined in: [src/core/agents/pes-agent.ts:106](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/agents/pes-agent.ts#L106) - -Creates an instance of the PESAgent. - -#### Parameters - -##### dependencies - -`PESAgentDependencies` - -An object containing instances of all required subsystems (managers, registries, etc.). - -#### Returns - -`PESAgent` - -## Methods - -### process() - -> **process**(`props`): `Promise`\<[`AgentFinalResponse`](../interfaces/AgentFinalResponse.md)\> - -Defined in: [src/core/agents/pes-agent.ts:142](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/agents/pes-agent.ts#L142) - -Executes the full Plan-Execute-Synthesize cycle for a given user query. - -**Workflow:** -1. **Initiation & Config:** Loads thread configuration. Resolves the final system prompt based on a hierarchy: - Call-level (`AgentProps.options.systemPrompt`) > Thread-level (`ThreadConfig.systemPrompt`) > - Instance-level (`ArtInstanceConfig.defaultSystemPrompt` via constructor) > Agent's base prompt. - The resolved custom part is appended to the agent's base prompt. -2. **Data Gathering:** Gathers history, available tools, the resolved system prompt, and query. -3. **Planning Prompt Construction:** Directly constructs the `ArtStandardPrompt` object/array for planning. -4. **Planning LLM Call:** Sends the planning prompt object to the `reasoningEngine` (requesting streaming). Consumes the `StreamEvent` stream, buffers the output text, and handles potential errors. -5. **Planning Output Parsing:** Parses the buffered planning output text to extract intent, plan, and tool calls using `outputParser.parsePlanningOutput`. -6. **Tool Execution:** Executes identified tool calls via the `toolSystem`. -7. **Data Gathering (Synthesis):** Gathers the original query, plan, tool results, history, etc. -8. **Synthesis Prompt Construction:** Directly constructs the `ArtStandardPrompt` object/array for synthesis. -9. **Synthesis LLM Call:** Sends the synthesis prompt object to the `reasoningEngine` (requesting streaming). Consumes the `StreamEvent` stream, buffers the final response text, and handles potential errors. -10. **Finalization:** Saves the final AI message, updates state if needed, records observations, and returns the result. - -**Error Handling:** -- Errors during critical phases (planning/synthesis LLM call) will throw an `ARTError`. Prompt construction errors are less likely but possible if data is malformed. -- Errors during tool execution or synthesis LLM call might result in a 'partial' success status, potentially using the error message as the final response content. - -#### Parameters - -##### props - -[`AgentProps`](../interfaces/AgentProps.md) - -The input properties containing the user query, threadId, userId, traceId, etc. - -#### Returns - -`Promise`\<[`AgentFinalResponse`](../interfaces/AgentFinalResponse.md)\> - -A promise resolving to the final response, including the AI message and execution metadata. - -#### Throws - -If a critical error occurs that prevents the agent from completing the process (e.g., config loading, planning failure). - -#### See - - - - - // - - // Removed - context is implicit in object construction - - - - - -#### Implementation of - -[`IAgentCore`](../interfaces/IAgentCore.md).[`process`](../interfaces/IAgentCore.md#process) diff --git a/Docs/API/classes/TypedSocket.md b/Docs/API/classes/TypedSocket.md deleted file mode 100644 index b197db9..0000000 --- a/Docs/API/classes/TypedSocket.md +++ /dev/null @@ -1,161 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / TypedSocket - -# Class: TypedSocket\<DataType, FilterType\> - -Defined in: [src/systems/ui/typed-socket.ts:18](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/systems/ui/typed-socket.ts#L18) - -A generic class for implementing a publish/subscribe pattern with filtering capabilities. -Designed for decoupling components, particularly UI updates from backend events. - -## Extended by - -- [`LLMStreamSocket`](LLMStreamSocket.md) - -## Type Parameters - -### DataType - -`DataType` - -### FilterType - -`FilterType` = `any` - -## Constructors - -### Constructor - -> **new TypedSocket**\<`DataType`, `FilterType`\>(): `TypedSocket`\<`DataType`, `FilterType`\> - -Defined in: [src/systems/ui/typed-socket.ts:22](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/systems/ui/typed-socket.ts#L22) - -#### Returns - -`TypedSocket`\<`DataType`, `FilterType`\> - -## Methods - -### clearAllSubscriptions() - -> **clearAllSubscriptions**(): `void` - -Defined in: [src/systems/ui/typed-socket.ts:99](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/systems/ui/typed-socket.ts#L99) - -Clears all subscriptions. Useful for cleanup. - -#### Returns - -`void` - -*** - -### getHistory()? - -> `optional` **getHistory**(`_filter`?, `_options`?): `Promise`\<`DataType`[]\> - -Defined in: [src/systems/ui/typed-socket.ts:91](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/systems/ui/typed-socket.ts#L91) - -Optional: Retrieves historical data. This base implementation is empty. -Subclasses might implement this by interacting with repositories. - -#### Parameters - -##### \_filter? - -`FilterType` - -##### \_options? - -###### limit? - -`number` - -###### threadId? - -`string` - -#### Returns - -`Promise`\<`DataType`[]\> - -*** - -### notify() - -> **notify**(`data`, `options`?, `filterCheck`?): `void` - -Defined in: [src/systems/ui/typed-socket.ts:55](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/systems/ui/typed-socket.ts#L55) - -Notifies all relevant subscribers with new data. - -#### Parameters - -##### data - -`DataType` - -The data payload to send to subscribers. - -##### options? - -Optional targeting options (e.g., targetThreadId). - -###### targetSessionId? - -`string` - -###### targetThreadId? - -`string` - -##### filterCheck? - -(`data`, `filter`?) => `boolean` - -A function to check if a subscription's filter matches the data. - -#### Returns - -`void` - -*** - -### subscribe() - -> **subscribe**(`callback`, `filter`?, `options`?): [`UnsubscribeFunction`](../type-aliases/UnsubscribeFunction.md) - -Defined in: [src/systems/ui/typed-socket.ts:33](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/systems/ui/typed-socket.ts#L33) - -Subscribes a callback function to receive notifications. - -#### Parameters - -##### callback - -(`data`) => `void` - -The function to call when new data is notified. - -##### filter? - -`FilterType` - -An optional filter to only receive specific types of data. - -##### options? - -Optional configuration, like a threadId for filtering. - -###### threadId? - -`string` - -#### Returns - -[`UnsubscribeFunction`](../type-aliases/UnsubscribeFunction.md) - -An unsubscribe function. diff --git a/Docs/API/classes/UnknownProviderError.md b/Docs/API/classes/UnknownProviderError.md deleted file mode 100644 index 0031678..0000000 --- a/Docs/API/classes/UnknownProviderError.md +++ /dev/null @@ -1,79 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / UnknownProviderError - -# Class: UnknownProviderError - -Defined in: [src/errors.ts:79](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L79) - -Custom error class for ART framework specific errors. - -## Extends - -- [`ARTError`](ARTError.md) - -## Constructors - -### Constructor - -> **new UnknownProviderError**(`providerName`): `UnknownProviderError` - -Defined in: [src/errors.ts:80](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L80) - -#### Parameters - -##### providerName - -`string` - -#### Returns - -`UnknownProviderError` - -#### Overrides - -[`ARTError`](ARTError.md).[`constructor`](ARTError.md#constructor) - -## Properties - -### code - -> `readonly` **code**: [`ErrorCode`](../enumerations/ErrorCode.md) - -Defined in: [src/errors.ts:54](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L54) - -#### Inherited from - -[`ARTError`](ARTError.md).[`code`](ARTError.md#code) - -*** - -### originalError? - -> `readonly` `optional` **originalError**: `Error` - -Defined in: [src/errors.ts:55](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L55) - -#### Inherited from - -[`ARTError`](ARTError.md).[`originalError`](ARTError.md#originalerror) - -## Methods - -### toString() - -> **toString**(): `string` - -Defined in: [src/errors.ts:69](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L69) - -Returns a string representation of an object. - -#### Returns - -`string` - -#### Inherited from - -[`ARTError`](ARTError.md).[`toString`](ARTError.md#tostring) diff --git a/Docs/API/classes/XmlMatcher.md b/Docs/API/classes/XmlMatcher.md deleted file mode 100644 index 675309a..0000000 --- a/Docs/API/classes/XmlMatcher.md +++ /dev/null @@ -1,157 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / XmlMatcher - -# Class: XmlMatcher\<Result\> - -Defined in: [utils/xml-matcher.ts:25](https://github.com/hashangit/ART/blob/3153790647102134b487bb6168bd208568e6a8ad/src/utils/xml-matcher.ts#L25) - -A utility class to find and extract content within a specific XML tag from a stream of text. -It processes text chunks incrementally and yields segments, marking whether each segment -was inside or outside the specified XML tag. - -Example: Given tagName 'think', and input "Some text <think>this is a thought</think> and more text.", -it would yield: -- { matched: false, data: "Some text " } -- { matched: true, data: "this is a thought" } -- { matched: false, data: " and more text." } - -## Type Parameters - -### Result - -`Result` = [`XmlMatcherChunk`](../interfaces/XmlMatcherChunk.md) - -## Constructors - -### Constructor - -> **new XmlMatcher**\<`Result`\>(`tagName`, `transform`?, `position`?): `XmlMatcher`\<`Result`\> - -Defined in: [utils/xml-matcher.ts:44](https://github.com/hashangit/ART/blob/3153790647102134b487bb6168bd208568e6a8ad/src/utils/xml-matcher.ts#L44) - -Constructs an XmlMatcher. - -#### Parameters - -##### tagName - -`string` - -The name of the XML tag to match (e.g., "think"). - -##### transform? - -(`chunk`) => `Result` - -An optional function to transform the yielded XmlMatcherChunk into a custom Result type. - -##### position? - -`number` = `0` - -The character position in the input stream at which matching should begin. - If 0, matching starts immediately. If greater than 0, characters before this - position are treated as unmatched text until the tag is encountered at or after - this position. This is useful if the tag is expected after some preamble. - The example code had `this.pointer <= this.position + 1 || this.matched` - which implies matching can start if we are at/before the desired start position OR if we are already in a matched state. - -#### Returns - -`XmlMatcher`\<`Result`\> - -## Properties - -### position - -> `readonly` **position**: `number` = `0` - -Defined in: [utils/xml-matcher.ts:47](https://github.com/hashangit/ART/blob/3153790647102134b487bb6168bd208568e6a8ad/src/utils/xml-matcher.ts#L47) - -The character position in the input stream at which matching should begin. - If 0, matching starts immediately. If greater than 0, characters before this - position are treated as unmatched text until the tag is encountered at or after - this position. This is useful if the tag is expected after some preamble. - The example code had `this.pointer <= this.position + 1 || this.matched` - which implies matching can start if we are at/before the desired start position OR if we are already in a matched state. - -*** - -### tagName - -> `readonly` **tagName**: `string` - -Defined in: [utils/xml-matcher.ts:45](https://github.com/hashangit/ART/blob/3153790647102134b487bb6168bd208568e6a8ad/src/utils/xml-matcher.ts#L45) - -The name of the XML tag to match (e.g., "think"). - -*** - -### transform()? - -> `readonly` `optional` **transform**: (`chunk`) => `Result` - -Defined in: [utils/xml-matcher.ts:46](https://github.com/hashangit/ART/blob/3153790647102134b487bb6168bd208568e6a8ad/src/utils/xml-matcher.ts#L46) - -An optional function to transform the yielded XmlMatcherChunk into a custom Result type. - -#### Parameters - -##### chunk - -[`XmlMatcherChunk`](../interfaces/XmlMatcherChunk.md) - -#### Returns - -`Result` - -## Methods - -### final() - -> **final**(`chunk`?): `Result`[] - -Defined in: [utils/xml-matcher.ts:181](https://github.com/hashangit/ART/blob/3153790647102134b487bb6168bd208568e6a8ad/src/utils/xml-matcher.ts#L181) - -Finalizes processing, flushing any remaining buffered text. - -#### Parameters - -##### chunk? - -`string` - -An optional final text chunk to process. - -#### Returns - -`Result`[] - -An array of transformed results. - -*** - -### update() - -> **update**(`chunk`): `Result`[] - -Defined in: [utils/xml-matcher.ts:98](https://github.com/hashangit/ART/blob/3153790647102134b487bb6168bd208568e6a8ad/src/utils/xml-matcher.ts#L98) - -Processes an incoming chunk of text. - -#### Parameters - -##### chunk - -`string` - -The text chunk to process. - -#### Returns - -`Result`[] - -An array of transformed results based on the matched segments. diff --git a/Docs/API/enumerations/ErrorCode.md b/Docs/API/enumerations/ErrorCode.md deleted file mode 100644 index b07e169..0000000 --- a/Docs/API/enumerations/ErrorCode.md +++ /dev/null @@ -1,235 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ErrorCode - -# Enumeration: ErrorCode - -Defined in: [src/errors.ts:6](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L6) - -Defines standard error codes for the ART framework. - -## Enumeration Members - -### ADAPTER\_INSTANTIATION\_ERROR - -> **ADAPTER\_INSTANTIATION\_ERROR**: `"ADAPTER_INSTANTIATION_ERROR"` - -Defined in: [src/errors.ts:47](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L47) - -*** - -### AGENT\_PROCESSING\_ERROR - -> **AGENT\_PROCESSING\_ERROR**: `"AGENT_PROCESSING_ERROR"` - -Defined in: [src/errors.ts:35](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L35) - -*** - -### API\_QUEUE\_TIMEOUT - -> **API\_QUEUE\_TIMEOUT**: `"API_QUEUE_TIMEOUT"` - -Defined in: [src/errors.ts:46](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L46) - -*** - -### INVALID\_CONFIG - -> **INVALID\_CONFIG**: `"INVALID_CONFIG"` - -Defined in: [src/errors.ts:8](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L8) - -*** - -### LLM\_PROVIDER\_ERROR - -> **LLM\_PROVIDER\_ERROR**: `"LLM_PROVIDER_ERROR"` - -Defined in: [src/errors.ts:17](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L17) - -*** - -### LOCAL\_INSTANCE\_BUSY - -> **LOCAL\_INSTANCE\_BUSY**: `"LOCAL_INSTANCE_BUSY"` - -Defined in: [src/errors.ts:45](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L45) - -*** - -### LOCAL\_PROVIDER\_CONFLICT - -> **LOCAL\_PROVIDER\_CONFLICT**: `"LOCAL_PROVIDER_CONFLICT"` - -Defined in: [src/errors.ts:44](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L44) - -*** - -### MISSING\_API\_KEY - -> **MISSING\_API\_KEY**: `"MISSING_API_KEY"` - -Defined in: [src/errors.ts:9](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L9) - -*** - -### NETWORK\_ERROR - -> **NETWORK\_ERROR**: `"NETWORK_ERROR"` - -Defined in: [src/errors.ts:38](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L38) - -*** - -### OUTPUT\_PARSING\_FAILED - -> **OUTPUT\_PARSING\_FAILED**: `"OUTPUT_PARSING_FAILED"` - -Defined in: [src/errors.ts:19](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L19) - -*** - -### PLANNING\_FAILED - -> **PLANNING\_FAILED**: `"PLANNING_FAILED"` - -Defined in: [src/errors.ts:32](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L32) - -*** - -### PROMPT\_ASSEMBLY\_FAILED - -> **PROMPT\_ASSEMBLY\_FAILED**: `"PROMPT_ASSEMBLY_FAILED"` - -Defined in: [src/errors.ts:20](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L20) - -*** - -### PROMPT\_FRAGMENT\_NOT\_FOUND - -> **PROMPT\_FRAGMENT\_NOT\_FOUND**: `"PROMPT_FRAGMENT_NOT_FOUND"` - -Defined in: [src/errors.ts:21](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L21) - -*** - -### PROMPT\_GENERATION\_FAILED - -> **PROMPT\_GENERATION\_FAILED**: `"PROMPT_GENERATION_FAILED"` - -Defined in: [src/errors.ts:18](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L18) - -*** - -### PROMPT\_TRANSLATION\_FAILED - -> **PROMPT\_TRANSLATION\_FAILED**: `"PROMPT_TRANSLATION_FAILED"` - -Defined in: [src/errors.ts:23](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L23) - -*** - -### PROMPT\_VALIDATION\_FAILED - -> **PROMPT\_VALIDATION\_FAILED**: `"PROMPT_VALIDATION_FAILED"` - -Defined in: [src/errors.ts:22](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L22) - -*** - -### SAVE\_FAILED - -> **SAVE\_FAILED**: `"SAVE_FAILED"` - -Defined in: [src/errors.ts:14](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L14) - -*** - -### STORAGE\_ERROR - -> **STORAGE\_ERROR**: `"STORAGE_ERROR"` - -Defined in: [src/errors.ts:12](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L12) - -*** - -### SYNTHESIS\_FAILED - -> **SYNTHESIS\_FAILED**: `"SYNTHESIS_FAILED"` - -Defined in: [src/errors.ts:34](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L34) - -*** - -### THREAD\_NOT\_FOUND - -> **THREAD\_NOT\_FOUND**: `"THREAD_NOT_FOUND"` - -Defined in: [src/errors.ts:13](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L13) - -*** - -### TIMEOUT\_ERROR - -> **TIMEOUT\_ERROR**: `"TIMEOUT_ERROR"` - -Defined in: [src/errors.ts:39](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L39) - -*** - -### TOOL\_DISABLED - -> **TOOL\_DISABLED**: `"TOOL_DISABLED"` - -Defined in: [src/errors.ts:29](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L29) - -*** - -### TOOL\_EXECUTION\_ERROR - -> **TOOL\_EXECUTION\_ERROR**: `"TOOL_EXECUTION_ERROR"` - -Defined in: [src/errors.ts:28](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L28) - -*** - -### TOOL\_EXECUTION\_FAILED - -> **TOOL\_EXECUTION\_FAILED**: `"TOOL_EXECUTION_FAILED"` - -Defined in: [src/errors.ts:33](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L33) - -*** - -### TOOL\_NOT\_FOUND - -> **TOOL\_NOT\_FOUND**: `"TOOL_NOT_FOUND"` - -Defined in: [src/errors.ts:26](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L26) - -*** - -### TOOL\_SCHEMA\_VALIDATION\_FAILED - -> **TOOL\_SCHEMA\_VALIDATION\_FAILED**: `"TOOL_SCHEMA_VALIDATION_FAILED"` - -Defined in: [src/errors.ts:27](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L27) - -*** - -### UNKNOWN\_ERROR - -> **UNKNOWN\_ERROR**: `"UNKNOWN_ERROR"` - -Defined in: [src/errors.ts:40](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L40) - -*** - -### UNKNOWN\_PROVIDER - -> **UNKNOWN\_PROVIDER**: `"UNKNOWN_PROVIDER"` - -Defined in: [src/errors.ts:43](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/errors.ts#L43) diff --git a/Docs/API/enumerations/LogLevel.md b/Docs/API/enumerations/LogLevel.md deleted file mode 100644 index 11016fc..0000000 --- a/Docs/API/enumerations/LogLevel.md +++ /dev/null @@ -1,51 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / LogLevel - -# Enumeration: LogLevel - -Defined in: [src/utils/logger.ts:4](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/utils/logger.ts#L4) - -Defines the available logging levels, ordered from most verbose to least verbose. - -## Enumeration Members - -### DEBUG - -> **DEBUG**: `0` - -Defined in: [src/utils/logger.ts:6](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/utils/logger.ts#L6) - -Detailed debugging information, useful for development. - -*** - -### ERROR - -> **ERROR**: `3` - -Defined in: [src/utils/logger.ts:12](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/utils/logger.ts#L12) - -Errors that indicate a failure or problem. - -*** - -### INFO - -> **INFO**: `1` - -Defined in: [src/utils/logger.ts:8](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/utils/logger.ts#L8) - -General informational messages about application flow. - -*** - -### WARN - -> **WARN**: `2` - -Defined in: [src/utils/logger.ts:10](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/utils/logger.ts#L10) - -Potential issues or unexpected situations that don't prevent execution. diff --git a/Docs/API/enumerations/MessageRole.md b/Docs/API/enumerations/MessageRole.md deleted file mode 100644 index a1e3e74..0000000 --- a/Docs/API/enumerations/MessageRole.md +++ /dev/null @@ -1,43 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / MessageRole - -# Enumeration: MessageRole - -Defined in: [src/types/index.ts:38](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L38) - -Represents the role of a message sender in a conversation. - -## Enumeration Members - -### AI - -> **AI**: `"AI"` - -Defined in: [src/types/index.ts:40](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L40) - -*** - -### SYSTEM - -> **SYSTEM**: `"SYSTEM"` - -Defined in: [src/types/index.ts:41](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L41) - -*** - -### TOOL - -> **TOOL**: `"TOOL"` - -Defined in: [src/types/index.ts:42](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L42) - -*** - -### USER - -> **USER**: `"USER"` - -Defined in: [src/types/index.ts:39](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L39) diff --git a/Docs/API/enumerations/ModelCapability.md b/Docs/API/enumerations/ModelCapability.md deleted file mode 100644 index f3ce3bb..0000000 --- a/Docs/API/enumerations/ModelCapability.md +++ /dev/null @@ -1,68 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ModelCapability - -# Enumeration: ModelCapability - -Defined in: [src/types/index.ts:99](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L99) - -Represents the different capabilities a model might possess. -Used for model selection and validation. - -## Enumeration Members - -### CODE - -> **CODE**: `"code"` - -Defined in: [src/types/index.ts:105](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L105) - -*** - -### RAG - -> **RAG**: `"rag"` - -Defined in: [src/types/index.ts:104](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L104) - -*** - -### REASONING - -> **REASONING**: `"reasoning"` - -Defined in: [src/types/index.ts:106](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L106) - -*** - -### STREAMING - -> **STREAMING**: `"streaming"` - -Defined in: [src/types/index.ts:102](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L102) - -*** - -### TEXT - -> **TEXT**: `"text"` - -Defined in: [src/types/index.ts:100](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L100) - -*** - -### TOOL\_USE - -> **TOOL\_USE**: `"tool_use"` - -Defined in: [src/types/index.ts:103](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L103) - -*** - -### VISION - -> **VISION**: `"vision"` - -Defined in: [src/types/index.ts:101](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L101) diff --git a/Docs/API/enumerations/ObservationType.md b/Docs/API/enumerations/ObservationType.md deleted file mode 100644 index b61be54..0000000 --- a/Docs/API/enumerations/ObservationType.md +++ /dev/null @@ -1,135 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ObservationType - -# Enumeration: ObservationType - -Defined in: [src/types/index.ts:66](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L66) - -Represents the type of an observation record, capturing significant events during agent execution. - -## Enumeration Members - -### ERROR - -> **ERROR**: `"ERROR"` - -Defined in: [src/types/index.ts:77](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L77) - -Records an error encountered during any phase of execution. - -*** - -### FINAL\_RESPONSE - -> **FINAL\_RESPONSE**: `"FINAL_RESPONSE"` - -Defined in: [src/types/index.ts:79](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L79) - -Records the final AI response message generated by the agent. - -*** - -### INTENT - -> **INTENT**: `"INTENT"` - -Defined in: [src/types/index.ts:67](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L67) - -*** - -### LLM\_STREAM\_END - -> **LLM\_STREAM\_END**: `"LLM_STREAM_END"` - -Defined in: [src/types/index.ts:89](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L89) - -Logged by Agent Core upon receiving an END stream event. - -*** - -### LLM\_STREAM\_ERROR - -> **LLM\_STREAM\_ERROR**: `"LLM_STREAM_ERROR"` - -Defined in: [src/types/index.ts:91](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L91) - -Logged by Agent Core upon receiving an ERROR stream event. Content should be Error object or message. - -*** - -### LLM\_STREAM\_METADATA - -> **LLM\_STREAM\_METADATA**: `"LLM_STREAM_METADATA"` - -Defined in: [src/types/index.ts:87](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L87) - -Logged by Agent Core upon receiving a METADATA stream event. Content should be LLMMetadata. - -*** - -### LLM\_STREAM\_START - -> **LLM\_STREAM\_START**: `"LLM_STREAM_START"` - -Defined in: [src/types/index.ts:85](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L85) - -Logged by Agent Core when LLM stream consumption begins. - -*** - -### PLAN - -> **PLAN**: `"PLAN"` - -Defined in: [src/types/index.ts:68](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L68) - -*** - -### STATE\_UPDATE - -> **STATE\_UPDATE**: `"STATE_UPDATE"` - -Defined in: [src/types/index.ts:81](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L81) - -Records changes made to the agent's persistent state. - -*** - -### SYNTHESIS - -> **SYNTHESIS**: `"SYNTHESIS"` - -Defined in: [src/types/index.ts:75](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L75) - -Records events specifically related to the synthesis phase (e.g., the LLM call). - -*** - -### THOUGHTS - -> **THOUGHTS**: `"THOUGHTS"` - -Defined in: [src/types/index.ts:69](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L69) - -*** - -### TOOL\_CALL - -> **TOOL\_CALL**: `"TOOL_CALL"` - -Defined in: [src/types/index.ts:71](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L71) - -Records the LLM's decision to call one or more tools (part of the plan). - -*** - -### TOOL\_EXECUTION - -> **TOOL\_EXECUTION**: `"TOOL_EXECUTION"` - -Defined in: [src/types/index.ts:73](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L73) - -Records the actual execution attempt and result of a specific tool call. diff --git a/Docs/API/functions/createArtInstance.md b/Docs/API/functions/createArtInstance.md deleted file mode 100644 index 2ae433a..0000000 --- a/Docs/API/functions/createArtInstance.md +++ /dev/null @@ -1,44 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / createArtInstance - -# Function: createArtInstance() - -> **createArtInstance**(`config`): `Promise`\<[`ArtInstance`](../interfaces/ArtInstance.md)\> - -Defined in: [src/core/agent-factory.ts:294](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/agent-factory.ts#L294) - -High-level factory function to create and initialize a complete ART framework instance. -This simplifies the setup process by handling the instantiation and wiring of all -necessary components based on the provided configuration. - -## Parameters - -### config - -[`ArtInstanceConfig`](../interfaces/ArtInstanceConfig.md) - -The configuration object specifying storage, reasoning, tools, etc. - -## Returns - -`Promise`\<[`ArtInstance`](../interfaces/ArtInstance.md)\> - -A promise that resolves to a ready-to-use `ArtInstance` object, providing access to the core `process` method and essential managers/systems. - -## Throws - -If initialization fails (e.g., invalid config, storage connection error). - -## Example - -```ts -const art = await createArtInstance({ - storage: { type: 'indexedDB', dbName: 'myAgentDb' }, - reasoning: { provider: 'openai', apiKey: '...' }, - tools: [new CalculatorTool()] -}); -const response = await art.process({ query: "Calculate 5*5", threadId: "thread1" }); -``` diff --git a/Docs/API/functions/generateUUID.md b/Docs/API/functions/generateUUID.md deleted file mode 100644 index a84522c..0000000 --- a/Docs/API/functions/generateUUID.md +++ /dev/null @@ -1,20 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / generateUUID - -# Function: generateUUID() - -> **generateUUID**(): `string` - -Defined in: [src/utils/uuid.ts:8](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/utils/uuid.ts#L8) - -Generates a unique Version 4 UUID (Universally Unique Identifier) string. -Uses the underlying 'uuid' library's v4 implementation. - -## Returns - -`string` - -A randomly generated UUID string (e.g., "f47ac10b-58cc-4372-a567-0e02b2c3d479"). diff --git a/Docs/API/interfaces/AgentFinalResponse.md b/Docs/API/interfaces/AgentFinalResponse.md deleted file mode 100644 index b3790d3..0000000 --- a/Docs/API/interfaces/AgentFinalResponse.md +++ /dev/null @@ -1,31 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / AgentFinalResponse - -# Interface: AgentFinalResponse - -Defined in: [src/types/index.ts:357](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L357) - -The final structured response returned by the agent core after processing. - -## Properties - -### metadata - -> **metadata**: [`ExecutionMetadata`](ExecutionMetadata.md) - -Defined in: [src/types/index.ts:361](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L361) - -Metadata summarizing the execution cycle that produced this response. - -*** - -### response - -> **response**: [`ConversationMessage`](ConversationMessage.md) - -Defined in: [src/types/index.ts:359](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L359) - -The final `ConversationMessage` generated by the AI, which has also been persisted. diff --git a/Docs/API/interfaces/AgentOptions.md b/Docs/API/interfaces/AgentOptions.md deleted file mode 100644 index 200f476..0000000 --- a/Docs/API/interfaces/AgentOptions.md +++ /dev/null @@ -1,89 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / AgentOptions - -# Interface: AgentOptions - -Defined in: [src/types/index.ts:336](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L336) - -Options to override agent behavior at runtime. - -## Properties - -### forceTools? - -> `optional` **forceTools**: `string`[] - -Defined in: [src/types/index.ts:342](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L342) - -Force the use of specific tools, potentially overriding the thread's `enabledTools` for this call (use with caution). - -*** - -### llmParams? - -> `optional` **llmParams**: `Record`\<`string`, `any`\> - -Defined in: [src/types/index.ts:338](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L338) - -Override specific LLM parameters (e.g., temperature, max_tokens) for this call only. - -*** - -### overrideModel? - -> `optional` **overrideModel**: `object` - -Defined in: [src/types/index.ts:344](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L344) - -Specify a particular reasoning model to use for this call, overriding the thread's default. - -#### model - -> **model**: `string` - -#### provider - -> **provider**: `string` - -*** - -### promptTemplateId? - -> `optional` **promptTemplateId**: `string` - -Defined in: [src/types/index.ts:348](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L348) - -Override the prompt template used for this specific call. - -*** - -### providerConfig? - -> `optional` **providerConfig**: [`RuntimeProviderConfig`](RuntimeProviderConfig.md) - -Defined in: [src/types/index.ts:340](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L340) - -Override provider configuration for this specific call. - -*** - -### stream? - -> `optional` **stream**: `boolean` - -Defined in: [src/types/index.ts:346](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L346) - -Request a streaming response for this specific agent process call. - -*** - -### systemPrompt? - -> `optional` **systemPrompt**: `string` - -Defined in: [src/types/index.ts:350](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L350) - -Optional system prompt string to override thread, instance, or agent defaults for this specific call. diff --git a/Docs/API/interfaces/AgentProps.md b/Docs/API/interfaces/AgentProps.md deleted file mode 100644 index 2f13151..0000000 --- a/Docs/API/interfaces/AgentProps.md +++ /dev/null @@ -1,71 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / AgentProps - -# Interface: AgentProps - -Defined in: [src/types/index.ts:316](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L316) - -Properties required to initiate an agent processing cycle. - -## Properties - -### options? - -> `optional` **options**: [`AgentOptions`](AgentOptions.md) - -Defined in: [src/types/index.ts:328](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L328) - -Optional runtime options that can override default behaviors for this specific `process` call. - -*** - -### query - -> **query**: `string` - -Defined in: [src/types/index.ts:318](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L318) - -The user's input query or request to the agent. - -*** - -### sessionId? - -> `optional` **sessionId**: `string` - -Defined in: [src/types/index.ts:322](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L322) - -An optional identifier for the specific UI session, useful for targeting UI updates. - -*** - -### threadId - -> **threadId**: `string` - -Defined in: [src/types/index.ts:320](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L320) - -The mandatory identifier for the conversation thread. All context is scoped to this ID. - -*** - -### traceId? - -> `optional` **traceId**: `string` - -Defined in: [src/types/index.ts:326](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L326) - -An optional identifier used for tracing a request across multiple systems or services. - -*** - -### userId? - -> `optional` **userId**: `string` - -Defined in: [src/types/index.ts:324](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L324) - -An optional identifier for the user interacting with the agent. diff --git a/Docs/API/interfaces/AgentState.md b/Docs/API/interfaces/AgentState.md deleted file mode 100644 index 95ef95e..0000000 --- a/Docs/API/interfaces/AgentState.md +++ /dev/null @@ -1,38 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / AgentState - -# Interface: AgentState - -Defined in: [src/types/index.ts:294](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L294) - -Represents non-configuration state associated with an agent or thread. -Could include user preferences, accumulated knowledge, etc. (Less defined for v1.0) - -## Indexable - -\[`key`: `string`\]: `any` - -Allows for other arbitrary properties to be stored in the agent's state. - -## Properties - -### data - -> **data**: `any` - -Defined in: [src/types/index.ts:296](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L296) - -The primary data payload of the agent's state. Structure is application-defined. - -*** - -### version? - -> `optional` **version**: `number` - -Defined in: [src/types/index.ts:298](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L298) - -An optional version number for the agent's state, useful for migrations or tracking changes. diff --git a/Docs/API/interfaces/ArtInstance.md b/Docs/API/interfaces/ArtInstance.md deleted file mode 100644 index 90da2b1..0000000 --- a/Docs/API/interfaces/ArtInstance.md +++ /dev/null @@ -1,94 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ArtInstance - -# Interface: ArtInstance - -Defined in: [src/core/interfaces.ts:480](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L480) - -Represents the fully initialized and configured ART Framework client instance. -This object is the main entry point for interacting with the framework after setup. -It provides access to the core processing method and key subsystems. - -## Properties - -### conversationManager - -> `readonly` **conversationManager**: [`ConversationManager`](ConversationManager.md) - -Defined in: [src/core/interfaces.ts:488](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L488) - -Accessor for the Conversation Manager, used for managing message history. - -*** - -### observationManager - -> `readonly` **observationManager**: [`ObservationManager`](ObservationManager.md) - -Defined in: [src/core/interfaces.ts:492](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L492) - -Accessor for the Observation Manager, used for recording and retrieving observations. - -*** - -### process() - -> `readonly` **process**: (`props`) => `Promise`\<[`AgentFinalResponse`](AgentFinalResponse.md)\> - -Defined in: [src/core/interfaces.ts:482](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L482) - -The main method to process a user query using the configured Agent Core. - -Processes a user query through the configured agent reasoning pattern (e.g., PES). -Orchestrates interactions between various ART subsystems. - -#### Parameters - -##### props - -[`AgentProps`](AgentProps.md) - -The input properties for the agent execution, including the query, thread ID, and injected dependencies. - -#### Returns - -`Promise`\<[`AgentFinalResponse`](AgentFinalResponse.md)\> - -A promise that resolves with the final agent response and execution metadata. - -#### Throws - -If a critical error occurs during orchestration that prevents completion. - -*** - -### stateManager - -> `readonly` **stateManager**: [`StateManager`](StateManager.md) - -Defined in: [src/core/interfaces.ts:486](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L486) - -Accessor for the State Manager, used for managing thread configuration and state. - -*** - -### toolRegistry - -> `readonly` **toolRegistry**: [`ToolRegistry`](ToolRegistry.md) - -Defined in: [src/core/interfaces.ts:490](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L490) - -Accessor for the Tool Registry, used for managing available tools. - -*** - -### uiSystem - -> `readonly` **uiSystem**: [`UISystem`](UISystem.md) - -Defined in: [src/core/interfaces.ts:484](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L484) - -Accessor for the UI System, used to get sockets for subscriptions. diff --git a/Docs/API/interfaces/ArtInstanceConfig.md b/Docs/API/interfaces/ArtInstanceConfig.md deleted file mode 100644 index f30be69..0000000 --- a/Docs/API/interfaces/ArtInstanceConfig.md +++ /dev/null @@ -1,108 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ArtInstanceConfig - -# Interface: ArtInstanceConfig - -Defined in: [src/types/index.ts:610](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L610) - -Configuration for creating an ART instance. - -## Properties - -### agentCore()? - -> `optional` **agentCore**: (`dependencies`) => [`IAgentCore`](IAgentCore.md) - -Defined in: [src/types/index.ts:625](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L625) - -The agent core implementation class to use. -Defaults to `PESAgent` if not provided. -Example: `MyCustomAgentClass` - -#### Parameters - -##### dependencies - -`any` - -#### Returns - -[`IAgentCore`](IAgentCore.md) - -*** - -### defaultSystemPrompt? - -> `optional` **defaultSystemPrompt**: `string` - -Defined in: [src/types/index.ts:646](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L646) - -Optional default system prompt string to be used for the entire ART instance. -This can be overridden at the thread level or at the individual call level. - -*** - -### logger? - -> `optional` **logger**: `object` - -Defined in: [src/types/index.ts:638](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L638) - -Optional configuration for the framework's logger. - -#### level? - -> `optional` **level**: [`LogLevel`](../enumerations/LogLevel.md) - -Minimum log level to output. Defaults to 'info'. - -*** - -### providers - -> **providers**: [`ProviderManagerConfig`](ProviderManagerConfig.md) - -Defined in: [src/types/index.ts:619](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L619) - -Configuration for the ProviderManager, defining available LLM provider adapters. - -*** - -### stateSavingStrategy? - -> `optional` **stateSavingStrategy**: [`StateSavingStrategy`](../type-aliases/StateSavingStrategy.md) - -Defined in: [src/types/index.ts:636](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L636) - -Defines the strategy for saving `AgentState`. Defaults to 'explicit'. -- 'explicit': `AgentState` is only saved when `StateManager.setAgentState()` is explicitly called by the agent. - `StateManager.saveStateIfModified()` will be a no-op for `AgentState` persistence. -- 'implicit': `AgentState` is loaded by `StateManager.loadThreadContext()`. If modified by the agent, - `StateManager.saveStateIfModified()` will attempt to automatically persist these changes. - `StateManager.setAgentState()` will still work for explicit saves in this mode. - -*** - -### storage - -> **storage**: [`StorageAdapter`](StorageAdapter.md) \| \{ `dbName`: `string`; `objectStores`: `any`[]; `type`: `"memory"` \| `"indexedDB"`; `version`: `number`; \} - -Defined in: [src/types/index.ts:617](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L617) - -Configuration for the storage adapter. -Can be a pre-configured `StorageAdapter` instance, -or an object specifying the type and options for a built-in adapter. -Example: `{ type: 'indexedDB', dbName: 'MyArtDB' }` - -*** - -### tools? - -> `optional` **tools**: [`IToolExecutor`](IToolExecutor.md)[] - -Defined in: [src/types/index.ts:627](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L627) - -An optional array of tool executor instances to register at initialization. diff --git a/Docs/API/interfaces/ArtStandardMessage.md b/Docs/API/interfaces/ArtStandardMessage.md deleted file mode 100644 index 458c65b..0000000 --- a/Docs/API/interfaces/ArtStandardMessage.md +++ /dev/null @@ -1,101 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ArtStandardMessage - -# Interface: ArtStandardMessage - -Defined in: [src/types/index.ts:457](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L457) - -Represents a single message in the standardized, provider-agnostic `ArtStandardPrompt` format. -This structure aims to capture common message elements used by various LLM APIs. - -## Properties - -### content - -> **content**: `null` \| `string` \| `object` - -Defined in: [src/types/index.ts:468](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L468) - -The primary content of the message. The type and interpretation depend on the `role`: -- `system`: string (The system instruction). -- `user`: string (The user's text input). -- `assistant`: string | null (The AI's text response, or null/empty if only making `tool_calls`). -- `tool_request`: object | null (Structured representation of the tool call, often implicitly handled via `assistant` message's `tool_calls`). -- `tool_result`: string (Stringified JSON output or error message from the tool execution). - -*** - -### name? - -> `optional` **name**: `string` - -Defined in: [src/types/index.ts:470](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L470) - -Optional name associated with the message. Primarily used for `tool_result` role to specify the name of the tool that was executed. - -*** - -### role - -> **role**: [`ArtStandardMessageRole`](../type-aliases/ArtStandardMessageRole.md) - -Defined in: [src/types/index.ts:459](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L459) - -The role indicating the source or type of the message. - -*** - -### tool\_call\_id? - -> `optional` **tool\_call\_id**: `string` - -Defined in: [src/types/index.ts:494](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L494) - -Optional identifier linking a 'tool_result' message back to the specific 'tool_calls' entry -in the preceding 'assistant' message that requested it. -Required for 'tool_result' role. - -*** - -### tool\_calls? - -> `optional` **tool\_calls**: `object`[] - -Defined in: [src/types/index.ts:476](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L476) - -Optional array of tool calls requested by the assistant. -Only relevant for 'assistant' role messages that trigger tool usage. -Structure mirrors common provider formats (e.g., OpenAI). - -#### function - -> **function**: `object` - -Details of the function to be called. - -##### function.arguments - -> **arguments**: `string` - -A stringified JSON object representing the arguments for the function. - -##### function.name - -> **name**: `string` - -The name of the function/tool to call. - -#### id - -> **id**: `string` - -A unique identifier for this specific tool call request. - -#### type - -> **type**: `"function"` - -The type of the tool call, typically 'function'. diff --git a/Docs/API/interfaces/AvailableProviderEntry.md b/Docs/API/interfaces/AvailableProviderEntry.md deleted file mode 100644 index 318f353..0000000 --- a/Docs/API/interfaces/AvailableProviderEntry.md +++ /dev/null @@ -1,53 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / AvailableProviderEntry - -# Interface: AvailableProviderEntry - -Defined in: [src/types/providers.ts:6](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L6) - -Entry defining an available provider adapter - -## Properties - -### adapter() - -> **adapter**: (`options`) => [`ProviderAdapter`](ProviderAdapter.md) - -Defined in: [src/types/providers.ts:8](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L8) - -#### Parameters - -##### options - -`any` - -#### Returns - -[`ProviderAdapter`](ProviderAdapter.md) - -*** - -### baseOptions? - -> `optional` **baseOptions**: `any` - -Defined in: [src/types/providers.ts:9](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L9) - -*** - -### isLocal? - -> `optional` **isLocal**: `boolean` - -Defined in: [src/types/providers.ts:10](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L10) - -*** - -### name - -> **name**: `string` - -Defined in: [src/types/providers.ts:7](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L7) diff --git a/Docs/API/interfaces/CallOptions.md b/Docs/API/interfaces/CallOptions.md deleted file mode 100644 index 887bcb9..0000000 --- a/Docs/API/interfaces/CallOptions.md +++ /dev/null @@ -1,90 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / CallOptions - -# Interface: CallOptions - -Defined in: [src/types/index.ts:407](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L407) - -Options for configuring an LLM call, including streaming and context information. - -## Indexable - -\[`key`: `string`\]: `any` - -Additional key-value pairs representing provider-specific parameters (e.g., `temperature`, `max_tokens`, `top_p`). These often override defaults set in `ThreadConfig`. - -## Properties - -### callContext? - -> `optional` **callContext**: `string` - -Defined in: [src/types/index.ts:426](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L426) - -Provides context for the LLM call, allowing adapters to differentiate -between agent-level thoughts and final synthesis calls for token typing. -Agent Core MUST provide this. - -*** - -### providerConfig - -> **providerConfig**: [`RuntimeProviderConfig`](RuntimeProviderConfig.md) - -Defined in: [src/types/index.ts:432](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L432) - -Carries the specific target provider and configuration for this call. - -*** - -### sessionId? - -> `optional` **sessionId**: `string` - -Defined in: [src/types/index.ts:415](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L415) - -Optional session ID. - -*** - -### stream? - -> `optional` **stream**: `boolean` - -Defined in: [src/types/index.ts:420](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L420) - -Request a streaming response from the LLM provider. -Adapters MUST check this flag. - -*** - -### threadId - -> **threadId**: `string` - -Defined in: [src/types/index.ts:409](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L409) - -The mandatory thread ID, used by the ReasoningEngine to fetch thread-specific configuration (e.g., model, params) via StateManager. - -*** - -### traceId? - -> `optional` **traceId**: `string` - -Defined in: [src/types/index.ts:411](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L411) - -Optional trace ID for correlation. - -*** - -### userId? - -> `optional` **userId**: `string` - -Defined in: [src/types/index.ts:413](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L413) - -Optional user ID. diff --git a/Docs/API/interfaces/ConversationManager.md b/Docs/API/interfaces/ConversationManager.md deleted file mode 100644 index d4ba30d..0000000 --- a/Docs/API/interfaces/ConversationManager.md +++ /dev/null @@ -1,72 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ConversationManager - -# Interface: ConversationManager - -Defined in: [src/core/interfaces.ts:292](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L292) - -Interface for managing conversation history. - -## Methods - -### addMessages() - -> **addMessages**(`threadId`, `messages`): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:300](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L300) - -Appends one or more `ConversationMessage` objects to the history of a specific thread. -Typically called at the end of an execution cycle to save the user query and the final AI response. - -#### Parameters - -##### threadId - -`string` - -The ID of the thread to add messages to. - -##### messages - -[`ConversationMessage`](ConversationMessage.md)[] - -An array containing the `ConversationMessage` objects to add. - -#### Returns - -`Promise`\<`void`\> - -A promise that resolves when the messages have been successfully added to storage. - -*** - -### getMessages() - -> **getMessages**(`threadId`, `options`?): `Promise`\<[`ConversationMessage`](ConversationMessage.md)[]\> - -Defined in: [src/core/interfaces.ts:308](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L308) - -Retrieves messages from a specific thread's history, usually in reverse chronological order. - -#### Parameters - -##### threadId - -`string` - -The ID of the thread whose history is needed. - -##### options? - -[`MessageOptions`](MessageOptions.md) - -Optional parameters to control retrieval, such as `limit` (max number of messages) or `beforeTimestamp` (for pagination). See `MessageOptions` type. - -#### Returns - -`Promise`\<[`ConversationMessage`](ConversationMessage.md)[]\> - -A promise resolving to an array of `ConversationMessage` objects, ordered according to the implementation (typically newest first if not specified otherwise). diff --git a/Docs/API/interfaces/ConversationMessage.md b/Docs/API/interfaces/ConversationMessage.md deleted file mode 100644 index 43cea0a..0000000 --- a/Docs/API/interfaces/ConversationMessage.md +++ /dev/null @@ -1,71 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ConversationMessage - -# Interface: ConversationMessage - -Defined in: [src/types/index.ts:48](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L48) - -Represents a single message within a conversation thread. - -## Properties - -### content - -> **content**: `string` - -Defined in: [src/types/index.ts:56](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L56) - -The textual content of the message. - -*** - -### messageId - -> **messageId**: `string` - -Defined in: [src/types/index.ts:50](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L50) - -A unique identifier for this specific message. - -*** - -### metadata? - -> `optional` **metadata**: `Record`\<`string`, `any`\> - -Defined in: [src/types/index.ts:60](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L60) - -Optional metadata associated with the message (e.g., related observation IDs, tool call info, UI state). - -*** - -### role - -> **role**: [`MessageRole`](../enumerations/MessageRole.md) - -Defined in: [src/types/index.ts:54](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L54) - -The role of the sender (User, AI, System, or Tool). - -*** - -### threadId - -> **threadId**: `string` - -Defined in: [src/types/index.ts:52](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L52) - -The identifier of the conversation thread this message belongs to. - -*** - -### timestamp - -> **timestamp**: `number` - -Defined in: [src/types/index.ts:58](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L58) - -A Unix timestamp (in milliseconds) indicating when the message was created. diff --git a/Docs/API/interfaces/ConversationSocket.md b/Docs/API/interfaces/ConversationSocket.md deleted file mode 100644 index ea2f95f..0000000 --- a/Docs/API/interfaces/ConversationSocket.md +++ /dev/null @@ -1,138 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ConversationSocket - -# Interface: ConversationSocket - -Defined in: [src/core/interfaces.ts:384](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L384) - -TypedSocket specifically for ConversationMessage data. -FilterType is MessageRole or array of MessageRole. - -## Extends - -- [`ITypedSocket`](ITypedSocket.md)\<[`ConversationMessage`](ConversationMessage.md), [`MessageRole`](../enumerations/MessageRole.md) \| [`MessageRole`](../enumerations/MessageRole.md)[]\> - -## Methods - -### getHistory()? - -> `optional` **getHistory**(`filter`?, `options`?): `Promise`\<[`ConversationMessage`](ConversationMessage.md)[]\> - -Defined in: [src/core/interfaces.ts:368](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L368) - -Optional method to retrieve historical data from the socket's source. - -#### Parameters - -##### filter? - -Optional filter criteria. - -[`MessageRole`](../enumerations/MessageRole.md) | [`MessageRole`](../enumerations/MessageRole.md)[] - -##### options? - -Optional configuration like threadId and limit. - -###### limit? - -`number` - -###### threadId? - -`string` - -#### Returns - -`Promise`\<[`ConversationMessage`](ConversationMessage.md)[]\> - -#### Inherited from - -[`ITypedSocket`](ITypedSocket.md).[`getHistory`](ITypedSocket.md#gethistory) - -*** - -### notify() - -> **notify**(`data`, `options`?): `void` - -Defined in: [src/core/interfaces.ts:358](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L358) - -Notifies subscribers of new data. - -#### Parameters - -##### data - -[`ConversationMessage`](ConversationMessage.md) - -The data payload. - -##### options? - -Optional targeting information (e.g., specific thread). - -###### targetSessionId? - -`string` - -###### targetThreadId? - -`string` - -#### Returns - -`void` - -#### Inherited from - -[`ITypedSocket`](ITypedSocket.md).[`notify`](ITypedSocket.md#notify) - -*** - -### subscribe() - -> **subscribe**(`callback`, `filter`?, `options`?): () => `void` - -Defined in: [src/core/interfaces.ts:347](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L347) - -Subscribes a callback function to receive data updates. - -#### Parameters - -##### callback - -(`data`) => `void` - -The function to call with new data. - -##### filter? - -Optional filter criteria specific to the socket type. - -[`MessageRole`](../enumerations/MessageRole.md) | [`MessageRole`](../enumerations/MessageRole.md)[] - -##### options? - -Optional configuration like target threadId. - -###### threadId? - -`string` - -#### Returns - -An unsubscribe function. - -> (): `void` - -##### Returns - -`void` - -#### Inherited from - -[`ITypedSocket`](ITypedSocket.md).[`subscribe`](ITypedSocket.md#subscribe) diff --git a/Docs/API/interfaces/ExecutionContext.md b/Docs/API/interfaces/ExecutionContext.md deleted file mode 100644 index 7a5e96d..0000000 --- a/Docs/API/interfaces/ExecutionContext.md +++ /dev/null @@ -1,41 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ExecutionContext - -# Interface: ExecutionContext - -Defined in: [src/types/index.ts:393](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L393) - -Context provided to a tool during its execution. - -## Properties - -### threadId - -> **threadId**: `string` - -Defined in: [src/types/index.ts:395](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L395) - -The ID of the thread in which the tool is being executed. - -*** - -### traceId? - -> `optional` **traceId**: `string` - -Defined in: [src/types/index.ts:397](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L397) - -The trace ID for this execution cycle, if available. - -*** - -### userId? - -> `optional` **userId**: `string` - -Defined in: [src/types/index.ts:399](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L399) - -The user ID associated with the execution, if available. diff --git a/Docs/API/interfaces/ExecutionMetadata.md b/Docs/API/interfaces/ExecutionMetadata.md deleted file mode 100644 index f0b8ac2..0000000 --- a/Docs/API/interfaces/ExecutionMetadata.md +++ /dev/null @@ -1,111 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ExecutionMetadata - -# Interface: ExecutionMetadata - -Defined in: [src/types/index.ts:367](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L367) - -Metadata summarizing an agent execution cycle, including performance metrics and outcomes. - -## Properties - -### error? - -> `optional` **error**: `string` - -Defined in: [src/types/index.ts:385](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L385) - -A top-level error message if the overall status is 'error' or 'partial'. - -*** - -### llmCalls - -> **llmCalls**: `number` - -Defined in: [src/types/index.ts:379](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L379) - -The number of calls made to the `ReasoningEngine`. - -*** - -### llmCost? - -> `optional` **llmCost**: `number` - -Defined in: [src/types/index.ts:383](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L383) - -An optional estimated cost for the LLM calls made during this execution. - -*** - -### llmMetadata? - -> `optional` **llmMetadata**: [`LLMMetadata`](LLMMetadata.md) - -Defined in: [src/types/index.ts:387](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L387) - -Aggregated metadata from LLM calls made during the execution. - -*** - -### status - -> **status**: `"success"` \| `"error"` \| `"partial"` - -Defined in: [src/types/index.ts:375](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L375) - -The overall status of the execution ('success', 'error', or 'partial' if some steps failed but a response was generated). - -*** - -### threadId - -> **threadId**: `string` - -Defined in: [src/types/index.ts:369](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L369) - -The thread ID associated with this execution cycle. - -*** - -### toolCalls - -> **toolCalls**: `number` - -Defined in: [src/types/index.ts:381](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L381) - -The number of tool execution attempts made by the `ToolSystem`. - -*** - -### totalDurationMs - -> **totalDurationMs**: `number` - -Defined in: [src/types/index.ts:377](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L377) - -The total duration of the `agent.process()` call in milliseconds. - -*** - -### traceId? - -> `optional` **traceId**: `string` - -Defined in: [src/types/index.ts:371](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L371) - -The trace ID used during this execution, if provided. - -*** - -### userId? - -> `optional` **userId**: `string` - -Defined in: [src/types/index.ts:373](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L373) - -The user ID associated with the execution, if provided. diff --git a/Docs/API/interfaces/FilterOptions.md b/Docs/API/interfaces/FilterOptions.md deleted file mode 100644 index 6283aed..0000000 --- a/Docs/API/interfaces/FilterOptions.md +++ /dev/null @@ -1,52 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / FilterOptions - -# Interface: FilterOptions - -Defined in: [src/types/index.ts:551](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L551) - -Options for filtering data retrieved from storage. -Structure depends heavily on the underlying adapter's capabilities. - -## Properties - -### filter? - -> `optional` **filter**: `Record`\<`string`, `any`\> - -Defined in: [src/types/index.ts:553](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L553) - -An object defining filter criteria (e.g., `{ threadId: 'abc', type: 'TOOL_EXECUTION' }`). Structure may depend on adapter capabilities. - -*** - -### limit? - -> `optional` **limit**: `number` - -Defined in: [src/types/index.ts:557](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L557) - -The maximum number of records to return. - -*** - -### skip? - -> `optional` **skip**: `number` - -Defined in: [src/types/index.ts:559](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L559) - -The number of records to skip (for pagination). - -*** - -### sort? - -> `optional` **sort**: `Record`\<`string`, `"asc"` \| `"desc"`\> - -Defined in: [src/types/index.ts:555](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L555) - -An object defining sorting criteria (e.g., `{ timestamp: 'desc' }`). diff --git a/Docs/API/interfaces/IAgentCore.md b/Docs/API/interfaces/IAgentCore.md deleted file mode 100644 index c7952e7..0000000 --- a/Docs/API/interfaces/IAgentCore.md +++ /dev/null @@ -1,40 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / IAgentCore - -# Interface: IAgentCore - -Defined in: [src/core/interfaces.ts:54](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L54) - -Interface for the central agent orchestrator. - -## Methods - -### process() - -> **process**(`props`): `Promise`\<[`AgentFinalResponse`](AgentFinalResponse.md)\> - -Defined in: [src/core/interfaces.ts:62](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L62) - -Processes a user query through the configured agent reasoning pattern (e.g., PES). -Orchestrates interactions between various ART subsystems. - -#### Parameters - -##### props - -[`AgentProps`](AgentProps.md) - -The input properties for the agent execution, including the query, thread ID, and injected dependencies. - -#### Returns - -`Promise`\<[`AgentFinalResponse`](AgentFinalResponse.md)\> - -A promise that resolves with the final agent response and execution metadata. - -#### Throws - -If a critical error occurs during orchestration that prevents completion. diff --git a/Docs/API/interfaces/IConversationRepository.md b/Docs/API/interfaces/IConversationRepository.md deleted file mode 100644 index a06ab52..0000000 --- a/Docs/API/interfaces/IConversationRepository.md +++ /dev/null @@ -1,55 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / IConversationRepository - -# Interface: IConversationRepository - -Defined in: [src/core/interfaces.ts:452](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L452) - -Repository for managing ConversationMessages. - -## Methods - -### addMessages() - -> **addMessages**(`threadId`, `messages`): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:453](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L453) - -#### Parameters - -##### threadId - -`string` - -##### messages - -[`ConversationMessage`](ConversationMessage.md)[] - -#### Returns - -`Promise`\<`void`\> - -*** - -### getMessages() - -> **getMessages**(`threadId`, `options`?): `Promise`\<[`ConversationMessage`](ConversationMessage.md)[]\> - -Defined in: [src/core/interfaces.ts:454](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L454) - -#### Parameters - -##### threadId - -`string` - -##### options? - -[`MessageOptions`](MessageOptions.md) - -#### Returns - -`Promise`\<[`ConversationMessage`](ConversationMessage.md)[]\> diff --git a/Docs/API/interfaces/IObservationRepository.md b/Docs/API/interfaces/IObservationRepository.md deleted file mode 100644 index e153133..0000000 --- a/Docs/API/interfaces/IObservationRepository.md +++ /dev/null @@ -1,51 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / IObservationRepository - -# Interface: IObservationRepository - -Defined in: [src/core/interfaces.ts:459](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L459) - -Repository for managing Observations. - -## Methods - -### addObservation() - -> **addObservation**(`observation`): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:460](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L460) - -#### Parameters - -##### observation - -[`Observation`](Observation.md) - -#### Returns - -`Promise`\<`void`\> - -*** - -### getObservations() - -> **getObservations**(`threadId`, `filter`?): `Promise`\<[`Observation`](Observation.md)[]\> - -Defined in: [src/core/interfaces.ts:461](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L461) - -#### Parameters - -##### threadId - -`string` - -##### filter? - -[`ObservationFilter`](ObservationFilter.md) - -#### Returns - -`Promise`\<[`Observation`](Observation.md)[]\> diff --git a/Docs/API/interfaces/IProviderManager.md b/Docs/API/interfaces/IProviderManager.md deleted file mode 100644 index d059394..0000000 --- a/Docs/API/interfaces/IProviderManager.md +++ /dev/null @@ -1,47 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / IProviderManager - -# Interface: IProviderManager - -Defined in: [src/types/providers.ts:34](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L34) - -Interface for the ProviderManager - -## Methods - -### getAdapter() - -> **getAdapter**(`config`): `Promise`\<[`ManagedAdapterAccessor`](ManagedAdapterAccessor.md)\> - -Defined in: [src/types/providers.ts:43](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L43) - -Gets a managed adapter instance based on the runtime config. -Handles instance creation, caching, pooling limits, and singleton constraints. -May queue requests or throw errors based on concurrency limits. - -#### Parameters - -##### config - -[`RuntimeProviderConfig`](RuntimeProviderConfig.md) - -#### Returns - -`Promise`\<[`ManagedAdapterAccessor`](ManagedAdapterAccessor.md)\> - -*** - -### getAvailableProviders() - -> **getAvailableProviders**(): `string`[] - -Defined in: [src/types/providers.ts:36](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L36) - -Returns identifiers for all registered potential providers - -#### Returns - -`string`[] diff --git a/Docs/API/interfaces/IStateRepository.md b/Docs/API/interfaces/IStateRepository.md deleted file mode 100644 index 0a80c97..0000000 --- a/Docs/API/interfaces/IStateRepository.md +++ /dev/null @@ -1,131 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / IStateRepository - -# Interface: IStateRepository - -Defined in: [src/core/interfaces.ts:465](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L465) - -Repository for managing ThreadConfig and AgentState. - -## Methods - -### getAgentState() - -> **getAgentState**(`threadId`): `Promise`\<`null` \| [`AgentState`](AgentState.md)\> - -Defined in: [src/core/interfaces.ts:468](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L468) - -#### Parameters - -##### threadId - -`string` - -#### Returns - -`Promise`\<`null` \| [`AgentState`](AgentState.md)\> - -*** - -### getThreadConfig() - -> **getThreadConfig**(`threadId`): `Promise`\<`null` \| [`ThreadConfig`](ThreadConfig.md)\> - -Defined in: [src/core/interfaces.ts:466](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L466) - -#### Parameters - -##### threadId - -`string` - -#### Returns - -`Promise`\<`null` \| [`ThreadConfig`](ThreadConfig.md)\> - -*** - -### getThreadContext() - -> **getThreadContext**(`threadId`): `Promise`\<`null` \| [`ThreadContext`](ThreadContext.md)\> - -Defined in: [src/core/interfaces.ts:471](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L471) - -#### Parameters - -##### threadId - -`string` - -#### Returns - -`Promise`\<`null` \| [`ThreadContext`](ThreadContext.md)\> - -*** - -### setAgentState() - -> **setAgentState**(`threadId`, `state`): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:469](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L469) - -#### Parameters - -##### threadId - -`string` - -##### state - -[`AgentState`](AgentState.md) - -#### Returns - -`Promise`\<`void`\> - -*** - -### setThreadConfig() - -> **setThreadConfig**(`threadId`, `config`): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:467](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L467) - -#### Parameters - -##### threadId - -`string` - -##### config - -[`ThreadConfig`](ThreadConfig.md) - -#### Returns - -`Promise`\<`void`\> - -*** - -### setThreadContext() - -> **setThreadContext**(`threadId`, `context`): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:472](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L472) - -#### Parameters - -##### threadId - -`string` - -##### context - -[`ThreadContext`](ThreadContext.md) - -#### Returns - -`Promise`\<`void`\> diff --git a/Docs/API/interfaces/IToolExecutor.md b/Docs/API/interfaces/IToolExecutor.md deleted file mode 100644 index ff48adc..0000000 --- a/Docs/API/interfaces/IToolExecutor.md +++ /dev/null @@ -1,51 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / IToolExecutor - -# Interface: IToolExecutor - -Defined in: [src/core/interfaces.ts:164](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L164) - -Interface for the executable logic of a tool. - -## Properties - -### schema - -> `readonly` **schema**: [`ToolSchema`](ToolSchema.md) - -Defined in: [src/core/interfaces.ts:166](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L166) - -The schema definition for this tool. - -## Methods - -### execute() - -> **execute**(`input`, `context`): `Promise`\<[`ToolResult`](ToolResult.md)\> - -Defined in: [src/core/interfaces.ts:174](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L174) - -Executes the tool's logic. - -#### Parameters - -##### input - -`any` - -Validated input arguments matching the tool's inputSchema. - -##### context - -[`ExecutionContext`](ExecutionContext.md) - -Execution context containing threadId, traceId, etc. - -#### Returns - -`Promise`\<[`ToolResult`](ToolResult.md)\> - -A promise resolving to the structured tool result. diff --git a/Docs/API/interfaces/ITypedSocket.md b/Docs/API/interfaces/ITypedSocket.md deleted file mode 100644 index ac4205c..0000000 --- a/Docs/API/interfaces/ITypedSocket.md +++ /dev/null @@ -1,136 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ITypedSocket - -# Interface: ITypedSocket\<DataType, FilterType\> - -Defined in: [src/core/interfaces.ts:339](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L339) - -Generic interface for a typed publish/subscribe socket. - -## Extended by - -- [`ObservationSocket`](ObservationSocket.md) -- [`ConversationSocket`](ConversationSocket.md) - -## Type Parameters - -### DataType - -`DataType` - -### FilterType - -`FilterType` = `any` - -## Methods - -### getHistory()? - -> `optional` **getHistory**(`filter`?, `options`?): `Promise`\<`DataType`[]\> - -Defined in: [src/core/interfaces.ts:368](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L368) - -Optional method to retrieve historical data from the socket's source. - -#### Parameters - -##### filter? - -`FilterType` - -Optional filter criteria. - -##### options? - -Optional configuration like threadId and limit. - -###### limit? - -`number` - -###### threadId? - -`string` - -#### Returns - -`Promise`\<`DataType`[]\> - -*** - -### notify() - -> **notify**(`data`, `options`?): `void` - -Defined in: [src/core/interfaces.ts:358](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L358) - -Notifies subscribers of new data. - -#### Parameters - -##### data - -`DataType` - -The data payload. - -##### options? - -Optional targeting information (e.g., specific thread). - -###### targetSessionId? - -`string` - -###### targetThreadId? - -`string` - -#### Returns - -`void` - -*** - -### subscribe() - -> **subscribe**(`callback`, `filter`?, `options`?): () => `void` - -Defined in: [src/core/interfaces.ts:347](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L347) - -Subscribes a callback function to receive data updates. - -#### Parameters - -##### callback - -(`data`) => `void` - -The function to call with new data. - -##### filter? - -`FilterType` - -Optional filter criteria specific to the socket type. - -##### options? - -Optional configuration like target threadId. - -###### threadId? - -`string` - -#### Returns - -An unsubscribe function. - -> (): `void` - -##### Returns - -`void` diff --git a/Docs/API/interfaces/JsonObjectSchema.md b/Docs/API/interfaces/JsonObjectSchema.md deleted file mode 100644 index 5876135..0000000 --- a/Docs/API/interfaces/JsonObjectSchema.md +++ /dev/null @@ -1,48 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / JsonObjectSchema - -# Interface: JsonObjectSchema - -Defined in: [src/types/index.ts:185](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L185) - -Represents a basic JSON Schema definition, focusing on object types commonly used for tool inputs/outputs. -This is a simplified representation and doesn't cover all JSON Schema features. - -## Properties - -### additionalProperties? - -> `optional` **additionalProperties**: `boolean` - -Defined in: [src/types/index.ts:200](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L200) - -*** - -### properties - -> **properties**: `object` - -Defined in: [src/types/index.ts:187](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L187) - -#### Index Signature - -\[`key`: `string`\]: `object` - -*** - -### required? - -> `optional` **required**: `string`[] - -Defined in: [src/types/index.ts:199](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L199) - -*** - -### type - -> **type**: `"object"` - -Defined in: [src/types/index.ts:186](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L186) diff --git a/Docs/API/interfaces/LLMMetadata.md b/Docs/API/interfaces/LLMMetadata.md deleted file mode 100644 index 150b90c..0000000 --- a/Docs/API/interfaces/LLMMetadata.md +++ /dev/null @@ -1,92 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / LLMMetadata - -# Interface: LLMMetadata - -Defined in: [src/types/index.ts:210](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L210) - -Structure for holding metadata about an LLM call, typically received via a `METADATA` `StreamEvent` -or parsed from a non-streaming response. Fields are optional as availability varies by provider and stream state. - -## Properties - -### inputTokens? - -> `optional` **inputTokens**: `number` - -Defined in: [src/types/index.ts:212](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L212) - -The number of tokens in the input prompt, if available. - -*** - -### outputTokens? - -> `optional` **outputTokens**: `number` - -Defined in: [src/types/index.ts:214](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L214) - -The number of tokens generated in the output response, if available. - -*** - -### providerRawUsage? - -> `optional` **providerRawUsage**: `any` - -Defined in: [src/types/index.ts:224](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L224) - -Optional raw usage data provided directly by the LLM provider for extensibility (structure depends on provider). - -*** - -### stopReason? - -> `optional` **stopReason**: `string` - -Defined in: [src/types/index.ts:222](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L222) - -The reason the LLM stopped generating tokens (e.g., 'stop_sequence', 'max_tokens', 'tool_calls'), if available. - -*** - -### thinkingTokens? - -> `optional` **thinkingTokens**: `number` - -Defined in: [src/types/index.ts:216](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L216) - -The number of tokens identified as part of the LLM's internal thinking process (if available from provider). - -*** - -### timeToFirstTokenMs? - -> `optional` **timeToFirstTokenMs**: `number` - -Defined in: [src/types/index.ts:218](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L218) - -The time elapsed (in milliseconds) until the first token was generated in a streaming response, if applicable and available. - -*** - -### totalGenerationTimeMs? - -> `optional` **totalGenerationTimeMs**: `number` - -Defined in: [src/types/index.ts:220](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L220) - -The total time elapsed (in milliseconds) for the entire generation process, if available. - -*** - -### traceId? - -> `optional` **traceId**: `string` - -Defined in: [src/types/index.ts:226](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L226) - -The trace ID associated with the LLM call, useful for correlating metadata with the specific request. diff --git a/Docs/API/interfaces/ManagedAdapterAccessor.md b/Docs/API/interfaces/ManagedAdapterAccessor.md deleted file mode 100644 index 8349c91..0000000 --- a/Docs/API/interfaces/ManagedAdapterAccessor.md +++ /dev/null @@ -1,33 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ManagedAdapterAccessor - -# Interface: ManagedAdapterAccessor - -Defined in: [src/types/providers.ts:28](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L28) - -Object returned by ProviderManager granting access to an adapter instance - -## Properties - -### adapter - -> **adapter**: [`ProviderAdapter`](ProviderAdapter.md) - -Defined in: [src/types/providers.ts:29](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L29) - -*** - -### release() - -> **release**: () => `void` - -Defined in: [src/types/providers.ts:31](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L31) - -Signals that the current call using this adapter instance is finished. - -#### Returns - -`void` diff --git a/Docs/API/interfaces/MessageOptions.md b/Docs/API/interfaces/MessageOptions.md deleted file mode 100644 index 7f8a060..0000000 --- a/Docs/API/interfaces/MessageOptions.md +++ /dev/null @@ -1,51 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / MessageOptions - -# Interface: MessageOptions - -Defined in: [src/types/index.ts:566](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L566) - -Options for retrieving conversation messages. - -## Properties - -### afterTimestamp? - -> `optional` **afterTimestamp**: `number` - -Defined in: [src/types/index.ts:572](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L572) - -Retrieve messages created after this Unix timestamp (milliseconds). - -*** - -### beforeTimestamp? - -> `optional` **beforeTimestamp**: `number` - -Defined in: [src/types/index.ts:570](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L570) - -Retrieve messages created before this Unix timestamp (milliseconds). - -*** - -### limit? - -> `optional` **limit**: `number` - -Defined in: [src/types/index.ts:568](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L568) - -The maximum number of messages to retrieve. - -*** - -### roles? - -> `optional` **roles**: [`MessageRole`](../enumerations/MessageRole.md)[] - -Defined in: [src/types/index.ts:574](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L574) - -Optionally filter messages by role (e.g., retrieve only 'AI' messages). diff --git a/Docs/API/interfaces/Observation.md b/Docs/API/interfaces/Observation.md deleted file mode 100644 index bc84d5c..0000000 --- a/Docs/API/interfaces/Observation.md +++ /dev/null @@ -1,91 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / Observation - -# Interface: Observation - -Defined in: [src/types/index.ts:114](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L114) - -Represents a recorded event during the agent's execution. - -## Properties - -### content - -> **content**: `any` - -Defined in: [src/types/index.ts:128](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L128) - -The main data payload of the observation, structure depends on the `type`. - -*** - -### id - -> **id**: `string` - -Defined in: [src/types/index.ts:116](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L116) - -A unique identifier for this specific observation record. - -*** - -### metadata? - -> `optional` **metadata**: `Record`\<`string`, `any`\> - -Defined in: [src/types/index.ts:130](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L130) - -Optional metadata providing additional context (e.g., source phase, related IDs, status). - -*** - -### threadId - -> **threadId**: `string` - -Defined in: [src/types/index.ts:118](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L118) - -The identifier of the conversation thread this observation relates to. - -*** - -### timestamp - -> **timestamp**: `number` - -Defined in: [src/types/index.ts:122](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L122) - -A Unix timestamp (in milliseconds) indicating when the observation was recorded. - -*** - -### title - -> **title**: `string` - -Defined in: [src/types/index.ts:126](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L126) - -A concise, human-readable title summarizing the observation (often generated based on type/metadata). - -*** - -### traceId? - -> `optional` **traceId**: `string` - -Defined in: [src/types/index.ts:120](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L120) - -An optional identifier for tracing a request across multiple systems or components. - -*** - -### type - -> **type**: [`ObservationType`](../enumerations/ObservationType.md) - -Defined in: [src/types/index.ts:124](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L124) - -The category of the event being observed (e.g., PLAN, THOUGHTS, TOOL_EXECUTION). diff --git a/Docs/API/interfaces/ObservationFilter.md b/Docs/API/interfaces/ObservationFilter.md deleted file mode 100644 index 7c9a0fd..0000000 --- a/Docs/API/interfaces/ObservationFilter.md +++ /dev/null @@ -1,41 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ObservationFilter - -# Interface: ObservationFilter - -Defined in: [src/types/index.ts:580](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L580) - -Options for filtering observations. - -## Properties - -### afterTimestamp? - -> `optional` **afterTimestamp**: `number` - -Defined in: [src/types/index.ts:586](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L586) - -Retrieve observations recorded after this Unix timestamp (milliseconds). - -*** - -### beforeTimestamp? - -> `optional` **beforeTimestamp**: `number` - -Defined in: [src/types/index.ts:584](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L584) - -Retrieve observations recorded before this Unix timestamp (milliseconds). - -*** - -### types? - -> `optional` **types**: [`ObservationType`](../enumerations/ObservationType.md)[] - -Defined in: [src/types/index.ts:582](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L582) - -An array of `ObservationType` enums to filter by. If provided, only observations matching these types are returned. diff --git a/Docs/API/interfaces/ObservationManager.md b/Docs/API/interfaces/ObservationManager.md deleted file mode 100644 index d53779c..0000000 --- a/Docs/API/interfaces/ObservationManager.md +++ /dev/null @@ -1,67 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ObservationManager - -# Interface: ObservationManager - -Defined in: [src/core/interfaces.ts:317](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L317) - -Interface for managing the recording and retrieval of observations. - -## Methods - -### getObservations() - -> **getObservations**(`threadId`, `filter`?): `Promise`\<[`Observation`](Observation.md)[]\> - -Defined in: [src/core/interfaces.ts:333](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L333) - -Retrieves historical observations stored for a specific thread. - -#### Parameters - -##### threadId - -`string` - -The ID of the thread whose observations are to be retrieved. - -##### filter? - -[`ObservationFilter`](ObservationFilter.md) - -Optional criteria to filter the observations, e.g., by `ObservationType`. See `ObservationFilter`. - -#### Returns - -`Promise`\<[`Observation`](Observation.md)[]\> - -A promise resolving to an array of `Observation` objects matching the criteria. - -*** - -### record() - -> **record**(`observationData`): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:325](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L325) - -Creates, persists, and broadcasts a new observation record. -This is the primary method used by other systems to log significant events. -It automatically generates a unique ID, timestamp, and potentially a title. - -#### Parameters - -##### observationData - -`Omit`\<[`Observation`](Observation.md), `"id"` \| `"timestamp"` \| `"title"`\> - -An object containing the core data for the observation (`threadId`, `type`, `content`, `metadata`, etc.), excluding fields generated by the manager (`id`, `timestamp`, `title`). - -#### Returns - -`Promise`\<`void`\> - -A promise that resolves when the observation has been recorded and notified. diff --git a/Docs/API/interfaces/ObservationSocket.md b/Docs/API/interfaces/ObservationSocket.md deleted file mode 100644 index 4e84b39..0000000 --- a/Docs/API/interfaces/ObservationSocket.md +++ /dev/null @@ -1,138 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ObservationSocket - -# Interface: ObservationSocket - -Defined in: [src/core/interfaces.ts:378](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L378) - -TypedSocket specifically for Observation data. -FilterType is ObservationType or array of ObservationType. - -## Extends - -- [`ITypedSocket`](ITypedSocket.md)\<[`Observation`](Observation.md), [`ObservationType`](../enumerations/ObservationType.md) \| [`ObservationType`](../enumerations/ObservationType.md)[]\> - -## Methods - -### getHistory()? - -> `optional` **getHistory**(`filter`?, `options`?): `Promise`\<[`Observation`](Observation.md)[]\> - -Defined in: [src/core/interfaces.ts:368](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L368) - -Optional method to retrieve historical data from the socket's source. - -#### Parameters - -##### filter? - -Optional filter criteria. - -[`ObservationType`](../enumerations/ObservationType.md) | [`ObservationType`](../enumerations/ObservationType.md)[] - -##### options? - -Optional configuration like threadId and limit. - -###### limit? - -`number` - -###### threadId? - -`string` - -#### Returns - -`Promise`\<[`Observation`](Observation.md)[]\> - -#### Inherited from - -[`ITypedSocket`](ITypedSocket.md).[`getHistory`](ITypedSocket.md#gethistory) - -*** - -### notify() - -> **notify**(`data`, `options`?): `void` - -Defined in: [src/core/interfaces.ts:358](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L358) - -Notifies subscribers of new data. - -#### Parameters - -##### data - -[`Observation`](Observation.md) - -The data payload. - -##### options? - -Optional targeting information (e.g., specific thread). - -###### targetSessionId? - -`string` - -###### targetThreadId? - -`string` - -#### Returns - -`void` - -#### Inherited from - -[`ITypedSocket`](ITypedSocket.md).[`notify`](ITypedSocket.md#notify) - -*** - -### subscribe() - -> **subscribe**(`callback`, `filter`?, `options`?): () => `void` - -Defined in: [src/core/interfaces.ts:347](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L347) - -Subscribes a callback function to receive data updates. - -#### Parameters - -##### callback - -(`data`) => `void` - -The function to call with new data. - -##### filter? - -Optional filter criteria specific to the socket type. - -[`ObservationType`](../enumerations/ObservationType.md) | [`ObservationType`](../enumerations/ObservationType.md)[] - -##### options? - -Optional configuration like target threadId. - -###### threadId? - -`string` - -#### Returns - -An unsubscribe function. - -> (): `void` - -##### Returns - -`void` - -#### Inherited from - -[`ITypedSocket`](ITypedSocket.md).[`subscribe`](ITypedSocket.md#subscribe) diff --git a/Docs/API/interfaces/OllamaAdapterOptions.md b/Docs/API/interfaces/OllamaAdapterOptions.md deleted file mode 100644 index d15f4ef..0000000 --- a/Docs/API/interfaces/OllamaAdapterOptions.md +++ /dev/null @@ -1,44 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / OllamaAdapterOptions - -# Interface: OllamaAdapterOptions - -Defined in: [src/adapters/reasoning/ollama.ts:21](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/ollama.ts#L21) - -Configuration options required for the `OllamaAdapter`. - -## Properties - -### apiKey? - -> `optional` **apiKey**: `string` - -Defined in: [src/adapters/reasoning/ollama.ts:36](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/ollama.ts#L36) - -API key for Ollama (if secured). Defaults to "ollama" as commonly used. - -*** - -### defaultModel? - -> `optional` **defaultModel**: `string` - -Defined in: [src/adapters/reasoning/ollama.ts:32](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/ollama.ts#L32) - -The default Ollama model ID to use (e.g., 'llama3', 'mistral'). -This can be overridden by `RuntimeProviderConfig.modelId` or `CallOptions.model`. -It's recommended to set this if you primarily use one model with Ollama. - -*** - -### ollamaBaseUrl? - -> `optional` **ollamaBaseUrl**: `string` - -Defined in: [src/adapters/reasoning/ollama.ts:26](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/adapters/reasoning/ollama.ts#L26) - -The base URL for the Ollama API. Defaults to 'http://localhost:11434'. -The '/v1' suffix for OpenAI compatibility will be added automatically. diff --git a/Docs/API/interfaces/OutputParser.md b/Docs/API/interfaces/OutputParser.md deleted file mode 100644 index 853efdc..0000000 --- a/Docs/API/interfaces/OutputParser.md +++ /dev/null @@ -1,69 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / OutputParser - -# Interface: OutputParser - -Defined in: [src/core/interfaces.ts:123](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L123) - -Interface for parsing structured output from LLM responses. - -## Methods - -### parsePlanningOutput() - -> **parsePlanningOutput**(`output`): `Promise`\<\{ `intent`: `string`; `plan`: `string`; `toolCalls`: [`ParsedToolCall`](ParsedToolCall.md)[]; \}\> - -Defined in: [src/core/interfaces.ts:131](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L131) - -Parses the raw string output from the planning LLM call to extract structured information. -Implementations should be robust to variations in LLM output formatting. - -#### Parameters - -##### output - -`string` - -The raw string response from the planning LLM call. - -#### Returns - -`Promise`\<\{ `intent`: `string`; `plan`: `string`; `toolCalls`: [`ParsedToolCall`](ParsedToolCall.md)[]; \}\> - -A promise resolving to an object containing the extracted intent, plan description, and an array of parsed tool calls. - -#### Throws - -If the output cannot be parsed into the expected structure (typically code `OUTPUT_PARSING_FAILED`). - -*** - -### parseSynthesisOutput() - -> **parseSynthesisOutput**(`output`): `Promise`\<`string`\> - -Defined in: [src/core/interfaces.ts:144](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L144) - -Parses the raw string output from the synthesis LLM call to extract the final, user-facing response content. -This might involve removing extraneous tags or formatting. - -#### Parameters - -##### output - -`string` - -The raw string response from the synthesis LLM call. - -#### Returns - -`Promise`\<`string`\> - -A promise resolving to the clean, final response string. - -#### Throws - -If the final response cannot be extracted (typically code `OUTPUT_PARSING_FAILED`). diff --git a/Docs/API/interfaces/ParsedToolCall.md b/Docs/API/interfaces/ParsedToolCall.md deleted file mode 100644 index 316edea..0000000 --- a/Docs/API/interfaces/ParsedToolCall.md +++ /dev/null @@ -1,41 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ParsedToolCall - -# Interface: ParsedToolCall - -Defined in: [src/types/index.ts:266](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L266) - -Represents a parsed request from the LLM to call a specific tool. - -## Properties - -### arguments - -> **arguments**: `any` - -Defined in: [src/types/index.ts:272](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L272) - -The arguments object, parsed from the LLM response, intended to be passed to the tool's `execute` method after validation. - -*** - -### callId - -> **callId**: `string` - -Defined in: [src/types/index.ts:268](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L268) - -A unique identifier generated by the OutputParser for this specific tool call request within a plan. - -*** - -### toolName - -> **toolName**: `string` - -Defined in: [src/types/index.ts:270](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L270) - -The name of the tool the LLM intends to call. Must match a registered tool's schema name. diff --git a/Docs/API/interfaces/PromptContext.md b/Docs/API/interfaces/PromptContext.md deleted file mode 100644 index b428ea3..0000000 --- a/Docs/API/interfaces/PromptContext.md +++ /dev/null @@ -1,88 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / PromptContext - -# Interface: PromptContext - -Defined in: [src/types/index.ts:512](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L512) - -Represents the contextual data gathered by Agent Logic (e.g., `PESAgent`) to be injected -into a Mustache blueprint/template by the `PromptManager.assemblePrompt` method. - -Contains standard fields commonly needed for prompts, plus allows for arbitrary -additional properties required by specific agent blueprints. Agent logic is responsible -for populating this context appropriately before calling `assemblePrompt`. - -## Indexable - -\[`key`: `string`\]: `any` - -Allows agent patterns (like PES) to pass any other custom data needed by their specific blueprints (e.g., `intent`, `plan`). - -## Properties - -### availableTools? - -> `optional` **availableTools**: [`ToolSchema`](ToolSchema.md) & `object`[] - -Defined in: [src/types/index.ts:525](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L525) - -The schemas of the tools available for use, potentially pre-formatted for the blueprint -(e.g., with `inputSchemaJson` pre-stringified). - -*** - -### history? - -> `optional` **history**: `object`[] - -Defined in: [src/types/index.ts:520](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L520) - -The conversation history, typically formatted as an array suitable for the blueprint -(e.g., array of objects with `role` and `content`). Agent logic should pre-format this. -Note: While `ArtStandardPrompt` could be used, simpler structures might be preferred for blueprints. - -#### Index Signature - -\[`key`: `string`\]: `any` - -#### content - -> **content**: `string` - -#### role - -> **role**: `string` - -*** - -### query? - -> `optional` **query**: `string` - -Defined in: [src/types/index.ts:514](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L514) - -The user's current query or input relevant to this prompt generation step. - -*** - -### systemPrompt? - -> `optional` **systemPrompt**: `string` - -Defined in: [src/types/index.ts:532](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L532) - -The system prompt string to be used (resolved by agent logic from config or defaults). - -*** - -### toolResults? - -> `optional` **toolResults**: [`ToolResult`](ToolResult.md) & `object`[] - -Defined in: [src/types/index.ts:530](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L530) - -The results from any tools executed in a previous step, potentially pre-formatted for the blueprint -(e.g., with `outputJson` pre-stringified). diff --git a/Docs/API/interfaces/PromptManager.md b/Docs/API/interfaces/PromptManager.md deleted file mode 100644 index 2266481..0000000 --- a/Docs/API/interfaces/PromptManager.md +++ /dev/null @@ -1,76 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / PromptManager - -# Interface: PromptManager - -Defined in: [src/core/interfaces.ts:92](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L92) - -Interface for the stateless prompt assembler. -Uses a blueprint (template) and context provided by Agent Logic -to create a standardized prompt format (`ArtStandardPrompt`). - -## Methods - -### getFragment() - -> **getFragment**(`name`, `context`?): `string` - -Defined in: [src/core/interfaces.ts:102](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L102) - -Retrieves a named prompt fragment (e.g., a piece of instruction text). -Optionally allows for simple variable substitution if the fragment is a basic template. - -#### Parameters - -##### name - -`string` - -The unique identifier for the fragment. - -##### context? - -`Record`\<`string`, `any`\> - -Optional data for simple variable substitution within the fragment. - -#### Returns - -`string` - -The processed prompt fragment string. - -#### Throws - -If the fragment is not found. - -*** - -### validatePrompt() - -> **validatePrompt**(`prompt`): [`ArtStandardPrompt`](../type-aliases/ArtStandardPrompt.md) - -Defined in: [src/core/interfaces.ts:111](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L111) - -Validates a constructed prompt object against the standard schema. - -#### Parameters - -##### prompt - -[`ArtStandardPrompt`](../type-aliases/ArtStandardPrompt.md) - -The ArtStandardPrompt object constructed by the agent. - -#### Returns - -[`ArtStandardPrompt`](../type-aliases/ArtStandardPrompt.md) - -The validated prompt object (potentially after normalization if the schema does that). - -#### Throws - -If validation fails (can be caught and wrapped in ARTError). diff --git a/Docs/API/interfaces/ProviderAdapter.md b/Docs/API/interfaces/ProviderAdapter.md deleted file mode 100644 index 159f38f..0000000 --- a/Docs/API/interfaces/ProviderAdapter.md +++ /dev/null @@ -1,84 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ProviderAdapter - -# Interface: ProviderAdapter - -Defined in: [src/core/interfaces.ts:151](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L151) - -Base interface for LLM Provider Adapters, extending the core ReasoningEngine. -Implementations will handle provider-specific API calls, authentication, etc. - -## Extends - -- [`ReasoningEngine`](ReasoningEngine.md) - -## Properties - -### providerName - -> `readonly` **providerName**: `string` - -Defined in: [src/core/interfaces.ts:155](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L155) - -The unique identifier name for this provider (e.g., 'openai', 'anthropic'). - -## Methods - -### call() - -> **call**(`prompt`, `options`): `Promise`\<`AsyncIterable`\<[`StreamEvent`](StreamEvent.md), `any`, `any`\>\> - -Defined in: [src/core/interfaces.ts:83](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L83) - -Executes a call to the configured Large Language Model (LLM). -This method is typically implemented by a specific `ProviderAdapter`. -When streaming is requested via `options.stream`, it returns an AsyncIterable -that yields `StreamEvent` objects as they are generated by the LLM provider. -When streaming is not requested, it should still return an AsyncIterable -that yields a minimal sequence of events (e.g., a single TOKEN event with the full response, -a METADATA event if available, and an END event). - -#### Parameters - -##### prompt - -[`ArtStandardPrompt`](../type-aliases/ArtStandardPrompt.md) - -The prompt to send to the LLM, potentially formatted specifically for the provider. - -##### options - -[`CallOptions`](CallOptions.md) - -Options controlling the LLM call, including mandatory `threadId`, tracing IDs, model parameters (like temperature), streaming preference, and call context. - -#### Returns - -`Promise`\<`AsyncIterable`\<[`StreamEvent`](StreamEvent.md), `any`, `any`\>\> - -A promise resolving to an AsyncIterable of `StreamEvent` objects. - -#### Throws - -If a critical error occurs during the initial call setup or if the stream itself errors out (typically code `LLM_PROVIDER_ERROR`). - -#### Inherited from - -[`ReasoningEngine`](ReasoningEngine.md).[`call`](ReasoningEngine.md#call) - -*** - -### shutdown()? - -> `optional` **shutdown**(): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:158](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L158) - -Optional: Method for graceful shutdown - -#### Returns - -`Promise`\<`void`\> diff --git a/Docs/API/interfaces/ProviderManagerConfig.md b/Docs/API/interfaces/ProviderManagerConfig.md deleted file mode 100644 index 51e94c8..0000000 --- a/Docs/API/interfaces/ProviderManagerConfig.md +++ /dev/null @@ -1,39 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ProviderManagerConfig - -# Interface: ProviderManagerConfig - -Defined in: [src/types/providers.ts:13](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L13) - -Configuration for the ProviderManager passed during ART initialization - -## Properties - -### apiInstanceIdleTimeoutSeconds? - -> `optional` **apiInstanceIdleTimeoutSeconds**: `number` - -Defined in: [src/types/providers.ts:18](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L18) - -Time in seconds an API adapter instance can be idle before being eligible for removal. Default: 300 - -*** - -### availableProviders - -> **availableProviders**: [`AvailableProviderEntry`](AvailableProviderEntry.md)[] - -Defined in: [src/types/providers.ts:14](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L14) - -*** - -### maxParallelApiInstancesPerProvider? - -> `optional` **maxParallelApiInstancesPerProvider**: `number` - -Defined in: [src/types/providers.ts:16](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L16) - -Max concurrent ACTIVE instances per API-based provider NAME. Default: 5 diff --git a/Docs/API/interfaces/ReasoningEngine.md b/Docs/API/interfaces/ReasoningEngine.md deleted file mode 100644 index 373755d..0000000 --- a/Docs/API/interfaces/ReasoningEngine.md +++ /dev/null @@ -1,55 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ReasoningEngine - -# Interface: ReasoningEngine - -Defined in: [src/core/interfaces.ts:68](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L68) - -Interface for the component responsible for interacting with LLMs. - -## Extended by - -- [`ProviderAdapter`](ProviderAdapter.md) - -## Methods - -### call() - -> **call**(`prompt`, `options`): `Promise`\<`AsyncIterable`\<[`StreamEvent`](StreamEvent.md), `any`, `any`\>\> - -Defined in: [src/core/interfaces.ts:83](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L83) - -Executes a call to the configured Large Language Model (LLM). -This method is typically implemented by a specific `ProviderAdapter`. -When streaming is requested via `options.stream`, it returns an AsyncIterable -that yields `StreamEvent` objects as they are generated by the LLM provider. -When streaming is not requested, it should still return an AsyncIterable -that yields a minimal sequence of events (e.g., a single TOKEN event with the full response, -a METADATA event if available, and an END event). - -#### Parameters - -##### prompt - -[`ArtStandardPrompt`](../type-aliases/ArtStandardPrompt.md) - -The prompt to send to the LLM, potentially formatted specifically for the provider. - -##### options - -[`CallOptions`](CallOptions.md) - -Options controlling the LLM call, including mandatory `threadId`, tracing IDs, model parameters (like temperature), streaming preference, and call context. - -#### Returns - -`Promise`\<`AsyncIterable`\<[`StreamEvent`](StreamEvent.md), `any`, `any`\>\> - -A promise resolving to an AsyncIterable of `StreamEvent` objects. - -#### Throws - -If a critical error occurs during the initial call setup or if the stream itself errors out (typically code `LLM_PROVIDER_ERROR`). diff --git a/Docs/API/interfaces/RuntimeProviderConfig.md b/Docs/API/interfaces/RuntimeProviderConfig.md deleted file mode 100644 index cf7ad31..0000000 --- a/Docs/API/interfaces/RuntimeProviderConfig.md +++ /dev/null @@ -1,35 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / RuntimeProviderConfig - -# Interface: RuntimeProviderConfig - -Defined in: [src/types/providers.ts:21](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L21) - -Configuration passed AT RUNTIME for a specific LLM call - -## Properties - -### adapterOptions - -> **adapterOptions**: `any` - -Defined in: [src/types/providers.ts:24](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L24) - -*** - -### modelId - -> **modelId**: `string` - -Defined in: [src/types/providers.ts:23](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L23) - -*** - -### providerName - -> **providerName**: `string` - -Defined in: [src/types/providers.ts:22](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/providers.ts#L22) diff --git a/Docs/API/interfaces/StateManager.md b/Docs/API/interfaces/StateManager.md deleted file mode 100644 index 03f5017..0000000 --- a/Docs/API/interfaces/StateManager.md +++ /dev/null @@ -1,209 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / StateManager - -# Interface: StateManager - -Defined in: [src/core/interfaces.ts:225](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L225) - -Interface for managing thread-specific configuration and state. - -## Methods - -### getThreadConfigValue() - -> **getThreadConfigValue**\<`T`\>(`threadId`, `key`): `Promise`\<`undefined` \| `T`\> - -Defined in: [src/core/interfaces.ts:253](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L253) - -Retrieves a specific value from the thread's configuration (`ThreadConfig`). -Supports accessing nested properties using dot notation (e.g., 'reasoning.model'). - -#### Type Parameters - -##### T - -`T` - -The expected type of the configuration value. - -#### Parameters - -##### threadId - -`string` - -The ID of the thread. - -##### key - -`string` - -The key (potentially nested) of the configuration value to retrieve. - -#### Returns - -`Promise`\<`undefined` \| `T`\> - -A promise resolving to the configuration value, or `undefined` if the key doesn't exist or the thread config isn't loaded. - -*** - -### isToolEnabled() - -> **isToolEnabled**(`threadId`, `toolName`): `Promise`\<`boolean`\> - -Defined in: [src/core/interfaces.ts:243](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L243) - -Verifies if a specific tool is permitted for use within a given thread. -Checks against the `enabledTools` array in the thread's loaded `ThreadConfig`. - -#### Parameters - -##### threadId - -`string` - -The ID of the thread. - -##### toolName - -`string` - -The name of the tool to check. - -#### Returns - -`Promise`\<`boolean`\> - -A promise resolving to `true` if the tool is enabled for the thread, `false` otherwise. - -*** - -### loadThreadContext() - -> **loadThreadContext**(`threadId`, `userId`?): `Promise`\<[`ThreadContext`](ThreadContext.md)\> - -Defined in: [src/core/interfaces.ts:234](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L234) - -Loads the complete context (`ThreadConfig` and `AgentState`) for a specific thread. -This is typically called at the beginning of an agent execution cycle. - -#### Parameters - -##### threadId - -`string` - -The unique identifier for the thread. - -##### userId? - -`string` - -Optional user identifier, potentially used for retrieving user-specific state or config overrides. - -#### Returns - -`Promise`\<[`ThreadContext`](ThreadContext.md)\> - -A promise resolving to the `ThreadContext` object containing the loaded configuration and state. - -#### Throws - -If the context for the thread cannot be loaded (e.g., code `THREAD_NOT_FOUND`). - -*** - -### saveStateIfModified() - -> **saveStateIfModified**(`threadId`): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:261](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L261) - -Persists the `AgentState` for the thread, but only if it has been marked as modified during the current execution cycle. -This prevents unnecessary writes to the storage layer. - -#### Parameters - -##### threadId - -`string` - -The ID of the thread whose state should potentially be saved. - -#### Returns - -`Promise`\<`void`\> - -A promise that resolves when the save operation is complete (or skipped). - -*** - -### setAgentState() - -> **setAgentState**(`threadId`, `state`): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:282](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L282) - -Sets or updates the AgentState for a specific thread. -This method allows an agent to explicitly persist its internal state. -It requires that a ThreadConfig already exists for the thread, which is typically -ensured by the application calling setThreadConfig() prior to agent execution. - -#### Parameters - -##### threadId - -`string` - -The unique identifier of the thread. - -##### state - -[`AgentState`](AgentState.md) - -The AgentState object to save. - -#### Returns - -`Promise`\<`void`\> - -A promise that resolves when the state is saved. - -#### Throws - -If no ThreadConfig exists for the threadId, or if the repository fails. - -*** - -### setThreadConfig() - -> **setThreadConfig**(`threadId`, `config`): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:270](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L270) - -Sets or completely replaces the configuration (`ThreadConfig`) for a specific thread. -Use with caution, as this overwrites the existing configuration. Consider methods for partial updates if needed. - -#### Parameters - -##### threadId - -`string` - -The ID of the thread whose configuration is being set. - -##### config - -[`ThreadConfig`](ThreadConfig.md) - -The complete `ThreadConfig` object to save. - -#### Returns - -`Promise`\<`void`\> - -A promise that resolves when the configuration is saved. diff --git a/Docs/API/interfaces/StorageAdapter.md b/Docs/API/interfaces/StorageAdapter.md deleted file mode 100644 index 5229eaa..0000000 --- a/Docs/API/interfaces/StorageAdapter.md +++ /dev/null @@ -1,205 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / StorageAdapter - -# Interface: StorageAdapter - -Defined in: [src/core/interfaces.ts:406](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L406) - -Interface for a storage adapter, providing a generic persistence layer. - -## Methods - -### clearAll()? - -> `optional` **clearAll**(): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:445](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L445) - -Optional: Clears all data managed by the adapter. Use with caution! - -#### Returns - -`Promise`\<`void`\> - -*** - -### clearCollection()? - -> `optional` **clearCollection**(`collection`): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:442](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L442) - -Optional: Clears all items from a specific collection. - -#### Parameters - -##### collection - -`string` - -#### Returns - -`Promise`\<`void`\> - -*** - -### delete() - -> **delete**(`collection`, `id`): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:431](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L431) - -Deletes an item from a collection by its ID. - -#### Parameters - -##### collection - -`string` - -The name of the collection. - -##### id - -`string` - -The unique ID of the item. - -#### Returns - -`Promise`\<`void`\> - -*** - -### get() - -> **get**\<`T`\>(`collection`, `id`): `Promise`\<`null` \| `T`\> - -Defined in: [src/core/interfaces.ts:416](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L416) - -Retrieves a single item from a collection by its ID. - -#### Type Parameters - -##### T - -`T` - -#### Parameters - -##### collection - -`string` - -The name of the data collection (e.g., 'conversations', 'observations'). - -##### id - -`string` - -The unique ID of the item. - -#### Returns - -`Promise`\<`null` \| `T`\> - -The item or null if not found. - -*** - -### init()? - -> `optional` **init**(`config`?): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:408](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L408) - -Optional initialization method (e.g., connecting to DB). - -#### Parameters - -##### config? - -`any` - -#### Returns - -`Promise`\<`void`\> - -*** - -### query() - -> **query**\<`T`\>(`collection`, `filterOptions`): `Promise`\<`T`[]\> - -Defined in: [src/core/interfaces.ts:439](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L439) - -Queries items in a collection based on filter options. - -#### Type Parameters - -##### T - -`T` - -#### Parameters - -##### collection - -`string` - -The name of the collection. - -##### filterOptions - -[`FilterOptions`](FilterOptions.md) - -Filtering, sorting, and pagination options. - -#### Returns - -`Promise`\<`T`[]\> - -An array of matching items. - -*** - -### set() - -> **set**\<`T`\>(`collection`, `id`, `data`): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:424](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L424) - -Saves (creates or updates) an item in a collection. - -#### Type Parameters - -##### T - -`T` - -#### Parameters - -##### collection - -`string` - -The name of the collection. - -##### id - -`string` - -The unique ID of the item. - -##### data - -`T` - -The data to save. - -#### Returns - -`Promise`\<`void`\> diff --git a/Docs/API/interfaces/StreamEvent.md b/Docs/API/interfaces/StreamEvent.md deleted file mode 100644 index 3e2a8b2..0000000 --- a/Docs/API/interfaces/StreamEvent.md +++ /dev/null @@ -1,95 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / StreamEvent - -# Interface: StreamEvent - -Defined in: [src/types/index.ts:138](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L138) - -Represents a single event emitted from an asynchronous LLM stream (`ReasoningEngine.call`). -Allows for real-time delivery of tokens, metadata, errors, and lifecycle signals. -Adapters are responsible for translating provider-specific stream chunks into these standard events. - -## Properties - -### data - -> **data**: `any` - -Defined in: [src/types/index.ts:154](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L154) - -The actual content of the event. -- For `TOKEN`: string (the text chunk). -- For `METADATA`: `LLMMetadata` object. -- For `ERROR`: `Error` object or error details. -- For `END`: null. - -*** - -### sessionId? - -> `optional` **sessionId**: `string` - -Defined in: [src/types/index.ts:178](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L178) - -Optional identifier linking the event to a specific UI tab/window. - -*** - -### threadId - -> **threadId**: `string` - -Defined in: [src/types/index.ts:174](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L174) - -The identifier of the conversation thread this event belongs to. - -*** - -### tokenType? - -> `optional` **tokenType**: `"LLM_THINKING"` \| `"LLM_RESPONSE"` \| `"AGENT_THOUGHT_LLM_THINKING"` \| `"AGENT_THOUGHT_LLM_RESPONSE"` \| `"FINAL_SYNTHESIS_LLM_THINKING"` \| `"FINAL_SYNTHESIS_LLM_RESPONSE"` - -Defined in: [src/types/index.ts:172](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L172) - -Optional: Provides a more specific classification for `TOKEN` events, -combining LLM-level detection (thinking/response, if available from adapter) -and agent-level context (`callContext` from `CallOptions`). -Used by consumers (like UI) to differentiate between intermediate thoughts and the final response. - -- `LLM_THINKING`: Token identified by the adapter as part of the LLM's internal reasoning/thought process. -- `LLM_RESPONSE`: Token identified by the adapter as part of the LLM's final response content. -- `AGENT_THOUGHT_LLM_THINKING`: Token from an LLM call made in the 'AGENT_THOUGHT' context, identified as thinking. -- `AGENT_THOUGHT_LLM_RESPONSE`: Token from an LLM call made in the 'AGENT_THOUGHT' context, identified as response (e.g., the raw planning output). -- `FINAL_SYNTHESIS_LLM_THINKING`: Token from an LLM call made in the 'FINAL_SYNTHESIS' context, identified as thinking. -- `FINAL_SYNTHESIS_LLM_RESPONSE`: Token from an LLM call made in the 'FINAL_SYNTHESIS' context, identified as response (part of the final answer to the user). - -Note: Not all adapters can reliably distinguish 'LLM_THINKING' vs 'LLM_RESPONSE'. -Adapters should prioritize setting the agent context part (`AGENT_THOUGHT_...` or `FINAL_SYNTHESIS_...`) based on `CallOptions.callContext`. -If thinking detection is unavailable, adapters should default to `AGENT_THOUGHT_LLM_RESPONSE` or `FINAL_SYNTHESIS_LLM_RESPONSE`. - -*** - -### traceId - -> **traceId**: `string` - -Defined in: [src/types/index.ts:176](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L176) - -The identifier tracing the specific agent execution cycle this event is part of. - -*** - -### type - -> **type**: `"TOKEN"` \| `"METADATA"` \| `"ERROR"` \| `"END"` - -Defined in: [src/types/index.ts:146](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L146) - -The type of the stream event: -- `TOKEN`: A chunk of text generated by the LLM. -- `METADATA`: Information about the LLM call (e.g., token counts, stop reason), typically sent once at the end. -- `ERROR`: An error occurred during the LLM call or stream processing. `data` will contain the Error object. -- `END`: Signals the successful completion of the stream. `data` is typically null. diff --git a/Docs/API/interfaces/ThreadConfig.md b/Docs/API/interfaces/ThreadConfig.md deleted file mode 100644 index b396b66..0000000 --- a/Docs/API/interfaces/ThreadConfig.md +++ /dev/null @@ -1,51 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ThreadConfig - -# Interface: ThreadConfig - -Defined in: [src/types/index.ts:278](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L278) - -Configuration specific to a conversation thread. - -## Properties - -### enabledTools - -> **enabledTools**: `string`[] - -Defined in: [src/types/index.ts:282](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L282) - -An array of tool names (matching `ToolSchema.name`) that are permitted for use within this thread. - -*** - -### historyLimit - -> **historyLimit**: `number` - -Defined in: [src/types/index.ts:284](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L284) - -The maximum number of past messages (`ConversationMessage` objects) to retrieve for context. - -*** - -### providerConfig - -> **providerConfig**: [`RuntimeProviderConfig`](RuntimeProviderConfig.md) - -Defined in: [src/types/index.ts:280](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L280) - -Default provider configuration for this thread. - -*** - -### systemPrompt? - -> `optional` **systemPrompt**: `string` - -Defined in: [src/types/index.ts:286](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L286) - -Optional system prompt string to be used for this thread, overriding instance or agent defaults. diff --git a/Docs/API/interfaces/ThreadContext.md b/Docs/API/interfaces/ThreadContext.md deleted file mode 100644 index 4074d50..0000000 --- a/Docs/API/interfaces/ThreadContext.md +++ /dev/null @@ -1,31 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ThreadContext - -# Interface: ThreadContext - -Defined in: [src/types/index.ts:306](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L306) - -Encapsulates the configuration and state for a specific thread. - -## Properties - -### config - -> **config**: [`ThreadConfig`](ThreadConfig.md) - -Defined in: [src/types/index.ts:308](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L308) - -The configuration settings (`ThreadConfig`) currently active for the thread. - -*** - -### state - -> **state**: `null` \| [`AgentState`](AgentState.md) - -Defined in: [src/types/index.ts:310](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L310) - -The persistent state (`AgentState`) associated with the thread, or `null` if no state exists. diff --git a/Docs/API/interfaces/ToolRegistry.md b/Docs/API/interfaces/ToolRegistry.md deleted file mode 100644 index 5625437..0000000 --- a/Docs/API/interfaces/ToolRegistry.md +++ /dev/null @@ -1,87 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ToolRegistry - -# Interface: ToolRegistry - -Defined in: [src/core/interfaces.ts:180](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L180) - -Interface for managing the registration and retrieval of tools. - -## Methods - -### getAvailableTools() - -> **getAvailableTools**(`filter`?): `Promise`\<[`ToolSchema`](ToolSchema.md)[]\> - -Defined in: [src/core/interfaces.ts:200](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L200) - -Retrieves the schemas of available tools. Can be filtered, e.g., to get only tools enabled for a specific thread. - -#### Parameters - -##### filter? - -Optional filter criteria. If `enabledForThreadId` is provided, it should consult the `StateManager` to return only schemas for tools enabled in that thread's configuration. - -###### enabledForThreadId? - -`string` - -#### Returns - -`Promise`\<[`ToolSchema`](ToolSchema.md)[]\> - -A promise resolving to an array of `ToolSchema` objects. - -*** - -### getToolExecutor() - -> **getToolExecutor**(`toolName`): `Promise`\<`undefined` \| [`IToolExecutor`](IToolExecutor.md)\> - -Defined in: [src/core/interfaces.ts:193](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L193) - -Retrieves a registered tool executor instance by its unique name. - -#### Parameters - -##### toolName - -`string` - -The `name` property defined in the tool's schema. - -#### Returns - -`Promise`\<`undefined` \| [`IToolExecutor`](IToolExecutor.md)\> - -A promise resolving to the executor instance, or `undefined` if no tool with that name is registered. - -*** - -### registerTool() - -> **registerTool**(`executor`): `Promise`\<`void`\> - -Defined in: [src/core/interfaces.ts:186](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L186) - -Registers a tool executor instance, making it available for use. - -#### Parameters - -##### executor - -[`IToolExecutor`](IToolExecutor.md) - -The instance of the class implementing `IToolExecutor`. - -#### Returns - -`Promise`\<`void`\> - -#### Throws - -If a tool with the same name is already registered. diff --git a/Docs/API/interfaces/ToolResult.md b/Docs/API/interfaces/ToolResult.md deleted file mode 100644 index b113557..0000000 --- a/Docs/API/interfaces/ToolResult.md +++ /dev/null @@ -1,71 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ToolResult - -# Interface: ToolResult - -Defined in: [src/types/index.ts:248](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L248) - -Represents the structured result of a tool execution. - -## Properties - -### callId - -> **callId**: `string` - -Defined in: [src/types/index.ts:250](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L250) - -The unique identifier of the corresponding `ParsedToolCall` that initiated this execution attempt. - -*** - -### error? - -> `optional` **error**: `string` - -Defined in: [src/types/index.ts:258](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L258) - -A descriptive error message if the execution failed (`status` is 'error'). - -*** - -### metadata? - -> `optional` **metadata**: `Record`\<`string`, `any`\> - -Defined in: [src/types/index.ts:260](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L260) - -Optional metadata about the execution (e.g., duration, cost, logs). - -*** - -### output? - -> `optional` **output**: `any` - -Defined in: [src/types/index.ts:256](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L256) - -The data returned by the tool upon successful execution. Structure may be validated against `outputSchema`. - -*** - -### status - -> **status**: `"success"` \| `"error"` - -Defined in: [src/types/index.ts:254](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L254) - -Indicates whether the tool execution succeeded or failed. - -*** - -### toolName - -> **toolName**: `string` - -Defined in: [src/types/index.ts:252](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L252) - -The name of the tool that was executed. diff --git a/Docs/API/interfaces/ToolSchema.md b/Docs/API/interfaces/ToolSchema.md deleted file mode 100644 index d68018a..0000000 --- a/Docs/API/interfaces/ToolSchema.md +++ /dev/null @@ -1,74 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ToolSchema - -# Interface: ToolSchema - -Defined in: [src/types/index.ts:233](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L233) - -Defines the schema for a tool, including its input parameters. -Uses JSON Schema format for inputSchema. - -## Properties - -### description - -> **description**: `string` - -Defined in: [src/types/index.ts:237](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L237) - -A clear description of what the tool does, intended for the LLM to understand its purpose and usage. - -*** - -### examples? - -> `optional` **examples**: `object`[] - -Defined in: [src/types/index.ts:243](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L243) - -Optional array of examples demonstrating how to use the tool, useful for few-shot prompting of the LLM. - -#### description? - -> `optional` **description**: `string` - -#### input - -> **input**: `any` - -#### output? - -> `optional` **output**: `any` - -*** - -### inputSchema - -> **inputSchema**: [`JsonSchema`](../type-aliases/JsonSchema.md) - -Defined in: [src/types/index.ts:239](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L239) - -A JSON Schema object defining the structure, types, and requirements of the input arguments the tool expects. - -*** - -### name - -> **name**: `string` - -Defined in: [src/types/index.ts:235](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L235) - -A unique name identifying the tool (used in LLM prompts and registry lookups). Must be unique. - -*** - -### outputSchema? - -> `optional` **outputSchema**: [`JsonSchema`](../type-aliases/JsonSchema.md) - -Defined in: [src/types/index.ts:241](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L241) - -An optional JSON Schema object defining the expected structure of the data returned in the `output` field of a successful `ToolResult`. diff --git a/Docs/API/interfaces/ToolSystem.md b/Docs/API/interfaces/ToolSystem.md deleted file mode 100644 index 86d04d0..0000000 --- a/Docs/API/interfaces/ToolSystem.md +++ /dev/null @@ -1,48 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ToolSystem - -# Interface: ToolSystem - -Defined in: [src/core/interfaces.ts:206](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L206) - -Interface for the system responsible for orchestrating tool execution. - -## Methods - -### executeTools() - -> **executeTools**(`toolCalls`, `threadId`, `traceId`?): `Promise`\<[`ToolResult`](ToolResult.md)[]\> - -Defined in: [src/core/interfaces.ts:215](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L215) - -Orchestrates the execution of a sequence of tool calls determined during the planning phase. -This involves verifying permissions, validating inputs, calling the tool executor, and recording observations. - -#### Parameters - -##### toolCalls - -[`ParsedToolCall`](ParsedToolCall.md)[] - -An array of `ParsedToolCall` objects generated by the `OutputParser`. - -##### threadId - -`string` - -The ID of the current thread, used for context and checking tool permissions via `StateManager`. - -##### traceId? - -`string` - -Optional trace ID for correlating observations. - -#### Returns - -`Promise`\<[`ToolResult`](ToolResult.md)[]\> - -A promise resolving to an array of `ToolResult` objects, one for each attempted tool call (including errors). diff --git a/Docs/API/interfaces/UISystem.md b/Docs/API/interfaces/UISystem.md deleted file mode 100644 index 3897c57..0000000 --- a/Docs/API/interfaces/UISystem.md +++ /dev/null @@ -1,53 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / UISystem - -# Interface: UISystem - -Defined in: [src/core/interfaces.ts:393](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L393) - -Interface for the system providing access to UI communication sockets. - -## Methods - -### getConversationSocket() - -> **getConversationSocket**(): `ConversationSocket` - -Defined in: [src/core/interfaces.ts:397](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L397) - -Returns the singleton instance of the ConversationSocket. - -#### Returns - -`ConversationSocket` - -*** - -### getLLMStreamSocket() - -> **getLLMStreamSocket**(): [`LLMStreamSocket`](../classes/LLMStreamSocket.md) - -Defined in: [src/core/interfaces.ts:399](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L399) - -Returns the singleton instance of the LLMStreamSocket. - -#### Returns - -[`LLMStreamSocket`](../classes/LLMStreamSocket.md) - -*** - -### getObservationSocket() - -> **getObservationSocket**(): `ObservationSocket` - -Defined in: [src/core/interfaces.ts:395](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/core/interfaces.ts#L395) - -Returns the singleton instance of the ObservationSocket. - -#### Returns - -`ObservationSocket` diff --git a/Docs/API/interfaces/XmlMatcherChunk.md b/Docs/API/interfaces/XmlMatcherChunk.md deleted file mode 100644 index f42dbbc..0000000 --- a/Docs/API/interfaces/XmlMatcherChunk.md +++ /dev/null @@ -1,32 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / XmlMatcherChunk - -# Interface: XmlMatcherChunk - -Defined in: [utils/xml-matcher.ts:7](https://github.com/hashangit/ART/blob/3153790647102134b487bb6168bd208568e6a8ad/src/utils/xml-matcher.ts#L7) - -Represents a chunk of text processed by XmlMatcher, indicating whether -it was part of the matched XML tag's content or outside of it. - -## Properties - -### data - -> **data**: `string` - -Defined in: [utils/xml-matcher.ts:11](https://github.com/hashangit/ART/blob/3153790647102134b487bb6168bd208568e6a8ad/src/utils/xml-matcher.ts#L11) - -The text content of this chunk. - -*** - -### matched - -> **matched**: `boolean` - -Defined in: [utils/xml-matcher.ts:9](https://github.com/hashangit/ART/blob/3153790647102134b487bb6168bd208568e6a8ad/src/utils/xml-matcher.ts#L9) - -True if this chunk was inside the matched XML tag, false otherwise. diff --git a/Docs/API/type-aliases/ArtStandardMessageRole.md b/Docs/API/type-aliases/ArtStandardMessageRole.md deleted file mode 100644 index f1b228f..0000000 --- a/Docs/API/type-aliases/ArtStandardMessageRole.md +++ /dev/null @@ -1,22 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ArtStandardMessageRole - -# Type Alias: ArtStandardMessageRole - -> **ArtStandardMessageRole** = `"system"` \| `"user"` \| `"assistant"` \| `"tool_request"` \| `"tool_result"` \| `"tool"` - -Defined in: [src/types/index.ts:451](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L451) - -Defines the standard roles for messages within the `ArtStandardPrompt` format. -These roles are chosen for broad compatibility across major LLM providers (like OpenAI, Anthropic, Gemini). -Provider Adapters are responsible for translating these standard roles into the specific formats -required by their respective APIs (e.g., 'assistant' might become 'model' for Gemini). - -- `system`: Instructions or context provided to the AI, typically at the beginning. -- `user`: Input or queries from the end-user. Also used to wrap `tool_result` content for some providers (e.g., Gemini). -- `assistant`: Responses generated by the AI model. Can contain text content and/or `tool_calls`. -- `tool_request`: Represents the LLM's request to use tools (often implicitly part of an `assistant` message with `tool_calls`). Included for potential future explicit use. -- `tool_result`: The outcome (output or error) of executing a requested tool call. diff --git a/Docs/API/type-aliases/ArtStandardPrompt.md b/Docs/API/type-aliases/ArtStandardPrompt.md deleted file mode 100644 index 1664ba8..0000000 --- a/Docs/API/type-aliases/ArtStandardPrompt.md +++ /dev/null @@ -1,15 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ArtStandardPrompt - -# Type Alias: ArtStandardPrompt - -> **ArtStandardPrompt** = [`ArtStandardMessage`](../interfaces/ArtStandardMessage.md)[] - -Defined in: [src/types/index.ts:502](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L502) - -Represents the entire prompt as an array of standardized messages (`ArtStandardMessage`). -This is the standard format produced by `PromptManager.assemblePrompt` and consumed -by `ProviderAdapter.call` for translation into provider-specific API formats. diff --git a/Docs/API/type-aliases/FormattedPrompt.md b/Docs/API/type-aliases/FormattedPrompt.md deleted file mode 100644 index 07fc746..0000000 --- a/Docs/API/type-aliases/FormattedPrompt.md +++ /dev/null @@ -1,18 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / FormattedPrompt - -# Type Alias: ~~FormattedPrompt~~ - -> **FormattedPrompt** = [`ArtStandardPrompt`](ArtStandardPrompt.md) - -Defined in: [src/types/index.ts:545](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L545) - -Represents the prompt data formatted for a specific LLM provider. -Can be a simple string or a complex object (e.g., for OpenAI Chat Completion API). - -## Deprecated - -Use `ArtStandardPrompt` as the standard intermediate format. ProviderAdapters handle final formatting. diff --git a/Docs/API/type-aliases/JsonSchema.md b/Docs/API/type-aliases/JsonSchema.md deleted file mode 100644 index e3b5c51..0000000 --- a/Docs/API/type-aliases/JsonSchema.md +++ /dev/null @@ -1,11 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / JsonSchema - -# Type Alias: JsonSchema - -> **JsonSchema** = [`JsonObjectSchema`](../interfaces/JsonObjectSchema.md) \| \{[`key`: `string`]: `any`; `type`: `"string"` \| `"number"` \| `"boolean"` \| `"array"`; \} - -Defined in: [src/types/index.ts:204](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L204) diff --git a/Docs/API/type-aliases/StateSavingStrategy.md b/Docs/API/type-aliases/StateSavingStrategy.md deleted file mode 100644 index fb0a823..0000000 --- a/Docs/API/type-aliases/StateSavingStrategy.md +++ /dev/null @@ -1,19 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / StateSavingStrategy - -# Type Alias: StateSavingStrategy - -> **StateSavingStrategy** = `"explicit"` \| `"implicit"` - -Defined in: [src/types/index.ts:602](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/index.ts#L602) - -Defines the strategy for saving AgentState. -- 'explicit': AgentState is only saved when `StateManager.setAgentState()` is explicitly called by the agent. - `StateManager.saveStateIfModified()` will be a no-op for AgentState persistence. -- 'implicit': AgentState is loaded by `StateManager.loadThreadContext()`, and if modified by the agent, - `StateManager.saveStateIfModified()` will attempt to automatically persist these changes - by comparing the current state with a snapshot taken at load time. - `StateManager.setAgentState()` will still work for explicit saves. diff --git a/Docs/API/type-aliases/UnsubscribeFunction.md b/Docs/API/type-aliases/UnsubscribeFunction.md deleted file mode 100644 index 34b1574..0000000 --- a/Docs/API/type-aliases/UnsubscribeFunction.md +++ /dev/null @@ -1,15 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / UnsubscribeFunction - -# Type Alias: UnsubscribeFunction() - -> **UnsubscribeFunction** = () => `void` - -Defined in: [src/systems/ui/typed-socket.ts:5](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/systems/ui/typed-socket.ts#L5) - -## Returns - -`void` diff --git a/Docs/API/variables/ArtStandardMessageSchema.md b/Docs/API/variables/ArtStandardMessageSchema.md deleted file mode 100644 index e20691b..0000000 --- a/Docs/API/variables/ArtStandardMessageSchema.md +++ /dev/null @@ -1,13 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ArtStandardMessageSchema - -# Variable: ArtStandardMessageSchema - -> `const` **ArtStandardMessageSchema**: `ZodEffects`\<`ZodObject`\<\{ `content`: `ZodUnion`\<\[`ZodString`, `ZodRecord`\<`ZodString`, `ZodAny`\>, `ZodNull`\]\>; `name`: `ZodOptional`\<`ZodString`\>; `role`: `ZodType`\<[`ArtStandardMessageRole`](../type-aliases/ArtStandardMessageRole.md), `ZodTypeDef`, [`ArtStandardMessageRole`](../type-aliases/ArtStandardMessageRole.md)\>; `tool_call_id`: `ZodOptional`\<`ZodString`\>; `tool_calls`: `ZodOptional`\<`ZodArray`\<`ZodObject`\<\{ `function`: `ZodObject`\<\{ `arguments`: `ZodString`; `name`: `ZodString`; \}, `"strip"`, `ZodTypeAny`, \{ `arguments`: `string`; `name`: `string`; \}, \{ `arguments`: `string`; `name`: `string`; \}\>; `id`: `ZodString`; `type`: `ZodLiteral`\<`"function"`\>; \}, `"strip"`, `ZodTypeAny`, \{ `function`: \{ `arguments`: `string`; `name`: `string`; \}; `id`: `string`; `type`: `"function"`; \}, \{ `function`: \{ `arguments`: `string`; `name`: `string`; \}; `id`: `string`; `type`: `"function"`; \}\>, `"many"`\>\>; \}, `"strict"`, `ZodTypeAny`, \{ `content`: `null` \| `string` \| `Record`\<`string`, `any`\>; `name`: `string`; `role`: [`ArtStandardMessageRole`](../type-aliases/ArtStandardMessageRole.md); `tool_call_id`: `string`; `tool_calls`: `object`[]; \}, \{ `content`: `null` \| `string` \| `Record`\<`string`, `any`\>; `name`: `string`; `role`: [`ArtStandardMessageRole`](../type-aliases/ArtStandardMessageRole.md); `tool_call_id`: `string`; `tool_calls`: `object`[]; \}\>, \{ `content`: `null` \| `string` \| `Record`\<`string`, `any`\>; `name`: `string`; `role`: [`ArtStandardMessageRole`](../type-aliases/ArtStandardMessageRole.md); `tool_call_id`: `string`; `tool_calls`: `object`[]; \}, \{ `content`: `null` \| `string` \| `Record`\<`string`, `any`\>; `name`: `string`; `role`: [`ArtStandardMessageRole`](../type-aliases/ArtStandardMessageRole.md); `tool_call_id`: `string`; `tool_calls`: `object`[]; \}\> - -Defined in: [src/types/schemas.ts:8](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/schemas.ts#L8) - -Zod schema for validating a single ArtStandardMessage object. diff --git a/Docs/API/variables/ArtStandardPromptSchema.md b/Docs/API/variables/ArtStandardPromptSchema.md deleted file mode 100644 index 1569748..0000000 --- a/Docs/API/variables/ArtStandardPromptSchema.md +++ /dev/null @@ -1,13 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / ArtStandardPromptSchema - -# Variable: ArtStandardPromptSchema - -> `const` **ArtStandardPromptSchema**: `ZodArray`\<`ZodEffects`\<`ZodObject`\<\{ `content`: `ZodUnion`\<\[`ZodString`, `ZodRecord`\<`ZodString`, `ZodAny`\>, `ZodNull`\]\>; `name`: `ZodOptional`\<`ZodString`\>; `role`: `ZodType`\<[`ArtStandardMessageRole`](../type-aliases/ArtStandardMessageRole.md), `ZodTypeDef`, [`ArtStandardMessageRole`](../type-aliases/ArtStandardMessageRole.md)\>; `tool_call_id`: `ZodOptional`\<`ZodString`\>; `tool_calls`: `ZodOptional`\<`ZodArray`\<`ZodObject`\<\{ `function`: `ZodObject`\<\{ `arguments`: `ZodString`; `name`: `ZodString`; \}, `"strip"`, `ZodTypeAny`, \{ `arguments`: `string`; `name`: `string`; \}, \{ `arguments`: `string`; `name`: `string`; \}\>; `id`: `ZodString`; `type`: `ZodLiteral`\<`"function"`\>; \}, `"strip"`, `ZodTypeAny`, \{ `function`: \{ `arguments`: `string`; `name`: `string`; \}; `id`: `string`; `type`: `"function"`; \}, \{ `function`: \{ `arguments`: `string`; `name`: `string`; \}; `id`: `string`; `type`: `"function"`; \}\>, `"many"`\>\>; \}, `"strict"`, `ZodTypeAny`, \{ `content`: `null` \| `string` \| `Record`\<`string`, `any`\>; `name`: `string`; `role`: [`ArtStandardMessageRole`](../type-aliases/ArtStandardMessageRole.md); `tool_call_id`: `string`; `tool_calls`: `object`[]; \}, \{ `content`: `null` \| `string` \| `Record`\<`string`, `any`\>; `name`: `string`; `role`: [`ArtStandardMessageRole`](../type-aliases/ArtStandardMessageRole.md); `tool_call_id`: `string`; `tool_calls`: `object`[]; \}\>, \{ `content`: `null` \| `string` \| `Record`\<`string`, `any`\>; `name`: `string`; `role`: [`ArtStandardMessageRole`](../type-aliases/ArtStandardMessageRole.md); `tool_call_id`: `string`; `tool_calls`: `object`[]; \}, \{ `content`: `null` \| `string` \| `Record`\<`string`, `any`\>; `name`: `string`; `role`: [`ArtStandardMessageRole`](../type-aliases/ArtStandardMessageRole.md); `tool_call_id`: `string`; `tool_calls`: `object`[]; \}\>, `"many"`\> - -Defined in: [src/types/schemas.ts:54](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/types/schemas.ts#L54) - -Zod schema for validating an entire ArtStandardPrompt (an array of messages). diff --git a/Docs/API/variables/VERSION.md b/Docs/API/variables/VERSION.md deleted file mode 100644 index 43756a5..0000000 --- a/Docs/API/variables/VERSION.md +++ /dev/null @@ -1,13 +0,0 @@ -[**ART Framework API Reference**](../README.md) - -*** - -[ART Framework API Reference](../README.md) / VERSION - -# Variable: VERSION - -> `const` **VERSION**: `"0.2.7"` = `'0.2.7'` - -Defined in: [src/index.ts:72](https://github.com/hashangit/ART/blob/a8524de337702d2ec210d86aff2464ac0aeed73e/src/index.ts#L72) - -The current version of the ART Framework package. diff --git a/Docs/CONTRIBUTING.md b/Docs/CONTRIBUTING.md deleted file mode 100644 index 47b782b..0000000 --- a/Docs/CONTRIBUTING.md +++ /dev/null @@ -1,79 +0,0 @@ -# Contributing to ART Framework - -Thank you for your interest in contributing to the ART (Agent-Reasoning-Tooling) Framework! We welcome contributions from the community to help make ART better. Whether it's bug reports, feature requests, documentation improvements, or code contributions, your help is appreciated. - -## Ways to Contribute - -* **Reporting Bugs:** If you find a bug, please open an issue on our GitHub repository. Include a clear description, steps to reproduce, your environment details (OS, Node.js version, ART version), and any relevant error messages or logs. -* **Suggesting Enhancements:** Have an idea for a new feature or an improvement to an existing one? Open an issue to discuss it. Provide a clear explanation of the feature and its potential benefits. -* **Improving Documentation:** Good documentation is crucial. If you find areas that are unclear, incorrect, or missing, please let us know by opening an issue or, even better, submitting a pull request with your suggested changes. -* **Writing Code:** - * **Bug Fixes:** If you've fixed a bug, submit a pull request with your changes. - * **New Features:** It's best to discuss new features in an issue first to ensure they align with the project's goals and roadmap before you invest significant time in implementation. - * **New Adapters:** Adding support for new LLM providers or storage backends is a valuable contribution. - * **New Tools:** Contributing useful, general-purpose tools. -* **Writing Tests:** Improving test coverage helps ensure the stability and reliability of the framework. -* **Providing Feedback:** Share your experiences using ART. What do you like? What could be better? What challenges are you facing? - -## Development Setup (Conceptual) - -1. **Fork & Clone:** Fork the official ART Framework repository on GitHub and then clone your fork locally. - ```bash - git clone https://github.com/YOUR_USERNAME/art-framework.git - cd art-framework - ``` -2. **Install Dependencies:** - ```bash - npm install - # or - yarn install - ``` -3. **Branching:** Create a new branch for your changes: - ```bash - git checkout -b feature/my-new-feature - # or - git checkout -b fix/issue-123 - ``` -4. **Making Changes:** - * Write your code, following the existing coding style and conventions. - * Ensure your code is well-commented, especially public APIs (use TSDoc). - * Add or update unit tests for your changes in the relevant `*.test.ts` files. - * Update documentation if your changes affect public APIs or behavior. -5. **Testing:** Run the test suite to ensure your changes haven't introduced regressions: - ```bash - npm test - # or - yarn test - ``` -6. **Linting & Formatting:** Ensure your code adheres to the project's linting and formatting rules (e.g., using ESLint, Prettier). - ```bash - npm run lint - npm run format # (Or similar scripts defined in package.json) - ``` -7. **Building (if applicable):** - ```bash - npm run build - # or - yarn build - ``` - -## Pull Request Guidelines - -1. **Keep PRs Focused:** Each pull request should address a single bug or feature. Avoid mixing unrelated changes. -2. **Base on `main` (or `develop`):** Ensure your branch is based on the latest version of the project's main development branch. Rebase your branch if necessary before submitting. -3. **Clear Commit Messages:** Write clear and concise commit messages explaining the "what" and "why" of your changes. -4. **Link to Issues:** If your PR addresses an existing issue, reference it in the PR description (e.g., "Fixes #123"). -5. **Detailed PR Description:** Explain the changes you've made, the problem they solve, and any relevant context. If it's a new feature, explain its usage. -6. **Tests:** Include new tests for new features or bug fixes. Ensure all tests pass. -7. **Documentation:** Update any relevant documentation (code comments, Markdown files). -8. **Code Review:** Be prepared for feedback and discussion during the code review process. - -## Code of Conduct - -Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms. (If a CODE_OF_CONDUCT.md file exists, link to it here). - -## Questions? - -If you have questions about contributing, feel free to open an issue or reach out through the project's designated communication channels (if any). - -We look forward to your contributions! \ No newline at end of file diff --git a/Docs/Welcome.md b/Docs/Welcome.md deleted file mode 100644 index 754a1c7..0000000 --- a/Docs/Welcome.md +++ /dev/null @@ -1,270 +0,0 @@ -# Welcome to the ART Framework! - -The ART (Agent Runtime) Framework is a comprehensive TypeScript library designed to simplify the development of sophisticated AI agents. It provides a modular, extensible, and robust architecture for building agents that can reason, use tools, manage context, and interact with users and external systems. - -## Why ART? - -ART aims to address common challenges in AI agent development by offering: - -* **Flexible Orchestration:** ART's core design decouples the agent's orchestration logic (the "how" of processing a query) from its core functionalities (reasoning, tools, context). This means developers can use the default `PESAgent` or easily **swap in their own custom agent core implementations** via `ArtInstanceConfig` without altering the underlying systems. This provides unparalleled flexibility in defining agent behavior. -* **Structured Yet Adaptable:** While offering patterns like Plan-Execute-Synthesize (`PESAgent`), the framework allows for diverse agent architectures. -* **Modularity:** Decoupled systems for reasoning, context management, tool usage, observation, and UI communication, allowing for easier customization and extension. -* **Provider Agnosticism:** A flexible `ProviderManager` and adapter system to seamlessly switch between different LLM providers (OpenAI, Anthropic, Gemini, Ollama, etc.) without rewriting core agent logic. -* **Standardized Primitives:** Core abstractions like `ArtStandardPrompt` for LLM interactions and `StreamEvent` for handling real-time responses simplify development and ensure consistency. -* **Robust Tool Integration:** A powerful `ToolSystem` and `ToolRegistry` for defining, registering, and executing custom capabilities for your agents. -* **Configurable State Management:** Built-in support for managing conversation history and agent state, with strategies for both explicit and implicit state saving. -* **Comprehensive Observability:** A dedicated `ObservationSystem` to track key events and data points throughout the agent's lifecycle, aiding in debugging and analysis. -* **Developer-Friendly API:** Designed to be intuitive and easy to learn, with a focus on clear interfaces and conventions. - -## Core Philosophy & Design Principles - -* **Separation of Concerns:** Each component in ART has a well-defined responsibility. -* **Extensibility:** Interfaces are designed to be implemented and extended, allowing developers to plug in custom components, including entirely different agent orchestration logics. -* **Developer Experience:** Focus on providing clear APIs, good documentation, and tools that make agent development faster and more reliable. -* **Standardization:** Promote common patterns and data structures (like `ArtStandardPrompt`) to reduce boilerplate and improve interoperability. - -## Key Features - -* **Swappable Agent Core (`IAgentCore`):** Use the default `PESAgent` (Plan-Execute-Synthesize) or implement your own custom orchestration logic. -* **Multi-Provider LLM Support:** Easily integrate and switch between various LLM providers via the `ProviderManager` and `ProviderAdapter` system. -* **Streaming LLM Responses:** Built-in support for handling `StreamEvent`s for real-time token-by-token output from LLMs. -* **Flexible Tool System:** Define custom tools with JSON Schema for input validation and seamlessly integrate them into your agent's workflow. -* **Persistent & In-Memory Storage:** Choose between `IndexedDBStorageAdapter` for browser persistence or `InMemoryStorageAdapter` for testing and ephemeral agents, or implement your own. -* **Configurable State Management:** Manage thread-specific configurations and agent state with strategies for explicit or implicit saving. -* **Comprehensive Observability:** Log and retrieve detailed observations of agent activity for debugging and analysis. -* **UI Integration Sockets:** `TypedSocket` implementations for `ConversationMessage`, `Observation`, and `LLMStreamEvent` to easily connect your agent to a user interface. - -## Who is ART For? - -* Developers building AI-powered applications that require complex reasoning, tool use, and interaction. -* Teams looking for a structured and maintainable way to develop AI agents with the ability to define custom operational flows. -* Developers who want the flexibility to experiment with different LLM providers and agent architectures. -* Anyone interested in building robust, observable, and adaptable AI systems. - -## High-Level Architecture![[welcome.excalidraw]] - -```mermaid -flowchart TD - -%% Main user flow - -User([User]) -->|Input| UI[UI System] - -UI -->|Query| AgentCore - -AgentCore -->|Response| UI - -UI -->|Output| User - -%% Core Agent - Swappable - -subgraph AgentCore[Agent Core] - -direction TB - -Core{{"IAgentCore"}} - -PESAgent[PESAgent\nPlan-Execute-Synthesize] - -CustomAgent[CustomAgent\nUser-defined flow] - -Core --- PESAgent - -Core --- CustomAgent - -class PESAgent,CustomAgent agentTypes - -end - -%% Reasoning System - -subgraph ReasoningSystem[Reasoning System] - -direction TB - -ReasoningEngine[Reasoning Engine] - -ProviderManager[Provider Manager] - -PromptManager[Prompt Manager] - -OutputParser[Output Parser] - -ProviderAdapters[Provider Adapters] - -LLMs[(LLM Providers)] - -ReasoningEngine --> ProviderManager - -ReasoningEngine --> PromptManager - -ReasoningEngine --> OutputParser - -ProviderManager --> ProviderAdapters - -ProviderAdapters --> LLMs - -end - -%% Tool System - -subgraph ToolSystem[Tool System] - -direction TB - -ToolSys[Tool System] - -ToolRegistry[Tool Registry] - -ToolExecutors[IToolExecutors] - -ToolSys --> ToolRegistry - -ToolRegistry --> ToolExecutors - -end - -%% Context System - -subgraph ContextSystem[Context System] - -direction TB - -StateManager[State Manager] - -ConversationManager[Conversation Manager] - -ContextProvider[Context Provider] - -Repositories[Repositories] - -StateManager --> Repositories - -ConversationManager --> Repositories - -ContextProvider --> Repositories - -end - -%% Observation System - -subgraph ObservationSystem[Observation System] - -direction TB - -ObservationManager[Observation Manager] - -ObsRepositories[Observation Repository] - -ObservationManager --> ObsRepositories - -end - -%% Storage System - -subgraph StorageSystem[Storage System] - -direction TB - -StorageAdapter{{"StorageAdapter"}} - -InMemoryStorage[InMemoryStorageAdapter] - -IndexedDBStorage[IndexedDBStorageAdapter] - -CustomStorage[Custom Storage] - -StorageAdapter --- InMemoryStorage - -StorageAdapter --- IndexedDBStorage - -StorageAdapter --- CustomStorage - -class InMemoryStorage,IndexedDBStorage,CustomStorage storageTypes - -end - -%% UI System - -subgraph UISystem[UI System] - -direction TB - -ConversationSocket[Conversation Socket] - -ObservationSocket[Observation Socket] - -LLMStreamSocket[LLM Stream Socket] - -end - -%% Connections between systems - -AgentCore <--> ReasoningSystem - -AgentCore <--> ToolSystem - -AgentCore <--> ContextSystem - -AgentCore <--> ObservationSystem - -ContextSystem --> StorageSystem - -ObservationSystem --> StorageSystem - -AgentCore --> UISystem - -%% Styling - -classDef agentTypes fill:#f9f,stroke:#333,stroke-width:2px - -classDef storageTypes fill:#bbf,stroke:#333,stroke-width:2px - -classDef default fill:#fff,stroke:#333,stroke-width:1px - -style AgentCore fill:#ffe6cc,stroke:#d79b00 - -style ReasoningSystem fill:#dae8fc,stroke:#6c8ebf - -style ToolSystem fill:#d5e8d4,stroke:#82b366 - -style ContextSystem fill:#fff2cc,stroke:#d6b656 - -style ObservationSystem fill:#e1d5e7,stroke:#9673a6 - -style StorageSystem fill:#f8cecc,stroke:#b85450 - -style UISystem fill:#ffe6cc,stroke:#d79b00 -``` - -**Key Subsystems:** - -The ART Framework is composed of several key subsystems that work together: - -* **Agent Core (`IAgentCore`):** The heart of the agent, responsible for the overall orchestration logic (e.g., `PESAgent`'s Plan-Execute-Synthesize flow, or a custom-defined flow). It coordinates interactions between all other systems to process a user's query and generate a response. This component is designed to be **swappable**, allowing developers to implement entirely different agent behaviors. -* **Reasoning System:** Handles all interactions with LLM providers. It includes the `ReasoningEngine`, `ProviderManager` (for managing multiple LLM `ProviderAdapter`s), the `ProviderAdapter`s themselves (which translate to specific LLM APIs), the `PromptManager` (for prompt fragments and validation), and the `OutputParser` (for interpreting LLM responses). -* **Tool System:** Enables agents to use external capabilities. It comprises a `ToolRegistry` (to manage available tools) and a `ToolSystem` (to handle the secure execution of tools, including input validation). -* **Context System:** Manages all stateful information for a conversation. This includes: - * `StateManager`: For thread-specific configurations (`ThreadConfig`) and persistent agent operational state (`AgentState`). - * `ConversationManager`: For managing the history of `ConversationMessage`s. - * `ContextProvider` (currently a placeholder): Intended for future Retrieval-Augmented Generation (RAG) features. - * Repositories (`StateRepository`, `ConversationRepository`, `ObservationRepository`): Abstractions over the storage layer for specific data types. -* **Observation System:** Key to the observability of the agent's activities. The `ObservationManager` records significant events (`Observation`s) throughout the agent's lifecycle, which can be persisted (via `ObservationRepository`) and broadcast for debugging or UI updates. -* **UI System:** Provides `TypedSocket` instances (`ConversationSocket`, `ObservationSocket`, `LLMStreamSocket`) that allow front-end applications or other services to subscribe to real-time updates from the agent's backend. -* **Storage System:** An abstraction layer (`StorageAdapter` interface) for data persistence, with concrete implementations like `InMemoryStorageAdapter` and `IndexedDBStorageAdapter`, allowing for flexibility in how and where agent data is stored. - -Configuration for these components is primarily managed through `ArtInstanceConfig` when creating an ART instance using `createArtInstance`. - -## Quick Links - -* **[Getting Started](./getting-started/quick-start.md):** Build your first "Hello, Agent!" -* **Core Concepts:** - * [Architecture Overview](./core-concepts/architecture-overview.md) - * [ArtStandardPrompt](./core-concepts/art-standard-prompt.md) - The common language for LLM prompts. - * [Streaming & StreamEvents](./core-concepts/streaming-and-streamevents.md) - Real-time LLM responses. - * [Provider Management](./core-concepts/provider-management.md) - Using multiple LLM providers. -* **Key How-To Guides:** - * [Configure an ART Instance](./how-to/configure-art-instance.md) - * [Define and Use Tools](./how-to/define-tools.md) - * [Handle Streaming in UI](./how-to/handle-streaming-ui.md) -* **[Examples](./examples/basic-chatbot.md):** See ART in action. \ No newline at end of file diff --git a/Docs/advanced/debugging-art-applications.md b/Docs/advanced/debugging-art-applications.md deleted file mode 100644 index f6240ed..0000000 --- a/Docs/advanced/debugging-art-applications.md +++ /dev/null @@ -1,107 +0,0 @@ -# Advanced: Debugging ART Applications - -Debugging AI agents built with the ART Framework involves understanding the flow of data and decisions through its various components. Here are strategies and tools to help you troubleshoot and diagnose issues: - -## 1. Leverage the `Logger` - -ART's built-in `Logger` is your first line of defense. - -* **Set Log Level:** During development, configure the log level to `LogLevel.DEBUG` in your `ArtInstanceConfig` to get the most detailed output from framework internals. - ```typescript - // In ArtInstanceConfig - logger: { - level: LogLevel.DEBUG - } - ``` -* **Inspect Console Output:** Pay attention to logs prefixed with `[ART]` (or your custom prefix). Key events logged include: - * Initialization of components (`AgentFactory`, `StateManager`, `ProviderManager`, etc.). - * `ReasoningEngine` requesting and releasing adapters. - * `ProviderAdapter` making calls (often includes model ID, stream status). - * `OutputParser` warnings or errors during JSON parsing or validation. - * `ToolSystem` and `ToolRegistry` messages about tool execution and registration. - * `StateManager` messages about context loading or state saving (especially with `'implicit'` strategy). - * UI Socket activity (`subscribe`, `notify`). -* **Add Your Own Logs:** Use `Logger.debug()`, `Logger.info()`, `Logger.warn()`, and `Logger.error()` within your custom tools, agent logic, and adapter implementations to trace your application's specific flow. - -## 2. Utilize the `ObservationSystem` - -The `ObservationManager` records significant events during an agent's execution. This provides a structured audit trail. - -* **Subscribe to `ObservationSocket`:** In your development UI or a dedicated debugging tool, subscribe to `artInstance.uiSystem.getObservationSocket()`. - ```javascript - // Conceptual client-side subscription - // artInstance.uiSystem.getObservationSocket().subscribe( - // (observation) => { - // console.log('OBSERVATION:', observation.type, observation.title, observation.content); - // }, - // undefined, // No type filter (get all) - // { threadId: currentThreadId } // Filter by current thread - // ); - ``` -* **Inspect Observation Content:** - * `INTENT`, `PLAN`, `THOUGHTS`: See what the LLM understood and planned, including its raw reasoning if `<think>` tags were used and parsed. - * `TOOL_CALL`: View the exact tools and arguments the LLM requested. - * `TOOL_EXECUTION`: Check the `status` ('success' or 'error'), `input`, `output`, or `error` message for each tool call. This is vital for debugging tool issues. - * `SYNTHESIS`: See context before final response generation. - * `ERROR`: Pinpoint where and why an error occurred during a specific phase. - * `LLM_STREAM_START`, `LLM_STREAM_METADATA`, `LLM_STREAM_ERROR`, `LLM_STREAM_END`: Track the lifecycle of LLM calls. -* **Query Historical Observations:** Use `artInstance.observationManager.getObservations(threadId, filter?)` to retrieve past observations for a thread if you're debugging an issue after the fact. - -## 3. Inspect Stored Data (`StorageAdapter`) - -If you're using a persistent `StorageAdapter` like `IndexedDBStorageAdapter`: - -* **Browser Developer Tools:** - * Open your browser's developer tools (F12). - * Navigate to the "Application" (Chrome/Edge) or "Storage" (Firefox) tab. - * Find "IndexedDB" and expand your database (e.g., "MyAgentDB_ART"). - * You can inspect the content of object stores like: - * `conversations`: See the raw `ConversationMessage` objects. - * `observations`: Examine persisted `Observation` records. - * `state`: View the stored `ThreadContext` (containing `ThreadConfig` and `AgentState`). -* **Verify Data Integrity:** Check if messages, state, and configurations are being saved and loaded as expected. - -## 4. Debugging LLM Prompts and Responses - -This is often the most challenging part. - -* **Log Full Prompts:** In your custom agent logic or by modifying `PESAgent` (if you've forked it), log the complete `ArtStandardPrompt` object just before it's sent to `ReasoningEngine.call()`. - ```typescript - // Logger.debug("Sending to LLM (Planning):", JSON.stringify(planningPrompt, null, 2)); - ``` -* **Log Raw LLM Output:** Log the accumulated text from the LLM stream (e.g., `planningOutputText` in `PESAgent`) before it's passed to the `OutputParser`. This helps you see exactly what the LLM produced. -* **Isolate LLM Calls:** - * Temporarily bypass parts of your agent logic to test a specific LLM call with a fixed prompt directly. - * Use tools like Postman, Insomnia, or the LLM provider's own playground/workbench to send the *exact same prompt and parameters* that your adapter is sending. Compare the results. This can help determine if an issue is with your prompt, the model's behavior, or your adapter's translation. -* **Iterate on Prompts:** If the LLM isn't producing the desired output format (for planning, tool calls) or quality: - * Refine your system prompt. - * Improve tool descriptions (`ToolSchema.description`). - * Add or clarify instructions for output formatting (e.g., for the "Tool Calls:" JSON). - * Experiment with few-shot examples in the prompt. - * Consider using `<think>` tags to encourage the LLM to show its reasoning, then inspect the `thoughts` output by `OutputParser`. -* **Check Adapter Translation:** If you suspect an issue in how `ArtStandardPrompt` is being translated by a `ProviderAdapter`, add debug logs within the adapter's `call` method and its prompt translation helpers to see the provider-specific payload being generated. - -## 5. Debugging Tools (`IToolExecutor`) - -* **Validate `ToolSchema`:** Ensure your `inputSchema` is correct and accurately reflects the arguments your `execute` method expects. Use a JSON Schema validator tool. -* **Log Inside `execute()`:** Add detailed logging at the beginning of your tool's `execute` method to see the `input` it received and the `context`. Log key steps and the final `output` or `error`. -* **Test Tools in Isolation:** Write unit tests for your tool executors, mocking any external dependencies they might have. -* **Inspect `TOOL_EXECUTION` Observations:** These observations will show the exact `input` the `ToolSystem` passed to your tool (after validation) and the `ToolResult` it returned. - -## 6. TypeScript and Static Analysis - -* Leverage TypeScript's static type checking. Ensure your custom components correctly implement ART interfaces and use the defined types. -* Use a linter (like ESLint) to catch common errors and enforce code style. - -## 7. Step-Through Debugging - -* If running in Node.js or a browser environment with a debugger, set breakpoints in: - * Your custom agent logic. - * `PESAgent.process()` stages. - * `OutputParser.parsePlanningOutput()`. - * `ToolSystem.executeTools()`. - * Your custom tool's `execute()` method. - * The relevant `ProviderAdapter.call()` method. - This allows you to inspect variable values and understand the control flow at critical points. - -By combining these techniques, you can effectively debug your ART applications and gain a clear understanding of your agent's behavior. \ No newline at end of file diff --git a/Docs/advanced/index.md b/Docs/advanced/index.md deleted file mode 100644 index af19205..0000000 --- a/Docs/advanced/index.md +++ /dev/null @@ -1,165 +0,0 @@ -# Advanced Topics - -This section delves into more advanced concepts and customization options within the ART Framework, intended for developers looking to extend the framework or understand its deeper mechanics. - -## Topics: - -1. **[Extending the Framework](./extending-the-framework.md)** - * Guidance on implementing custom `IAgentCore`, `ProviderAdapter`, `StorageAdapter`, and `IToolExecutor`. - * Best practices for creating new systems or managers. - -2. **[Performance Tuning (Conceptual)](./performance-tuning.md)** - * Considerations for optimizing agent performance. - * Impact of `StorageAdapter` choice (e.g., `InMemoryStorageAdapter` vs. `IndexedDBStorageAdapter` vs. custom remote DB adapter). - * LLM call optimization (prompt engineering, model selection via `ProviderManager`). - * Caching strategies (e.g., `ProviderManager`'s adapter caching, potential for application-level caching). - * Efficient querying with custom `StorageAdapter`s. - -3. **[Security Considerations](./security-considerations.md)** - * Managing API keys and sensitive configuration. - * Input validation for tool arguments (handled by `ToolSystem` using JSON Schema). - * Risks associated with tools that execute arbitrary code or interact with external systems. - * Data privacy considerations for persisted conversation history and agent state. - * Securing UI socket communication channels if exposed externally. - -4. **[Debugging ART Applications](./debugging-art-applications.md)** - * Leveraging the `Logger` and `LogLevels`. - * Using the `ObservationSystem` (`ObservationManager`, `ObservationSocket`) to trace agent execution. - * Inspecting data in `StorageAdapter` (e.g., using browser developer tools for IndexedDB). - * Tips for debugging LLM prompts and responses. - -5. **[Understanding ProviderManager Internals](./understanding-provider-manager.md)** - * A deeper look into `ProviderManagerImpl`'s logic for: - * Configuration signature generation. - * Adapter instance caching and pooling. - * Idle instance eviction. - * Local provider constraints (singleton, busy checks, eviction on switch). - * API provider concurrency limits and request queuing. - * Relevant for developers troubleshooting multi-provider setups or needing to understand resource management nuances. - -These advanced topics provide further insight into how to make the most of the ART Framework's capabilities and tailor it to specific, complex requirements. -``` - -```markdown -docs/advanced/extending-the-framework.md -``` -```markdown -# Advanced: Extending the Framework - -The ART Framework is designed with extensibility in mind. Its modular architecture and reliance on interfaces allow developers to replace or augment core components with custom implementations to suit specific needs. - -Here are the primary ways you can extend the ART Framework: - -## 1. Implementing a Custom Agent Core (`IAgentCore`) - -While `PESAgent` provides a robust Plan-Execute-Synthesize flow, you might require a different reasoning pattern (e.g., ReAct, or a highly specialized task-specific flow). - -* **Steps:** - 1. Create a class that implements the `IAgentCore` interface (`src/core/interfaces.ts`). - 2. Implement the `async process(props: AgentProps): Promise<AgentFinalResponse>` method. This method will contain your custom agent's orchestration logic. - 3. Your agent's constructor should accept an object of dependencies it needs (e.g., `StateManager`, `ConversationManager`, `ReasoningEngine`, `ToolRegistry`, `ToolSystem`, `ObservationManager`, `UISystem`). These will be injected by the `AgentFactory`. - 4. In `ArtInstanceConfig`, set the `agentCore` property to your custom agent class constructor: - ```typescript - // import { MyCustomAgent } from './my-custom-agent'; - const artConfig: ArtInstanceConfig = { - // ... - agentCore: MyCustomAgent, - // ... - }; - ``` -* **Considerations:** - * Ensure your custom agent correctly interacts with the standard ART systems for context, history, tools, LLM calls, observations, and UI notifications to maintain framework compatibility. - * Properly handle `AgentProps` and return a valid `AgentFinalResponse`. - * Manage state persistence according to the configured `StateSavingStrategy` or by explicitly calling `StateManager.setAgentState()`. - * See [How-To: Create a Custom Agent](../how-to/create-custom-agent.md). - -## 2. Implementing a Custom LLM Provider Adapter (`ProviderAdapter`) - -If you need to connect to an LLM provider not yet supported by ART's built-in adapters: - -* **Steps:** - 1. Create a class that implements the `ProviderAdapter` interface (`src/core/interfaces.ts`). - 2. Set the `readonly providerName: string` property to a unique identifier. - 3. Implement the `async call(prompt: ArtStandardPrompt, options: CallOptions): Promise<AsyncIterable<StreamEvent>>` method: - * Translate the input `ArtStandardPrompt` to the provider's native API request format. - * Make the API call to the LLM provider (handle authentication, streaming if supported). - * Translate the provider's response/stream back into an `AsyncIterable<StreamEvent>`. - * Correctly set `StreamEvent.tokenType` based on `CallOptions.callContext` and any provider-specific cues. - 4. Optionally implement `async shutdown(): Promise<void>` for resource cleanup. - 5. Add an entry for your custom adapter in `ArtInstanceConfig.providers.availableProviders`: - ```typescript - // import { MyCustomLlmAdapter } from './my-custom-llm-adapter'; - const artConfig: ArtInstanceConfig = { - // ... - providers: { - availableProviders: [ - { name: 'my-llm', adapter: MyCustomLlmAdapter, isLocal: false /* or true */ }, - // ... other providers - ], - // ... - }, - // ... - }; - ``` -* **Considerations:** - * Thoroughly test prompt translation, especially for roles and tool/function calling constructs. - * Robustly handle API errors and map them to `ERROR` `StreamEvent`s with appropriate `ARTError` codes. - * Implement streaming correctly if the provider supports it. - * See [How-To: Add an LLM Provider Adapter](../how-to/add-llm-adapter.md). - -## 3. Implementing a Custom Storage Adapter (`StorageAdapter`) - -If you need to store ART data (conversations, observations, state) in a backend not supported by `InMemoryStorageAdapter` or `IndexedDBStorageAdapter` (e.g., a remote database, local files): - -* **Steps:** - 1. Create a class that implements the `StorageAdapter` interface (`src/core/interfaces.ts`). - 2. Implement all required methods: `get`, `set`, `delete`, `query`, and optionally `init`, `clearCollection`, `clearAll`. - 3. Your adapter's constructor should accept any necessary configuration (e.g., connection strings, API keys). - 4. In `ArtInstanceConfig.storage`, provide an instance of your custom adapter: - ```typescript - // import { MyCustomStorage } from './my-custom-storage'; - // const myDbConfig = { connection: '...' }; - // const customStorageAdapter = new MyCustomStorage(myDbConfig); - // await customStorageAdapter.init(); // Initialize if needed - - const artConfig: ArtInstanceConfig = { - // ... - storage: customStorageAdapter, // Pass the instance - // ... - }; - ``` -* **Considerations:** - * The `query` method can be complex to implement efficiently. Translate `FilterOptions` into native queries for your backend. - * Ensure data is handled securely if connecting to remote databases. - * Repositories expect an `id` property on stored objects to be used as the key. - * See [How-To: Create a Custom Storage Adapter](../../components/adapters/custom-storage-adapter.md). - -## 4. Implementing Custom Tools (`IToolExecutor`) - -This is one of the most common ways to extend an agent's capabilities. - -* **Steps:** - 1. Create a class that implements the `IToolExecutor` interface (`src/core/interfaces.ts`). - 2. Define the `readonly schema: ToolSchema`, including `name`, `description`, and `inputSchema` (JSON Schema). - 3. Implement the `async execute(input: any, context: ExecutionContext): Promise<ToolResult>` method with your tool's logic. - 4. Instantiate your tool and add it to the `tools: IToolExecutor[]` array in `ArtInstanceConfig`. -* **Considerations:** - * Input validation against `inputSchema` is handled by the `ToolSystem` before `execute` is called. - * Return a `ToolResult` indicating success or failure. - * Tools should be self-contained or manage their dependencies carefully. - * See [How-To: Define and Use Tools](../how-to/define-tools.md). - -## 5. Creating New Systems or Managers (Advanced) - -For more significant architectural changes or additions, you might consider creating entirely new systems or managers that adhere to ART's design principles (e.g., a new system for long-term memory that's more sophisticated than simple `AgentState`). - -* **Steps:** - 1. Define clear interfaces for your new components. - 2. Implement the components. - 3. Modify `AgentFactory` (if you're customizing the core framework setup) or your application's setup logic to instantiate and inject these new components into your custom `IAgentCore` or other relevant parts of the system. -* **Considerations:** - * This is a more advanced undertaking and requires a good understanding of ART's overall architecture. - * Aim for loose coupling and clear responsibilities. - * Consider how your new system will interact with existing ones like `ObservationManager` or `StateManager`. - -By leveraging these extension points, you can adapt the ART Framework to a wide range of specific requirements and build highly customized AI agent solutions. \ No newline at end of file diff --git a/Docs/advanced/performance-tuning.md b/Docs/advanced/performance-tuning.md deleted file mode 100644 index 44dee4f..0000000 --- a/Docs/advanced/performance-tuning.md +++ /dev/null @@ -1,75 +0,0 @@ -# Advanced: Performance Tuning (Conceptual) - -Optimizing the performance of an ART Framework application involves considering various factors, from the choice of underlying services (LLMs, storage) to the efficiency of your custom components and agent logic. This page offers conceptual guidance on areas to focus on for performance tuning. - -## 1. LLM Interaction - -LLM calls are often the most significant performance bottleneck. - -* **Model Selection (`RuntimeProviderConfig.modelId`):** - * **Latency vs. Capability:** Larger, more capable models (e.g., GPT-4o, Claude 3 Opus) generally have higher latency than smaller, faster models (e.g., GPT-3.5-Turbo, Claude 3 Haiku, Gemini Flash, local models like Llama 3 8B). - * **Task-Specific Models:** Choose the smallest, fastest model that can reliably perform the specific task (planning, synthesis, tool argument generation). You can use different models for different phases within `PESAgent` by providing different `RuntimeProviderConfig`s. - * **Fine-tuned Models:** For specific, repetitive tasks, fine-tuned models can sometimes offer better performance and accuracy than larger general-purpose models. -* **Streaming (`CallOptions.stream: true`):** - * **Always enable streaming for user-facing LLM responses.** This dramatically improves *perceived* performance by showing tokens as they are generated. - * Streaming can also be beneficial for internal agent "thought" processes if you want to log or observe them in real-time. -* **Prompt Engineering:** - * **Conciseness:** Shorter prompts (fewer input tokens) generally lead to faster responses and lower costs. - * **Clarity:** Well-structured prompts that clearly define the task and desired output format can reduce the need for the LLM to generate excessive "thinking" tokens or make multiple attempts. - * **Few-Shot Examples:** For complex tasks or tool usage, providing a few high-quality examples in the prompt can guide the LLM more effectively than lengthy instructions. -* **`max_tokens` / `maxOutputTokens`:** - * Set a reasonable `max_tokens` limit for LLM responses to prevent unexpectedly long (and slow) generations, especially for planning or intermediate steps. -* **Provider Latency:** - * Network latency to the LLM provider's API and the provider's own inference speed are factors. Choose providers or regions that offer lower latency if critical. -* **`ProviderManager` Configuration:** - * `maxParallelApiInstancesPerProvider`: If your application makes many concurrent LLM calls to the same API provider, ensure this is set appropriately. Too low might cause queueing; too high might hit rate limits or increase costs unnecessarily. - * `apiInstanceIdleTimeoutSeconds`: A shorter timeout will evict idle adapter instances sooner, potentially freeing up resources but might lead to more cold starts (re-instantiation) if calls are infrequent but bursty. - -## 2. Storage Adapter (`StorageAdapter`) - -The choice and implementation of your `StorageAdapter` can impact performance, especially for agents with long conversation histories or frequent state updates. - -* **`InMemoryStorageAdapter`:** Fastest for reads and writes as it's all in memory. Suitable for testing or ephemeral agents. Not for production persistence. -* **`IndexedDBStorageAdapter`:** - * Performance is generally good for typical browser use cases. - * **Querying:** The current `query()` method fetches all items for a collection (filtered by `threadId`) and then performs further filtering/sorting client-side. For very large histories or observation logs per thread, this could become slow. - * **Optimization:** For high-performance querying in IndexedDB, a custom adapter or an enhanced `IndexedDBStorageAdapter` would need to leverage IndexedDB indexes and cursors to perform filtering and sorting at the database level. -* **Custom Remote Database Adapter:** - * Network latency to your database will be a factor. - * Database indexing is crucial for efficient `query()` operations. Ensure your adapter translates `FilterOptions` into optimized database queries. - * Connection pooling and management within your adapter can affect performance. - -## 3. Agent Logic (`IAgentCore` - e.g., `PESAgent`) - -* **Minimize LLM Calls:** The `PESAgent` makes at least two LLM calls (plan, synthesize). If tools are used, it doesn't inherently add more LLM calls unless the *tools themselves* make LLM calls. Design agent flows to achieve goals with the fewest necessary LLM interactions. -* **Efficient Context Gathering:** - * `historyLimit` in `ThreadConfig`: Keep this reasonable. Sending excessively long histories to the LLM increases token count and latency. - * Optimize how `availableTools` are described in prompts. Very long tool descriptions can bloat prompts. -* **Tool Execution:** - * Tools that make network calls should be asynchronous and efficient. - * Avoid tools that perform very long-running computations synchronously, as this will block the agent's `process` method. -* **State Management (`StateSavingStrategy`):** - * `'implicit'` strategy involves JSON stringification for snapshotting and comparison. For very large or complex `AgentState` objects that change frequently, this could add minor overhead. `'explicit'` gives more control if state saving is a bottleneck. - -## 4. Asynchronous Operations - -ART heavily uses `async/await`. Ensure your custom components (tools, adapters, agent cores) correctly use asynchronous patterns to avoid blocking the event loop, especially for I/O-bound operations. - -## 5. Caching (Application Level) - -Beyond the `ProviderManager`'s adapter caching: - -* **Tool Results:** If a tool is likely to be called with the same input and produce the same output, consider implementing caching within the tool executor itself or via a caching decorator. -* **Frequently Accessed Configuration/Data:** If your agent frequently accesses static or slowly changing data, cache it at the application level rather than repeatedly fetching it. - -## 6. Observability and Profiling - -* Use `LogLevel.DEBUG` and the `ObservationSystem` during development to understand where time is being spent. -* Use browser or Node.js profiling tools to identify bottlenecks in your custom code or within framework components under load. - -## 7. Client-Side UI Performance (for Streaming) - -* Efficiently render incoming `TOKEN` `StreamEvent`s. Avoid excessive DOM manipulations for each token. Virtual rendering or batching updates can help for very fast streams. -* Debounce or throttle UI updates for frequent `Observation` events if they cause rendering jank. - -Performance tuning is an iterative process. Start by identifying the most critical paths and potential bottlenecks in your specific application, then measure, optimize, and measure again. \ No newline at end of file diff --git a/Docs/advanced/security-considerations.md b/Docs/advanced/security-considerations.md deleted file mode 100644 index 2bd3fa8..0000000 --- a/Docs/advanced/security-considerations.md +++ /dev/null @@ -1,87 +0,0 @@ -# Advanced: Security Considerations - -When developing AI agents with the ART Framework, especially those that interact with external services, use tools, or handle user data, security is a critical concern. Here are key areas to consider: - -## 1. API Key Management - -* **Never Hardcode API Keys:** API keys for LLM providers (OpenAI, Anthropic, etc.) or other services used by tools should **never** be hardcoded directly into your source code (client-side or server-side). -* **Environment Variables:** For server-side applications or during local development, use environment variables (e.g., `process.env.OPENAI_API_KEY`). Use a `.env` file (added to `.gitignore`) for local development convenience. -* **Secrets Management Services:** For production environments, use dedicated secrets management services like: - * AWS Secrets Manager - * Google Cloud Secret Manager - * Azure Key Vault - * HashiCorp Vault - Your application backend should securely fetch keys from these services at startup or on demand. -* **Backend Proxy for Client-Side Apps:** If your ART agent runs partly or wholly in a client-side environment (browser), **do not embed API keys directly in the client-side code.** Instead, have your client make requests to your own trusted backend server. Your backend server then securely holds the API keys and makes the calls to the LLM providers or other services on behalf of the client. This prevents exposure of your API keys to end-users. The `apiBaseUrl` option in `ProviderAdapter` configurations can be used to point adapters to your backend proxy. - -## 2. Tool Security - -Tools extend an agent's capabilities but can also introduce security risks if not handled carefully. - -* **Input Validation (`ToolSchema` & `validateJsonSchema`):** - * Always define a strict `inputSchema` (JSON Schema) for your tools. - * The `ToolSystem` uses `validateJsonSchema` to validate arguments provided by the LLM against this schema before executing the tool. This helps prevent injection attacks or unexpected behavior due to malformed input. - * Be specific with types, formats, and constraints in your JSON Schemas. -* **Principle of Least Privilege:** - * Tools should only have the minimum permissions necessary to perform their function. For example, a tool that reads from a database should use credentials with read-only access if it doesn't need to write. - * If a tool interacts with external APIs, the API keys it uses should be scoped to the minimum required permissions for that tool's operation. -* **Sandboxing:** - * For tools that execute code or evaluate expressions (like the `CalculatorTool` using `mathjs`), ensure they operate in a sandboxed or restricted environment to prevent execution of arbitrary, malicious code. The `CalculatorTool` uses a limited scope of `mathjs` functions. -* **Output Sanitization (Less Common for Tools, More for LLM):** - * While less common for direct tool output, if a tool's output is directly rendered in a UI without sanitization, be mindful of potential XSS vulnerabilities if the output could contain user-generated or externally sourced HTML/script content. Usually, the LLM's synthesis of tool output is the part that needs more careful handling for UI display. -* **Tool Enablement (`ThreadConfig.enabledTools`):** - * Use `ThreadConfig.enabledTools` to restrict which tools are available for a specific conversation thread or user context. This prevents an LLM from attempting to use inappropriate or unauthorized tools. `ToolRegistry` (if configured with `StateManager`) and `ToolSystem` respect this. - -## 3. LLM Prompt Injection - -* **Risk:** Malicious users might try to craft inputs (queries) that trick the LLM into ignoring previous instructions, revealing sensitive parts of its system prompt, or causing it to execute unintended tool calls. -* **Mitigations:** - * **Instructional System Prompts:** Clearly instruct the LLM on its role, capabilities, and limitations. Explicitly tell it not to deviate from its core instructions or reveal its full prompt. - * **Input Sanitization/Filtering (Limited Effectiveness):** While difficult to do perfectly, some basic filtering of user input for known malicious patterns or instruction-like phrases can be a layer of defense, but it's not foolproof. - * **Output Parsing & Validation:** Carefully parse and validate the LLM's output, especially the "Tool Calls:" section. The `OutputParser` and `ToolSystem`'s schema validation help here. Do not blindly execute any tool call suggested by the LLM. - * **Few-Shot Prompting with Examples:** Show the LLM examples of valid and invalid requests or tool uses to guide its behavior. - * **Defense in Depth:** Combine multiple strategies. Prompt injection is an ongoing research area. - * **Use Models with Built-in Defenses:** Some newer models are being trained to be more resilient to prompt injection. - -## 4. Data Privacy and Storage - -* **Conversation History (`ConversationRepository`):** - * Be mindful of the sensitivity of data stored in conversation logs. This can include Personally Identifiable Information (PII) or other confidential data shared by users. - * If using `IndexedDBStorageAdapter`, the data is stored on the user's client machine. Inform users about this data storage and its implications (e.g., accessible via browser dev tools). - * If using a custom `StorageAdapter` with a remote database: - * Ensure appropriate database security measures (access controls, network security). - * Encrypt data at rest and in transit. - * Implement robust authentication and authorization for database access. - * Implement data retention policies according to legal and business requirements. - * Provide mechanisms for users to export or delete their data if required by privacy regulations (e.g., GDPR, CCPA). -* **Agent State (`StateRepository`):** - * `AgentState` can also store sensitive user preferences or accumulated information. Apply the same privacy and security considerations as for conversation history. -* **Observations (`ObservationRepository`):** - * Observations can log detailed internal workings of the agent, including inputs to tools or intermediate LLM outputs (`<think>` tags). This data can be sensitive. - * Secure access to observation logs and apply retention policies. Avoid logging overly sensitive raw data directly into observation content if possible; prefer summaries or anonymized forms if the raw data isn't strictly needed for debugging. - -## 5. UI Socket Communication - -* If your ART application exposes its UI Sockets (`LLMStreamSocket`, `ObservationSocket`, `ConversationSocket`) over a network (e.g., via WebSockets to a frontend application): - * **Secure the Channel:** Use encrypted communication (e.g., WSS for WebSockets, HTTPS for Server-Sent Events). - * **Authentication & Authorization:** Implement authentication to ensure only legitimate clients can connect to the sockets. Authorize subscriptions based on user identity and thread ownership/permissions to prevent users from eavesdropping on or interfering with other users' sessions or threads. - * **Input Validation (for control messages):** If your socket protocol allows clients to send control messages to the backend, validate these messages rigorously. - -## 6. Denial of Service (DoS) / Resource Exhaustion - -* **LLM Costs:** Uncontrolled or malicious use of an agent that makes many LLM calls can lead to high costs. Implement rate limiting, quotas, or monitoring for API usage. -* **Tool Execution:** Tools that consume significant resources (CPU, memory, network bandwidth, external API quotas) could be targets for DoS if an attacker can trigger them repeatedly with expensive inputs. Implement input validation, timeouts, and rate limiting for such tools. -* **Storage Growth:** Unbounded conversation history or observation logging can lead to excessive storage consumption. Implement pruning or archival strategies. - -## 7. Third-Party Dependencies - -* Keep all third-party libraries, including the ART Framework itself and any SDKs (e.g., `@anthropic-ai/sdk`, `@google/genai`, `openai`), up to date with security patches. -* Audit dependencies for known vulnerabilities. - -## 8. Secure Development Practices - -* Follow standard secure coding practices (input validation, output encoding if rendering LLM output directly to HTML, proper error handling that doesn't leak sensitive information). -* Regularly review and audit your agent's prompts, tool configurations, and data handling logic for potential security weaknesses. -* Consider threat modeling for your specific agent application to identify potential attack vectors. - -Security is an ongoing process, not a one-time setup. As your agent's capabilities and integrations grow, continuously reassess and enhance its security posture. \ No newline at end of file diff --git a/Docs/advanced/understanding-provider-manager.md b/Docs/advanced/understanding-provider-manager.md deleted file mode 100644 index 4961d16..0000000 --- a/Docs/advanced/understanding-provider-manager.md +++ /dev/null @@ -1,74 +0,0 @@ -# Advanced: Understanding `ProviderManagerImpl` Internals - -The `ProviderManagerImpl` is a sophisticated component within the ART Framework responsible for managing access to various LLM `ProviderAdapter` instances. While developers typically interact with it indirectly via the `ReasoningEngine`, understanding its internal workings can be beneficial for troubleshooting multi-provider setups, optimizing resource usage, or extending its behavior. - -* **Source:** `src/providers/ProviderManagerImpl.ts` - -## Core Internal Mechanisms - -1. **Configuration Signature (`_getConfigSignature`)** - * **Purpose:** To create a unique, stable string identifier for a specific runtime configuration of a provider adapter. This signature is used as a key for caching and managing adapter instances. - * **Generation:** It stringifies a JSON object containing: - * `providerName` (from `RuntimeProviderConfig`) - * `modelId` (from `RuntimeProviderConfig`) - * A sorted version of `adapterOptions` (from `RuntimeProviderConfig`). Sorting the keys of `adapterOptions` ensures that `{ apiKey: "X", model: "Y" }` and `{ model: "Y", apiKey: "X" }` produce the same signature if they represent the same logical configuration. - * **Example:** A `RuntimeProviderConfig` for OpenAI with a specific model and API key will have a distinct signature from one for Anthropic or even OpenAI with a different model or API key. - -2. **Managed Instances (`managedInstances: Map<string, ManagedInstance>`)** - * **Purpose:** This internal map stores all adapter instances currently managed by the `ProviderManagerImpl`. - * **Key:** The `configSignature` string. - * **Value (`ManagedInstance` interface):** - * `adapter: ProviderAdapter`: The actual adapter instance. - * `configSignature: string`: The signature it was created with. - * `state: 'idle' | 'active'`: - * `'active'`: The adapter has been leased out (via `getAdapter`) and not yet released. - * `'idle'`: The adapter has been released and is available for reuse or eviction. - * `lastUsedTimestamp?: number`: Timestamp of when it was last released (moved to 'idle'). Used for API instance idle eviction. - * `idleTimer?: NodeJS.Timeout`: A reference to the `setTimeout` timer scheduled to evict this instance when it becomes idle (only for API-based providers). - -3. **Request Queue (`requestQueue: QueuedRequest[]`)** - * **Purpose:** To hold requests for API-based provider adapters when the `maxParallelApiInstancesPerProvider` limit for that provider `name` has been reached. - * **Value (`QueuedRequest` interface):** - * `config: RuntimeProviderConfig`: The original runtime config of the queued request. - * `resolve`: The `resolve` function of the Promise returned by the initial `getAdapter` call. - * `reject`: The `reject` function. - * **Processing:** When an active API adapter instance is released (`_releaseAdapter`), the `ProviderManagerImpl` checks this queue. If requests are pending, it attempts to process the oldest one by calling `getAdapter` again for that request. - -## Lifecycle of an Adapter Instance - -1. **Request (`getAdapter(runtimeConfig)`):** - * Signature is generated. - * **Cache Hit (Idle):** If an 'idle' instance with the same signature exists, its state becomes 'active', its idle timer (if any) is cleared, and it's returned. - * **Local Provider Checks:** - * If requesting a local provider: - * Throws `LocalProviderConflictError` if another *different* local provider is 'active'. - * Throws `LocalInstanceBusyError` if this *same* local provider instance is already 'active'. - * If another *different* local provider is 'idle', that idle provider is evicted (`_evictInstance`) before proceeding. - * **API Concurrency Check:** - * If requesting an API provider and the number of 'active' instances for that `providerName` meets `maxParallelApiInstancesPerProvider`, the request is added to `requestQueue`, and its promise will resolve later. - * **New Instance Creation:** If none of the above apply, a new adapter instance is created using `new providerEntry.adapter(runtimeConfig.adapterOptions)`. - * Throws `AdapterInstantiationError` if the constructor fails. - * The new instance is stored in `managedInstances` with state 'active'. - * A `ManagedAdapterAccessor` (containing the adapter and a `release` function bound to this signature) is returned. - -2. **Release (`accessor.release()`):** - * Called by the consumer (e.g., `ReasoningEngine`) when done with the adapter for a specific call. - * The corresponding `ManagedInstance` in `managedInstances` has its state set to 'idle' and `lastUsedTimestamp` updated. - * **Idle Timer (API Providers):** If it's an API provider, an idle timer is started using `apiInstanceIdleTimeoutMs`. If this timer expires before the instance is reused, `_evictInstance(configSignature)` is called. - * **Queue Processing:** The `requestQueue` is checked, and if pending requests exist, an attempt is made to fulfill the next one. - -3. **Eviction (`_evictInstance(configSignature)`):** - * Called by the idle timer for API providers or when a local provider needs to be replaced. - * Checks if the instance still exists and is 'idle'. - * If so, calls `instance.adapter.shutdown?.()` for graceful cleanup. - * Removes the instance from `managedInstances`. - * Clears its `idleTimer` if it was the one that triggered the eviction. - -## Key Trade-offs and Design Choices - -* **Caching by Signature:** Caching instances based on the full `RuntimeProviderConfig` (including sorted `adapterOptions`) ensures that if even a minor option (like `temperature` passed via `adapterOptions` instead of `CallOptions`) changes, a new, correctly configured instance is used or created. This prioritizes correctness over potentially reusing an instance that's "close enough." -* **Local Provider Singleton:** The strict singleton behavior for local providers (only one active at a time, even across different *types* of local providers like Ollama vs. LMStudio) simplifies resource management for local inference servers that might not handle concurrent requests well or might consume significant local resources. -* **API Concurrency per Provider Name:** The `maxParallelApiInstancesPerProvider` limit is applied per `AvailableProviderEntry.name`. This means if you define two entries for OpenAI (e.g., "openai-gpt4" and "openai-gpt3.5"), each will have its own concurrency pool. -* **Release Responsibility:** The consumer of the `ManagedAdapterAccessor` (i.e., `ReasoningEngine`) is critically responsible for calling `release()`. Failure to do so will lead to instances remaining 'active' indefinitely, potentially exhausting concurrency limits or preventing idle eviction. The `ReasoningEngine`'s stream wrapping mechanism is designed to ensure this. - -Understanding these internal details can help in configuring the `ProviderManagerConfig` optimally for your application's expected load and LLM usage patterns, as well as in diagnosing issues related to provider access or resource limits. \ No newline at end of file diff --git a/Docs/components/adapters/custom-storage-adapter.md b/Docs/components/adapters/custom-storage-adapter.md deleted file mode 100644 index 2a424cd..0000000 --- a/Docs/components/adapters/custom-storage-adapter.md +++ /dev/null @@ -1,168 +0,0 @@ -# Creating a Custom Storage Adapter - -The ART Framework's `StorageAdapter` interface allows you to integrate virtually any storage backend with your AI agent. If the built-in `InMemoryStorageAdapter` or `IndexedDBStorageAdapter` don't meet your needs (e.g., you want to use a remote database like PostgreSQL, MongoDB, Firebase, or store data in the local file system for a Node.js agent), you can create a custom adapter. - -## Steps to Create a Custom Storage Adapter - -1. **Understand the `StorageAdapter` Interface:** - Familiarize yourself with the methods defined in `src/core/interfaces.ts`: - - ```typescript - export interface StorageAdapter { - init?(config?: any): Promise<void>; - get<T>(collection: string, id: string): Promise<T | null>; - set<T>(collection: string, id: string, data: T): Promise<void>; - delete(collection: string, id: string): Promise<void>; - query<T>(collection: string, filterOptions: FilterOptions): Promise<T[]>; - clearCollection?(collection: string): Promise<void>; - clearAll?(): Promise<void>; - } - ``` - Your custom adapter class must implement these methods. - -2. **Create Your Adapter Class:** - Create a new TypeScript class that implements `StorageAdapter`. - - ```typescript - // src/my-adapters/my-custom-storage-adapter.ts - import { StorageAdapter, FilterOptions } from 'art-framework'; - // Import any client libraries for your target database - // import { MyDatabaseClient } from 'my-database-library'; - - export class MyCustomStorageAdapter implements StorageAdapter { - // private dbClient: MyDatabaseClient; // Example for a database client - - constructor(config: any) { - // Initialize your database client or connection parameters here - // Example: this.dbClient = new MyDatabaseClient(config.connectionString); - console.log("MyCustomStorageAdapter initialized with config:", config); - } - - async init(config?: any): Promise<void> { - // Perform any asynchronous setup, like connecting to the database - // or ensuring tables/collections exist. - // Example: await this.dbClient.connect(); - console.log("MyCustomStorageAdapter init() called.", config); - return Promise.resolve(); - } - - async get<T>(collection: string, id: string): Promise<T | null> { - console.log(`MyCustomStorageAdapter: Getting item from ${collection} with id ${id}`); - // Implement logic to fetch data from your storage backend - // Example: return await this.dbClient.table(collection).find(id); - return null; // Placeholder - } - - async set<T>(collection: string, id: string, data: T): Promise<void> { - console.log(`MyCustomStorageAdapter: Setting item in ${collection} with id ${id}`, data); - // Implement logic to save data (create or update) - // Ensure you handle the 'id' correctly as the primary key. - // ART repositories often store objects with an 'id' property that matches the 'id' parameter. - // Example: await this.dbClient.table(collection).upsert({ id, ...data }); - return Promise.resolve(); - } - - async delete(collection: string, id: string): Promise<void> { - console.log(`MyCustomStorageAdapter: Deleting item from ${collection} with id ${id}`); - // Implement logic to delete data - // Example: await this.dbClient.table(collection).remove(id); - return Promise.resolve(); - } - - async query<T>(collection: string, filterOptions: FilterOptions): Promise<T[]> { - console.log(`MyCustomStorageAdapter: Querying ${collection} with options`, filterOptions); - // Implement logic to query data based on FilterOptions. - // This is often the most complex part, as you'll need to translate - // FilterOptions (filter, sort, limit, skip) into queries supported - // by your storage backend. - // Example: - // const dbQuery = this.buildDbQuery(filterOptions); - // return await this.dbClient.table(collection).search(dbQuery); - return []; // Placeholder - } - - async clearCollection(collection: string): Promise<void> { - console.log(`MyCustomStorageAdapter: Clearing collection ${collection}`); - // Implement logic to remove all items from a collection - // Example: await this.dbClient.table(collection).truncate(); - return Promise.resolve(); - } - - async clearAll(): Promise<void> { - console.log("MyCustomStorageAdapter: Clearing all data"); - // Implement logic to remove all data managed by this adapter - // Example: await this.dbClient.dropAllTables(); - return Promise.resolve(); - } - - // Optional: Helper method to translate FilterOptions - // private buildDbQuery(filterOptions: FilterOptions): any { /* ... */ } - } - ``` - -3. **Implement Each Method:** - * **`constructor(config: any)`:** Accept any necessary configuration for your adapter (e.g., connection strings, API keys for a cloud database). - * **`init?(config?: any)`:** Perform asynchronous setup. This is called once by `AgentFactory`. - * **`get<T>(collection: string, id: string)`:** Fetch a single record. ART typically uses `collection` names like "conversations", "observations", "state". The `id` is the primary key. - * **`set<T>(collection: string, id: string, data: T)`:** Insert or update a record. The `data` object passed by ART repositories (like `ConversationRepository`, `StateRepository`) will usually have an `id` property that matches the `id` parameter. Your adapter should use this `id` as the key. - * **`delete(collection: string, id: string)`:** Remove a record. - * **`query<T>(collection: string, filterOptions: FilterOptions)`:** This can be challenging. - * `filterOptions.filter`: An object like `{ threadId: 'abc', type: 'USER' }`. You'll need to translate this into your backend's query language for exact matches. - * `filterOptions.sort`: An object like `{ timestamp: 'asc' }`. Translate to backend sorting. - * `filterOptions.limit` and `filterOptions.skip`: For pagination. - * If your backend doesn't support all these natively, you might need to fetch a broader set of data and perform some filtering/sorting client-side within the adapter (similar to how `InMemoryStorageAdapter` works), but this can be inefficient. - * **`clearCollection?` and `clearAll?` (Optional):** Implement if your backend supports these operations efficiently. - -4. **Handle Data Copying (Important for `set` and `get`):** - * When data is passed to `set()`, it's good practice to store a deep copy if your storage mechanism doesn't do this automatically. This prevents external modifications to the original object from affecting the stored version. `JSON.parse(JSON.stringify(data))` is a common way for simple objects. - * Similarly, when `get()` or `query()` returns data, return deep copies to prevent consumers from accidentally modifying the adapter's internal cache or the raw data from the store. - -5. **Error Handling:** - * Catch errors from your storage backend operations and re-throw them, or wrap them in custom error types if needed. The ART framework will handle these errors further up the chain. - -6. **Use Your Custom Adapter in `ArtInstanceConfig`:** - When creating your ART instance, provide an instance of your custom adapter: - - ```typescript - // src/config/art-config.ts - import { ArtInstanceConfig } from 'art-framework'; - import { MyCustomStorageAdapter } from '../my-adapters/my-custom-storage-adapter'; // Adjust path - - const myCustomAdapterConfig = { - // Options specific to your adapter's constructor - // connectionString: process.env.MY_DB_CONNECTION_STRING, - // apiKey: process.env.MY_CLOUD_DB_API_KEY, - }; - - const artConfig: ArtInstanceConfig = { - storage: new MyCustomStorageAdapter(myCustomAdapterConfig), // Pass an instance - providers: { - // ... your provider manager config ... - }, - // ... other ART configurations ... - }; - - // Then in your main application file: - // import { createArtInstance } from 'art-framework'; - // import { artConfig } from './config/art-config'; - // - // async function start() { - // const art = await createArtInstance(artConfig); - // // ... use art instance ... - // } - // start(); - ``` - -## Considerations for Custom Adapters: - -* **Asynchronicity:** All methods must return Promises. -* **Collection Names:** ART's default repositories use specific collection names: - * `ConversationRepository` uses `"conversations"`. - * `ObservationRepository` uses `"observations"`. - * `StateRepository` uses `"state"`. - Your adapter should be prepared to handle these collection names. -* **ID Management:** ART components often rely on an `id` field within the stored objects to serve as the primary key. Ensure your `set` method uses the provided `id` parameter as the key for storage, and that data objects passed to it will likely contain a matching `id` property. -* **Query Capabilities:** The more sophisticated your `query` method's translation of `FilterOptions` to native backend queries, the more efficient your data retrieval will be. Client-side filtering in the adapter should be a fallback for complex cases or simple backends. -* **Testing:** Thoroughly test your custom adapter, especially the `query` method with various `FilterOptions`. - -By implementing the `StorageAdapter` interface, you can seamlessly integrate ART with your preferred data persistence solution. \ No newline at end of file diff --git a/Docs/components/adapters/overview.md b/Docs/components/adapters/overview.md deleted file mode 100644 index aabef03..0000000 --- a/Docs/components/adapters/overview.md +++ /dev/null @@ -1,79 +0,0 @@ -# Adapters Overview - -In the ART Framework, **Adapters** are crucial components that bridge the gap between the framework's standardized interfaces and the diverse APIs of external services. They act as translators and intermediaries, allowing ART to interact with different systems (like LLM providers or storage backends) in a consistent way. - -There are two main categories of adapters in ART: - -1. **Reasoning Adapters (`ProviderAdapter`)** -2. **Storage Adapters (`StorageAdapter`)** - -## 1. Reasoning Adapters (`ProviderAdapter`) - -* **Interface:** `ProviderAdapter` (extends `ReasoningEngine`) from `src/core/interfaces.ts`. -* **Purpose:** To enable communication with various Large Language Model (LLM) providers. Each specific LLM service (e.g., OpenAI's GPT models, Anthropic's Claude models, Google's Gemini models, locally hosted models via Ollama) will have its own `ProviderAdapter` implementation. -* **Managed by:** `ProviderManager`. The `ReasoningEngine` requests adapters from the `ProviderManager` based on runtime configuration. - -**Key Responsibilities of a `ProviderAdapter`:** - -* **Implement `call(prompt: ArtStandardPrompt, options: CallOptions)`:** - * **Prompt Translation:** Takes ART's standard `ArtStandardPrompt` (an array of `ArtStandardMessage` objects) and translates it into the specific request format required by the target LLM provider's API. This includes mapping roles (e.g., ART's `assistant` to Gemini's `model`), content structures, and tool/function calling formats. - * **API Interaction:** Makes the actual HTTP request to the LLM provider's endpoint. This involves: - * Handling authentication (e.g., using API keys passed in `CallOptions.providerConfig.adapterOptions`). - * Setting appropriate headers. - * Sending the translated prompt payload. - * **Response Handling (Streaming):** If `CallOptions.stream` is `true`, the adapter must process the provider's streaming response (e.g., Server-Sent Events) and convert each data chunk into a standard ART `StreamEvent` (`TOKEN`, `METADATA`, `ERROR`, `END`). It returns an `AsyncIterable<StreamEvent>`. - * **Response Handling (Non-Streaming):** If streaming is not requested, the adapter makes a regular API call, waits for the full response, and then typically yields a minimal sequence of `StreamEvent`s (e.g., one `TOKEN` event with the full content, a `METADATA` event, and an `END` event) via an `AsyncIterable`. - * **Tool/Function Calling Support:** - * Formats `ToolSchema` definitions (from `CallOptions.tools`, though less common now as tools are usually described in the prompt by the agent) in a way the LLM understands for its function-calling capabilities. - * Parses tool call requests from the LLM's response (if the provider's format differs significantly from `ArtStandardMessage.tool_calls`). - * Formats `tool_result` messages correctly for the LLM when providing feedback from executed tools. -* **`providerName: string` (readonly):** A unique string identifying the provider (e.g., "openai", "anthropic"). -* **`shutdown?(): Promise<void>` (optional):** A method for graceful cleanup if the adapter holds persistent connections or resources. Called by the `ProviderManager` during eviction. - -**Built-in Reasoning Adapters:** - -ART `v0.2.7` includes adapters for: - -* `AnthropicAdapter` -* `DeepSeekAdapter` -* `GeminiAdapter` -* `OllamaAdapter` -* `OpenAIAdapter` -* `OpenRouterAdapter` - -(See `docs/components/adapters/reasoning/` for details on each.) - -## 2. Storage Adapters (`StorageAdapter`) - -* **Interface:** `StorageAdapter` from `src/core/interfaces.ts`. -* **Purpose:** To provide a generic persistence layer for ART's data, such as conversation history, agent state, and observations. This allows the framework to be independent of any specific database or storage mechanism. -* **Used by:** Repository classes (`ConversationRepository`, `ObservationRepository`, `StateRepository`). - -**Key Responsibilities of a `StorageAdapter`:** - -* **Implement CRUD-like operations:** - * `get<T>(collection: string, id: string): Promise<T | null>` - * `set<T>(collection: string, id: string, data: T): Promise<void>` - * `delete(collection: string, id: string): Promise<void>` - * `query<T>(collection: string, filterOptions: FilterOptions): Promise<T[]>` -* **`init?(config?: any): Promise<void>` (optional):** For any initialization tasks, like connecting to a database or setting up tables/stores. This is called by `AgentFactory` during ART instance setup. -* **`clearCollection?(collection: string): Promise<void>` (optional):** Clears all items from a specific collection. -* **`clearAll?(): Promise<void>` (optional):** Clears all data managed by the adapter. - -**Built-in Storage Adapters:** - -* **`InMemoryStorageAdapter`:** Stores all data in JavaScript Maps in memory. Data is lost when the application session ends. Useful for testing, demos, or ephemeral agents. -* **`IndexedDBStorageAdapter`:** Uses the browser's IndexedDB API for persistent client-side storage. Suitable for web applications where data needs to persist across sessions. - -(See `docs/components/adapters/storage/` for details on each.) - -## Why Adapters? - -The adapter pattern is fundamental to ART's design because it: - -* **Promotes Loose Coupling:** Core framework components (like `ReasoningEngine` or Repositories) interact with abstract interfaces (`ProviderAdapter`, `StorageAdapter`) rather than concrete implementations. -* **Enhances Extensibility:** Developers can easily add support for new LLM providers or storage backends by creating new classes that implement the respective adapter interfaces, without modifying the core framework. -* **Simplifies Maintenance:** Changes to a specific provider's API only require updates to its corresponding adapter, isolating the impact. -* **Facilitates Testing:** Mock adapter implementations can be easily created for unit and integration testing. - -By leveraging adapters, ART achieves a flexible and maintainable architecture capable of evolving with the rapidly changing landscape of AI services and data storage solutions. \ No newline at end of file diff --git a/Docs/components/adapters/reasoning/anthropic.md b/Docs/components/adapters/reasoning/anthropic.md deleted file mode 100644 index 64ae83f..0000000 --- a/Docs/components/adapters/reasoning/anthropic.md +++ /dev/null @@ -1,106 +0,0 @@ -# Anthropic Adapter (`AnthropicAdapter`) - -The `AnthropicAdapter` enables the ART Framework to interact with Anthropic's Claude models via their Messages API. It handles the translation of ART's standard prompt format (`ArtStandardPrompt`) into Anthropic's specific message structure and processes responses, including streaming and tool use. - -* **Source:** `src/adapters/reasoning/anthropic.ts` -* **Implements:** `ProviderAdapter` - -## Constructor Options - -When configuring the `AnthropicAdapter` within the `ProviderManagerConfig` (as part of `ArtInstanceConfig`) or providing `adapterOptions` in `RuntimeProviderConfig`, the following options are recognized by its constructor (`AnthropicAdapterOptions`): - -```typescript -export interface AnthropicAdapterOptions { - apiKey: string; // Required - model?: string; // Optional: Default model ID (e.g., 'claude-3-opus-20240229') - apiBaseUrl?: string; // Optional: Override Anthropic API base URL - defaultMaxTokens?: number; // Optional: Default max_tokens for responses - defaultTemperature?: number; // Optional: Default temperature -} -``` - -* **`apiKey: string` (Required):** Your Anthropic API key. -* **`model?: string` (Optional):** The default Anthropic model ID to use if not specified in `CallOptions` or `RuntimeProviderConfig.modelId`. Defaults to `'claude-3-haiku-20240307'` if not provided at all. - * Examples: `'claude-3-opus-20240229'`, `'claude-3-sonnet-20240229'`, `'claude-3-5-sonnet-20240620'`, `'claude-3-haiku-20240307'`. -* **`apiBaseUrl?: string` (Optional):** Allows overriding the default Anthropic API base URL (`https://api.anthropic.com/v1`). Useful for proxies or testing environments. The Anthropic SDK handles the final URL construction. -* **`defaultMaxTokens?: number` (Optional):** A default value for `max_tokens` to be sent to the Anthropic API if not overridden by `CallOptions.max_tokens` or `CallOptions.maxOutputTokens`. Defaults to `4096` (Anthropic's default for Claude 3 models if not specified by user). -* **`defaultTemperature?: number` (Optional):** A default temperature value if not overridden by `CallOptions.temperature`. - -**Example Configuration (`RuntimeProviderConfig.adapterOptions`):** - -```typescript -// In CallOptions.providerConfig.adapterOptions -const anthropicAdapterOpts = { - apiKey: process.env.ANTHROPIC_API_KEY, // Required - model: 'claude-3-sonnet-20240229', // Optional default for this specific config - defaultMaxTokens: 2000 // Optional -}; -``` - -## Prompt Translation (`ArtStandardPrompt` to Anthropic Messages API) - -The `AnthropicAdapter` translates the `ArtStandardPrompt` (an array of `ArtStandardMessage` objects) into the format expected by Anthropic's Messages API. Key translation behaviors include: - -* **Roles:** - * `system` messages in `ArtStandardPrompt` are combined and sent as the `system` parameter in the Anthropic API request. - * `user` messages map to Anthropic's `user` role. - * `assistant` messages map to Anthropic's `assistant` role. - * `tool_result` messages (from ART) map to an Anthropic `user` message containing a `tool_result` content block. -* **Message Merging:** Anthropic's API requires that messages strictly alternate between `user` and `assistant` roles. The adapter handles merging consecutive messages of the same translated role. For example, two back-to-back `user` messages in `ArtStandardPrompt` will be merged into a single `user` message with concatenated content for the Anthropic API. -* **Content:** - * Text content is passed directly. - * The adapter handles non-string content by attempting to stringify it, with warnings logged. -* **Tool Use:** - * **Tool Definition (`ToolSchema` to Anthropic `tools`):** - * When `CallOptions.tools` (an array of `ToolSchema`) is provided, the adapter translates these into Anthropic's `tools` format. The `input_schema` in Anthropic's tool definition directly uses the `inputSchema` (JSON Schema) from ART's `ToolSchema`. - * **Assistant Tool Calls (`ArtStandardMessage.tool_calls` to Anthropic `tool_use` content block):** - * If an `assistant` message in `ArtStandardPrompt` contains `tool_calls`, these are translated into `tool_use` content blocks in the Anthropic request. The `arguments` (which are stringified JSON in `ArtStandardMessage`) are parsed into a JSON object for Anthropic's `input` field. - * **Tool Results (`ArtStandardMessage` with `role: 'tool_result'` to Anthropic `tool_result` content block):** - * An `ArtStandardMessage` with `role: 'tool_result'` (containing `tool_call_id` and `content` as the stringified tool output/error) is translated into an Anthropic `user` message. This `user` message will contain a `tool_result` content block with the `tool_use_id` and the `content` (or `error` if applicable, though the adapter primarily passes content). - -## Streaming and `StreamEvent` Generation - -When `CallOptions.stream` is `true`, the `AnthropicAdapter` uses the Anthropic SDK's streaming capabilities. It processes the events from the Anthropic stream and translates them into ART `StreamEvent`s: - -* **`message_start` (Anthropic) -> `METADATA` (ART):** - * The initial `message_start` event from Anthropic, which includes `input_tokens` and initial `output_tokens` (often 0), is used to yield an initial `METADATA` `StreamEvent`. -* **`content_block_delta` (Anthropic) with `type: 'text_delta'` -> `TOKEN` (ART):** - * Each `text_delta` containing a piece of the response text results in a `TOKEN` `StreamEvent`. - * The `tokenType` is set based on `CallOptions.callContext` (e.g., `AGENT_THOUGHT_LLM_RESPONSE` or `FINAL_SYNTHESIS_LLM_RESPONSE`). Anthropic doesn't natively emit distinct "thinking" deltas that are easily distinguishable from response deltas without specific prompt engineering (like using `<search_quality_reflection>` tags, which this adapter doesn't automatically inject or parse for `tokenType` differentiation beyond `callContext`). -* **`content_block_delta` (Anthropic) with `type: 'input_json_delta'`:** - * These deltas contribute to the arguments of a `tool_use` block. The adapter accumulates these, and the full `tool_use` block (including the completely streamed arguments) is typically processed at `message_stop` or derived from the final message content. -* **`message_delta` (Anthropic) -> `METADATA` (ART):** - * This event provides cumulative `output_tokens` and the `stop_reason`. The adapter uses this to yield updated `METADATA` `StreamEvent`s. -* **`message_stop` (Anthropic) -> final `TOKEN` (if tool use) and `METADATA` (ART):** - * When the stream stops: - * If the `stop_reason` was `'tool_use'`, the adapter constructs a final `TOKEN` event. The `data` of this event will be an array of objects, each representing a tool call (`type: 'tool_use'`, `id`, `name`, `input`). If there was also preceding text from the assistant before the tool call, that text is included as a `{type: 'text', text: '...'}` object in the array. - * A final `METADATA` `StreamEvent` is yielded, containing the final token counts and stop reason. -* **Error Handling:** Errors from the Anthropic SDK or API during streaming are caught and yielded as an `ERROR` `StreamEvent`. - -## Non-Streaming Behavior - -If `CallOptions.stream` is `false`: - -1. The adapter makes a non-streaming call to the Anthropic Messages API. -2. It processes the `content` array in the response: - * Text blocks are concatenated. - * `tool_use` blocks are collected. -3. It yields a sequence of `StreamEvent`s: - * A single `TOKEN` event: - * If tool calls were made (`stop_reason: 'tool_use'`), the `data` will be an array structured similarly to the streaming `tool_use` case (text part + tool call objects). - * Otherwise, `data` is the trimmed concatenated text response. - * A `METADATA` event with usage details and stop reason from the API response. - * An `END` event. - -## Error Handling - -* API errors from Anthropic (e.g., authentication failure, invalid request) are caught and transformed into `ARTError` objects with `ErrorCode.LLM_PROVIDER_ERROR`. These are then yielded as `ERROR` `StreamEvent`s or thrown if not streaming. -* Invalid response structures (e.g., missing expected text content when not a tool call) will also result in an `ARTError` with `ErrorCode.LLM_PROVIDER_ERROR`. - -## Unique Features and Limitations - -* **SDK Usage:** The `AnthropicAdapter` leverages the official `@anthropic-ai/sdk`, which handles many low-level API details, including versioning. -* **Message Alternation:** The adapter internally manages the strict user/assistant message alternation required by Anthropic by merging consecutive messages of the same role before sending the request. -* **System Prompt:** Supports Anthropic's top-level `system` prompt parameter. -* **Tool Schema:** Directly uses JSON Schema for `input_schema` in tool definitions, aligning well with ART's `ToolSchema.inputSchema`. -* **No Explicit "Thinking" Detection for `tokenType`:** While Anthropic models do "think," the adapter doesn't currently parse specific XML tags (like `<search_quality_reflection>`) that might indicate internal thought processes to set a more granular `tokenType` beyond what `callContext` provides. All `TOKEN` events from a planning call will be `AGENT_THOUGHT_LLM_RESPONSE`, and from synthesis will be `FINAL_SYNTHESIS_LLM_RESPONSE`. \ No newline at end of file diff --git a/Docs/components/adapters/reasoning/deepseek.md b/Docs/components/adapters/reasoning/deepseek.md deleted file mode 100644 index 8573e8a..0000000 --- a/Docs/components/adapters/reasoning/deepseek.md +++ /dev/null @@ -1,92 +0,0 @@ -# DeepSeek Adapter (`DeepSeekAdapter`) - -The `DeepSeekAdapter` allows the ART Framework to connect to DeepSeek AI models, which offer an OpenAI-compatible API endpoint. This adapter primarily focuses on translating ART's standard prompt format to the OpenAI Chat Completions format expected by DeepSeek. - -* **Source:** `src/adapters/reasoning/deepseek.ts` -* **Implements:** `ProviderAdapter` - -## Constructor Options - -When configuring the `DeepSeekAdapter` (e.g., in `RuntimeProviderConfig.adapterOptions`), the following options are available (`DeepSeekAdapterOptions`): - -```typescript -export interface DeepSeekAdapterOptions { - apiKey: string; // Required - model?: string; // Optional: Default DeepSeek model ID - apiBaseUrl?: string; // Optional: Override API base URL -} -``` - -* **`apiKey: string` (Required):** Your DeepSeek API key. -* **`model?: string` (Optional):** The default DeepSeek model ID to use (e.g., `'deepseek-chat'`, `'deepseek-coder'`). If not provided, it defaults to `'deepseek-chat'`. This can be overridden by `RuntimeProviderConfig.modelId`. -* **`apiBaseUrl?: string` (Optional):** Allows overriding the default DeepSeek API base URL (`https://api.deepseek.com/v1`). - -**Example Configuration (`RuntimeProviderConfig.adapterOptions`):** - -```typescript -// In CallOptions.providerConfig.adapterOptions -const deepseekAdapterOpts = { - apiKey: process.env.DEEPSEEK_API_KEY, // Required - model: 'deepseek-coder' // Optional override for this specific config -}; -``` - -## Prompt Translation (`ArtStandardPrompt` to OpenAI Format) - -The `DeepSeekAdapter` uses a translation logic very similar to the `OpenAIAdapter` because DeepSeek's API is designed to be compatible with OpenAI's Chat Completions format. - -* **Roles:** - * `system` (ART) -> `system` (OpenAI) - * `user` (ART) -> `user` (OpenAI) - * `assistant` (ART) -> `assistant` (OpenAI) - * `tool_result` (ART) -> `tool` (OpenAI), including `tool_call_id` and `content`. -* **Content:** - * String content is passed directly. - * Non-string content for `user` or `system` roles is stringified with a warning. - * For `assistant` messages, `content` can be `null` if `tool_calls` are present. -* **Tool Use:** - * **Tool Definition (`ToolSchema`):** While DeepSeek's API documentation mentions tool/function calling similar to OpenAI, the current `DeepSeekAdapter` in ART `v0.2.7` does **not** explicitly translate `ToolSchema` from `CallOptions.tools` into the `tools` parameter for the DeepSeek API call. If tool definitions are required by the DeepSeek model being used, they would need to be part of the system prompt or user instructions. - * **Assistant Tool Calls (`ArtStandardMessage.tool_calls`):** If an `assistant` message in `ArtStandardPrompt` contains `tool_calls`, these are translated directly into the `tool_calls` array in the OpenAI message format. - * **Tool Results (`ArtStandardMessage` with `role: 'tool_result'`):** These are translated into OpenAI messages with `role: 'tool'`, including `tool_call_id` and the stringified `content`. - -## Streaming and `StreamEvent` Generation - -**Important: As of ART `v0.2.7`, streaming is NOT YET IMPLEMENTED for the `DeepSeekAdapter`.** - -* If `CallOptions.stream` is set to `true`, the adapter will: - 1. Log a warning: `"DeepSeekAdapter: Streaming requested but not implemented. Returning error stream."` - 2. Yield an `ERROR` `StreamEvent` with an `ARTError` indicating that streaming is not implemented. - 3. Yield an `END` `StreamEvent`. -* The call will effectively fail from a streaming perspective. - -## Non-Streaming Behavior - -When `CallOptions.stream` is `false` (or omitted): - -1. The adapter constructs the OpenAI-compatible payload. -2. It makes a non-streaming HTTP POST request to the DeepSeek API endpoint (`${apiBaseUrl}/chat/completions`). -3. **Response Handling:** - * It parses the JSON response from DeepSeek. - * It extracts the content from the first choice's message (`response.choices[0].message.content`). - * Tool calls in the response (`response.choices[0].message.tool_calls`) are logged but not explicitly processed further by this adapter for direct inclusion in the `TOKEN` data (unlike some other adapters that might combine text and tool calls in a structured `TOKEN` event). The agent logic would typically look for `finish_reason: 'tool_calls'` and then access the full message object. -4. **`StreamEvent` Yielding (Simulated Stream for Consistency):** - Even for non-streaming calls, ART adapters return an `AsyncIterable<StreamEvent>`. The `DeepSeekAdapter` will yield: - * A single `TOKEN` `StreamEvent`: - * `data`: The trimmed text content from `response.choices[0].message.content`. - * `tokenType`: Determined by `CallOptions.callContext` (e.g., `AGENT_THOUGHT_LLM_RESPONSE` or `FINAL_SYNTHESIS_LLM_RESPONSE`). - * A `METADATA` `StreamEvent`: Containing `inputTokens`, `outputTokens` (from `response.usage`), and `stopReason` (from `response.choices[0].finish_reason`). - * An `END` `StreamEvent`. - -## Error Handling - -* **API Errors:** If the DeepSeek API returns a non-200 status, the adapter attempts to parse an error message from the JSON response body (looking for `error.message`). This is then wrapped in an `ARTError` (ErrorCode: `LLM_PROVIDER_ERROR`) and yielded as an `ERROR` `StreamEvent` (or thrown if an error occurs before stream generation can begin). -* **Invalid Response Structure:** If the API response is 200 OK but doesn't contain the expected structure (e.g., `choices[0].message` is missing), an `ARTError` (ErrorCode: `LLM_PROVIDER_ERROR`) is generated and handled similarly. -* **Network Errors:** Fetch-related network errors are caught, wrapped in an `ARTError`, and handled. -* **Prompt Translation Errors:** Errors during the initial `ArtStandardPrompt` to OpenAI message translation (e.g., invalid `tool_call` structure in an assistant message) will result in an `ERROR` stream before any API call is made. - -## Unique Features and Limitations - -* **OpenAI Compatibility:** Relies on DeepSeek's OpenAI-compatible API, simplifying the adapter's translation logic. -* **No Streaming (Current Limitation):** Streaming is a significant missing feature that would improve responsiveness. -* **Basic Tool Call Handling:** Translates outgoing `tool_calls` and `tool_result` messages. However, it doesn't actively process or structure incoming tool calls from the LLM response into the `TOKEN` event data for non-streaming calls (the agent would inspect the raw `finish_reason` and message object). -* **No Explicit Tool Schema Transmission:** Does not send `ToolSchema` definitions as part of the `tools` parameter in the API request. \ No newline at end of file diff --git a/Docs/components/adapters/reasoning/gemini.md b/Docs/components/adapters/reasoning/gemini.md deleted file mode 100644 index 41a6fba..0000000 --- a/Docs/components/adapters/reasoning/gemini.md +++ /dev/null @@ -1,95 +0,0 @@ -# Gemini Adapter (`GeminiAdapter`) - -The `GeminiAdapter` integrates Google's Gemini models into the ART Framework using the `@google/genai` SDK. It handles translation between ART's `ArtStandardPrompt` and the Gemini API's content format, supports streaming, and maps tool functionalities. - -* **Source:** `src/adapters/reasoning/gemini.ts` -* **Implements:** `ProviderAdapter` - -## Constructor Options - -When configuring the `GeminiAdapter` (e.g., in `RuntimeProviderConfig.adapterOptions`), the following `GeminiAdapterOptions` are available: - -```typescript -export interface GeminiAdapterOptions { - apiKey: string; // Required - model?: string; // Optional: Default Gemini model ID - // apiBaseUrl and apiVersion are not directly used by the basic SDK setup -} -``` - -* **`apiKey: string` (Required):** Your Google AI API key (e.g., from Google AI Studio). -* **`model?: string` (Optional):** The default Gemini model ID to use (e.g., `'gemini-1.5-flash-latest'`, `'gemini-pro'`). If not provided, it defaults to `'gemini-1.5-flash-latest'`. This can be overridden by `RuntimeProviderConfig.modelId`. -* **`apiBaseUrl?: string` / `apiVersion?: string` (Not directly used by basic SDK setup):** The `@google/genai` SDK typically handles endpoint resolution. These are included for structural consistency but may not have an effect with standard SDK usage. - -**Example Configuration (`RuntimeProviderConfig.adapterOptions`):** - -```typescript -// In CallOptions.providerConfig.adapterOptions -const geminiAdapterOpts = { - apiKey: process.env.GEMINI_API_KEY, // Required - model: 'gemini-2.5-pro-preview-05-06' // Optional override -}; -``` - -## Prompt Translation (`ArtStandardPrompt` to Gemini `Content[]`) - -The `GeminiAdapter.translateToGemini()` method converts an `ArtStandardPrompt` into an array of `Content` objects suitable for the Gemini API: - -* **Roles:** - * `system` (ART): System prompt content is **prepended** to the content of the *first* `user` message in the sequence. Gemini doesn't have a separate top-level system prompt parameter in the same way as OpenAI or Anthropic for its `generateContent` history. - * `user` (ART) -> `user` (Gemini `Content.role`). - * `assistant` (ART) -> `model` (Gemini `Content.role`). - * `tool_result` (ART) -> `user` (Gemini `Content.role`). The content of this `user` message will be a `Part` object of type `functionResponse`. -* **Content Structure:** Each message in `ArtStandardPrompt` is translated into a Gemini `Content` object, which has a `role` and an array of `Part`s. - * Text content from `ArtStandardMessage.content` becomes a `Part` with a `text` field. - * Non-string user content is stringified. -* **Tool Use:** - * **Tool Definition (`ToolSchema` to Gemini `Tool`):** When `CallOptions.tools` (an array of `ToolSchema`) is provided, the adapter translates these into Gemini's `tools` format for function declaration. The `inputSchema` from ART's `ToolSchema` is used for Gemini's `parameters` schema. - * **Assistant Tool Calls (`ArtStandardMessage.tool_calls` to Gemini `functionCall` Part):** - * If an `assistant` message in `ArtStandardPrompt` contains `tool_calls`, these are translated into a `Part` object with a `functionCall` field within the corresponding `model` role `Content` object. Gemini expects `functionCall.args` to be an object, so the stringified JSON `arguments` from ART are parsed. - * **Tool Results (`ArtStandardMessage` with `role: 'tool_result'` to Gemini `functionResponse` Part):** - * An `ArtStandardMessage` with `role: 'tool_result'` (containing `tool_call_id`, `name` for the tool, and `content` as the stringified tool output) is translated into a `user` role `Content` object. This `Content` object will contain a single `Part` with a `functionResponse` field. The `functionResponse` includes the `name` of the tool and a `response` object, where `response.content` holds the tool's output from `ArtStandardMessage.content`. -* **Message Order Validation:** The adapter ensures the conversation history sent to Gemini does not start with a `model` role, prepending a dummy `user` turn if necessary. - -## Streaming and `StreamEvent` Generation - -When `CallOptions.stream` is `true`, the `GeminiAdapter` uses the `genAI.models.generateContentStream()` method from the `@google/genai` SDK. - -* **Stream Consumption:** The adapter iterates over the stream returned by the SDK. Each chunk from the Gemini stream is a `GenerateContentResponse` object. -* **`TOKEN` Events:** - * The `text()` method of each chunk is called to get the text delta. If text is present, a `TOKEN` `StreamEvent` is yielded. - * `tokenType` is set based on `CallOptions.callContext` (e.g., `AGENT_THOUGHT_LLM_RESPONSE`, `FINAL_SYNTHESIS_LLM_RESPONSE`). Gemini SDK does not provide a direct way to distinguish "thinking" tokens within a single stream response for more granular `tokenType`s. -* **`METADATA` Events:** - * The Gemini SDK's streaming response might include `usageMetadata` (like `promptTokenCount`, `candidatesTokenCount`) and `finishReason` (from `chunk.candidates[0].finishReason`) in later chunks, particularly the last one. - * The adapter attempts to extract this information from the **last chunk** received from the stream to construct and yield a final `METADATA` `StreamEvent`. `timeToFirstTokenMs` and `totalGenerationTimeMs` are also calculated. -* **`ERROR` Events:** Errors from the SDK during the stream or from processing chunks are caught and yielded as an `ERROR` `StreamEvent`. -* **`END` Event:** Yielded after the stream is fully consumed or an error terminates it. - -## Non-Streaming Behavior - -If `CallOptions.stream` is `false`: - -1. The adapter calls `genAI.models.generateContent()` from the SDK. -2. It processes the `GenerateContentResponse` object: - * Extracts text using `result.text()`. - * Gets `finishReason` from `result.candidates[0].finishReason`. - * Gets usage data from `result.usageMetadata`. - * Handles blocked content scenarios by checking `result.promptFeedback.blockReason`. If blocked, an `ERROR` event is yielded. -3. **`StreamEvent` Yielding (Simulated Stream):** - * A single `TOKEN` `StreamEvent` with the full `responseText`. - * A `METADATA` `StreamEvent` with token counts, stop reason, and timing. - * An `END` `StreamEvent`. - -## Error Handling - -* **SDK Errors:** Errors thrown by the `@google/genai` SDK (e.g., invalid API key, network issues) are caught and yielded as `ERROR` `StreamEvent`s (or thrown if occurring before stream generation). -* **Blocked Content:** If the Gemini API blocks content due to safety settings (indicated by `response.promptFeedback.blockReason`), an `ERROR` `StreamEvent` is yielded with a message like "Gemini API call blocked: SAFETY". -* **Invalid Response Structure:** If the SDK response is missing expected content (e.g., no text and not a tool call, or no candidates), an `ERROR` `StreamEvent` is yielded. -* **Prompt Translation Errors:** Errors during `ArtStandardPrompt` to Gemini `Content[]` translation (e.g., a `tool_result` message missing `tool_call_id` or `name`) result in an `ERROR` stream before any API call. - -## Unique Features and Limitations - -* **SDK Usage:** Relies entirely on the official `@google/genai` SDK for API interactions. -* **System Prompt Handling:** System prompts are merged into the first user message. -* **Tool Result Role:** `tool_result` messages are mapped to the `user` role with a `functionResponse` part, as per Gemini API requirements. -* **No Distinct "Thinking" Tokens:** The adapter does not currently have a mechanism to identify and flag "thinking" tokens from Gemini streams beyond the `callContext` provided in `CallOptions`. \ No newline at end of file diff --git a/Docs/components/adapters/reasoning/index.md b/Docs/components/adapters/reasoning/index.md deleted file mode 100644 index 56c259f..0000000 --- a/Docs/components/adapters/reasoning/index.md +++ /dev/null @@ -1,55 +0,0 @@ -# Reasoning Adapters - -Reasoning Adapters in the ART Framework are implementations of the `ProviderAdapter` interface. Their primary role is to enable communication with various Large Language Model (LLM) providers. They act as a translation layer, converting ART's standardized `ArtStandardPrompt` into the specific format required by an LLM provider's API, and then translating the provider's response back into a stream of standard `StreamEvent` objects. - -## The `ProviderAdapter` Interface - -All reasoning adapters must implement the `ProviderAdapter` interface (which extends `ReasoningEngine`), defined in `src/core/interfaces.ts`. - -**Key Requirements:** - -* **`providerName: string` (readonly):** A unique string identifying the provider (e.g., "openai", "anthropic", "google-gemini", "ollama"). -* **`constructor(options: any)`:** Adapters typically accept an `options` object in their constructor. This object is supplied by the `ProviderManager` based on the `RuntimeProviderConfig.adapterOptions` and may include: - * `apiKey`: The API key for the provider. - * `model` or `defaultModel`: The default model ID to use if not overridden in `CallOptions`. - * `apiBaseUrl` or `baseURL`: To target a custom API endpoint (e.g., for proxies or self-hosted models like Ollama). - * Other provider-specific settings (e.g., `defaultMaxTokens` for Anthropic). -* **`async call(prompt: ArtStandardPrompt, options: CallOptions): Promise<AsyncIterable<StreamEvent>>`:** - * This is the core method. - * It receives an `ArtStandardPrompt` (an array of `ArtStandardMessage` objects). - * It must translate this standard prompt into the native request format of the LLM provider it targets. This includes mapping roles, content structures, and tool/function call representations. - * It makes the actual API call to the LLM provider. - * If `options.stream` is true, it processes the provider's streaming response, yielding `StreamEvent` objects (`TOKEN`, `METADATA`, `ERROR`, `END`) as data arrives. - * If `options.stream` is false, it makes a non-streaming call and then typically yields a minimal sequence of `StreamEvent`s representing the complete response. - * It must correctly populate the `tokenType` field in `TOKEN` `StreamEvent`s based on `options.callContext` (e.g., `AGENT_THOUGHT_LLM_RESPONSE`, `FINAL_SYNTHESIS_LLM_RESPONSE`) and any ability to detect "thinking" steps from the LLM. -* **`shutdown?(): Promise<void>` (optional):** If the adapter manages persistent connections or resources, this method provides a way for graceful cleanup. It's called by the `ProviderManager` when an idle instance is evicted. - -## How Adapters are Used - -1. **Configuration:** Adapters are registered with the `ProviderManager` via `ArtInstanceConfig.providers.availableProviders`. -2. **Runtime Selection:** When `ReasoningEngine.call()` is invoked, the `CallOptions.providerConfig` specifies which provider (by `name`) and `modelId` to use, along with runtime `adapterOptions` (like the API key). -3. **Instantiation & Management:** The `ProviderManager` instantiates (or reuses an idle instance of) the selected adapter, passing the `adapterOptions` to its constructor. -4. **Delegation:** The `ReasoningEngine` delegates the `call` to the obtained adapter instance. - -## Available Reasoning Adapters - -ART `v0.2.7` includes the following built-in reasoning adapters: - -* **[Anthropic (`AnthropicAdapter`)](./anthropic.md):** For Claude models. -* **[DeepSeek (`DeepSeekAdapter`)](./deepseek.md):** For DeepSeek models. -* **[Gemini (`GeminiAdapter`)](./gemini.md):** For Google's Gemini models. -* **[Ollama (`OllamaAdapter`)](./ollama.md):** For interacting with locally hosted models via Ollama's OpenAI-compatible API. -* **[OpenAI (`OpenAIAdapter`)](./openai.md):** For OpenAI's GPT models (e.g., GPT-3.5, GPT-4, GPT-4o). -* **[OpenRouter (`OpenRouterAdapter`)](./openrouter.md):** For accessing a variety of models through the OpenRouter API. - -Click on each adapter name to learn more about its specific constructor options, prompt translation nuances, and any unique features. - -## Creating a Custom Reasoning Adapter - -If you need to integrate an LLM provider not yet supported by ART, you can create your own custom adapter. -See the [How-To Guide: Add an LLM Adapter](../../how-to/add-llm-adapter.md) for detailed instructions. The key steps involve: - -1. Creating a class that implements the `ProviderAdapter` interface. -2. Implementing the `call` method to handle prompt translation, API interaction, and `StreamEvent` generation. -3. Defining a constructor to accept necessary options (like API key, base URL). -4. Optionally implementing a `shutdown` method. \ No newline at end of file diff --git a/Docs/components/adapters/reasoning/ollama.md b/Docs/components/adapters/reasoning/ollama.md deleted file mode 100644 index d074f76..0000000 --- a/Docs/components/adapters/reasoning/ollama.md +++ /dev/null @@ -1,109 +0,0 @@ -# Ollama Adapter (`OllamaAdapter`) - -The `OllamaAdapter` allows the ART Framework to connect to various Large Language Models (LLMs) hosted locally via an [Ollama](https://ollama.com/) server. Ollama exposes an OpenAI-compatible API endpoint, so this adapter leverages the official `openai` Node.js SDK to communicate with it. - -* **Source:** `src/adapters/reasoning/ollama.ts` -* **Implements:** `ProviderAdapter` - -## Constructor Options - -When configuring the `OllamaAdapter` (e.g., in `RuntimeProviderConfig.adapterOptions`), the following `OllamaAdapterOptions` are available: - -```typescript -export interface OllamaAdapterOptions { - ollamaBaseUrl?: string; // Optional: Base URL for Ollama (e.g., 'http://localhost:11434') - defaultModel?: string; // Optional: Default Ollama model ID (e.g., 'llama3', 'mistral') - apiKey?: string; // Optional: API key if Ollama is secured (defaults to "ollama") -} -``` - -* **`ollamaBaseUrl?: string` (Optional):** The base URL of your Ollama server. - * Defaults to `'http://localhost:11434'`. - * The adapter automatically appends `/v1` to this URL to target Ollama's OpenAI-compatible API endpoint (e.g., `http://localhost:11434/v1`). -* **`defaultModel?: string` (Optional):** The default Ollama model ID to use (e.g., `'llama3'`, `'mistral'`, `'codellama:13b'`). This is required if no model is specified in `RuntimeProviderConfig.modelId` or `CallOptions.model`. It's highly recommended to set either this default or provide a model at runtime. -* **`apiKey?: string` (Optional):** The API key to use if your Ollama instance is secured. - * Defaults to `"ollama"`, which is a common placeholder for unsecured local Ollama instances. - -**Example Configuration (`RuntimeProviderConfig.adapterOptions`):** - -```typescript -// In CallOptions.providerConfig.adapterOptions -const ollamaAdapterOpts = { - // ollamaBaseUrl: 'http://my-ollama-server:11434', // Optional if not localhost - defaultModel: 'qwen3:14b-q4_K_M', // Recommended to set a default - // apiKey: 'my-secure-ollama-key' // If your Ollama instance uses an API key -}; -``` - -**Important:** A model ID **must** be available for each call, either from `OllamaAdapterOptions.defaultModel`, `RuntimeProviderConfig.modelId` (in `CallOptions.providerConfig`), or `CallOptions.model`. If no model is resolved, the call will fail. - -## Prompt Translation (`ArtStandardPrompt` to OpenAI Format) - -Since Ollama's API is OpenAI-compatible, the `OllamaAdapter` translates `ArtStandardPrompt` to the OpenAI Chat Completions message format. - -* **Roles:** - * `system` (ART) -> `system` (OpenAI) - * `user` (ART) -> `user` (OpenAI) - * `assistant` (ART) -> `assistant` (OpenAI) - * `tool_result` (ART) -> `tool` (OpenAI), including `tool_call_id` and `content`. -* **R1-Style Merging (for specific models like `deepseek-r1`):** - * If the `modelIdToUse` (resolved model ID for the call) contains "deepseek-r1" (case-insensitive), the adapter will merge consecutive `user` messages into a single `user` message, and consecutive `assistant` messages (including their `tool_calls`) into a single `assistant` message. This is to accommodate models that do not support alternating messages of the same role. - * For other models, messages are translated directly without this specific merging logic. -* **Content:** - * String content is passed directly. - * Non-string content for `user` or `system` roles is stringified with a warning. - * For `assistant` messages, `content` can be `null` if `tool_calls` are present. -* **Tool Use:** - * **Tool Definition (`ToolSchema` to OpenAI `tools`):** - * If `CallOptions.tools` (an array of `ToolSchema`) is provided, the adapter translates these into the `tools` parameter format expected by the OpenAI API (each tool becoming an object with `type: 'function'` and a `function` definition containing `name`, `description`, and `parameters` based on `ToolSchema.inputSchema`). - * **Assistant Tool Calls (`ArtStandardMessage.tool_calls`):** - * Translated directly into the `tool_calls` array in the OpenAI message format. - * **Tool Results (`ArtStandardMessage` with `role: 'tool_result'`):** - * Translated into OpenAI messages with `role: 'tool'`, including `tool_call_id` and the stringified `content`. - -## Streaming and `StreamEvent` Generation - -When `CallOptions.stream` is `true`: - -1. The adapter makes a streaming call to `this.client.chat.completions.create()` from the `openai` SDK, with `stream: true`. -2. It iterates over the chunks from the SDK's stream: - * **`TOKEN` Events:** - * Content from `chunk.choices[0].delta.content` is yielded as a `TOKEN` `StreamEvent`. - * `tokenType` is set based on `CallOptions.callContext`. - * **Tool Call Aggregation:** Deltas for `tool_calls` (`chunk.choices[0].delta.tool_calls`) are aggregated. Each tool call delta provides parts like `index`, `id`, `function.name`, and `function.arguments` (which itself can be streamed in parts). The adapter reconstructs the full tool call(s). - * **Final `TOKEN` for Tool Calls:** If the `finish_reason` for the stream is `'tool_calls'`, after all chunks are processed, a final `TOKEN` `StreamEvent` is yielded. Its `data` will be an array of objects, each representing an aggregated tool call (`type: 'tool_use'`, `id`, `name`, `input` (parsed from arguments string)). - * **`METADATA` Event:** - * Ollama's OpenAI-compatible stream *may* include a `usage` object in the final chunk (or sometimes per chunk, though less common for usage). The adapter captures this if present. - * A single `METADATA` `StreamEvent` is yielded at the end, containing the `stopReason` (from `chunk.choices[0].finish_reason`), estimated `outputTokens` (approximated by counting content chunks for streaming), `inputTokens` (if available from `finalApiResponseUsage`), `timeToFirstTokenMs`, and `totalGenerationTimeMs`. - * **`ERROR` Events:** Errors from the `openai` SDK or during stream processing are caught and yielded as an `ERROR` `StreamEvent`. - * **`END` Event:** Yielded after the stream is fully consumed or an error terminates it. - -## Non-Streaming Behavior - -When `CallOptions.stream` is `false`: - -1. The adapter makes a non-streaming call to `this.client.chat.completions.create()`. -2. It processes the response: - * Extracts text content from `response.choices[0].message.content`. - * Collects `tool_calls` from `response.choices[0].message.tool_calls`. -3. **`StreamEvent` Yielding (Simulated Stream):** - * A single `TOKEN` `StreamEvent`: - * If `tool_calls` are present: `data` is an array. If text content also exists, the first element is `{type: 'text', text: '...'}` followed by objects for each tool call (`type: 'tool_use'`, `id`, `name`, `input`). If only tool calls, it's just the array of tool call objects. - * If only text content: `data` is the trimmed text. - * `tokenType` is set based on `CallOptions.callContext`. - * A `METADATA` `StreamEvent` with `inputTokens`, `outputTokens` (from `response.usage`), `stopReason`. - * An `END` `StreamEvent`. - -## Error Handling - -* **API Errors:** Errors from the `openai` SDK (which wraps HTTP errors from Ollama) like `APIError` are caught. The status and message are extracted and wrapped in an `ARTError` (ErrorCode: `LLM_PROVIDER_ERROR`), then yielded as an `ERROR` `StreamEvent` or thrown. -* **Invalid Response Structure:** If the API response is 200 OK but malformed, an `ARTError` is generated. -* **Prompt Translation Errors:** Errors during `ArtStandardPrompt` translation result in an `ERROR` stream before any API call. -* **Missing Model ID:** If no model ID can be resolved for the call, an `ARTError` (ErrorCode: `INVALID_CONFIG`) is generated. - -## Unique Features and Limitations - -* **Uses `openai` SDK:** Leverages the official OpenAI Node.js SDK for robust interaction with Ollama's compatible endpoint. -* **Local Model Focus:** Primarily designed for local LLM inference via Ollama. -* **R1-Style Message Merging:** Includes specific logic to merge consecutive user or assistant messages for models like `deepseek-r1` that require strict role alternation. -* **Full Tool Support:** Implements translation for `ToolSchema` (to OpenAI `tools` format), outgoing `tool_calls`, and incoming `tool_result` messages, making it capable of function calling with compatible Ollama models. \ No newline at end of file diff --git a/Docs/components/adapters/reasoning/openai.md b/Docs/components/adapters/reasoning/openai.md deleted file mode 100644 index 0881a59..0000000 --- a/Docs/components/adapters/reasoning/openai.md +++ /dev/null @@ -1,101 +0,0 @@ -# OpenAI Adapter (`OpenAIAdapter`) - -The `OpenAIAdapter` facilitates communication between the ART Framework and OpenAI's suite of models (like GPT-3.5, GPT-4, GPT-4o) via their Chat Completions API. It handles prompt translation, streaming, and tool/function calling. - -* **Source:** `src/adapters/reasoning/openai.ts` -* **Implements:** `ProviderAdapter` - -## Constructor Options - -When configuring the `OpenAIAdapter` (e.g., in `RuntimeProviderConfig.adapterOptions`), the following `OpenAIAdapterOptions` are available: - -```typescript -export interface OpenAIAdapterOptions { - apiKey: string; // Required - model?: string; // Optional: Default OpenAI model ID - apiBaseUrl?: string; // Optional: Override API base URL -} -``` - -* **`apiKey: string` (Required):** Your OpenAI API key. -* **`model?: string` (Optional):** The default OpenAI model ID to use (e.g., `'gpt-4o'`, `'gpt-4-turbo'`, `'gpt-3.5-turbo'`). If not provided, it defaults to `'gpt-3.5-turbo'`. This can be overridden by `RuntimeProviderConfig.modelId`. -* **`apiBaseUrl?: string` (Optional):** Allows overriding the default OpenAI API base URL (`https://api.openai.com/v1`). Useful for Azure OpenAI Service or custom proxies. - -**Example Configuration (`RuntimeProviderConfig.adapterOptions`):** - -```typescript -// In CallOptions.providerConfig.adapterOptions -const openaiAdapterOpts = { - apiKey: process.env.OPENAI_API_KEY, // Required - model: 'gpt-4o-mini' // Optional override - // apiBaseUrl: 'https://YOUR_AZURE_OPENAI_RESOURCE.openai.azure.com/' // For Azure -}; -``` - -## Prompt Translation (`ArtStandardPrompt` to OpenAI Messages) - -The `OpenAIAdapter.translateToOpenAI()` method converts an `ArtStandardPrompt` into the `messages` array format expected by the OpenAI Chat Completions API: - -* **Roles:** - * `system` (ART) -> `system` (OpenAI) - * `user` (ART) -> `user` (OpenAI) - * `assistant` (ART) -> `assistant` (OpenAI) - * `tool_result` (ART) -> `tool` (OpenAI), including `tool_call_id` and `content`. -* **Content:** - * String content is passed directly. - * Non-string content for `user` or `system` roles is stringified with a warning. - * For `assistant` messages, `content` can be `null` if `tool_calls` are present (as per OpenAI API requirements). -* **Tool Use (Function Calling):** - * **Tool Definition (`ToolSchema` to OpenAI `tools`):** - * While the `OpenAIAdapter`'s `translateToOpenAI` method itself doesn't directly process `ToolSchema` (as this schema is usually passed in `CallOptions.tools` to the `call` method which then forms the main API payload), if `CallOptions.tools` are provided to the `OpenAIAdapter.call` method, they would be formatted into the `tools` parameter of the OpenAI API request. Each `ToolSchema` becomes an object with `type: 'function'` and a `function` definition (name, description, parameters from `inputSchema`). - * **Assistant Tool Calls (`ArtStandardMessage.tool_calls`):** - * If an `assistant` message in `ArtStandardPrompt` contains `tool_calls`, these are translated directly into the `tool_calls` array in the OpenAI message format. The `arguments` (stringified JSON in `ArtStandardMessage`) are passed as is. - * **Tool Results (`ArtStandardMessage` with `role: 'tool_result'`):** - * An `ArtStandardMessage` with `role: 'tool_result'` (containing `tool_call_id` and `content` as the stringified tool output/error) is translated into an OpenAI message with `role: 'tool'`, `tool_call_id`, and `content`. - -## Streaming and `StreamEvent` Generation - -When `CallOptions.stream` is `true`: - -1. The adapter makes an HTTP POST request to the OpenAI API with `stream: true` in the payload. -2. It processes the Server-Sent Events (SSE) stream from the API response body. -3. **`TOKEN` Events:** - * Each data chunk from the stream typically contains a `delta` object (e.g., `chunk.choices[0].delta.content` or `chunk.choices[0].delta.tool_calls`). - * If `delta.content` exists and is non-empty, a `TOKEN` `StreamEvent` is yielded with this content. - * `tokenType` is set based on `CallOptions.callContext`. - * **Tool Call Streaming:** OpenAI streams tool calls incrementally. The `delta.tool_calls` array will contain partial information for each tool call (e.g., just the `id` and `type` first, then `function.name`, then chunks of `function.arguments`). The adapter's `processStream` method attempts to aggregate these partial tool call deltas. - * *Note: The current `OpenAIAdapter.processStream` in `v0.2.7` has basic aggregation for `tool_calls`. A more robust implementation might be needed for complex, concurrent tool call streaming. The primary focus for streaming `TOKEN` events is usually on text content.* -4. **`METADATA` Event:** - * Information like `finish_reason` comes in a later chunk. Token usage (`prompt_tokens`, `completion_tokens`) is **not** typically provided by OpenAI in streaming responses. - * A `METADATA` `StreamEvent` is yielded at the end, containing the `stopReason` (if available) and estimated `outputTokens` (based on content chunks). `timeToFirstTokenMs` and `totalGenerationTimeMs` are also calculated. -5. **`ERROR` Events:** Errors during stream reading or JSON parsing of chunks are caught and yielded as `ERROR` `StreamEvent`s. -6. **`END` Event:** Yielded when the `data: [DONE]` signal is received from OpenAI or if an error terminates the stream. - -## Non-Streaming Behavior - -When `CallOptions.stream` is `false`: - -1. The adapter makes a non-streaming HTTP POST request. -2. It parses the full JSON response from OpenAI (`OpenAIChatCompletionResponse`). -3. **Response Handling:** - * Extracts text content from `response.choices[0].message.content`. - * Collects `tool_calls` from `response.choices[0].message.tool_calls`. -4. **`StreamEvent` Yielding (Simulated Stream):** - * A single `TOKEN` `StreamEvent`: - * `data`: The trimmed text content. *Note: If `tool_calls` are present, the OpenAI API usually sets `content` to `null` or an empty string. The `TOKEN` event will reflect this. The agent logic needs to inspect `finish_reason` and the full `message` object for tool calls.* - * `tokenType`: Determined by `CallOptions.callContext`. - * A `METADATA` `StreamEvent` with `inputTokens`, `outputTokens` (from `response.usage`), and `stopReason`. - * An `END` `StreamEvent`. - -## Error Handling - -* **API Errors:** If the OpenAI API returns a non-200 status, the adapter attempts to parse an error message from the JSON response body (`error.message`). This is wrapped in an `ARTError` (ErrorCode: `LLM_PROVIDER_ERROR`) and handled. -* **Invalid Response Structure:** If the API response is 200 OK but malformed (e.g., `choices[0].message` missing), an `ARTError` is generated. -* **Network Errors:** Fetch-related network errors are caught and wrapped. -* **Prompt Translation Errors:** Errors during `ArtStandardPrompt` to OpenAI message translation result in an `ERROR` stream. - -## Unique Features and Limitations - -* **Raw Fetch:** The current `OpenAIAdapter` in `v0.2.7` uses raw `fetch` calls. Future versions may migrate to the official `openai` SDK for potentially better type safety, error handling, and helper utilities. -* **Tool Call Streaming Aggregation:** Basic aggregation of streamed tool call deltas is attempted, but complex scenarios might require more sophisticated handling by the consuming agent logic if it needs fully formed tool calls *during* the stream. Typically, full tool call objects are reliably available in the final message object when the stream ends or in non-streaming responses. -* **No Streaming Usage Data:** OpenAI's streaming API does not provide token usage details in the stream itself. The `METADATA` event will have estimated `outputTokens` for streams. Full usage is only available in non-streaming responses. \ No newline at end of file diff --git a/Docs/components/adapters/reasoning/openrouter.md b/Docs/components/adapters/reasoning/openrouter.md deleted file mode 100644 index 2ac15ca..0000000 --- a/Docs/components/adapters/reasoning/openrouter.md +++ /dev/null @@ -1,100 +0,0 @@ -# OpenRouter Adapter (`OpenRouterAdapter`) - -The `OpenRouterAdapter` enables the ART Framework to connect to a wide variety of LLMs available through the [OpenRouter.ai](https://openrouter.ai/) service. OpenRouter provides an OpenAI-compatible API, so this adapter functions similarly to the `OpenAIAdapter`. - -* **Source:** `src/adapters/reasoning/openrouter.ts` -* **Implements:** `ProviderAdapter` - -## Constructor Options - -When configuring the `OpenRouterAdapter` (e.g., in `RuntimeProviderConfig.adapterOptions`), the following `OpenRouterAdapterOptions` are available: - -```typescript -export interface OpenRouterAdapterOptions { - apiKey: string; // Required: Your OpenRouter API key - model: string; // Required: The OpenRouter model identifier string - apiBaseUrl?: string; // Optional: Override OpenRouter API base URL - siteUrl?: string; // Optional: Your app's site URL (HTTP-Referer header) - appName?: string; // Optional: Your app's name (X-Title header) -} -``` - -* **`apiKey: string` (Required):** Your OpenRouter API key. -* **`model: string` (Required):** The specific OpenRouter model identifier string. This tells OpenRouter which underlying model to use. - * Examples: `'google/gemini-flash-1.5'`, `'anthropic/claude-3-haiku'`, `'openai/gpt-4o'`, `'mistralai/mistral-7b-instruct'`. - * You can find a list of available models on the OpenRouter website. - * This `model` field in `OpenRouterAdapterOptions` acts as the **default model for this adapter configuration**. It can be overridden by `RuntimeProviderConfig.modelId` if you want to use a different OpenRouter model for a specific call, as long as the `providerName` in `RuntimeProviderConfig` still points to this OpenRouter adapter setup. -* **`apiBaseUrl?: string` (Optional):** Allows overriding the default OpenRouter API base URL (`https://openrouter.ai/api/v1`). -* **`siteUrl?: string` (Optional):** Your application's site URL. If provided, it will be sent as the `HTTP-Referer` header in API requests, which is recommended by OpenRouter for analytics and identifying your application. -* **`appName?: string` (Optional):** Your application's name. If provided, it will be sent as the `X-Title` header, also recommended by OpenRouter. - -**Example Configuration (`RuntimeProviderConfig.adapterOptions`):** - -```typescript -// In CallOptions.providerConfig.adapterOptions -const openRouterAdapterOpts = { - apiKey: process.env.OPENROUTER_API_KEY, // Required - model: 'anthropic/claude-3-sonnet', // Required: The specific model on OpenRouter - siteUrl: 'https://my-art-app.com', - appName: 'My ART Application' -}; -``` - -## Prompt Translation (`ArtStandardPrompt` to OpenAI Format) - -Since OpenRouter uses an OpenAI-compatible API, the `OpenRouterAdapter` translates `ArtStandardPrompt` to the OpenAI Chat Completions message format, similar to the `OpenAIAdapter`. - -* **Roles:** - * `system` (ART) -> `system` (OpenAI) - * `user` (ART) -> `user` (OpenAI) - * `assistant` (ART) -> `assistant` (OpenAI) - * `tool_result` (ART) -> `tool` (OpenAI), including `tool_call_id` and `content`. -* **Content:** - * String content is passed directly. - * Non-string content for `user` or `system` is stringified with a warning. - * For `assistant` messages, `content` can be `null` if `tool_calls` are present. -* **Tool Use:** - * **Tool Definition (`ToolSchema`):** Like the `DeepSeekAdapter` and `OpenAIAdapter` (raw fetch version), the current `OpenRouterAdapter` does **not** explicitly translate `ToolSchema` from `CallOptions.tools` into the `tools` parameter for the API call. Tool definitions, if required by the specific model being used via OpenRouter, would need to be part of the system prompt or user instructions. - * **Assistant Tool Calls (`ArtStandardMessage.tool_calls`):** Translated directly to the `tool_calls` array in the OpenAI message format. - * **Tool Results (`ArtStandardMessage` with `role: 'tool_result'`):** Translated to OpenAI messages with `role: 'tool'`, `tool_call_id`, and stringified `content`. - -## Streaming and `StreamEvent` Generation - -**Important: As of ART `v0.2.7`, streaming is NOT YET IMPLEMENTED for the `OpenRouterAdapter`.** - -* If `CallOptions.stream` is set to `true`, the adapter will: - 1. Log a warning: `"OpenRouterAdapter: Streaming requested but not implemented. Returning error stream."` - 2. Yield an `ERROR` `StreamEvent` with an `ARTError` indicating that streaming is not implemented. - 3. Yield an `END` `StreamEvent`. -* The call will effectively fail from a streaming perspective. - -## Non-Streaming Behavior - -When `CallOptions.stream` is `false` (or omitted): - -1. The adapter constructs the OpenAI-compatible payload, including the `model` specified in its options (or overridden by `RuntimeProviderConfig.modelId`). -2. It makes a non-streaming HTTP POST request to the OpenRouter API endpoint (`${apiBaseUrl}/chat/completions`), including `HTTP-Referer` and `X-Title` headers if `siteUrl` and `appName` were provided in options. -3. **Response Handling:** - * Parses the JSON response from OpenRouter. - * Extracts content from `response.choices[0].message.content`. - * Tool calls in the response (`response.choices[0].message.tool_calls`) are logged but not explicitly processed into the `TOKEN` data. -4. **`StreamEvent` Yielding (Simulated Stream):** - * A single `TOKEN` `StreamEvent` with the trimmed text content. `tokenType` is based on `CallOptions.callContext`. - * A `METADATA` `StreamEvent` with `inputTokens`, `outputTokens` (from `response.usage`), and `stopReason`. OpenRouter responses often include detailed usage and sometimes cost information, which would be part of `providerRawUsage`. - * An `END` `StreamEvent`. - -## Error Handling - -* **API Errors:** Non-200 status codes from the OpenRouter API are handled by attempting to parse an error message from the JSON response body (`error.message`). This is wrapped in an `ARTError` (ErrorCode: `LLM_PROVIDER_ERROR`). -* **Invalid Response Structure:** Malformed 200 OK responses trigger an `ARTError`. -* **Network Errors:** Fetch-related errors are caught and wrapped. -* **Prompt Translation Errors:** Errors during prompt translation lead to an `ERROR` stream. -* **Missing API Key/Model:** Constructor throws an error if `apiKey` or `model` is missing. - -## Unique Features and Limitations - -* **Access to Many Models:** The primary advantage is leveraging OpenRouter's extensive catalog of LLMs through a single, consistent API interface. -* **OpenAI Compatibility:** Relies on OpenRouter's OpenAI-compatible API. -* **Recommended Headers:** Supports sending `HTTP-Referer` (`siteUrl`) and `X-Title` (`appName`) headers as recommended by OpenRouter. -* **No Streaming (Current Limitation):** Streaming is not yet implemented. -* **Basic Tool Call Handling:** Similar to `DeepSeekAdapter`, it translates outgoing `tool_calls` and `tool_result` messages but doesn't explicitly send `ToolSchema` definitions or process incoming tool calls into structured `TOKEN` data for non-streaming. \ No newline at end of file diff --git a/Docs/components/adapters/storage/inMemory.md b/Docs/components/adapters/storage/inMemory.md deleted file mode 100644 index 339d752..0000000 --- a/Docs/components/adapters/storage/inMemory.md +++ /dev/null @@ -1,75 +0,0 @@ -# `InMemoryStorageAdapter` - -The `InMemoryStorageAdapter` is a simple, fast, and dependency-free implementation of the `StorageAdapter` interface. It stores all data in JavaScript `Map` objects held in the current process's memory. - -* **Source:** `src/adapters/storage/inMemory.ts` -* **Implements:** `StorageAdapter` - -## Use Cases - -* **Testing:** Ideal for unit and integration tests due to its speed and lack of external dependencies. It allows for quick setup and teardown of storage state. -* **Demos and Examples:** Useful for simple demonstrations where data persistence is not a requirement. -* **Ephemeral Agents:** Suitable for agents that do not need to remember information across sessions or application restarts. -* **Development:** Can be a quick way to get started during development before setting up a persistent storage solution. - -## Key Characteristics - -* **Non-Persistent:** All data is lost when the application process ends (e.g., browser tab closed, Node.js server stopped). -* **Fast:** Operations are generally very fast as they involve direct memory access. -* **Deep Copies:** When setting or getting data, the adapter uses `JSON.parse(JSON.stringify(item))` to create deep copies. This prevents accidental modification of the stored data by external references and ensures that retrieved data is a fresh copy. -* **Client-Side Querying:** The `query()` method retrieves all items from a collection and then performs filtering and limiting client-side (within the adapter's code). This can be inefficient for very large datasets but is acceptable for its typical use cases. -* **No `init()` Configuration:** The `init()` method is a no-op as no external connections or setup are required. - -## Interface Implementation - -The `InMemoryStorageAdapter` implements all methods of the `StorageAdapter` interface: - -* **`async init(_config?: any): Promise<void>`:** - * Does nothing. Resolves immediately. -* **`async get<T>(collection: string, id: string): Promise<T | null>`:** - * Retrieves an item (as a deep copy) from the specified `collection` Map using the `id` as the key. - * Returns `null` if the collection or item doesn't exist. -* **`async set<T>(collection: string, id: string, data: T): Promise<void>`:** - * Stores a deep copy of the `data` in the `collection` Map, keyed by `id`. - * If the `collection` doesn't exist, it's created. -* **`async delete(collection: string, id: string): Promise<void>`:** - * Deletes an item from the `collection` Map. - * If the collection or item doesn't exist, it completes silently. -* **`async query<T>(collection: string, filterOptions: FilterOptions): Promise<T[]>`:** - * Retrieves all items from the `collection`. - * Applies basic exact-match filtering based on `filterOptions.filter`. - * Applies limiting based on `filterOptions.limit`. - * **Does not support sorting (`filterOptions.sort`) or skipping (`filterOptions.skip`) in the current implementation (`v0.2.7`).** - * Returns an array of deep copies of the matching items. -* **`async clearCollection(collection: string): Promise<void>`:** - * Removes the specified `collection` Map from storage. -* **`async clearAll(): Promise<void>`:** - * Clears all collections, effectively resetting the adapter's state. - -## Usage Example - -When configuring your ART instance: - -```typescript -// In ArtInstanceConfig -// import { InMemoryStorageAdapter } from 'art-framework'; // Not needed if using object config - -const artConfig = { - storage: { - type: 'memory' // This tells AgentFactory to use InMemoryStorageAdapter - }, - // ... other configurations (providers, tools, etc.) -}; - -// Or, if you want to instantiate it yourself (less common for basic use): -// import { InMemoryStorageAdapter } from 'art-framework'; -// const myInMemoryAdapter = new InMemoryStorageAdapter(); -// await myInMemoryAdapter.init(); // Though init is a no-op for this adapter - -// const artConfigWithInstance = { -// storage: myInMemoryAdapter, -// // ... -// }; -``` - -The `InMemoryStorageAdapter` provides a straightforward and convenient way to handle data for many development and testing scenarios within the ART Framework. \ No newline at end of file diff --git a/Docs/components/adapters/storage/index.md b/Docs/components/adapters/storage/index.md deleted file mode 100644 index 5f741ec..0000000 --- a/Docs/components/adapters/storage/index.md +++ /dev/null @@ -1,121 +0,0 @@ -# Storage Adapters - -Storage Adapters in the ART Framework provide a flexible and abstracted way to manage data persistence. They implement the `StorageAdapter` interface, defining a common set of methods for Create, Read, Update, Delete (CRUD) operations, and querying. This allows the rest of the framework, particularly Repository classes, to work with different storage backends without needing to know their specific implementation details. - -## The `StorageAdapter` Interface - -* **Source:** `src/core/interfaces.ts` - -The `StorageAdapter` interface defines the contract that all storage solutions must adhere to: - -```typescript -export interface StorageAdapter { - init?(config?: any): Promise<void>; // Optional initialization - - get<T>(collection: string, id: string): Promise<T | null>; - set<T>(collection: string, id: string, data: T): Promise<void>; - delete(collection: string, id: string): Promise<void>; - query<T>(collection: string, filterOptions: FilterOptions): Promise<T[]>; - - clearCollection?(collection: string): Promise<void>; // Optional - clearAll?(): Promise<void>; // Optional -} -``` - -**Key Methods:** - -* **`init?(config?: any)` (Optional):** - * Allows the adapter to perform any necessary setup, like connecting to a database, creating tables/object stores, or performing migrations. - * This method is called by `AgentFactory` during the ART instance initialization process. -* **`get<T>(collection: string, id: string)`:** - * Retrieves a single item of type `T` from the specified `collection` (analogous to a table or document store) using its unique `id`. - * Returns `null` if the item is not found. -* **`set<T>(collection: string, id: string, data: T)`:** - * Saves (creates or updates) an item in the `collection`. The `id` is used as the primary key. - * Implementations should ideally store deep copies of the `data` to prevent external mutations from affecting the stored version. -* **`delete(collection: string, id: string)`:** - * Removes an item from the `collection` by its `id`. -* **`query<T>(collection: string, filterOptions: FilterOptions)`:** - * Retrieves multiple items from a `collection` based on `FilterOptions`. - * `FilterOptions` can include: - * `filter`: An object for basic exact-match filtering (e.g., `{ threadId: 'abc' }`). - * `sort`: Sorting criteria (e.g., `{ timestamp: 'asc' }`). - * `limit`: Maximum number of items to return. - * `skip`: Number of items to skip (for pagination). - * The efficiency and capability of querying heavily depend on the underlying storage mechanism and the adapter's implementation. Simple adapters like `InMemoryStorageAdapter` might perform all filtering/sorting client-side. -* **`clearCollection?(collection: string)` (Optional):** - * Removes all items from a specific `collection`. -* **`clearAll?()` (Optional):** - * Removes all data managed by the adapter across all collections. Use with caution. - -## How Storage Adapters are Used - -1. **Configuration:** When creating an ART instance with `createArtInstance`, you specify the storage configuration in `ArtInstanceConfig.storage`. This can be: - * An object like `{ type: 'memory' }` or `{ type: 'indexedDB', dbName: 'MyData' }` to use a built-in adapter. - * A pre-instantiated object that implements the `StorageAdapter` interface. -2. **Initialization:** The `AgentFactory` instantiates the chosen adapter and calls its `init()` method. -3. **Repository Interaction:** Repository classes (`ConversationRepository`, `ObservationRepository`, `StateRepository`) are initialized with the `StorageAdapter` instance. They use the adapter's methods to perform their specific data management tasks (e.g., `ConversationRepository.addMessages` calls `adapter.set()`). - -## Built-in Storage Adapters - -ART `v0.2.7` provides two built-in storage adapters: - -1. **[`InMemoryStorageAdapter`](inMemory.md):** - * Stores all data in JavaScript Maps within the current process's memory. - * **Pros:** Very fast, no external dependencies, excellent for unit/integration testing, demos, or ephemeral agents where data persistence across sessions is not required. - * **Cons:** Data is lost when the application or browser tab closes. Querying is entirely client-side. -2. **[`IndexedDBStorageAdapter`](indexedDB.md):** - * Uses the browser's IndexedDB API for persistent client-side storage. - * **Pros:** Data persists across browser sessions, suitable for web applications needing to remember conversation history, user preferences, etc. - * **Cons:** Only available in browser environments. Querying capabilities are limited by IndexedDB's own features and the adapter's current implementation (which relies on `getAll()` and client-side filtering for complex queries). - -## Creating a Custom Storage Adapter - -If you need to integrate with a different storage backend (e.g., a remote database, local file system for Node.js applications, or a specific cloud storage service), you can create a custom storage adapter: - -1. Create a new class that implements the `StorageAdapter` interface. -2. Implement all the required methods (`get`, `set`, `delete`, `query`) and any optional ones (`init`, `clearCollection`, `clearAll`) to interact with your chosen storage system. -3. When configuring your ART instance, provide an instance of your custom adapter in `ArtInstanceConfig.storage`. - -**Example (Conceptual structure for a custom adapter):** - -```typescript -// import { StorageAdapter, FilterOptions } from 'art-framework'; -// import { MyDatabaseClient } from './my-db-client'; // Your DB client - -// export class MyCustomStorageAdapter implements StorageAdapter { -// private dbClient: MyDatabaseClient; - -// constructor(config: any) { -// this.dbClient = new MyDatabaseClient(config.connectionString); -// } - -// async init(): Promise<void> { -// await this.dbClient.connect(); -// // await this.dbClient.ensureTablesExist(['conversations', 'observations', 'state']); -// } - -// async get<T>(collection: string, id: string): Promise<T | null> { -// // return await this.dbClient.fetchById(collection, id); -// return null; // Placeholder -// } - -// async set<T>(collection: string, id: string, data: T): Promise<void> { -// // await this.dbClient.save(collection, id, data); -// } - -// async delete(collection: string, id: string): Promise<void> { -// // await this.dbClient.remove(collection, id); -// } - -// async query<T>(collection: string, filterOptions: FilterOptions): Promise<T[]> { -// // const dbQuery = this.translateFilterOptionsToDbQuery(filterOptions); -// // return await this.dbClient.find(collection, dbQuery); -// return []; // Placeholder -// } - -// // ... other methods -// } -``` - -This adapter system ensures that ART remains flexible and adaptable to various data storage needs. \ No newline at end of file diff --git a/Docs/components/adapters/storage/indexedDB.md b/Docs/components/adapters/storage/indexedDB.md deleted file mode 100644 index 772042a..0000000 --- a/Docs/components/adapters/storage/indexedDB.md +++ /dev/null @@ -1,76 +0,0 @@ -# `IndexedDBStorageAdapter` - -The `IndexedDBStorageAdapter` implements the `StorageAdapter` interface using the browser's built-in [IndexedDB API](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API). This adapter allows ART framework data (conversation history, agent state, observations) to be persisted client-side, meaning it will remain available across browser sessions. - -* **Source:** `src/adapters/storage/indexedDB.ts` -* **Implements:** `StorageAdapter` - -## Use Cases - -* **Web Applications:** Ideal for web-based AI agents where conversation history, user preferences, or agent state needs to be remembered between visits. -* **Offline Capabilities (Limited):** While not a full offline solution by itself, persisting data locally with IndexedDB is a step towards enabling some level of functionality when the user is offline. -* **Persistent Client-Side Demos:** For showcasing agent capabilities where data needs to survive page reloads. - -## Configuration (`IndexedDBConfig`) - -When specifying `'indexedDB'` as the storage type in `ArtInstanceConfig`, you can provide the following options: - -```typescript -export interface IndexedDBConfig { - dbName?: string; // Defaults to 'ART_Framework_DB' - dbVersion?: number; // Defaults to 1. Increment to trigger upgrades. - objectStores: string[]; // Names of object stores (collections) required. -} -``` - -* **`dbName?: string`:** The name of the IndexedDB database. - * Defaults to `'ART_Framework_DB'`. -* **`dbVersion?: number`:** The version of your database schema. - * Defaults to `1`. - * **Important:** You **must increment** this version number whenever you change the `objectStores` (e.g., add a new store, add an index to an existing store) to trigger the `onupgradeneeded` event, which is where schema modifications occur. -* **`objectStores: string[]` (Required by constructor, though `AgentFactory` might provide defaults):** An array of strings specifying the names of the object stores (collections) your application requires. - * The `AgentFactory` typically ensures that core stores like `'conversations'`, `'observations'`, and `'state'` are included if you use the simple `{ type: 'indexedDB', dbName: 'MyDB' }` config. If you provide an `objectStores` array yourself, ensure these core stores are present if your application uses the default repositories. - * Each object store created by the current adapter implementation uses `'id'` as its `keyPath`. This means that objects stored in these collections **must** have an `id` property that serves as their unique key. - -**Example Configuration (`ArtInstanceConfig.storage`):** - -```typescript -const artConfig = { - storage: { - type: 'indexedDB', - dbName: 'MyAgentDatabase_V2', // Custom database name - dbVersion: 2, // Increment if schemas changed from v1 - // objectStores: ['conversations', 'observations', 'state', 'myCustomStore'] // Explicitly list if needed - }, - // ... other configurations -}; -``` - -## Key Characteristics & Implementation Details - -* **`init()` Method:** - * This method **must be called and awaited** successfully before any other database operations (`get`, `set`, `delete`, `query`) can be performed. `AgentFactory` handles this during ART instance initialization. - * It opens the IndexedDB database connection. - * It handles the `onupgradeneeded` event: If the `dbVersion` provided in the config is higher than the existing database version, this event fires. The adapter uses this opportunity to create any object stores listed in `config.objectStores` that do not already exist. - * Current implementation creates object stores with `{ keyPath: 'id' }`. -* **Asynchronous Operations:** All database operations are asynchronous and return Promises. -* **Transactions:** Each operation (`get`, `set`, `delete`, `query` using `getAll`) is performed within an IndexedDB transaction. -* **Error Handling:** Errors from IndexedDB operations (e.g., transaction errors, request errors) are caught and typically re-thrown as standard JavaScript `Error` objects. -* **Deep Copies for `set`:** Uses `structuredClone(data)` before storing data with `put()` to ensure a deep copy is saved, preventing external modifications from affecting the stored version. -* **Querying (`query()` method):** - * The current implementation of `query()` retrieves **all** records from the specified collection using `store.getAll()`. - * Filtering (based on `filterOptions.filter`), sorting (based on `filterOptions.sort`), skipping (`filterOptions.skip`), and limiting (`filterOptions.limit`) are then performed **client-side** on this retrieved array. - * **Performance Note:** This client-side querying approach can be inefficient for very large datasets. For optimal performance with large collections, a more advanced implementation would leverage IndexedDB indexes and cursors to perform filtering and sorting directly within the database. The current adapter provides basic functionality suitable for many common use cases. -* **Browser Environment Only:** IndexedDB is a browser API and is not available in Node.js environments (unless a shim is used, which is outside the scope of this adapter). - -## Interface Implementation - -* **`async init(config: IndexedDBConfig)`:** Opens the database, handles upgrades to create specified object stores. -* **`async get<T>(collection: string, id: string): Promise<T | null>`:** Retrieves an item by ID from an object store. -* **`async set<T>(collection: string, id: string, data: T & { id: string })`:** Saves (creates/updates) an item. The `data` object **must** have an `id` property matching the `id` parameter, as this is used as the key for `store.put()`. A warning is logged if the provided `id` parameter and `data.id` mismatch, but `data.id` is used for the operation. -* **`async delete(collection: string, id: string): Promise<void>`:** Deletes an item by ID. -* **`async query<T>(collection: string, filterOptions: FilterOptions): Promise<T[]>`:** Fetches all items and applies filters/sort/limit client-side. -* **`async clearCollection(collection: string): Promise<void>`:** Clears all items from a specific object store. -* **`async clearAll(): Promise<void>`:** Clears all object stores managed by this adapter instance within the database. - -The `IndexedDBStorageAdapter` provides a robust solution for persistent client-side storage in web-based ART applications, enabling agents to maintain context and history across user sessions. \ No newline at end of file diff --git a/Docs/components/core/agent-factory.md b/Docs/components/core/agent-factory.md deleted file mode 100644 index ebbc6ec..0000000 --- a/Docs/components/core/agent-factory.md +++ /dev/null @@ -1,82 +0,0 @@ -# Deep Dive: `AgentFactory` and `createArtInstance` - -While developers primarily interact with the ART Framework through the `ArtInstance` object returned by `createArtInstance`, understanding the role of `AgentFactory` provides insight into how the framework is initialized and its components are wired together. - -## `createArtInstance(config: ArtInstanceConfig)` - -* **Source:** `src/core/agent-factory.ts` (exported via `src/index.ts`) -* **Purpose:** This is the **recommended high-level factory function** for setting up and obtaining a ready-to-use ART framework instance. -* **Process:** - 1. It takes a single `ArtInstanceConfig` object as input. - 2. Internally, it creates an instance of `AgentFactory` with this configuration. - 3. It calls `await factory.initialize()` to set up all core components. - 4. It then calls `factory.createAgent()` to get an instance of the configured `IAgentCore` (e.g., `PESAgent`). - 5. Finally, it constructs and returns an `ArtInstance` object, which bundles: - * The `process` method from the created agent core. - * Accessors to key systems like `uiSystem`, `stateManager`, `conversationManager`, `toolRegistry`, and `observationManager`. - -**Why use `createArtInstance`?** -It abstracts away the multi-step initialization process, providing a clean and simple entry point for developers. - -## `AgentFactory` Class - -* **Source:** `src/core/agent-factory.ts` -* **Purpose:** The `AgentFactory` is the internal workhorse responsible for instantiating and connecting all the different systems and managers within the ART framework based on the provided `ArtInstanceConfig`. - -**Constructor:** - -* `constructor(config: ArtInstanceConfig)`: Takes the main configuration object. It performs basic validation to ensure required fields like `storage` and `providers` are present. - -**Key Method: `async initialize(): Promise<void>`** - -This asynchronous method orchestrates the setup of all framework components in a specific order: - -1. **Storage System:** - * Based on `config.storage` (either a pre-configured `StorageAdapter` instance or an object like `{ type: 'memory' }` or `{ type: 'indexedDB', ... }`), it instantiates the appropriate `StorageAdapter` (`InMemoryStorageAdapter` or `IndexedDBStorageAdapter`). - * Calls `await storageAdapter.init()` to perform any necessary setup for the adapter (e.g., opening an IndexedDB connection and creating object stores). - -2. **Repositories:** - * Instantiates `ConversationRepository`, `ObservationRepository`, and `StateRepository`, injecting the initialized `StorageAdapter` into each. - -3. **UI System:** - * Instantiates `UISystemImpl`, injecting the `ObservationRepository` and `ConversationRepository` (which the sockets might use for their `getHistory` methods). - * The `UISystem` internally creates instances of `ObservationSocket`, `ConversationSocket`, and `LLMStreamSocket`. - -4. **Managers (Context & Observation):** - * `ConversationManagerImpl`: Initialized with the `ConversationRepository` and the `ConversationSocket` (obtained from `UISystem`). - * `StateManagerImpl`: Initialized with the `StateRepository` and the `config.stateSavingStrategy` (defaulting to `'explicit'`). - * `ObservationManagerImpl`: Initialized with the `ObservationRepository` and the `ObservationSocket` (obtained from `UISystem`). - -5. **Tool Registry & Initial Tools:** - * `ToolRegistryImpl`: Initialized, potentially with the `StateManager` instance (if `config.stateManager` was provided, allowing the registry to filter tools based on thread enablement). - * If `config.tools` (an array of `IToolExecutor` instances) is provided, it iterates through them and calls `toolRegistry.registerTool()` for each. - -6. **ProviderManager:** - * `ProviderManagerImpl`: Initialized with `config.providers` (`ProviderManagerConfig`), which defines all available LLM provider adapters and their settings. - -7. **Reasoning Components:** - * `ReasoningEngineImpl`: Initialized with the `ProviderManager` instance. - * `PromptManagerImpl`: Instantiated (currently stateless, mainly provides fragment access and validation). - * `OutputParserImpl`: Instantiated. - -8. **Tool System:** - * `ToolSystemImpl`: Initialized with the `ToolRegistry`, `StateManager`, and `ObservationManager`. - -**Key Method: `createAgent(): IAgentCore`** - -* This method is called *after* `initialize()` has successfully completed. -* It checks if all essential components (managers, engine, parser, systems) have been initialized. If not, it throws an error. -* It then instantiates the configured `IAgentCore` implementation. This is determined by `config.agentCore`, defaulting to `PESAgent`. -* It injects all the necessary initialized dependencies (like `stateManager`, `conversationManager`, `reasoningEngine`, etc.) into the agent core's constructor. -* Returns the created agent instance. - -**Getters:** - -The `AgentFactory` also provides public getter methods (e.g., `getStorageAdapter()`, `getUISystem()`, `getToolRegistry()`) that allow `createArtInstance` to retrieve the initialized components to bundle into the `ArtInstance` object. These getters return `null` if `initialize()` has not yet been called. - -**In essence:** - -* `ArtInstanceConfig` is the blueprint. -* `AgentFactory.initialize()` builds and wires all the framework parts according to the blueprint. -* `AgentFactory.createAgent()` assembles the "brain" (the agent core) using these parts. -* `createArtInstance()` wraps this entire process into a single, convenient function for the end-user. \ No newline at end of file diff --git a/Docs/components/core/interfaces.md b/Docs/components/core/interfaces.md deleted file mode 100644 index f01b401..0000000 --- a/Docs/components/core/interfaces.md +++ /dev/null @@ -1,128 +0,0 @@ -# Core Interfaces (`src/core/interfaces.ts`) - -The `src/core/interfaces.ts` file defines the fundamental contracts for the major components within the ART Framework. Implementing these interfaces allows for custom components to be seamlessly integrated into the framework. - -Below is a summary of the key public interfaces found in this file. For detailed TSDoc and specific method signatures, please refer directly to the source code. - -* **`IAgentCore`**: - * **Purpose:** The central orchestrator of an agent's reasoning and action cycle. - * **Key Method:** `process(props: AgentProps): Promise<AgentFinalResponse>` - * **Implementations:** `PESAgent` - -* **`ReasoningEngine`**: - * **Purpose:** Handles interaction with Large Language Models (LLMs). In ART `v0.2.7+`, this interface is primarily fulfilled by the `ReasoningEngineImpl` which uses `IProviderManager` to get specific provider adapters. - * **Key Method:** `call(prompt: FormattedPrompt, options: CallOptions): Promise<AsyncIterable<StreamEvent>>` - * Note: `FormattedPrompt` is an alias for `ArtStandardPrompt`. - * **Implementations:** `ReasoningEngineImpl` which delegates to `ProviderAdapter`s. - -* **`PromptManager`**: - * **Purpose:** Manages prompt fragments and validates constructed prompt objects. - * **Key Methods:** - * `getFragment(name: string, context?: Record<string, any>): string` - * `validatePrompt(prompt: ArtStandardPrompt): ArtStandardPrompt` - * **Implementations:** `PromptManagerImpl` - -* **`OutputParser`**: - * **Purpose:** Extracts structured information from raw LLM string outputs. - * **Key Methods:** - * `parsePlanningOutput(output: string): Promise<{ intent?: string; plan?: string; toolCalls?: ParsedToolCall[]; thoughts?: string; }>` - * `parseSynthesisOutput(output: string): Promise<string>` - * **Implementations:** `OutputParserImpl` - -* **`ProviderAdapter` (extends `ReasoningEngine`)**: - * **Purpose:** Adapts ART's standard prompt/event formats to a specific LLM provider's API. - * **Key Properties/Methods:** - * `providerName: string` (readonly) - * `call(...)`: Implements the actual LLM API interaction. - * `shutdown?(): Promise<void>` (optional) - * **Implementations:** `OpenAIAdapter`, `AnthropicAdapter`, `GeminiAdapter`, `OllamaAdapter`, etc. - -* **`IToolExecutor`**: - * **Purpose:** Defines the contract for an executable tool. - * **Key Properties/Methods:** - * `schema: ToolSchema` (readonly) - * `execute(input: any, context: ExecutionContext): Promise<ToolResult>` - * **Implementations:** `CalculatorTool`, custom user-defined tools. - -* **`ToolRegistry`**: - * **Purpose:** Manages the registration and retrieval of tool executors. - * **Key Methods:** - * `registerTool(executor: IToolExecutor): Promise<void>` - * `getToolExecutor(toolName: string): Promise<IToolExecutor | undefined>` - * `getAvailableTools(filter?: { enabledForThreadId?: string }): Promise<ToolSchema[]>` - * **Implementations:** `ToolRegistryImpl` - -* **`ToolSystem`**: - * **Purpose:** Orchestrates the execution of a sequence of tool calls. - * **Key Method:** `executeTools(toolCalls: ParsedToolCall[], threadId: string, traceId?: string): Promise<ToolResult[]>` - * **Implementations:** `ToolSystemImpl` - -* **`StateManager`**: - * **Purpose:** Manages thread-specific configuration (`ThreadConfig`) and state (`AgentState`). - * **Key Methods:** - * `loadThreadContext(threadId: string, userId?: string): Promise<ThreadContext>` - * `isToolEnabled(threadId: string, toolName: string): Promise<boolean>` - * `getThreadConfigValue<T>(threadId: string, key: string): Promise<T | undefined>` - * `saveStateIfModified(threadId: string): Promise<void>` - * `setThreadConfig(threadId: string, config: ThreadConfig): Promise<void>` - * `setAgentState(threadId: string, state: AgentState): Promise<void>` - * **Implementations:** `StateManagerImpl` - -* **`ConversationManager`**: - * **Purpose:** Manages conversation history (`ConversationMessage`). - * **Key Methods:** - * `addMessages(threadId: string, messages: ConversationMessage[]): Promise<void>` - * `getMessages(threadId: string, options?: MessageOptions): Promise<ConversationMessage[]>` - * **Implementations:** `ConversationManagerImpl` - -* **`ObservationManager`**: - * **Purpose:** Manages the recording and retrieval of agent execution observations. - * **Key Methods:** - * `record(observationData: Omit<Observation, 'id' | 'timestamp' | 'title'>): Promise<void>` - * `getObservations(threadId: string, filter?: ObservationFilter): Promise<Observation[]>` - * **Implementations:** `ObservationManagerImpl` - -* **`TypedSocket<DataType, FilterType = any>`**: - * **Purpose:** A generic publish/subscribe mechanism for UI or inter-component communication. - * **Key Methods:** - * `subscribe(callback: (data: DataType) => void, filter?: FilterType, options?: { threadId?: string }): UnsubscribeFunction` - * `notify(data: DataType, options?: { targetThreadId?: string; targetSessionId?: string }, filterCheck?: (data: DataType, filter?: FilterType) => boolean): void` - * `getHistory?(...)`: Optional method for historical data. - * **Implementations:** This is a base class. `ObservationSocket`, `ConversationSocket`, `LLMStreamSocket` extend it. - -* **`ObservationSocket` (extends `TypedSocket`)**: - * Specialized for `Observation` data. - -* **`ConversationSocket` (extends `TypedSocket`)**: - * Specialized for `ConversationMessage` data. - -* **`UISystem`**: - * **Purpose:** Provides access to the various UI communication sockets. - * **Key Methods:** - * `getObservationSocket(): ObservationSocket` - * `getConversationSocket(): ConversationSocket` - * `getLLMStreamSocket(): LLMStreamSocket` - * **Implementations:** `UISystemImpl` - -* **`StorageAdapter`**: - * **Purpose:** Generic interface for data persistence. - * **Key Methods:** `init?`, `get`, `set`, `delete`, `query`, `clearCollection?`, `clearAll?` - * **Implementations:** `InMemoryStorageAdapter`, `IndexedDBStorageAdapter`. - -* **`IConversationRepository`**: - * **Purpose:** Repository for `ConversationMessage` data, using a `StorageAdapter`. - * **Implementations:** `ConversationRepository` - -* **`IObservationRepository`**: - * **Purpose:** Repository for `Observation` data, using a `StorageAdapter`. - * **Implementations:** `ObservationRepository` - -* **`IStateRepository`**: - * **Purpose:** Repository for `ThreadContext` (config and state), using a `StorageAdapter`. - * **Implementations:** `StateRepository` - -* **`ArtInstance`**: - * **Purpose:** The main object returned by `createArtInstance`, providing top-level access to the framework's capabilities. - * **Key Properties (readonly):** `process`, `uiSystem`, `stateManager`, `conversationManager`, `toolRegistry`, `observationManager`. - -These interfaces define the contracts that allow ART's components to interact in a decoupled and extensible manner. \ No newline at end of file diff --git a/Docs/components/core/pes-agent.md b/Docs/components/core/pes-agent.md deleted file mode 100644 index 65833aa..0000000 --- a/Docs/components/core/pes-agent.md +++ /dev/null @@ -1,109 +0,0 @@ -# Deep Dive: `PESAgent` - -The `PESAgent` (Plan-Execute-Synthesize Agent) is the default agent core implementation provided by the ART Framework. It follows a structured, three-stage process to handle user queries, making it a robust foundation for many AI agent applications. - -* **Source:** `src/core/agents/pes-agent.ts` -* **Implements:** `IAgentCore` - -## The PES Flow - -When `PESAgent.process(props: AgentProps)` is called, it orchestrates the following flow: - -<!-- Placeholder for PESAgent.process() Sequence Diagram --> -<!-- Diagram should show: - 1. Input: AgentProps - 2. Load Context (StateManager, ConversationManager) - 3. Planning: - - Construct ArtStandardPrompt (planning) - - Call ReasoningEngine.call() -> StreamEvents - - Consume StreamEvents, buffer text - - Call OutputParser.parsePlanningOutput() -> intent, plan, toolCalls - - Record INTENT, PLAN, TOOL_CALL Observations - 4. Execution (if toolCalls exist): - - Call ToolSystem.executeTools(toolCalls) -> ToolResults - - ToolSystem records TOOL_EXECUTION Observations - 5. Synthesis: - - Construct ArtStandardPrompt (synthesis, including toolResults) - - Call ReasoningEngine.call() -> StreamEvents - - Consume StreamEvents, buffer final response text - - Record SYNTHESIS Observation - 6. Finalization: - - Save final AI message (ConversationManager) - - Save state if modified (StateManager based on StateSavingStrategy) - - Record FINAL_RESPONSE Observation - 7. Output: AgentFinalResponse ---> - -1. **Stage 1: Initiation & Configuration Loading** - * Loads the `ThreadContext` (which includes `ThreadConfig` and `AgentState`) for the current `props.threadId` using the injected `StateManager`. - * **Resolves the System Prompt**: The `PESAgent` determines the final system prompt by checking the following sources in order of precedence. The first custom prompt found is appended to the agent's internal base prompt (`DEFAULT_PES_SYSTEM_PROMPT`): - 1. **Call-Level**: `props.options.systemPrompt` (from the current `agent.process()` call). - 2. **Thread-Level**: `ThreadConfig.systemPrompt` (retrieved via `StateManager.getThreadConfigValue()`). - 3. **Instance-Level**: `ArtInstanceConfig.defaultSystemPrompt` (passed to `PESAgent` constructor via `AgentFactory` as `instanceDefaultCustomSystemPrompt`). - 4. **Agent Base Prompt**: If no custom prompt is found at any of the above levels, only the agent's internal `DEFAULT_PES_SYSTEM_PROMPT` is used. - * Determines the `RuntimeProviderConfig` to be used for LLM calls, prioritizing `props.options.providerConfig` if present, otherwise using `threadContext.config.providerConfig`. - -2. **Stage 2: Planning Context Assembly** - * Fetches the recent conversation `history` for the thread using `ConversationManager`, respecting the `historyLimit` from `ThreadConfig`. - * Gets a list of `ToolSchema`s for tools available to this thread from `ToolRegistry` (which may consult `StateManager` if configured to do so). - * Formats the history into a structure suitable for the prompt. - -3. **Stage 3: Planning Prompt Construction & LLM Call** - * **Prompt Construction:** The `PESAgent` directly constructs an `ArtStandardPrompt` object (an array of `ArtStandardMessage` objects). This planning prompt typically includes: - * A `system` message with the resolved system prompt. - * `user` and `assistant` messages from the formatted conversation `history`. - * A final `user` message that includes: - * The current `props.query`. - * Descriptions of the `availableTools` (name, description, input schema stringified). - * Instructions for the LLM to identify intent, create a plan, and specify any `Tool Calls` in a specific JSON format. - * *(The `PESAgent` may use `PromptManager.getFragment()` to fetch parts of these instructions, but it assembles the final `ArtStandardPrompt` object itself.)* - * **LLM Call:** - * Calls `reasoningEngine.call(planningPrompt, callOptions)`. - * `callOptions` will include `stream: true` and `callContext: 'AGENT_THOUGHT'`, along with the determined `RuntimeProviderConfig`. - * The `PESAgent` then consumes the `AsyncIterable<StreamEvent>` returned by the `ReasoningEngine`. - * `TOKEN` events are buffered to accumulate the complete text output of the LLM's planning phase. - * `LLM_STREAM_START`, `LLM_STREAM_METADATA`, `LLM_STREAM_ERROR`, and `LLM_STREAM_END` observations are recorded via `ObservationManager`. UI sockets are notified. - * **Output Parsing:** - * The accumulated text from the planning LLM call is passed to `outputParser.parsePlanningOutput()`. - * This parser extracts the `intent`, `plan` description, and an array of `ParsedToolCall` objects. It also handles `<think>` tags via `XmlMatcher`. - * `INTENT`, `PLAN`, and `TOOL_CALL` `Observation`s are recorded. - -4. **Stage 4: Tool Execution** - * If `parsedPlanningOutput.toolCalls` is not empty, these calls are passed to `toolSystem.executeTools()`. - * The `ToolSystem` handles enabling checks, input validation, execution of each tool, and records `TOOL_EXECUTION` observations. - * It returns an array of `ToolResult` objects. - * If any tool execution results in an error, the overall status of the agent process might be marked as `'partial'`. - -5. **Stage 5: Synthesis Prompt Construction & LLM Call** - * **Prompt Construction:** A new `ArtStandardPrompt` is constructed for the synthesis phase. It typically includes: - * The `system` message. - * The formatted conversation `history`. - * A `user` message detailing: - * The original `props.query`. - * The `intent` and `plan` from the planning phase. - * The `ToolResult`s from the execution phase (including successes and errors, with outputs stringified). - * Instructions for the LLM to synthesize a final, user-facing response based on all this information. - * **LLM Call:** - * Calls `reasoningEngine.call(synthesisPrompt, callOptions)`. - * `callOptions` will include `stream: true` and `callContext: 'FINAL_SYNTHESIS'`, plus the `RuntimeProviderConfig`. - * The `PESAgent` consumes the `StreamEvent`s. - * `TOKEN` events (specifically those with `tokenType` indicating final synthesis, like `FINAL_SYNTHESIS_LLM_RESPONSE`) are buffered to form the final AI response content. - * Stream-related observations are recorded, and UI sockets are notified. - * The accumulated text from the synthesis LLM call becomes the agent's final textual response. No separate parsing step (`outputParser.parseSynthesisOutput`) is strictly needed for the content itself in `v0.2.7` as the raw stream output is used. - -6. **Stage 6: Finalization** - * A new `ConversationMessage` (with `role: MessageRole.AI`) is created containing the final synthesized response content. - * This AI message is saved to the conversation history using `conversationManager.addMessages()`. - * `FINAL_RESPONSE` observation is recorded. - * `stateManager.saveStateIfModified(props.threadId)` is called. Its behavior depends on the `StateSavingStrategy`: - * If `'implicit'`, it checks if `threadContext.state` was modified during the `process` call and saves it if necessary. - * If `'explicit'`, this call is a no-op for `AgentState` (state must be saved via explicit calls to `stateManager.setAgentState()`). - * An `AgentFinalResponse` object is constructed, containing the final AI message and `ExecutionMetadata` (status, duration, LLM/tool call counts, errors). - -## Error Handling - -* Critical errors during planning or synthesis (e.g., LLM provider errors, prompt assembly failures) will typically cause the `process()` method to throw an `ARTError`. -* Tool execution failures are generally caught by the `ToolSystem` and returned as error `ToolResult`s. The `PESAgent` then incorporates these error results into the synthesis prompt, allowing the LLM to potentially explain the tool failure to the user. The overall status in `ExecutionMetadata` might be set to `'partial'`. -* If synthesis itself fails after tools have run, the status might also be `'partial'`, and the error message might become the content of the final AI response. - -The `PESAgent` provides a well-defined and observable flow for agent operations, making it easier to build, debug, and extend complex AI agents. \ No newline at end of file diff --git a/Docs/components/providers/provider-manager.md b/Docs/components/providers/provider-manager.md deleted file mode 100644 index 7d5c86e..0000000 --- a/Docs/components/providers/provider-manager.md +++ /dev/null @@ -1,84 +0,0 @@ -# Deep Dive: `ProviderManager` - -The `ProviderManager` (implemented by `ProviderManagerImpl` in `src/providers/ProviderManagerImpl.ts`) is a cornerstone of the ART Framework's ability to support multiple Large Language Model (LLM) providers. It centralizes the management and access to different `ProviderAdapter` instances, enabling dynamic selection of LLMs at runtime. - -## Purpose and Role - -The `ProviderManager` serves several key functions: - -1. **Adapter Abstraction:** It decouples the `ReasoningEngine` from concrete `ProviderAdapter` implementations. The `ReasoningEngine` doesn't need to know how to instantiate or manage specific adapters; it simply requests one from the `ProviderManager`. -2. **Lifecycle Management:** It handles the creation, caching, and eviction of `ProviderAdapter` instances to optimize resource usage and manage connections. -3. **Configuration Hub:** It's configured at application startup with all *available* providers and their base settings, and then uses *runtime* configuration to select and prepare an adapter for a specific LLM call. -4. **Constraint Enforcement:** It manages rules like concurrency limits for API-based providers and singleton behavior for local providers. - -## Configuration - -The `ProviderManager` relies on two types of configuration: - -1. **`ProviderManagerConfig` (`src/types/providers.ts`):** - * Provided once when the ART instance is created via `createArtInstance(artConfig)`. - * **`availableProviders: AvailableProviderEntry[]`**: An array defining each LLM provider the application *can* use. - * `name: string`: A unique identifier for this provider setup (e.g., "openai-gpt4o", "ollama-llama3"). This name is crucial for runtime selection. - * `adapter: new (options: any) => ProviderAdapter`: The constructor of the adapter class (e.g., `OpenAIAdapter`, `OllamaAdapter`). - * `isLocal?: boolean` (default: `false`): If `true`, the provider is treated as a local singleton (only one local provider type active at a time). - * `baseOptions?: any`: Rarely used; default options for the adapter if not overridden at runtime. - * **`maxParallelApiInstancesPerProvider?: number`** (default: `5`): Limits concurrent *active* instances for each non-local (API-based) provider `name`. - * **`apiInstanceIdleTimeoutSeconds?: number`** (default: `300`): How long an API-based adapter instance can be idle before being eligible for eviction. - -2. **`RuntimeProviderConfig` (`src/types/providers.ts`):** - * Provided dynamically within the `CallOptions` for each call to `ReasoningEngine.call()`. - * **`providerName: string`**: Must match one of the `name`s in `ProviderManagerConfig.availableProviders`. This selects which provider setup to use. - * **`modelId: string`**: The specific model ID for that provider (e.g., "gpt-4o-mini", "claude-3-opus-20240229"). - * **`adapterOptions: any`**: Options passed directly to the selected adapter's constructor. This is where API keys, specific model parameters (if not set in `CallOptions`), or `baseURL` overrides are typically provided. - -## Key Method: `getAdapter(config: RuntimeProviderConfig)` - -This is the primary method used by the `ReasoningEngine`. It returns a `Promise<ManagedAdapterAccessor>`. - -* **`ManagedAdapterAccessor`**: An object containing: - * `adapter: ProviderAdapter`: The ready-to-use adapter instance. - * `release: () => void`: A function that **must** be called by the consumer (e.g., `ReasoningEngine`) once it's finished with the adapter for that particular LLM call. Releasing the adapter allows the `ProviderManager` to manage its state (e.g., mark as idle, make available for reuse, or queue processing). - -**Internal Logic of `getAdapter()`:** - -1. **Signature Generation:** Creates a unique string signature based on `RuntimeProviderConfig` (providerName, modelId, sorted adapterOptions) for caching purposes. -2. **Cache Check (Reuse Idle):** - * If an **idle** instance with the same signature exists in the cache, it's marked as **active**, its idle timer is cleared, and it's returned. -3. **Local Provider Constraints:** - * If the requested provider is `isLocal: true`: - * **Conflict Check:** If another *different* local provider is currently **active**, throws `LocalProviderConflictError`. - * **Busy Check:** If the *same* local provider instance (same signature) is already **active** (i.e., obtained but not yet released), throws `LocalInstanceBusyError`. - * **Evict Other Idle Local:** If a *different* local provider is **idle**, that idle provider is evicted (shut down and removed) before proceeding to create the newly requested one. This ensures only one local provider instance (regardless of type) is managed at a time. -4. **API Provider Concurrency Limits:** - * If the requested provider is *not* local: - * Counts the number of **active** instances for the *same provider name*. - * If this count reaches `maxParallelApiInstancesPerProvider`, the request is **queued**. The promise returned by `getAdapter` will resolve when an instance becomes available and this queued request is processed. - * *(Note: The `ProviderManagerImpl` does not currently implement a timeout for waiting in the queue itself; this would be an `ApiQueueTimeoutError` if implemented.)* -5. **Instance Creation:** - * If no suitable idle instance is found and no constraints prevent it, a new `ProviderAdapter` instance is created using the constructor from `AvailableProviderEntry` and the `adapterOptions` from `RuntimeProviderConfig`. - * Throws `AdapterInstantiationError` if the adapter constructor fails. -6. **Store and Return:** - * The new instance is marked as **active** and stored in the `managedInstances` map. - * A `ManagedAdapterAccessor` (containing the adapter and its `release` function) is returned. - -## Releasing Adapters and Idle Eviction - -* **`release()` function:** When the `ReasoningEngine` finishes using an adapter (i.e., the LLM stream is fully consumed or an error occurs), it **must** call the `release()` function associated with that adapter instance. -* **State Transition:** `release()` transitions the adapter's state in the `ProviderManager` from 'active' to 'idle'. -* **Idle Timer (API Providers):** For non-local (API) providers, releasing an adapter starts an idle timer (`apiInstanceIdleTimeoutSeconds`). If the instance remains idle and the timer expires, the `_evictInstance` method is called. -* **Eviction (`_evictInstance`):** - * Checks if the instance is still 'idle'. - * Calls the adapter's `shutdown()` method, if it exists, for graceful cleanup. - * Removes the instance from the `managedInstances` map. -* **Queue Processing:** After an adapter is released, `_releaseAdapter` checks the `requestQueue`. If there are pending requests, it attempts to fulfill the oldest one by calling `getAdapter` again. - -## Error Handling - -The `ProviderManagerImpl` can throw several specific errors (extending `ARTError`): - -* `UnknownProviderError`: If `RuntimeProviderConfig.providerName` is not found in `availableProviders`. -* `LocalProviderConflictError`: If attempting to activate a local provider while another is already active. -* `LocalInstanceBusyError`: If attempting to get an already active local provider instance. -* `AdapterInstantiationError`: If the adapter's constructor throws an error. - -The `ProviderManager` is a sophisticated component that enables ART's powerful multi-LLM capabilities, balancing flexibility with resource management and operational constraints. \ No newline at end of file diff --git a/Docs/components/systems/context/context-provider.md b/Docs/components/systems/context/context-provider.md deleted file mode 100644 index 1520662..0000000 --- a/Docs/components/systems/context/context-provider.md +++ /dev/null @@ -1,63 +0,0 @@ -# Deep Dive: `ContextProvider` - -The `ContextProvider` is a component within ART's Context System. In the current version of the ART Framework (`v0.2.7`), it serves primarily as a **placeholder** for future enhancements, particularly for integrating Retrieval-Augmented Generation (RAG) capabilities. - -* **Source:** `src/systems/context/ContextProvider.ts` - -## Current Functionality (ART v0.2.7) - -* **Constructor:** - * When instantiated, it logs an informational message: `"ContextProvider initialized (v1.0 Placeholder)"`. - * It does not take any dependencies in its constructor in the current version. - -* **`async getDynamicContext(_threadId: string, _query?: string): Promise<Record<string, any>>`:** - * This is the main method intended to provide dynamic context. - * In `v0.2.7`, this method: - 1. Logs an informational message: `"ContextProvider.getDynamicContext called (v1.0 Placeholder - returning empty context)"`. - 2. Returns `Promise.resolve({})` (an empty object). - * It does not perform any actual context retrieval or processing. The parameters `_threadId` and `_query` are marked with underscores to indicate they are currently unused. - -## Intended Future Role (Retrieval-Augmented Generation - RAG) - -The long-term vision for `ContextProvider` is to be the central component for RAG. In such a system, its responsibilities would expand significantly: - -1. **Configuration:** It would be configured with details of one or more external knowledge sources (e.g., connection details for a vector database, API endpoints for document stores, local file paths). -2. **Query Analysis:** When `getDynamicContext` is called with a `threadId` and `query`: - * It might analyze the current `query` and potentially the recent conversation history (obtained via `ConversationManager`) to understand the information needs. -3. **Knowledge Retrieval:** - * Based on the analysis, it would formulate queries to the configured knowledge sources. - * For a vector database, this would involve generating embeddings for the query and performing a similarity search. - * For other sources, it might involve keyword searches or structured API calls. -4. **Information Processing & Formatting:** - * It would retrieve relevant chunks of information (documents, text snippets, data records). - * It might perform further processing like re-ranking, summarization, or extraction of key facts from the retrieved data. - * The processed information would be formatted into a string or a structured object suitable for injection into an LLM prompt. -5. **Context Provision:** - * The `getDynamicContext` method would return this formatted, dynamically retrieved context. -6. **Agent Integration:** - * The Agent Core (e.g., `PESAgent`) would call `ContextProvider.getDynamicContext()` at an appropriate stage (likely before or during prompt construction for planning or synthesis). - * The context returned by the `ContextProvider` would then be included in the `ArtStandardPrompt` sent to the `ReasoningEngine`. This allows the LLM to generate responses that are "grounded" in or augmented by this external, up-to-date, or domain-specific information. - -**Example of Future Usage (Conceptual):** - -```typescript -// Inside PESAgent or other agent logic (future version) -// ... -// const dynamicContext = await this.deps.contextProvider.getDynamicContext(props.threadId, props.query); -// -// const planningPromptContext = { -// query: props.query, -// history: formattedHistory, -// availableTools: formattedTools, -// systemPrompt: systemPrompt, -// retrievedKnowledge: dynamicContext.knowledgeSnippets // Example field -// }; -// -// const planningPrompt = await this.deps.promptManager.assemblePrompt("planning_blueprint_with_rag", planningPromptContext); -// ... -``` - -## Summary for ART v0.2.7 - -For the current version, developers should be aware that `ContextProvider` does not provide any dynamic context. Core contextual information like conversation history and thread configuration is managed and retrieved directly by the agent via `ConversationManager` and `StateManager` respectively. The `ContextProvider` is included in the codebase as a forward-looking component for planned RAG features. - diff --git a/Docs/components/systems/context/conversation-manager.md b/Docs/components/systems/context/conversation-manager.md deleted file mode 100644 index 87a0219..0000000 --- a/Docs/components/systems/context/conversation-manager.md +++ /dev/null @@ -1,133 +0,0 @@ -# Deep Dive: `ConversationManager` - -The `ConversationManager` is a key component of ART's Context System, responsible for managing the history of `ConversationMessage`s within a specific thread. It acts as an intermediary between the agent core (like `PESAgent`) and the `ConversationRepository`, which handles the actual data persistence. - -* **Source:** `src/systems/context/managers/ConversationManager.ts` -* **Implements:** `ConversationManager` interface from `src/core/interfaces.ts` -* **Dependencies:** `IConversationRepository`, `ConversationSocket` (from `UISystem`). - -## Constructor - -```typescript -constructor( - conversationRepository: IConversationRepository, - conversationSocket: ConversationSocket -) -``` - -* `conversationRepository`: An instance implementing `IConversationRepository` (typically `ConversationRepository`). This is used to save new messages and retrieve historical messages. -* `conversationSocket`: An instance of `ConversationSocket`. The manager uses this to `notify` subscribers (e.g., the UI) whenever new messages are added to a thread. - -## Core Responsibilities & Methods - -1. **Adding Messages to History:** - * **`async addMessages(threadId: string, messages: ConversationMessage[]): Promise<void>`** - * **Purpose:** To append one or more `ConversationMessage` objects to the history of a specified `threadId`. - * **Process:** - 1. Performs basic validation: - * Ensures `threadId` is not empty (rejects with an error if it is). - * If `messages` array is null or empty, it resolves immediately without further action. - 2. Calls `this.repository.addMessages(threadId, messages)` to persist the messages using the underlying `ConversationRepository`. - 3. After the messages are successfully saved to the repository, it iterates through each message in the `messages` array. - 4. For each `message`, it calls `this.conversationSocket.notify(message, { targetThreadId: threadId })`. This broadcasts the new message to any UI components or other services subscribed to the `ConversationSocket` for that particular thread. - * **Error Handling:** - * Errors from `repository.addMessages()` (e.g., storage adapter failure) will propagate and cause the promise to reject. If this happens, socket notifications are typically not sent. - * Errors during `conversationSocket.notify()` are caught and logged by the manager, but they generally do not cause the `addMessages` promise itself to reject, ensuring that a notification failure doesn't prevent the overall message addition process from being considered complete from the repository's perspective. - -2. **Retrieving Messages from History:** - * **`async getMessages(threadId: string, options?: MessageOptions): Promise<ConversationMessage[]>`** - * **Purpose:** To fetch historical `ConversationMessage`s for a given `threadId`. - * **Process:** - 1. Performs basic validation: Ensures `threadId` is not empty (rejects with an error if it is). - 2. Calls `this.repository.getMessages(threadId, options)` to retrieve messages from the `ConversationRepository`. - 3. The `options` parameter (`MessageOptions`) can include: - * `limit?: number`: Maximum number of messages to retrieve. - * `beforeTimestamp?: number`: Retrieve messages created before this timestamp. - * `afterTimestamp?: number`: Retrieve messages created after this timestamp. - * `roles?: MessageRole[]`: (Note: While `MessageOptions` defines this, the `ConversationRepository` in `v0.2.7` primarily handles limit and timestamp filtering; role filtering might be client-side within the repository or not fully implemented at the storage query level.) - 4. Returns the array of `ConversationMessage` objects fetched by the repository. The repository typically sorts these messages chronologically. - * **Error Handling:** Errors from `repository.getMessages()` will propagate. - -## Interaction with `PESAgent` - -The `PESAgent` typically uses the `ConversationManager` in two main scenarios: - -1. **Beginning of `process()`:** - * It calls `conversationManager.getMessages(threadId, { limit: historyLimitFromConfig })` to fetch the recent conversation history. This history is then formatted and included in the prompts sent to the LLM for both planning and synthesis phases, providing context for the current interaction. - -2. **End of `process()` (Finalization):** - * After the LLM has generated its final response, the `PESAgent` creates two `ConversationMessage` objects: - * One for the user's initial query (`role: MessageRole.USER`). - * One for the AI's final synthesized response (`role: MessageRole.AI`). - * It then calls `conversationManager.addMessages(threadId, [userQueryMessage, aiResponseMessage])` to save these new messages to the history and notify the UI. - -The `ConversationManager` provides a clean abstraction for handling conversation history, separating the agent's core logic from the specifics of data storage and UI updates. -``` - -```markdown -docs/components/systems/context/conversation-repository.md -``` -```markdown -# Deep Dive: `ConversationRepository` - -The `ConversationRepository` is responsible for the persistence and retrieval of `ConversationMessage` objects. It implements the `IConversationRepository` interface and uses an injected `StorageAdapter` to interact with the actual storage backend (like `InMemoryStorageAdapter` or `IndexedDBStorageAdapter`). - -* **Source:** `src/systems/context/repositories/ConversationRepository.ts` -* **Implements:** `IConversationRepository` from `src/core/interfaces.ts` -* **Dependencies:** `StorageAdapter`. - -## Constructor - -```typescript -constructor(storageAdapter: StorageAdapter) -``` - -* `storageAdapter`: An instance of a class that implements the `StorageAdapter` interface. This adapter will be used for all underlying storage operations. - * The constructor throws an error if no `storageAdapter` is provided. - * It assumes the `storageAdapter` has been (or will be) initialized separately (e.g., by `AgentFactory`). - -## Core Responsibilities & Methods - -The `ConversationRepository` typically uses a specific collection name (e.g., `"conversations"`) within the `StorageAdapter` to store messages. - -1. **Adding Messages:** - * **`async addMessages(threadId: string, messages: ConversationMessage[]): Promise<void>`** - * **Purpose:** To save one or more `ConversationMessage` objects to the storage. - * **Process:** - 1. If the `messages` array is null or empty, the method returns immediately. - 2. It iterates through each `message` in the input array. - 3. **ID Handling:** For compatibility with `StorageAdapter`s that use a common `keyPath` like `'id'`, the repository creates a `StoredConversationMessage` object. This object includes all properties of the original `ConversationMessage` plus an `id` property that is explicitly set to the value of `message.messageId`. - ```typescript - // Internal structure used for storage - type StoredConversationMessage = ConversationMessage & { id: string }; - // ... - const messageToStore: StoredConversationMessage = { - ...message, - id: message.messageId // message.messageId becomes the primary key for storage - }; - ``` - 4. Calls `this.adapter.set<StoredConversationMessage>(this.collectionName, messageToStore.id, messageToStore)` for each message. This uses the `messageId` (now also `messageToStore.id`) as the key for the `set` operation. - 5. If a message's `message.threadId` does not match the `threadId` parameter passed to `addMessages`, a warning is logged, but the message is still typically added under its own `messageId` (the `threadId` parameter to `addMessages` is primarily for context and potential future validation, not for altering the `message.threadId` itself during storage by this method). - * **Error Handling:** Propagates errors from the `storageAdapter.set()` calls. - -2. **Retrieving Messages:** - * **`async getMessages(threadId: string, options?: MessageOptions): Promise<ConversationMessage[]>`** - * **Purpose:** To fetch `ConversationMessage`s for a specific `threadId`, with optional filtering and limiting. - * **Process:** - 1. **Initial Fetch:** Calls `this.adapter.query<StoredConversationMessage>(this.collectionName, { filter: { threadId: threadId } })`. This attempts to retrieve all messages from the `"conversations"` collection where the `threadId` property matches the provided `threadId`. - 2. **Client-Side Sorting:** The results from the adapter (`queryResults`) are **sorted by `timestamp` in ascending order** (oldest first). This is crucial for maintaining the correct chronological sequence of the conversation. - 3. **Client-Side Timestamp Filtering:** - * If `options.beforeTimestamp` is provided, messages with `timestamp >= options.beforeTimestamp` are filtered out. - * If `options.afterTimestamp` is provided, messages with `timestamp <= options.afterTimestamp` are filtered out. - 4. **Client-Side Limiting:** - * If `options.limit` is provided and is greater than 0, the sorted and filtered list is sliced to return only the **most recent 'N' messages** (due to the ascending sort, `slice(-options.limit)` is used). - * If `options.limit` is 0, an empty array is returned. - * If `options.limit` is negative, the behavior of `slice` might be unexpected (e.g., `slice(-(-1))` becomes `slice(1)`), potentially returning all but the first 'N' items. The current implementation tests this behavior. - 5. **Data Cleaning:** Before returning, the internal `id` property (which was a copy of `messageId`) is removed from each message object to ensure the returned objects strictly conform to the `ConversationMessage` interface. - * **Error Handling:** Propagates errors from the `storageAdapter.query()` call. - -**Note on Querying and Performance:** - -The `ConversationRepository` in ART `v0.2.7` performs significant parts of filtering (timestamps) and limiting **client-side** after fetching potentially all messages for a thread that match the `threadId` filter. While this works for many scenarios, for applications with extremely large conversation histories per thread, this approach could become less performant. Future optimizations might involve pushing more of the querying logic (especially sorting and complex filtering) down into the `StorageAdapter` implementations if the underlying storage backends support it efficiently (e.g., using database indexes). - -The `ConversationRepository` provides the necessary abstraction for the `ConversationManager` and, by extension, the agent core, to interact with conversation history without being concerned about the specifics of how or where that history is stored. \ No newline at end of file diff --git a/Docs/components/systems/context/observation-repository.md b/Docs/components/systems/context/observation-repository.md deleted file mode 100644 index 262b115..0000000 --- a/Docs/components/systems/context/observation-repository.md +++ /dev/null @@ -1,52 +0,0 @@ -# Deep Dive: `ObservationRepository` - -The `ObservationRepository` is a component of ART's Context System, dedicated to persisting and retrieving `Observation` objects. It implements the `IObservationRepository` interface and, like other repositories, utilizes an injected `StorageAdapter` for the actual storage operations. - -* **Source:** `src/systems/context/repositories/ObservationRepository.ts` -* **Implements:** `IObservationRepository` from `src/core/interfaces.ts` -* **Dependencies:** `StorageAdapter`. - -## Constructor - -```typescript -constructor(storageAdapter: StorageAdapter) -``` - -* `storageAdapter`: An instance of a class that implements the `StorageAdapter` interface. This adapter handles the underlying storage. - * The constructor throws an error if no `storageAdapter` is provided. - * It assumes the `storageAdapter` has been (or will be) initialized separately. - -## Core Responsibilities & Methods - -The `ObservationRepository` typically uses a collection named `"observations"` within the `StorageAdapter`. Since the `Observation` interface already includes an `id: string` property, this `id` is directly used as the key for storage, assuming the `StorageAdapter`'s object stores are configured with `{ keyPath: 'id' }`. - -1. **Adding an Observation:** - * **`async addObservation(observation: Observation): Promise<void>`** - * **Purpose:** To save a single `Observation` object to storage. - * **Process:** - 1. Validates that the `observation` object has an `id` property. If not, it rejects the promise with an error. - 2. Calls `this.adapter.set<Observation>(this.collectionName, observation.id, observation)`. This uses the `observation.id` as the key for the `set` operation. If an observation with the same ID already exists, it will be overwritten. - * **Error Handling:** Propagates errors from the `storageAdapter.set()` call. - -2. **Retrieving Observations:** - * **`async getObservations(threadId: string, filter?: ObservationFilter): Promise<Observation[]>`** - * **Purpose:** To fetch `Observation`s for a specific `threadId`, with optional filtering. - * **Process:** - 1. **Initial Fetch:** Calls `this.adapter.query<Observation>(this.collectionName, { filter: { threadId: threadId } })`. This retrieves all observations from the `"observations"` collection where the `threadId` property matches. - 2. **Client-Side Sorting:** The results are **sorted by `timestamp` in ascending order** (oldest first) to provide a chronological view. - 3. **Client-Side Filtering (based on `ObservationFilter`):** - * **`filter.types?: ObservationType[]`:** If provided and not empty, it filters the observations to include only those whose `type` is present in the `filter.types` array. - * **`filter.beforeTimestamp?: number`:** If provided, observations with `timestamp >= filter.beforeTimestamp` are excluded. - * **`filter.afterTimestamp?: number`:** If provided, observations with `timestamp <= filter.afterTimestamp` are excluded. - 4. **Limit/Skip:** The current `ObservationFilter` type and `ObservationRepository` implementation in `v0.2.7` do not directly support `limit` or `skip` options for observations in the same way `ConversationRepository` does for messages. If pagination or limiting is needed for observations, this would be a potential area for enhancement in the `ObservationFilter` type and this method's client-side processing logic or by pushing it to the `StorageAdapter` query. - * **Data Integrity:** The objects retrieved from storage should already conform to the `Observation` interface, so no structural transformation (like removing an internal `id` field) is typically needed before returning. - * **Error Handling:** Propagates errors from the `storageAdapter.query()` call. - -## Usage - -The `ObservationManager` uses the `ObservationRepository` to: - -* Persist new observations generated during an agent's execution cycle via `addObservation()`. -* Retrieve historical observations (e.g., for display in a UI or for analysis) via `getObservations()`. - -Like other repositories in ART, the `ObservationRepository` abstracts the details of data storage, allowing the `ObservationManager` to focus on the logic of handling observations without being tied to a specific storage backend. \ No newline at end of file diff --git a/Docs/components/systems/context/state-manager.md b/Docs/components/systems/context/state-manager.md deleted file mode 100644 index bc88f65..0000000 --- a/Docs/components/systems/context/state-manager.md +++ /dev/null @@ -1,89 +0,0 @@ -# Deep Dive: `StateManager` - -The `StateManager` is a pivotal component within ART's Context System. It's responsible for loading, managing, and persisting thread-specific configurations (`ThreadConfig`) and the agent's operational state (`AgentState`). A key aspect of its behavior is governed by the `StateSavingStrategy` chosen during the ART instance setup. - -* **Source:** `src/systems/context/managers/StateManager.ts` -* **Implements:** `StateManager` interface from `src/core/interfaces.ts` -* **Dependencies:** `IStateRepository`, `StateSavingStrategy` (configured at construction). - -## Constructor - -```typescript -constructor( - stateRepository: IStateRepository, - strategy: StateSavingStrategy = 'explicit' // Default to explicit -) -``` - -* `stateRepository`: An instance implementing `IStateRepository` (typically `StateRepository`), which handles the actual interaction with the `StorageAdapter`. -* `strategy`: The `StateSavingStrategy` ('explicit' or 'implicit') that dictates how `AgentState` modifications are persisted. This is usually passed from `ArtInstanceConfig.stateSavingStrategy`. - -## Core Responsibilities & Methods - -1. **Loading Thread Context:** - * **`async loadThreadContext(threadId: string, _userId?: string): Promise<ThreadContext>`** - * Fetches the complete `ThreadContext` (which includes both `config: ThreadConfig` and `state: AgentState | null`) for the given `threadId` from the `IStateRepository`. - * **Caching (Implicit Strategy):** If the `stateSavingStrategy` is `'implicit'`, this method plays a crucial role. - * If the context for the `threadId` is already in its internal cache (from a previous call within the same agent processing cycle), it returns the cached version. This ensures the agent operates on a consistent object instance that `saveStateIfModified` will later check. - * If not cached, it fetches from the repository, **deep clones** the context, stores this clone in its cache, and creates a JSON snapshot of the `AgentState` part of this cloned context. This snapshot is used later by `saveStateIfModified` to detect changes. - * If the `stateSavingStrategy` is `'explicit'`, it simply fetches and returns the context from the repository without caching or snapshotting for modification detection. - * Throws an error if the context is not found in the repository (applications should generally call `setThreadConfig` to initialize context for new threads). - -2. **Accessing Thread Configuration:** - * **`async isToolEnabled(threadId: string, toolName: string): Promise<boolean>`** - * Calls `loadThreadContext(threadId)` (which may use the cache). - * Checks if `toolName` is present in the `context.config.enabledTools` array. - * Returns `false` if the context or config is missing, or if the tool is not in the list. Logs a warning if context loading fails. - * **`async getThreadConfigValue<T>(threadId: string, key: string): Promise<T | undefined>`** - * Calls `loadThreadContext(threadId)`. - * Returns the value of the top-level `key` from `context.config`. - * Does not support nested key access (e.g., `reasoning.model`). - * Returns `undefined` if the config or key is not found. - -3. **Managing `ThreadConfig`:** - * **`async setThreadConfig(threadId: string, config: ThreadConfig): Promise<void>`** - * Directly calls `IStateRepository.setThreadConfig(threadId, config)` to save or overwrite the configuration for the thread. - * **Cache Invalidation:** If a context for this `threadId` was cached (in `'implicit'` mode), it is **deleted** from the cache. This ensures that the next call to `loadThreadContext` fetches the newly updated configuration from the repository. - -4. **Managing `AgentState`:** - * **`async setAgentState(threadId: string, state: AgentState): Promise<void>`** - * Explicitly saves or overwrites the `AgentState` for the thread by calling `IStateRepository.setAgentState(threadId, state)`. - * Requires that a `ThreadConfig` already exists for the thread (throws an error otherwise). - * **Implicit Strategy Interaction:** If the strategy is `'implicit'` and a context for the `threadId` is cached: - * The `StateManager` updates its cached `context.state` with a deep clone of the new `state`. - * It also updates its internal `originalStateSnapshot` to match this new `state`. This prevents `saveStateIfModified` from immediately detecting this explicit change as another modification and re-saving it. - * **`async saveStateIfModified(threadId: string): Promise<void>`** - * This method's behavior is highly dependent on the `stateSavingStrategy`. - * **`'explicit'` strategy:** - * Logs a warning indicating that `AgentState` must be saved explicitly using `setAgentState()`. - * This method becomes a **no-op** for `AgentState` persistence. - * **`'implicit'` strategy:** - * Retrieves the cached `ThreadContext` for the `threadId` (which the agent might have modified during its `process` cycle). - * If no context is cached for this `threadId` in the current `StateManager` instance (e.g., `loadThreadContext` wasn't called for this thread in this cycle through this manager instance), it logs a warning and does nothing further for state saving. - * Compares a JSON snapshot of the current `cachedData.context.state` with the `originalStateSnapshot` taken during `loadThreadContext`. - * If they differ (meaning the agent modified the state object): - * It calls `IStateRepository.setAgentState(threadId, currentState)` to persist the changes. - * It then updates its internal `originalStateSnapshot` to the new `currentStateSnapshot` to reflect that the current state is now persisted. - * *Note:* If `currentState` becomes `null` (and was not `null` originally), the current implementation (`v0.2.7`) logs a warning and does **not** attempt to save `null` state via `setAgentState` because `IStateRepository.setAgentState` (and underlying `StateRepository`) typically expects a non-null `AgentState` object. Clearing state implicitly would require further design considerations. - * If the snapshots are the same, no save operation occurs. - -5. **Cache Management (Internal):** - * **`contextCache: Map<string, { originalStateSnapshot: string | null, context: ThreadContext }>`:** Stores loaded contexts when in `'implicit'` mode. - * **`public clearCache(): void`:** A public method to clear the entire internal `contextCache`. This might be useful for testing or in scenarios where external modifications to the underlying storage occur that the `StateManager` isn't aware of. - -## How `StateSavingStrategy` Influences Workflow - -* **With `'explicit'` strategy (default):** - 1. Agent calls `loadThreadContext()`. - 2. Agent performs operations, potentially modifying the `state` object it received. - 3. If the agent wants to persist these state changes, it **must** explicitly call `stateManager.setAgentState(threadId, modifiedState)`. - 4. `PESAgent` calls `saveStateIfModified()` at the end; this does nothing for the `AgentState`. - -* **With `'implicit'` strategy:** - 1. Agent calls `loadThreadContext()`. `StateManager` caches the context and snapshots `AgentState`. - 2. Agent performs operations and directly modifies the `state` object within the `ThreadContext` it received from `loadThreadContext()`. - 3. Agent might also call `stateManager.setAgentState()` for deliberate, immediate saves. This also updates the cache and snapshot. - 4. `PESAgent` calls `saveStateIfModified()` at the end. - 5. `StateManager` compares the current (potentially modified) cached `AgentState` with the original snapshot. If different, it saves the state to the repository. - -The `StateManager` thus provides a flexible way to handle configuration and state, allowing developers to choose the persistence model that best suits their agent's needs. \ No newline at end of file diff --git a/Docs/components/systems/context/state-repository.md b/Docs/components/systems/context/state-repository.md deleted file mode 100644 index 9e295f4..0000000 --- a/Docs/components/systems/context/state-repository.md +++ /dev/null @@ -1,93 +0,0 @@ -# Deep Dive: `StateRepository` - -The `StateRepository` is a specialized repository within ART's Context System responsible for persisting and retrieving the complete `ThreadContext` for each conversation thread. A `ThreadContext` object encapsulates both the `ThreadConfig` (configuration settings for the thread) and the `AgentState` (persistent operational state for the agent within that thread). - -* **Source:** `src/systems/context/repositories/StateRepository.ts` -* **Implements:** `IStateRepository` from `src/core/interfaces.ts` -* **Dependencies:** `StorageAdapter`. - -## Constructor - -```typescript -constructor(storageAdapter: StorageAdapter) -``` - -* `storageAdapter`: An instance of a class implementing the `StorageAdapter` interface. This adapter handles the actual storage of `ThreadContext` objects. - * The constructor throws an error if `storageAdapter` is not provided. - * It assumes the `storageAdapter` is already initialized. - -## Core Responsibilities & Data Structure - -The `StateRepository` typically uses a collection named `"state"` within the `StorageAdapter`. - -* **Keying:** Each `ThreadContext` is stored under a key equal to its `threadId`. -* **Stored Object (`StoredThreadContext`):** Internally, when saving, the `threadId` is also added as an `id` property to the `ThreadContext` object itself. This is for compatibility with `StorageAdapter` implementations (like `IndexedDBStorageAdapter`) that might use `{ keyPath: 'id' }` for their object stores. - ```typescript - // Internal structure used for storage - type StoredThreadContext = ThreadContext & { id: string }; - ``` - When data is retrieved, this internal `id` property is removed before returning the `ThreadContext` to ensure it strictly matches the interface. - -## Methods - -1. **`async getThreadContext(threadId: string): Promise<ThreadContext | null>`** - * **Purpose:** Retrieves the complete `ThreadContext` (config and state) for a given `threadId`. - * **Process:** - 1. Calls `this.adapter.get<StoredThreadContext>(this.collectionName, threadId)`. - 2. If a `StoredThreadContext` is found: - * It creates a copy of the object. - * Deletes the internal `id` property from this copy. - * Returns the cleaned `ThreadContext` object. - 3. If not found, returns `null`. - * **Error Handling:** Propagates errors from the `storageAdapter.get()` call. - -2. **`async setThreadContext(threadId: string, context: ThreadContext): Promise<void>`** - * **Purpose:** Saves or overwrites the complete `ThreadContext` for a `threadId`. - * **Process:** - 1. Validates that the provided `context` object has a `config` property (as `ThreadConfig` is mandatory). If not, it rejects the promise. - 2. Creates a `StoredThreadContext` object by spreading the input `context` and adding an `id: threadId` property. - 3. Calls `this.adapter.set<StoredThreadContext>(this.collectionName, threadId, contextToStore)`. - * **Error Handling:** Propagates errors from the `storageAdapter.set()` call. - -3. **`async getThreadConfig(threadId: string): Promise<ThreadConfig | null>`** - * **Purpose:** Retrieves only the `ThreadConfig` portion for a `threadId`. - * **Process:** - 1. Calls `this.getThreadContext(threadId)`. - 2. If a context is found, returns `context.config`. - 3. Otherwise, returns `null`. - -4. **`async setThreadConfig(threadId: string, config: ThreadConfig): Promise<void>`** - * **Purpose:** Sets or updates only the `ThreadConfig` for a `threadId`, preserving any existing `AgentState`. - * **Process:** - 1. Calls `this.getThreadContext(threadId)` to fetch the current context. - 2. Constructs a new `ThreadContext` object: - * Uses the provided `config`. - * Uses `currentContext.state` if `currentContext` and `currentContext.state` exist, otherwise sets `state` to `null`. - 3. Calls `this.setThreadContext(threadId, newContext)` to save the updated full context. - -5. **`async getAgentState(threadId: string): Promise<AgentState | null>`** - * **Purpose:** Retrieves only the `AgentState` portion for a `threadId`. - * **Process:** - 1. Calls `this.getThreadContext(threadId)`. - 2. If a context is found, returns `context.state` (which could be an `AgentState` object or `null`). - 3. Otherwise, returns `null`. - -6. **`async setAgentState(threadId: string, state: AgentState | null): Promise<void>`** - * **Purpose:** Sets or updates only the `AgentState` for a `threadId`, preserving the existing `ThreadConfig`. - * **Process:** - 1. Calls `this.getThreadContext(threadId)` to fetch the current context. - 2. **Validation:** If `currentContext` or `currentContext.config` is not found (meaning no configuration has been set for this thread yet), it rejects the promise with an error. `AgentState` cannot be set without an existing `ThreadConfig`. - 3. Constructs a new `ThreadContext` object: - * Uses `currentContext.config`. - * Uses the provided `state` (which can be an `AgentState` object or `null` to clear the state). - 4. Calls `this.setThreadContext(threadId, newContext)` to save the updated full context. - -## Usage - -The `StateManager` is the primary consumer of the `StateRepository`. It uses these methods to: - -* Load the initial `ThreadContext` at the start of an agent's processing cycle. -* Allow the agent or application to explicitly set/update `ThreadConfig` or `AgentState`. -* Persist `AgentState` changes (especially when `StateSavingStrategy` is 'implicit' and `StateManager.saveStateIfModified` is called). - -By centralizing context storage through the `StateRepository`, ART ensures a consistent approach to managing the essential configuration and persistent data associated with each conversation thread. \ No newline at end of file diff --git a/Docs/components/systems/observation/observation-manager.md b/Docs/components/systems/observation/observation-manager.md deleted file mode 100644 index 732a782..0000000 --- a/Docs/components/systems/observation/observation-manager.md +++ /dev/null @@ -1,68 +0,0 @@ -# Deep Dive: `ObservationManager` - -The `ObservationManager` is the central service within ART's Observation System. Its primary role is to facilitate the creation, persistence, and real-time broadcasting of `Observation` records. These observations capture significant events and data points that occur during an agent's execution cycle, providing crucial insights for debugging, monitoring, and UI updates. - -* **Source:** `src/systems/observation/observation-manager.ts` -* **Implements:** `ObservationManager` interface from `src/core/interfaces.ts` -* **Dependencies:** `IObservationRepository`, `ObservationSocket` (from `UISystem`). - -## Constructor - -```typescript -constructor( - observationRepository: IObservationRepository, - observationSocket: ObservationSocket -) -``` - -* `observationRepository`: An instance implementing `IObservationRepository` (typically `ObservationRepository`). This is used to save new `Observation` objects to the configured storage. -* `observationSocket`: An instance of `ObservationSocket`. The manager uses this to `notify` subscribers (e.g., the UI) whenever a new observation is recorded. - -## Core Responsibilities & Methods - -1. **Recording Observations:** - * **`async record(observationData: Omit<Observation, 'id' | 'timestamp' | 'title'>): Promise<void>`** - * **Purpose:** This is the main method used by various ART components (like `PESAgent`, `ToolSystem`) to log an event. - * **Process:** - 1. **Enrichment:** Takes `observationData` (which includes `threadId`, `type`, `content`, and optional `traceId`, `metadata`) and enriches it by: - * Generating a unique `id` for the observation using `generateUUID()`. - * Setting the current `timestamp` using `Date.now()`. - * Creating a default `title` string, typically in the format "`<ObservationType>` Recorded" (e.g., "PLAN Recorded", "TOOL_EXECUTION Recorded"). - 2. **Persistence:** Calls `this.observationRepository.addObservation(fullObservation)` to save the complete `Observation` object using the underlying repository. - 3. **Notification:** After successful persistence, it calls `this.observationSocket.notify(fullObservation, { targetThreadId: fullObservation.threadId })`. This broadcasts the newly recorded observation to any subscribers listening on the `ObservationSocket`, filtered by `threadId`. - * **Error Handling:** - * If `observationRepository.addObservation()` fails (e.g., due to a storage adapter error), the error is re-thrown, and the socket notification will not occur. - * If `observationSocket.notify()` fails, an error is logged to the console, and the method re-throws the error. This means a notification failure can cause the `record` operation to be perceived as failed by the caller. (This behavior could be adjusted if notifications are considered non-critical for the success of recording itself). - -2. **Retrieving Observations:** - * **`async getObservations(threadId: string, filter?: ObservationFilter): Promise<Observation[]>`** - * **Purpose:** To fetch historical `Observation`s for a given `threadId`. - * **Process:** - 1. Delegates directly to `this.observationRepository.getObservations(threadId, filter)`. - 2. The `filter` parameter (`ObservationFilter`) can be used to specify: - * `types?: ObservationType[]`: An array of `ObservationType`s to include. - * `beforeTimestamp?: number`: Retrieve observations recorded before this time. - * `afterTimestamp?: number`: Retrieve observations recorded after this time. - 3. Returns the array of `Observation` objects fetched by the repository. The repository typically sorts these chronologically by timestamp. - * **Error Handling:** Propagates errors from the `observationRepository.getObservations()` call. - -## How Observations are Created and Used - -* **Agent Core (`PESAgent`):** Records observations at various stages of its Plan-Execute-Synthesize cycle: - * `PLAN`: When starting the planning LLM call. - * `INTENT`, `PLAN` (details), `TOOL_CALL`: After parsing the planning LLM's output. - * `SYNTHESIS`: When starting the synthesis LLM call. - * `FINAL_RESPONSE`: After the final AI message is generated and saved. - * `ERROR`: If an error occurs during a specific phase (e.g., planning, synthesis). - * `LLM_STREAM_START`, `LLM_STREAM_METADATA`, `LLM_STREAM_ERROR`, `LLM_STREAM_END`: When consuming `StreamEvent`s from the `ReasoningEngine`. -* **`ToolSystem`:** Records `TOOL_EXECUTION` observations for each tool call attempt, capturing the `ToolResult` (success or error, input, output). -* **Other Components:** Any other custom component within ART could potentially use the `ObservationManager` to record significant events. - -**Benefits of this System:** - -* **Decoupling:** Components that generate events don't need to know about specific logging mechanisms or UI update protocols. They just call `observationManager.record()`. -* **Centralization:** Provides a single point for managing how observations are handled. -* **Real-time Monitoring:** Through the `ObservationSocket`, UIs or other monitoring tools can get immediate updates. -* **Debugging & Auditing:** Persisted observations provide a valuable trail for understanding agent behavior, diagnosing issues, and auditing past interactions. - -The `ObservationManager`, in conjunction with its repository and socket, forms a comprehensive system for capturing and utilizing runtime information about the agent's operations. \ No newline at end of file diff --git a/Docs/components/systems/reasoning/output-parser.md b/Docs/components/systems/reasoning/output-parser.md deleted file mode 100644 index c07d14c..0000000 --- a/Docs/components/systems/reasoning/output-parser.md +++ /dev/null @@ -1,54 +0,0 @@ -# Deep Dive: `OutputParser` - -The `OutputParser` in the ART Framework is responsible for transforming the raw string output from Large Language Models (LLMs) into more structured and usable data, particularly after the agent's planning phase. It also handles basic cleaning of the synthesis output. - -* **Source:** `src/systems/reasoning/OutputParser.ts` -* **Implements:** `OutputParser` interface from `src/core/interfaces.ts` - -## Core Responsibilities & Methods - -1. **Parsing Planning Output:** - * **`async parsePlanningOutput(output: string): Promise<{ intent?: string; plan?: string; toolCalls?: ParsedToolCall[]; thoughts?: string; }>`** - * **Purpose:** To extract structured information from the LLM's response during the agent's planning phase. This typically includes the agent's understanding of the user's intent, its proposed plan, any tools it intends to call, and its internal "thinking" steps. - * **Process:** - 1. **Extracting `<think>` Tags (Thoughts):** - * It first uses an `XmlMatcher` instance (from `src/utils/xml-matcher.ts`) configured to find and extract content within `<think>...</think>` XML-like tags. - * All content found within these tags is aggregated into a single `thoughts` string, with multiple thought blocks separated by `\n\n---\n\n`. - * The content *outside* these `<think>` tags is considered the "non-thinking" part of the output and is processed further. - 2. **Extracting Intent, Plan, and Tool Calls from Non-Thinking Content:** - * It searches the non-thinking content for distinct sections, typically marked by keywords (case-insensitive): - * `Intent:`: Extracts the text following this keyword as the `intent`. - * `Plan:`: Extracts the text following this keyword as the `plan`. - * `Tool Calls:`: Extracts the text following this keyword, expecting it to contain a JSON array of tool call requests. - * The extraction uses regular expressions to capture content until the next section keyword or the end of the string. - 3. **Parsing Tool Calls JSON:** - * Within the "Tool Calls:" section, it looks for a JSON array. It's designed to handle: - * Plain JSON arrays: `[{"callId": ..., "toolName": ..., "arguments": ...}]` - * JSON arrays enclosed in Markdown code fences: - * ````json`\n[...]\n` ````` - * ````\n[...]\n` ````` - * It attempts to parse the identified JSON string into a JavaScript array. - * **Validation with Zod:** The parsed array is then validated against a Zod schema (`toolCallsSchema`) which ensures each element is an object with required `callId` (string), `toolName` (string), and `arguments` (any type, further validation happens in `ToolSystem`). - * If JSON parsing fails (e.g., malformed JSON), an error is logged, and `toolCalls` defaults to an empty array `[]`. - * If Zod validation fails (e.g., missing `callId`, `toolName`, or JSON is not an array), a warning is logged, and `toolCalls` defaults to an empty array `[]`. - 4. **Return Value:** Returns an object containing the optional `intent`, `plan`, `toolCalls` (which will be an empty array `[]` if parsing/validation failed but the "Tool Calls:" section was present, or `undefined` if the section was missing entirely from non-thinking content), and `thoughts`. - * **Robustness:** The parser is designed to be somewhat resilient to variations in LLM output, such as extra whitespace or slight deviations in section ordering, as long as the keyword markers are present. - * **Logging:** It logs warnings or errors if sections are missing or if JSON parsing/validation fails. - -2. **Parsing Synthesis Output:** - * **`async parseSynthesisOutput(output: string): Promise<string>`** - * **Purpose:** To clean up the raw string output from the LLM during the agent's synthesis phase, preparing it as the final user-facing response. - * **Process (ART v0.2.7):** - * The current implementation is very straightforward: it simply calls `output.trim()` to remove leading and trailing whitespace. - * The `PESAgent` now directly uses the accumulated text from the synthesis stream as the final response content. This means complex parsing (like removing specific tags, unless they are `<think>` tags which wouldn't typically be in final synthesis) by `parseSynthesisOutput` is less critical for the core content itself. If an LLM includes extraneous prefixes/suffixes in its final answer that are not desired, this method could be enhanced to remove them. - * **Return Value:** Returns the trimmed string. - -## Usage by `PESAgent` - -* After the planning LLM call, `PESAgent` accumulates the streamed text output and passes it to `outputParser.parsePlanningOutput()`. The resulting structured data (intent, plan, tool calls, thoughts) is then used to: - * Record observations. - * Pass `ParsedToolCall`s to the `ToolSystem` for execution. - * Formulate the context for the subsequent synthesis LLM call. -* After the synthesis LLM call, `PESAgent` accumulates the streamed text. While `parseSynthesisOutput` is available, the `PESAgent` in `v0.2.7` directly uses the trimmed, accumulated synthesis stream text as the final `ConversationMessage.content`. - -The `OutputParser` plays a vital role in bridging the gap between the often less structured, natural language (or mixed format) output of LLMs and the structured data needed by other ART systems like the `ToolSystem`. Its ability to handle `<think>` tags separately using `XmlMatcher` is key for agents that expose their "thought process." \ No newline at end of file diff --git a/Docs/components/systems/reasoning/prompt-manager.md b/Docs/components/systems/reasoning/prompt-manager.md deleted file mode 100644 index 320330d..0000000 --- a/Docs/components/systems/reasoning/prompt-manager.md +++ /dev/null @@ -1,75 +0,0 @@ -# Deep Dive: `PromptManager` - -In ART Framework `v0.2.7`, the `PromptManager` serves a more focused role compared to traditional template-based prompt management systems. Its primary responsibilities are to provide access to pre-defined **prompt fragments** and to **validate** fully constructed `ArtStandardPrompt` objects. The actual assembly of the `ArtStandardPrompt` (the array of `ArtStandardMessage` objects) is now handled directly by the agent logic (e.g., within `PESAgent`). - -* **Source:** `src/systems/reasoning/PromptManager.ts` -* **Implements:** `PromptManager` interface from `src/core/interfaces.ts` - -## Core Responsibilities & Methods - -1. **Providing Prompt Fragments:** - * **`getFragment(name: string, context?: Record<string, any>): string`** - * **Purpose:** To retrieve named, reusable pieces of text that can be incorporated into prompts. - * **Process:** - 1. Looks up the `name` in an internal `PROMPT_FRAGMENTS` record (a simple key-value store of strings defined within `PromptManager.ts`). - 2. If the fragment is not found, it throws an `ARTError` with `ErrorCode.PROMPT_FRAGMENT_NOT_FOUND`. - 3. **Basic Substitution:** If a `context` object is provided, the method performs a simple string replacement for placeholders like `{{key}}` within the fragment string, using corresponding values from the `context`. If a key in a placeholder is not found in the `context`, the placeholder remains in the string. - 4. Returns the processed fragment string. - * **Example Fragments (Conceptual, in `PromptManager.ts`):** - ```typescript - const PROMPT_FRAGMENTS: Record<string, string> = { - pes_system_default: "You are a helpful AI assistant...", - pes_planning_instructions: "Based on the user query...", - common_tool_format: "Tool Calls: [Output *only* the JSON array...]" - }; - ``` - * **Usage by Agent Logic:** - ```typescript - // In PESAgent or custom agent logic - // const systemInstruction = this.deps.promptManager.getFragment('pes_system_default'); - // const planningUserContent = ` - // ${this.deps.promptManager.getFragment('pes_planning_instructions')} - // User Query: ${props.query} - // Available Tools: ${toolsDescription} - // ${this.deps.promptManager.getFragment('common_tool_format')} - // `; - // - // const planningPrompt: ArtStandardPrompt = [ - // { role: 'system', content: systemInstruction }, - // // ... history messages ... - // { role: 'user', content: planningUserContent } - // ]; - ``` - -2. **Validating `ArtStandardPrompt` Objects:** - * **`validatePrompt(prompt: ArtStandardPrompt): ArtStandardPrompt`** - * **Purpose:** To ensure that a fully assembled `ArtStandardPrompt` object (an array of `ArtStandardMessage` objects) conforms to the expected structure and types defined by the Zod schema (`ArtStandardPromptSchema` from `src/types/schemas.ts`). - * **Process:** - 1. Uses `ArtStandardPromptSchema.parse(prompt)`. The `parse` method from Zod will throw a `ZodError` if validation fails. - 2. If validation is successful, it returns the (potentially normalized by Zod) `prompt` object. - 3. If validation fails (a `ZodError` is thrown): - * Logs the detailed Zod errors. - * Throws an `ARTError` with `ErrorCode.PROMPT_VALIDATION_FAILED`, including the original `ZodError` for context. - * **Usage by Agent Logic:** After agent logic has constructed the complete `ArtStandardPrompt` object, it can optionally call this method for an extra layer of validation before sending it to the `ReasoningEngine`. - ```typescript - // In PESAgent or custom agent logic, after constructing 'myAssembledPrompt' - // try { - // const validatedPrompt = this.deps.promptManager.validatePrompt(myAssembledPrompt); - // // ... send validatedPrompt to ReasoningEngine ... - // } catch (validationError) { - // // Handle prompt validation failure - // } - ``` - -## Shift in Responsibility for Prompt Assembly - -In earlier design concepts or other frameworks, a `PromptManager` might be responsible for taking a template name and a large context object, and then rendering a complete, complex prompt. - -In ART `v0.2.7`, this responsibility is shifted: - -* **Agent Logic (e.g., `PESAgent`)** is responsible for the **assembly** of the `ArtStandardPrompt` object. This means the agent code itself defines the sequence of `ArtStandardMessage`s and constructs their `role` and `content` fields. This approach offers greater flexibility and direct control over the prompt structure within the agent's specific workflow (like the distinct planning and synthesis phases of `PESAgent`). -* **`PromptManager`** acts as a **utility** to: - * Provide reusable text **fragments** that the agent logic can embed into the `content` of the messages it creates. - * Offer a **validation** step for the finally assembled `ArtStandardPrompt` object against a standard schema. - -This division of labor keeps the `PromptManager` relatively simple and stateless, while empowering the agent logic with full control over the crucial process of prompt construction tailored to its operational phase and the LLM's requirements. \ No newline at end of file diff --git a/Docs/components/systems/reasoning/reasoning-engine.md b/Docs/components/systems/reasoning/reasoning-engine.md deleted file mode 100644 index 2c0095d..0000000 --- a/Docs/components/systems/reasoning/reasoning-engine.md +++ /dev/null @@ -1,76 +0,0 @@ -# Deep Dive: `ReasoningEngine` - -The `ReasoningEngine` is the primary interface within ART's Reasoning System for interacting with Large Language Models (LLMs). It abstracts the complexities of different LLM provider APIs, allowing the agent core (like `PESAgent`) to make LLM calls in a standardized way. In ART `v0.2.7+`, the `ReasoningEngineImpl` achieves this by delegating calls to the `ProviderManager`. - -* **Source:** `src/systems/reasoning/ReasoningEngine.ts` (for `ReasoningEngineImpl`) -* **Implements:** `ReasoningEngine` interface from `src/core/interfaces.ts` -* **Dependencies:** `IProviderManager`. - -## Constructor (`ReasoningEngineImpl`) - -```typescript -constructor(providerManager: IProviderManager) -``` - -* `providerManager`: An instance implementing `IProviderManager` (typically `ProviderManagerImpl`). The `ReasoningEngine` uses this manager to dynamically obtain `ProviderAdapter` instances at runtime. - -## Core Method: `call` - -* **`async call(prompt: FormattedPrompt, options: CallOptions): Promise<AsyncIterable<StreamEvent>>`** - * **Purpose:** To execute an LLM call using the provider and model specified in `options.providerConfig`. - * **Parameters:** - * `prompt: FormattedPrompt` (which is an alias for `ArtStandardPrompt`): The standardized prompt object (an array of `ArtStandardMessage`s) constructed by the agent logic. - * `options: CallOptions`: An object containing crucial information for the call: - * `threadId: string` (Required): The ID of the current conversation thread. - * `traceId?: string`: Optional trace ID for logging and correlation. - * `userId?: string`: Optional user ID. - * `sessionId?: string`: Optional UI session ID. - * `stream?: boolean`: If `true`, requests a streaming response from the LLM. - * `callContext?: 'AGENT_THOUGHT' | 'FINAL_SYNTHESIS' | string`: Indicates the purpose of the LLM call (e.g., for planning or for generating the final user-facing response). This helps adapters and stream consumers determine the `tokenType` for `TOKEN` `StreamEvent`s. - * **`providerConfig: RuntimeProviderConfig` (Required):** This is vital. It specifies: - * `providerName`: The name of the provider to use (must match an entry in `ProviderManagerConfig.availableProviders`). - * `modelId`: The specific model ID for the call. - * `adapterOptions`: Options to be passed to the adapter's constructor (e.g., API key, base URL). - * Other provider-specific parameters (e.g., `temperature`, `max_tokens`) can also be included in `options` and will be passed to the adapter. - - * **Process:** - 1. **Adapter Acquisition:** - * Extracts the `providerConfig` from `options`. - * Calls `await this.providerManager.getAdapter(providerConfig)` to obtain a `ManagedAdapterAccessor`. This accessor contains the ready-to-use `ProviderAdapter` instance and a `release()` function. The `ProviderManager` handles instance creation, caching, pooling, and local provider constraints. - 2. **Delegation to Adapter:** - * Calls `await accessor.adapter.call(prompt, options)`, passing the `ArtStandardPrompt` and the full `CallOptions` to the selected adapter. - * The adapter translates the `ArtStandardPrompt` to its native format, makes the API call, and returns an `AsyncIterable<StreamEvent>`. - 3. **Stream Wrapping & Release:** - * The `ReasoningEngine` wraps the `AsyncIterable<StreamEvent>` returned by the adapter in another async generator. - * This wrapper ensures that `accessor.release()` is called in a `finally` block. This is **critical** because it signals to the `ProviderManager` that the adapter instance is no longer in active use for this specific call, allowing it to be reused, managed by an idle timer, or for the `ProviderManager` to process queued requests. The release happens whether the stream is fully consumed, exited early (e.g., via `break`), or an error occurs during consumption. - 4. **Return Value:** Returns the wrapped `AsyncIterable<StreamEvent>` to the caller (e.g., `PESAgent`). - - * **Error Handling:** - * If `providerManager.getAdapter()` fails (e.g., unknown provider, local provider conflict, adapter instantiation error), the error is re-thrown by the `ReasoningEngine`. - * If `accessor.adapter.call()` itself throws an error (e.g., an immediate issue before streaming begins), the adapter is released, and the error is re-thrown. - * Errors occurring *during* the consumption of the stream (yielded as `ERROR` `StreamEvent`s by the adapter, or errors in the stream processing itself) are handled by the consuming async generator's `finally` block ensuring release, and the error propagates up to the caller of `ReasoningEngine.call()`. - -## How it Fits into the ART Ecosystem - -1. **Agent Logic (e.g., `PESAgent`):** - * Constructs an `ArtStandardPrompt`. - * Defines `CallOptions`, including the crucial `providerConfig` to select the desired LLM and its settings for the current task (planning or synthesis). - * Calls `await reasoningEngine.call(prompt, options)`. - * Iterates over the returned `AsyncIterable<StreamEvent>` to process tokens, metadata, etc. - -2. **`ReasoningEngine`:** - * Receives the request. - * Uses `ProviderManager` to get the correct, configured `ProviderAdapter`. - * Delegates the actual LLM interaction to this adapter. - * Ensures the adapter is released after use. - -3. **`ProviderManager`:** - * Manages the pool of available adapter instances. - * Provides an instance based on `RuntimeProviderConfig`. - -4. **`ProviderAdapter` (e.g., `OpenAIAdapter`, `AnthropicAdapter`):** - * Translates `ArtStandardPrompt` to its specific API format. - * Calls the LLM provider's API. - * Translates the provider's response/stream into `AsyncIterable<StreamEvent>`. - -The `ReasoningEngine` provides a clean and consistent interface for making LLM calls, while the underlying `ProviderManager` and `ProviderAdapter` system handles the complexities of interacting with diverse LLM providers. This design is key to ART's flexibility and provider-agnostic nature. \ No newline at end of file diff --git a/Docs/components/systems/tool/tool-registry.md b/Docs/components/systems/tool/tool-registry.md deleted file mode 100644 index caedea8..0000000 --- a/Docs/components/systems/tool/tool-registry.md +++ /dev/null @@ -1,65 +0,0 @@ -# Deep Dive: `ToolRegistry` - -The `ToolRegistry` is a component of ART's Tool System responsible for managing the collection of available tools (`IToolExecutor` instances) that an agent can potentially use. It allows for the registration of tools and provides a way to retrieve them by name or get a list of their schemas. - -* **Source:** `src/systems/tool/ToolRegistry.ts` -* **Implements:** `ToolRegistry` interface from `src/core/interfaces.ts` -* **Dependencies (Optional):** `StateManager`. - -## Constructor - -```typescript -constructor(stateManager?: StateManager) -``` - -* `stateManager?: StateManager` (Optional): An instance implementing `StateManager`. - * If a `StateManager` is provided, the `ToolRegistry` can use it in its `getAvailableTools` method to filter the returned tool schemas based on which tools are enabled for a specific thread (via `ThreadConfig.enabledTools`). - * If no `StateManager` is provided, `getAvailableTools` will always return all registered tools when a filter by `enabledForThreadId` is attempted, logging a warning. - -## Core Responsibilities & Methods - -1. **Registering Tools:** - * **`async registerTool(executor: IToolExecutor): Promise<void>`** - * **Purpose:** To add a tool (an instance of `IToolExecutor`) to the registry, making it available for use. - * **Process:** - 1. Validates that the provided `executor` is valid and has a `schema` with a `name`. If not, it throws an error. - 2. Uses the `executor.schema.name` as the key to store the `executor` instance in an internal `Map`. - 3. If a tool with the same name already exists in the registry, it will be **overwritten**, and a warning message is logged. - 4. Logs a debug message upon successful registration. - -2. **Retrieving Tool Executors:** - * **`async getToolExecutor(toolName: string): Promise<IToolExecutor | undefined>`** - * **Purpose:** To fetch a specific tool executor instance by its registered name. - * **Process:** - 1. Looks up the `toolName` in its internal `Map` of executors. - 2. If found, returns the `IToolExecutor` instance. - 3. If not found, logs a debug message and returns `undefined`. - -3. **Getting Available Tool Schemas:** - * **`async getAvailableTools(filter?: { enabledForThreadId?: string }): Promise<ToolSchema[]>`** - * **Purpose:** To retrieve the `ToolSchema` objects for available tools, potentially filtered by what's enabled for a specific thread. - * **Process:** - 1. Retrieves all registered tool executors and maps them to their `ToolSchema`s. - 2. **Filtering (if `filter.enabledForThreadId` and `StateManager` are present):** - * If `filter.enabledForThreadId` is provided AND a `StateManager` instance was supplied to the `ToolRegistry`'s constructor: - * It calls `this.stateManager.loadThreadContext(threadId)` to get the `ThreadConfig`. - * It then filters the list of all tool schemas, keeping only those whose names are included in the `threadContext.config.enabledTools` array. - * If `enabledTools` is not found in the config or is not an array, or if `loadThreadContext` fails, it logs a warning/error and defaults to returning all registered tool schemas as a fallback. - 3. **No Filtering:** - * If `filter.enabledForThreadId` is provided but no `StateManager` was configured, it logs a warning and returns all registered tool schemas. - * If no `filter` (or no `enabledForThreadId` in the filter) is provided, it returns all registered tool schemas. - 4. Logs debug messages indicating the filtering status and the number of schemas being returned. - -4. **Clearing Tools:** - * **`async clearAllTools(): Promise<void>`** - * **Purpose:** To remove all registered tool executors from the registry. - * **Process:** Clears the internal `Map` of executors. - * Useful primarily for testing or specific application reset scenarios. - -## Usage - -* **Initialization:** An instance of `ToolRegistryImpl` is created by the `AgentFactory` during ART setup. Any tools provided in `ArtInstanceConfig.tools` are registered at this time. -* **By `ToolSystem`:** The `ToolSystem` uses `toolRegistry.getToolExecutor(toolName)` to fetch the executor for a tool that the agent's plan has requested. -* **By Agent Logic (e.g., `PESAgent`):** The agent logic calls `toolRegistry.getAvailableTools({ enabledForThreadId: currentThreadId })` to get the list of tools that are currently permitted and relevant. The schemas of these tools (especially their names and descriptions) are then included in the planning prompt to inform the LLM about the capabilities it can request. - -The `ToolRegistry` provides a simple yet effective mechanism for managing tools within the ART Framework, with an optional integration with `StateManager` for thread-specific tool enablement. \ No newline at end of file diff --git a/Docs/components/systems/tool/tool-system.md b/Docs/components/systems/tool/tool-system.md deleted file mode 100644 index 5dc1bd7..0000000 --- a/Docs/components/systems/tool/tool-system.md +++ /dev/null @@ -1,66 +0,0 @@ -# Deep Dive: `ToolSystem` - -The `ToolSystem` is a critical component of ART's Tool System. Its primary function is to orchestrate the execution of one or more tool calls that have been identified by the agent's planning phase (typically parsed by the `OutputParser` into `ParsedToolCall` objects). It manages the entire lifecycle of a tool call, from verification and input validation to execution and result recording. - -* **Source:** `src/systems/tool/ToolSystem.ts` -* **Implements:** `ToolSystem` interface from `src/core/interfaces.ts` -* **Dependencies:** `ToolRegistry`, `StateManager`, `ObservationManager`. - -## Constructor - -```typescript -constructor( - toolRegistry: ToolRegistry, - stateManager: StateManager, - observationManager: ObservationManager -) -``` - -* `toolRegistry`: An instance of `ToolRegistry` used to look up and retrieve `IToolExecutor` instances by name. -* `stateManager`: An instance of `StateManager` used to verify if a requested tool is enabled for the current conversation thread. -* `observationManager`: An instance of `ObservationManager` used to record `TOOL_EXECUTION` observations for each tool call attempt. -* The constructor throws an error if any of these dependencies are missing. - -## Core Method: `executeTools` - -* **`async executeTools(toolCalls: ParsedToolCall[], threadId: string, traceId?: string): Promise<ToolResult[]>`** - * **Purpose:** To process an array of `ParsedToolCall` objects, execute each valid call, and return their results. - * **Parameters:** - * `toolCalls: ParsedToolCall[]`: An array of tool call requests. Each object contains `callId` (from the LLM plan, uniquely identifying this request), `toolName`, and `arguments` (the input for the tool as suggested by the LLM). - * `threadId: string`: The ID of the current conversation thread. - * `traceId?: string`: An optional trace ID for correlating observations. - * **Process (for each `ParsedToolCall` in the array):** - 1. **Log Start:** Logs the intention to execute the tool. - 2. **Check Enablement:** Calls `this.stateManager.isToolEnabled(threadId, toolName)`. - * If the tool is not enabled for the thread, an error `ToolResult` (status: 'error', error message: "Tool ... is not enabled...") is immediately generated for this call, and processing for this specific call stops. - 3. **Get Executor:** If enabled, calls `this.toolRegistry.getToolExecutor(toolName)`. - * If the tool executor is not found in the registry, an error `ToolResult` (status: 'error', error message: "Tool ... not found in registry.") is generated. - 4. **Validate Arguments:** If an executor is found: - * Calls `validateJsonSchema(executor.schema.inputSchema, call.arguments)` (from `src/utils/validation.ts`) to validate the `arguments` provided in the `ParsedToolCall` against the tool's defined `inputSchema`. - * If validation fails, an error `ToolResult` (status: 'error', error message: "Invalid arguments for tool...: [validation error details]") is generated. - 5. **Execute Tool:** If arguments are valid: - * Creates an `ExecutionContext` object containing `threadId` and `traceId`. - * Calls `await executor.execute(call.arguments, executionContext)`. - * The `IToolExecutor`'s `execute` method performs the tool's actual logic and returns a `ToolResult` (which should include `status`, `output` or `error`). - * The `ToolSystem` ensures that the `callId` and `toolName` from the original `ParsedToolCall` are correctly set on the final `ToolResult` object returned by `executeTools`, as the executor itself might not be aware of the planning-phase `callId`. - 6. **Handle Execution Errors:** If `executor.execute()` throws an exception, it's caught, and an error `ToolResult` is generated with the error message. - 7. **Record Observation:** Regardless of success or failure of the individual tool call, a `ToolResult` object is formulated. This `ToolResult` is then passed to `this.observationManager.record()` with `type: ObservationType.TOOL_EXECUTION`. This ensures every tool attempt is logged. - 8. **Collect Result:** The `ToolResult` for the current call is added to an array of results. - * **Return Value:** After processing all `ParsedToolCall`s in the input array, the method returns `Promise<ToolResult[]>`, containing a `ToolResult` for each attempted call. This array will include both success and error results. - * **Sequential Execution:** Tool calls are executed sequentially in the order they appear in the `toolCalls` array. The `ToolSystem` awaits the completion of one tool execution before starting the next. - -## Error Handling - -* The `executeTools` method itself is designed to be robust and generally **does not throw an error** if an *individual tool call* fails (e.g., tool not found, invalid args, executor throws). Instead, it captures the error within the corresponding `ToolResult` object (e.g., `status: 'error'`, `error: 'message'`). -* It will only throw an error if a critical internal issue occurs within the `ToolSystem` itself (which is unlikely given its current structure) or if a dependency like `StateManager.isToolEnabled` throws an unexpected error that isn't caught. -* The responsibility of handling individual tool failures (e.g., deciding whether to retry, inform the user, or try an alternative approach) lies with the agent core logic (like `PESAgent`) that consumes the array of `ToolResult`s. - -## Interaction with Other Systems - -* **`PESAgent`:** After the planning phase, if the `OutputParser` extracts `ParsedToolCall`s, the `PESAgent` passes this array to `toolSystem.executeTools()`. The returned `ToolResult`s are then used to inform the synthesis phase. -* **`ToolRegistry`:** Used to look up `IToolExecutor` instances based on `toolName`. -* **`StateManager`:** Used to check if a tool is enabled for the current `threadId` via `ThreadConfig.enabledTools`. -* **`ObservationManager`:** Used to record every `TOOL_EXECUTION` attempt and its outcome. -* **`IToolExecutor` Implementations:** The `ToolSystem` invokes the `execute` method of these concrete tool classes. - -The `ToolSystem` plays a crucial role in making agent tool use reliable and observable by centralizing the logic for verification, validation, execution, and logging of tool interactions. \ No newline at end of file diff --git a/Docs/components/systems/ui/conversation-socket.md b/Docs/components/systems/ui/conversation-socket.md deleted file mode 100644 index e0f017a..0000000 --- a/Docs/components/systems/ui/conversation-socket.md +++ /dev/null @@ -1,66 +0,0 @@ -# Deep Dive: `ConversationSocket` - -The `ConversationSocket` is a specialized `TypedSocket` within ART's UI System, designed specifically for broadcasting new `ConversationMessage` objects. It allows UI components or other services to subscribe to and receive real-time updates as messages are added to conversation threads. - -* **Source:** `src/systems/ui/conversation-socket.ts` -* **Extends:** `TypedSocket<ConversationMessage, MessageRole | MessageRole[]>` - -## Constructor - -```typescript -constructor(conversationRepository?: IConversationRepository) -``` - -* `conversationRepository?: IConversationRepository` (Optional): An instance of `IConversationRepository`. - * If provided, the `ConversationSocket` can use this repository to fulfill requests to its `getHistory()` method, allowing subscribers to fetch past messages. - * If not provided, `getHistory()` will log a warning and return an empty array. - -## Key Methods - -1. **`subscribe(callback: (data: ConversationMessage) => void, filter?: MessageRole | MessageRole[], options?: { threadId?: string }): UnsubscribeFunction`** - * Inherited from `TypedSocket`. - * Registers a `callback` function to be invoked when a new `ConversationMessage` is notified that matches the optional `filter` and `options`. - * **`filter?: MessageRole | MessageRole[]`:** - * If provided, the callback will only be triggered if the `role` of the notified `ConversationMessage` matches the specified `MessageRole` (if a single role is given) or is one of the roles in the array (if an array of roles is given). - * If `undefined`, the callback receives messages of any role (subject to `options.threadId` filtering). - * **`options?: { threadId?: string }`:** - * If `options.threadId` is provided, the callback will only be triggered for messages belonging to that specific `threadId`. - * The `notifyMessage` method uses `targetThreadId` from the message itself for this comparison. - * Returns an `UnsubscribeFunction` to remove the subscription. - -2. **`notifyMessage(message: ConversationMessage): void`** - * This is a convenience method specific to `ConversationSocket` (though it internally calls the base `super.notify()`). - * **Purpose:** To broadcast a new `ConversationMessage` to all relevant subscribers. - * **Process:** - 1. Logs the notification attempt. - 2. Calls `super.notify(message, { targetThreadId: message.threadId }, filterCheckFn)`. - * `targetThreadId: message.threadId` ensures that only subscribers interested in this specific thread (or all threads) are considered. - * The `filterCheckFn` is an internal function passed to `super.notify` that implements the logic for matching the message's `role` against the subscriber's `MessageRole` filter. - -3. **`async getHistory(filter?: MessageRole | MessageRole[], options?: { threadId?: string; limit?: number }): Promise<ConversationMessage[]>`** - * Overrides the optional `getHistory` method from `TypedSocket`. - * **Purpose:** To retrieve historical `ConversationMessage`s for a specific thread, potentially filtered by role (though role filtering is currently a client-side aspect within the repository or not fully supported at the query level). - * **Process:** - 1. Checks if a `conversationRepository` was configured during construction. If not, logs a warning and returns `[]`. - 2. Checks if `options.threadId` is provided. If not, logs a warning and returns `[]`. - 3. Constructs `MessageOptions` for the repository call, primarily using `options.limit`. - 4. **Role Filtering Note:** If `filter` (a `MessageRole` or array of roles) is provided, it logs a warning. The current `IConversationRepository.getMessages` interface and its typical implementations (`ConversationRepository`) primarily filter by `threadId` and apply `limit` and timestamp filters at the repository/storage level. Filtering by `MessageRole` is not a standard feature of `getMessages` in `v0.2.7`. The `ConversationSocket.getHistory` method will fetch messages based on `threadId` and `limit`, and any role filtering would need to be done by the caller on the returned array if strictly required. - 5. Calls `await this.conversationRepository.getMessages(options.threadId, messageOptions)`. - 6. Returns the fetched messages. - * **Error Handling:** Catches errors from the repository, logs them, and returns an empty array. - -## Usage Scenario - -The `ConversationManager` is the primary component that calls `conversationSocket.notifyMessage()`. When the `ConversationManager.addMessages()` method successfully saves new messages to the `ConversationRepository`, it then notifies the `ConversationSocket` for each added message. - -**Frontend/UI Integration (Conceptual):** - -A UI component responsible for displaying a chat conversation would: - -1. Obtain an instance of `ConversationSocket` (e.g., via `artInstance.uiSystem.getConversationSocket()`). -2. When a specific chat thread is opened in the UI: - * Call `conversationSocket.getHistory(undefined, { threadId: currentThreadId, limit: 50 })` to load recent messages. - * Call `conversationSocket.subscribe(newMessage => { /* Add newMessage to UI */ }, undefined, { threadId: currentThreadId })` to listen for new messages in real-time for that thread. - * Store the returned `unsubscribe` function to call it when the chat thread UI is closed or the component is unmounted, to prevent memory leaks. - -This setup allows the UI to be dynamically updated as new messages (both from the user and the AI) are processed and saved by the ART backend. \ No newline at end of file diff --git a/Docs/components/systems/ui/index.md b/Docs/components/systems/ui/index.md deleted file mode 100644 index 362aba5..0000000 --- a/Docs/components/systems/ui/index.md +++ /dev/null @@ -1,73 +0,0 @@ -# UI System Overview - -The UI System in the ART Framework provides the mechanisms for an ART agent's backend to communicate real-time updates to a user interface or other subscribed services. It's designed around a publish/subscribe pattern using specialized "sockets." - -## Purpose - -The primary goal of the UI System is to decouple the agent's core logic from the specifics of how information is presented to or consumed by a UI. Instead of the agent directly manipulating UI elements, it emits events through dedicated sockets, and the UI (or other listeners) can subscribe to these events to react accordingly. - -This enables: - -* **Real-time Updates:** UIs can display information as it happens (e.g., LLM tokens streaming in, observations about the agent's plan). -* **Decoupling:** Agent backend logic doesn't need to know about the UI's structure or technology. -* **Multiple Subscribers:** Different parts of a UI, or even different external services, can subscribe to the same event streams. -* **Testability:** Easier to test agent logic without a full UI, and UI components can be tested by mocking socket events. - -## Key Components - -1. **`UISystem` (`src/systems/ui/ui-system.ts`):** - * **Role:** A central service that instantiates and provides access to the various specialized sockets. - * It's initialized by the `AgentFactory` and injected into components like `AgentFactory` (for `ArtInstance`) and potentially directly into the agent core if needed. - * **Key Methods:** - * `getObservationSocket(): ObservationSocket` - * `getConversationSocket(): ConversationSocket` - * `getLLMStreamSocket(): LLMStreamSocket` - -2. **`TypedSocket<DataType, FilterType>` (`src/systems/ui/typed-socket.ts`):** - * **Role:** A generic base class for creating publish/subscribe channels with filtering capabilities. It's not typically used directly by applications but is extended by the specialized sockets. - * **Key Methods:** - * `subscribe(callback, filter?, options?)`: Allows a listener to register a callback function. Returns an unsubscribe function. - * `notify(data, options?, filterCheck?)`: Pushes data to relevant subscribers. - * `getHistory?(...)` (optional): A base method that subclasses can override to provide historical data. - * `clearAllSubscriptions()`: Removes all current subscriptions. - -3. **Specialized Sockets (extending `TypedSocket`):** - * **[`LLMStreamSocket`](./llm-stream-socket.md):** - * For broadcasting `StreamEvent` objects (`TOKEN`, `METADATA`, `ERROR`, `END`) generated during LLM interactions. - * Allows filtering by `StreamEvent.type`. - * **[`ObservationSocket`](./observation-socket.md):** - * For broadcasting `Observation` objects as they are recorded by the `ObservationManager`. - * Allows filtering by `ObservationType`. - * Can fetch historical observations if an `IObservationRepository` is provided to its constructor. - * **[`ConversationSocket`](./conversation-socket.md):** - * For broadcasting new `ConversationMessage` objects when they are added to a thread's history by the `ConversationManager`. - * Allows filtering by `MessageRole`. - * Can fetch historical messages if an `IConversationRepository` is provided to its constructor. - -## How It Works - -1. **Initialization:** - * During `createArtInstance`, the `AgentFactory` instantiates `UISystem`. - * `UISystem` in turn instantiates `LLMStreamSocket`, `ObservationSocket` (with `IObservationRepository`), and `ConversationSocket` (with `IConversationRepository`). - -2. **Notification (Backend):** - * **`LLMStreamSocket`:** The `PESAgent` (or other agent logic consuming `ReasoningEngine.call()`'s output) receives `StreamEvent`s and calls `llmStreamSocket.notify(event, ...)` for each one. - * **`ObservationSocket`:** The `ObservationManager.record()` method, after saving an observation, calls `observationSocket.notify(observation, ...)`. - * **`ConversationSocket`:** The `ConversationManager.addMessages()` method, after saving messages, calls `conversationSocket.notify(message, ...)` for each new message. - -3. **Subscription (Frontend/Client):** - * A UI component (or any other service) would obtain references to these socket instances (typically through an application-specific layer that bridges the ART backend with the frontend, e.g., via WebSockets, an event bus, or direct function calls if in the same process). - * It then calls `socket.subscribe(myCallbackFunction, myFilter, myOptions)` to register interest in specific events. - * `myCallbackFunction` will be invoked when a matching event is notified. - * `myFilter` (e.g., `ObservationType.PLAN` or `MessageRole.AI`) restricts which events trigger the callback. - * `myOptions` (e.g., `{ threadId: 'current-thread' }`) further refines which notifications are received. - -**Example Scenario (Conceptual UI):** - -A chat interface might: - -* Subscribe to `ConversationSocket` to display new user and AI messages for the active thread. -* Subscribe to `LLMStreamSocket` (type `TOKEN`, `tokenType: 'FINAL_SYNTHESIS_LLM_RESPONSE'`) to stream the AI's final response token by token. -* Subscribe to `ObservationSocket` (type `TOOL_EXECUTION`) to show "Agent is using tool X..." messages. - -The UI System provides a flexible and powerful way to build dynamic and informative interfaces for ART agents. \ No newline at end of file diff --git a/Docs/components/systems/ui/llm-stream-socket.md b/Docs/components/systems/ui/llm-stream-socket.md deleted file mode 100644 index 3c5b1c6..0000000 --- a/Docs/components/systems/ui/llm-stream-socket.md +++ /dev/null @@ -1,87 +0,0 @@ -# Deep Dive: `LLMStreamSocket` - -The `LLMStreamSocket` is a specialized `TypedSocket` within ART's UI System, dedicated to broadcasting `StreamEvent` objects. These events (`TOKEN`, `METADATA`, `ERROR`, `END`) are generated by `ProviderAdapter`s during Large Language Model (LLM) interactions, especially when streaming is enabled. This socket allows UI components or other services to receive real-time updates directly from the LLM's generation process. - -* **Source:** `src/systems/ui/llm-stream-socket.ts` -* **Extends:** `TypedSocket<StreamEvent, StreamEvent['type'] | Array<StreamEvent['type']>>` - * `DataType` is `StreamEvent`. - * `FilterType` is a single `StreamEvent['type']` (e.g., `'TOKEN'`, `'METADATA'`) or an array of such types. - -## Constructor - -```typescript -constructor() -``` - -* The `LLMStreamSocket` constructor is simple and currently takes no arguments. It calls `super()` to initialize the base `TypedSocket` functionality and logs an initialization message. -* It does not require a repository, as `StreamEvent`s are transient and typically not persisted as individual historical records in the same way `ConversationMessage`s or `Observation`s are (though their *content* or effects might be captured in those other records). - -## Key Methods - -1. **`subscribe(callback: (data: StreamEvent) => void, filter?: StreamEventTypeFilter, options?: { threadId?: string; sessionId?: string }): UnsubscribeFunction`** - * Inherited from `TypedSocket`, but with `FilterType` specialized for `StreamEvent['type']`. - * Registers a `callback` function to be invoked when a new `StreamEvent` is notified that matches the optional `filter` and `options`. - * **`filter?: StreamEvent['type'] | Array<StreamEvent['type']>`:** - * If provided, the callback will only be triggered if the `type` of the notified `StreamEvent` (e.g., `'TOKEN'`, `'METADATA'`) matches the specified type or is one of the types in the array. - * If `undefined`, the callback receives all `StreamEvent` types (subject to `options` filtering). - * **`options?: { threadId?: string; sessionId?: string }`:** - * `threadId`: If provided, the callback is only triggered for events belonging to this `threadId`. - * `sessionId`: If provided, the callback is only triggered for events associated with this specific UI session. - * The `notifyStreamEvent` method uses `targetThreadId` and `targetSessionId` from the `StreamEvent` itself for this comparison. - * Returns an `UnsubscribeFunction` to remove the subscription. - -2. **`notifyStreamEvent(event: StreamEvent): void`** - * This is a convenience method specific to `LLMStreamSocket` (internally calls `super.notify()`). - * **Purpose:** To broadcast a new `StreamEvent` to all relevant subscribers. - * **Process:** - 1. Logs the notification attempt, including event type, threadId, and traceId. - 2. Calls `super.notify(event, { targetThreadId: event.threadId, targetSessionId: event.sessionId }, filterCheckFn)`. - * `targetThreadId: event.threadId` and `targetSessionId: event.sessionId` ensure that only subscribers interested in this specific thread/session (or all) are considered. - * The `filterCheckFn` is an internal function passed to `super.notify` that implements the logic for matching the event's `type` against the subscriber's `StreamEvent['type']` filter. - -3. **`getHistory?` Method:** - * The `LLMStreamSocket` **does not** override the `getHistory` method from `TypedSocket`. - * `StreamEvent`s are transient and represent real-time chunks of data from an active LLM call. They are generally not stored historically as individual events by the framework. - * If `getHistory` were called on an `LLMStreamSocket` instance, it would execute the base `TypedSocket.getHistory` implementation, which logs a warning ("getHistory is not implemented in the base TypedSocket.") and returns an empty array. - -## Usage Scenario - -The `PESAgent` (or other agent core logic) is the primary component that calls `llmStreamSocket.notifyStreamEvent()`. As the agent consumes the `AsyncIterable<StreamEvent>` returned by `ReasoningEngine.call()`, it forwards each `StreamEvent` to this socket. - -**Frontend/UI Integration (Conceptual):** - -A UI component aiming to display an LLM's response as it streams in would: - -1. Obtain an instance of `LLMStreamSocket` (e.g., via `artInstance.uiSystem.getLLMStreamSocket()`). -2. When an LLM call is initiated for a specific operation (e.g., final response synthesis for `currentThreadId` and `currentSessionId`): - * Subscribe to receive `TOKEN` events: - ```javascript - // const currentThreadId = 'thread-abc'; - // const currentSessionId = 'session-xyz'; // If using session-specific updates - // const llmOutputElement = document.getElementById('llm-response-area'); - // - // const unsubscribe = art.uiSystem.getLLMStreamSocket().subscribe( - // (event) => { - // if (event.type === 'TOKEN') { - // // Append event.data (the text chunk) to the UI - // // Optionally use event.tokenType for different styling (e.g., thoughts vs. response) - // llmOutputElement.textContent += event.data; - // } else if (event.type === 'METADATA') { - // console.log('LLM Metadata:', event.data); - // } else if (event.type === 'END') { - // console.log('LLM Stream ended.'); - // // Perform any UI cleanup for the end of the stream - // } else if (event.type === 'ERROR') { - // console.error('LLM Stream error:', event.data); - // llmOutputElement.innerHTML += `<p class="error">Stream Error!</p>`; - // } - // }, - // ['TOKEN', 'METADATA', 'ERROR', 'END'], // Subscribe to all relevant types - // { threadId: currentThreadId, sessionId: currentSessionId } - // ); - // - // // Later, when the UI component is destroyed or the stream is no longer needed: - // // unsubscribe(); - ``` - -The `LLMStreamSocket` is essential for creating responsive user experiences by enabling UIs to display LLM-generated content token by token, providing immediate feedback to the user. \ No newline at end of file diff --git a/Docs/components/systems/ui/observation-socket.md b/Docs/components/systems/ui/observation-socket.md deleted file mode 100644 index 06418bc..0000000 --- a/Docs/components/systems/ui/observation-socket.md +++ /dev/null @@ -1,69 +0,0 @@ -# Deep Dive: `ObservationSocket` - -The `ObservationSocket` is a specialized `TypedSocket` within ART's UI System, designed for broadcasting `Observation` objects. As the agent executes its tasks, various components record observations using the `ObservationManager`. The `ObservationManager`, in turn, uses the `ObservationSocket` to notify any interested subscribers (like UI components or logging services) about these newly recorded observations in real-time. - -* **Source:** `src/systems/ui/observation-socket.ts` -* **Extends:** `TypedSocket<Observation, ObservationType | ObservationType[]>` - * `DataType` is `Observation`. - * `FilterType` is a single `ObservationType` enum value (e.g., `ObservationType.PLAN`) or an array of such types. - -## Constructor - -```typescript -constructor(observationRepository?: IObservationRepository) -``` - -* `observationRepository?: IObservationRepository` (Optional): An instance of `IObservationRepository`. - * If provided, the `ObservationSocket` can use this repository to fulfill requests to its `getHistory()` method, allowing subscribers to fetch past observations. - * If not provided, `getHistory()` will log a warning and return an empty array. - -## Key Methods - -1. **`subscribe(callback: (data: Observation) => void, filter?: ObservationType | ObservationType[], options?: { threadId?: string }): UnsubscribeFunction`** - * Inherited from `TypedSocket`. - * Registers a `callback` function to be invoked when a new `Observation` is notified that matches the optional `filter` and `options`. - * **`filter?: ObservationType | ObservationType[]`:** - * If provided, the callback will only be triggered if the `type` of the notified `Observation` matches the specified `ObservationType` (if a single type is given) or is one of the types in the array (if an array of types is given). - * If `undefined`, the callback receives observations of any type (subject to `options.threadId` filtering). - * **`options?: { threadId?: string }`:** - * If `options.threadId` is provided, the callback will only be triggered for observations belonging to that specific `threadId`. - * The `notifyObservation` method uses `targetThreadId` from the observation itself for this comparison. - * Returns an `UnsubscribeFunction` to remove the subscription. - -2. **`notifyObservation(observation: Observation): void`** - * This is a convenience method specific to `ObservationSocket` (internally calls `super.notify()`). - * **Purpose:** To broadcast a new `Observation` to all relevant subscribers. - * **Process:** - 1. Logs the notification attempt, including observation ID, type, and threadId. - 2. Calls `super.notify(observation, { targetThreadId: observation.threadId }, filterCheckFn)`. - * `targetThreadId: observation.threadId` ensures that only subscribers interested in this specific thread (or all threads) are considered. - * The `filterCheckFn` is an internal function passed to `super.notify` that implements the logic for matching the observation's `type` against the subscriber's `ObservationType` filter. - -3. **`async getHistory(filter?: ObservationType | ObservationType[], options?: { threadId?: string; limit?: number }): Promise<Observation[]>`** - * Overrides the optional `getHistory` method from `TypedSocket`. - * **Purpose:** To retrieve historical `Observation`s for a specific thread, potentially filtered by type. - * **Process:** - 1. Checks if an `observationRepository` was configured. If not, logs a warning and returns `[]`. - 2. Checks if `options.threadId` is provided. If not, logs a warning and returns `[]`. - 3. Constructs an `ObservationFilter` object for the repository call: - * If `filter` (an `ObservationType` or array of types) is provided, it sets `observationFilter.types`. - * The `options.limit` is **not directly part of `ObservationFilter`** in `v0.2.7`. The `IObservationRepository.getObservations` method is expected to handle limiting if its underlying `StorageAdapter.query` supports it, or the repository itself might apply a limit. The socket logs a debug message if a limit is requested, reminding that repository implementation handles it. - 4. Calls `await this.observationRepository.getObservations(options.threadId, observationFilter)`. - 5. Returns the fetched observations. - * **Error Handling:** Catches errors from the repository, logs them, and returns an empty array. - -## Usage Scenario - -The `ObservationManager` is the primary component that calls `observationSocket.notifyObservation()`. When `ObservationManager.record()` successfully saves a new observation, it then notifies the `ObservationSocket`. - -**Frontend/UI Integration (Conceptual):** - -A UI component designed to display an agent's "thought process" or a log of its actions would: - -1. Obtain an instance of `ObservationSocket` (e.g., via `artInstance.uiSystem.getObservationSocket()`). -2. When a specific agent interaction or thread is being monitored: - * Optionally, call `observationSocket.getHistory(undefined, { threadId: currentThreadId, limit: 20 })` to load some recent observations for display. - * Call `observationSocket.subscribe(newObservation => { /* Add newObservation to UI log */ }, [ObservationType.PLAN, ObservationType.TOOL_CALL, ObservationType.TOOL_EXECUTION, ObservationType.ERROR], { threadId: currentThreadId })` to listen for specific types of new observations in real-time for that thread. - * Store the returned `unsubscribe` function to call it when the UI component is unmounted or no longer needs updates for that thread. - -This allows the UI to provide users with insights into the agent's internal workings and progress as it processes requests. \ No newline at end of file diff --git a/Docs/components/systems/ui/typed-socket.md b/Docs/components/systems/ui/typed-socket.md deleted file mode 100644 index 0a6f83b..0000000 --- a/Docs/components/systems/ui/typed-socket.md +++ /dev/null @@ -1,75 +0,0 @@ -# Deep Dive: `TypedSocket` - -The `TypedSocket<DataType, FilterType>` is a generic base class within ART's UI System. It provides the core functionality for a publish/subscribe mechanism, allowing different parts of the application (especially UI components) to receive real-time updates when specific data events occur. It's designed to be extended by more specialized sockets like `LLMStreamSocket`, `ObservationSocket`, and `ConversationSocket`. - -* **Source:** `src/systems/ui/typed-socket.ts` - -## Purpose - -* **Decoupling:** Enables components that generate data (e.g., `ObservationManager`, `ConversationManager`, `PESAgent` for LLM streams) to notify interested parties without having direct dependencies on them. -* **Real-time Updates:** Facilitates pushing data to subscribers as soon as it becomes available. -* **Filtering:** Allows subscribers to specify criteria (a `FilterType` and `options` like `threadId`) to receive only relevant data. -* **Type Safety:** Uses generics (`DataType`, `FilterType`) to provide type safety for the data being passed and the filters being applied. - -## Generics - -* **`DataType`**: The type of data that will be broadcast through this socket (e.g., `StreamEvent`, `Observation`, `ConversationMessage`). -* **`FilterType` (optional, defaults to `any`):** The type of the filter criteria that subscribers can use to narrow down the notifications they receive. For example, for `ObservationSocket`, `FilterType` is `ObservationType | ObservationType[]`. - -## Constructor - -```typescript -constructor() -``` - -* The base `TypedSocket` constructor is simple and currently does not take any arguments. It initializes an internal `Map` to store subscriptions. - -## Key Methods - -1. **`subscribe(callback: (data: DataType) => void, filter?: FilterType, options?: { threadId?: string }): UnsubscribeFunction`** - * **Purpose:** Allows a client (e.g., a UI component) to register interest in receiving data from this socket. - * **Parameters:** - * `callback: (data: DataType) => void`: The function that will be invoked when a matching data event is notified. It receives the `data` of type `DataType`. - * `filter?: FilterType`: (Optional) A filter specific to the `DataType` and the specialized socket implementation. For example, for `ObservationSocket`, this could be an `ObservationType`. - * `options?: { threadId?: string }`: (Optional) Currently supports a `threadId` to scope subscriptions to a particular conversation thread. - * **Process:** - 1. Generates a unique ID for the subscription using `uuidv4()`. - 2. Stores the `callback`, `filter`, and `options` in its internal `subscriptions` Map, keyed by the generated ID. - 3. Logs that a new subscription has been added. - * **Return Value:** `UnsubscribeFunction` - A function that, when called, will remove this specific subscription from the socket. This is crucial for preventing memory leaks when a subscriber is no longer interested or is destroyed. - -2. **`notify(data: DataType, options?: { targetThreadId?: string; targetSessionId?: string }, filterCheck?: (data: DataType, filter?: FilterType) => boolean): void`** - * **Purpose:** Called by data producers to broadcast `data` to all relevant subscribers. - * **Parameters:** - * `data: DataType`: The data payload to send. - * `options?: { targetThreadId?: string; targetSessionId?: string }`: (Optional) Targeting options for the notification. - * `targetThreadId`: If provided, only subscribers whose `options.threadId` matches this (or subscribers with no `threadId` filter) will be considered. - * `targetSessionId`: (Placeholder for future use) Could be used to target specific UI sessions. - * `filterCheck?: (data: DataType, filter?: FilterType) => boolean`: (Optional) A function provided by the specialized socket (like `LLMStreamSocket.notifyStreamEvent`) that knows how to evaluate if the `data` matches a subscriber's specific `filter` (of `FilterType`). - * **Process:** - 1. Logs the notify attempt, including the type of socket and number of current subscriptions. - 2. Iterates through all active `subscriptions`. - 3. For each subscription: - * **Thread ID Check:** If the subscription has `sub.options.threadId` and the notification has `options.targetThreadId`, it checks if they match. If they don't, this subscriber is skipped. - * **Custom Filter Check:** If a `filterCheck` function is provided and the subscription has a `sub.filter`, it calls `filterCheck(data, sub.filter)`. If this returns `false`, this subscriber is skipped. - * If all checks pass, the `sub.callback(data)` is invoked. - * Catches and logs any errors thrown by a subscriber's callback function but continues notifying other subscribers. - -3. **`async getHistory?(_filter?: FilterType, _options?: { threadId?: string; limit?: number }): Promise<DataType[]>` (Optional Method)** - * **Purpose:** Intended as a hook for specialized sockets to provide a way to fetch historical data. - * **Base Implementation:** The base `TypedSocket` implementation logs a warning ("getHistory is not implemented...") and returns `Promise.resolve([])`. - * **Override in Subclasses:** Specialized sockets like `ObservationSocket` and `ConversationSocket` override this method to interact with their respective repositories if configured. `LLMStreamSocket` does not override it as stream events are typically transient. - -4. **`clearAllSubscriptions(): void`** - * **Purpose:** Removes all current subscriptions from the socket. - * Useful for cleanup, especially during testing or application shutdown/reset. - -## Extending `TypedSocket` - -Specialized sockets like `LLMStreamSocket`, `ObservationSocket`, and `ConversationSocket` extend `TypedSocket` by: - -1. Specifying the `DataType` and `FilterType` generics. -2. Often providing a more specific `notify<SpecificName>(data: DataType)` method (e.g., `notifyStreamEvent`, `notifyObservation`) that internally calls `super.notify()` with the appropriate `filterCheck` function tailored to their `DataType` and `FilterType`. -3. Optionally overriding `getHistory()` if they have a backing repository to fetch historical data from. - -`TypedSocket` provides a robust and reusable foundation for event-driven communication within the ART Framework, particularly for UI updates. \ No newline at end of file diff --git a/Docs/components/systems/ui/ui-system.md b/Docs/components/systems/ui/ui-system.md deleted file mode 100644 index ae13138..0000000 --- a/Docs/components/systems/ui/ui-system.md +++ /dev/null @@ -1,64 +0,0 @@ -# Deep Dive: `UISystem` - -The `UISystem` is a straightforward but essential component in the ART Framework. Its primary purpose is to act as a centralized service that instantiates and provides access to the various specialized `TypedSocket` instances used for UI communication. - -* **Source:** `src/systems/ui/ui-system.ts` -* **Implements:** `UISystem` interface from `src/core/interfaces.ts` -* **Dependencies:** `IObservationRepository`, `IConversationRepository`. - -## Constructor - -```typescript -constructor( - observationRepository: IObservationRepository, - conversationRepository: IConversationRepository -) -``` - -* `observationRepository: IObservationRepository`: An instance of `IObservationRepository`. This is passed directly to the constructor of the `ObservationSocket` instance that `UISystem` creates. It allows the `ObservationSocket` to fulfill `getHistory()` requests. -* `conversationRepository: IConversationRepository`: An instance of `IConversationRepository`. This is passed directly to the constructor of the `ConversationSocket` instance, enabling its `getHistory()` functionality. - -During construction, the `UISystem` performs the following: - -1. Instantiates `ObservationSocket`, providing it with the `observationRepository`. -2. Instantiates `ConversationSocket`, providing it with the `conversationRepository`. -3. Instantiates `LLMStreamSocket` (which currently has no constructor dependencies). -4. Logs a debug message indicating successful initialization. - -## Key Methods (Accessors for Sockets) - -The `UISystem` provides getter methods to retrieve the singleton instances of the specialized sockets it manages: - -1. **`getObservationSocket(): ObservationSocket`** - * Returns the single instance of `ObservationSocket` created during `UISystem`'s construction. - -2. **`getConversationSocket(): ConversationSocket`** - * Returns the single instance of `ConversationSocket`. - -3. **`getLLMStreamSocket(): LLMStreamSocket`** - * Returns the single instance of `LLMStreamSocket`. - -## Role in the Framework - -* **Centralized Access:** Instead of various components needing to know how to instantiate or locate individual sockets, they can simply get them from the `UISystem`. -* **Dependency Injection:** The `UISystem` handles injecting necessary dependencies (like repositories) into the sockets that need them for historical data retrieval. -* **Singleton Management:** Ensures that there's a single, shared instance of each type of UI communication socket throughout the application, simplifying event broadcasting and subscription management. - -## Usage - -1. **Initialization:** An instance of `UISystemImpl` is created by the `AgentFactory` during the `createArtInstance` process. The necessary repository dependencies are injected at this time. -2. **Access by `ArtInstance`:** The `ArtInstance` object returned by `createArtInstance` holds a reference to the `UISystem`, making it available to the application. - ```typescript - // const art = await createArtInstance(config); - // const obsSocket = art.uiSystem.getObservationSocket(); - // const convSocket = art.uiSystem.getConversationSocket(); - // const llmStreamSocket = art.uiSystem.getLLMStreamSocket(); - ``` -3. **Usage by Internal ART Components:** - * **`PESAgent`:** Obtains the `LLMStreamSocket` from `UISystem` to notify `StreamEvent`s during LLM calls. - * **`ObservationManager`:** Obtains the `ObservationSocket` from `UISystem` (usually injected into `ObservationManager`) to notify new `Observation`s. - * **`ConversationManager`:** Obtains the `ConversationSocket` from `UISystem` (usually injected into `ConversationManager`) to notify new `ConversationMessage`s. -4. **Usage by Application/UI Layer:** - * The application frontend or other services would typically get references to these sockets from the `artInstance.uiSystem` and then use their `subscribe()` methods to listen for relevant real-time updates. They might also use the `getHistory()` methods of `ObservationSocket` and `ConversationSocket` to load initial data. - -The `UISystem` simplifies the management and accessibility of UI communication channels within the ART Framework. \ No newline at end of file diff --git a/Docs/components/tools/calculator-tool.md b/Docs/components/tools/calculator-tool.md deleted file mode 100644 index 5d68c2b..0000000 --- a/Docs/components/tools/calculator-tool.md +++ /dev/null @@ -1,117 +0,0 @@ -# Built-in Tool: `CalculatorTool` - -The `CalculatorTool` is a built-in tool provided by the ART Framework that allows agents to evaluate mathematical expressions. It uses the [mathjs](https -://mathjs.org/) library in a sandboxed environment to perform calculations safely. - -* **Source:** `src/tools/CalculatorTool.ts` -* **Implements:** `IToolExecutor` - -## Features - -* **Safe Evaluation:** Uses `mathjs.evaluate()` with a restricted scope to prevent execution of arbitrary or unsafe code. -* **Supported Operations:** - * Basic arithmetic: `+`, `-`, `*`, `/`, `%` (modulo), `^` (power). - * Parentheses for grouping. - * Complex numbers (e.g., `sqrt(-4)`, `(1+i)*(2-i)`). -* **Allowed Functions:** A predefined set of safe mathematical functions from `mathjs` are exposed, including: - * Roots: `sqrt`, `cbrt` - * Absolute value: `abs` - * Exponentials & Logarithms: `exp`, `log` (natural), `log10`, `log2` - * Trigonometry: `sin`, `cos`, `tan`, `asin`, `acos`, `atan`, `atan2` - * Rounding: `round`, `floor`, `ceil` - * Statistical: `mean`, `median`, `std`, `variance`, `max`, `min` - * Combinatorics: `factorial`, `gamma`, `combinations`, `permutations` - * Formatting: `format` -* **Variable Scope:** Supports passing variables and their numeric values via an optional `scope` object in the input. -* **Previous Result (`ans` variable):** The tool remembers the result of the last calculation *within the same thread* and makes it available as a special variable named `ans` for subsequent calculations in that thread. - -## Schema (`ToolSchema`) - -The `CalculatorTool.schema` property defines its interface for the LLM and the `ToolSystem`: - -```typescript -{ - name: "calculator", - description: "Evaluates mathematical expressions using a sandboxed mathjs environment.\nYou can reference previous calculation results using the 'ans' variable.\nSupports standard operators (+, -, *, /, %, ^), variables via 'scope', complex numbers, and a predefined list of allowed functions...", // (truncated for brevity, see source for full list) - inputSchema: { - type: 'object', - properties: { - expression: { - type: 'string', - description: 'The mathematical expression to evaluate (e.g., "2 + 2", "sqrt(a)", "a * b", "sqrt(-4)", "factorial(5)", "ans + 10").', - }, - scope: { - type: 'object', - description: 'An optional object containing variables and their values (numbers only) to be used in the expression (e.g., {"a": 16, "b": 3}).', - additionalProperties: { type: 'number' }, - default: {}, - }, - }, - required: ['expression'], - }, - examples: [ - // ... (see source or tests for full list of examples) - { input: { expression: "2 + 2" }, output: { result: 4 } }, - { input: { expression: "a + b", scope: { a: 7, b: 3 } }, output: { result: 10 } }, - { input: { expression: "sqrt(-4)" }, output: { result: "2i" } }, - { input: { expression: "ans + 10" }, output: { result: 130 }, description: "Using previous result (assuming previous result was 120)" }, - ] -} -``` - -**Input:** - -* `expression: string` (Required): The mathematical expression to evaluate. -* `scope?: object` (Optional): An object where keys are variable names and values are their **numeric** values. - -**Output (on success):** - -* An object: `{ result: number | string }` - * `result`: The numerical result of the calculation, or a string representation if the result is a complex number (e.g., "2i", "-1 + 5i"). - -## `execute` Method - -`async execute(input: any, context: ExecutionContext): Promise<ToolResult>` - -1. Retrieves the `expression` and optional `scope` from the `input`. -2. Retrieves the `threadId` from the `context` to manage the `ans` variable correctly per thread. -3. Fetches the previous calculation result (`ans`) for the current `threadId` from an internal `resultStore` (a `Map`). -4. Constructs an `executionScope` for `mathjs.evaluate()`: - * Starts with the `allowedFunctions`. - * Merges in the user-provided `input.scope`. - * If a previous result (`ans`) exists for the thread, it's added to the scope. -5. Calls `mathjs.evaluate(expression, executionScope)`. -6. **Result Handling:** - * If the result is a finite `number`, it's used directly. - * If the result is a `Complex` number object from `mathjs`, it's converted to its string representation (e.g., `"2 + 3i"`). - * If the evaluation results in any other type (e.g., a function definition `f(x)=x^2`, a matrix), it's treated as an error because the tool is designed to return simple numerical or complex string results. -7. Stores the new numerical or complex result (the actual `mathjs` object, not just the string for complex numbers if further calculations are needed) in the `resultStore` for the current `threadId`, making it available as `ans` for the next calculation in that thread. -8. Returns a `ToolResult`: - * On success: `{ status: 'success', output: { result: outputResult } }`. - * On error (e.g., invalid expression, undefined symbol, disallowed function, unsupported result type): `{ status: 'error', error: "Failed to evaluate expression: <error_message>" }`. - -## Usage - -To use the `CalculatorTool`: - -1. Instantiate it: `new CalculatorTool()`. -2. Register it with the `ToolRegistry` by including it in the `tools` array of `ArtInstanceConfig` when calling `createArtInstance`. -3. Ensure your agent's planning prompt informs the LLM about the "calculator" tool, its description, and its input schema (especially the `expression` and optional `scope` arguments, and the `ans` variable). - -**Example LLM Interaction:** - -*User Query:* "What is 5 times 3, and then add 10 to that result?" - -*Agent Plan (Simplified LLM Output):* -``` -Intent: Perform two calculations. -Plan: -1. Calculate 5 * 3. -2. Add 10 to the previous result. -Tool Calls: [ - {"callId": "calc1", "toolName": "calculator", "arguments": {"expression": "5 * 3"}}, - {"callId": "calc2", "toolName": "calculator", "arguments": {"expression": "ans + 10"}} -] -``` - -The `ToolSystem` would execute these sequentially. After the first call, `resultStore` for the thread would hold `15`. The second call would use `ans` (which resolves to `15`) to calculate `15 + 10`. \ No newline at end of file diff --git a/Docs/components/tools/creating-custom-tools.md b/Docs/components/tools/creating-custom-tools.md deleted file mode 100644 index 2bdc793..0000000 --- a/Docs/components/tools/creating-custom-tools.md +++ /dev/null @@ -1,198 +0,0 @@ -# Creating Custom Tools - -The ART Framework's tool system is designed to be extensible, allowing you to empower your AI agents with custom capabilities. By creating classes that implement the `IToolExecutor` interface, you can define tools that interact with external APIs, databases, internal application logic, or perform any other specialized task. - -## Steps to Create a Custom Tool - -1. **Define the Tool's Purpose and Interface:** - * Clearly define what the tool will do. - * Determine the inputs it needs and the output it will produce. - -2. **Create a Tool Class Implementing `IToolExecutor`:** - * **Source:** Typically in your project's `src/tools/` directory. - * Import necessary types from `art-framework`: - ```typescript - import { - IToolExecutor, - ToolSchema, - JsonSchema, // For defining input/output schemas - ExecutionContext, - ToolResult, - Logger // Optional, for logging within your tool - } from 'art-framework'; - ``` - -3. **Implement the `schema` Property (Readonly `ToolSchema`):** - This is crucial metadata that describes your tool to both the LLM and the ART framework. - * **`name: string`:** A unique, descriptive name for the tool (e.g., "get_stock_price", "send_email"). This name is used by the LLM to request the tool. Use snake_case for multi-word names if your LLM prefers it for function calling. - * **`description: string`:** A clear, natural language explanation of: - * What the tool does. - * When it should be used. - * Any important considerations or limitations. - This description is vital for the LLM to make an informed decision about using your tool. - * **`inputSchema: JsonSchema`:** A [JSON Schema](https://json-schema.org/) object defining the expected input arguments for your tool. - * Specify `type: "object"`. - * Define `properties` for each argument, including its `type` (e.g., "string", "number", "boolean", "array", "object") and a `description` for the LLM. - * List required arguments in a `required: string[]` array. - * Example: - ```typescript - inputSchema: { - type: "object", - properties: { - city: { type: "string", description: "The city name, e.g., 'London'." }, - countryCode: { type: "string", description: "The 2-letter ISO country code, e.g., 'GB'." } - }, - required: ["city"] - } as JsonSchema, // Cast if properties isn't exhaustive for JsonSchema type - ``` - * **`outputSchema?: JsonSchema` (Optional but Recommended):** A JSON Schema defining the structure of the data your tool returns in the `output` field of a successful `ToolResult`. This helps the LLM understand what kind of data to expect back. - * **`examples?: Array<{ input: any; output?: any; error?: string; description?: string }>` (Optional but Recommended):** - * Provide a few examples of how the tool is called (sample `input` arguments) and what its `output` (on success) or `error` (on failure) might look like. - * These examples can significantly help the LLM understand how to use the tool correctly, especially for few-shot prompting. - -4. **Implement the `async execute(input: any, context: ExecutionContext): Promise<ToolResult>` Method:** - This is where your tool's core logic resides. - * **`input: any`:** This will be an object containing the arguments for your tool, as provided by the LLM and **already validated** by the `ToolSystem` against your `inputSchema`. You can safely access `input.argumentName`. - * **`context: ExecutionContext`:** Provides: - * `threadId: string`: The ID of the current conversation thread. - * `traceId?: string`: The trace ID for the current agent execution cycle. - * You can use these for logging, or if your tool needs to interact with thread-specific data. - * **Logic:** Implement the functionality of your tool. This might involve: - * Calling external APIs. - * Querying a database. - * Performing calculations or data transformations. - * Interacting with other parts of your application. - * **Return `ToolResult`:** - * **On Success:** - ```typescript - return { - callId: context.traceId || 'some-unique-call-id', // Best to use provided traceId if available - toolName: this.schema.name, - status: 'success', - output: { /* your tool's result data */ } - }; - ``` - The `output` should ideally match your `outputSchema` if defined. - * **On Failure:** - Catch any errors and return a `ToolResult` with `status: 'error'`. - ```typescript - return { - callId: context.traceId || 'some-unique-call-id', - toolName: this.schema.name, - status: 'error', - error: "Descriptive error message about what went wrong." - }; - ``` - Use `Logger.error()` for more detailed internal logging if needed. - -## Example: Simple User Profile Tool - -```typescript -// src/tools/user-profile-tool.ts -import { - IToolExecutor, - ToolSchema, - JsonSchema, - ExecutionContext, - ToolResult, - Logger -} from 'art-framework'; - -interface UserProfile { - userId: string; - name: string; - email?: string; - preferences?: Record<string, any>; -} - -// Mock database -const MOCK_USER_DB: Record<string, UserProfile> = { - "user123": { userId: "user123", name: "Alice Wonderland", email: "alice@example.com", preferences: { theme: "dark" } }, - "user456": { userId: "user456", name: "Bob The Builder" } -}; - -export class UserProfileTool implements IToolExecutor { - readonly schema: ToolSchema = { - name: "get_user_profile", - description: "Retrieves the profile information for a given user ID. Returns name, email, and preferences if available.", - inputSchema: { - type: "object", - properties: { - userId: { - type: "string", - description: "The unique identifier of the user." - } - }, - required: ["userId"] - } as JsonSchema, - outputSchema: { - type: "object", - properties: { - userId: { type: "string" }, - name: { type: "string" }, - email: { type: "string" }, - preferences: { type: "object" } - }, - required: ["userId", "name"] - } as JsonSchema, - examples: [ - { - input: { userId: "user123" }, - output: { userId: "user123", name: "Alice Wonderland", email: "alice@example.com", preferences: { theme: "dark" } }, - description: "Get Alice's profile." - }, - { - input: { userId: "user789" }, - output: null, // Or an error status if appropriate for your design - error: "User profile not found for ID: user789", - description: "Attempt to get a non-existent user." - } - ] - }; - - async execute(input: { userId: string }, context: ExecutionContext): Promise<ToolResult> { - const callId = context.traceId || `user-profile-${Date.now()}`; - Logger.info(`UserProfileTool: Attempting to fetch profile for userId: ${input.userId}`, { callId, threadId: context.threadId }); - - const profile = MOCK_USER_DB[input.userId]; - - if (profile) { - return { - callId, - toolName: this.schema.name, - status: 'success', - output: profile // The profile object itself - }; - } else { - const errorMessage = `User profile not found for ID: ${input.userId}`; - Logger.warn(`UserProfileTool: ${errorMessage}`, { callId }); - return { - callId, - toolName: this.schema.name, - status: 'error', - error: errorMessage - }; - } - } -} -``` - -5. **Register Your Tool:** - Add an instance of your new tool to the `tools` array in your `ArtInstanceConfig` when calling `createArtInstance`. - - ```typescript - // src/config/art-config.ts - import { ArtInstanceConfig /* ... other imports */ } from 'art-framework'; - import { UserProfileTool } from '../tools/user-profile-tool'; // Adjust path - - export const myAppArtConfig: ArtInstanceConfig = { - // ... storage and provider config ... - tools: [ - new UserProfileTool(), - // ... other tools ... - ], - // ... - }; - ``` - -By following these steps, you can extend your ART agent's capabilities to interact with any system or perform any action you need. Remember that clear descriptions and well-defined input/output schemas are key to enabling the LLM to use your tools effectively. \ No newline at end of file diff --git a/Docs/components/tools/index.md b/Docs/components/tools/index.md deleted file mode 100644 index 86925cf..0000000 --- a/Docs/components/tools/index.md +++ /dev/null @@ -1,67 +0,0 @@ -# Tools Overview - -Tools in the ART Framework represent external capabilities or actions that an AI agent can utilize to gather information, interact with other systems, or perform tasks beyond the inherent knowledge of the Large Language Model (LLM). The framework provides a structured way to define, register, and execute these tools. - -## Key Concepts and Components - -1. **`IToolExecutor` Interface (`src/core/interfaces.ts`):** - * This is the **contract** that all tools must implement. - * **`schema: ToolSchema` (readonly):** Every tool must provide a `ToolSchema` that describes its: - * `name`: A unique identifier for the tool. - * `description`: A natural language explanation of what the tool does, for the LLM to understand its purpose. - * `inputSchema: JsonSchema`: A JSON Schema defining the expected input arguments. - * `outputSchema?: JsonSchema` (Optional): A JSON Schema for the tool's successful output. - * `examples?: Array<{...}>` (Optional): Examples of usage. - * **`async execute(input: any, context: ExecutionContext): Promise<ToolResult>`:** The method containing the tool's actual logic. It receives validated `input` and an `ExecutionContext` (with `threadId`, `traceId`) and returns a `ToolResult`. - -2. **`ToolSchema` Interface (`src/types/index.ts`):** - * Provides the metadata that describes a tool to both the LLM (for selection and argument generation) and the ART Framework (for validation and execution). See above and the [Tools and Capabilities core concept page](../../core-concepts/tools-and-capabilities.md) for more details. - -3. **`ToolResult` Interface (`src/types/index.ts`):** - * The standardized structure for the outcome of a tool execution: - * `callId: string`: Links back to the `ParsedToolCall` ID from the LLM's plan. - * `toolName: string`: The name of the executed tool. - * `status: 'success' | 'error'`: Indicates the outcome. - * `output?: any`: The data returned by the tool on success. - * `error?: string`: An error message if execution failed. - * `metadata?: Record<string, any>`: Optional additional execution metadata. - -4. **`ToolRegistry` (`src/systems/tool/ToolRegistry.ts`):** - * A central repository for all registered `IToolExecutor` instances. - * Allows tools to be added (registered) and retrieved by their unique `name`. - * Can provide a list of `ToolSchema`s for all available (and potentially thread-enabled) tools, which is crucial for prompting the LLM. - -5. **`ToolSystem` (`src/systems/tool/ToolSystem.ts`):** - * Orchestrates the actual execution of tools requested by the agent. - * It takes `ParsedToolCall` objects (from the `OutputParser`), verifies tool enablement (via `StateManager`), retrieves the executor from `ToolRegistry`, validates input arguments against the `ToolSchema`, calls the executor's `execute` method, and records `TOOL_EXECUTION` observations. - -6. **`ParsedToolCall` (`src/types/index.ts`):** - * Represents the LLM's request to use a tool, as interpreted by the `OutputParser` from the planning phase output. Contains `callId`, `toolName`, and `arguments`. - -## Workflow of Tool Usage (Typical in `PESAgent`) - -1. **Tool Definition & Registration:** - * Developers create custom tool classes implementing `IToolExecutor`. - * Instances of these tools are provided in `ArtInstanceConfig.tools` when calling `createArtInstance`. - * The `AgentFactory` registers these tools with the `ToolRegistry`. -2. **Planning Phase:** - * The agent (e.g., `PESAgent`) retrieves schemas of available (and enabled) tools from the `ToolRegistry`. - * These tool schemas (name, description, input schema) are included in the prompt sent to the LLM. - * The LLM, if it decides a tool is necessary, includes a request to call the tool (with specific arguments) in its planning output. This is often in a structured format like JSON. - * The `OutputParser` processes the LLM's planning output and extracts these requests as `ParsedToolCall` objects. -3. **Execution Phase:** - * The agent passes the `ParsedToolCall` objects to the `ToolSystem.executeTools()`. - * The `ToolSystem` handles the execution of each tool as described above. -4. **Synthesis Phase:** - * The `ToolResult`s (both successes and errors) are provided back to the agent. - * The agent includes these results in the context for the synthesis prompt, allowing the LLM to use the tool outputs to formulate its final response or explain any tool failures. - -## Built-in Tools - -ART `v0.2.7` includes: - -* **[`CalculatorTool`](calculator-tool.md):** A tool for evaluating mathematical expressions using a sandboxed `mathjs` environment. - -## Creating Custom Tools - -Refer to the [Creating Custom Tools](./creating-custom-tools.md) guide for detailed instructions on how to implement the `IToolExecutor` interface and define your tool's `ToolSchema`. This is a core extensibility point of the ART Framework. \ No newline at end of file diff --git a/Docs/components/types/index.md b/Docs/components/types/index.md deleted file mode 100644 index 77af9ac..0000000 --- a/Docs/components/types/index.md +++ /dev/null @@ -1,107 +0,0 @@ -# Key Types Overview - -The `src/types/index.ts` file (along with `src/types/providers.ts` and `src/types/schemas.ts`) serves as the central hub for most of the important data structures and type definitions used throughout the ART Framework. Understanding these types is essential for working with and extending ART. - -This page provides an overview of some of the most critical types. For detailed definitions, refer to the source files. - -## Core Agent Interaction Types - -* **`AgentProps`**: - * The input object passed to `IAgentCore.process()`. - * Contains `query: string`, `threadId: string`, and optional `sessionId`, `userId`, `traceId`, and `options: AgentOptions`. -* **`AgentOptions`**: - * Optional overrides for a specific `process` call, like `llmParams`, `providerConfig` (for runtime LLM selection), `forceTools`. -* **`AgentFinalResponse`**: - * The output object from `IAgentCore.process()`. - * Contains `response: ConversationMessage` (the final AI message) and `metadata: ExecutionMetadata`. -* **`ExecutionMetadata`**: - * Summarizes an agent's execution cycle: `threadId`, `traceId`, `status` ('success', 'error', 'partial'), `totalDurationMs`, `llmCalls`, `toolCalls`, `error?` message, and `llmMetadata?`. - -## Conversation and Messaging Types - -* **`MessageRole` (Enum):** - * Defines the sender of a message: `USER`, `AI`, `SYSTEM`, `TOOL`. -* **`ConversationMessage`**: - * Structure for a single message in a conversation: `messageId`, `threadId`, `role`, `content: string`, `timestamp`, `metadata?`. -* **`ArtStandardMessageRole` (Type Alias):** - * Roles used in `ArtStandardPrompt`: `'system' | 'user' | 'assistant' | 'tool_request' | 'tool_result' | 'tool'`. -* **`ArtStandardMessage`**: - * The standardized message structure for `ArtStandardPrompt`. Includes `role`, `content` (can be string, object, or null depending on role), `name?`, `tool_calls?` (for assistant role, defining function calls), `tool_call_id?` (for tool_result role). -* **`ArtStandardPrompt` (Type Alias):** - * `ArtStandardMessage[]`: An array of standardized messages, representing the complete prompt sent to `ProviderAdapter.call`. This is the primary prompt abstraction in ART. -* **`MessageOptions`**: - * Options for retrieving messages, e.g., `limit`, `beforeTimestamp`, `afterTimestamp`. - -## LLM Interaction and Streaming - -* **`StreamEvent`**: - * The standard object emitted by `ProviderAdapter.call()` when streaming. - * `type: 'TOKEN' | 'METADATA' | 'ERROR' | 'END'`. - * `data: any` (content depends on `type`). - * `tokenType?: string` (e.g., `AGENT_THOUGHT_LLM_RESPONSE`, `FINAL_SYNTHESIS_LLM_RESPONSE`) for `TOKEN` events, providing more context about the token's origin/purpose. - * Includes `threadId`, `traceId`, `sessionId?`. -* **`LLMMetadata`**: - * Structure for metadata about an LLM call (often part of a `METADATA` `StreamEvent`): `inputTokens?`, `outputTokens?`, `timeToFirstTokenMs?`, `totalGenerationTimeMs?`, `stopReason?`, `providerRawUsage?`. -* **`CallOptions`**: - * Options passed to `ReasoningEngine.call()` and `ProviderAdapter.call()`. - * Includes `threadId`, `traceId?`, `stream?`, `callContext?` (e.g., 'AGENT_THOUGHT', 'FINAL_SYNTHESIS'), and crucially `providerConfig: RuntimeProviderConfig`. Also allows arbitrary provider-specific parameters. -* **`ModelCapability` (Enum):** - * Defines capabilities of an LLM like `TEXT`, `VISION`, `STREAMING`, `TOOL_USE`, `REASONING`. Used for model selection or validation. - -## Tool System Types - -* **`ToolSchema`**: - * Defines a tool's interface: `name`, `description`, `inputSchema: JsonSchema`, `outputSchema?: JsonSchema`, `examples?`. -* **`JsonSchema` (Type Alias for `JsonObjectSchema` or other basic schema types):** - * Represents a JSON Schema, primarily used for `ToolSchema.inputSchema` and `outputSchema`. -* **`ParsedToolCall`**: - * Structure representing the LLM's request to call a tool, as parsed by `OutputParser`: `callId`, `toolName`, `arguments`. -* **`ToolResult`**: - * The outcome of a tool execution: `callId`, `toolName`, `status: 'success' | 'error'`, `output?`, `error?`. -* **`ExecutionContext`**: - * Context provided to a tool's `execute` method: `threadId`, `traceId?`, `userId?`. - -## State and Configuration Types - -* **`ThreadConfig`**: - * Configuration for a specific conversation thread: `providerConfig: RuntimeProviderConfig` (default LLM setup for the thread), `enabledTools: string[]`, `historyLimit: number`. -* **`AgentState`**: - * Persistent state for an agent within a thread: `data: any` (application-defined), `version?`. -* **`ThreadContext`**: - * Bundles `config: ThreadConfig` and `state: AgentState | null`. -* **`StateSavingStrategy` (Type Alias):** - * `'explicit' | 'implicit'`: Defines how `AgentState` is saved. - -## Provider Management Types (`src/types/providers.ts`) - -* **`AvailableProviderEntry`**: - * Defines a provider adapter available to the `ProviderManager`: `name`, `adapter` (constructor), `isLocal?`. -* **`ProviderManagerConfig`**: - * Configuration for `ProviderManager`: `availableProviders[]`, `maxParallelApiInstancesPerProvider?`, `apiInstanceIdleTimeoutSeconds?`. -* **`RuntimeProviderConfig`**: - * Configuration for a *specific* LLM call: `providerName`, `modelId`, `adapterOptions` (e.g., API key). Passed in `CallOptions`. -* **`ManagedAdapterAccessor`**: - * Object returned by `ProviderManager.getAdapter()`: `adapter: ProviderAdapter`, `release: () => void`. - -## Observation Types - -* **`ObservationType` (Enum):** - * Categories of agent events: `INTENT`, `PLAN`, `TOOL_CALL`, `TOOL_EXECUTION`, `SYNTHESIS`, `ERROR`, `FINAL_RESPONSE`, `LLM_STREAM_START`, etc. -* **`Observation`**: - * Structure for a recorded event: `id`, `threadId`, `timestamp`, `type`, `title`, `content: any`, `metadata?`. -* **`ObservationFilter`**: - * Options for filtering observations: `types?`, `beforeTimestamp?`, `afterTimestamp?`. - -## Error Types (`src/errors.ts`) - -* **`ErrorCode` (Enum):** - * Standardized error codes for various framework issues (e.g., `INVALID_CONFIG`, `LLM_PROVIDER_ERROR`, `TOOL_NOT_FOUND`). -* **`ARTError` (Class):** - * Custom error class extending `Error`, includes `code: ErrorCode` and `originalError?`. - -## Zod Schemas (`src/types/schemas.ts`) - -* **`ArtStandardMessageSchema`**: Zod schema for validating a single `ArtStandardMessage`. -* **`ArtStandardPromptSchema`**: Zod schema for validating an `ArtStandardPrompt` (an array of messages). - -These types collectively define the data contracts and structures that enable the different components of the ART Framework to communicate and operate effectively. Developers building with or extending ART will frequently interact with these types. \ No newline at end of file diff --git a/Docs/components/utils/logger.md b/Docs/components/utils/logger.md deleted file mode 100644 index 07b72b6..0000000 --- a/Docs/components/utils/logger.md +++ /dev/null @@ -1,99 +0,0 @@ -# Utility: `Logger` - -The ART Framework includes a simple, static `Logger` class for handling console log messages at different severity levels. This helps in debugging and monitoring the framework's internal operations as well as application-specific events. - -* **Source:** `src/utils/logger.ts` - -## Features - -* **Static Class:** No need to instantiate; methods are called directly (e.g., `Logger.info(...)`). -* **Configurable Log Level:** You can set a minimum log level to control the verbosity of the output. -* **Standard Log Levels:** Supports `DEBUG`, `INFO`, `WARN`, and `ERROR` levels. -* **Optional Prefix:** A prefix (defaulting to `[ART]`) can be added to all log messages for easy identification. -* **Console Output:** Uses standard `console.debug`, `console.info`, `console.warn`, and `console.error`. - -## `LogLevel` Enum - -Defines the available logging levels, ordered by severity (lower number is more verbose): - -```typescript -export enum LogLevel { - DEBUG = 0, // Detailed debugging information - INFO = 1, // General informational messages - WARN = 2, // Potential issues or unexpected situations - ERROR = 3 // Errors indicating a failure -} -``` - -## Configuration - -The `Logger` is configured globally using the static `configure` method. - -* **`Logger.configure(config: Partial<LoggerConfig>): void`** - * `config: Partial<LoggerConfig>`: An object that can contain: - * `level?: LogLevel`: The minimum log level to output. Messages below this level will be ignored. Defaults to `LogLevel.INFO` if not configured. - * `prefix?: string`: An optional string to prepend to all log messages. Defaults to `[ART]` if not set during configuration. - -**Example Configuration (typically done once at application startup):** - -```typescript -import { Logger, LogLevel, ArtInstanceConfig /* ... */ } from 'art-framework'; - -// Example within your ArtInstanceConfig setup -const artConfig: ArtInstanceConfig = { - // ... other configurations ... - logger: { - level: LogLevel.DEBUG, // Show all messages including debug - // prefix: "[MyAgentApp]" // Optional: Custom prefix - }, -}; - -// If you are not using ArtInstanceConfig to set it, or want to change it later: -// Logger.configure({ level: LogLevel.WARN, prefix: "[MyApp-ART]" }); - -// Note: If ArtInstanceConfig.logger is provided to createArtInstance, -// the AgentFactory will internally call Logger.configure. -// If you call Logger.configure manually, it will affect the global logger state. -``` -If `ArtInstanceConfig.logger` is provided to `createArtInstance`, the `AgentFactory` will call `Logger.configure` internally. - -## Logging Methods - -All logging methods are static: - -* **`Logger.debug(message: string, ...args: any[]): void`** - * Logs a message at the `DEBUG` level. - * Only outputs if the configured `level` is `LogLevel.DEBUG`. - -* **`Logger.info(message: string, ...args: any[]): void`** - * Logs a message at the `INFO` level. - * Outputs if the configured `level` is `LogLevel.INFO` or `LogLevel.DEBUG`. - -* **`Logger.warn(message: string, ...args: any[]): void`** - * Logs a message at the `WARN` level. - * Outputs if the configured `level` is `LogLevel.WARN`, `LogLevel.INFO`, or `LogLevel.DEBUG`. - -* **`Logger.error(message: string, ...args: any[]): void`** - * Logs a message at the `ERROR` level. - * Outputs for any configured `level` (as `ERROR` is the highest severity). - -**Usage Example:** - -```typescript -import { Logger, LogLevel } from 'art-framework'; - -Logger.configure({ level: LogLevel.INFO }); - -Logger.debug("This debug message will not be shown."); // Below configured level -Logger.info("Application started successfully.", { version: "1.0.0" }); -Logger.warn("A minor configuration issue was detected.", { setting: "someSetting" }); -Logger.error("A critical error occurred!", new Error("Something went wrong")); - -// Output (if prefix is default '[ART]'): -// [ART] Application started successfully. { version: '1.0.0' } -// [ART] A minor configuration issue was detected. { setting: 'someSetting' } -// [ART] A critical error occurred! Error: Something went wrong -// at ... (stack trace) -``` - -The `Logger` is used extensively throughout the ART Framework internals to provide insights into its operations. Application developers can also use it for their own logging needs, benefiting from the same level and prefix configuration. \ No newline at end of file diff --git a/Docs/components/utils/validation.md b/Docs/components/utils/validation.md deleted file mode 100644 index aa49b4d..0000000 --- a/Docs/components/utils/validation.md +++ /dev/null @@ -1,64 +0,0 @@ -# Utility: JSON Schema Validation - -The ART Framework includes a utility function for validating JavaScript objects against a [JSON Schema](https://json-schema.org/) definition. This is particularly important for validating the input arguments provided to tools before execution. - -* **Source:** `src/utils/validation.ts` -* **Underlying Library:** Uses [Ajv (Another JSON Schema Validator)](https://ajv.js.org/) for robust and efficient schema validation. - -## `validateJsonSchema` Function - -* **`validateJsonSchema(schema: object, data: any): { isValid: boolean; errors: ValidateFunction['errors'] | null }`** - * **Purpose:** To check if a given `data` object conforms to the structure and constraints defined by a `schema` object. - * **Parameters:** - * `schema: object`: The JSON Schema object to validate against. It's assumed to be a valid JSON Schema structure. - * `data: any`: The JavaScript data (typically an object) to be validated. - * **Return Value:** An object with two properties: - * `isValid: boolean`: `true` if the `data` is valid according to the `schema`, `false` otherwise. - * `errors: AjvErrorObject[] | null`: - * If `isValid` is `false`, this property contains an array of Ajv validation error objects, providing details about why the validation failed (e.g., missing required properties, incorrect data types). - * If `isValid` is `true`, this is `null`. - * If the provided `schema` itself fails to compile with Ajv, `isValid` will be `false`, and `errors` will contain a single error object indicating schema compilation failure. - * **Caching:** The function caches compiled Ajv validation functions based on a stringified version of the schema. This improves performance for repeated validations against the same schema, as schema compilation can be an expensive operation. - * The cache can be cleared using `clearJsonSchemaValidatorCache()`. - -## How It's Used - -The primary use case within the ART Framework is in the **`ToolSystem`**: - -1. When the `ToolSystem` is about to execute a tool, it retrieves the tool's `IToolExecutor` instance from the `ToolRegistry`. -2. It accesses `executor.schema.inputSchema`, which is the JSON Schema defining the expected input arguments for that tool. -3. It calls `validateJsonSchema(inputSchema, argumentsFromLLM)` to validate the arguments provided by the LLM (from a `ParsedToolCall`) against the tool's declared input requirements. -4. If `isValid` is `false`, the `ToolSystem` generates an error `ToolResult` for that tool call, including details from the `validationResult.errors`. The tool's `execute` method is not called. -5. If `isValid` is `true`, the (now validated) arguments are passed to the tool's `execute` method. - -**Example (`ToolSystem` conceptual usage):** - -```typescript -// import { validateJsonSchema } from 'art-framework'; // Path from art-framework/utils -// import { ToolSchema, ParsedToolCall } from 'art-framework'; // Path from art-framework/types - -// async function processToolCall(toolSchema: ToolSchema, parsedCall: ParsedToolCall) { -// const validationResult = validateJsonSchema(toolSchema.inputSchema, parsedCall.arguments); - -// if (!validationResult.isValid) { -// const errorMessages = validationResult.errors?.map(e => `${e.instancePath || 'input'} ${e.message}`).join(', '); -// console.error(`Argument validation failed for tool ${toolSchema.name}: ${errorMessages}`); -// // Return an error ToolResult -// return { status: 'error', error: `Invalid arguments: ${errorMessages}` }; -// } - -// // Proceed with tool execution using parsedCall.arguments -// // const output = await executor.execute(parsedCall.arguments, ...); -// // return { status: 'success', output }; -// } -``` - -## `clearJsonSchemaValidatorCache` Function - -* **`clearJsonSchemaValidatorCache(): void`** - * **Purpose:** Clears the internal cache of compiled Ajv validation functions. - * **Use Cases:** - * Primarily useful in testing scenarios where you might be redefining schemas or want to ensure a clean state for validator performance tests. - * In production, it's generally not needed unless schemas are being dynamically generated and updated in a way that requires recompilation for correctness. - -This validation utility helps ensure that tools receive input in the format they expect, reducing runtime errors within tool execution logic and providing clearer feedback when LLMs generate malformed tool arguments. \ No newline at end of file diff --git a/Docs/components/utils/xml-matcher.md b/Docs/components/utils/xml-matcher.md deleted file mode 100644 index 8a9ac8a..0000000 --- a/Docs/components/utils/xml-matcher.md +++ /dev/null @@ -1,113 +0,0 @@ -# Utility: `XmlMatcher` - -The `XmlMatcher` is a utility class provided by the ART Framework designed to find and extract content within a specific XML-like tag from a stream of text or a complete string. It's particularly useful for parsing LLM outputs where "thinking" steps or other structured information might be embedded within tags (e.g., `<think>...</think>`). - -* **Source:** `src/utils/xml-matcher.ts` - -## Purpose - -LLMs sometimes interleave their reasoning or intermediate thoughts with the main content of their response. A common convention is to wrap these thoughts in XML-like tags. The `XmlMatcher` provides a way to process text (either incrementally or all at once) and separate the content found inside a specified tag from the content outside it. - -## `XmlMatcherChunk` Interface - -When processing text, `XmlMatcher` yields or returns chunks of data represented by the `XmlMatcherChunk` interface: - -```typescript -export interface XmlMatcherChunk { - matched: boolean; // True if this chunk was inside the matched XML tag - data: string; // The text content of this chunk -} -``` - -## Constructor - -```typescript -constructor( - readonly tagName: string, - readonly transform?: (chunk: XmlMatcherChunk) => Result, // Result defaults to XmlMatcherChunk - readonly position = 0 -) -``` - -* **`tagName: string` (Required):** The name of the XML tag to match (e.g., `"think"`, `"reflection"`). The matching is case-sensitive. -* **`transform?: (chunk: XmlMatcherChunk) => Result` (Optional):** - * A function that can be provided to transform each `XmlMatcherChunk` into a different `Result` type. - * If not provided, the methods return `XmlMatcherChunk` objects directly. -* **`position = 0` (Optional):** - * The character position in the input stream at which active matching for the *start* of the `tagName` should begin. - * If `0` (default), matching for `<tagName>` starts from the beginning of the input. - * If greater than `0`, characters before this `position` are treated as unmatched text (`matched: false`) until the opening tag is encountered at or after this `position`. - * The internal logic (`this.pointer > this.position || this.isCurrentlyMatched || this.tagDepth > 0`) means matching for the tag itself can start if: - * The current character pointer is past the specified `position`. - * Or, if the matcher is already inside a matched tag (`this.isCurrentlyMatched` is true, e.g., for nested tags of the same name or handling content after the initial match). - * Or, if `tagDepth > 0` (meaning it's already inside one or more instances of the target tag). This handles nested tags of the same name correctly, ensuring only the outermost pair defines the matched content block. - -## Key Methods - -1. **`update(chunk: string): Result[]`** - * **Purpose:** Processes an incoming chunk of text incrementally. This is useful if you are receiving text in a stream. - * **Process:** - * It iterates through the input `chunk` character by character, maintaining an internal state (e.g., `S_TEXT`, `S_TAG_OPEN`, `S_TAG_NAME`, `S_TAG_CLOSING_SLASH`, `S_IGNORE_UNTIL_GT`). - * When it encounters `<`, it transitions to a state expecting a tag name or a closing slash, but only if the `position` condition (or already being matched) is met. - * If it matches the opening tag (e.g., `<think>`), it transitions `isCurrentlyMatched` to `true`, increments `tagDepth`, and starts collecting subsequent characters as `matched: true` data. - * If it encounters another opening tag (even a nested one of the same name), it increments `tagDepth`. - * If it matches the corresponding closing tag (e.g., `</think>`), it decrements `tagDepth`. Only when `tagDepth` returns to `0` does `isCurrentlyMatched` become `false`. - * Characters outside the specified tags, or within other tags, are collected as `matched: false` data. - * It accumulates characters in an internal buffer (`cachedBuffer`). When the state changes (e.g., from text to tag, or tag to text, or at the end of a chunk), it flushes this buffer into an `XmlMatcherChunk` and adds it to an internal list (`currentChunks`). - * **Return Value:** Returns an array of `Result` objects (which are `XmlMatcherChunk`s if no `transform` function was provided). This array contains all the fully formed chunks identified *within the current `update` call*. It's possible that a tag might span multiple `update` calls, in which case the complete matched content will be spread across chunks returned by different `update` calls. - -2. **`final(chunk?: string): Result[]`** - * **Purpose:** Finalizes the processing, flushing any remaining buffered text. This should be called when you know there's no more input text. - * **Parameters:** - * `chunk?: string` (Optional): An optional final text chunk to process before finalizing. - * **Process:** - 1. If a `chunk` is provided, it calls `this.update(chunk)` to process it. - 2. It then collects any data remaining in its internal `cachedBuffer` (this would be text that didn't end with a state change, typically the last segment of text). - 3. Flushes all accumulated `currentChunks`. - * **Return Value:** Returns an array of `Result` objects representing all segments identified since the last flush or from the beginning if `update` wasn't called in a way that flushed everything. - -## How It's Used (Example: `OutputParser`) - -The `OutputParser` in ART uses `XmlMatcher` to extract content from `<think>...</think>` tags in the LLM's planning output: - -```typescript -// Simplified from OutputParser.ts -// import { XmlMatcher, XmlMatcherChunk } from 'art-framework'; // Path from art-framework/utils - -// async parsePlanningOutput(output: string): Promise<...> { -// const thoughtsList: string[] = []; -// let nonThinkingContent = ""; - -// const xmlMatcher = new XmlMatcher('think'); // Match the <think> tag -// const chunks: XmlMatcherChunk[] = xmlMatcher.final(output); // Process the entire output string at once - -// chunks.forEach(chunk => { -// if (chunk.matched) { // Content was inside <think>...</think> -// thoughtsList.push(chunk.data.trim()); -// } else { // Content was outside -// nonThinkingContent += chunk.data; -// } -// }); - -// const result = { thoughts: thoughtsList.join("\n\n---\n\n") }; - -// // ... then parse Intent, Plan, Tool Calls from nonThinkingContent ... -// return result; -// } -``` - -In this usage: -* `xmlMatcher.final(output)` processes the entire LLM output string in one go. -* It iterates through the returned `XmlMatcherChunk[]`. -* If `chunk.matched` is `true`, `chunk.data` is considered part of the LLM's "thoughts." -* If `chunk.matched` is `false`, `chunk.data` is part of the regular output to be parsed for Intent, Plan, etc. - -## When to Use `XmlMatcher` - -Developers might use `XmlMatcher` directly if: - -* They are creating custom output parsers for LLM responses that use XML-like tags other than `<think>` to demarcate specific sections. -* They are processing text streams that contain embedded XML-like structures and need to differentiate between the tagged content and the surrounding text. -* They need to handle potentially malformed or non-standard XML where a full XML parser might be too strict or overkill. - -The `XmlMatcher` provides a relatively lightweight and flexible way to handle simple XML tag extraction from text. \ No newline at end of file diff --git a/Docs/core-concepts/agent-creation-and-config.md b/Docs/core-concepts/agent-creation-and-config.md deleted file mode 100644 index 3e7a824..0000000 --- a/Docs/core-concepts/agent-creation-and-config.md +++ /dev/null @@ -1,184 +0,0 @@ -# Agent Creation and Configuration: `createArtInstance` & `ArtInstanceConfig` - -The primary way to get started with the ART Framework and create a functional agent instance is by using the `createArtInstance` function. This function handles the complex process of initializing and wiring together all the necessary framework components based on a central configuration object: `ArtInstanceConfig`. - -## `createArtInstance(config: ArtInstanceConfig)` - -Found in `src/core/agent-factory.ts` (and exported from `art-framework`), `createArtInstance` is your main entry point. - -* **Purpose:** To simplify the setup of a complete ART environment. It instantiates an `AgentFactory` internally, which then initializes all required systems (storage, context managers, reasoning engine, tool systems, UI sockets, etc.) according to the provided configuration. Finally, it creates and returns an `ArtInstance` object. -* **`ArtInstance` Object:** This returned object provides: - * `process(props: AgentProps): Promise<AgentFinalResponse>`: The main method to interact with the configured agent. - * Access to key managers and systems like `uiSystem`, `stateManager`, `conversationManager`, `toolRegistry`, and `observationManager`, allowing for more direct interaction if needed (e.g., subscribing to UI sockets, managing tools). - -**Basic Usage:** - -```typescript -import { createArtInstance, ArtInstanceConfig, AgentProps /* ... other imports */ } from 'art-framework'; - -// 1. Define your configuration (see ArtInstanceConfig details below) -const myArtConfig: ArtInstanceConfig = { - storage: { type: 'memory' }, - providers: { /* ... provider manager config ... */ }, - // ... other config options -}; - -async function main() { - try { - // 2. Create and initialize the ART instance - const art = await createArtInstance(myArtConfig); - - // 3. Prepare AgentProps for an interaction - const agentProps: AgentProps = { - query: "Hello, agent!", - threadId: "user123-conv456", - options: { - providerConfig: { /* ... runtime provider config ... */ } - } - }; - - // 4. Process the query - const finalResponse = await art.process(agentProps); - console.log("Agent says:", finalResponse.response.content); - - } catch (error) { - console.error("Error setting up or running ART:", error); - } -} - -main(); -``` - -## `ArtInstanceConfig` - -The `ArtInstanceConfig` interface (defined in `src/types/index.ts`) is the cornerstone of configuring your ART setup. It's a single object that specifies how all the different parts of the framework should be initialized. - -**Key Properties of `ArtInstanceConfig`:** - -1. **`storage: StorageAdapter | { type: 'memory' | 'indexedDB', ... }`** (Required) - * Determines how conversation history, agent state, and observations are stored. - * You can either provide a pre-configured `StorageAdapter` instance directly. - * Or, provide an object specifying the `type` of built-in adapter and its options: - * `{ type: 'memory' }`: Uses `InMemoryStorageAdapter` (data lost when process ends). - * `{ type: 'indexedDB', dbName?: string, version?: number, objectStores?: any[] }`: Uses `IndexedDBStorageAdapter` for persistent browser storage. - * `dbName`: Name of the IndexedDB database (defaults to `ART_Framework_DB`). - * `version`: Database version for schema migrations (defaults to `1`). - * `objectStores`: Array of object store names (defaults include `conversations`, `observations`, `state`). - - ```typescript - // Example storage configurations: - const memoryStorage = { type: 'memory' }; - const persistentStorage = { type: 'indexedDB', dbName: 'MyAgentData_v2', version: 2 }; - ``` - -2. **`providers: ProviderManagerConfig`** (Required) - * Configures the `ProviderManager`, which handles access to LLM providers. - * See [Provider Management](provider-management.md) and `src/types/providers.ts` for details on `ProviderManagerConfig`. - * Includes `availableProviders` (array defining each LLM adapter like `OpenAIAdapter`, `AnthropicAdapter`, their names, and if they are local), `maxParallelApiInstancesPerProvider`, and `apiInstanceIdleTimeoutSeconds`. - - ```typescript - // Example providers configuration: - // import { OpenAIAdapter, OllamaAdapter } from 'art-framework'; - const providersConfig = { - availableProviders: [ - { name: 'openai-chat', adapter: OpenAIAdapter, isLocal: false }, - { name: 'ollama-local', adapter: OllamaAdapter, isLocal: true } - ], - maxParallelApiInstancesPerProvider: 2, - apiInstanceIdleTimeoutSeconds: 120 - }; - ``` - -3. **`agentCore?: new (dependencies: any) => IAgentCore`** (Optional) - * Specifies the agent core implementation class to use. - * If omitted, it defaults to `PESAgent`. - * Useful if you create a custom agent class implementing the `IAgentCore` interface. - - ```typescript - // import { MyCustomAgent } from './my-custom-agent'; - // const agentCoreConfig = { agentCore: MyCustomAgent }; - ``` - -4. **`tools?: IToolExecutor[]`** (Optional) - * An array of pre-instantiated tool executor objects (classes implementing `IToolExecutor`). - * These tools will be automatically registered with the `ToolRegistry` during initialization. - - ```typescript - // import { CalculatorTool, MyCustomSearchTool } from 'art-framework'; // or from your project - // const toolsConfig = { tools: [new CalculatorTool(), new MyCustomSearchTool()] }; - ``` - -5. **`stateSavingStrategy?: StateSavingStrategy`** (Optional) - * Determines how `AgentState` is persisted. Can be `'explicit'` (default) or `'implicit'`. - * `'explicit'`: Agent state is only saved when `StateManager.setAgentState()` is explicitly called. `StateManager.saveStateIfModified()` will be a no-op for agent state. - * `'implicit'`: `StateManager.loadThreadContext()` caches the loaded agent state. If the agent modifies this state, `StateManager.saveStateIfModified()` (called by `PESAgent` at the end of `process`) will automatically persist the changes by comparing it to the initial snapshot. `setAgentState()` still works for explicit saves. - * See [State Management](./state-management.md) for more details. - - ```typescript - const stateStrategyConfig = { stateSavingStrategy: 'implicit' }; - ``` - -6. **`logger?: { level?: LogLevel }`** (Optional) - * Configures the framework's internal `Logger`. - * `level`: Sets the minimum log level (e.g., `LogLevel.DEBUG`, `LogLevel.INFO`, `LogLevel.WARN`, `LogLevel.ERROR`). Defaults to `LogLevel.INFO`. - - ```typescript - // import { LogLevel } from 'art-framework'; - const loggerConfig = { logger: { level: LogLevel.DEBUG } }; - ``` - -**Complete `ArtInstanceConfig` Example:** - -```typescript -import { - ArtInstanceConfig, - OpenAIAdapter, - CalculatorTool, - LogLevel -} from 'art-framework'; - -const fullConfig: ArtInstanceConfig = { - storage: { - type: 'indexedDB', - dbName: 'MyFullAgentDB', - version: 1 - }, - providers: { - availableProviders: [ - { - name: 'openai-main-model', - adapter: OpenAIAdapter, - isLocal: false, - } - ], - maxParallelApiInstancesPerProvider: 5, - apiInstanceIdleTimeoutSeconds: 300, - }, - tools: [ - new CalculatorTool() - ], - // agentCore: MyCustomAgent, // Defaults to PESAgent - stateSavingStrategy: 'implicit', - logger: { - level: LogLevel.INFO, - } -}; -``` - -## The `AgentFactory` (Internal Mechanism) - -While `createArtInstance` is the recommended public API, it internally uses the `AgentFactory` class (`src/core/agent-factory.ts`). - -* **Role:** The `AgentFactory` is responsible for the detailed process of: - 1. Receiving the `ArtInstanceConfig`. - 2. Initializing the correct `StorageAdapter`. - 3. Instantiating all repositories (`ConversationRepository`, `ObservationRepository`, `StateRepository`) with the storage adapter. - 4. Setting up the `UISystem` and its associated sockets. - 5. Instantiating all managers (`ConversationManager`, `StateManager`, `ObservationManager`) with their dependencies (repositories, sockets, strategy). - 6. Initializing the `ToolRegistry` (and `StateManager` if provided) and registering any initial tools. - 7. Initializing the `ProviderManager` with the `providers` configuration. - 8. Setting up reasoning components (`ReasoningEngine`, `PromptManager`, `OutputParser`). - 9. Initializing the `ToolSystem`. - 10. Finally, creating an instance of the specified `IAgentCore` (e.g., `PESAgent`) and injecting all the initialized components as dependencies. - -Developers typically don't need to interact with `AgentFactory` directly unless they are doing very advanced framework customization or embedding ART in a unique way. `createArtInstance` provides a simpler and more stable interface. \ No newline at end of file diff --git a/Docs/core-concepts/agents.md b/Docs/core-concepts/agents.md deleted file mode 100644 index 0c980e6..0000000 --- a/Docs/core-concepts/agents.md +++ /dev/null @@ -1,92 +0,0 @@ -# Agents in ART - -In the ART Framework, an **Agent** is the core component responsible for orchestrating the entire process of receiving input, reasoning, potentially using tools, and generating a response. It embodies the "brain" of your AI application. - -## The `IAgentCore` Interface - -All agent implementations in ART adhere to the `IAgentCore` interface (defined in `src/core/interfaces.ts`). This interface is simple but powerful: - -```typescript -export interface IAgentCore { - process(props: AgentProps): Promise<AgentFinalResponse>; -} -``` - -* **`process(props: AgentProps): Promise<AgentFinalResponse>`:** - * This is the main entry point for interacting with an agent. - * `AgentProps`: An object containing the necessary input for the agent, such as: - * `query`: The user's input or question. - * `threadId`: A unique identifier for the current conversation thread. - * `userId` (optional): Identifier for the user. - * `traceId` (optional): For tracing requests across systems. - * `options` (optional): Runtime overrides, including `providerConfig` to select the LLM for this call. - * `AgentFinalResponse`: A promise that resolves to an object containing: - * `response`: The final `ConversationMessage` generated by the AI. - * `metadata`: An `ExecutionMetadata` object summarizing the agent's execution cycle (duration, LLM calls, tool calls, status, errors). - -## `PESAgent`: Plan-Execute-Synthesize - -ART provides a default agent implementation called `PESAgent` (`src/core/agents/pes-agent.ts`). "PES" stands for **Plan-Execute-Synthesize**, which describes its three-stage operational flow: - -1. **Plan:** - * **Goal:** Understand the user's query and the conversational context. Formulate an intent and a step-by-step plan to address the query. This plan might involve deciding to use one or more available tools. - * **Process:** - * Loads current `ThreadContext` (config & state) via `StateManager` and conversation `history` via `ConversationManager`. - * Constructs a planning prompt (`ArtStandardPrompt`) including the system prompt, history, user query, and a description of available tools. - * Calls the `ReasoningEngine` with this prompt (requesting a streaming response). - * Consumes the `StreamEvent`s from the LLM. The accumulated text output from this planning call is then parsed by the `OutputParser`. - * The `OutputParser` extracts the `intent`, `plan` description, and any `ParsedToolCall`s (requests to use tools). - * Observations like `INTENT`, `PLAN`, and `TOOL_CALL` are recorded. - -2. **Execute:** - * **Goal:** If the planning phase identified any tools to be used, this stage executes them. - * **Process:** - * The `ParsedToolCall`s are passed to the `ToolSystem`. - * The `ToolSystem` verifies if each tool is enabled (via `StateManager`), retrieves the tool's executor from the `ToolRegistry`, validates the arguments against the tool's `ToolSchema`, and then calls the tool's `execute` method. - * The `ToolResult` (success or error) for each tool call is collected. - * `TOOL_EXECUTION` observations are recorded by the `ToolSystem`. - -3. **Synthesize:** - * **Goal:** Generate a final, coherent, user-facing response based on the original query, the plan, and the results from any executed tools. - * **Process:** - * Constructs a synthesis prompt (`ArtStandardPrompt`). This prompt includes the system prompt, history, original query, the generated plan, and the `ToolResult`s. - * Calls the `ReasoningEngine` with this synthesis prompt (requesting a streaming response). - * Consumes the `StreamEvent`s. The accumulated text from `TOKEN` events (specifically those with `tokenType` indicating final synthesis) forms the final AI response. - * `SYNTHESIS` observations are recorded. - -**Lifecycle and Dependencies:** - -The `PESAgent` (and any `IAgentCore` implementation) is instantiated by the `AgentFactory` (used internally by `createArtInstance`). The factory injects all necessary dependencies: - -* `StateManager` -* `ConversationManager` -* `ToolRegistry` -* `ReasoningEngine` -* `OutputParser` -* `ObservationManager` -* `ToolSystem` -* `UISystem` - -This dependency injection allows the agent to focus on its orchestration logic without being tightly coupled to the concrete implementations of these underlying systems. - -## Agent Lifecycle (Conceptual) - -1. **Initialization (`createArtInstance`):** - * The application provides an `ArtInstanceConfig`. - * `AgentFactory` initializes all systems (storage, managers, engines, registries) based on this config. - * An instance of the configured `IAgentCore` (e.g., `PESAgent`) is created and wired with these initialized systems. - * An `ArtInstance` object is returned, providing the `process` method. - -2. **Processing a Query (`artInstance.process(props)`):** - * The application calls `artInstance.process()` with `AgentProps`. - * The `IAgentCore` (e.g., `PESAgent`) executes its defined flow (like Plan-Execute-Synthesize). - * Throughout the process, interactions with LLMs, tools, and context management occur. - * Observations are recorded. - * UI sockets are notified of events (new messages, LLM stream tokens, observations). - * The agent returns an `AgentFinalResponse`. - -3. **State & History Persistence:** - * `ConversationManager` saves new messages to the configured `StorageAdapter`. - * `StateManager` saves `AgentState` based on the `StateSavingStrategy` (either explicitly via `setAgentState` or implicitly via `saveStateIfModified` if changes are detected after `loadThreadContext`). - -ART's agent architecture provides a structured yet flexible way to build sophisticated AI applications. While `PESAgent` is the default, developers can implement custom `IAgentCore` to realize different reasoning patterns or agent behaviors. \ No newline at end of file diff --git a/Docs/core-concepts/architecture-overview.md b/Docs/core-concepts/architecture-overview.md deleted file mode 100644 index 53e3090..0000000 --- a/Docs/core-concepts/architecture-overview.md +++ /dev/null @@ -1,290 +0,0 @@ -# Architecture Overview![[architecture-overview.excalidraw]] - -The ART (Agent-Reasoning-Tooling) Framework is designed with a modular architecture to promote separation of concerns, extensibility, and maintainability. Understanding how these components fit together is key to effectively using and customizing ART. - -```mermaid -flowchart TD - -%% Main Components - -User([User Input/External Triggers]) --> ArtInstance["ArtInstance\n(process method)"] - -%% Agent Core as the central orchestrator - -ArtInstance --> AgentCore["Agent Core (IAgentCore)\n(Swappable Component)\n(e.g., PESAgent)"] - -%% Major Subsystems - -subgraph ReasoningSystem ["Reasoning System"] - -ReasoningEngine["ReasoningEngine"] - -ProviderManager["ProviderManager"] - -ProviderAdapters["ProviderAdapters\n(OpenAI, Anthropic, Ollama)"] - -PromptManager["PromptManager\n(fragments/validation)"] - -OutputParser["OutputParser"] - -ExternalLLM["External LLM APIs"] - -ReasoningEngine --> ProviderManager - -ProviderManager --> ProviderAdapters - -ProviderAdapters <--> ExternalLLM - -PromptManager -.-> ReasoningEngine - -ReasoningEngine -.-> OutputParser - -end - -subgraph ToolSystem ["Tool System"] - -ToolSystemMain["ToolSystem"] - -ToolRegistry["ToolRegistry"] - -ToolExecutor["IToolExecutor\n(specific tools)"] - -ToolSystemMain --> ToolRegistry - -ToolSystemMain --> ToolExecutor - -end - -subgraph ContextSystem ["Context System"] - -StateManager["StateManager\n(ThreadConfig, AgentState)"] - -ConversationManager["ConversationManager\n(message history)"] - -ContextProvider["ContextProvider\n(future: RAG)"] - -StateRepository["StateRepository"] - -ConversationRepository["ConversationRepository"] - -StateManager --> StateRepository - -ConversationManager --> ConversationRepository - -ContextProvider -.-> AgentCore - -end - -subgraph ObservationSystem ["Observation System"] - -ObservationManager["ObservationManager"] - -ObservationRepository["ObservationRepository"] - -ObservationManager --> ObservationRepository - -end - -subgraph StorageSystem ["Storage System"] - -StorageAdapter["StorageAdapter\n(InMemory, IndexedDB, etc.)"] - -StateRepository --> StorageAdapter - -ConversationRepository --> StorageAdapter - -ObservationRepository --> StorageAdapter - -end - -subgraph UISystem ["UI System"] - -UISystemMain["UISystem"] - -LLMStreamSocket["LLMStreamSocket"] - -ObservationSocket["ObservationSocket"] - -ConversationSocket["ConversationSocket"] - -ExternalUI["External UI/Subscribers"] - -UISystemMain --> LLMStreamSocket - -UISystemMain --> ObservationSocket - -UISystemMain --> ConversationSocket - -LLMStreamSocket --> ExternalUI - -ObservationSocket --> ExternalUI - -ConversationSocket --> ExternalUI - -end - -%% Connections between Agent Core and Subsystems - -AgentCore --> ReasoningEngine - -AgentCore --> ToolSystemMain - -AgentCore --> StateManager - -AgentCore --> ConversationManager - -%% Cross-system connections - -ReasoningEngine --> LLMStreamSocket - -ToolSystemMain --> ObservationManager - -ToolSystemMain <--> StateManager - -ObservationManager --> ObservationSocket - -ConversationManager --> ConversationSocket - -AgentCore --> ObservationManager - -%% Key Data Flow Items - -ArtStandardPrompt["ArtStandardPrompt"] -.-> ReasoningEngine - -StreamEvent["StreamEvent"] -.-> LLMStreamSocket - -ToolResult["ToolResult"] -.-> AgentCore - -Observation["Observation"] -.-> ObservationManager - -ConversationMessage["ConversationMessage"] -.-> ConversationManager - -%% Configuration - -ArtInstanceConfig["ArtInstanceConfig"] -.-> ArtInstance - -%% Style - -classDef system fill:#f9f9f9,stroke:#999,stroke-width:1px - -classDef core fill:#ffebcd,stroke:#ff8c00,stroke-width:2px - -classDef component fill:#e6f7ff,stroke:#1890ff,stroke-width:1px - -classDef external fill:#f0f0f0,stroke:#d9d9d9,stroke-width:1px - -classDef dataitem fill:#f6ffed,stroke:#52c41a,stroke-width:1px,stroke-dasharray: 5 5 - -class ReasoningSystem,ToolSystem,ContextSystem,ObservationSystem,StorageSystem,UISystem system - -class AgentCore core - -class ReasoningEngine,ProviderManager,ProviderAdapters,PromptManager,OutputParser,ToolSystemMain,ToolRegistry,ToolExecutor,StateManager,ConversationManager,ContextProvider,ObservationManager,UISystemMain,LLMStreamSocket,ObservationSocket,ConversationSocket,StateRepository,ConversationRepository,ObservationRepository,StorageAdapter component - -class User,ExternalLLM,ExternalUI external - -class ArtStandardPrompt,StreamEvent,ToolResult,Observation,ConversationMessage,ArtInstanceConfig dataitem -``` -<!-- - Placeholder for Detailed Architecture Diagram. - This diagram should visually represent: - 1. **User Input/External Triggers** feeding into the system. - 2. The **`ArtInstance`** as the primary entry point (`process` method). - 3. The central **Agent Core (`IAgentCore`)** (e.g., `PESAgent` or a custom implementation) as the main orchestrator. Highlight that this component is swappable. - 4. Arrows showing the Agent Core interacting with the major subsystems: - * **Reasoning System:** - * Agent Core -> `ReasoningEngine` - * `ReasoningEngine` -> `ProviderManager` - * `ProviderManager` -> (selects/manages) -> `ProviderAdapter` (multiple, e.g., OpenAI, Anthropic, Ollama) - * `ProviderAdapter` <-> External LLM API - * Agent Core also uses `PromptManager` (for fragments/validation) and `OutputParser`. - * **Tool System:** - * Agent Core -> `ToolSystem` - * `ToolSystem` -> `ToolRegistry` - * `ToolSystem` -> `IToolExecutor` (specific tool) - * `ToolSystem` also interacts with `StateManager` (for tool enablement) and `ObservationManager` (to record tool execution). - * **Context System:** - * Agent Core -> `StateManager` (for `ThreadConfig`, `AgentState`) - * Agent Core -> `ConversationManager` (for message history) - * Managers -> Respective Repositories (`StateRepository`, `ConversationRepository`) - * (Future: Agent Core -> `ContextProvider` for RAG) - * **Observation System:** - * Various components (Agent Core, `ToolSystem`, etc.) -> `ObservationManager` - * `ObservationManager` -> `ObservationRepository` - * **Storage System:** - * All Repositories (`StateRepository`, `ConversationRepository`, `ObservationRepository`) -> `StorageAdapter` (e.g., `InMemoryStorageAdapter`, `IndexedDBStorageAdapter`) - * **UI System:** - * `ReasoningEngine` (via Agent Core), `ObservationManager`, `ConversationManager` -> `UISystem` (which provides specific sockets like `LLMStreamSocket`, `ObservationSocket`, `ConversationSocket`) - * Sockets -> External UI/Subscribers - 5. Show data flow for key items like `ArtStandardPrompt`, `StreamEvent`, `ToolResult`, `Observation`, `ConversationMessage`. ---> - -## Core Subsystems and Their Roles - -The ART framework is organized into several distinct subsystems, each with a clear responsibility: - -1. **Agent Core (`IAgentCore`):** - * **Role:** The central brain and orchestrator of the agent. It defines the high-level logic for processing user queries and coordinating other systems. - * **Key Feature:** This component is **swappable**. While ART provides `PESAgent` (Plan-Execute-Synthesize) as a default, developers can implement the `IAgentCore` interface to create entirely different agent behaviors (e.g., ReAct, custom task-specific flows) without altering the underlying framework functionalities. This is configured via `ArtInstanceConfig.agentCore`. - * **Interaction:** Receives user input, drives the reasoning process, decides when to use tools, manages the flow of information, and produces the final response. - -2. **Reasoning System:** - * **Role:** Handles all aspects of interaction with Large Language Models (LLMs). - * **Components:** - * `ReasoningEngine`: The primary interface for making calls to an LLM. - * `ProviderManager`: Manages a collection of `ProviderAdapter`s, enabling dynamic selection of LLM providers and models at runtime. It handles adapter instantiation, caching, and lifecycle. - * `ProviderAdapter`s (e.g., `OpenAIAdapter`, `AnthropicAdapter`, `OllamaAdapter`): Translate ART's standard `ArtStandardPrompt` into provider-specific API requests and convert responses back into `StreamEvent`s. - * `PromptManager`: Provides utility for retrieving pre-defined prompt fragments and validating `ArtStandardPrompt` objects. - * `OutputParser`: Interprets raw LLM responses, extracting structured data like intent, plans, tool call requests, and `<think>` tag content. - * **Interaction:** The Agent Core constructs an `ArtStandardPrompt` and uses the `ReasoningEngine` (which leverages the `ProviderManager` and a specific `ProviderAdapter`) to get a response from an LLM. - -3. **Tool System:** - * **Role:** Enables the agent to use external capabilities or "tools." - * **Components:** - * `ToolRegistry`: A catalog of available `IToolExecutor` instances. - * `ToolSystem`: Orchestrates tool execution, including validating inputs against `ToolSchema`, invoking the tool, and handling results. - * `IToolExecutor`: The interface that custom tools implement, defining their `schema` (for LLM understanding and input validation) and `execute` logic. - * **Interaction:** If the Reasoning System's output (parsed by `OutputParser`) indicates a tool should be used, the Agent Core directs the `ToolSystem` to execute it. Results are then fed back into the agent's context. - -4. **Context System:** - * **Role:** Manages all contextual information necessary for the agent's operation within a conversation thread. - * **Components:** - * `StateManager`: Handles loading, saving, and providing access to `ThreadConfig` (e.g., enabled tools, default LLM settings for the thread) and `AgentState` (persistent agent-specific data). - * `ConversationManager`: Manages the history of `ConversationMessage`s for a thread. - * `ContextProvider` (Placeholder for future RAG): Intended to inject dynamically retrieved information into prompts. - * Repositories (`StateRepository`, `ConversationRepository`, `ObservationRepository`): These components act as a bridge between the managers and the `StorageAdapter`, specializing in how specific data types are stored and retrieved. - * **Interaction:** The Agent Core constantly interacts with `StateManager` and `ConversationManager` to fetch context for prompts and to save new messages and state changes. - -5. **Observation System:** - * **Role:** Provides observability into the agent's internal workings by recording significant events. - * **Components:** - * `ObservationManager`: The service used by other systems to record `Observation` objects (e.g., `INTENT`, `PLAN`, `TOOL_CALL`, `TOOL_EXECUTION`, `ERROR`, `LLM_STREAM_START`). - * `ObservationRepository`: Persists these observations via a `StorageAdapter`. - * **Interaction:** Various components (Agent Core, `ToolSystem`) call `ObservationManager.record()` to log events. These observations are crucial for debugging, monitoring, and can be broadcast to UIs. - -6. **Storage System:** - * **Role:** Provides a generic persistence layer for all framework data. - * **Components:** - * `StorageAdapter` (Interface): Defines methods like `get`, `set`, `delete`, `query`. - * Concrete Adapters (`InMemoryStorageAdapter`, `IndexedDBStorageAdapter`, custom adapters): Implement the `StorageAdapter` interface for specific storage backends. - * **Interaction:** All Repositories (`StateRepository`, `ConversationRepository`, `ObservationRepository`) use a configured `StorageAdapter` instance to save and retrieve their respective data types. - -7. **UI System:** - * **Role:** Facilitates real-time communication from the agent's backend to user interfaces or other subscribed services. - * **Components:** - * `UISystem`: A central service that instantiates and provides access to various `TypedSocket`s. - * Specialized Sockets (`ConversationSocket`, `ObservationSocket`, `LLMStreamSocket`): Extend `TypedSocket` to broadcast specific data types (`ConversationMessage`s, `Observation`s, `StreamEvent`s). - * **Interaction:** Core components like the `AgentCore` (for LLM streams), `ObservationManager`, and `ConversationManager` use these sockets (obtained from `UISystem`) to `notify` subscribers of updates. - -## Configuration: `ArtInstanceConfig` - -The entire framework is initialized and wired together based on the `ArtInstanceConfig` object passed to the `createArtInstance` function. This single configuration object dictates: - -* The choice of `StorageAdapter`. -* The setup of the `ProviderManager` (defining all available LLM providers). -* The `IAgentCore` implementation to use (e.g., `PESAgent` or a custom one). -* Initial tools to be registered. -* The `StateSavingStrategy`. -* Logger settings. - -This modular, interface-driven architecture makes ART highly flexible and extensible, allowing developers to tailor it to a wide range of AI agent applications. The ability to swap out the core orchestration logic (`IAgentCore`) without rewriting other systems is a particularly powerful feature for advanced customization. \ No newline at end of file diff --git a/Docs/core-concepts/art-standard-prompt.md b/Docs/core-concepts/art-standard-prompt.md deleted file mode 100644 index 1bd9a2b..0000000 --- a/Docs/core-concepts/art-standard-prompt.md +++ /dev/null @@ -1,150 +0,0 @@ -# ArtStandardPrompt: The Universal LLM Input - -A core design principle of the ART Framework is to provide a standardized way to interact with various Large Language Models (LLMs). The `ArtStandardPrompt` and its constituent `ArtStandardMessage` objects serve as this universal format for constructing prompts that are then translated by specific `ProviderAdapter`s into the native format required by each LLM provider. - -## What are `ArtStandardPrompt` and `ArtStandardMessage`? - -You can find their definitions in `src/types/index.ts`. - -* **`ArtStandardMessageRole`**: An enum defining the possible roles a message can have: - * `system`: Instructions or context for the AI, typically at the start. - * `user`: Input from the end-user or, in some cases (like Gemini with tool results), a wrapper for tool responses. - * `assistant`: Responses generated by the AI. Can include text and/or `tool_calls`. - * `tool_request`: (Less common for direct use) Represents the LLM's intent to use a tool, often implicitly part of an `assistant` message containing `tool_calls`. - * `tool_result` (or `tool`): The outcome (output or error) from a tool's execution. This is often translated to a `user` or `tool` role by adapters depending on the provider. - -* **`ArtStandardMessage`**: An interface representing a single message within the prompt. - ```typescript - export interface ArtStandardMessage { - role: ArtStandardMessageRole; - content: string | object | null; // Type depends on role - name?: string; // For tool_result, the tool name - tool_calls?: Array<{ /* ... */ }>; // For assistant role - tool_call_id?: string; // For tool_result role - } - ``` - * `role`: One of the `ArtStandardMessageRole` values. - * `content`: - * For `system` and `user`: A `string` containing the instruction or query. - * For `assistant`: A `string` (the AI's text response) or `null` (if the assistant is only making `tool_calls`). - * For `tool_result` (or `tool`): A `string` representing the stringified JSON output or error message from the tool. - * For `tool_request`: An `object` or `null`. - * `name`: (Optional) Primarily used with `tool_result` to indicate the name of the tool that was executed. - * `tool_calls`: (Optional) An array of objects detailing tools the `assistant` wants to call. Each object includes: - * `id`: A unique ID for the tool call request. - * `type`: Typically `"function"`. - * `function`: An object with: - * `name`: The name of the tool/function. - * `arguments`: A **stringified JSON object** of arguments for the tool. - * `tool_call_id`: (Optional) Used in `tool_result` messages to link the result back to the specific `id` in the `assistant`'s `tool_calls`. - -* **`ArtStandardPrompt`**: This is simply an array of `ArtStandardMessage` objects, representing the complete, ordered sequence of messages to be sent to the LLM. - ```typescript - export type ArtStandardPrompt = ArtStandardMessage[]; - ``` - -## Why This Standard Format? - -1. **Provider Agnosticism:** Different LLM providers (OpenAI, Anthropic, Google Gemini, etc.) have their own unique API structures for sending prompts. `ArtStandardPrompt` acts as an intermediary abstraction. Agent logic (like `PESAgent`) constructs prompts in this standard format. Then, the selected `ProviderAdapter` (e.g., `OpenAIAdapter`, `AnthropicAdapter`) translates this standard prompt into the specific format required by its target LLM API. -2. **Simplified Agent Logic:** Agent developers can focus on the *content* and *sequence* of interactions (system instructions, user queries, AI responses, tool interactions) without worrying about the low-level formatting details of each LLM provider. -3. **Consistency:** Ensures a consistent way of representing conversational turns and tool interactions within the ART framework. - -## How `PESAgent` Constructs `ArtStandardPrompt` - -The `PESAgent` (Plan-Execute-Synthesize Agent) is responsible for constructing `ArtStandardPrompt` objects during its planning and synthesis phases. It does this directly by creating JavaScript arrays of `ArtStandardMessage` objects. - -**Example: Planning Phase in `PESAgent` (Conceptual)** - -```typescript -// Inside PESAgent.process() during planning: - -// 1. Get system prompt (Conceptual - actual logic is more detailed) -// The PESAgent resolves the system prompt using a hierarchy: -// Call-level (props.options.systemPrompt) > Thread-level (ThreadConfig.systemPrompt) > -// Instance-level (ArtInstanceConfig.defaultSystemPrompt) > Agent's base prompt. -// The resolved custom part is appended to the agent's base prompt. -// Let's assume 'finalResolvedSystemPrompt' holds this combined string. -const finalResolvedSystemPrompt = "/* Resolved system prompt based on hierarchy */"; // Placeholder for conceptual example -const systemPromptContent = finalResolvedSystemPrompt; - -// 2. Get formatted history -const formattedHistory = this.formatHistoryForPrompt(rawHistory); // Converts ConversationMessage[] - -// 3. Get available tools and format them for the prompt -const toolsDescription = availableTools.map(tool => - `- ${tool.name}: ${tool.description}\n Input Schema: ${JSON.stringify(tool.inputSchema)}` -).join('\n'); - -// 4. Construct the planning prompt -const planningPrompt: ArtStandardPrompt = [ - { role: 'system', content: systemPromptContent }, - ...formattedHistory, - { - role: 'user', - content: `User Query: ${props.query}\n\nAvailable Tools:\n${toolsDescription}\n\nBased on the user query and conversation history, identify the user's intent and create a plan... Respond in the following format:\nIntent: ...\nPlan: ...\nTool Calls: ...` - } -]; - -// 5. Validate (optional, but good practice if PromptManager is used) -// this.deps.promptManager.validatePrompt(planningPrompt); - -// 6. Send to ReasoningEngine -// const planningStream = await this.deps.reasoningEngine.call(planningPrompt, planningOptions); -``` -*(See `src/core/agents/pes-agent.ts` for the actual implementation details.)* - -The `PESAgent` follows a similar process for constructing the `synthesisPrompt`, incorporating the results of tool executions into the prompt context. - -## Example of a Complete `ArtStandardPrompt` (with Tool Use) - -This example shows what an `ArtStandardPrompt` might look like when an agent is about to synthesize a response after using a tool: - -```json -[ - { - "role": "system", - "content": "You are a helpful weather assistant." - }, - { - "role": "user", - "content": "What's the weather like in London?" - }, - { - "role": "assistant", - "content": null, // Assistant decided to use a tool, no immediate text response - "tool_calls": [ - { - "id": "call_weather_london_123", - "type": "function", - "function": { - "name": "get_weather", - "arguments": "{\"location\":\"London, UK\"}" - } - } - ] - }, - { - "role": "tool_result", // Could also be 'tool' depending on internal representation before adapter translation - "tool_call_id": "call_weather_london_123", - "name": "get_weather", // Tool name often included for clarity or by some providers - "content": "{\"temperature\": \"15°C\", \"condition\": \"Partly Cloudy\"}" // Stringified JSON result - } - // The next message in the prompt for the LLM would likely be a user-role message (constructed by the agent) - // asking it to synthesize this information, or the agent might directly construct an assistant message - // with the synthesized response. - // For PESAgent, the synthesis prompt would include the above history and then a final user message like: - // { - // "role": "user", - // "content": "User Query: What's the weather like in London?\n\nOriginal Intent: Find weather in London.\nExecution Plan: Use get_weather tool.\n\nTool Execution Results:\n- Tool: get_weather (Call ID: call_weather_london_123)\n Status: success\n Output: {\"temperature\": \"15°C\", \"condition\": \"Partly Cloudy\"}\n\nBased on the user query, the plan, and the results of any tool executions, synthesize a final response to the user." - // } -] -``` - -## Role of `PromptManager` - -While agent logic (like `PESAgent`) is responsible for *assembling* the `ArtStandardPrompt` object, the `PromptManager` can assist by: - -1. **Providing Reusable Fragments:** Using `promptManager.getFragment("fragment_name")` to fetch common instructions or templates that can be embedded into the `content` of `ArtStandardMessage` objects. -2. **Validating Prompts:** Using `promptManager.validatePrompt(promptObject)` to ensure the constructed `ArtStandardPrompt` adheres to the expected schema (defined in `src/types/schemas.ts` using Zod). This helps catch structural errors early. - -By adhering to `ArtStandardPrompt`, ART framework components can communicate effectively, and developers can build more robust and adaptable AI agents. \ No newline at end of file diff --git a/Docs/core-concepts/context-and-conversation.md b/Docs/core-concepts/context-and-conversation.md deleted file mode 100644 index 644f3f5..0000000 --- a/Docs/core-concepts/context-and-conversation.md +++ /dev/null @@ -1,79 +0,0 @@ -# Context and Conversation Management - -In the ART Framework, managing the context of an interaction and the history of a conversation is fundamental to building intelligent agents. This is handled by the **Context System**, primarily through the `ConversationManager` and its underlying `ConversationRepository`. The `ContextProvider` is also part of this system, though its role is more geared towards future enhancements like Retrieval-Augmented Generation (RAG). - -## `ConversationManager` - -* **Source:** `src/systems/context/managers/ConversationManager.ts` -* **Interface:** `IConversationManager` from `src/core/interfaces.ts` - -The `ConversationManager` is responsible for: - -1. **Adding Messages:** Appending new `ConversationMessage` objects to a specific thread's history. -2. **Retrieving Messages:** Fetching past messages from a thread's history, with options for limiting the number of messages. -3. **UI Notification:** Notifying the `ConversationSocket` (obtained from `UISystem`) whenever new messages are added, allowing connected UIs to update in real-time. - -**Key Methods:** - -* **`async addMessages(threadId: string, messages: ConversationMessage[]): Promise<void>`:** - * Takes a `threadId` and an array of `ConversationMessage` objects. - * Delegates the actual storage of these messages to the `ConversationRepository`. - * After successfully adding messages to the repository, it iterates through the added messages and calls `conversationSocket.notify(message, { targetThreadId: threadId })` for each one. - * Performs basic validation (e.g., `threadId` cannot be empty, `messages` array should not be null/empty). - -* **`async getMessages(threadId: string, options?: MessageOptions): Promise<ConversationMessage[]>`:** - * Takes a `threadId` and optional `MessageOptions` (e.g., `limit`, `beforeTimestamp`, `afterTimestamp`). - * Delegates the retrieval to `ConversationRepository.getMessages()`. - * Returns the array of `ConversationMessage` objects fetched from the repository. - -The `PESAgent` uses `ConversationManager`: -* To fetch historical messages at the beginning of its `process` cycle to build context for the LLM. -* To add the new user query and the final AI response to the history at the end of the `process` cycle. - -## `ConversationRepository` - -* **Source:** `src/systems/context/repositories/ConversationRepository.ts` -* **Interface:** `IConversationRepository` from `src/core/interfaces.ts` - -The `ConversationRepository` is an abstraction layer over the chosen `StorageAdapter` (e.g., `InMemoryStorageAdapter` or `IndexedDBStorageAdapter`). It specializes in storing and retrieving `ConversationMessage` objects. - -**Key Responsibilities & Implementation Details:** - -* **Storage Collection:** It typically stores messages in a dedicated collection/object store within the `StorageAdapter` (e.g., named `"conversations"`). -* **Message ID as Key:** Each `ConversationMessage` has a `messageId`. The repository uses this `messageId` as the primary key when storing the message (e.g., by setting an `id` property on the stored object to `message.messageId` if the adapter uses `id` as `keyPath`). -* **`addMessages` Implementation:** - * Iterates through the provided messages. - * For each message, it calls `storageAdapter.set(collectionName, message.messageId, messageWithInternalId)`. -* **`getMessages` Implementation:** - * Calls `storageAdapter.query(collectionName, { filter: { threadId: threadId } })` to fetch all messages belonging to the specified thread. - * **Client-Side Sorting & Filtering:** After retrieving messages, it performs client-side sorting by `timestamp` (ascending by default to represent chronological order). It also applies any `beforeTimestamp`, `afterTimestamp`, and `limit` options from `MessageOptions` on the retrieved set. - * The `limit` option, when applied client-side after an ascending sort, effectively retrieves the *most recent* 'N' messages if the full history is first sorted chronologically. - * It ensures that the internal `id` field (used for storage keying) is removed from the messages before returning them, so they conform strictly to the `ConversationMessage` interface. - -## `ContextProvider` - -* **Source:** `src/systems/context/ContextProvider.ts` - -As noted in its source code comments, the `ContextProvider` in ART `v0.2.7` is primarily a **placeholder** for future capabilities, particularly for Retrieval-Augmented Generation (RAG). - -**Current (v0.2.7) Behavior:** - -* **`constructor()`:** Logs an informational message about its placeholder status. -* **`async getDynamicContext(_threadId: string, _query?: string): Promise<Record<string, any>>`:** - * This method is intended to fetch dynamic, relevant information from external sources (like vector databases, APIs, documents) based on the current query and conversation. - * In `v0.2.7`, it simply logs that it was called and returns an empty object (`Promise.resolve({})`). - -**Future Role (RAG):** - -In future versions, `ContextProvider` would be enhanced to: - -1. Analyze the user's query and potentially the recent conversation history. -2. Formulate queries to one or more configured knowledge sources (e.g., a vector store containing embeddings of your documents). -3. Retrieve relevant chunks of information from these sources. -4. Format this retrieved information into a string or structured data. -5. Return this dynamic context, which the Agent Core (e.g., `PESAgent`) would then inject into the LLM prompt, allowing the LLM to generate responses grounded in this external knowledge. - -**In Summary:** - -* `ConversationManager` and `ConversationRepository` are the workhorses for managing and persisting explicit conversation history. -* `ContextProvider` is currently a forward-looking component, laying the groundwork for more advanced dynamic context retrieval in future ART versions. For now, core context like history and thread configuration is handled directly by the agent via `ConversationManager` and `StateManager`. \ No newline at end of file diff --git a/Docs/core-concepts/error-handling.md b/Docs/core-concepts/error-handling.md deleted file mode 100644 index ff48138..0000000 --- a/Docs/core-concepts/error-handling.md +++ /dev/null @@ -1,127 +0,0 @@ -# Error Handling in ART - -Robust error handling is essential for building reliable AI agents. The ART Framework provides a standardized way to represent and manage errors through the `ARTError` class and the `ErrorCode` enum. - -## `ARTError` Class - -* **Source:** `src/errors.ts` - -`ARTError` is a custom error class that extends the built-in JavaScript `Error`. It's used throughout the framework to signal issues specific to ART's operations. - -**Key Properties:** - -* `message: string`: A human-readable description of the error (inherited from `Error`). -* `name: string`: Set to `'ARTError'`. -* `code: ErrorCode`: A string enum value from `ErrorCode` that categorizes the error. This is useful for programmatic error handling. -* `originalError?: Error`: If the `ARTError` was thrown as a result of catching another error (e.g., an error from an external library or API), this property will hold the original error object, preserving its stack trace and details. - -**Example Usage (Conceptual):** - -```typescript -// import { ARTError, ErrorCode } from 'art-framework'; - -function someRiskyOperation() { - try { - // ... operation that might fail ... - if (/* condition for failure */) { - throw new Error("Underlying system failure."); - } - } catch (e: any) { - throw new ARTError("The risky operation failed.", ErrorCode.AGENT_PROCESSING_ERROR, e); - } -} -``` - -## `ErrorCode` Enum - -* **Source:** `src/errors.ts` - -The `ErrorCode` enum provides a set of predefined string constants representing different categories of errors that can occur within the ART framework. Using these codes allows for more precise error identification and handling. - -**Key Error Codes (Refer to `src/errors.ts` for the complete list):** - -* **Configuration Errors:** - * `INVALID_CONFIG`: General invalid configuration. - * `MISSING_API_KEY`: An API key required by an adapter is missing. -* **Storage Errors:** - * `STORAGE_ERROR`: General error from the storage adapter. - * `THREAD_NOT_FOUND`: Attempted to access a thread that doesn't exist. - * `SAVE_FAILED`: Failed to save data to storage. -* **Reasoning Errors (LLM Interactions):** - * `LLM_PROVIDER_ERROR`: An error occurred during communication with the LLM provider (e.g., API error, network issue from adapter's perspective). - * `PROMPT_FRAGMENT_NOT_FOUND`: A requested prompt fragment does not exist. - * `PROMPT_VALIDATION_FAILED`: A constructed `ArtStandardPrompt` object failed schema validation. - * `PROMPT_TRANSLATION_FAILED`: An error occurred while an adapter was translating an `ArtStandardPrompt` to a provider-specific format. - * `OUTPUT_PARSING_FAILED`: Failed to parse the LLM's output (e.g., malformed JSON in tool calls). -* **Tool Errors:** - * `TOOL_NOT_FOUND`: The requested tool is not registered. - * `TOOL_SCHEMA_VALIDATION_FAILED`: Tool input arguments failed validation against the tool's schema. - * `TOOL_EXECUTION_ERROR`: A generic error occurred during the tool's `execute` method. - * `TOOL_DISABLED`: The tool is not enabled for the current thread. -* **Agent Core / Orchestration Errors:** - * `PLANNING_FAILED`: The agent's planning phase failed. - * `TOOL_EXECUTION_FAILED`: The `ToolSystem` encountered an error executing one or more tools (distinct from an individual tool's `TOOL_EXECUTION_ERROR` status). - * `SYNTHESIS_FAILED`: The agent's synthesis phase failed. - * `AGENT_PROCESSING_ERROR`: A general error during the `agent.process()` cycle. -* **Provider Manager Errors:** - * `UNKNOWN_PROVIDER`: The requested LLM provider name is not configured in `ProviderManagerConfig`. - * `LOCAL_PROVIDER_CONFLICT`: Attempted to activate a local provider when another is already active. - * `LOCAL_INSTANCE_BUSY`: Attempted to use a local provider instance that is currently busy. - * `ADAPTER_INSTANTIATION_ERROR`: Failed to create an instance of a provider adapter. -* **General Errors:** - * `NETWORK_ERROR`: A network-related error occurred. - * `TIMEOUT_ERROR`: An operation timed out. - * `UNKNOWN_ERROR`: An unspecified or unexpected error. - -## Best Practices for Error Handling - -1. **Catch and Wrap:** When implementing custom components (like tools or agent cores), if you catch an error from an external library or a lower-level operation, consider wrapping it in an `ARTError` with an appropriate `ErrorCode` and passing the original error as the third argument. This provides more context. - - ```typescript - // import { ARTError, ErrorCode, Logger } from 'art-framework'; - // async function myCustomToolExecute(input: any): Promise<any> { - // try { - // const externalResult = await someExternalApiCall(input.param); - // return externalResult.data; - // } catch (e: any) { - // Logger.error("External API call failed in MyCustomTool", e); - // throw new ARTError( - // `MyCustomTool failed: External API error - ${e.message}`, - // ErrorCode.TOOL_EXECUTION_ERROR, // Or a more specific custom error code - // e - // ); - // } - // } - ``` - -2. **Check `ErrorCode`:** When handling errors from ART framework functions (like `art.process()`), you can inspect the `error.code` property if the error is an `ARTError` instance to implement specific recovery or logging logic. - - ```typescript - // import { ARTError, ErrorCode } from 'art-framework'; - // async function runApp() { - // try { - // const result = await art.process({ /* ... */ }); - // // ... - // } catch (error: any) { - // if (error instanceof ARTError) { - // console.error(`ART Error [${error.code}]: ${error.message}`); - // if (error.code === ErrorCode.MISSING_API_KEY) { - // // Prompt user to configure API key - // } else if (error.code === ErrorCode.LLM_PROVIDER_ERROR) { - // // Maybe retry or switch provider - // } - // if (error.originalError) { - // console.error("Original error:", error.originalError); - // } - // } else { - // console.error("An unexpected error occurred:", error); - // } - // } - // } - ``` - -3. **Use `ExecutionMetadata`:** The `AgentFinalResponse.metadata` object contains a `status` field ('success', 'error', 'partial') and an `error` message field. This provides a summary of the execution outcome even if the `process()` call itself doesn't throw a critical error (e.g., a tool fails but the agent can still synthesize a response). - -4. **Leverage Observations:** The `ObservationSystem` records `ERROR` type observations during agent execution. Subscribing to the `ObservationSocket` or querying the `ObservationRepository` can provide a detailed log of errors that occurred, including their phase and context. - -By using `ARTError` and `ErrorCode` consistently, the framework and applications built on it can handle errors in a more structured and informative way. \ No newline at end of file diff --git a/Docs/core-concepts/key-interfaces.md b/Docs/core-concepts/key-interfaces.md deleted file mode 100644 index e867e51..0000000 --- a/Docs/core-concepts/key-interfaces.md +++ /dev/null @@ -1,74 +0,0 @@ -# Key Interfaces in ART - -The ART Framework is built upon a set of core interfaces that define the contracts between its various components. Understanding these interfaces is crucial for comprehending the framework's architecture and for extending its capabilities. - -This page highlights some of the most important public interfaces. For a complete list and detailed TSDoc, refer to the source files, primarily `src/core/interfaces.ts` and `src/types/providers.ts`. - -## 1. `IAgentCore` - -* **Source:** `src/core/interfaces.ts` -* **Purpose:** Defines the central orchestration logic of an agent. -* **Key Method:** - * `process(props: AgentProps): Promise<AgentFinalResponse>`: The main entry point to run the agent's reasoning cycle for a given user query. -* **Implementations:** `PESAgent` is the default implementation. Developers can create custom agents by implementing this interface. - -## 2. `ProviderAdapter` (extends `ReasoningEngine`) - -* **Source:** `src/core/interfaces.ts` -* **Purpose:** Acts as a bridge between the ART framework and a specific Large Language Model (LLM) provider's API. -* **Key Properties/Methods:** - * `providerName: string` (readonly): A unique identifier for the provider (e.g., "openai", "anthropic"). - * `call(prompt: ArtStandardPrompt, options: CallOptions): Promise<AsyncIterable<StreamEvent>>`: - * Takes a standardized `ArtStandardPrompt`. - * Translates it into the provider-specific API format. - * Makes the API call to the LLM. - * Translates the provider's response (streaming or non-streaming) into an `AsyncIterable<StreamEvent>`. - * `shutdown?(): Promise<void>` (optional): For graceful cleanup of resources if needed. -* **Implementations:** `OpenAIAdapter`, `AnthropicAdapter`, `GeminiAdapter`, `OllamaAdapter`, `OpenRouterAdapter`, `DeepSeekAdapter`. - -## 3. `IToolExecutor` - -* **Source:** `src/core/interfaces.ts` -* **Purpose:** Defines the contract for an executable tool that an agent can use. -* **Key Properties/Methods:** - * `schema: ToolSchema` (readonly): Describes the tool's name, description, input parameters (using JSON Schema), output schema (optional), and examples. This schema is used by the LLM to decide when and how to use the tool, and by the `ToolSystem` for input validation. - * `execute(input: any, context: ExecutionContext): Promise<ToolResult>`: Contains the actual logic of the tool. Takes validated input and execution context, returns a `ToolResult`. -* **Implementations:** `CalculatorTool` is a built-in example. Developers create custom tools by implementing this interface. - -## 4. `StorageAdapter` - -* **Source:** `src/core/interfaces.ts` -* **Purpose:** Provides a generic interface for persisting and retrieving data, abstracting the underlying storage mechanism. -* **Key Methods:** - * `init?(config?: any): Promise<void>` (optional): For any setup the adapter needs (e.g., opening a database connection). - * `get<T>(collection: string, id: string): Promise<T | null>`: Retrieves an item. - * `set<T>(collection: string, id: string, data: T): Promise<void>`: Saves (creates or updates) an item. - * `delete(collection: string, id: string): Promise<void>`: Deletes an item. - * `query<T>(collection: string, filterOptions: FilterOptions): Promise<T[]>`: Queries items. - * `clearCollection?(collection: string): Promise<void>` (optional). - * `clearAll?(): Promise<void>` (optional). -* **Implementations:** `InMemoryStorageAdapter`, `IndexedDBStorageAdapter`. - -## 5. `ArtInstance` - -* **Source:** `src/core/interfaces.ts` -* **Purpose:** Represents the fully initialized and configured ART Framework client instance. This is the main object returned by `createArtInstance` and is the primary way applications interact with the framework. -* **Key Properties (readonly):** - * `process: IAgentCore['process']`: The main method to process a user query using the configured agent. - * `uiSystem: UISystem`: Accessor for the UI System, used to get sockets for subscriptions. - * `stateManager: StateManager`: Accessor for managing thread configuration and state. - * `conversationManager: ConversationManager`: Accessor for managing message history. - * `toolRegistry: ToolRegistry`: Accessor for managing available tools. - * `observationManager: ObservationManager`: Accessor for recording and retrieving observations. - -## 6. `IProviderManager` - -* **Source:** `src/types/providers.ts` -* **Purpose:** Manages the lifecycle and access to multiple `ProviderAdapter` implementations, enabling flexible LLM provider selection. -* **Key Methods:** - * `getAvailableProviders(): string[]`: Returns a list of names for all configured (available) providers. - * `getAdapter(config: RuntimeProviderConfig): Promise<ManagedAdapterAccessor>`: The core method used by the `ReasoningEngine`. It takes a `RuntimeProviderConfig` (specifying which provider to use and its runtime options like API key and model ID) and returns a `ManagedAdapterAccessor`. - * `ManagedAdapterAccessor`: An object containing the `adapter` instance and a `release()` function that must be called when the adapter is no longer needed for the current operation. -* **Implementations:** `ProviderManagerImpl`. - -These interfaces form the backbone of the ART Framework, enabling its modular and extensible design. Developers working with ART will frequently interact with objects that implement these interfaces, either by using them directly or by providing their own custom implementations. \ No newline at end of file diff --git a/Docs/core-concepts/observations.md b/Docs/core-concepts/observations.md deleted file mode 100644 index 6378c50..0000000 --- a/Docs/core-concepts/observations.md +++ /dev/null @@ -1,98 +0,0 @@ -# Observations in ART - -Observations are a critical part of the ART Framework, providing a mechanism for introspection, debugging, and real-time monitoring of an agent's execution. They allow developers and systems to understand what the agent is doing, why it's making certain decisions, and how it's progressing through its tasks. - -## Key Components - -1. **`Observation` Interface (`src/types/index.ts`):** - This interface defines the structure of a single observation record: - ```typescript - export interface Observation { - id: string; // Unique ID for the observation - threadId: string; // ID of the conversation thread - traceId?: string; // Optional trace ID for the execution cycle - timestamp: number; // When the observation was recorded (Unix ms) - type: ObservationType; // The category of the event - title: string; // Human-readable summary - content: any; // Payload, structure depends on 'type' - metadata?: Record<string, any>; // Additional context - } - ``` - -2. **`ObservationType` Enum (`src/types/index.ts`):** - This enum categorizes the different kinds of events that can be observed: - * `INTENT`: The agent's understanding of the user's goal. - * `PLAN`: The step-by-step plan formulated by the agent. - * `THOUGHTS`: Internal reasoning or "thinking" steps of the LLM (often extracted from `<think>` tags). - * `TOOL_CALL`: The agent's decision to call one or more tools. - * `TOOL_EXECUTION`: The attempt and result of executing a specific tool. - * `SYNTHESIS`: Events related to the final response generation phase. - * `ERROR`: An error encountered during execution. - * `FINAL_RESPONSE`: The final AI message generated. - * `STATE_UPDATE`: Changes made to the agent's persistent state. - * `LLM_STREAM_START`: Marks the beginning of consuming an LLM stream for a phase (e.g., planning, synthesis). - * `LLM_STREAM_METADATA`: When an LLM stream yields metadata (e.g., token counts). - * `LLM_STREAM_END`: Marks the successful end of an LLM stream. - * `LLM_STREAM_ERROR`: When an error occurs within an LLM stream. - -3. **`ObservationManager` (`src/systems/observation/observation-manager.ts`):** - * **Role:** The central service responsible for creating, persisting, and broadcasting observations. - * **Key Method: `record(observationData: Omit<Observation, 'id' | 'timestamp' | 'title'>)`:** - * Takes the core data for an observation. - * Automatically generates a unique `id`, sets the `timestamp`, and creates a default `title` (e.g., "`<TYPE>` Recorded"). - * Uses an injected `IObservationRepository` to save the observation. - * Uses an injected `ObservationSocket` (from `UISystem`) to notify any subscribers (like a UI) about the new observation. - * **Key Method: `getObservations(threadId: string, filter?: ObservationFilter)`:** - * Retrieves historical observations for a thread from the `IObservationRepository`, optionally applying filters. - -4. **`IObservationRepository` (`src/core/interfaces.ts`):** - * An interface defining how `Observation` objects are stored and retrieved. - * Implemented by `ObservationRepository` (`src/systems/context/repositories/ObservationRepository.ts`), which uses a generic `StorageAdapter` for persistence. - -5. **`ObservationSocket` (`src/systems/ui/observation-socket.ts`):** - * A `TypedSocket` specialized for `Observation` data. - * Allows UI components or other services to `subscribe` to new observations, optionally filtering by `ObservationType` or `threadId`. - * The `ObservationManager` calls `notify()` on this socket. - -## How Observations are Used - -* **Debugging:** Developers can inspect the stream of observations to trace the agent's execution path, understand its decisions at each step (intent, plan, tool calls), see tool inputs/outputs, and identify where errors occur. -* **Real-time UI Updates:** A user interface can subscribe to the `ObservationSocket` to display: - * The agent's current "thought process" (e.g., "Planning...", "Calling tool: get_weather..."). - * Results of tool executions. - * Errors as they happen. - * The final response as it's being synthesized (if combined with `LLMStreamSocket`). -* **Monitoring & Analytics:** In production, observations can be logged to a central system for monitoring agent performance, identifying common failure points, or analyzing usage patterns. -* **Agent Self-Correction (Advanced):** Future agent designs might even use their own observation history to reflect on past actions and improve future performance, though this is not a primary focus of ART `v0.2.7`. - -## Example Flow with Observations (`PESAgent`) - -Consider the `PESAgent` processing a query that involves a tool: - -1. **User Query:** "What's the weather in Paris?" -2. `PESAgent.process()` starts. -3. **Planning Phase:** - * `ObservationManager.record({ type: ObservationType.PLAN, content: { message: "Preparing for planning LLM call." } })` (simplified). - * `PESAgent` calls `ReasoningEngine` for planning. - * `ObservationManager.record({ type: ObservationType.LLM_STREAM_START, content: { phase: 'planning' } })`. - * LLM stream events are processed. - * `ObservationManager.record({ type: ObservationType.LLM_STREAM_END, content: { phase: 'planning' } })`. - * `OutputParser` extracts intent, plan, and tool calls. - * `ObservationManager.record({ type: ObservationType.INTENT, content: { intent: "Find weather in Paris" } })`. - * `ObservationManager.record({ type: ObservationType.PLAN, content: { plan: "Use get_weather tool for Paris.", rawOutput: "..." } })`. - * `ObservationManager.record({ type: ObservationType.TOOL_CALL, content: { toolCalls: [{ callId: "c1", toolName: "get_weather", args: {location: "Paris"} }] } })`. -4. **Execution Phase:** - * `ToolSystem.executeTools()` is called. - * For the "get_weather" tool call: - * `ObservationManager.record({ type: ObservationType.TOOL_EXECUTION, content: { callId: "c1", toolName: "get_weather", status: "success", output: { temp: "12°C" } } })`. (This is recorded by `ToolSystem`). -5. **Synthesis Phase:** - * `ObservationManager.record({ type: ObservationType.SYNTHESIS, content: { message: "Preparing for synthesis LLM call." } })`. - * `PESAgent` calls `ReasoningEngine` for synthesis. - * `ObservationManager.record({ type: ObservationType.LLM_STREAM_START, content: { phase: 'synthesis' } })`. - * LLM stream events for the final answer are processed. - * `ObservationManager.record({ type: ObservationType.LLM_STREAM_END, content: { phase: 'synthesis' } })`. -6. **Finalization:** - * The final AI message is created. - * `ObservationManager.record({ type: ObservationType.FINAL_RESPONSE, content: { message: { role: "AI", content: "The weather in Paris is 12°C." } } })`. - -Throughout this process, each call to `ObservationManager.record()` would also trigger a notification on the `ObservationSocket`, allowing a connected UI to display these events as they occur. If any step resulted in an error, an `ObservationType.ERROR` would be recorded. \ No newline at end of file diff --git a/Docs/core-concepts/provider-management.md b/Docs/core-concepts/provider-management.md deleted file mode 100644 index 82fa61c..0000000 --- a/Docs/core-concepts/provider-management.md +++ /dev/null @@ -1,168 +0,0 @@ -# Provider Management in ART - -The ART Framework is designed to be LLM provider-agnostic, allowing developers to easily switch between or even use multiple Large Language Models (e.g., OpenAI, Anthropic, Gemini, local models via Ollama) within the same application. This flexibility is primarily achieved through the **`ProviderManager`** and the **`ProviderAdapter`** pattern. - -## Introduction to `ProviderManager` - -The `ProviderManager` (implementing the `IProviderManager` interface from `src/types/providers.ts`) is a crucial component in ART's reasoning system. Its main responsibilities are: - -1. **Centralized Adapter Access:** It acts as a single point of contact for the `ReasoningEngine` to obtain instances of `ProviderAdapter`s. -2. **Lifecycle Management:** It manages the creation, caching/pooling, and potential eviction of `ProviderAdapter` instances. -3. **Configuration Handling:** It uses two levels of configuration: - * `ProviderManagerConfig`: Provided once when initializing the ART instance via `createArtInstance`. This defines all *available* providers and their base settings. - * `RuntimeProviderConfig`: Passed in `CallOptions` for each specific LLM call. This tells the `ProviderManager` *which* provider to use for that call and provides any necessary runtime options (like API keys or model overrides). -4. **Constraint Enforcement:** It handles specific constraints, especially for local providers (e.g., ensuring only one local provider is active at a time). - -The primary implementation is `ProviderManagerImpl` found in `src/providers/ProviderManagerImpl.ts`. - -## Configuration - -### 1. `ProviderManagerConfig` - -This configuration is part of the main `ArtInstanceConfig` and is provided when you call `createArtInstance`. It tells the `ProviderManager` about all the LLM providers your application *might* use. - -**Key Fields:** - -* `availableProviders`: An array of `AvailableProviderEntry` objects. Each entry defines: - * `name`: A unique string identifier for this provider setup (e.g., "openai-main", "anthropic-claude3", "ollama-llama3"). This name is used in `RuntimeProviderConfig` to select it. - * `adapter`: The constructor of the `ProviderAdapter` class (e.g., `OpenAIAdapter`, `AnthropicAdapter`). - * `isLocal` (Optional, default: `false`): A boolean indicating if the provider is running locally (e.g., Ollama, LMStudio). Local providers typically have singleton behavior (only one active instance across all local provider types). - * `baseOptions` (Optional): Rarely used. Base options that might be passed to the adapter constructor if not overridden by `RuntimeProviderConfig.adapterOptions`. -* `maxParallelApiInstancesPerProvider` (Optional, default: `5`): The maximum number of *active* adapter instances allowed concurrently for a single non-local (API-based) provider `name`. If this limit is reached, subsequent requests for that provider may be queued. -* `apiInstanceIdleTimeoutSeconds` (Optional, default: `300`): The time (in seconds) an adapter instance for an API-based provider can remain idle in the cache before it's eligible for eviction (and its `shutdown()` method is called, if available). - -**Example `ProviderManagerConfig`:** - -```typescript -// Part of ArtInstanceConfig -// import { OpenAIAdapter, AnthropicAdapter, OllamaAdapter } from 'art-framework'; - -const providerManagerConfig = { - availableProviders: [ - { - name: 'openai-gpt4o', - adapter: OpenAIAdapter, // from 'art-framework' - isLocal: false, - }, - { - name: 'anthropic-haiku', - adapter: AnthropicAdapter, // from 'art-framework' - isLocal: false, - }, - { - name: 'ollama-local-llama3', - adapter: OllamaAdapter, // from 'art-framework' - isLocal: true, // Mark as a local provider - } - ], - maxParallelApiInstancesPerProvider: 3, - apiInstanceIdleTimeoutSeconds: 180, -}; -``` - -### 2. `RuntimeProviderConfig` - -This configuration is provided dynamically within the `CallOptions` object passed to `ReasoningEngine.call()` (and subsequently to `ProviderManager.getAdapter()`). It specifies exactly which provider to use for *that specific LLM call* and provides the necessary options for the adapter. - -**Key Fields:** - -* `providerName`: A string that **must match** one of the `name`s defined in `ProviderManagerConfig.availableProviders`. -* `modelId`: The specific model identifier to be used for this call (e.g., "gpt-4o-mini", "claude-3-haiku-20240307", "llama3:latest"). -* `adapterOptions`: An object containing options required by the selected adapter's constructor. This typically includes the `apiKey`, and can also include other settings like `temperature` (though these can also be passed directly in `CallOptions`), `baseURL` overrides, etc. - -**Example `RuntimeProviderConfig` (within `CallOptions`):** - -```typescript -// Passed to reasoningEngine.call(prompt, callOptions) -const callOptions = { - threadId: "thread-123", - stream: true, - providerConfig: { // This is the RuntimeProviderConfig - providerName: 'openai-gpt4o', // Selects the 'openai-gpt4o' entry from availableProviders - modelId: 'gpt-4o-mini', - adapterOptions: { - apiKey: process.env.OPENAI_API_KEY, // API key provided at runtime - // temperature: 0.7 // Can also be set here or directly in CallOptions - } - }, - // temperature: 0.7 // Can also be set here -}; -``` - -## Key Features of `ProviderManagerImpl` - -1. **Adapter Instantiation and Caching:** - * When `getAdapter(runtimeConfig)` is called, the `ProviderManagerImpl` first generates a unique `configSignature` based on the `runtimeConfig` (providerName, modelId, sorted adapterOptions). - * It checks if an **idle** instance with the same signature already exists in its cache. If so, it reuses that instance. - * If no suitable idle instance is found, it creates a new one using the `adapter` constructor from `AvailableProviderEntry` and the `adapterOptions` from `RuntimeProviderConfig`. - * The new instance is marked as **active** and stored. - -2. **Managed Adapter Accessor (`ManagedAdapterAccessor`):** - * `getAdapter()` returns a `Promise<ManagedAdapterAccessor>`. - * The `ManagedAdapterAccessor` object contains: - * `adapter`: The ready-to-use `ProviderAdapter` instance. - * `release()`: A function that **must be called** by the consumer (e.g., `ReasoningEngine`) once it's finished using the adapter for that specific call. Releasing an adapter marks it as 'idle' and makes it available for reuse or eviction. - -3. **Idle Instance Eviction (for API providers):** - * When an API-based adapter is released, an idle timer starts (based on `apiInstanceIdleTimeoutSeconds`). - * If the instance remains idle and the timeout expires, it's evicted from the cache, and its `shutdown()` method (if defined on the adapter) is called. This helps manage resources. - -4. **Local Provider Constraints:** - * **Singleton Behavior:** If an adapter is marked with `isLocal: true` in `AvailableProviderEntry`, the `ProviderManagerImpl` enforces that only *one* local provider instance can be active across *all* local provider types at any given time. - * If you request a local provider (`ollama-local-llama3`) while another local provider (`lmstudio-mistral`) is already active, it will throw a `LocalProviderConflictError`. - * If you request the *same* local provider instance while it's already active (i.e., not yet released from a previous call), it will throw a `LocalInstanceBusyError`. - * **Eviction on Switch:** If an idle local provider instance exists (e.g., `ollama-local-llama3` was used and released) and you request a *different* local provider (e.g., `lmstudio-mistral`), the `ProviderManagerImpl` will first evict (shutdown and remove) the idle `ollama-local-llama3` instance before creating the new `lmstudio-mistral` instance. - -5. **Concurrency Limiting & Queuing (for API providers):** - * The `maxParallelApiInstancesPerProvider` setting limits how many active instances can exist simultaneously for a given API provider *name* (e.g., if "openai-gpt4o" and "openai-gpt3.5" are two entries under the conceptual "openai" provider, this limit applies *per entry name*). - * If this limit is reached for an API provider, new requests for that provider are queued. - * When an active instance for that provider is released, the `ProviderManagerImpl` attempts to process the next request from its queue. - * *(Note: The plan mentions an `ApiQueueTimeoutError`, but its implementation detail for timeout handling in the queue itself might vary or be a future enhancement.)* - -6. **Error Handling:** - * `UnknownProviderError`: Thrown if `RuntimeProviderConfig.providerName` doesn't match any `name` in `availableProviders`. - * `AdapterInstantiationError`: Thrown if creating a new adapter instance fails (e.g., constructor throws an error). - * `LocalProviderConflictError`, `LocalInstanceBusyError`: As described above for local providers. - -## How `ReasoningEngine` Uses `ProviderManager` - -The `ReasoningEngine` is the primary consumer of the `ProviderManager`. - -```typescript -// Simplified flow in ReasoningEngine.call() - -async call(prompt: FormattedPrompt, options: CallOptions): Promise<AsyncIterable<StreamEvent>> { - const providerConfig = options.providerConfig; // Must be present - if (!providerConfig) { - throw new Error("CallOptions must include 'providerConfig'."); - } - - let accessor: ManagedAdapterAccessor; - try { - accessor = await this.providerManager.getAdapter(providerConfig); - } catch (error) { - // Handle or re-throw error from getAdapter - throw error; - } - - try { - const streamResult = await accessor.adapter.call(prompt, options); - - // Wrap the stream to ensure release is called - return (async function*() { - try { - for await (const event of streamResult) { - yield event; - } - } finally { - accessor.release(); // CRITICAL: Release the adapter - } - })(); - } catch (error) { - accessor.release(); // Ensure release even if initial call to adapter fails - throw error; - } -} -``` - -By using the `ProviderManager`, ART allows developers to define a suite of potential LLM backends and dynamically choose the appropriate one at runtime for each agent interaction, promoting flexibility and efficient resource management. \ No newline at end of file diff --git a/Docs/core-concepts/reasoning-and-llms.md b/Docs/core-concepts/reasoning-and-llms.md deleted file mode 100644 index 33c26d4..0000000 --- a/Docs/core-concepts/reasoning-and-llms.md +++ /dev/null @@ -1,90 +0,0 @@ -# Reasoning and LLMs in ART - -The "Reasoning" part of ART (Agent-Reasoning-Tooling) refers to how an agent "thinks" and makes decisions, primarily by interacting with Large Language Models (LLMs). The **Reasoning System** in ART orchestrates these interactions. - -## Core Components of the Reasoning System - -1. **`ReasoningEngine` (`src/systems/reasoning/ReasoningEngine.ts`):** - * **Role:** Acts as the central gateway for all LLM calls within the framework. It doesn't directly make API calls itself but delegates this task to a `ProviderAdapter`. - * **Key Method: `call(prompt: ArtStandardPrompt, options: CallOptions)`:** - * Receives a standardized prompt (`ArtStandardPrompt`) constructed by the agent logic (e.g., `PESAgent`). - * Receives `CallOptions` which crucially include a `RuntimeProviderConfig`. This config specifies which LLM provider and model to use for *this specific call*, along with necessary `adapterOptions` (like API keys). - * Uses the `ProviderManager` to obtain a managed instance (`ManagedAdapterAccessor`) of the appropriate `ProviderAdapter` based on the `RuntimeProviderConfig`. - * Invokes the `call` method on the obtained adapter. - * Returns an `AsyncIterable<StreamEvent>`, allowing the agent to process LLM responses token by token if streaming is enabled. - * Ensures the adapter instance is `release()`d back to the `ProviderManager` after the stream is consumed or an error occurs. - * **Interaction:** The `PESAgent` calls `reasoningEngine.call()` for both its planning and synthesis phases. - -2. **`ProviderManager` (`src/providers/ProviderManagerImpl.ts`):** - * **Role:** Manages the lifecycle and access to various `ProviderAdapter` implementations. It allows ART to be LLM provider-agnostic. - * **Functionality:** - * Configured at startup (`ArtInstanceConfig.providers`) with a list of `AvailableProviderEntry` objects, each defining an adapter class (e.g., `OpenAIAdapter`), a unique name, and whether it's a local provider. - * Handles instantiation, caching/pooling of API adapter instances, and enforces constraints (e.g., singleton for local providers, concurrency limits for API providers). - * See the [Provider Management](./provider-management.md) page for a detailed explanation. - -3. **`ProviderAdapter` (`src/core/interfaces.ts` and `src/adapters/reasoning/`):** - * **Role:** Bridges the ART framework's standard interfaces with the specific APIs of different LLM providers. Each supported LLM (OpenAI, Anthropic, Gemini, Ollama, etc.) has its own adapter. - * **Key Responsibilities:** - * **Prompt Translation:** Translates the incoming `ArtStandardPrompt` (an array of `ArtStandardMessage` objects) into the specific request format required by the target LLM provider's API. This includes mapping roles (e.g., ART's `assistant` to Gemini's `model`), content structures, and tool call formats. - * **API Interaction:** Makes the actual HTTP request to the LLM provider's endpoint, handling authentication (e.g., API keys from `adapterOptions`) and other provider-specific headers or parameters. - * **Response Streaming:** If streaming is requested (`CallOptions.stream: true`), the adapter processes the provider's streaming response (e.g., Server-Sent Events) and converts each chunk into a standard ART `StreamEvent` (`TOKEN`, `METADATA`, `ERROR`, `END`). - * **Non-Streaming Handling:** If not streaming, it makes a regular request, gets the full response, and typically yields a minimal sequence of `StreamEvent`s (e.g., one `TOKEN` event with the full content, `METADATA`, and `END`). - * **Tool Support:** Adapters are responsible for formatting `ToolSchema`s (from `CallOptions.tools`) in a way the LLM can understand for function calling, and for parsing tool call requests from the LLM's response back into a standard format if necessary (though often `ArtStandardPrompt`'s `tool_calls` structure is close to what providers expect). They also format `tool_result` messages for the LLM. - -4. **`PromptManager` (`src/systems/reasoning/PromptManager.ts`):** - * **Role:** In ART `v0.2.7`, the `PromptManager`'s primary roles are: - * **`getFragment(name: string, context?: Record<string, any>): string`:** Retrieves pre-defined, named prompt pieces (fragments). These fragments can be static text or simple templates with basic `{{variable}}` substitution. Agent logic (like `PESAgent`) can use these fragments when constructing the `ArtStandardPrompt` object. - * **`validatePrompt(prompt: ArtStandardPrompt): ArtStandardPrompt`:** Validates a fully constructed `ArtStandardPrompt` object against the Zod schema defined in `src/types/schemas.ts` (`ArtStandardPromptSchema`). This helps catch structural errors before the prompt is sent to an adapter. - * **Note:** The `PESAgent` (and other agent logic) is now directly responsible for *assembling* the `ArtStandardPrompt` object (an array of `ArtStandardMessage`s). It might use `promptManager.getFragment()` to get parts of the content for those messages but doesn't rely on the `PromptManager` to render a full template into the final prompt structure. - -5. **`OutputParser` (`src/systems/reasoning/OutputParser.ts`):** - * **Role:** Extracts structured information from the raw text output of LLM calls, particularly during the planning phase. - * **Key Methods:** - * **`async parsePlanningOutput(output: string)`:** - * Processes the LLM's response from the planning phase. - * **Handles `<think>` tags:** It uses an `XmlMatcher` (`src/utils/xml-matcher.ts`) to find and extract content embedded within `<think>...</think>` tags. This "thinking" content is aggregated. - * Extracts distinct sections labeled "Intent:", "Plan:", and "Tool Calls:" from the non-thinking part of the output. - * For "Tool Calls:", it attempts to parse a JSON array (potentially enclosed in markdown fences like ` ```json ... ``` `) and validates its structure against a Zod schema to produce `ParsedToolCall[]`. - * Returns an object like `{ intent?: string, plan?: string, toolCalls?: ParsedToolCall[], thoughts?: string }`. - * **`async parseSynthesisOutput(output: string)`:** - * In ART `v0.2.7`, this method is very simple: it primarily trims whitespace from the synthesis LLM's output. The `PESAgent` now consumes the raw text directly from the synthesis stream for the final response, so complex parsing here is less critical. - * **Interaction:** The `PESAgent` uses `outputParser.parsePlanningOutput()` after the planning LLM call to understand the LLM's plan and any requested tool uses. - -## The Flow of Reasoning - -1. **Agent Logic (e.g., `PESAgent`) Prepares Context:** - * Gathers necessary information: system prompt, conversation history, available tools, current user query, and (if applicable) results from previous tool executions. - -2. **Agent Logic Constructs `ArtStandardPrompt`:** - * The agent directly creates an array of `ArtStandardMessage` objects. - * It might use `promptManager.getFragment()` to fetch reusable pieces of text for the `content` fields of these messages. - * Example: For planning, it might create a system message, several user/assistant messages from history, and a final user message detailing the task, available tools, and desired output format. - * Optionally, it can call `promptManager.validatePrompt()` on the constructed object. - -3. **Agent Logic Calls `ReasoningEngine`:** - * `reasoningEngine.call(artStandardPrompt, callOptions)` is invoked. - * `callOptions` includes `stream: true` (usually) and the `RuntimeProviderConfig` specifying the LLM provider, model, and adapter options (like API key). - -4. **`ReasoningEngine` Orchestrates:** - * It requests a `ManagedAdapterAccessor` from the `ProviderManager` using the `RuntimeProviderConfig`. - -5. **`ProviderAdapter` Takes Over:** - * The obtained adapter's `call` method is invoked. - * The adapter translates the `ArtStandardPrompt` into the specific format its target LLM API expects. - * It makes the API call to the LLM. - * It processes the LLM's response (streaming or non-streaming) and converts it into an `AsyncIterable<StreamEvent>`. - -6. **Agent Logic Consumes `StreamEvent`s:** - * The agent iterates over the `StreamEvent`s. - * `TOKEN` events are accumulated to form the complete text response for that phase (e.g., planning output or synthesis output). - * `METADATA`, `ERROR`, and `END` events are handled appropriately. - * The `LLMStreamSocket` is notified of each event for UI updates. - -7. **Agent Logic Uses `OutputParser` (for Planning):** - * After the planning stream completes, the accumulated text output is passed to `outputParser.parsePlanningOutput()`. - * This extracts the intent, plan, and any `ParsedToolCall`s. - -8. **Agent Continues:** - * Based on the parsed plan, the agent might proceed to tool execution or directly to synthesizing a final response. The synthesis phase follows a similar pattern of prompt construction and `ReasoningEngine` interaction. - -This system allows ART to abstract away the complexities of different LLM APIs, enabling developers to focus on the agent's logic and prompt engineering using a consistent, standardized approach. \ No newline at end of file diff --git a/Docs/core-concepts/state-management.md b/Docs/core-concepts/state-management.md deleted file mode 100644 index fea1244..0000000 --- a/Docs/core-concepts/state-management.md +++ /dev/null @@ -1,101 +0,0 @@ -# State Management in ART - -Effective state management is crucial for AI agents to maintain context, remember preferences, and provide coherent, multi-turn interactions. The ART Framework provides a robust **Context System** with a central `StateManager` to handle this. - -## Key Components - -* **`StateManager` (`src/systems/context/managers/StateManager.ts`):** - * The primary service for managing thread-specific configuration (`ThreadConfig`) and persistent agent state (`AgentState`). - * It interacts with an underlying `IStateRepository` to load and save this data. - * Crucially, its behavior regarding `AgentState` persistence is influenced by the `StateSavingStrategy` defined in `ArtInstanceConfig`. -* **`IStateRepository` (`src/core/interfaces.ts`):** - * An interface defining how `ThreadContext` (which bundles `ThreadConfig` and `AgentState`) is stored and retrieved. - * Implemented by `StateRepository` (`src/systems/context/repositories/StateRepository.ts`), which uses a generic `StorageAdapter` (like `InMemoryStorageAdapter` or `IndexedDBStorageAdapter`) for actual persistence. -* **`ThreadContext` (`src/types/index.ts`):** - * An object holding both the `ThreadConfig` and `AgentState` for a specific conversation thread. - * `config: ThreadConfig`: Contains settings like enabled tools, LLM provider details for the thread, history limits, and system prompts. - * `state: AgentState | null`: Holds arbitrary, persistent data specific to the agent's operation within that thread (e.g., user preferences, accumulated knowledge, intermediate task results). Can be `null` if no state has been set. -* **`StateSavingStrategy` (`src/types/index.ts`):** - * An important configuration option set in `ArtInstanceConfig` when calling `createArtInstance`. - * It dictates how `AgentState` is saved by the `StateManager`. - -## `StateSavingStrategy`: Explicit vs. Implicit - -The `StateSavingStrategy` significantly impacts how `AgentState` is persisted. - -1. **`'explicit'` (Default Strategy):** - * **Behavior:** `AgentState` is **only** saved when the agent logic explicitly calls `StateManager.setAgentState(threadId, newState)`. - * The `StateManager.saveStateIfModified(threadId)` method (which `PESAgent` calls at the end of its `process` cycle) becomes a **no-op** for `AgentState` persistence in this mode. It will *not* automatically save changes made to `AgentState` during the agent's operation. - * **Use Case:** Gives developers full control over when `AgentState` is written to storage. Suitable when state changes are deliberate and should not happen automatically after every interaction. - * **Example:** - ```typescript - // In agent logic, after loading context via stateManager.loadThreadContext(threadId) - // context.state.someProperty = 'new value'; // This change IS NOT automatically saved - - // To save it explicitly: - // await stateManager.setAgentState(threadId, context.state); - ``` - -2. **`'implicit'`:** - * **Behavior:** - * When `StateManager.loadThreadContext(threadId)` is called, the `StateManager` caches the loaded `ThreadContext` and internally creates a snapshot (e.g., a JSON string) of the initial `AgentState`. - * The agent logic receives and can modify this cached `ThreadContext.state` object directly. - * When `StateManager.saveStateIfModified(threadId)` is called (typically by `PESAgent` at the end of its processing cycle): - * The `StateManager` compares the current `AgentState` in its cache (which might have been modified by the agent) with the initial snapshot. - * If they are different, the `StateManager` automatically calls `IStateRepository.setAgentState(threadId, currentState)` to persist the changes. - * The internal snapshot is then updated to reflect the newly saved state. - * Explicit calls to `StateManager.setAgentState(threadId, newState)` will still save the state immediately and also update the internal snapshot in the `StateManager`. - * **Use Case:** Convenient for scenarios where any modification to the `AgentState` object during an agent's turn should be automatically persisted. Reduces boilerplate for saving state. - * **Example:** - ```typescript - // ArtInstanceConfig: { ..., stateSavingStrategy: 'implicit', ... } - - // In agent logic, after loading context via stateManager.loadThreadContext(threadId) - // context.state.someProperty = 'new value'; // This change WILL BE automatically saved - // when PESAgent calls saveStateIfModified. - ``` - -**Choosing a Strategy:** - -* Use **`'explicit'`** if you need fine-grained control over state persistence, want to minimize writes, or if state changes are complex and shouldn't be saved automatically after every turn. -* Use **`'implicit'`** for simpler state management where automatic persistence of any changes to the `AgentState` object during an agent's turn is desired. - -## `StateManager` Key Methods - -* **`async loadThreadContext(threadId: string, userId?: string): Promise<ThreadContext>`:** - * Loads the `ThreadConfig` and `AgentState` for the given `threadId`. - * If `stateSavingStrategy` is `'implicit'`, it caches the context and snapshots the `AgentState`. - * Throws an error if the context is not found (application should call `setThreadConfig` for new threads). - -* **`async isToolEnabled(threadId: string, toolName: string): Promise<boolean>`:** - * Loads the thread context (respecting caching if `'implicit'`) and checks if `toolName` is in `ThreadConfig.enabledTools`. - * Returns `false` if context/config cannot be loaded or tool is not listed. - -* **`async getThreadConfigValue<T>(threadId: string, key: string): Promise<T | undefined>`:** - * Loads the thread context and retrieves a top-level value from `ThreadConfig` by its `key`. - * Does *not* support deep/nested key access (e.g., `'reasoning.model'`). - -* **`async saveStateIfModified(threadId: string): Promise<void>`:** - * Crucial method, especially for the `'implicit'` strategy. - * If `'explicit'`, it's a no-op for `AgentState`. - * If `'implicit'`, compares the current cached `AgentState` with its initial snapshot. If different, saves the state via the repository. - -* **`async setThreadConfig(threadId: string, config: ThreadConfig): Promise<void>`:** - * Explicitly sets or overwrites the `ThreadConfig` for a thread. - * If context was cached (in `'implicit'` mode), it's cleared to ensure fresh data on next load. - -* **`async setAgentState(threadId: string, state: AgentState): Promise<void>`:** - * Explicitly sets or overwrites the `AgentState` for a thread. - * Requires `ThreadConfig` to exist for the thread. - * If `stateSavingStrategy` is `'implicit'`, this method also updates the `StateManager`'s internal snapshot of the state to prevent an immediate re-save by `saveStateIfModified`. - -## Interaction with `PESAgent` - -The `PESAgent` interacts with the `StateManager` as follows: - -1. At the beginning of `process()`: Calls `loadThreadContext()` to get the current configuration and state. -2. During planning/execution: May call `isToolEnabled()` or `getThreadConfigValue()` to make decisions. -3. Agent logic might modify `context.state` directly (especially in `'implicit'` mode) or call `setAgentState()` (especially in `'explicit'` mode or for deliberate saves in `'implicit'` mode). -4. At the end of `process()` (in a `finally` block): Calls `saveStateIfModified()` to ensure state is persisted according to the chosen strategy. - -Understanding `StateManager` and `StateSavingStrategy` is key to controlling how your ART agent remembers information and preferences across interactions. \ No newline at end of file diff --git a/Docs/core-concepts/streaming-and-streamevents.md b/Docs/core-concepts/streaming-and-streamevents.md deleted file mode 100644 index 31ee3eb..0000000 --- a/Docs/core-concepts/streaming-and-streamevents.md +++ /dev/null @@ -1,148 +0,0 @@ -# Streaming and StreamEvents in ART - -Modern Large Language Models (LLMs) often support streaming, where they generate responses token by token (or chunk by chunk) rather than returning the entire response at once. The ART Framework embraces streaming to enhance user experience by providing real-time feedback and improving perceived performance. This is primarily achieved through the `StreamEvent` interface and its handling by the `ReasoningEngine` and `ProviderAdapter`s. - -## What is `StreamEvent`? - -`StreamEvent` is a standardized interface within ART (`src/types/index.ts`) that represents a single piece of data emitted from an LLM stream. Adapters are responsible for translating provider-specific stream chunks into these standard events. - -```typescript -export interface StreamEvent { - type: 'TOKEN' | 'METADATA' | 'ERROR' | 'END'; - data: any; // Content depends on the 'type' - tokenType?: 'LLM_THINKING' | 'LLM_RESPONSE' | /* ...other combined types */; - threadId: string; - traceId: string; - sessionId?: string; -} -``` - -**Key `StreamEvent` Types:** - -* **`TOKEN`**: - * `data`: A `string` representing a chunk of text generated by the LLM. - * `tokenType` (Optional): Provides more specific classification for `TOKEN` events, helping to distinguish between intermediate thoughts and the final response. It combines LLM-level detection (if available from the adapter, e.g., `<think>` tags) and agent-level context (`callContext` from `CallOptions`). - * Examples: `AGENT_THOUGHT_LLM_RESPONSE` (for planning output), `FINAL_SYNTHESIS_LLM_RESPONSE` (for the user-facing answer). -* **`METADATA`**: - * `data`: An `LLMMetadata` object containing information like token counts (`inputTokens`, `outputTokens`), `stopReason`, `timeToFirstTokenMs`, and `totalGenerationTimeMs`. This event is typically sent once, often towards or at the end of a stream. -* **`ERROR`**: - * `data`: An `Error` object or error details if an issue occurred during the LLM call or while processing the stream. -* **`END`**: - * `data`: Usually `null`. Signals that the LLM has finished generating its response for the current call and the stream is complete. - -Each `StreamEvent` also includes `threadId`, `traceId`, and an optional `sessionId` for context and correlation. - -## How Streaming Works in ART - -1. **Requesting a Stream:** - When an agent (like `PESAgent`) calls the `ReasoningEngine`, it can request a streaming response by setting `stream: true` in the `CallOptions`. - - ```typescript - // In PESAgent, during a call to the ReasoningEngine: - const callOptions: CallOptions = { - threadId: props.threadId, - traceId: traceId, - stream: true, // Request a streaming response - callContext: 'AGENT_THOUGHT', // e.g., for planning phase - providerConfig: { /* ... */ }, - // ... other parameters - }; - const llmStream = await this.deps.reasoningEngine.call(promptObject, callOptions); - ``` - -2. **`ReasoningEngine` and `ProviderAdapter` Handling:** - * The `ReasoningEngine` receives the call. It uses the `ProviderManager` to obtain an appropriate `ProviderAdapter` based on `callOptions.providerConfig`. - * The selected `ProviderAdapter` (e.g., `OpenAIAdapter`, `AnthropicAdapter`) is responsible for making the actual API call to the LLM provider with streaming enabled. - * As the LLM provider sends back data chunks, the `ProviderAdapter` translates these provider-specific chunks into standard ART `StreamEvent` objects. - * The `ProviderAdapter.call()` method returns an `AsyncIterable<StreamEvent>`. - -3. **Consuming the Stream (`PESAgent` Example):** - The `PESAgent` (or any other component calling `ReasoningEngine`) consumes this `AsyncIterable` to process events as they arrive. - - ```typescript - // In PESAgent, after calling reasoningEngine.call(): - let accumulatedText = ""; - for await (const event of llmStream) { - // Notify UI subscribers about every event - this.deps.uiSystem.getLLMStreamSocket().notify(event, { /* ... */ }); - - switch (event.type) { - case 'TOKEN': - accumulatedText += event.data; - // Further processing based on event.tokenType if needed - break; - case 'METADATA': - // Store or log metadata - console.log("LLM Metadata received:", event.data); - break; - case 'ERROR': - // Handle stream error - console.error("LLM Stream Error:", event.data); - // Potentially throw or set an error state - break; - case 'END': - // Stream finished - console.log("LLM Stream Ended."); - break; - } - if (/* error occurred */) break; // Exit loop on error - } - // After the loop, 'accumulatedText' contains the full response from this LLM call. - ``` - -## Benefits of Streaming - -* **Real-time Feedback:** Users see parts of the response as they are generated, making the agent feel more responsive, especially for longer generations. -* **Improved Perceived Performance:** The application doesn't have to wait for the entire LLM response before displaying something. -* **Handling Intermediate Thoughts:** The `tokenType` field in `StreamEvent` (when `type` is `TOKEN`) allows the system to differentiate between the LLM's internal "thinking" process (e.g., planning steps, reasoning traces often wrapped in `<think>` tags by some models/prompts) and the actual "response" content intended for the next stage or the user. This is crucial for complex agent behavior and debugging. - -## UI Integration via `LLMStreamSocket` - -The ART Framework provides an `LLMStreamSocket` (part of the `UISystem`) specifically for broadcasting `StreamEvent`s. - -* The `PESAgent` (or other core logic) `notify`s this socket with every `StreamEvent` it receives from the `ReasoningEngine`. -* UI components can `subscribe` to the `LLMStreamSocket` to receive these events in real-time. -* Subscribers can filter events based on `StreamEvent.type` (e.g., only listen for `TOKEN` events) or by `threadId` and `sessionId`. - -**Conceptual UI Snippet:** - -```javascript -// Hypothetical client-side JavaScript using a WebSocket connection to ART's backend sockets - -// Assume 'artSockets' is an object that manages WebSocket connections -// and provides interfaces similar to ART's internal sockets. - -const llmStreamDisplay = document.getElementById('llm-output'); -const currentThreadId = 'some-active-thread-id'; - -artSockets.llmStream.subscribe( - (event) => { // Callback function - switch (event.type) { - case 'TOKEN': - // Append text, potentially differentiating based on event.tokenType - const span = document.createElement('span'); - span.textContent = event.data; - if (event.tokenType && event.tokenType.includes('THOUGHT')) { - span.className = 'thought-token'; // Style thoughts differently - } - llmStreamDisplay.appendChild(span); - break; - case 'METADATA': - console.log('LLM Call Metadata:', event.data); - break; - case 'ERROR': - console.error('LLM Stream Error:', event.data); - llmStreamDisplay.innerHTML += `<p class="error">Error: ${event.data.message || event.data}</p>`; - break; - case 'END': - console.log('LLM Stream finished.'); - llmStreamDisplay.innerHTML += `<p class="stream-end">--- End of Stream ---</p>`; - break; - } - }, - null, // No type filter (receive all event types) - { threadId: currentThreadId } // Filter by current thread -); -``` - -By standardizing stream events and providing dedicated sockets, ART enables developers to easily build responsive and informative user interfaces for their AI agents. \ No newline at end of file diff --git a/Docs/core-concepts/system-prompt-hierarchy.md b/Docs/core-concepts/system-prompt-hierarchy.md deleted file mode 100644 index 3db38ce..0000000 --- a/Docs/core-concepts/system-prompt-hierarchy.md +++ /dev/null @@ -1,50 +0,0 @@ -# Core Concept: System Prompt Hierarchy and Customization - -The ART Framework (`v0.2.8` and later) provides a flexible and layered approach to defining the system prompt used by agents like `PESAgent`. This allows for a base level of instruction inherent to the agent, with multiple levels of customization to tailor the agent's persona, behavior, and domain-specific knowledge for different instances, threads, or even individual calls. - -## The System Prompt Hierarchy - -The final system prompt an agent uses is constructed by combining a **base agent prompt** with a **custom prompt part**. The custom part is resolved through a specific hierarchy: - -1. **Call-Level Custom Prompt**: Defined in `AgentProps.options.systemPrompt`. This has the highest precedence and overrides any other custom prompts for a single `agent.process()` call. - * **Use Case**: Temporarily altering agent behavior for a specific query, A/B testing different personas, or injecting highly specific, short-lived instructions. - -2. **Thread-Level Custom Prompt**: Defined in `ThreadConfig.systemPrompt`. This applies to all interactions within a specific conversation thread if no call-level prompt is provided. - * **Use Case**: Defining a consistent persona or set of instructions for an entire conversation (e.g., "You are a financial advisor specializing in stocks" for thread A, and "You are a travel agent specializing in European destinations" for thread B). - -3. **Instance-Level Custom Prompt**: Defined in `ArtInstanceConfig.defaultSystemPrompt`. This serves as the default custom prompt for the entire ART instance if no thread-level or call-level prompt is specified. - * **Use Case**: Setting a global default persona or instruction set for all agents created by this ART instance, unless overridden at a more specific level. - -4. **Agent Base Prompt**: This is an internal, hardcoded prompt within the agent implementation itself (e.g., `PESAgent.defaultSystemPrompt`). It provides the fundamental operational instructions for the agent (e.g., "You are a helpful AI assistant. You need to understand a user's query..."). - * **Purpose**: Ensures the agent always has its core behavioral guidelines, regardless of customization. - -## Concatenation Logic - -The `finalSystemPrompt` is constructed as follows: - -``` -finalSystemPrompt = Agent Base Prompt + (Resolved Custom Prompt Part ? "\n\n" + Resolved Custom Prompt Part : "") -``` - -* The **Agent Base Prompt** is always included. -* If a **Custom Prompt Part** is resolved from any of the hierarchy levels (Call, Thread, or Instance), it is appended to the Agent Base Prompt, typically separated by a double newline (`\n\n`) for clarity. -* If no custom prompt is found at any level, only the Agent Base Prompt is used. - -## How It Works in `PESAgent` - -1. **Base Prompt**: `PESAgent` has an internal `this.defaultSystemPrompt` (e.g., "You are a helpful AI assistant..."). -2. **Custom Part Resolution**: - * It first checks `props.options.systemPrompt` (Call-level). - * If not found, it checks `ThreadConfig.systemPrompt` (retrieved via `StateManager.getThreadConfigValue()`). - * If not found, it checks `this.instanceDefaultCustomSystemPrompt` (passed from `ArtInstanceConfig` via `AgentFactory` during agent instantiation). -3. **Combination**: The resolved custom part (if any) is appended to the base prompt. -4. **Usage**: This `finalSystemPrompt` is then used as the content for the `{ role: 'system', ... }` message in the `ArtStandardPrompt` sent to the `ReasoningEngine`. - -## Benefits - -* **Flexibility**: Tailor agent behavior at multiple granularities. -* **Consistency**: Maintain core agent functionality via the base prompt. -* **Overrides**: Higher-level prompts cleanly override lower-level ones. -* **Clear Separation**: Distinguishes between fundamental agent instructions and customizable persona/domain instructions. - -This hierarchical system provides developers with powerful control over system prompts, enabling a wide range of applications and agent behaviors within the ART Framework. \ No newline at end of file diff --git a/Docs/core-concepts/tools-and-capabilities.md b/Docs/core-concepts/tools-and-capabilities.md deleted file mode 100644 index a2e6651..0000000 --- a/Docs/core-concepts/tools-and-capabilities.md +++ /dev/null @@ -1,200 +0,0 @@ -# Tools and Capabilities in ART - -A key feature of advanced AI agents is their ability to interact with the external world, fetch information, or perform actions beyond the inherent knowledge of the Large Language Model (LLM). The ART Framework provides a robust **Tool System** to define, manage, and execute these external capabilities, referred to as "tools." - -## Core Components of the Tool System - -1. **`IToolExecutor` Interface (`src/core/interfaces.ts`):** - * This is the fundamental interface that every custom tool must implement. - * **`schema: ToolSchema` (readonly):** Each tool must expose a `ToolSchema` that describes its functionality to both the LLM (for deciding when and how to use the tool) and the `ToolSystem` (for input validation). - * **`async execute(input: any, context: ExecutionContext): Promise<ToolResult>`:** The method that contains the actual logic of the tool. - * `input`: The arguments provided by the LLM for the tool call, which should have been validated against `schema.inputSchema` by the `ToolSystem`. - * `context`: An `ExecutionContext` object providing `threadId` and `traceId`. - * Returns a `ToolResult` indicating success or failure, along with the output or error information. - -2. **`ToolSchema` Interface (`src/types/index.ts`):** - * Defines the metadata for a tool: - * `name: string`: A unique name for the tool (e.g., "get_current_weather", "calculator"). This name is used by the LLM to request the tool. - * `description: string`: A clear, natural language description of what the tool does, its capabilities, and when it should be used. This is crucial for the LLM's decision-making process. - * `inputSchema: JsonSchema`: A JSON Schema object that defines the expected input arguments for the tool, including their types, descriptions, and whether they are required. This is used by the `ToolSystem` to validate arguments provided by the LLM and by the LLM to understand how to structure the arguments. - * `outputSchema?: JsonSchema` (Optional): A JSON Schema defining the expected structure of the data returned in the `output` field of a successful `ToolResult`. Can be used for validation or by the LLM to understand what to expect back. - * `examples?: Array<{ input: any; output?: any; description?: string }>` (Optional): Examples of how the tool is used, which can be very helpful for LLMs, especially in few-shot prompting scenarios. - -3. **`ToolRegistry` (`src/systems/tool/ToolRegistry.ts`):** - * **Role:** A central place to register and retrieve `IToolExecutor` instances. - * **Key Methods:** - * `registerTool(executor: IToolExecutor)`: Adds a tool executor to the registry. - * `getToolExecutor(toolName: string): Promise<IToolExecutor | undefined>`: Retrieves a tool executor by its name. - * `getAvailableTools(filter?: { enabledForThreadId?: string }): Promise<ToolSchema[]>`: Returns the schemas of available tools. - * **Filtering with `StateManager`:** If a `StateManager` instance is provided to the `ToolRegistry`'s constructor, and `filter.enabledForThreadId` is used, this method will consult the `ThreadConfig.enabledTools` for that thread and only return schemas of tools permitted for that specific conversation. If no `StateManager` is available or no specific filtering is requested, it returns all registered tools. - * Tools can be registered when setting up the `ArtInstance` via the `tools` array in `ArtInstanceConfig`. - -4. **`ToolSystem` (`src/systems/tool/ToolSystem.ts`):** - * **Role:** Orchestrates the execution of tool calls that the agent's planning phase has decided to make. - * **Key Method: `async executeTools(toolCalls: ParsedToolCall[], threadId: string, traceId?: string): Promise<ToolResult[]>`:** - 1. Receives an array of `ParsedToolCall` objects (these are extracted by the `OutputParser` from the LLM's planning response). Each `ParsedToolCall` includes a `callId`, `toolName`, and `arguments`. - 2. For each `ParsedToolCall`: - * **Verification:** Checks if the tool is enabled for the current `threadId` using the `StateManager`. If not, it returns an error `ToolResult`. - * **Retrieval:** Fetches the corresponding `IToolExecutor` from the `ToolRegistry`. If not found, returns an error `ToolResult`. - * **Input Validation:** Validates the `arguments` from the `ParsedToolCall` against the tool's `inputSchema` using `validateJsonSchema` (from `src/utils/validation.ts`). If validation fails, returns an error `ToolResult`. - * **Execution:** Calls the `executor.execute(validatedArguments, executionContext)` method. - * **Observation:** Records a `TOOL_EXECUTION` `Observation` via the `ObservationManager`, containing the `ToolResult` (whether success or error). - 3. Returns an array of `ToolResult` objects, one for each attempted tool call. - -5. **`ParsedToolCall` (`src/types/index.ts`):** - * The structure representing the LLM's request to use a tool, as parsed by the `OutputParser`. - * `callId: string`: A unique ID for this specific call request (often generated by the parser or a unique part of the LLM output). - * `toolName: string`: The name of the tool to invoke. - * `arguments: any`: The arguments the LLM wants to pass to the tool. - -## How Agents Use Tools (Example: `PESAgent`) - -1. **Planning Phase:** - * The `PESAgent` constructs a planning prompt (`ArtStandardPrompt`). This prompt includes descriptions of available tools (obtained from `ToolRegistry.getAvailableTools()`, filtered for the current thread). - * The LLM processes this prompt and, if it decides a tool is needed, includes a "Tool Calls" section in its response, typically as a JSON array describing which tool(s) to call and with what arguments. - * Example LLM planning output: - ``` - Intent: Calculate the square root of 16. - Plan: Use the calculator tool. - Tool Calls: [ - {"callId": "calc_sqrt_16", "toolName": "calculator", "arguments": {"expression": "sqrt(16)"}} - ] - ``` - * The `OutputParser.parsePlanningOutput()` method extracts this information into `ParsedToolCall` objects. - -2. **Execution Phase:** - * The `PESAgent` passes the array of `ParsedToolCall`s to `ToolSystem.executeTools()`. - * The `ToolSystem` handles the execution of each tool as described above, returning an array of `ToolResult`s. - -3. **Synthesis Phase:** - * The `PESAgent` constructs a synthesis prompt. This prompt now includes the original query, the plan, and the `ToolResult`s (both successes and errors) from the execution phase. - * The LLM uses this information to generate a final, user-facing response. If a tool failed, the LLM can explain the failure or try to answer based on partial information. - -## Defining Custom Tools - -To create a custom tool for your ART agent: - -1. **Create a class** that implements the `IToolExecutor` interface. -2. **Define the `schema` property:** - * `name`: Must be unique. - * `description`: Clear and informative for the LLM. - * `inputSchema`: A valid JSON Schema object for the tool's inputs. - * `outputSchema` (optional but recommended). - * `examples` (optional but recommended). -3. **Implement the `async execute(input: any, context: ExecutionContext): Promise<ToolResult>` method:** - * This method contains your tool's core logic. - * `input` will be the validated arguments. - * Return a `ToolResult` with `status: 'success'` and the output, or `status: 'error'` and an error message. - -**Example: A Simple Weather Tool (Conceptual)** - -```typescript -// src/tools/weather-tool.ts -import { IToolExecutor, ToolSchema, ExecutionContext, ToolResult, JsonSchema, Logger } from 'art-framework'; - -export class WeatherTool implements IToolExecutor { - readonly schema: ToolSchema = { - name: "get_weather_forecast", - description: "Gets the current weather forecast for a specified location.", - inputSchema: { - type: "object", - properties: { - location: { - type: "string", - description: "The city and state/country, e.g., 'San Francisco, CA' or 'London, UK'." - }, - days: { - type: "number", - description: "Number of days for the forecast (e.g., 1 for current, 3 for 3-day).", - default: 1 - } - }, - required: ["location"] - } as JsonSchema, // Cast to JsonSchema for type safety if properties aren't fully exhaustive - outputSchema: { - type: "object", - properties: { - forecast: { type: "string", description: "A summary of the weather forecast." }, - temperature: { type: "string", description: "The current or average temperature." } - }, - required: ["forecast", "temperature"] - } as JsonSchema, // Cast to JsonSchema - examples: [ - { - input: { location: "Paris, France" }, - output: { forecast: "Sunny with a high of 22°C", temperature: "22°C" }, - description: "Get current weather for Paris." - }, - { - input: { location: "Tokyo, Japan", days: 3 }, - output: { forecast: "Mixed sunshine and clouds over the next 3 days. Average temp 18°C.", temperature: "18°C" }, - description: "Get a 3-day forecast for Tokyo." - } - ] - }; // End of schema - - async execute(input: any, context: ExecutionContext): Promise<ToolResult> { - const { location, days = 1 } = input; // Use default for days if not provided - const callId = context.traceId || `weather-call-${Date.now()}`; // Ensure a callId - - Logger.info(`WeatherTool: Fetching ${days}-day forecast for ${location}`, { callId, threadId: context.threadId }); - - // In a real tool, you would call a weather API here. - // For this example, we'll return mock data. - if (typeof location !== 'string' || location.trim() === "") { - Logger.warn(`WeatherTool: Invalid location provided.`, { location, callId }); - return { - callId, - toolName: this.schema.name, - status: 'error', - error: `Invalid location provided: '${location}'. Location must be a non-empty string.` - }; - } - - if (location.toLowerCase().includes("error_city")) { - Logger.warn(`WeatherTool: Simulating error for location ${location}`, { callId }); - return { - callId, - toolName: this.schema.name, - status: 'error', - error: `Simulated error: Could not fetch weather for ${location}. API unavailable.` - }; - } - - // Mock successful response - const mockTemperature = `${Math.floor(Math.random() * 15) + 10}°C`; // Random temp between 10-24°C - const mockForecast = `Mock forecast for ${location} (${days} day${days > 1 ? 's' : ''}): Sunny with a chance of AI.`; - - return { - callId, - toolName: this.schema.name, - status: 'success', - output: { - forecast: mockForecast, - temperature: mockTemperature - } - }; - } -} -``` - -**Registering the Custom Tool:** - -You would then instantiate and register this tool when setting up your ART instance: - -```typescript -// In your ArtInstanceConfig (e.g., src/config/art-config.ts) -import { WeatherTool } from '../tools/weather-tool'; // Adjust path as needed -import { ArtInstanceConfig, CalculatorTool } from 'art-framework'; - -const myArtConfig: ArtInstanceConfig = { - // ... other storage and provider configurations - tools: [ - new CalculatorTool(), // Built-in tool - new WeatherTool() // Your custom tool - ], - // ... other configurations -}; -``` - -This comprehensive tool system allows ART agents to extend their capabilities significantly, making them more versatile and powerful. \ No newline at end of file diff --git a/Docs/diagrams/architecture-overview.excalidraw b/Docs/diagrams/architecture-overview.excalidraw deleted file mode 100644 index ebd15df..0000000 --- a/Docs/diagrams/architecture-overview.excalidraw +++ /dev/null @@ -1,5670 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://github.com/zsviczian/obsidian-excalidraw-plugin/releases/tag/2.11.1", - "elements": [ - { - "id": "URbMUDZQl_ay6qNUNDuTa", - "type": "rectangle", - "x": 1284.556738328141, - "y": 588.5719529611468, - "width": 854.74609375, - "height": 444, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 506296566, - "version": 46, - "versionNonce": 676167964, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "VWyukAXP" - } - ], - "updated": 1747513142232, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a0" - }, - { - "id": "AWMR1hb8zB9z7a3r0iR5E", - "type": "rectangle", - "x": 2305.59765625, - "y": 859, - "width": 1052.73828125, - "height": 123, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1077623146, - "version": 2, - "versionNonce": 390020900, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "UbOUChrd" - } - ], - "updated": 1747512808426, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a1" - }, - { - "id": "3vwRS4eXullfB06rQl3Y6", - "type": "rectangle", - "x": 3122.3125, - "y": 538, - "width": 339.99609375, - "height": 271, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ObservationSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1597958710, - "version": 2, - "versionNonce": 1857205532, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "h6Mg3py2" - } - ], - "updated": 1747512808426, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a2" - }, - { - "id": "vPJinicvzJVQDsKNFwVrO", - "type": "rectangle", - "x": 2170.5126159089787, - "y": -185.3741806925421, - "width": 786.453125, - "height": 715, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1747221546, - "version": 444, - "versionNonce": 36102052, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "UqhqCzbc" - } - ], - "updated": 1747512966415, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a3" - }, - { - "id": "4Ai5in2TvRzlmW9bF1qlO", - "type": "rectangle", - "x": 605.80859375, - "y": 419, - "width": 450.625, - "height": 242, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": null, - "seed": 2005939062, - "version": 35, - "versionNonce": 1576793756, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "AVnn1U4f" - } - ], - "updated": 1747513100132, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a4" - }, - { - "id": "dnImkyEeehI3lVsFoTpF1", - "type": "rectangle", - "x": 0, - "y": 242, - "width": 585.80859375, - "height": 740, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 794257130, - "version": 2, - "versionNonce": 760006180, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "chunb8VI" - } - ], - "updated": 1747512808426, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a5" - }, - { - "id": "YlvwTsKCC1j8ps42flSDT", - "type": "rectangle", - "x": 1627.361832439505, - "y": -211.16040763651512, - "width": 342.0625, - "height": 44, - "angle": 0, - "strokeColor": "#d9d9d9", - "backgroundColor": "#f0f0f0", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "seed": 560354486, - "version": 59, - "versionNonce": 225474332, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "PLwbuyZr" - }, - { - "id": "HHfhr380SyV0bXmZ4mGbb", - "type": "arrow" - } - ], - "updated": 1747512834665, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a6" - }, - { - "id": "sv084I-7dO-b1bGmEwcnl", - "type": "rectangle", - "x": 1786.334488689505, - "y": -92.16040763651512, - "width": 239, - "height": 73, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 1314847146, - "version": 62, - "versionNonce": 93322396, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "7DyfeAiW" - }, - { - "id": "HHfhr380SyV0bXmZ4mGbb", - "type": "arrow" - }, - { - "id": "uzhA2m4PKndokokBM48oK", - "type": "arrow" - }, - { - "id": "YfuHpIFVMWGNCQEEN_YXA", - "type": "arrow" - } - ], - "updated": 1747512834665, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a7" - }, - { - "id": "W5qvMe8KlQXemvhLQiOix", - "type": "rectangle", - "x": 2213.8719909089787, - "y": -12.374180692542097, - "width": 287.921875, - "height": 110, - "angle": 0, - "strokeColor": "#ff8c00", - "backgroundColor": "#ffebcd", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 107367926, - "version": 453, - "versionNonce": 841369252, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "MQHxfD9E" - }, - { - "id": "uzhA2m4PKndokokBM48oK", - "type": "arrow" - }, - { - "id": "dMGXZ7Yxonaoj5c8AGbDt", - "type": "arrow" - }, - { - "id": "FF1xQZTGqMM8JWoT2RBhH", - "type": "arrow" - }, - { - "id": "b4CvzVvBqF0cP_oWQLZmq", - "type": "arrow" - }, - { - "id": "M3gBwHpkWBq3vLh4qXO9M", - "type": "arrow" - }, - { - "id": "sADbLacQ8XjPWtjtZS_cB", - "type": "arrow" - }, - { - "id": "Z68YAMy_cZXiY9rtOpWVt", - "type": "arrow" - }, - { - "id": "mvpPdqZLQ2NOnxiWJivbk", - "type": "arrow" - } - ], - "updated": 1747512966415, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a8" - }, - { - "id": "SfB6bkbUXw5bc6NQ3u3CQ", - "type": "rectangle", - "x": 280.21484375, - "y": 444, - "width": 199.875, - "height": 44, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 879113322, - "version": 8, - "versionNonce": 1155829028, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "H0Wpr7vI" - }, - { - "id": "B1P85D85q7NiNz-p0QNYj", - "type": "arrow" - }, - { - "id": "hNo7XEWu47vsJLmw47Zyn", - "type": "arrow" - }, - { - "id": "TOb9tB0bTJOCrcJzxY4NA", - "type": "arrow" - }, - { - "id": "FF1xQZTGqMM8JWoT2RBhH", - "type": "arrow" - }, - { - "id": "7fyOh9OjfPX9KeCsPTvrV", - "type": "arrow" - }, - { - "id": "LJevVSkpL_VrhDCS7Q7Op", - "type": "arrow" - } - ], - "updated": 1747512808426, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a9" - }, - { - "id": "oH7-849XX0DMcLjGMkqgh", - "type": "rectangle", - "x": 100.609375, - "y": 577.5, - "width": 201.125, - "height": 44, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1402281782, - "version": 4, - "versionNonce": 1397835548, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "Xy5CbkqK" - }, - { - "id": "B1P85D85q7NiNz-p0QNYj", - "type": "arrow" - }, - { - "id": "cf4hRmSwmXp1Wv_oFuUIZ", - "type": "arrow" - } - ], - "updated": 1747512808426, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aA" - }, - { - "id": "1MhXjLvsQgeqIyj4qPbxG", - "type": "rectangle", - "x": 35, - "y": 711, - "width": 332.34375, - "height": 73, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 859313962, - "version": 4, - "versionNonce": 983517348, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "HAzYh5Rb" - }, - { - "id": "cf4hRmSwmXp1Wv_oFuUIZ", - "type": "arrow" - }, - { - "id": "euLIihhBsN7ZOSwd22K03", - "type": "arrow" - } - ], - "updated": 1747512808426, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aB" - }, - { - "id": "n0dbkZlx-ckln9jeXtq5A", - "type": "rectangle", - "x": 40.5234375, - "y": 281.5, - "width": 316, - "height": 73, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1297598582, - "version": 4, - "versionNonce": 944898972, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "KnZ9Zywi" - }, - { - "id": "hNo7XEWu47vsJLmw47Zyn", - "type": "arrow" - } - ], - "updated": 1747512808426, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aC" - }, - { - "id": "-jXFqjFNJ_U939E2ievGn", - "type": "rectangle", - "x": 351.734375, - "y": 577.5, - "width": 162.015625, - "height": 44, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 725590506, - "version": 3, - "versionNonce": 813077540, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "3e2vCnbo" - }, - { - "id": "TOb9tB0bTJOCrcJzxY4NA", - "type": "arrow" - } - ], - "updated": 1747512808426, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aD" - }, - { - "id": "S3-08Iat6bZgsq1wFapu6", - "type": "rectangle", - "x": 95.7421875, - "y": 898.5, - "width": 210.859375, - "height": 44, - "angle": 0, - "strokeColor": "#d9d9d9", - "backgroundColor": "#f0f0f0", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1668499894, - "version": 3, - "versionNonce": 654782492, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "Kp4mPUzT" - }, - { - "id": "euLIihhBsN7ZOSwd22K03", - "type": "arrow" - } - ], - "updated": 1747512808426, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aE" - }, - { - "id": "kCozrr01nlraRu2GIkt9_", - "type": "rectangle", - "x": 774.8374858196323, - "y": 467.57439619974605, - "width": 139.390625, - "height": 44, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": null, - "seed": 931648682, - "version": 132, - "versionNonce": 836324636, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "TxFcAwHC" - }, - { - "id": "b4CvzVvBqF0cP_oWQLZmq", - "type": "arrow" - }, - { - "id": "uzw-GkFfT4359nw728Ric", - "type": "arrow" - }, - { - "id": "tWIpLVzYIOgob1ZYR7Sd2", - "type": "arrow" - }, - { - "id": "IobsKxObGEN4tfDoQIVSk", - "type": "arrow" - }, - { - "id": "SPRKzHJvHTEWRr0P9YqXF", - "type": "arrow" - } - ], - "updated": 1747513105800, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aF" - }, - { - "id": "zeFiM-fefB7tFSa7MetB1", - "type": "rectangle", - "x": 640.80859375, - "y": 577.5, - "width": 149.546875, - "height": 44, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1158456054, - "version": 38, - "versionNonce": 468097692, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "h2eOp3kK" - }, - { - "id": "IobsKxObGEN4tfDoQIVSk", - "type": "arrow" - } - ], - "updated": 1747513100133, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aG" - }, - { - "id": "NG7OwzM5aEDpJbCBm4I4Q", - "type": "rectangle", - "x": 840.35546875, - "y": 563, - "width": 212, - "height": 73, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1505472362, - "version": 39, - "versionNonce": 704488348, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "1yjS61qu" - }, - { - "id": "SPRKzHJvHTEWRr0P9YqXF", - "type": "arrow" - } - ], - "updated": 1747513100133, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aH" - }, - { - "id": "B15clfWBgo09caHAgqD18", - "type": "rectangle", - "x": 2217.1532409089787, - "y": 283.6258193074579, - "width": 321.359375, - "height": 73, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1957221430, - "version": 447, - "versionNonce": 427100580, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "9PwBIBib" - }, - { - "id": "nJrYgt5DW613hBBxO1PT-", - "type": "arrow" - }, - { - "id": "M3gBwHpkWBq3vLh4qXO9M", - "type": "arrow" - }, - { - "id": "tWIpLVzYIOgob1ZYR7Sd2", - "type": "arrow" - } - ], - "updated": 1747512966416, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aI" - }, - { - "id": "dO7lpvt19HOndHW0OJZlg", - "type": "rectangle", - "x": 2588.5126159089787, - "y": 283.6258193074579, - "width": 288, - "height": 73, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 640037418, - "version": 449, - "versionNonce": 1030128420, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "hwHeNZbZ" - }, - { - "id": "ToEPP1Mw-87h0n3_kpH1t", - "type": "arrow" - }, - { - "id": "sADbLacQ8XjPWtjtZS_cB", - "type": "arrow" - }, - { - "id": "9OuXWgEWPvrQ680uTH1Y5", - "type": "arrow" - }, - { - "id": "lFDnEk3LqxOdSrvfyYDGx", - "type": "arrow" - } - ], - "updated": 1747512966416, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aJ" - }, - { - "id": "3p3g2_aDpLLl3sK9WrWlY", - "type": "rectangle", - "x": 2449.1649596589787, - "y": -160.3741806925421, - "width": 227, - "height": 73, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1546444150, - "version": 446, - "versionNonce": 156948516, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "2NDcNMzv" - }, - { - "id": "dMGXZ7Yxonaoj5c8AGbDt", - "type": "arrow" - } - ], - "updated": 1747512966416, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aK" - }, - { - "id": "lIGXJaWPoGERNsZ8MbuqX", - "type": "rectangle", - "x": 2337.8563659089787, - "y": 446.1258193074579, - "width": 190.765625, - "height": 44, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1873960170, - "version": 446, - "versionNonce": 2077137572, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "MvlV8qBk" - }, - { - "id": "nJrYgt5DW613hBBxO1PT-", - "type": "arrow" - }, - { - "id": "-sNQvge_wj7EMgIj5GTj0", - "type": "arrow" - } - ], - "updated": 1747512966416, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aL" - }, - { - "id": "VwpDW7hQ2y1gV_p4Qjefs", - "type": "rectangle", - "x": 2632.1298034089787, - "y": 446.1258193074579, - "width": 277.140625, - "height": 44, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1625145014, - "version": 446, - "versionNonce": 1596598436, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "Q4W281nw" - }, - { - "id": "ToEPP1Mw-87h0n3_kpH1t", - "type": "arrow" - }, - { - "id": "o7a_B4O5Nu1LLAr5Ms6jt", - "type": "arrow" - } - ], - "updated": 1747512966416, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aM" - }, - { - "id": "QB41BH_LXmwNl6d7tdXkb", - "type": "rectangle", - "x": 3163.20703125, - "y": 577.5, - "width": 242.3125, - "height": 44, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ObservationSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1944793002, - "version": 9, - "versionNonce": 1332617628, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "55XJHKVo" - }, - { - "id": "8Lpa2nUOkY-yqV8mLRKHr", - "type": "arrow" - }, - { - "id": "uzw-GkFfT4359nw728Ric", - "type": "arrow" - }, - { - "id": "Z68YAMy_cZXiY9rtOpWVt", - "type": "arrow" - }, - { - "id": "War5jqarL0xiwzShWhRAt", - "type": "arrow" - }, - { - "id": "cZ-T7CncgLAh5Dor7_ubn", - "type": "arrow" - } - ], - "updated": 1747513000482, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aN" - }, - { - "id": "KBqtRn3VIpr89SHW9njcj", - "type": "rectangle", - "x": 3161.41796875, - "y": 725.5, - "width": 265.890625, - "height": 44, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ObservationSystem" - ], - "frameId": null, - "roundness": null, - "seed": 2002810870, - "version": 4, - "versionNonce": 628727452, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "0efd7pDo" - }, - { - "id": "8Lpa2nUOkY-yqV8mLRKHr", - "type": "arrow" - }, - { - "id": "9nbzQVpnGles8Jr7ctRJO", - "type": "arrow" - } - ], - "updated": 1747512808426, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aO" - }, - { - "id": "w_DIadNSyinMWmUmnEqPM", - "type": "rectangle", - "x": 2720.734375, - "y": 884, - "width": 334.796875, - "height": 73, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": null, - "seed": 117156458, - "version": 5, - "versionNonce": 1063921956, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "p2T3xMHp" - }, - { - "id": "-sNQvge_wj7EMgIj5GTj0", - "type": "arrow" - }, - { - "id": "o7a_B4O5Nu1LLAr5Ms6jt", - "type": "arrow" - }, - { - "id": "9nbzQVpnGles8Jr7ctRJO", - "type": "arrow" - } - ], - "updated": 1747512808426, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aP" - }, - { - "id": "PaWaEo1Abq__A4JEDiqap", - "type": "rectangle", - "x": 1597.892675828141, - "y": 628.2037965756168, - "width": 116.953125, - "height": 44, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 934938934, - "version": 48, - "versionNonce": 29157916, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "atorKxrP" - }, - { - "id": "N7ktKmntv8KDXYXqm32eQ", - "type": "arrow" - }, - { - "id": "ez5Vtp5NLv4rOFcNXLZcJ", - "type": "arrow" - }, - { - "id": "DHhJqOL7O81Qhd0ySGk43", - "type": "arrow" - } - ], - "updated": 1747513142232, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aQ" - }, - { - "id": "vkVwaoeJVwaTEzRWm-s_Y", - "type": "rectangle", - "x": 1336.380957078141, - "y": 776.2037965756168, - "width": 211.21875, - "height": 44, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 1068420394, - "version": 49, - "versionNonce": 895162524, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "OrKf1Bqf" - }, - { - "id": "N7ktKmntv8KDXYXqm32eQ", - "type": "arrow" - }, - { - "id": "Zvyg7i_D0LKseVZnzKyMO", - "type": "arrow" - }, - { - "id": "7fyOh9OjfPX9KeCsPTvrV", - "type": "arrow" - }, - { - "id": "-joEKP5xoZKr7k0-WyK03", - "type": "arrow" - } - ], - "updated": 1747513142232, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aR" - }, - { - "id": "kY_wuaVOzF4Sp6nKmUQFk", - "type": "rectangle", - "x": 1597.599707078141, - "y": 776.2037965756168, - "width": 222.71875, - "height": 44, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 1901032054, - "version": 50, - "versionNonce": 2146366364, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "WtED8nec" - }, - { - "id": "ez5Vtp5NLv4rOFcNXLZcJ", - "type": "arrow" - }, - { - "id": "aY6HpxG2Vx43EtzM5_EGu", - "type": "arrow" - }, - { - "id": "cZ-T7CncgLAh5Dor7_ubn", - "type": "arrow" - } - ], - "updated": 1747513142233, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aS" - }, - { - "id": "62Ho1mH47pmV4BJ_NQ2oL", - "type": "rectangle", - "x": 1870.318457078141, - "y": 776.2037965756168, - "width": 233.984375, - "height": 44, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "#e6f7ff", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 594515946, - "version": 48, - "versionNonce": 1402417692, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "c6DjxQG6" - }, - { - "id": "DHhJqOL7O81Qhd0ySGk43", - "type": "arrow" - }, - { - "id": "V4jr_5dIy_ks4NDxKKrGB", - "type": "arrow" - }, - { - "id": "9OuXWgEWPvrQ680uTH1Y5", - "type": "arrow" - } - ], - "updated": 1747513142233, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aT" - }, - { - "id": "x7ls2lE6KYKx-KMGGm5Fu", - "type": "rectangle", - "x": 1602.865332078141, - "y": 949.2037965756168, - "width": 278.515625, - "height": 44, - "angle": 0, - "strokeColor": "#d9d9d9", - "backgroundColor": "#f0f0f0", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 1055241142, - "version": 48, - "versionNonce": 768106652, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "49upoErM" - }, - { - "id": "Zvyg7i_D0LKseVZnzKyMO", - "type": "arrow" - }, - { - "id": "aY6HpxG2Vx43EtzM5_EGu", - "type": "arrow" - }, - { - "id": "V4jr_5dIy_ks4NDxKKrGB", - "type": "arrow" - } - ], - "updated": 1747513142233, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aU" - }, - { - "id": "cTRHaRl9GkFPHwBwMiQZr", - "type": "rectangle", - "x": 1289.3515625, - "y": 296, - "width": 229.3125, - "height": 44, - "angle": 0, - "strokeColor": "#52c41a", - "backgroundColor": "#f6ffed", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 1380518570, - "version": 3, - "versionNonce": 1257474980, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "g4qjUfXH" - }, - { - "id": "LJevVSkpL_VrhDCS7Q7Op", - "type": "arrow" - } - ], - "updated": 1747512808426, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aV" - }, - { - "id": "aARlt45sQryQeEVW_Thz0", - "type": "rectangle", - "x": 1091.43359375, - "y": 577.5, - "width": 157.03125, - "height": 44, - "angle": 0, - "strokeColor": "#52c41a", - "backgroundColor": "#f6ffed", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 446811382, - "version": 3, - "versionNonce": 949448860, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "75C0lJKs" - }, - { - "id": "-joEKP5xoZKr7k0-WyK03", - "type": "arrow" - } - ], - "updated": 1747512808426, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aW" - }, - { - "id": "Y3_dUxyHxFJheks_MDkc9", - "type": "rectangle", - "x": 3094.923652512105, - "y": 34.315963964758396, - "width": 128.84375, - "height": 44, - "angle": 0, - "strokeColor": "#52c41a", - "backgroundColor": "#f6ffed", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 853943658, - "version": 43, - "versionNonce": 839438244, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "D3XJclhq" - }, - { - "id": "mvpPdqZLQ2NOnxiWJivbk", - "type": "arrow" - } - ], - "updated": 1747512857850, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aX" - }, - { - "id": "3voYkLasWeQVzwsi1jgdS", - "type": "rectangle", - "x": 3283.9609375, - "y": 444, - "width": 148.75, - "height": 44, - "angle": 0, - "strokeColor": "#52c41a", - "backgroundColor": "#f6ffed", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 1913175606, - "version": 3, - "versionNonce": 907476252, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "iQLg1TgV" - }, - { - "id": "War5jqarL0xiwzShWhRAt", - "type": "arrow" - } - ], - "updated": 1747512808426, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aY" - }, - { - "id": "Fe80a-MSX0vqFJVOO7HKn", - "type": "rectangle", - "x": 2983.0234375, - "y": 444, - "width": 250.9375, - "height": 44, - "angle": 0, - "strokeColor": "#52c41a", - "backgroundColor": "#f6ffed", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 512878634, - "version": 3, - "versionNonce": 414708388, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "ejZrKkcC" - }, - { - "id": "lFDnEk3LqxOdSrvfyYDGx", - "type": "arrow" - } - ], - "updated": 1747512808426, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aZ" - }, - { - "id": "QTTzOs_-veCzl_jw2X31X", - "type": "rectangle", - "x": 2020.4998499696399, - "y": -267.1862019143702, - "width": 213.78125, - "height": 44, - "angle": 0, - "strokeColor": "#52c41a", - "backgroundColor": "#f6ffed", - "fillStyle": "solid", - "strokeWidth": 1, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 973047670, - "version": 91, - "versionNonce": 335412260, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "wUiXPyCn" - }, - { - "id": "YfuHpIFVMWGNCQEEN_YXA", - "type": "arrow" - } - ], - "updated": 1747512973166, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aa" - }, - { - "id": "HHfhr380SyV0bXmZ4mGbb", - "type": "arrow", - "x": 1798.392863689505, - "y": -167.02789011286774, - "width": 33.26599999999962, - "height": 71.93748247635261, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 221729514, - "version": 176, - "versionNonce": 1720609188, - "isDeleted": false, - "boundElements": [], - "updated": 1747512835016, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 24.86748247635262 - ], - [ - 0, - 49.86748247635262 - ], - [ - 33.26599999999962, - 71.93748247635261 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "YlvwTsKCC1j8ps42flSDT", - "focus": 0.0000012790060305082954, - "gap": 1 - }, - "endBinding": { - "elementId": "sv084I-7dO-b1bGmEwcnl", - "focus": -0.08447914119007217, - "gap": 2.930000000000007 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ab" - }, - { - "id": "uzhA2m4PKndokokBM48oK", - "type": "arrow", - "x": 1935.7276470370357, - "y": -18.160407636515117, - "width": 382.9650842203814, - "height": 231.69592887037595, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 46868662, - "version": 636, - "versionNonce": 951578020, - "isDeleted": false, - "boundElements": [], - "updated": 1747512966415, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 197.42556967115252, - 204.30348912151265 - ], - [ - 314.87231578632964, - 231.69592887037595 - ], - [ - 382.9650842203814, - 119.73522694397303 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "sv084I-7dO-b1bGmEwcnl", - "focus": 0.040992093732314126, - "gap": 1 - }, - "endBinding": { - "elementId": "W5qvMe8KlQXemvhLQiOix", - "focus": 0.018535067464369604, - "gap": 3.9490000000000123 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ac" - }, - { - "id": "B1P85D85q7NiNz-p0QNYj", - "type": "arrow", - "x": 292.56592000000006, - "y": 488.99999999999994, - "width": 91.3940590244521, - "height": 83.2000000000001, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1096902058, - "version": 6, - "versionNonce": 1666802204, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808493, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -91.39392000000007, - 24.000000000000057 - ], - [ - -91.39392000000007, - 49.00000000000006 - ], - [ - -91.3940590244521, - 83.2000000000001 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "SfB6bkbUXw5bc6NQ3u3CQ", - "focus": 0.0000031774714846805266, - "gap": 1 - }, - "endBinding": { - "elementId": "oH7-849XX0DMcLjGMkqgh", - "focus": 0.000001243008079523124, - "gap": 5.2999999999999545 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ad" - }, - { - "id": "cf4hRmSwmXp1Wv_oFuUIZ", - "type": "arrow", - "x": 201.17184349586537, - "y": 622.5, - "width": 0.0001565041346225371, - "height": 83.20000000000005, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 202416630, - "version": 6, - "versionNonce": 33852188, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808493, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0.0001565041346225371, - 38.5 - ], - [ - 0.0000273133421728744, - 83.20000000000005 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "oH7-849XX0DMcLjGMkqgh", - "focus": -0.000001243008079523124, - "gap": 1 - }, - "endBinding": { - "elementId": "1MhXjLvsQgeqIyj4qPbxG", - "focus": 7.522331922718219e-7, - "gap": 5.2999999999999545 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ae" - }, - { - "id": "euLIihhBsN7ZOSwd22K03", - "type": "arrow", - "x": 201.1719199186634, - "y": 789.3, - "width": 0.00013902444919722257, - "height": 103.90000000000009, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1950031978, - "version": 6, - "versionNonce": 2080906524, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808493, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0.00008008133659132, - 19.700000000000045 - ], - [ - 0.00008008133659132, - 44.700000000000045 - ], - [ - 0.00008008133659132, - 69.70000000000005 - ], - [ - -0.00005894311260590257, - 103.90000000000009 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "1MhXjLvsQgeqIyj4qPbxG", - "focus": -7.522331922718219e-7, - "gap": 5.2999999999999545 - }, - "endBinding": { - "elementId": "S3-08Iat6bZgsq1wFapu6", - "focus": 0.0000011856243052702222, - "gap": 5.2999999999999545 - }, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "index": "af" - }, - { - "id": "hNo7XEWu47vsJLmw47Zyn", - "type": "arrow", - "x": 175.64799999999997, - "y": 355.5, - "width": 103.61400000000003, - "height": 87.31299999999999, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1490350902, - "version": 6, - "versionNonce": 1824093212, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808493, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 2.842170943040401e-14, - 38.5 - ], - [ - 2.842170943040401e-14, - 63.5 - ], - [ - 103.61400000000003, - 87.31299999999999 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "n0dbkZlx-ckln9jeXtq5A", - "focus": 0.14478125000000003, - "gap": 1 - }, - "endBinding": { - "elementId": "SfB6bkbUXw5bc6NQ3u3CQ", - "focus": -8.451274029012426e-7, - "gap": 1.1870000000000118 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ag" - }, - { - "id": "TOb9tB0bTJOCrcJzxY4NA", - "type": "arrow", - "x": 405.88791999999984, - "y": 489, - "width": 26.85408000000018, - "height": 83.20000000000005, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 26182442, - "version": 6, - "versionNonce": 774672540, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808493, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 26.85408000000018, - 24 - ], - [ - 26.85408000000018, - 49 - ], - [ - 26.854080000000124, - 83.20000000000005 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "SfB6bkbUXw5bc6NQ3u3CQ", - "focus": -0.0000033419309607989636, - "gap": 1 - }, - "endBinding": { - "elementId": "-jXFqjFNJ_U939E2ievGn", - "focus": -0.0000023145915707988698, - "gap": 5.2999999999999545 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ah" - }, - { - "id": "IobsKxObGEN4tfDoQIVSk", - "type": "arrow", - "x": 773.8374858196323, - "y": 502.41708410671833, - "width": 58.25548581963244, - "height": 69.78291589328171, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1132272758, - "version": 195, - "versionNonce": 945396636, - "isDeleted": false, - "boundElements": [], - "updated": 1747513105802, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -58.25548581963233, - 10.582915893281665 - ], - [ - -58.25548581963233, - 35.582915893281665 - ], - [ - -58.25548581963244, - 69.78291589328171 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "kCozrr01nlraRu2GIkt9_", - "focus": 0.0000027352344027306974, - "gap": 1 - }, - "endBinding": { - "elementId": "zeFiM-fefB7tFSa7MetB1", - "focus": -4.1792916109235265e-7, - "gap": 5.2999999999999545 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ai" - }, - { - "id": "SPRKzHJvHTEWRr0P9YqXF", - "type": "arrow", - "x": 840.244110858535, - "y": 512.5743961997459, - "width": 33.52937343679764, - "height": 45.63728655050318, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 331976170, - "version": 296, - "versionNonce": 1918617628, - "isDeleted": false, - "boundElements": [], - "updated": 1747513105803, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -0.468806330114262, - 2.5147081232336177 - ], - [ - 33.06056710668338, - 45.63728655050318 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "kCozrr01nlraRu2GIkt9_", - "focus": 0.000012132982508472038, - "gap": 1 - }, - "endBinding": { - "elementId": "NG7OwzM5aEDpJbCBm4I4Q", - "focus": -0.3047149757040795, - "gap": 4.7883172497508895 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "aj" - }, - { - "id": "nJrYgt5DW613hBBxO1PT-", - "type": "arrow", - "x": 2411.6172234089786, - "y": 357.6258193074579, - "width": 21.622080000000096, - "height": 83.20000000000005, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 298720694, - "version": 1336, - "versionNonce": 2000851100, - "isDeleted": false, - "boundElements": [], - "updated": 1747512966430, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 21.622080000000096, - 24 - ], - [ - 21.622080000000096, - 49 - ], - [ - 21.621940975544476, - 83.20000000000005 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "B15clfWBgo09caHAgqD18", - "focus": 0.0000010590852431050656, - "gap": 1 - }, - "endBinding": { - "elementId": "lIGXJaWPoGERNsZ8MbuqX", - "focus": -0.0000013105086413910494, - "gap": 5.2999999999999545 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ak" - }, - { - "id": "ToEPP1Mw-87h0n3_kpH1t", - "type": "arrow", - "x": 2749.0782234089784, - "y": 357.6258193074578, - "width": 21.622080000000096, - "height": 83.20000000000016, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1341407402, - "version": 1336, - "versionNonce": 190060956, - "isDeleted": false, - "boundElements": [], - "updated": 1747512966430, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 21.622080000000096, - 24.000000000000114 - ], - [ - 21.622080000000096, - 49.000000000000114 - ], - [ - 21.62187146331371, - 83.20000000000016 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "dO7lpvt19HOndHW0OJZlg", - "focus": 0.09734590683883773, - "gap": 1 - }, - "endBinding": { - "elementId": "VwpDW7hQ2y1gV_p4Qjefs", - "focus": -0.000001353103686736692, - "gap": 5.2999999999999545 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "al" - }, - { - "id": "dMGXZ7Yxonaoj5c8AGbDt", - "type": "arrow", - "x": 2546.954303408979, - "y": -86.3741806925421, - "width": 57.293000000000575, - "height": 72.024, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 149747446, - "version": 1336, - "versionNonce": 1297572508, - "isDeleted": false, - "boundElements": [], - "updated": 1747512966430, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 24 - ], - [ - 0, - 49 - ], - [ - -57.293000000000575, - 72.024 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "3p3g2_aDpLLl3sK9WrWlY", - "focus": 0.1384198788546237, - "gap": 1 - }, - "endBinding": { - "elementId": "W5qvMe8KlQXemvhLQiOix", - "focus": -0.035434750678361666, - "gap": 1.975999999999999 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "am" - }, - { - "id": "8Lpa2nUOkY-yqV8mLRKHr", - "type": "arrow", - "x": 3288.1035822784806, - "y": 622.5, - "width": 6.259417721519185, - "height": 97.70000000000005, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ObservationSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 29006698, - "version": 7, - "versionNonce": 1051882396, - "isDeleted": false, - "boundElements": [], - "updated": 1747513000484, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 6.259417721519185, - 38.5 - ], - [ - 6.259417721519185, - 63.5 - ], - [ - 6.259417721519185, - 97.70000000000005 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "QB41BH_LXmwNl6d7tdXkb", - "focus": -0.0000072845436213044914, - "gap": 1 - }, - "endBinding": { - "elementId": "KBqtRn3VIpr89SHW9njcj", - "focus": -0.0000021155315285823634, - "gap": 5.2999999999999545 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "an" - }, - { - "id": "-sNQvge_wj7EMgIj5GTj0", - "type": "arrow", - "x": 2432.6359349239638, - "y": 491.12581930745785, - "width": 291.183, - "height": 428.03724057284853, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 22980662, - "version": 657, - "versionNonce": 2029742492, - "isDeleted": false, - "boundElements": [], - "updated": 1747513057882, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -8.338934923963734, - 317.87418069254215 - ], - [ - 6.392781010998533, - 425.7672836849316 - ], - [ - 94.78715617002717, - 428.03724057284853 - ], - [ - 282.84406507603626, - 406.482180692542 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "lIGXJaWPoGERNsZ8MbuqX", - "focus": -0.0000013105086414333383, - "gap": 1 - }, - "endBinding": { - "elementId": "w_DIadNSyinMWmUmnEqPM", - "focus": -0.0000010853018084557408, - "gap": 5.254374999999982 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ao" - }, - { - "id": "o7a_B4O5Nu1LLAr5Ms6jt", - "type": "arrow", - "x": 2770.0969349468883, - "y": 491.12581930745785, - "width": 169.73981140922888, - "height": 382.4660835445595, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1197973034, - "version": 787, - "versionNonce": 991108124, - "isDeleted": false, - "boundElements": [], - "updated": 1747513048180, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 33.07052973792224, - 204.85824232382072 - ], - [ - 84.78604843821995, - 272.3515690713275 - ], - [ - 134.2762657384519, - 316.7603027899206 - ], - [ - 169.73981140922888, - 382.4660835445595 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "VwpDW7hQ2y1gV_p4Qjefs", - "focus": -0.0000013531036802044096, - "gap": 1 - }, - "endBinding": { - "elementId": "w_DIadNSyinMWmUmnEqPM", - "focus": 0.41166384042602394, - "gap": 10.40809714798263 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ap" - }, - { - "id": "9nbzQVpnGles8Jr7ctRJO", - "type": "arrow", - "x": 3294.490764065218, - "y": 770.3722359347823, - "width": 233.59100000000035, - "height": 126.74892661867023, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 2064134518, - "version": 266, - "versionNonce": 1927150372, - "isDeleted": false, - "boundElements": [], - "updated": 1747513029416, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -4.547473508864641e-13, - 38.5 - ], - [ - -16.75915919629506, - 99.76264971797411 - ], - [ - -83.06611296749588, - 126.74892661867023 - ], - [ - -233.59100000000035, - 123.86400000000015 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "KBqtRn3VIpr89SHW9njcj", - "focus": -0.0009589116970080563, - "gap": 1 - }, - "endBinding": { - "elementId": "w_DIadNSyinMWmUmnEqPM", - "focus": -0.001747786533867241, - "gap": 5.368514065217823 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "aq" - }, - { - "id": "N7ktKmntv8KDXYXqm32eQ", - "type": "arrow", - "x": 1596.8926758281411, - "y": 667.2657364266381, - "width": 154.90278125000032, - "height": 103.63806014897875, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1038502122, - "version": 214, - "versionNonce": 2069852452, - "isDeleted": false, - "boundElements": [], - "updated": 1747513142581, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -90.09144586488628, - 6.840285221182285 - ], - [ - -154.90278125000032, - 69.4380601489787 - ], - [ - -154.90278125000032, - 103.63806014897875 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "PaWaEo1Abq__A4JEDiqap", - "focus": -0.47451481934105794, - "gap": 1 - }, - "endBinding": { - "elementId": "vkVwaoeJVwaTEzRWm-s_Y", - "focus": -0.000004142624649030685, - "gap": 5.2999999999999545 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ar" - }, - { - "id": "ez5Vtp5NLv4rOFcNXLZcJ", - "type": "arrow", - "x": 1676.0370085021916, - "y": 673.2037965756168, - "width": 32.92188607594926, - "height": 97.70000000000005, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 825135798, - "version": 138, - "versionNonce": 680032292, - "isDeleted": false, - "boundElements": [], - "updated": 1747513142582, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 32.92188607594926, - 38.5 - ], - [ - 32.92188607594926, - 63.5 - ], - [ - 32.92188607594926, - 97.70000000000005 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "PaWaEo1Abq__A4JEDiqap", - "focus": -0.0000019397424255974313, - "gap": 1 - }, - "endBinding": { - "elementId": "kY_wuaVOzF4Sp6nKmUQFk", - "focus": -0.0000016837378984845604, - "gap": 5.2999999999999545 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "as" - }, - { - "id": "DHhJqOL7O81Qhd0ySGk43", - "type": "arrow", - "x": 1715.845800828141, - "y": 661.2566121965451, - "width": 271.46509375000005, - "height": 109.64718437907175, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 750885802, - "version": 231, - "versionNonce": 1717288740, - "isDeleted": false, - "boundElements": [], - "updated": 1747513142582, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 189.60216966082862, - 32.71968853754174 - ], - [ - 271.46509375000005, - 75.4471843790717 - ], - [ - 271.46481570100696, - 109.64718437907175 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "PaWaEo1Abq__A4JEDiqap", - "focus": 0.024583974127789492, - "gap": 1 - }, - "endBinding": { - "elementId": "62Ho1mH47pmV4BJ_NQ2oL", - "focus": -0.0000021368948229953407, - "gap": 5.2999999999999545 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "at" - }, - { - "id": "Zvyg7i_D0LKseVZnzKyMO", - "type": "arrow", - "x": 1441.9898945781408, - "y": 821.0802047766798, - "width": 187.57700000000023, - "height": 126.93600000000004, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 779537398, - "version": 178, - "versionNonce": 1061766692, - "isDeleted": false, - "boundElements": [], - "updated": 1747513142582, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 38.5 - ], - [ - 0, - 63.5 - ], - [ - 54.63712498409723, - 112.7300191985072 - ], - [ - 187.57700000000023, - 126.93600000000004 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "vkVwaoeJVwaTEzRWm-s_Y", - "focus": 0.000004142624649245606, - "gap": 1 - }, - "endBinding": { - "elementId": "x7ls2lE6KYKx-KMGGm5Fu", - "focus": 0.30258869786691117, - "gap": 1.1875917989369782 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "au" - }, - { - "id": "aY6HpxG2Vx43EtzM5_EGu", - "type": "arrow", - "x": 1708.9588945781409, - "y": 821.2037965756168, - "width": 18.78500000000031, - "height": 123.33500000000004, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 841258602, - "version": 138, - "versionNonce": 1640041764, - "isDeleted": false, - "boundElements": [], - "updated": 1747513142582, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 38.5 - ], - [ - 0, - 63.5 - ], - [ - 0, - 88.5 - ], - [ - 18.78500000000031, - 123.33500000000004 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "kY_wuaVOzF4Sp6nKmUQFk", - "focus": 0.0000016837378965194562, - "gap": 1 - }, - "endBinding": { - "elementId": "x7ls2lE6KYKx-KMGGm5Fu", - "focus": 1.6170192376679948e-7, - "gap": 4.664999999999964 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "av" - }, - { - "id": "V4jr_5dIy_ks4NDxKKrGB", - "type": "arrow", - "x": 1987.3105815697716, - "y": 821.2037965756167, - "width": 152.3379999999995, - "height": 126.71100000000001, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1625677110, - "version": 205, - "versionNonce": 540218404, - "isDeleted": false, - "boundElements": [], - "updated": 1747513142583, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0.0003130083694031782, - 38.500000000000114 - ], - [ - 0.0003130083694031782, - 63.500000000000114 - ], - [ - -33.262477253785164, - 94.14544714589397 - ], - [ - -152.3376869916301, - 126.71100000000001 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "62Ho1mH47pmV4BJ_NQ2oL", - "focus": 0.0000021368948267495737, - "gap": 1 - }, - "endBinding": { - "elementId": "x7ls2lE6KYKx-KMGGm5Fu", - "focus": 0.0350206441843298, - "gap": 1.289000000000101 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "aw" - }, - { - "id": "FF1xQZTGqMM8JWoT2RBhH", - "type": "arrow", - "x": 2345.0319777424193, - "y": 98.6258193074579, - "width": 1859.6439777424193, - "height": 365.300200010516, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1859795242, - "version": 579, - "versionNonce": 1179374756, - "isDeleted": false, - "boundElements": [], - "updated": 1747512966415, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -54.17697774241924, - 295.37418069254215 - ], - [ - -395.49255338451553, - 336.4502923842084 - ], - [ - -1859.6439777424193, - 365.300200010516 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "W5qvMe8KlQXemvhLQiOix", - "focus": 0.016420339437858568, - "gap": 1 - }, - "endBinding": { - "elementId": "SfB6bkbUXw5bc6NQ3u3CQ", - "focus": -0.000016606806132335425, - "gap": 5.29815624999992 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ax" - }, - { - "id": "b4CvzVvBqF0cP_oWQLZmq", - "type": "arrow", - "x": 2348.8642956073163, - "y": 98.6258193074579, - "width": 1430.7007941805186, - "height": 381.29470640595576, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 769705590, - "version": 739, - "versionNonce": 428287140, - "isDeleted": false, - "boundElements": [], - "updated": 1747513123181, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -38.00929560731629, - 295.37418069254215 - ], - [ - -294.1368048864442, - 358.14913462494565 - ], - [ - -1430.7007941805186, - 381.29470640595576 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "W5qvMe8KlQXemvhLQiOix", - "focus": 0.011668879050614946, - "gap": 1 - }, - "endBinding": { - "elementId": "kCozrr01nlraRu2GIkt9_", - "focus": -0.3481920143720452, - "gap": 3.9353906071653455 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ay" - }, - { - "id": "M3gBwHpkWBq3vLh4qXO9M", - "type": "arrow", - "x": 2373.6227434089783, - "y": 98.6258193074579, - "width": 4.2105600000004415, - "height": 179.70000000000005, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 843940842, - "version": 1336, - "versionNonce": 1004301212, - "isDeleted": false, - "boundElements": [], - "updated": 1747512966431, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 4.2105600000004415, - 16 - ], - [ - 4.2105600000004415, - 41 - ], - [ - 4.2105600000004415, - 88 - ], - [ - 4.2105600000004415, - 135 - ], - [ - 4.210172427364341, - 179.70000000000005 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "W5qvMe8KlQXemvhLQiOix", - "focus": -0.0066453545264842685, - "gap": 1 - }, - "endBinding": { - "elementId": "B15clfWBgo09caHAgqD18", - "focus": -0.0000023338357567602973, - "gap": 5.2999999999999545 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "az" - }, - { - "id": "sADbLacQ8XjPWtjtZS_cB", - "type": "arrow", - "x": 2502.793865908978, - "y": 86.83322282760003, - "width": 131.19943750000039, - "height": 194.51059647985795, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 103581622, - "version": 1336, - "versionNonce": 1903375516, - "isDeleted": false, - "boundElements": [], - "updated": 1747512966431, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 83.57443750000039, - 27.792596479857878 - ], - [ - 83.57443750000039, - 52.79259647985788 - ], - [ - 83.57443750000039, - 99.79259647985788 - ], - [ - 83.57443750000039, - 146.79259647985788 - ], - [ - 83.57443750000039, - 171.79259647985788 - ], - [ - 131.19943750000039, - 194.51059647985795 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "W5qvMe8KlQXemvhLQiOix", - "focus": -0.038874838799026, - "gap": 1 - }, - "endBinding": { - "elementId": "dO7lpvt19HOndHW0OJZlg", - "focus": -0.07808224843900778, - "gap": 2.2819999999999254 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "b00" - }, - { - "id": "7fyOh9OjfPX9KeCsPTvrV", - "type": "arrow", - "x": 462.6572000000001, - "y": 489, - "width": 868.4366945781405, - "height": 295.2731491902541, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 646543018, - "version": 49, - "versionNonce": 384559772, - "isDeleted": false, - "boundElements": [], - "updated": 1747513142233, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 86.0927999999999, - 24 - ], - [ - 86.0927999999999, - 49 - ], - [ - 86.0927999999999, - 110.5 - ], - [ - 86.0927999999999, - 172 - ], - [ - 86.0927999999999, - 197 - ], - [ - 868.4366945781405, - 295.2731491902541 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "SfB6bkbUXw5bc6NQ3u3CQ", - "focus": 0.000004158375541537322, - "gap": 1 - }, - "endBinding": { - "elementId": "vkVwaoeJVwaTEzRWm-s_Y", - "focus": 0.000015033721508421493, - "gap": 5.287062500000047 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "b01" - }, - { - "id": "uzw-GkFfT4359nw728Ric", - "type": "arrow", - "x": 875.5818730441629, - "y": 512.2310158728943, - "width": 2282.3271269558454, - "height": 82.265610559361, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 2045649142, - "version": 753, - "versionNonce": 1509867036, - "isDeleted": false, - "boundElements": [], - "updated": 1747513135532, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 80.09624826685194, - 28.052980036710665 - ], - [ - 439.7835002653271, - 10.836548068049183 - ], - [ - 2282.3271269558454, - 82.265610559361 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "kCozrr01nlraRu2GIkt9_", - "focus": 0.25386613274626735, - "gap": 1 - }, - "endBinding": { - "elementId": "QB41BH_LXmwNl6d7tdXkb", - "focus": 0.00001670285747634973, - "gap": 5.298031250000349 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "b02" - }, - { - "id": "tWIpLVzYIOgob1ZYR7Sd2", - "type": "arrow", - "x": 916.405992828027, - "y": 502.2332172732911, - "width": 1295.4523105809517, - "height": 160.51112817069594, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 2084114794, - "version": 907, - "versionNonce": 1338859676, - "isDeleted": false, - "boundElements": [], - "updated": 1747513128116, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 119.17005304487714, - 3.955326900936541 - ], - [ - 333.073287209152, - -16.315172117555846 - ], - [ - 1295.4523105809517, - -156.5558012697594 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "kCozrr01nlraRu2GIkt9_", - "focus": 0.6951966501498121, - "gap": 2.177882008394704 - }, - "endBinding": { - "elementId": "B15clfWBgo09caHAgqD18", - "focus": -0.000008644198020564914, - "gap": 5.294937499999833 - }, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "index": "b03" - }, - { - "id": "cZ-T7CncgLAh5Dor7_ubn", - "type": "arrow", - "x": 3228.6572850761054, - "y": 622.5, - "width": 1476.3083458697522, - "height": 142.99834805424723, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1286246966, - "version": 405, - "versionNonce": 658130332, - "isDeleted": false, - "boundElements": [], - "updated": 1747513142233, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -140.4961635820846, - 58.007662787959816 - ], - [ - -1108.0415616962468, - 6.818974482018916 - ], - [ - -1476.3083458697522, - 142.99834805424723 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "QB41BH_LXmwNl6d7tdXkb", - "focus": -0.000003668485842796654, - "gap": 1 - }, - "endBinding": { - "elementId": "kY_wuaVOzF4Sp6nKmUQFk", - "focus": -0.2637039945835917, - "gap": 10.70544852136959 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "b04" - }, - { - "id": "9OuXWgEWPvrQ680uTH1Y5", - "type": "arrow", - "x": 2679.4365076086347, - "y": 357.6258193074579, - "width": 617.7152459727986, - "height": 413.362914768159, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 380064810, - "version": 637, - "versionNonce": 663700508, - "isDeleted": false, - "boundElements": [], - "updated": 1747513142233, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -323.20287761657164, - 273.27206757207085 - ], - [ - -448.45338419274594, - 351.45863464591315 - ], - [ - -617.7152459727986, - 413.362914768159 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "dO7lpvt19HOndHW0OJZlg", - "focus": 0.04661191220640601, - "gap": 1 - }, - "endBinding": { - "elementId": "62Ho1mH47pmV4BJ_NQ2oL", - "focus": -0.000012444266803790186, - "gap": 5.215062499999931 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "b05" - }, - { - "id": "Z68YAMy_cZXiY9rtOpWVt", - "type": "arrow", - "x": 2445.6163708158924, - "y": 98.6258193074579, - "width": 814.360514808584, - "height": 473.9625298722455, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 155638646, - "version": 1052, - "versionNonce": 547092252, - "isDeleted": false, - "boundElements": [], - "updated": 1747513200265, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 377.6929251716547, - 123.34657195832767 - ], - [ - 516.1301464266089, - 180.74631170467 - ], - [ - 592.3039388433967, - 209.12844036934683 - ], - [ - 724.6755304779799, - 274.5356512040768 - ], - [ - 814.360514808584, - 363.7160615810389 - ], - [ - 731.3775173919307, - 473.9625298722455 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "W5qvMe8KlQXemvhLQiOix", - "focus": -0.052023794381415286, - "gap": 1 - }, - "endBinding": { - "elementId": "QB41BH_LXmwNl6d7tdXkb", - "focus": -0.9267343331027408, - "gap": 4.911650820296586 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "b06" - }, - { - "id": "LJevVSkpL_VrhDCS7Q7Op", - "type": "arrow", - "x": 1288.3515625, - "y": 327.1007213554516, - "width": 876.9305625000001, - "height": 113.56227864454848, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 935280362, - "version": 6, - "versionNonce": 664554524, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808495, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -850.1955625, - 66.89927864454842 - ], - [ - -850.1955625, - 91.89927864454842 - ], - [ - -876.9305625000001, - 113.56227864454848 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "cTRHaRl9GkFPHwBwMiQZr", - "focus": -0.0000027759996184321654, - "gap": 1 - }, - "endBinding": { - "elementId": "SfB6bkbUXw5bc6NQ3u3CQ", - "focus": -0.000004284111522335669, - "gap": 3.336999999999989 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "b07" - }, - { - "id": "-joEKP5xoZKr7k0-WyK03", - "type": "arrow", - "x": 1249.46484375, - "y": 610.6755169706188, - "width": 227.69411285147316, - "height": 163.693279604998, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 369622198, - "version": 170, - "versionNonce": 889222428, - "isDeleted": false, - "boundElements": [], - "updated": 1747513149116, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 111.67746283958991, - 67.94505389564483 - ], - [ - 164.87455894885125, - 99.8617886927675 - ], - [ - 227.69411285147316, - 163.693279604998 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "aARlt45sQryQeEVW_Thz0", - "focus": 0.000014413071090413896, - "gap": 1 - }, - "endBinding": { - "elementId": "vkVwaoeJVwaTEzRWm-s_Y", - "focus": 8.205763612492635e-7, - "gap": 1.8350000000000364 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "b08" - }, - { - "id": "mvpPdqZLQ2NOnxiWJivbk", - "type": "arrow", - "x": 3121.7469961888323, - "y": 79.3159639647584, - "width": 614.7106927798536, - "height": 126.82069898091702, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 738972074, - "version": 604, - "versionNonce": 1939762724, - "isDeleted": false, - "boundElements": [], - "updated": 1747512966416, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -199.99685573002625, - 122.3393190260436 - ], - [ - -308.3922390808025, - 71.37807129469905 - ], - [ - -614.7106927798536, - -4.481379954873418 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "Y3_dUxyHxFJheks_MDkc9", - "focus": -0.000012129319990515097, - "gap": 1 - }, - "endBinding": { - "elementId": "W5qvMe8KlQXemvhLQiOix", - "focus": -0.05230231919213386, - "gap": 5.242437500000051 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "b09" - }, - { - "id": "War5jqarL0xiwzShWhRAt", - "type": "arrow", - "x": 3358.3359361701873, - "y": 489, - "width": 43.4350000000004, - "height": 85.11199999999997, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1217590774, - "version": 7, - "versionNonce": 906840348, - "isDeleted": false, - "boundElements": [], - "updated": 1747513000484, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0.00006382981246133568, - 24 - ], - [ - 0.00006382981246133568, - 49 - ], - [ - -43.43493617018794, - 85.11199999999997 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "3voYkLasWeQVzwsi1jgdS", - "focus": -8.403361315678555e-7, - "gap": 1 - }, - "endBinding": { - "elementId": "QB41BH_LXmwNl6d7tdXkb", - "focus": 0.000009439452820147216, - "gap": 3.3880000000000337 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "b0A" - }, - { - "id": "lFDnEk3LqxOdSrvfyYDGx", - "type": "arrow", - "x": 2982.0234375, - "y": 487.2328123604187, - "width": 222.05075561041303, - "height": 128.2239930529608, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1991773290, - "version": 577, - "versionNonce": 1501756060, - "isDeleted": false, - "boundElements": [], - "updated": 1747513165184, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -48.77568833191435, - -80.6957739159119 - ], - [ - -79.8642647421525, - -87.08099667845386 - ], - [ - -222.05075561041303, - -128.2239930529608 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "Fe80a-MSX0vqFJVOO7HKn", - "focus": -0.000011698024940937305, - "gap": 1 - }, - "endBinding": { - "elementId": "dO7lpvt19HOndHW0OJZlg", - "focus": -0.07952917493312468, - "gap": 2.383000000000038 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "b0B" - }, - { - "id": "YfuHpIFVMWGNCQEEN_YXA", - "type": "arrow", - "x": 2127.150277083718, - "y": -222.18620191437017, - "width": 100.81578839421286, - "height": 131.1661749216395, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "dashed", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 2045560630, - "version": 208, - "versionNonce": 1296057124, - "isDeleted": false, - "boundElements": [], - "updated": 1747512973166, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -0.835413394212992, - 80.02579427785506 - ], - [ - -0.835413394212992, - 105.02579427785506 - ], - [ - -100.81578839421286, - 131.1661749216395 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "QTTzOs_-veCzl_jw2X31X", - "focus": 8.770647557477426e-7, - "gap": 1 - }, - "endBinding": { - "elementId": "sv084I-7dO-b1bGmEwcnl", - "focus": -0.05689484258019552, - "gap": 1 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "b0C" - }, - { - "id": "VWyukAXP", - "type": "text", - "x": 1660.689825486344, - "y": 593.5719529611468, - "width": 102.47991943359375, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 2106519338, - "version": 47, - "versionNonce": 1438055836, - "isDeleted": false, - "boundElements": [], - "updated": 1747513142232, - "link": null, - "locked": false, - "text": "UI System", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 18, - "containerId": "URbMUDZQl_ay6qNUNDuTa", - "originalText": "UI System", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0D", - "rawText": "" - }, - { - "id": "UbOUChrd", - "type": "text", - "x": 2754.5968704223633, - "y": 864, - "width": 154.73985290527344, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": null, - "seed": 888895978, - "version": 3, - "versionNonce": 741381020, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808426, - "link": null, - "locked": false, - "text": "Storage System", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 18, - "containerId": "AWMR1hb8zB9z7a3r0iR5E", - "originalText": "Storage System", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0E", - "rawText": "" - }, - { - "id": "h6Mg3py2", - "type": "text", - "x": 3196.170639038086, - "y": 543, - "width": 192.27981567382812, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ObservationSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1275636906, - "version": 3, - "versionNonce": 1535706148, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808426, - "link": null, - "locked": false, - "text": "Observation System", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 18, - "containerId": "3vwRS4eXullfB06rQl3Y6", - "originalText": "Observation System", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0F", - "rawText": "" - }, - { - "id": "UqhqCzbc", - "type": "text", - "x": 2486.0492522615177, - "y": -180.3741806925421, - "width": 155.37985229492188, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1482786666, - "version": 445, - "versionNonce": 1894992676, - "isDeleted": false, - "boundElements": [], - "updated": 1747512966415, - "link": null, - "locked": false, - "text": "Context System", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 18, - "containerId": "vPJinicvzJVQDsKNFwVrO", - "originalText": "Context System", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0G", - "rawText": "" - }, - { - "id": "AVnn1U4f", - "type": "text", - "x": 770.7211532592773, - "y": 424, - "width": 120.79988098144531, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": null, - "seed": 38865450, - "version": 36, - "versionNonce": 2011537188, - "isDeleted": false, - "boundElements": [], - "updated": 1747513100132, - "link": null, - "locked": false, - "text": "Tool System", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 18, - "containerId": "4Ai5in2TvRzlmW9bF1qlO", - "originalText": "Tool System", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0H", - "rawText": "" - }, - { - "id": "chunb8VI", - "type": "text", - "x": 207.82437133789062, - "y": 247, - "width": 170.15985107421875, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 818033898, - "version": 3, - "versionNonce": 685595804, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808426, - "link": null, - "locked": false, - "text": "Reasoning System", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 18, - "containerId": "dnImkyEeehI3lVsFoTpF1", - "originalText": "Reasoning System", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0I", - "rawText": "" - }, - { - "id": "PLwbuyZr", - "type": "text", - "x": 1653.1732032891143, - "y": -201.66040763651512, - "width": 290.43975830078125, - "height": 25, - "angle": 0, - "strokeColor": "#d9d9d9", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 893388714, - "version": 59, - "versionNonce": 1191916444, - "isDeleted": false, - "boundElements": [], - "updated": 1747512834665, - "link": null, - "locked": false, - "text": "User Input/External Triggers", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "YlvwTsKCC1j8ps42flSDT", - "originalText": "User Input/External Triggers", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0J", - "rawText": "" - }, - { - "id": "7DyfeAiW", - "type": "text", - "x": 1791.3545845147003, - "y": -80.66040763651512, - "width": 228.95980834960938, - "height": 50, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 2012578410, - "version": 59, - "versionNonce": 1813907740, - "isDeleted": false, - "boundElements": [], - "updated": 1747512834665, - "link": null, - "locked": false, - "text": "ArtInstance\\n(process \nmethod)", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 43, - "containerId": "sv084I-7dO-b1bGmEwcnl", - "originalText": "ArtInstance\\n(process \nmethod)", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0K", - "rawText": "" - }, - { - "id": "MQHxfD9E", - "type": "text", - "x": 2228.373028506635, - "y": -7.374180692542097, - "width": 258.9197998046875, - "height": 100, - "angle": 0, - "strokeColor": "#ff8c00", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1934236278, - "version": 445, - "versionNonce": 1517146660, - "isDeleted": false, - "boundElements": [], - "updated": 1747512966415, - "link": null, - "locked": false, - "text": "Agent Core \n(IAgentCore)\\n(Swappable \nComponent)\\n(e.g., \nPESAgent)", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 93, - "containerId": "W5qvMe8KlQXemvhLQiOix", - "originalText": "Agent Core \n(IAgentCore)\\n(Swappable \nComponent)\\n(e.g., \nPESAgent)", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0L", - "rawText": "" - }, - { - "id": "H0Wpr7vI", - "type": "text", - "x": 304.97240447998047, - "y": 453.5, - "width": 150.35987854003906, - "height": 25, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 913433258, - "version": 3, - "versionNonce": 1437328796, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808426, - "link": null, - "locked": false, - "text": "ReasoningEngine", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "SfB6bkbUXw5bc6NQ3u3CQ", - "originalText": "ReasoningEngine", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0M", - "rawText": "" - }, - { - "id": "Xy5CbkqK", - "type": "text", - "x": 121.3919448852539, - "y": 587, - "width": 159.5598602294922, - "height": 25, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1278475626, - "version": 3, - "versionNonce": 396612132, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808426, - "link": null, - "locked": false, - "text": "ProviderManager", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "oH7-849XX0DMcLjGMkqgh", - "originalText": "ProviderManager", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0N", - "rawText": "" - }, - { - "id": "HAzYh5Rb", - "type": "text", - "x": 61.4119873046875, - "y": 722.5, - "width": 279.519775390625, - "height": 50, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 6602794, - "version": 3, - "versionNonce": 47501852, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808426, - "link": null, - "locked": false, - "text": "ProviderAdapters\\n(OpenAI, \nAnthropic, Ollama)", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 43, - "containerId": "1MhXjLvsQgeqIyj4qPbxG", - "originalText": "ProviderAdapters\\n(OpenAI, \nAnthropic, Ollama)", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0O", - "rawText": "" - }, - { - "id": "KnZ9Zywi", - "type": "text", - "x": 45.60356140136719, - "y": 293, - "width": 305.8397521972656, - "height": 50, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1592732394, - "version": 3, - "versionNonce": 1596845476, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808426, - "link": null, - "locked": false, - "text": "PromptManager\\n(fragments/va\nlidation)", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 43, - "containerId": "n0dbkZlx-ckln9jeXtq5A", - "originalText": "PromptManager\\n(fragments/va\nlidation)", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0P", - "rawText": "" - }, - { - "id": "3e2vCnbo", - "type": "text", - "x": 365.1122589111328, - "y": 587, - "width": 135.25985717773438, - "height": 25, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 200100342, - "version": 3, - "versionNonce": 1697394332, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808426, - "link": null, - "locked": false, - "text": "OutputParser", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "-jXFqjFNJ_U939E2ievGn", - "originalText": "OutputParser", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0Q", - "rawText": "" - }, - { - "id": "Kp4mPUzT", - "type": "text", - "x": 105.73193359375, - "y": 908, - "width": 190.8798828125, - "height": 25, - "angle": 0, - "strokeColor": "#d9d9d9", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 115120950, - "version": 3, - "versionNonce": 1978177828, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808426, - "link": null, - "locked": false, - "text": "External LLM APIs", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "S3-08Iat6bZgsq1wFapu6", - "originalText": "External LLM APIs", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0R", - "rawText": "" - }, - { - "id": "TxFcAwHC", - "type": "text", - "x": 789.1328578289097, - "y": 477.07439619974605, - "width": 110.79988098144531, - "height": 25, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": null, - "seed": 575652982, - "version": 124, - "versionNonce": 1407797660, - "isDeleted": false, - "boundElements": [], - "updated": 1747513105800, - "link": null, - "locked": false, - "text": "ToolSystem", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "kCozrr01nlraRu2GIkt9_", - "originalText": "ToolSystem", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0S", - "rawText": "" - }, - { - "id": "h2eOp3kK", - "type": "text", - "x": 654.3120956420898, - "y": 587, - "width": 122.53987121582031, - "height": 25, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1342948790, - "version": 36, - "versionNonce": 1336810148, - "isDeleted": false, - "boundElements": [], - "updated": 1747513100132, - "link": null, - "locked": false, - "text": "ToolRegistry", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "zeFiM-fefB7tFSa7MetB1", - "originalText": "ToolRegistry", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0T", - "rawText": "" - }, - { - "id": "1yjS61qu", - "type": "text", - "x": 845.4855651855469, - "y": 574.5, - "width": 201.73980712890625, - "height": 50, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": null, - "seed": 20291318, - "version": 36, - "versionNonce": 1573999004, - "isDeleted": false, - "boundElements": [], - "updated": 1747513100132, - "link": null, - "locked": false, - "text": "IToolExecutor\\n(spe\ncific tools)", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 43, - "containerId": "NG7OwzM5aEDpJbCBm4I4Q", - "originalText": "IToolExecutor\\n(spe\ncific tools)", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0U", - "rawText": "" - }, - { - "id": "9PwBIBib", - "type": "text", - "x": 2222.65305780351, - "y": 295.1258193074579, - "width": 310.3597412109375, - "height": 50, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 115504682, - "version": 445, - "versionNonce": 283915556, - "isDeleted": false, - "boundElements": [], - "updated": 1747512966416, - "link": null, - "locked": false, - "text": "StateManager\\n(ThreadConfig, \nAgentState)", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 43, - "containerId": "B15clfWBgo09caHAgqD18", - "originalText": "StateManager\\n(ThreadConfig, \nAgentState)", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0V", - "rawText": "" - }, - { - "id": "hwHeNZbZ", - "type": "text", - "x": 2593.782726992963, - "y": 295.1258193074579, - "width": 277.45977783203125, - "height": 50, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 2017861866, - "version": 445, - "versionNonce": 2071101092, - "isDeleted": false, - "boundElements": [], - "updated": 1747512966416, - "link": null, - "locked": false, - "text": "ConversationManager\\n(mess\nage history)", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 43, - "containerId": "dO7lpvt19HOndHW0OJZlg", - "originalText": "ConversationManager\\n(mess\nage history)", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0W", - "rawText": "" - }, - { - "id": "2NDcNMzv", - "type": "text", - "x": 2454.285069217084, - "y": -148.8741806925421, - "width": 216.75978088378906, - "height": 50, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 153842678, - "version": 445, - "versionNonce": 1343501220, - "isDeleted": false, - "boundElements": [], - "updated": 1747512966416, - "link": null, - "locked": false, - "text": "ContextProvider\\n(fut\nure: RAG)", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 43, - "containerId": "3p3g2_aDpLLl3sK9WrWlY", - "originalText": "ContextProvider\\n(fut\nure: RAG)", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0X", - "rawText": "" - }, - { - "id": "MvlV8qBk", - "type": "text", - "x": 2353.199261416791, - "y": 455.6258193074579, - "width": 160.079833984375, - "height": 25, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 237572394, - "version": 445, - "versionNonce": 1944823332, - "isDeleted": false, - "boundElements": [], - "updated": 1747512966416, - "link": null, - "locked": false, - "text": "StateRepository", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "lIGXJaWPoGERNsZ8MbuqX", - "originalText": "StateRepository", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0Y", - "rawText": "" - }, - { - "id": "Q4W281nw", - "type": "text", - "x": 2658.3802306550724, - "y": 455.6258193074579, - "width": 224.6397705078125, - "height": 25, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 838949866, - "version": 445, - "versionNonce": 1084584996, - "isDeleted": false, - "boundElements": [], - "updated": 1747512966416, - "link": null, - "locked": false, - "text": "ConversationRepository", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "VwpDW7hQ2y1gV_p4Qjefs", - "originalText": "ConversationRepository", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0Z", - "rawText": "" - }, - { - "id": "55XJHKVo", - "type": "text", - "x": 3186.4233627319336, - "y": 587, - "width": 195.8798370361328, - "height": 25, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ObservationSystem" - ], - "frameId": null, - "roundness": null, - "seed": 839012010, - "version": 3, - "versionNonce": 70225180, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808426, - "link": null, - "locked": false, - "text": "ObservationManager", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "QB41BH_LXmwNl6d7tdXkb", - "originalText": "ObservationManager", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0a", - "rawText": "" - }, - { - "id": "0efd7pDo", - "type": "text", - "x": 3186.3533935546875, - "y": 735, - "width": 216.019775390625, - "height": 25, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ObservationSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1389816170, - "version": 3, - "versionNonce": 1110467236, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808426, - "link": null, - "locked": false, - "text": "ObservationRepository", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "KBqtRn3VIpr89SHW9njcj", - "originalText": "ObservationRepository", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0b", - "rawText": "" - }, - { - "id": "p2T3xMHp", - "type": "text", - "x": 2744.6429290771484, - "y": 895.5, - "width": 286.9797668457031, - "height": 50, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": null, - "seed": 197798954, - "version": 3, - "versionNonce": 24611228, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808426, - "link": null, - "locked": false, - "text": "StorageAdapter\\n(InMemory, \nIndexedDB, etc.)", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 43, - "containerId": "w_DIadNSyinMWmUmnEqPM", - "originalText": "StorageAdapter\\n(InMemory, \nIndexedDB, etc.)", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0c", - "rawText": "" - }, - { - "id": "atorKxrP", - "type": "text", - "x": 1610.129278611344, - "y": 637.7037965756168, - "width": 92.47991943359375, - "height": 25, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 851908330, - "version": 46, - "versionNonce": 2136032924, - "isDeleted": false, - "boundElements": [], - "updated": 1747513142232, - "link": null, - "locked": false, - "text": "UISystem", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "PaWaEo1Abq__A4JEDiqap", - "originalText": "UISystem", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0d", - "rawText": "" - }, - { - "id": "OrKf1Bqf", - "type": "text", - "x": 1355.2204040996253, - "y": 785.7037965756168, - "width": 173.53985595703125, - "height": 25, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 676899242, - "version": 46, - "versionNonce": 740664604, - "isDeleted": false, - "boundElements": [], - "updated": 1747513142232, - "link": null, - "locked": false, - "text": "LLMStreamSocket", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "vkVwaoeJVwaTEzRWm-s_Y", - "originalText": "LLMStreamSocket", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0e", - "rawText": "" - }, - { - "id": "WtED8nec", - "type": "text", - "x": 1618.8391708842933, - "y": 785.7037965756168, - "width": 180.2398223876953, - "height": 25, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 61465706, - "version": 48, - "versionNonce": 1300635676, - "isDeleted": false, - "boundElements": [], - "updated": 1747513142233, - "link": null, - "locked": false, - "text": "ObservationSocket", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "kY_wuaVOzF4Sp6nKmUQFk", - "originalText": "ObservationSocket", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0f", - "rawText": "" - }, - { - "id": "c6DjxQG6", - "type": "text", - "x": 1892.8807358256995, - "y": 785.7037965756168, - "width": 188.8598175048828, - "height": 25, - "angle": 0, - "strokeColor": "#1890ff", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 1048954666, - "version": 46, - "versionNonce": 782405276, - "isDeleted": false, - "boundElements": [], - "updated": 1747513142233, - "link": null, - "locked": false, - "text": "ConversationSocket", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "62Ho1mH47pmV4BJ_NQ2oL", - "originalText": "ConversationSocket", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0g", - "rawText": "" - }, - { - "id": "49upoErM", - "type": "text", - "x": 1623.723242234391, - "y": 958.7037965756168, - "width": 236.7998046875, - "height": 25, - "angle": 0, - "strokeColor": "#d9d9d9", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 1633112554, - "version": 46, - "versionNonce": 933883164, - "isDeleted": false, - "boundElements": [], - "updated": 1747513142233, - "link": null, - "locked": false, - "text": "External UI/Subscribers", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "x7ls2lE6KYKx-KMGGm5Fu", - "originalText": "External UI/Subscribers", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0h", - "rawText": "" - }, - { - "id": "g4qjUfXH", - "type": "text", - "x": 1308.7178955078125, - "y": 305.5, - "width": 190.579833984375, - "height": 25, - "angle": 0, - "strokeColor": "#52c41a", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 791250090, - "version": 3, - "versionNonce": 933371676, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808426, - "link": null, - "locked": false, - "text": "ArtStandardPrompt", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "cTRHaRl9GkFPHwBwMiQZr", - "originalText": "ArtStandardPrompt", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0i", - "rawText": "" - }, - { - "id": "75C0lJKs", - "type": "text", - "x": 1107.6892700195312, - "y": 587, - "width": 124.5198974609375, - "height": 25, - "angle": 0, - "strokeColor": "#52c41a", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 1369923434, - "version": 3, - "versionNonce": 577237156, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808426, - "link": null, - "locked": false, - "text": "StreamEvent", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "aARlt45sQryQeEVW_Thz0", - "originalText": "StreamEvent", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0j", - "rawText": "" - }, - { - "id": "D3XJclhq", - "type": "text", - "x": 3105.9555815282183, - "y": 43.815963964758396, - "width": 106.77989196777344, - "height": 25, - "angle": 0, - "strokeColor": "#52c41a", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 85713450, - "version": 43, - "versionNonce": 790051620, - "isDeleted": false, - "boundElements": [], - "updated": 1747512857850, - "link": null, - "locked": false, - "text": "ToolResult", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "Y3_dUxyHxFJheks_MDkc9", - "originalText": "ToolResult", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0k", - "rawText": "" - }, - { - "id": "iQLg1TgV", - "type": "text", - "x": 3300.845993041992, - "y": 453.5, - "width": 114.97988891601562, - "height": 25, - "angle": 0, - "strokeColor": "#52c41a", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 1148325098, - "version": 3, - "versionNonce": 1760181284, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808426, - "link": null, - "locked": false, - "text": "Observation", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "3voYkLasWeQVzwsi1jgdS", - "originalText": "Observation", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0l", - "rawText": "" - }, - { - "id": "ejZrKkcC", - "type": "text", - "x": 3005.5522842407227, - "y": 453.5, - "width": 205.8798065185547, - "height": 25, - "angle": 0, - "strokeColor": "#52c41a", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 1966399402, - "version": 3, - "versionNonce": 520226844, - "isDeleted": false, - "boundElements": [], - "updated": 1747512808426, - "link": null, - "locked": false, - "text": "ConversationMessage", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "Fe80a-MSX0vqFJVOO7HKn", - "originalText": "ConversationMessage", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0m", - "rawText": "" - }, - { - "id": "wUiXPyCn", - "type": "text", - "x": 2039.1405512635852, - "y": -257.6862019143702, - "width": 176.49984741210938, - "height": 25, - "angle": 0, - "strokeColor": "#52c41a", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 328161898, - "version": 91, - "versionNonce": 1655887780, - "isDeleted": false, - "boundElements": [], - "updated": 1747512973166, - "link": null, - "locked": false, - "text": "ArtInstanceConfig", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "QTTzOs_-veCzl_jw2X31X", - "originalText": "ArtInstanceConfig", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0n", - "rawText": "" - } - ], - "appState": { - "theme": "light", - "viewBackgroundColor": "#fafafa", - "currentItemStrokeColor": "#1e1e1e", - "currentItemBackgroundColor": "transparent", - "currentItemFillStyle": "solid", - "currentItemStrokeWidth": 2, - "currentItemStrokeStyle": "solid", - "currentItemRoughness": 1, - "currentItemOpacity": 100, - "currentItemFontFamily": 5, - "currentItemFontSize": 20, - "currentItemTextAlign": "left", - "currentItemStartArrowhead": null, - "currentItemEndArrowhead": "arrow", - "currentItemArrowType": "round", - "scrollX": -1901.5836002936405, - "scrollY": 96.7028518085739, - "zoom": { - "value": 0.631037 - }, - "currentItemRoundness": "round", - "gridSize": 20, - "gridStep": 5, - "gridModeEnabled": false, - "gridColor": { - "Bold": "rgba(212, 212, 212, 0.5)", - "Regular": "rgba(225, 225, 225, 0.5)" - }, - "currentStrokeOptions": null, - "frameRendering": { - "enabled": true, - "clip": true, - "name": true, - "outline": true - }, - "objectsSnapModeEnabled": false, - "activeTool": { - "type": "selection", - "customType": null, - "locked": false, - "fromSelection": false, - "lastActiveTool": null - } - }, - "files": {} -} \ No newline at end of file diff --git a/Docs/diagrams/welcome.excalidraw b/Docs/diagrams/welcome.excalidraw deleted file mode 100644 index e8dae40..0000000 --- a/Docs/diagrams/welcome.excalidraw +++ /dev/null @@ -1,4742 +0,0 @@ -{ - "type": "excalidraw", - "version": 2, - "source": "https://github.com/zsviczian/obsidian-excalidraw-plugin/releases/tag/2.11.1", - "elements": [ - { - "id": "VPfPMNLRWkwzonCSXIYLZ", - "type": "rectangle", - "x": -76.31486551771093, - "y": 451.1397422545674, - "width": 868.046875, - "height": 94, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 1008284214, - "version": 67, - "versionNonce": 106320292, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "KltyqPy9" - }, - { - "id": "1BHdgQDvuwmDs-pCepPoz", - "type": "arrow" - }, - { - "id": "nLvqc2BxWpnSY-jNd79-4", - "type": "arrow" - } - ], - "updated": 1747513343298, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a0" - }, - { - "id": "RSa7Jt3zKEhpF5JWR2fRY", - "type": "rectangle", - "x": 1902.13671875, - "y": 794.0323791503906, - "width": 962.46875, - "height": 188, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": null, - "seed": 317895722, - "version": 4, - "versionNonce": 1300859164, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "ViLD3QuP" - }, - { - "id": "g_ajRSGZJEERB5odra2VC", - "type": "arrow" - }, - { - "id": "DQtJWbwYeO_2v-QGvrmjr", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a1" - }, - { - "id": "Rxzd61qD4XgT0hMwuTYsJ", - "type": "rectangle", - "x": 3071.3515625, - "y": 411.5161895751953, - "width": 343.421875, - "height": 188, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ObservationSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1373731702, - "version": 4, - "versionNonce": 1350837924, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "9BYEyPRK" - }, - { - "id": "oBgDTKyuxYgxzV3RTOBHr", - "type": "arrow" - }, - { - "id": "DQtJWbwYeO_2v-QGvrmjr", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a2" - }, - { - "id": "0vHS-qpxa-_RvRQktVyOJ", - "type": "rectangle", - "x": 1119.21875, - "y": 411.5161895751953, - "width": 808.921875, - "height": 188, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1402904298, - "version": 4, - "versionNonce": 103941532, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "UQRUsZu5" - }, - { - "id": "L741GngnujCHOjKognS3E", - "type": "arrow" - }, - { - "id": "g_ajRSGZJEERB5odra2VC", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a3" - }, - { - "id": "FPTrGtMNGx5zLZj8WlPSK", - "type": "rectangle", - "x": 1978.140625, - "y": 364.5161895751953, - "width": 246.328125, - "height": 282, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": null, - "seed": 844012726, - "version": 3, - "versionNonce": 839889444, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "Szf5hNut" - }, - { - "id": "2NBu3777GHjpsJIg5zXnw", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a4" - }, - { - "id": "lEjxG2AwBKADL00RyOHtr", - "type": "rectangle", - "x": 2274.46875, - "y": 296, - "width": 746.8828125, - "height": 419.0323791503906, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1426010538, - "version": 3, - "versionNonce": 2107044380, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "Emj9hTJo" - }, - { - "id": "64S_IQCfsyV44zqCyDhOZ", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a5" - }, - { - "id": "E1QuceF-qIW0DHGKGAuWl", - "type": "rectangle", - "x": 1211.796875, - "y": 0, - "width": 623.765625, - "height": 217, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_AgentCore" - ], - "frameId": null, - "roundness": null, - "seed": 1661310454, - "version": 9, - "versionNonce": 18730404, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "WbqVmO7G" - }, - { - "id": "mj1xWgZrMSX7pTIJu10Q4", - "type": "arrow" - }, - { - "id": "S3HyRJ-dkTWkYt-cWhCmG", - "type": "arrow" - }, - { - "id": "64S_IQCfsyV44zqCyDhOZ", - "type": "arrow" - }, - { - "id": "2NBu3777GHjpsJIg5zXnw", - "type": "arrow" - }, - { - "id": "L741GngnujCHOjKognS3E", - "type": "arrow" - }, - { - "id": "oBgDTKyuxYgxzV3RTOBHr", - "type": "arrow" - }, - { - "id": "1BHdgQDvuwmDs-pCepPoz", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a6" - }, - { - "id": "GPkMah5NFJH15JGB_VIAL", - "type": "rectangle", - "x": 942.4453125, - "y": 866.0323791503906, - "width": 75.6875, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 3 - }, - "seed": 1782541418, - "version": 4, - "versionNonce": 44715676, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "KzwHcZIm" - }, - { - "id": "Q7aU3JkcXPsIhipbAO9uL", - "type": "arrow" - }, - { - "id": "Ujr21ePPP6oOgGctEGihy", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a7" - }, - { - "id": "OF2UjoJ7_fOrczm-BVK48", - "type": "rectangle", - "x": 918.046875, - "y": 483.5161895751953, - "width": 124.484375, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 1829463862, - "version": 7, - "versionNonce": 44120228, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "EnUnslNY" - }, - { - "id": "Q7aU3JkcXPsIhipbAO9uL", - "type": "arrow" - }, - { - "id": "mj1xWgZrMSX7pTIJu10Q4", - "type": "arrow" - }, - { - "id": "S3HyRJ-dkTWkYt-cWhCmG", - "type": "arrow" - }, - { - "id": "Ujr21ePPP6oOgGctEGihy", - "type": "arrow" - }, - { - "id": "nLvqc2BxWpnSY-jNd79-4", - "type": "arrow" - } - ], - "updated": 1747513343298, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a8" - }, - { - "id": "m4_zE8HuJeXh9RPDdE_ZN", - "type": "rectangle", - "x": 1461.93359375, - "y": 25, - "width": 160.1875, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_AgentCore" - ], - "frameId": null, - "roundness": null, - "seed": 1227509546, - "version": 4, - "versionNonce": 907942684, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "N1Z0JjbU" - }, - { - "id": "5toePMdlA07PBXG0eOuUl", - "type": "arrow" - }, - { - "id": "y5EOFdOTHUWxlKYXDriNF", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "a9" - }, - { - "id": "5PHWuavyCK7RsbpnG5AG4", - "type": "rectangle", - "x": 1246.796875, - "y": 119, - "width": 288.578125, - "height": 73, - "angle": 0, - "strokeColor": "#333", - "backgroundColor": "#f9f", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_AgentCore" - ], - "frameId": null, - "roundness": null, - "seed": 1891962998, - "version": 3, - "versionNonce": 1455010980, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "c1nxSVSm" - }, - { - "id": "5toePMdlA07PBXG0eOuUl", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aA" - }, - { - "id": "FJMkSho2yrp8sB-kTkM_h", - "type": "rectangle", - "x": 1585.375, - "y": 119, - "width": 215.1875, - "height": 73, - "angle": 0, - "strokeColor": "#333", - "backgroundColor": "#f9f", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_AgentCore" - ], - "frameId": null, - "roundness": null, - "seed": 908777962, - "version": 3, - "versionNonce": 1382307740, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "xWMksOpz" - }, - { - "id": "y5EOFdOTHUWxlKYXDriNF", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aB" - }, - { - "id": "9YnU_6TC81D8GiTlsjJuD", - "type": "rectangle", - "x": 2564.8046875, - "y": 321, - "width": 207.40625, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 972526006, - "version": 5, - "versionNonce": 912490532, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "LfVFlrMg" - }, - { - "id": "PNm0EwDbCKfv2NjGMLlXj", - "type": "arrow" - }, - { - "id": "kh1VkhHrBgi-oO4_NxEZ0", - "type": "arrow" - }, - { - "id": "IMUa8txOUzEwjXzQ1MktK", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aC" - }, - { - "id": "VycM3UrTDvjrih5cknB6_", - "type": "rectangle", - "x": 2311.5546875, - "y": 415, - "width": 208.65625, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 810290346, - "version": 4, - "versionNonce": 1940849692, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "cOMnSZkk" - }, - { - "id": "PNm0EwDbCKfv2NjGMLlXj", - "type": "arrow" - }, - { - "id": "U016KECMfqeUzZT7elfCI", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aD" - }, - { - "id": "aYh5YisIweGQwwfVH1aKE", - "type": "rectangle", - "x": 2570.2109375, - "y": 415, - "width": 196.59375, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1405610742, - "version": 3, - "versionNonce": 633854884, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "3t4Jodoi" - }, - { - "id": "kh1VkhHrBgi-oO4_NxEZ0", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aE" - }, - { - "id": "f2vVAFqI51h48IMdNISmg", - "type": "rectangle", - "x": 2816.8046875, - "y": 415, - "width": 169.546875, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 490268522, - "version": 3, - "versionNonce": 1609572508, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "yOObjnmV" - }, - { - "id": "IMUa8txOUzEwjXzQ1MktK", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aF" - }, - { - "id": "BohaQWZW3shJzcJRkRWZX", - "type": "rectangle", - "x": 2309.46875, - "y": 509, - "width": 212.828125, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 482024502, - "version": 4, - "versionNonce": 1863632676, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "YLAvAE3q" - }, - { - "id": "U016KECMfqeUzZT7elfCI", - "type": "arrow" - }, - { - "id": "qwKRx2GYDaG4aMAYXFrwn", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aG" - }, - { - "id": "b4o_hgCUk0AB9FfzDZ6dv", - "type": "rectangle", - "x": 2331.75, - "y": 602.9999956144617, - "width": 168.265625, - "height": 87.03238677978516, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1966893610, - "version": 3, - "versionNonce": 1322888476, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "YxNRq994" - }, - { - "id": "qwKRx2GYDaG4aMAYXFrwn", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aH" - }, - { - "id": "CJ_6lGAlgdP37BlLtl9_M", - "type": "rectangle", - "x": 2027.84375, - "y": 389.5161895751953, - "width": 146.921875, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1521886582, - "version": 3, - "versionNonce": 1723351716, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "YojuWZGD" - }, - { - "id": "AH74Pr0DGRMfJPVgsIos-", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aI" - }, - { - "id": "z8hLGazKLyxkod6I2KpXc", - "type": "rectangle", - "x": 2022.765625, - "y": 483.5161895751953, - "width": 157.078125, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1866568938, - "version": 4, - "versionNonce": 836610460, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "56oJlZtf" - }, - { - "id": "AH74Pr0DGRMfJPVgsIos-", - "type": "arrow" - }, - { - "id": "OjDHjopBjv6ysMTNS5o7x", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aJ" - }, - { - "id": "IvRAJCaYbB5TnQVgxjk1U", - "type": "rectangle", - "x": 2013.140625, - "y": 577.5161895751953, - "width": 176.328125, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1325270710, - "version": 3, - "versionNonce": 593514020, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "1sdD0OOs" - }, - { - "id": "OjDHjopBjv6ysMTNS5o7x", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aK" - }, - { - "id": "B3HiH9ZTnqaZSRhVZdwK_", - "type": "rectangle", - "x": 1154.21875, - "y": 436.5161895751953, - "width": 174.71875, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 752052138, - "version": 3, - "versionNonce": 2083395100, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "fhhog7ZP" - }, - { - "id": "Np9fh3F5ZAr2fVTOMMKVz", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aL" - }, - { - "id": "IiKZEPQZJEFS28_K1m7g6", - "type": "rectangle", - "x": 1378.9375, - "y": 436.5161895751953, - "width": 261.09375, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1245167606, - "version": 3, - "versionNonce": 905636260, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "RD954mGA" - }, - { - "id": "4b3gYHONr1zZUbJaydVcD", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aM" - }, - { - "id": "TW6DTYIrKH675pI6E9K5s", - "type": "rectangle", - "x": 1690.03125, - "y": 436.5161895751953, - "width": 203.109375, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1713169002, - "version": 3, - "versionNonce": 1790767772, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "TlnXtn2E" - }, - { - "id": "Zqr85WSLKxZ6tVvwToeQN", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aN" - }, - { - "id": "-blMmdM2sMEMs7RDsp6CG", - "type": "rectangle", - "x": 1434.1328125, - "y": 530.5161895751953, - "width": 150.703125, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1080578358, - "version": 5, - "versionNonce": 1639322916, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "m8XYC2iT" - }, - { - "id": "Np9fh3F5ZAr2fVTOMMKVz", - "type": "arrow" - }, - { - "id": "4b3gYHONr1zZUbJaydVcD", - "type": "arrow" - }, - { - "id": "Zqr85WSLKxZ6tVvwToeQN", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aO" - }, - { - "id": "s_W3K7i9ijY7WqbM3_8L1", - "type": "rectangle", - "x": 3118.140625, - "y": 436.5161895751953, - "width": 249.84375, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ObservationSystem" - ], - "frameId": null, - "roundness": null, - "seed": 367592746, - "version": 3, - "versionNonce": 1279016732, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "6k416seh" - }, - { - "id": "HN6Xq0LBItub0E3z1Scsv", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aP" - }, - { - "id": "ZgAbrcKcdjMWdoMQX1Ld9", - "type": "rectangle", - "x": 3106.3515625, - "y": 530.5161895751953, - "width": 273.421875, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ObservationSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1559542390, - "version": 3, - "versionNonce": 1409274020, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "Ea3dugTq" - }, - { - "id": "HN6Xq0LBItub0E3z1Scsv", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aQ" - }, - { - "id": "wNDNcGSK82UKeHWAmXIi2", - "type": "rectangle", - "x": 2331.60546875, - "y": 819.0323791503906, - "width": 210.390625, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": null, - "seed": 631427050, - "version": 5, - "versionNonce": 1226701724, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "xPtHfhaX" - }, - { - "id": "ZJ5sD0oVEYl0dR5ZCP3SG", - "type": "arrow" - }, - { - "id": "61wXDw3LPAbuoLPoDD5DM", - "type": "arrow" - }, - { - "id": "By0NRpRb7i7lx6JZWZnn3", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aR" - }, - { - "id": "mxEcOuNAtKZ9jT2-WCrTa", - "type": "rectangle", - "x": 1937.13671875, - "y": 913.0323791503906, - "width": 296.59375, - "height": 44, - "angle": 0, - "strokeColor": "#333", - "backgroundColor": "#bbf", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": null, - "seed": 379714486, - "version": 3, - "versionNonce": 1552292900, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "9K4r09UC" - }, - { - "id": "ZJ5sD0oVEYl0dR5ZCP3SG", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aS" - }, - { - "id": "XxSBUOmFtHHG_2C7dr7xL", - "type": "rectangle", - "x": 2283.73046875, - "y": 913.0323791503906, - "width": 306.140625, - "height": 44, - "angle": 0, - "strokeColor": "#333", - "backgroundColor": "#bbf", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": null, - "seed": 425018026, - "version": 3, - "versionNonce": 731129884, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "96jLH6LI" - }, - { - "id": "61wXDw3LPAbuoLPoDD5DM", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aT" - }, - { - "id": "uDXbez1t0OYlGd-AfXDtl", - "type": "rectangle", - "x": 2639.87109375, - "y": 913.0323791503906, - "width": 189.734375, - "height": 44, - "angle": 0, - "strokeColor": "#333", - "backgroundColor": "#bbf", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1133843702, - "version": 3, - "versionNonce": 624359332, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "dsEfyy4X" - }, - { - "id": "By0NRpRb7i7lx6JZWZnn3", - "type": "arrow" - } - ], - "updated": 1747513248859, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aU" - }, - { - "id": "bvNnML6gAoXVRk8c3LLAp", - "type": "rectangle", - "x": -41.31486551771093, - "y": 476.1397422545674, - "width": 241.515625, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 1001086314, - "version": 65, - "versionNonce": 2081173916, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "3LpsQ6LR" - } - ], - "updated": 1747513337567, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aV" - }, - { - "id": "qqx_UdBiU870V2hK50TeG", - "type": "rectangle", - "x": 250.20075948228907, - "y": 476.1397422545674, - "width": 230.25, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 760415798, - "version": 65, - "versionNonce": 1357478556, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "OsJnZcC2" - } - ], - "updated": 1747513337567, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aW" - }, - { - "id": "9ftUQCnF77Xi-hFy0r03v", - "type": "rectangle", - "x": 530.4507594822891, - "y": 476.1397422545674, - "width": 226.28125, - "height": 44, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 1240473642, - "version": 65, - "versionNonce": 1674085276, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "9DzmMXRp" - } - ], - "updated": 1747513337567, - "link": null, - "locked": false, - "customData": { - "legacyTextWrap": true - }, - "index": "aX" - }, - { - "id": "Q7aU3JkcXPsIhipbAO9uL", - "type": "arrow", - "x": 1017.0174861317558, - "y": 869.174778678055, - "width": 233.20899999999995, - "height": 337.99277867805495, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 616615798, - "version": 6, - "versionNonce": 1536776484, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "XiUqyZrr" - } - ], - "updated": 1747513248935, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 223.27951386824418, - -114.64277867805492 - ], - [ - -9.929486131755766, - -337.99277867805495 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "GPkMah5NFJH15JGB_VIAL", - "focus": 0.000013819091065176624, - "gap": 1 - }, - "endBinding": { - "elementId": "OF2UjoJ7_fOrczm-BVK48", - "focus": -0.0000023490095228784116, - "gap": 3.665810424804704 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "customData": { - "legacyTextWrap": true - }, - "index": "aY" - }, - { - "id": "mj1xWgZrMSX7pTIJu10Q4", - "type": "arrow", - "x": 1004.1167878508902, - "y": 482.51618957519537, - "width": 305.48721214910984, - "height": 263.07318957519533, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 537823978, - "version": 6, - "versionNonce": 953848996, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "1Od3L8Ix" - } - ], - "updated": 1747513248935, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 234.14921214910987, - -226.01618957519537 - ], - [ - 305.48721214910984, - -263.07318957519533 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "OF2UjoJ7_fOrczm-BVK48", - "focus": 0.000001030781908091472, - "gap": 1 - }, - "endBinding": { - "elementId": "E1QuceF-qIW0DHGKGAuWl", - "focus": 0.0009613114512232763, - "gap": 2.4430000000000405 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "customData": { - "legacyTextWrap": true - }, - "index": "aZ" - }, - { - "id": "S3HyRJ-dkTWkYt-cWhCmG", - "type": "arrow", - "x": 1210.796875, - "y": 167.7338340520139, - "width": 468.124875, - "height": 311.9481659479862, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 371421366, - "version": 6, - "versionNonce": 1634230308, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "ULs2vtwn" - } - ], - "updated": 1747513248935, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -468.124875, - 88.76616594798611 - ], - [ - -255.15987500000028, - 311.9481659479862 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "E1QuceF-qIW0DHGKGAuWl", - "focus": 0.0005680257290096401, - "gap": 1 - }, - "endBinding": { - "elementId": "OF2UjoJ7_fOrczm-BVK48", - "focus": -0.000006375236103738962, - "gap": 3.834189575195296 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "customData": { - "legacyTextWrap": true - }, - "index": "aa" - }, - { - "id": "Ujr21ePPP6oOgGctEGihy", - "type": "arrow", - "x": 976.2242212420483, - "y": 528.5161895751953, - "width": 39.94722124204827, - "height": 334.83173136673247, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1687264682, - "version": 6, - "versionNonce": 1563474852, - "isDeleted": false, - "boundElements": [ - { - "type": "text", - "id": "dPqBMtdP" - } - ], - "updated": 1747513248935, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -39.94722124204827, - 226.01581042480473 - ], - [ - -4.072829880765994, - 334.83173136673247 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "OF2UjoJ7_fOrczm-BVK48", - "focus": -0.000004529297386038403, - "gap": 1 - }, - "endBinding": { - "elementId": "GPkMah5NFJH15JGB_VIAL", - "focus": 0.0000064669825041813355, - "gap": 5.033379150390601 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "customData": { - "legacyTextWrap": true - }, - "index": "ab" - }, - { - "id": "5toePMdlA07PBXG0eOuUl", - "type": "arrow", - "x": 1470.191492977528, - "y": 70, - "width": 79.10561797752803, - "height": 48, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_AgentCore" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 488630774, - "version": 6, - "versionNonce": 888483364, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248935, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -79.10561797752803, - 24 - ], - [ - -79.10561797752803, - 48 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "m4_zE8HuJeXh9RPDdE_ZN", - "focus": -0.026038738186955224, - "gap": 1 - }, - "endBinding": { - "elementId": "5PHWuavyCK7RsbpnG5AG4", - "focus": -4.3315826528939384e-7, - "gap": 1 - }, - "startArrowhead": null, - "endArrowhead": null, - "index": "ac" - }, - { - "id": "y5EOFdOTHUWxlKYXDriNF", - "type": "arrow", - "x": 1614.82633888443, - "y": 70, - "width": 78.14253611557001, - "height": 48, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_AgentCore" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 883185770, - "version": 6, - "versionNonce": 32754084, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248935, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 78.14253611557001, - 24 - ], - [ - 78.14243855452696, - 48 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "m4_zE8HuJeXh9RPDdE_ZN", - "focus": 0.013759170343023673, - "gap": 1 - }, - "endBinding": { - "elementId": "FJMkSho2yrp8sB-kTkM_h", - "focus": 0.0000011617775198416809, - "gap": 1 - }, - "startArrowhead": null, - "endArrowhead": null, - "index": "ad" - }, - { - "id": "PNm0EwDbCKfv2NjGMLlXj", - "type": "arrow", - "x": 2563.8046875, - "y": 362.4800553284605, - "width": 147.92193750000024, - "height": 47.219944671539565, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 414923574, - "version": 6, - "versionNonce": 1035982756, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248935, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -147.92193750000024, - 27.51994467153952 - ], - [ - -147.92193750000024, - 47.219944671539565 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "9YnU_6TC81D8GiTlsjJuD", - "focus": -0.00001691497947259929, - "gap": 1 - }, - "endBinding": { - "elementId": "VycM3UrTDvjrih5cknB6_", - "focus": -5.99071441570589e-7, - "gap": 5.300000000000011 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ae" - }, - { - "id": "kh1VkhHrBgi-oO4_NxEZ0", - "type": "arrow", - "x": 2668.5077500000007, - "y": 366, - "width": 9.094947017729282e-13, - "height": 43.69999999999993, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1343339306, - "version": 6, - "versionNonce": 635518628, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248935, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -9.094947017729282e-13, - 43.69999999999993 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "9YnU_6TC81D8GiTlsjJuD", - "focus": 6.026819369243366e-7, - "gap": 1 - }, - "endBinding": { - "elementId": "aYh5YisIweGQwwfVH1aKE", - "focus": -6.358289644518873e-7, - "gap": 5.300000000000011 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "af" - }, - { - "id": "IMUa8txOUzEwjXzQ1MktK", - "type": "arrow", - "x": 2773.2109375, - "y": 364.113696657571, - "width": 128.36681249999992, - "height": 45.58630334242895, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1062888566, - "version": 6, - "versionNonce": 201968164, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248935, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 128.36681249999992, - 25.886303342429017 - ], - [ - 128.36681249999947, - 45.58630334242895 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "9YnU_6TC81D8GiTlsjJuD", - "focus": -0.000014325816518476654, - "gap": 1 - }, - "endBinding": { - "elementId": "f2vVAFqI51h48IMdNISmg", - "focus": -0.000004423555433580212, - "gap": 5.300000000000011 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ag" - }, - { - "id": "U016KECMfqeUzZT7elfCI", - "type": "arrow", - "x": 2415.8827499999998, - "y": 460, - "width": 4.547473508864641e-13, - "height": 43.69999999999999, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1162135018, - "version": 6, - "versionNonce": 1142220196, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248935, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 4.547473508864641e-13, - 43.69999999999999 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "VycM3UrTDvjrih5cknB6_", - "focus": 5.99071441570589e-7, - "gap": 1 - }, - "endBinding": { - "elementId": "BohaQWZW3shJzcJRkRWZX", - "focus": -5.873283922423938e-7, - "gap": 5.300000000000011 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ah" - }, - { - "id": "qwKRx2GYDaG4aMAYXFrwn", - "type": "arrow", - "x": 2415.8827499999998, - "y": 554, - "width": 0, - "height": 43.700000000000045, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 851600822, - "version": 6, - "versionNonce": 1758121124, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248935, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 43.700000000000045 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "BohaQWZW3shJzcJRkRWZX", - "focus": 5.873283922423938e-7, - "gap": 1 - }, - "endBinding": { - "elementId": "b4o_hgCUk0AB9FfzDZ6dv", - "focus": -7.428730644195046e-7, - "gap": 5.299995614461636 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ai" - }, - { - "id": "AH74Pr0DGRMfJPVgsIos-", - "type": "arrow", - "x": 2101.3046249999998, - "y": 434.5161895751953, - "width": 4.547473508864641e-13, - "height": 43.699999999999875, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 491288746, - "version": 6, - "versionNonce": 141751204, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248935, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -4.547473508864641e-13, - 43.699999999999875 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "CJ_6lGAlgdP37BlLtl9_M", - "focus": 8.507923035981756e-7, - "gap": 1 - }, - "endBinding": { - "elementId": "z8hLGazKLyxkod6I2KpXc", - "focus": -7.957823565834721e-7, - "gap": 5.300000000000011 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "aj" - }, - { - "id": "OjDHjopBjv6ysMTNS5o7x", - "type": "arrow", - "x": 2101.3046249999998, - "y": 528.5161895751954, - "width": 0, - "height": 43.69999999999993, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 337133302, - "version": 6, - "versionNonce": 998070948, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248936, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 43.69999999999993 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "z8hLGazKLyxkod6I2KpXc", - "focus": 7.957823565834721e-7, - "gap": 1 - }, - "endBinding": { - "elementId": "IvRAJCaYbB5TnQVgxjk1U", - "focus": -7.089056296618206e-7, - "gap": 5.2999999999999545 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ak" - }, - { - "id": "Np9fh3F5ZAr2fVTOMMKVz", - "type": "arrow", - "x": 1241.5777499999997, - "y": 481.51618957519526, - "width": 187.3350000000005, - "height": 56.865000000000066, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 130536298, - "version": 6, - "versionNonce": 1903749284, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248936, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 2.2737367544323206e-13, - 24.000000000000057 - ], - [ - 187.3350000000005, - 56.865000000000066 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "B3HiH9ZTnqaZSRhVZdwK_", - "focus": 0.000004292613129116337, - "gap": 1 - }, - "endBinding": { - "elementId": "-blMmdM2sMEMs7RDsp6CG", - "focus": -9.443490029696137e-7, - "gap": 5.22006250000004 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "al" - }, - { - "id": "4b3gYHONr1zZUbJaydVcD", - "type": "arrow", - "x": 1509.484590125435, - "y": 481.51618957519537, - "width": 0.000028312887025094824, - "height": 43.69999999999999, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 400617526, - "version": 6, - "versionNonce": 454833188, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248936, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -0.000028312887025094824, - 43.69999999999999 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "IiKZEPQZJEFS28_K1m7g6", - "focus": -0.000002872531418897599, - "gap": 1 - }, - "endBinding": { - "elementId": "-blMmdM2sMEMs7RDsp6CG", - "focus": 0.000004976671851713727, - "gap": 5.2999999999999545 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "am" - }, - { - "id": "Zqr85WSLKxZ6tVvwToeQN", - "type": "arrow", - "x": 1791.5857499999997, - "y": 481.5161895751953, - "width": 201.52199999999993, - "height": 57.575000000000045, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 118347306, - "version": 6, - "versionNonce": 1498025892, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248936, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 2.2737367544323206e-13, - 24 - ], - [ - -201.5219999999997, - 57.575000000000045 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "TW6DTYIrKH675pI6E9K5s", - "focus": 0.0000018462958692891334, - "gap": 1 - }, - "endBinding": { - "elementId": "-blMmdM2sMEMs7RDsp6CG", - "focus": 0.0000028241360710501806, - "gap": 5.227812500000027 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "an" - }, - { - "id": "HN6Xq0LBItub0E3z1Scsv", - "type": "arrow", - "x": 3243.062535854237, - "y": 481.51618957519537, - "width": 0.00000471885778097203, - "height": 43.7000000000001, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ObservationSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 436304246, - "version": 6, - "versionNonce": 507344548, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248936, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -0.00000471885778097203, - 43.7000000000001 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "s_W3K7i9ijY7WqbM3_8L1", - "focus": -5.003126973567007e-7, - "gap": 1 - }, - "endBinding": { - "elementId": "ZgAbrcKcdjMWdoMQX1Ld9", - "focus": 4.5716898284094206e-7, - "gap": 5.2999999999999545 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ao" - }, - { - "id": "ZJ5sD0oVEYl0dR5ZCP3SG", - "type": "arrow", - "x": 2330.6054687499995, - "y": 855.7859814331681, - "width": 245.171877659624, - "height": 56.24639771722252, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 470122730, - "version": 6, - "versionNonce": 357237924, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248936, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -245.17174999999952, - 32.24639771722252 - ], - [ - -245.171877659624, - 56.24639771722252 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "wNDNcGSK82UKeHWAmXIi2", - "focus": -0.02193846349302634, - "gap": 1 - }, - "endBinding": { - "elementId": "mxEcOuNAtKZ9jT2-WCrTa", - "focus": 8.429038037751359e-7, - "gap": 1 - }, - "startArrowhead": null, - "endArrowhead": null, - "index": "ap" - }, - { - "id": "61wXDw3LPAbuoLPoDD5DM", - "type": "arrow", - "x": 2437.2905146683675, - "y": 864.0323791503906, - "width": 0.4897959183676903, - "height": 48, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 834591414, - "version": 6, - "versionNonce": 910872612, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248936, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -0.4897959183676903, - 24 - ], - [ - -0.4897959183676903, - 48 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "wNDNcGSK82UKeHWAmXIi2", - "focus": -0.00907877893332261, - "gap": 1 - }, - "endBinding": { - "elementId": "XxSBUOmFtHHG_2C7dr7xL", - "focus": -4.0830909154971906e-7, - "gap": 1 - }, - "startArrowhead": null, - "endArrowhead": null, - "index": "aq" - }, - { - "id": "By0NRpRb7i7lx6JZWZnn3", - "type": "arrow", - "x": 2542.99609375, - "y": 858.1881876093494, - "width": 191.74262499999986, - "height": 53.844191541041255, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1916392362, - "version": 6, - "versionNonce": 1279601572, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248937, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 191.74262499999986, - 29.844191541041255 - ], - [ - 191.74217819052456, - 53.844191541041255 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "wNDNcGSK82UKeHWAmXIi2", - "focus": 0.016334555131003802, - "gap": 1 - }, - "endBinding": { - "elementId": "uDXbez1t0OYlGd-AfXDtl", - "focus": 0.00000461171044900806, - "gap": 1 - }, - "startArrowhead": null, - "endArrowhead": null, - "index": "ar" - }, - { - "id": "64S_IQCfsyV44zqCyDhOZ", - "type": "arrow", - "x": 1840.317, - "y": 150.25000000000003, - "width": 807.0929999999998, - "height": 140.44999999999996, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1170084854, - "version": 6, - "versionNonce": 1503164580, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248934, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 807.0929999999998, - 106.24999999999997 - ], - [ - 807.0929999999994, - 140.44999999999996 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "E1QuceF-qIW0DHGKGAuWl", - "focus": 0.00044254463466146456, - "gap": 4.754500000000007 - }, - "endBinding": { - "elementId": "lEjxG2AwBKADL00RyOHtr", - "focus": -0.001339316534346265, - "gap": 5.300000000000011 - }, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "index": "as" - }, - { - "id": "2NBu3777GHjpsJIg5zXnw", - "type": "arrow", - "x": 1840.197, - "y": 189.72699999999998, - "width": 260.60799999999995, - "height": 169.48900000000003, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 198561386, - "version": 6, - "versionNonce": 2026488868, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248934, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 260.60799999999995, - 66.77300000000002 - ], - [ - 260.60799999999995, - 169.48900000000003 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "E1QuceF-qIW0DHGKGAuWl", - "focus": 0.0006842078602976483, - "gap": 4.634499999999889 - }, - "endBinding": { - "elementId": "FPTrGtMNGx5zLZj8WlPSK", - "focus": -0.004057088487156421, - "gap": 5.300189575195304 - }, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "index": "at" - }, - { - "id": "L741GngnujCHOjKognS3E", - "type": "arrow", - "x": 1523.18, - "y": 222.3, - "width": 0, - "height": 183.916, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 537142582, - "version": 6, - "versionNonce": 1254465444, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248934, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 34.19999999999999 - ], - [ - 0, - 183.916 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "E1QuceF-qIW0DHGKGAuWl", - "focus": 0.0016021642744418188, - "gap": 5.300000000000011 - }, - "endBinding": { - "elementId": "0vHS-qpxa-_RvRQktVyOJ", - "focus": -0.0012354406907340372, - "gap": 5.300189575195304 - }, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "index": "au" - }, - { - "id": "oBgDTKyuxYgxzV3RTOBHr", - "type": "arrow", - "x": 1840.3429999999998, - "y": 135.80100000000004, - "width": 1402.2200000000003, - "height": 270.41499999999996, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1839493418, - "version": 6, - "versionNonce": 934939428, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248934, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 1402.2200000000003, - 120.69899999999996 - ], - [ - 1402.2200000000003, - 270.41499999999996 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "E1QuceF-qIW0DHGKGAuWl", - "focus": 0.0003217489503438027, - "gap": 4.780500000000075 - }, - "endBinding": { - "elementId": "Rxzd61qD4XgT0hMwuTYsJ", - "focus": -0.0029089585513438717, - "gap": 5.300189575195304 - }, - "startArrowhead": "arrow", - "endArrowhead": "arrow", - "index": "av" - }, - { - "id": "g_ajRSGZJEERB5odra2VC", - "type": "arrow", - "x": 1523.18, - "y": 600.5161895751953, - "width": 373.2189999999996, - "height": 211.97281042480472, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 32902774, - "version": 6, - "versionNonce": 917925668, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248934, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 154.01581042480473 - ], - [ - 373.2189999999996, - 211.97281042480472 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "0vHS-qpxa-_RvRQktVyOJ", - "focus": 0.0012354406907340377, - "gap": 1 - }, - "endBinding": { - "elementId": "RSa7Jt3zKEhpF5JWR2fRY", - "focus": -0.00046396056313954175, - "gap": 5.737718750000113 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "aw" - }, - { - "id": "DQtJWbwYeO_2v-QGvrmjr", - "type": "arrow", - "x": 3242.563, - "y": 600.5161895751953, - "width": 373.2199999999998, - "height": 211.97281042480483, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 1259387882, - "version": 6, - "versionNonce": 919545892, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248933, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 0, - 154.01581042480473 - ], - [ - -373.2199999999998, - 211.97281042480483 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "Rxzd61qD4XgT0hMwuTYsJ", - "focus": 0.002908958551343872, - "gap": 1 - }, - "endBinding": { - "elementId": "RSa7Jt3zKEhpF5JWR2fRY", - "focus": -0.0004577506260563801, - "gap": 4.737531249999847 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ax" - }, - { - "id": "1BHdgQDvuwmDs-pCepPoz", - "type": "arrow", - "x": 1210.796875, - "y": 150.94795956445213, - "width": 836.9765330479767, - "height": 294.89159311492006, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": { - "type": 2 - }, - "seed": 945344438, - "version": 69, - "versionNonce": 507065628, - "isDeleted": false, - "boundElements": [], - "updated": 1747513337567, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - -776.773875, - 105.55204043554787 - ], - [ - -836.9765330479767, - 294.89159311492006 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "E1QuceF-qIW0DHGKGAuWl", - "focus": 0.0004518200978371146, - "gap": 1 - }, - "endBinding": { - "elementId": "VPfPMNLRWkwzonCSXIYLZ", - "focus": -0.0011530195301952455, - "gap": 5.300189575195304 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "index": "ay" - }, - { - "id": "KltyqPy9", - "type": "text", - "x": 306.4686122654922, - "y": 456.1397422545674, - "width": 102.47991943359375, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 841330346, - "version": 66, - "versionNonce": 1184934044, - "isDeleted": false, - "boundElements": [], - "updated": 1747513337567, - "link": null, - "locked": false, - "text": "UI System", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 18, - "containerId": "VPfPMNLRWkwzonCSXIYLZ", - "originalText": "UI System", - "lineHeight": 1.25, - "autoResize": true, - "index": "az", - "rawText": "" - }, - { - "id": "ViLD3QuP", - "type": "text", - "x": 2306.0011672973633, - "y": 799.0323791503906, - "width": 154.73985290527344, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": null, - "seed": 932071786, - "version": 3, - "versionNonce": 1585524644, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Storage System", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 18, - "containerId": "RSa7Jt3zKEhpF5JWR2fRY", - "originalText": "Storage System", - "lineHeight": 1.25, - "autoResize": true, - "index": "b00", - "rawText": "" - }, - { - "id": "9BYEyPRK", - "type": "text", - "x": 3146.922592163086, - "y": 416.5161895751953, - "width": 192.27981567382812, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ObservationSystem" - ], - "frameId": null, - "roundness": null, - "seed": 580226090, - "version": 3, - "versionNonce": 690359452, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Observation System", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 18, - "containerId": "Rxzd61qD4XgT0hMwuTYsJ", - "originalText": "Observation System", - "lineHeight": 1.25, - "autoResize": true, - "index": "b01", - "rawText": "" - }, - { - "id": "UQRUsZu5", - "type": "text", - "x": 1445.989761352539, - "y": 416.5161895751953, - "width": 155.37985229492188, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 421951210, - "version": 3, - "versionNonce": 1837341476, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Context System", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 18, - "containerId": "0vHS-qpxa-_RvRQktVyOJ", - "originalText": "Context System", - "lineHeight": 1.25, - "autoResize": true, - "index": "b02", - "rawText": "" - }, - { - "id": "Szf5hNut", - "type": "text", - "x": 2040.9047470092773, - "y": 369.5161895751953, - "width": 120.79988098144531, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1271663018, - "version": 3, - "versionNonce": 1383209244, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Tool System", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 18, - "containerId": "FPTrGtMNGx5zLZj8WlPSK", - "originalText": "Tool System", - "lineHeight": 1.25, - "autoResize": true, - "index": "b03", - "rawText": "" - }, - { - "id": "Emj9hTJo", - "type": "text", - "x": 2562.8302307128906, - "y": 301, - "width": 170.15985107421875, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 565265514, - "version": 3, - "versionNonce": 1479317156, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Reasoning System", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 18, - "containerId": "lEjxG2AwBKADL00RyOHtr", - "originalText": "Reasoning System", - "lineHeight": 1.25, - "autoResize": true, - "index": "b04", - "rawText": "" - }, - { - "id": "WbqVmO7G", - "type": "text", - "x": 1469.5697326660156, - "y": 5, - "width": 108.21990966796875, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_AgentCore" - ], - "frameId": null, - "roundness": null, - "seed": 1688282922, - "version": 3, - "versionNonce": 2139657628, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Agent Core", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "top", - "baseline": 18, - "containerId": "E1QuceF-qIW0DHGKGAuWl", - "originalText": "Agent Core", - "lineHeight": 1.25, - "autoResize": true, - "index": "b05", - "rawText": "" - }, - { - "id": "KzwHcZIm", - "type": "text", - "x": 957.9490814208984, - "y": 875.5323791503906, - "width": 44.679962158203125, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 1829155306, - "version": 3, - "versionNonce": 187310628, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "User", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "GPkMah5NFJH15JGB_VIAL", - "originalText": "User", - "lineHeight": 1.25, - "autoResize": true, - "index": "b06", - "rawText": "" - }, - { - "id": "EnUnslNY", - "type": "text", - "x": 929.0491027832031, - "y": 493.0161895751953, - "width": 102.47991943359375, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 1307370666, - "version": 3, - "versionNonce": 765166108, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "UI System", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "OF2UjoJ7_fOrczm-BVK48", - "originalText": "UI System", - "lineHeight": 1.25, - "autoResize": true, - "index": "b07", - "rawText": "" - }, - { - "id": "N1Z0JjbU", - "type": "text", - "x": 1487.4673919677734, - "y": 34.5, - "width": 109.11990356445312, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_AgentCore" - ], - "frameId": null, - "roundness": null, - "seed": 16695146, - "version": 3, - "versionNonce": 761937316, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "IAgentCore", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "m4_zE8HuJeXh9RPDdE_ZN", - "originalText": "IAgentCore", - "lineHeight": 1.25, - "autoResize": true, - "index": "b08", - "rawText": "" - }, - { - "id": "c1nxSVSm", - "type": "text", - "x": 1266.176040649414, - "y": 130.5, - "width": 249.81979370117188, - "height": 50, - "angle": 0, - "strokeColor": "#333", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_AgentCore" - ], - "frameId": null, - "roundness": null, - "seed": 310854186, - "version": 3, - "versionNonce": 1671224988, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "PESAgent\\nPlan-Execute-\nSynthesize", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 43, - "containerId": "5PHWuavyCK7RsbpnG5AG4", - "originalText": "PESAgent\\nPlan-Execute-\nSynthesize", - "lineHeight": 1.25, - "autoResize": true, - "index": "b09", - "rawText": "" - }, - { - "id": "xWMksOpz", - "type": "text", - "x": 1594.4188385009766, - "y": 130.5, - "width": 197.09982299804688, - "height": 50, - "angle": 0, - "strokeColor": "#333", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_AgentCore" - ], - "frameId": null, - "roundness": null, - "seed": 1299279082, - "version": 3, - "versionNonce": 1478158628, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "CustomAgent\\nUser-\ndefined flow", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 43, - "containerId": "FJMkSho2yrp8sB-kTkM_h", - "originalText": "CustomAgent\\nUser-\ndefined flow", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0A", - "rawText": "" - }, - { - "id": "LfVFlrMg", - "type": "text", - "x": 2588.3278732299805, - "y": 330.5, - "width": 160.35987854003906, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1732788138, - "version": 3, - "versionNonce": 2050927388, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Reasoning Engine", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "9YnU_6TC81D8GiTlsjJuD", - "originalText": "Reasoning Engine", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0B", - "rawText": "" - }, - { - "id": "cOMnSZkk", - "type": "text", - "x": 2331.102882385254, - "y": 424.5, - "width": 169.5598602294922, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 741784170, - "version": 3, - "versionNonce": 1319773348, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Provider Manager", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "VycM3UrTDvjrih5cknB6_", - "originalText": "Provider Manager", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0C", - "rawText": "" - }, - { - "id": "3t4Jodoi", - "type": "text", - "x": 2589.6978759765625, - "y": 424.5, - "width": 157.619873046875, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 721935658, - "version": 3, - "versionNonce": 1676863388, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Prompt Manager", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "aYh5YisIweGQwwfVH1aKE", - "originalText": "Prompt Manager", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0D", - "rawText": "" - }, - { - "id": "yOObjnmV", - "type": "text", - "x": 2828.948196411133, - "y": 424.5, - "width": 145.25985717773438, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1629923306, - "version": 3, - "versionNonce": 918941732, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Output Parser", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "f2vVAFqI51h48IMdNISmg", - "originalText": "Output Parser", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0E", - "rawText": "" - }, - { - "id": "YLAvAE3q", - "type": "text", - "x": 2326.852897644043, - "y": 518.5, - "width": 178.05982971191406, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1721637546, - "version": 3, - "versionNonce": 1961595932, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Provider Adapters", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "BohaQWZW3shJzcJRkRWZX", - "originalText": "Provider Adapters", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0F", - "rawText": "" - }, - { - "id": "YxNRq994", - "type": "text", - "x": 2346.4828720092773, - "y": 634.0161890043543, - "width": 138.7998809814453, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ReasoningSystem" - ], - "frameId": null, - "roundness": null, - "seed": 437859690, - "version": 3, - "versionNonce": 1348225956, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "LLM Providers", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "b4o_hgCUk0AB9FfzDZ6dv", - "originalText": "LLM Providers", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0G", - "rawText": "" - }, - { - "id": "YojuWZGD", - "type": "text", - "x": 2040.9047470092773, - "y": 399.0161895751953, - "width": 120.79988098144531, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1289943082, - "version": 3, - "versionNonce": 723169436, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Tool System", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "CJ_6lGAlgdP37BlLtl9_M", - "originalText": "Tool System", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0H", - "rawText": "" - }, - { - "id": "56oJlZtf", - "type": "text", - "x": 2035.0347518920898, - "y": 493.0161895751953, - "width": 132.5398712158203, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1860592362, - "version": 3, - "versionNonce": 765146916, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Tool Registry", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "z8hLGazKLyxkod6I2KpXc", - "originalText": "Tool Registry", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0I", - "rawText": "" - }, - { - "id": "1sdD0OOs", - "type": "text", - "x": 2024.6547622680664, - "y": 587.0161895751953, - "width": 153.2998504638672, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ToolSystem" - ], - "frameId": null, - "roundness": null, - "seed": 984511914, - "version": 3, - "versionNonce": 1983003932, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "IToolExecutors", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "IvRAJCaYbB5TnQVgxjk1U", - "originalText": "IToolExecutors", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0J", - "rawText": "" - }, - { - "id": "fhhog7ZP", - "type": "text", - "x": 1166.6081771850586, - "y": 446.0161895751953, - "width": 149.9398956298828, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1634087018, - "version": 3, - "versionNonce": 1794159268, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "State Manager", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "B3HiH9ZTnqaZSRhVZdwK_", - "originalText": "State Manager", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0K", - "rawText": "" - }, - { - "id": "RD954mGA", - "type": "text", - "x": 1402.2344589233398, - "y": 446.0161895751953, - "width": 214.4998321533203, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 920163114, - "version": 3, - "versionNonce": 2141469084, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Conversation Manager", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "IiKZEPQZJEFS28_K1m7g6", - "originalText": "Conversation Manager", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0L", - "rawText": "" - }, - { - "id": "TlnXtn2E", - "type": "text", - "x": 1708.2160186767578, - "y": 446.0161895751953, - "width": 166.73983764648438, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1567661546, - "version": 3, - "versionNonce": 1728757284, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Context Provider", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "TW6DTYIrKH675pI6E9K5s", - "originalText": "Context Provider", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0M", - "rawText": "" - }, - { - "id": "m8XYC2iT", - "type": "text", - "x": 1450.5644454956055, - "y": 540.0161895751953, - "width": 117.83985900878906, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ContextSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1916358826, - "version": 3, - "versionNonce": 1923261980, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Repositories", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "-blMmdM2sMEMs7RDsp6CG", - "originalText": "Repositories", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0N", - "rawText": "" - }, - { - "id": "6k416seh", - "type": "text", - "x": 3140.1225814819336, - "y": 446.0161895751953, - "width": 205.8798370361328, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ObservationSystem" - ], - "frameId": null, - "roundness": null, - "seed": 954051434, - "version": 3, - "versionNonce": 2060933540, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Observation Manager", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "s_W3K7i9ijY7WqbM3_8L1", - "originalText": "Observation Manager", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0O", - "rawText": "" - }, - { - "id": "Ea3dugTq", - "type": "text", - "x": 3130.0526123046875, - "y": 540.0161895751953, - "width": 226.019775390625, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_ObservationSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1202236970, - "version": 3, - "versionNonce": 1142915740, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Observation Repository", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "ZgAbrcKcdjMWdoMQX1Ld9", - "originalText": "Observation Repository", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0P", - "rawText": "" - }, - { - "id": "xPtHfhaX", - "type": "text", - "x": 2358.8108520507812, - "y": 828.5323791503906, - "width": 155.9798583984375, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": null, - "seed": 864377066, - "version": 3, - "versionNonce": 830768420, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "StorageAdapter", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "wNDNcGSK82UKeHWAmXIi2", - "originalText": "StorageAdapter", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0Q", - "rawText": "" - }, - { - "id": "9K4r09UC", - "type": "text", - "x": 1963.3337020874023, - "y": 922.5323791503906, - "width": 244.1997833251953, - "height": 25, - "angle": 0, - "strokeColor": "#333", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": null, - "seed": 1006545834, - "version": 3, - "versionNonce": 2060242716, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "InMemoryStorageAdapter", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "mxEcOuNAtKZ9jT2-WCrTa", - "originalText": "InMemoryStorageAdapter", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0R", - "rawText": "" - }, - { - "id": "96jLH6LI", - "type": "text", - "x": 2305.680892944336, - "y": 922.5323791503906, - "width": 262.2397766113281, - "height": 25, - "angle": 0, - "strokeColor": "#333", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": null, - "seed": 2000660074, - "version": 3, - "versionNonce": 8405156, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "IndexedDBStorageAdapter", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "XxSBUOmFtHHG_2C7dr7xL", - "originalText": "IndexedDBStorageAdapter", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0S", - "rawText": "" - }, - { - "id": "dsEfyy4X", - "type": "text", - "x": 2655.948356628418, - "y": 922.5323791503906, - "width": 157.57984924316406, - "height": 25, - "angle": 0, - "strokeColor": "#333", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_StorageSystem" - ], - "frameId": null, - "roundness": null, - "seed": 2115193130, - "version": 3, - "versionNonce": 1998359452, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Custom Storage", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "uDXbez1t0OYlGd-AfXDtl", - "originalText": "Custom Storage", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0T", - "rawText": "" - }, - { - "id": "3LpsQ6LR", - "type": "text", - "x": -19.986961770152334, - "y": 485.6397422545674, - "width": 198.8598175048828, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 400856042, - "version": 66, - "versionNonce": 256613916, - "isDeleted": false, - "boundElements": [], - "updated": 1747513337567, - "link": null, - "locked": false, - "text": "Conversation Socket", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "bvNnML6gAoXVRk8c3LLAp", - "originalText": "Conversation Socket", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0U", - "rawText": "" - }, - { - "id": "OsJnZcC2", - "type": "text", - "x": 270.2058482884414, - "y": 485.6397422545674, - "width": 190.2398223876953, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 1723762346, - "version": 66, - "versionNonce": 1268238108, - "isDeleted": false, - "boundElements": [], - "updated": 1747513337567, - "link": null, - "locked": false, - "text": "Observation Socket", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "qqx_UdBiU870V2hK50TeG", - "originalText": "Observation Socket", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0V", - "rawText": "" - }, - { - "id": "9DzmMXRp", - "type": "text", - "x": 546.8214565037734, - "y": 485.6397422545674, - "width": 193.53985595703125, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [ - "subgraph_group_UISystem" - ], - "frameId": null, - "roundness": null, - "seed": 323756394, - "version": 66, - "versionNonce": 531476508, - "isDeleted": false, - "boundElements": [], - "updated": 1747513337567, - "link": null, - "locked": false, - "text": "LLM Stream Socket", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "9ftUQCnF77Xi-hFy0r03v", - "originalText": "LLM Stream Socket", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0W", - "rawText": "" - }, - { - "id": "XiUqyZrr", - "type": "text", - "x": 1213.9170256347657, - "y": 742.032, - "width": 52.75994873046875, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 2027447338, - "version": 3, - "versionNonce": 858477724, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Input", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "Q7aU3JkcXPsIhipbAO9uL", - "originalText": "Input", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0X", - "rawText": "" - }, - { - "id": "1Od3L8Ix", - "type": "text", - "x": 1211.076028076172, - "y": 244, - "width": 54.37994384765625, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 599989354, - "version": 3, - "versionNonce": 1733743396, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Query", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "mj1xWgZrMSX7pTIJu10Q4", - "originalText": "Query", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0Y", - "rawText": "" - }, - { - "id": "ULs2vtwn", - "type": "text", - "x": 698.9520445556641, - "y": 244, - "width": 87.43991088867188, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 976075946, - "version": 3, - "versionNonce": 2089705756, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Response", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "S3HyRJ-dkTWkYt-cWhCmG", - "originalText": "Response", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0Z", - "rawText": "" - }, - { - "id": "dPqBMtdP", - "type": "text", - "x": 901.4270396728516, - "y": 742.032, - "width": 69.69992065429688, - "height": 25, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "roundness": null, - "seed": 2118206698, - "version": 3, - "versionNonce": 584634020, - "isDeleted": false, - "boundElements": [], - "updated": 1747513248859, - "link": null, - "locked": false, - "text": "Output", - "fontSize": 20, - "fontFamily": 1, - "textAlign": "center", - "verticalAlign": "middle", - "baseline": 18, - "containerId": "Ujr21ePPP6oOgGctEGihy", - "originalText": "Output", - "lineHeight": 1.25, - "autoResize": true, - "index": "b0a", - "rawText": "" - }, - { - "id": "nLvqc2BxWpnSY-jNd79-4", - "type": "arrow", - "x": 797.646203389278, - "y": 513.903452267424, - "width": 113.10650972787766, - "height": 1.9028441927505355, - "angle": 0, - "strokeColor": "#1e1e1e", - "backgroundColor": "transparent", - "fillStyle": "solid", - "strokeWidth": 2, - "strokeStyle": "solid", - "roughness": 1, - "opacity": 100, - "groupIds": [], - "frameId": null, - "index": "b0b", - "roundness": { - "type": 2 - }, - "seed": 893672228, - "version": 90, - "versionNonce": 2009795356, - "isDeleted": false, - "boundElements": null, - "updated": 1747513349883, - "link": null, - "locked": false, - "points": [ - [ - 0, - 0 - ], - [ - 113.10650972787766, - -1.9028441927505355 - ] - ], - "lastCommittedPoint": null, - "startBinding": { - "elementId": "VPfPMNLRWkwzonCSXIYLZ", - "focus": 0.43211667731358916, - "gap": 5.914193906988885 - }, - "endBinding": { - "elementId": "OF2UjoJ7_fOrczm-BVK48", - "focus": -0.23059598948327478, - "gap": 7.294161882844378 - }, - "startArrowhead": null, - "endArrowhead": "arrow", - "elbowed": false - } - ], - "appState": { - "theme": "light", - "viewBackgroundColor": "#fafafa", - "currentItemStrokeColor": "#1e1e1e", - "currentItemBackgroundColor": "transparent", - "currentItemFillStyle": "solid", - "currentItemStrokeWidth": 2, - "currentItemStrokeStyle": "solid", - "currentItemRoughness": 1, - "currentItemOpacity": 100, - "currentItemFontFamily": 5, - "currentItemFontSize": 20, - "currentItemTextAlign": "left", - "currentItemStartArrowhead": null, - "currentItemEndArrowhead": "arrow", - "currentItemArrowType": "round", - "scrollX": -956.0091976891246, - "scrollY": 591.5537254305956, - "zoom": { - "value": 0.578839 - }, - "currentItemRoundness": "round", - "gridSize": null, - "gridStep": 5, - "gridModeEnabled": false, - "gridColor": { - "Bold": "rgba(212, 212, 212, 0.5)", - "Regular": "rgba(225, 225, 225, 0.5)" - }, - "currentStrokeOptions": null, - "frameRendering": { - "enabled": true, - "clip": true, - "name": true, - "outline": true - }, - "objectsSnapModeEnabled": false, - "activeTool": { - "type": "selection", - "customType": null, - "locked": false, - "fromSelection": false, - "lastActiveTool": null - } - }, - "files": {} -} \ No newline at end of file diff --git a/Docs/examples/agent-with-tools.md b/Docs/examples/agent-with-tools.md deleted file mode 100644 index 58b4d83..0000000 --- a/Docs/examples/agent-with-tools.md +++ /dev/null @@ -1,195 +0,0 @@ -# Example: Agent with Tools - -This example builds upon the basic chatbot by demonstrating how to integrate and use tools with the `PESAgent` in the ART Framework. We'll use the built-in `CalculatorTool`. - -## 1. Project Setup - -Ensure you have [installed ART Framework](installation.md). -If you followed the [Basic Chatbot](basic-chatbot.md) example, you can modify that file or create a new one, e.g., `src/agent-with-tools.ts`. - -## 2. Code - -```typescript -// src/agent-with-tools.ts -import { - createArtInstance, - ArtInstanceConfig, - AgentProps, - LogLevel, - OpenAIAdapter, // Using OpenAI for this example as it has good function calling - CalculatorTool // Import the built-in tool -} from 'art-framework'; -import dotenv from 'dotenv'; // For loading .env file - -dotenv.config(); // Load environment variables from .env file - -async function runAgentWithTools() { - console.log("Setting up Agent with Tools..."); - - const OPENAI_API_KEY = process.env.OPENAI_API_KEY; - if (!OPENAI_API_KEY) { - console.error("ERROR: OPENAI_API_KEY environment variable is not set. This example requires it."); - return; - } - - // --- Configuration --- - const artConfig: ArtInstanceConfig = { - storage: { - type: 'memory' - }, - providers: { - availableProviders: [ - { - name: 'openai-for-tools', - adapter: OpenAIAdapter, - isLocal: false, - } - ], - }, - // *** Register tools here *** - tools: [ - new CalculatorTool(), // Instantiate and add the CalculatorTool - // Add other custom or built-in tools here: new MyCustomTool(), - ], - logger: { - level: LogLevel.DEBUG // Use DEBUG to see more internal ART logs, including tool calls - }, - // Default PESAgent will be used - }; - - const art = await createArtInstance(artConfig); - console.log("ART Instance with Tools initialized."); - - // --- Interaction --- - const threadId = "tools-chat-thread-001"; - const userId = "tool-user"; - - // Helper function - async function ask(query: string) { - console.log(`\nYOU: ${query}`); - const agentProps: AgentProps = { - query, - threadId, - userId, - options: { - providerConfig: { - providerName: 'openai-for-tools', - // Use a model known for good function/tool calling - modelId: 'gpt-3.5-turbo', // or 'gpt-4o-mini', 'gpt-4o' - adapterOptions: { apiKey: OPENAI_API_KEY } - }, - // stream: true, // Enable for token-by-token, requires UI handling - } - }; - - try { - const finalResponse = await art.process(agentProps); - console.log(`AGENT: ${finalResponse.response.content}`); - console.log(` (Metadata: Status=${finalResponse.metadata.status}, LLM Calls=${finalResponse.metadata.llmCalls}, Tool Calls=${finalResponse.metadata.toolCalls}, Duration=${finalResponse.metadata.totalDurationMs}ms)`); - if (finalResponse.metadata.error) { - console.error(` Agent Error: ${finalResponse.metadata.error}`); - } - - // For detailed inspection, look at observations: - // const observations = await art.observationManager.getObservations(threadId); - // observations - // .filter(obs => obs.type === 'TOOL_CALL' || obs.type === 'TOOL_EXECUTION') - // .forEach(obs => console.log("Relevant Observation:", obs.type, obs.content)); - - } catch (error) { - console.error("Error during agent processing with tools:", error); - } - } - - // Queries that should trigger the calculator tool - await ask("What is 125 divided by 5, then multiplied by 3?"); - await ask("If I have a square room that is 7 meters on one side, what is its area in square meters?"); - // Query that uses the 'ans' variable of calculator tool - await ask("Calculate 100 + 50."); - await ask("Now, what is the previous answer (ans) divided by 3?"); - await ask("What is your name?"); // Should not use a tool - - console.log("\nAgent with tools session finished."); -} - -runAgentWithTools().catch(console.error); -``` - -## 3. `.env` File - -Create a `.env` file in the root of your project (and add it to `.gitignore`!): - -``` -OPENAI_API_KEY=your_actual_openai_api_key_here -``` - -## 4. Running the Example - -1. Install `dotenv` if you haven't: `npm install dotenv` -2. Run the script: - ```bash - npx ts-node src/agent-with-tools.ts - ``` - -## Expected Output (Illustrative) - -The exact LLM responses will vary. You should see logs indicating tool usage. With `LogLevel.DEBUG`, you'll see detailed ART logs, including the "Tool Calls" section in the planning output and "TOOL_EXECUTION" observations. - -``` -Setting up Agent with Tools... -[ART] ToolRegistry: Registered tool "calculator". -... (other initialization logs) ... -ART Instance with Tools initialized. - -YOU: What is 125 divided by 5, then multiplied by 3? -[ART] PESAgent processing query for thread tools-chat-thread-001: "What is 125 divided by 5, then multiplied by 3?" -... -[ART] OutputParser: Parsed Tool Calls: [{"callId":"...", "toolName":"calculator","arguments":{"expression":"125 / 5 * 3"}}] -[ART] ToolSystem executing 1 tool calls for thread tools-chat-thread-001 -[ART] CalculatorTool executing with expression: "125 / 5 * 3" ... -[ART] Tool "calculator" execution successful -[ART] ObservationManager: Recording observation: TOOL_EXECUTION ... "output":{"result":75} ... -... -AGENT: 125 divided by 5 is 25, and 25 multiplied by 3 is 75. - (Metadata: Status=success, LLM Calls=2, Tool Calls=1, Duration=...ms) - -YOU: If I have a square room that is 7 meters on one side, what is its area in square meters? -... -AGENT: The area of a square room that is 7 meters on one side is 49 square meters. - (Metadata: Status=success, LLM Calls=2, Tool Calls=1, Duration=...ms) - -YOU: Calculate 100 + 50. -... -AGENT: 100 + 50 equals 150. - (Metadata: Status=success, LLM Calls=2, Tool Calls=1, Duration=...ms) - -YOU: Now, what is the previous answer (ans) divided by 3? -... -AGENT: The previous answer (150) divided by 3 is 50. - (Metadata: Status=success, LLM Calls=2, Tool Calls=1, Duration=...ms) - -YOU: What is your name? -... -AGENT: I am a large language model trained by OpenAI. - (Metadata: Status=success, LLM Calls=2, Tool Calls=0, Duration=...ms) - -Agent with tools session finished. -``` - -## Key Concepts Illustrated - -* **Tool Registration:** Adding `new CalculatorTool()` to `ArtInstanceConfig.tools` makes it available. -* **LLM Prompting for Tools:** The `PESAgent` (by default) includes descriptions of available tools (from their `ToolSchema`) in the planning prompt it sends to the LLM. -* **Tool Call Detection:** The LLM, when appropriate, includes a request to call a tool (e.g., "calculator") with specific arguments in its planning output. -* **`OutputParser`:** Extracts these tool call requests (`ParsedToolCall` objects). -* **`ToolSystem`:** - * Receives `ParsedToolCall`s. - * Verifies if the tool is enabled for the thread (using `StateManager` - by default, all registered tools are enabled unless `ThreadConfig.enabledTools` restricts them). - * Retrieves the `IToolExecutor` from `ToolRegistry`. - * Validates the arguments from the LLM against the tool's `inputSchema`. - * Calls the tool's `execute` method. -* **`ToolResult`:** The outcome of the tool execution is passed back to the `PESAgent`. -* **Synthesis with Tool Results:** The `PESAgent` includes the `ToolResult`(s) in the context for the synthesis LLM call, allowing the LLM to use the tool's output to formulate the final answer. -* **`ans` Variable:** The `CalculatorTool` demonstrates internal state per thread by remembering the last result as `ans`. - -This example provides a foundation for building agents that can leverage custom or built-in tools to perform a wide variety of tasks. \ No newline at end of file diff --git a/Docs/examples/basic-chatbot.md b/Docs/examples/basic-chatbot.md deleted file mode 100644 index 4ca6fca..0000000 --- a/Docs/examples/basic-chatbot.md +++ /dev/null @@ -1,216 +0,0 @@ -# Example: Basic Chatbot - -This example demonstrates the minimal setup required to create a simple conversational agent using the ART Framework. It will use `InMemoryStorageAdapter` (so history is not persisted across sessions) and can be configured with a mock LLM adapter or a real one like `OpenAIAdapter`. - -## 1. Project Setup - -Ensure you have [installed ART Framework](installation.md). - -Create a file, e.g., `src/basic-chatbot.ts`. - -## 2. Code - -```typescript -// src/basic-chatbot.ts -import { - createArtInstance, - ArtInstanceConfig, - AgentProps, - LogLevel, - // If using a real LLM provider: - OpenAIAdapter, // Example - // AnthropicAdapter, - // OllamaAdapter, - // For a mock provider (as in Quick Start): - ProviderAdapter, - FormattedPrompt, - CallOptions, - StreamEvent -} from 'art-framework'; - -// --- Optional: Mock Adapter for testing without API keys --- -class SimpleEchoAdapter implements ProviderAdapter { - providerName = 'echo-adapter'; - constructor(private options: any) {} - async call(prompt: FormattedPrompt, options: CallOptions): Promise<AsyncIterable<StreamEvent>> { - const userMessage = prompt.find(m => m.role === 'user'); - const query = userMessage ? String(userMessage.content) : "no query provided"; - const responseText = `Echo: "${query}". My config: ${JSON.stringify(this.options)}`; - async function* generateStream(): AsyncIterable<StreamEvent> { - yield { type: 'TOKEN', data: responseText, threadId: options.threadId, traceId: options.traceId! }; - yield { type: 'METADATA', data: { inputTokens: 5, outputTokens: 10, stopReason: 'stop' }, threadId: options.threadId, traceId: options.traceId! }; - yield { type: 'END', data: null, threadId: options.threadId, traceId: options.traceId! }; - } - return generateStream(); - } - async shutdown() { console.log(`${this.providerName} shutting down.`); } -} -// --- End Mock Adapter --- - - -async function runBasicChatbot() { - console.log("Setting up Basic Chatbot..."); - - // --- Configuration --- - const artConfig: ArtInstanceConfig = { - storage: { - type: 'memory' // Conversation history will not persist - }, - providers: { - availableProviders: [ - // Option 1: Use the Mock Echo Adapter - { - name: 'mock-echo', - adapter: SimpleEchoAdapter, - isLocal: true, // Treat as local for simplicity - }, - // Option 2: Use OpenAI (requires OPENAI_API_KEY environment variable) - /* - { - name: 'openai-chat', - adapter: OpenAIAdapter, - isLocal: false, - } - */ - ], - }, - logger: { - level: LogLevel.INFO // Set to DEBUG for more verbose output - } - // No tools, default PESAgent, default 'explicit' stateSavingStrategy - }; - - // Create and initialize the ART instance - const art = await createArtInstance(artConfig); - console.log("ART Instance initialized."); - - // --- Interaction Loop --- - const threadId = "basic-chat-thread-001"; - const userId = "test-user"; - - // Helper function to send a query and log the response - async function sendQuery(query: string) { - console.log(`\nYOU: ${query}`); - - const agentProps: AgentProps = { - query, - threadId, - userId, - options: { - // Specify which provider configuration to use - providerConfig: { - // Option 1: Mock Echo Adapter - providerName: 'mock-echo', - modelId: 'echo-v1', - adapterOptions: { customGreeting: "Hi from basic chatbot" } - - // Option 2: OpenAI - /* - providerName: 'openai-chat', - modelId: 'gpt-3.5-turbo', // Or 'gpt-4o-mini', etc. - adapterOptions: { apiKey: process.env.OPENAI_API_KEY } - */ - }, - stream: false // For simplicity in this console example, disable streaming - // Set to true to see token-by-token (would need UI stream handling) - } - }; - - // Validate API key if using OpenAI - /* - if (agentProps.options?.providerConfig?.providerName === 'openai-chat' && !process.env.OPENAI_API_KEY) { - console.error("ERROR: OPENAI_API_KEY environment variable is not set. Skipping OpenAI call."); - return; - } - */ - - try { - const finalResponse = await art.process(agentProps); - console.log(`AGENT: ${finalResponse.response.content}`); - console.log(` (Metadata: Status=${finalResponse.metadata.status}, LLM Calls=${finalResponse.metadata.llmCalls}, Duration=${finalResponse.metadata.totalDurationMs}ms)`); - - // You can also inspect observations or full conversation history: - // const history = await art.conversationManager.getMessages(threadId); - // console.log("Current History:", history); - // const observations = await art.observationManager.getObservations(threadId); - // console.log("Last few Observations:", observations.slice(-3)); - - } catch (error) { - console.error("Error during agent processing:", error); - } - } - - // Simulate a conversation - await sendQuery("Hello there!"); - await sendQuery("What is the ART Framework?"); - await sendQuery("Thanks!"); - - console.log("\nChatbot session finished."); -} - -runBasicChatbot().catch(console.error); -``` - -## 3. Running the Example - -* **If using the `SimpleEchoAdapter`:** - You can run this directly. - ```bash - # If in TypeScript project: - npx ts-node src/basic-chatbot.ts - # Or compile first: npx tsc src/basic-chatbot.ts --outDir dist ... && node dist/basic-chatbot.js - ``` - -* **If using `OpenAIAdapter` (or another cloud provider):** - 1. Uncomment the OpenAI parts in the code. - 2. Make sure you have the provider's SDK/adapter installed if it's not a core ART export (though `OpenAIAdapter` is). - 3. Set the required API key as an environment variable (e.g., `OPENAI_API_KEY`). You can use a `.env` file with the `dotenv` package for local development: - * Install `dotenv`: `npm install dotenv` - * Create a `.env` file in your project root: - ``` - OPENAI_API_KEY=your_openai_api_key_here - ``` - * Add `require('dotenv').config();` at the very top of your `basic-chatbot.ts` file. - 4. Run the script: - ```bash - npx ts-node src/basic-chatbot.ts - ``` - -## Expected Output (with `SimpleEchoAdapter`) - -``` -Setting up Basic Chatbot... -[ART] InMemoryStorageAdapter initialized. -[ART] AgentFactory initialized with config: ... -... (other initialization logs) ... -ART Instance initialized. - -YOU: Hello there! -[ART] PESAgent processing query for thread basic-chat-thread-001: "Hello there!" -... (PESAgent flow logs) ... -AGENT: Echo: "Hello there!". My config: {"customGreeting":"Hi from basic chatbot"} - (Metadata: Status=success, LLM Calls=2, Duration=...ms) - -YOU: What is the ART Framework? -[ART] PESAgent processing query for thread basic-chat-thread-001: "What is the ART Framework?" -... (PESAgent flow logs) ... -AGENT: Echo: "What is the ART Framework?". My config: {"customGreeting":"Hi from basic chatbot"} - (Metadata: Status=success, LLM Calls=2, Duration=...ms) - -YOU: Thanks! -[ART] PESAgent processing query for thread basic-chat-thread-001: "Thanks!" -... (PESAgent flow logs) ... -AGENT: Echo: "Thanks!". My config: {"customGreeting":"Hi from basic chatbot"} - (Metadata: Status=success, LLM Calls=2, Duration=...ms) - -Chatbot session finished. -``` - -## Key Concepts Illustrated - -* **`ArtInstanceConfig`:** Minimal configuration for `storage` (using `'memory'`) and `providers`. -* **`createArtInstance`:** The main function to initialize the framework. -* **`AgentProps`:** How to structure input for `art.process()`, including `query`, `threadId`, and `options.providerConfig` for runtime LLM selection. -* **`RuntimeProviderConfig`:** Specifying `providerName`, `modelId`, and `adapterOptions` (like API keys or mock adapter settings) for each call. -* **Basic Interaction:** A simple loop to send queries and receive responses. -* **Non-Persistent History:** Because `InMemoryStorageAdapter` is used, the conversation context (history) is maintained during the `runBasicChatbot` execution but would be lost if the script were run again. For persistence, see the [Persistent Agent example](persistent-agent.md). \ No newline at end of file diff --git a/Docs/examples/index.md b/Docs/examples/index.md deleted file mode 100644 index c9afb98..0000000 --- a/Docs/examples/index.md +++ /dev/null @@ -1,28 +0,0 @@ -# Examples & Tutorials - -This section provides practical examples and tutorials to help you get started with building various types of AI agents using the ART Framework. Each example aims to illustrate specific features and common patterns. - -For the most up-to-date and runnable code, always refer to the source files linked within each example and the `*.test.ts` files in the ART repository, which often contain practical usage scenarios. - -## Available Examples: - -1. **[Basic Chatbot](basic-chatbot.md)** - * Demonstrates the fundamental setup for a simple conversational agent. - * Covers `ArtInstanceConfig` with `InMemoryStorageAdapter` and a single LLM provider. - * Shows how to use `art.process()` for a basic query-response interaction. - -2. **[Agent with Tools](agent-with-tools.md)** - * Illustrates how to define, register, and use tools (like the built-in `CalculatorTool` or a custom tool) with the `PESAgent`. - * Explains how tool schemas are provided to the LLM and how tool calls/results are handled. - -3. **[Persistent Agent (using IndexedDB)](persistent-agent.md)** - * Shows how to configure `ArtInstanceConfig` to use `IndexedDBStorageAdapter` for persistent storage of conversation history and agent state in a web browser environment. - -4. **[Streaming to UI (Conceptual)](./streaming-to-ui-conceptual.md)** - * Provides a conceptual example of how a client-side UI (JavaScript) could subscribe to ART's UI Sockets (`LLMStreamSocket`, `ObservationSocket`, `ConversationSocket`) to display real-time updates. - -5. **[Multi-Provider Agent](multi-provider-agent.md)** - * Demonstrates configuring the `ProviderManager` with multiple LLM providers (e.g., OpenAI and Anthropic, or OpenAI and a local Ollama model). - * Shows how to use `RuntimeProviderConfig` in `AgentProps.options` to dynamically select which provider and model to use for specific agent calls. - -These examples are designed to be starting points. You can adapt and expand upon them to build more complex and specialized AI agents. Remember to consult the [Core Concepts](../core-concepts/architecture-overview.md) and [Components Deep Dive](../components/core/pes-agent.md) sections for a deeper understanding of the underlying framework components. \ No newline at end of file diff --git a/Docs/examples/multi-provider-agent.md b/Docs/examples/multi-provider-agent.md deleted file mode 100644 index 8a95224..0000000 --- a/Docs/examples/multi-provider-agent.md +++ /dev/null @@ -1,190 +0,0 @@ -# Example: Multi-Provider Agent - -This example demonstrates how to configure and use the ART Framework to interact with multiple Large Language Model (LLM) providers. It leverages the `ProviderManager` to dynamically select an LLM provider and model at runtime for each agent call. - -## 1. Project Setup - -* Ensure you have [installed ART Framework](installation.md). -* You'll need API keys for the different LLM providers you want to use (e.g., OpenAI, Anthropic). Store them securely as environment variables. - -Create a file, e.g., `src/multi-provider-agent.ts`. - -## 2. Code - -```typescript -// src/multi-provider-agent.ts -import { - createArtInstance, - ArtInstanceConfig, - AgentProps, - LogLevel, - OpenAIAdapter, - AnthropicAdapter, - OllamaAdapter, // Example for a local provider - // CalculatorTool // If you want to add tools -} from 'art-framework'; -import dotenv from 'dotenv'; - -dotenv.config(); // Load .env file for API keys - -async function runMultiProviderDemo() { - console.log("Setting up Multi-Provider Agent Demo..."); - - const OPENAI_API_KEY = process.env.OPENAI_API_KEY; - const ANTHROPIC_API_KEY = process.env.ANTHROPIC_API_KEY; - - if (!OPENAI_API_KEY) { - console.warn("WARN: OPENAI_API_KEY not set. OpenAI calls will be skipped."); - } - if (!ANTHROPIC_API_KEY) { - console.warn("WARN: ANTHROPIC_API_KEY not set. Anthropic calls will be skipped."); - } - - // --- Configuration: Define all available providers --- - const artConfig: ArtInstanceConfig = { - storage: { type: 'memory' }, - providers: { - availableProviders: [ - { - name: 'openai-gpt4o-mini', // Unique name for this configuration - adapter: OpenAIAdapter, - isLocal: false, - }, - { - name: 'openai-gpt3.5', // Another OpenAI configuration - adapter: OpenAIAdapter, - isLocal: false, - }, - { - name: 'anthropic-claude3-haiku', - adapter: AnthropicAdapter, - isLocal: false, - }, - { - name: 'ollama-local-llama3', // Example for a local Ollama model - adapter: OllamaAdapter, - isLocal: true, - } - ], - maxParallelApiInstancesPerProvider: 2, // Max active instances per named provider config - apiInstanceIdleTimeoutSeconds: 120, - }, - // tools: [new CalculatorTool()], // Add tools if needed - logger: { level: LogLevel.INFO }, - }; - - const art = await createArtInstance(artConfig); - console.log("ART Instance with Multiple Providers initialized."); - - const threadId = "multi-provider-thread-001"; - - // --- Function to make a call with specified provider --- - async function askWithProvider(query: string, providerName: string, modelId: string, adapterOptions: any) { - console.log(`\n--- Asking "${query}" using ${providerName} (${modelId}) ---`); - - const agentProps: AgentProps = { - query, - threadId, - options: { - providerConfig: { // This is the RuntimeProviderConfig - providerName: providerName, - modelId: modelId, - adapterOptions: adapterOptions - }, - // llmParams: { temperature: 0.7 } // Can add other LLM params here - } - }; - - try { - const result = await art.process(agentProps); - console.log(`RESPONSE (${providerName}): ${result.response.content}`); - console.log(` (Metadata: Status=${result.metadata.status}, LLM Calls=${result.metadata.llmCalls})`); - if (result.metadata.error) console.error(` Error: ${result.metadata.error}`); - } catch (error) { - console.error(`Error processing with ${providerName}:`, error); - } - } - - // --- Make calls using different providers --- - - // Call 1: OpenAI GPT-4o mini - if (OPENAI_API_KEY) { - await askWithProvider( - "What are three key benefits of using a modular framework for AI development?", - 'openai-gpt4o-mini', // providerName from availableProviders - 'gpt-4o-mini', // modelId for OpenAI - { apiKey: OPENAI_API_KEY } // adapterOptions for OpenAIAdapter - ); - } - - // Call 2: Anthropic Claude 3 Haiku - if (ANTHROPIC_API_KEY) { - await askWithProvider( - "Write a short, optimistic sentence about the future of AI.", - 'anthropic-claude3-haiku', // providerName - 'claude-3-haiku-20240307', // modelId for Anthropic - { apiKey: ANTHROPIC_API_KEY, defaultMaxTokens: 500 } // adapterOptions for AnthropicAdapter - ); - } - - // Call 3: OpenAI GPT-3.5 Turbo (using a different 'name' but same adapter type) - if (OPENAI_API_KEY) { - await askWithProvider( - "Suggest a catchy name for a new coffee shop.", - 'openai-gpt3.5', // Different providerName - 'gpt-3.5-turbo-instruct', // Different modelId - { apiKey: OPENAI_API_KEY } - ); - } - - // Call 4: Local Ollama model (e.g., Llama 3) - // Ensure your Ollama server is running and has the 'llama3' model pulled. - await askWithProvider( - "What is the capital of France?", - 'ollama-local-llama3', // providerName - 'llama3', // modelId (the tag of your Ollama model) - { - // For Ollama, apiKey defaults to "ollama", ollamaBaseUrl to localhost. - // Explicitly set if different: - // ollamaBaseUrl: 'http://localhost:11434', - // defaultModel: 'llama3' // Can also be set here - } - ); - - console.log("\nMulti-Provider Demo finished."); -} - -runMultiProviderDemo().catch(console.error); -``` - -## Explanation - -1. **`ArtInstanceConfig.providers.availableProviders`**: - * We define multiple entries, each with a unique `name` (e.g., `openai-gpt4o-mini`, `anthropic-claude3-haiku`, `ollama-local-llama3`). - * Each entry specifies the `adapter` class (`OpenAIAdapter`, `AnthropicAdapter`, `OllamaAdapter`) and whether it's `isLocal`. - -2. **`AgentProps.options.providerConfig`**: - * When calling `art.process()`, the `agentProps.options.providerConfig` object is crucial. - * `providerName`: This string **must exactly match** one of the `name`s you defined in `availableProviders`. This tells the `ProviderManager` which adapter configuration to use. - * `modelId`: This specifies the exact model to be used for that call (e.g., "gpt-4o-mini", "claude-3-haiku-20240307", "llama3"). This `modelId` is passed to the selected adapter. - * `adapterOptions`: This object is passed to the constructor of the selected adapter. This is where you provide runtime necessities like the `apiKey`. You can also include other options specific to that adapter (e.g., `defaultMaxTokens` for `AnthropicAdapter`, or `ollamaBaseUrl` for `OllamaAdapter` if it's not running on the default localhost). - -3. **Dynamic Selection:** - By changing the `providerConfig` within `AgentProps.options` for each call to `art.process()`, you can dynamically switch between different LLM providers and models for different tasks or based on user choice, cost considerations, or capability requirements. - -4. **Local vs. API Providers:** - * The `ollama-local-llama3` entry is marked `isLocal: true`. The `ProviderManager` will treat this as a singleton (only one local provider active at a time) and won't apply the `maxParallelApiInstancesPerProvider` or `apiInstanceIdleTimeoutSeconds` settings to it in the same way as API-based providers. - * API-based providers like `openai-gpt4o-mini` and `anthropic-claude3-haiku` (with `isLocal: false` or `isLocal` omitted) will be subject to pooling and idle timeout based on the `ProviderManagerConfig`. - -## Running the Example - -1. Create a `.env` file in your project root with your API keys: - ``` - OPENAI_API_KEY=your_openai_api_key - ANTHROPIC_API_KEY=your_anthropic_api_key - ``` -2. Ensure Ollama is running locally and you have pulled the model you intend to use (e.g., `ollama pull llama3`). -3. Install `dotenv`: `npm install dotenv`. -4. Run the script: `npx ts-node src/multi-provider-agent.ts`. - -You will see responses from the different configured LLMs, demonstrating the ability to switch providers at runtime. The ART Framework's `ProviderManager` handles the instantiation and management of the underlying adapter instances. \ No newline at end of file diff --git a/Docs/examples/persistent-agent.md b/Docs/examples/persistent-agent.md deleted file mode 100644 index aa89095..0000000 --- a/Docs/examples/persistent-agent.md +++ /dev/null @@ -1,553 +0,0 @@ -# Example: Persistent Agent (using IndexedDB) - -This example demonstrates how to configure an ART agent to use `IndexedDBStorageAdapter`. This allows conversation history and agent state (if managed) to persist across browser sessions, making the agent "remember" past interactions within the same thread. - -**Note:** This example is intended to be run in a browser environment where IndexedDB is available. - -## 1. Project Setup - -* Ensure you have [installed ART Framework](installation.md). -* If you're setting up a new project for the browser, you might use a bundler like Vite, Parcel, or Webpack. For simplicity, this example can be adapted into a single HTML file with a `<script type="module">`. - -## 2. HTML File (Example: `persistent-agent.html`) - -```html -<!DOCTYPE html> -<html lang="en"> -<head> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1.0"> - <title>ART Persistent Agent Example - - - -

ART Persistent Agent (IndexedDB)

-
- - -

Open browser console (F12) to see ART Framework logs.

-

Refresh the page to see if history persists for the current thread.

- - - - -``` - -## 3. JavaScript Code (within ` - - -``` -**Important Security Note:** Prompting for an API key in a real application is **highly insecure**. This is done here *only* for a simplified, self-contained browser demo. In production, API keys should be managed securely, typically by a backend service that makes calls to the LLM provider on behalf of the client. - -## 4. Running the Example - -1. Save the HTML code above as `persistent-agent.html` in a directory. -2. You'll need to serve the `art-framework` library so the browser can import it. The simplest way for a local demo: - * If your `art-framework` project has an ESM build (e.g., in `node_modules/art-framework/dist/esm/index.js` relative to your project structure), you can try to directly link to it. - * **Recommended for easy testing:** Use a simple HTTP server. If you have Node.js, you can install `http-server`: - ```bash - npm install -g http-server - ``` - Then navigate to the directory containing `persistent-agent.html` and your `node_modules` (or where `art-framework` is accessible) and run: - ```bash - http-server . -o - ``` - This will open the page in your browser. -3. When the page loads, it will prompt you for your OpenAI API key. -4. Open your browser's developer console (usually F12) to see logs from ART. - -## How to Test Persistence - -1. Send a few messages to the agent. -2. **Refresh the browser page.** -3. The agent should re-initialize. Observe the console and the chat log. You should see a message like "--- Loaded X previous messages ---" and your previous messages should reappear in the chat log. This confirms that the `IndexedDBStorageAdapter` has successfully persisted and reloaded the conversation history for the `threadId` ("persistent-thread-example-001"). -4. You can also inspect your browser's IndexedDB storage: - * Open Developer Tools (F12). - * Go to the "Application" tab (in Chrome/Edge) or "Storage" tab (in Firefox). - * Find "IndexedDB" in the sidebar. You should see your database (e.g., "MyPersistentAgentDB_ART"). - * You can inspect the "conversations" object store to see the raw message data. - -## Key Concepts Illustrated - -* **`ArtInstanceConfig.storage` for IndexedDB:** - ```javascript - storage: { - type: 'indexedDB', - dbName: 'MyPersistentAgentDB_ART', - dbVersion: 1, - } - ``` - This tells `AgentFactory` to use `IndexedDBStorageAdapter`. -* **Initialization (`artInstance.conversationManager.getMessages`):** The UI calls this after `createArtInstance` to load and display any existing history for the thread. -* **Automatic Persistence:** The `PESAgent` (default agent core) automatically calls `conversationManager.addMessages()` at the end of its `process` cycle. The `ConversationManager` then uses the `ConversationRepository`, which in turn uses the configured `IndexedDBStorageAdapter`, to save the messages. -* **`StateSavingStrategy`:** If you set `stateSavingStrategy: 'implicit'` and your agent modifies `threadContext.state`, those state changes would also persist via `IndexedDBStorageAdapter` (through `StateManager` and `StateRepository`). - -This example provides a basic illustration of how to achieve data persistence in browser-based ART applications. -``` - -```markdown -docs/examples/streaming-to-ui-conceptual.md -``` -```markdown -# Example: Streaming to UI (Conceptual) - -This document provides a conceptual guide and pseudo-code for how a client-side User Interface (UI) could integrate with an ART Framework backend to display real-time streaming updates. It focuses on the client-side subscription to ART's UI Sockets. - -**Prerequisites:** - -* An ART Framework backend application is running and exposing its UI Sockets. -* A communication channel is established between the frontend (browser) and the backend (e.g., WebSockets, Server-Sent Events, or a library that abstracts this). This guide **does not** cover setting up this communication channel itself but focuses on how to use ART's socket concepts once that channel is in place. - -**Conceptual Client-Side `artSockets` Object:** - -For this example, let's imagine a client-side JavaScript object, `artSockets`, that acts as a proxy or interface to the backend ART sockets. Its methods would internally handle sending subscription requests to the backend and routing incoming events from the backend to the correct client-side callbacks. - -```javascript -// --- Conceptual Client-Side artSockets Object --- -// This is NOT actual ART Framework code, but a representation -// of what your client-side WebSocket/SSE wrapper might provide. - -const artSockets = { - llmStream: { - /** - * @param {(event: StreamEvent) => void} callback - * @param {Array | StreamEvent['type']} filter - Event types to subscribe to - * @param {{ threadId?: string, sessionId?: string }} options - * @returns {() => void} Unsubscribe function - */ - subscribe: function(callback, filter, options) { - console.log(`[UI] Subscribing to LLMStream: Filter=${JSON.stringify(filter)}, Options=${JSON.stringify(options)}`); - // Actual implementation: Send subscription message to backend via WebSocket/SSE - // Store callback locally, keyed by subscription ID or criteria - const subId = `llm-${Date.now()}`; - // window.myBackendConnection.send({ type: 'subscribe_llm', subId, filter, options }); - // window.myBackendConnection.onMessage((backendEvent) => { - // if (backendEvent.subId === subId && backendEvent.type === 'llm_event_data') { - // callback(backendEvent.payload); - // } - // }); - return () => { - console.log(`[UI] Unsubscribing from LLMStream: ${subId}`); - // window.myBackendConnection.send({ type: 'unsubscribe_llm', subId }); - }; - } - }, - observation: { - /** - * @param {(observation: Observation) => void} callback - * @param {Array | ObservationType} filter - Observation types - * @param {{ threadId?: string }} options - * @returns {() => void} Unsubscribe function - */ - subscribe: function(callback, filter, options) { /* Similar WebSocket/SSE logic */ return () => {}; }, - /** - * @param {Array | ObservationType} filter - * @param {{ threadId?: string, limit?: number }} options - * @returns {Promise} - */ - getHistory: async function(filter, options) { - console.log(`[UI] Requesting Observation History: Filter=${JSON.stringify(filter)}, Options=${JSON.stringify(options)}`); - // Actual implementation: Send request to backend, await response - // return window.myBackendConnection.request({ type: 'get_observation_history', filter, options }); - return Promise.resolve([]); // Mock - } - }, - conversation: { - /** - * @param {(message: ConversationMessage) => void} callback - * @param {Array | MessageRole} filter - Message roles - * @param {{ threadId?: string }} options - * @returns {() => void} Unsubscribe function - */ - subscribe: function(callback, filter, options) { /* Similar WebSocket/SSE logic */ return () => {}; }, - /** - * @param {Array | MessageRole} filter - * @param {{ threadId?: string, limit?: number }} options - * @returns {Promise} - */ - getHistory: async function(filter, options) { - console.log(`[UI] Requesting Conversation History: Filter=${JSON.stringify(filter)}, Options=${JSON.stringify(options)}`); - // return window.myBackendConnection.request({ type: 'get_conversation_history', filter, options }); - return Promise.resolve([]); // Mock - } - } -}; -// --- End Conceptual Client-Side artSockets Object --- -``` - -## Displaying Streaming LLM Responses - -This is often the most desired real-time feature. - -**HTML:** -```html -
-

-``` - -**JavaScript:** -```javascript -const llmOutputElement = document.getElementById('llm-output-area'); -const llmStatusIndicator = document.getElementById('llm-status-indicator'); -let currentLLMStreamUnsubscribe = null; - -function handleNewAgentInteraction(threadId, sessionId) { - // Unsubscribe from any previous stream for this UI area - if (currentLLMStreamUnsubscribe) { - currentLLMStreamUnsubscribe(); - } - - llmOutputElement.innerHTML = ''; // Clear previous content - llmStatusIndicator.textContent = 'Agent is processing...'; - - currentLLMStreamUnsubscribe = artSockets.llmStream.subscribe( - (event) => { - // Ensure event is for the current context if your socket wrapper doesn't pre-filter - if (event.threadId !== threadId /* && event.sessionId !== sessionId */) return; - - switch (event.type) { - case 'TOKEN': - // We are interested in tokens that form the final answer - if (event.tokenType === 'FINAL_SYNTHESIS_LLM_RESPONSE' || event.tokenType === 'LLM_RESPONSE') { - const span = document.createElement('span'); - span.textContent = event.data; // event.data is the text chunk - llmOutputElement.appendChild(span); - } else if (event.tokenType && event.tokenType.includes('THOUGHT')) { - // Optionally display "thinking" tokens differently or log them - console.debug(`LLM Thought: ${event.data}`); - // You might have a separate area for thoughts or just log them - // llmStatusIndicator.textContent = `Thinking: ${event.data.slice(0, 20)}...`; - } - break; - case 'METADATA': - console.info('LLM Metadata received:', event.data); - llmStatusIndicator.textContent = `Call complete. Stop reason: ${event.data.stopReason || 'N/A'}.`; - break; - case 'ERROR': - console.error('LLM Stream Error:', event.data); - const errorMsg = event.data?.message || String(event.data); - llmOutputElement.innerHTML += `

Error: ${errorMsg}

`; - llmStatusIndicator.textContent = 'An error occurred.'; - break; - case 'END': - console.info('LLM Stream ended.'); - if (llmStatusIndicator.textContent === 'Agent is processing...') { - llmStatusIndicator.textContent = 'Done.'; - } - // The full response is now in llmOutputElement - // This is where you might move it to a persistent chat log area - break; - } - }, - ['TOKEN', 'METADATA', 'ERROR', 'END'], // Subscribe to all relevant event types - { threadId: threadId, sessionId: sessionId } // Filter by thread and session - ); -} - -// Example: When user sends a message and backend starts agent.process() -// Assume currentThread and currentSession are known -// handleNewAgentInteraction(currentThread, currentSession); - -// Don't forget to call currentLLMStreamUnsubscribe() when the UI component -// displaying this stream is removed or the conversation changes, to prevent memory leaks. -``` - -## Displaying Agent Observations (Activity Log) - -```html -
    -``` - -```javascript -const activityFeedElement = document.getElementById('agent-activity-feed'); -let currentObservationUnsubscribe = null; - -async function displayAgentActivity(threadId) { - if (currentObservationUnsubscribe) { - currentObservationUnsubscribe(); - } - activityFeedElement.innerHTML = '
  • Loading activity...
  • '; - - // Optional: Load some recent history - try { - const recentObservations = await artSockets.observation.getHistory( - undefined, // No type filter, get all - { threadId: threadId, limit: 5 } - ); - activityFeedElement.innerHTML = ''; // Clear loading message - recentObservations.reverse().forEach(obs => addObservationToFeed(obs)); // Display newest first - } catch (e) { - console.error("Error loading observation history:", e); - activityFeedElement.innerHTML = '
  • Could not load activity history.
  • '; - } - - currentObservationUnsubscribe = artSockets.observation.subscribe( - (observation) => { - if (observation.threadId !== threadId) return; - addObservationToFeed(observation); - }, - // Example: Subscribe to a few key types for a high-level activity feed - ['PLAN', 'TOOL_CALL', 'TOOL_EXECUTION', 'ERROR', 'FINAL_RESPONSE'], - { threadId: threadId } - ); -} - -function addObservationToFeed(observation) { - const item = document.createElement('li'); - item.innerHTML = ` - ${new Date(observation.timestamp).toLocaleTimeString()} - - ${observation.title} (${observation.type}) -
    ${JSON.stringify(observation.content, null, 2).substring(0, 150)}...
    - `; - // Prepend to show newest first if that's the desired order for live updates - if (activityFeedElement.firstChild && activityFeedElement.firstChild.textContent === 'Loading activity...') { - activityFeedElement.innerHTML = ''; - } - activityFeedElement.prepend(item); -} - -// Example: When a thread view is loaded -// displayAgentActivity(currentThread); -// Call currentObservationUnsubscribe() on cleanup. -``` - -## Updating Conversation History - -```html -
    -``` - -```javascript -const chatMessagesElement = document.getElementById('chat-messages'); -let currentConversationUnsubscribe = null; - -function displayChatMessage(message) { - const div = document.createElement('div'); - div.className = `chat-message ${message.role.toLowerCase()}`; - div.innerHTML = `${message.role}:

    ${message.content}

    - ${new Date(message.timestamp).toLocaleTimeString()}`; - chatMessagesElement.appendChild(div); - chatMessagesElement.scrollTop = chatMessagesElement.scrollHeight; -} - -async function loadAndFollowConversation(threadId) { - if (currentConversationUnsubscribe) { - currentConversationUnsubscribe(); - } - chatMessagesElement.innerHTML = '
  • Loading messages...
  • '; - - try { - const messages = await artSockets.conversation.getHistory( - undefined, // All roles - { threadId: threadId, limit: 100 } - ); - chatMessagesElement.innerHTML = ''; - messages.forEach(displayChatMessage); - } catch (e) { - console.error("Error loading conversation history:", e); - chatMessagesElement.innerHTML = '
  • Could not load messages.
  • '; - } - - currentConversationUnsubscribe = artSockets.conversation.subscribe( - (message) => { - if (message.threadId !== threadId) return; - // Deduplication: Check if message already displayed (e.g., from initial history load) - // This depends on how your history load and real-time updates are coordinated. - // A simple check could be by messageId if your UI tracks them. - // For this example, we'll assume new notifications are distinct. - displayChatMessage(message); - }, - undefined, // All roles - { threadId: threadId } - ); -} - -// Example: When a chat interface for a thread is loaded -// loadAndFollowConversation(currentThread); -// Call currentConversationUnsubscribe() on cleanup. -``` - -This conceptual guide illustrates how to consume the real-time data streams provided by ART's UI Sockets. The actual implementation will depend on your specific frontend framework (React, Vue, Angular, Svelte, vanilla JS) and the chosen backend-frontend communication protocol. \ No newline at end of file diff --git a/Docs/faq.md b/Docs/faq.md deleted file mode 100644 index 03977cb..0000000 --- a/Docs/faq.md +++ /dev/null @@ -1,94 +0,0 @@ -# Frequently Asked Questions (FAQ) - -This FAQ aims to answer common questions about the ART Framework. - -## General - -**Q1: What is the ART Framework?** -A: ART (Agent-Reasoning-Tooling) is a TypeScript library for building sophisticated AI agents. It provides a modular architecture for agents that can reason using LLMs, use tools, manage context, and interact with users. - -**Q2: Who is ART for?** -A: It's for developers building AI applications that require complex orchestration, interaction with external systems (via tools), and the flexibility to use different LLM providers. - -**Q3: What are the main benefits of using ART?** -A: Key benefits include structured agent development (e.g., `PESAgent`), modularity, LLM provider agnosticism (`ProviderManager`), standardized prompt and event formats (`ArtStandardPrompt`, `StreamEvent`), robust tool integration, configurable state/history management, and built-in observability. - -## Configuration & Setup - -**Q4: How do I configure which LLM provider and model to use?** -A: This is done in two parts: - 1. **`ArtInstanceConfig.providers.availableProviders`**: Define all potential provider setups (e.g., OpenAI, Anthropic, Ollama) with unique names and their adapter classes when you call `createArtInstance`. - 2. **`AgentProps.options.providerConfig`**: For each call to `art.process()`, you pass a `RuntimeProviderConfig` object. This object specifies the `providerName` (from your `availableProviders` list), the `modelId` (e.g., "gpt-4o-mini", "claude-3-haiku"), and `adapterOptions` (like the API key for that provider). - This allows dynamic selection of LLMs per call. A default `providerConfig` can also be set at the thread level in `ThreadConfig`. - -**Q5: How do I manage API keys securely?** -A: **Never hardcode API keys.** Use environment variables (e.g., `process.env.OPENAI_API_KEY`) for local development and server-side applications. For production, use secrets management services (AWS Secrets Manager, Azure Key Vault, etc.). If your ART agent runs client-side, proxy LLM calls through your own backend where keys are stored securely. API keys are passed at runtime via `RuntimeProviderConfig.adapterOptions.apiKey`. - -**Q6: What's the difference between `InMemoryStorageAdapter` and `IndexedDBStorageAdapter`?** -A: - * `InMemoryStorageAdapter`: Stores data (conversation history, state) in memory. Data is lost when the application session ends. Good for testing, demos, or ephemeral agents. - * `IndexedDBStorageAdapter`: Uses the browser's IndexedDB to persist data across sessions. Suitable for web applications needing to remember history or state. - -## Agents & Logic - -**Q7: What is `PESAgent`?** -A: `PESAgent` is the default agent core implementation in ART. It follows a Plan-Execute-Synthesize flow: - 1. **Plan:** Understands the query, creates a plan, and identifies tools. - 2. **Execute:** Runs any identified tools. - 3. **Synthesize:** Generates a final response using the query, plan, and tool results. - -**Q8: Can I create my own agent logic instead of using `PESAgent`?** -A: Yes. You can create a class that implements the `IAgentCore` interface and provide it in `ArtInstanceConfig.agentCore`. See [How-To: Create a Custom Agent Core](create-custom-agent.md). - -**Q9: How does `PESAgent` decide which tools to use?** -A: During its planning phase, `PESAgent` constructs a prompt for the LLM that includes descriptions of the available (and enabled for the thread) tools from their `ToolSchema` (name, description, input schema). The LLM then decides if any tools are needed and specifies which ones to call and with what arguments in its response. The `OutputParser` extracts these tool call requests. - -## Prompts & LLMs - -**Q10: What is `ArtStandardPrompt`?** -A: It's ART's standardized, provider-agnostic format for representing a sequence of messages to be sent to an LLM. It's an array of `ArtStandardMessage` objects, each having a `role` (system, user, assistant, tool_result), `content`, and optional tool-related fields. `ProviderAdapter`s translate this into the native format of their target LLM API. See [Core Concept: ArtStandardPrompt](art-standard-prompt.md). - -**Q11: How does the `PromptManager` work in v0.2.7?** -A: The `PromptManager` primarily provides: - 1. `getFragment(name, context?)`: Retrieves pre-defined text pieces (fragments) which can be used by agent logic (like `PESAgent`) when *it* constructs the `ArtStandardPrompt` messages. - 2. `validatePrompt(prompt)`: Validates a fully constructed `ArtStandardPrompt` object against a Zod schema. - The agent logic itself is responsible for assembling the `ArtStandardPrompt` array. - -**Q12: How does streaming work? What are `StreamEvent`s?** -A: When `CallOptions.stream: true` is set, `ProviderAdapter`s return an `AsyncIterable`. A `StreamEvent` can be of type `TOKEN` (a chunk of text), `METADATA` (LLM call info), `ERROR`, or `END`. This allows UIs to display responses token by token. See [Core Concept: Streaming & StreamEvents](streaming-and-streamevents.md). - -## Tools - -**Q13: How do I create a custom tool?** -A: Create a class that implements `IToolExecutor`. Define its `schema` (name, description, JSON Schema for input/output) and implement the `async execute(input, context)` method with your tool's logic. Register an instance of your tool in `ArtInstanceConfig.tools`. See [How-To: Define and Use Tools](define-tools.md). - -**Q14: How are tool input arguments validated?** -A: The `ToolSystem` automatically validates the arguments provided by the LLM (in a `ParsedToolCall`) against your tool's `ToolSchema.inputSchema` (using `validateJsonSchema` which relies on Ajv) *before* calling your tool's `execute` method. - -## State Management - -**Q15: What's the difference between `StateSavingStrategy` 'explicit' and 'implicit'?** -A: This setting in `ArtInstanceConfig` controls how `AgentState` is saved by `StateManager`: - * `'explicit'` (default): `AgentState` is only saved if your agent logic explicitly calls `stateManager.setAgentState()`. - * `'implicit'`: `StateManager.loadThreadContext()` caches the loaded state. If the agent modifies this cached state, `stateManager.saveStateIfModified()` (called by `PESAgent` at the end of a cycle) will automatically save the changes. - See [How-To: Manage Agent State](manage-agent-state.md). - -## Troubleshooting - -**Q16: My agent isn't using tools as expected. What should I check?** -A: - 1. **Tool Registration:** Is an instance of your tool included in `ArtInstanceConfig.tools`? - 2. **Tool Enablement:** If using `ThreadConfig.enabledTools`, is your tool listed for the current thread? - 3. **Tool Schema Description:** Is `ToolSchema.description` clear and compelling enough for the LLM to understand when to use the tool? Does `ToolSchema.inputSchema` accurately describe the arguments? - 4. **Planning Prompt:** Log the full planning prompt sent to the LLM. Does it correctly include the tool's description and schema? - 5. **LLM Output (Planning):** Log the raw output from the LLM's planning phase. Is it attempting to call the tool? Is the "Tool Calls:" JSON format correct? The `OutputParser` logs warnings/errors if it can't parse this. - 6. **Observations:** Check `TOOL_CALL` and `TOOL_EXECUTION` observations. `TOOL_EXECUTION` will show if validation failed or if the tool's `execute` method threw an error. - 7. **LLM Model:** Some smaller or less capable models struggle with complex tool use or adhering to specific JSON output formats. Try a more capable model (e.g., GPT-4o, Claude 3 Sonnet/Opus). - -**Q17: I'm getting errors related to `providerConfig` or "Unknown provider".** -A: - 1. Ensure that for every `art.process()` call, `AgentProps.options.providerConfig` is correctly set OR that a default `providerConfig` is set in the `ThreadConfig` for that `threadId`. - 2. The `providerConfig.providerName` must exactly match one of the `name`s you defined in `ArtInstanceConfig.providers.availableProviders`. - 3. The `providerConfig.adapterOptions` must include any required options for that adapter (especially `apiKey` for cloud providers). - -*(This FAQ will be expanded as more common questions arise.)* \ No newline at end of file diff --git a/Docs/getting-started/installation.md b/Docs/getting-started/installation.md deleted file mode 100644 index e632dd9..0000000 --- a/Docs/getting-started/installation.md +++ /dev/null @@ -1,75 +0,0 @@ -# Installation - -This guide will walk you through installing the ART Framework into your project. - -## Prerequisites - -Before you begin, ensure you have the following installed: - -* **Node.js:** ART is a TypeScript library and typically runs in a Node.js environment or a browser environment bundled with tools like Webpack or Vite. We recommend using a recent LTS version of Node.js (e.g., v18.x or v20.x). You can download it from [nodejs.org](https://nodejs.org/). -* **npm (Node Package Manager) or yarn:** These are package managers for JavaScript and come bundled with Node.js (npm) or can be installed separately (yarn). - -## Installing ART Framework - -You can install the ART Framework using either npm or yarn. Open your project's terminal and run one ofthe following commands: - -**Using npm:** - -```bash -npm install art-framework -``` - -**Using yarn:** - -```bash -yarn add art-framework -``` - -This command will download the ART Framework package and add it to your project's `node_modules` directory and `package.json` file. - -## Verifying Installation (Optional) - -After installation, you can verify that the package is correctly installed by trying to import a core component in a test JavaScript or TypeScript file. - -For example, create a file named `test-art.js` (or `.ts`): - -```typescript -// test-art.ts -import { createArtInstance, PESAgent, InMemoryStorageAdapter, OpenAIAdapter } from 'art-framework'; - -console.log('ART Framework components imported successfully!'); -console.log('createArtInstance:', typeof createArtInstance); -console.log('PESAgent:', typeof PESAgent); -console.log('InMemoryStorageAdapter:', typeof InMemoryStorageAdapter); -console.log('OpenAIAdapter:', typeof OpenAIAdapter); - -// Basic check to see if createArtInstance can be called (without full config for brevity) -try { - // This will throw due to missing config, but confirms the function exists - // @ts-ignore - Intentionally omitting config for simple check - createArtInstance({}); -} catch (e: any) { - if (e.message.includes("requires 'storage' configuration")) { - console.log('createArtInstance function is present.'); - } else { - console.error('Unexpected error with createArtInstance:', e); - } -} -``` - -Then run it: - -```bash -node test-art.js -# Or if using TypeScript with ts-node: -# npx ts-node test-art.ts -``` - -You should see output indicating successful imports and that `createArtInstance` exists. This is a basic check; the [Quick Start](./quick-start.md) guide will walk you through creating a runnable agent. - -## Next Steps - -With ART Framework installed, you're ready to start building your first agent! - -* **[Quick Start Guide](./quick-start.md):** A hands-on tutorial to create a simple "Hello, Agent!" -* **[Project Setup](./project-setup.md):** Recommendations for structuring your ART project. \ No newline at end of file diff --git a/Docs/getting-started/project-setup.md b/Docs/getting-started/project-setup.md deleted file mode 100644 index 058ec5d..0000000 --- a/Docs/getting-started/project-setup.md +++ /dev/null @@ -1,174 +0,0 @@ -# Project Setup Recommendations - -While ART is flexible, a structured project setup can make development smoother, especially for larger applications. Here are some recommendations: - -## Recommended Directory Structure - -A typical ART project might look like this: - -``` -my-art-project/ -├── src/ -│ ├── agents/ # Custom agent logic (if extending beyond PESAgent) -│ │ └── my-custom-agent.ts -│ ├── tools/ # Custom tool implementations -│ │ ├── weather-tool.ts -│ │ └── database-tool.ts -│ ├── prompts/ # Store prompt blueprints or fragments (if using PromptManager heavily) -│ │ ├── planning-blueprint.md -│ │ └── common-instructions.txt -│ ├── config/ # Application-specific configurations -│ │ └── art-config.ts # Central place to define your ArtInstanceConfig -│ ├── services/ # Other application services -│ ├── main.ts # Main application entry point (e.g., where createArtInstance is called) -│ └── types.ts # Custom application-specific types -├── tests/ -│ ├── agents/ -│ └── tools/ -├── node_modules/ -├── package.json -├── tsconfig.json -└── README.md -``` - -**Explanation:** - -* **`src/agents/`**: If you create custom agent core implementations (beyond the default `PESAgent`), place them here. -* **`src/tools/`**: Your custom tool implementations (classes that implement `IToolExecutor`). -* **`src/prompts/`**: If you use the `PromptManager` extensively with many custom fragments or complex blueprints, organizing them here can be helpful. (Note: For `PESAgent` using direct `ArtStandardPrompt` construction, this might be less critical). -* **`src/config/art-config.ts`**: This is a crucial file. It's recommended to define your main `ArtInstanceConfig` here. This keeps your agent setup centralized and easy to manage. -* **`src/main.ts`**: Your application's primary entry point. This is often where you'll call `createArtInstance` using the configuration from `art-config.ts` and start interacting with the agent. -* **`src/types.ts`**: For any custom TypeScript types or interfaces specific to your application's domain that might be used with agent state or tool inputs/outputs. - -## Centralizing `ArtInstanceConfig` - -It's highly recommended to define your `ArtInstanceConfig` in a dedicated file (e.g., `src/config/art-config.ts`). This makes it easier to manage and modify your agent's setup. - -**Example (`src/config/art-config.ts`):** - -```typescript -import { - ArtInstanceConfig, - InMemoryStorageAdapter, // Or IndexedDBStorageAdapter - OpenAIAdapter, // Example LLM Adapter - CalculatorTool, // Example built-in tool - LogLevel -} from 'art-framework'; -// import { MyCustomTool } from '../tools/my-custom-tool'; // If you have custom tools - -export const myAppArtConfig: ArtInstanceConfig = { - storage: { - type: 'memory', // Or: { type: 'indexedDB', dbName: 'MyAgentDB_V1', version: 1 } - }, - providers: { - availableProviders: [ - { - name: 'openai-gpt4', - adapter: OpenAIAdapter, - isLocal: false, - // No baseOptions needed if apiKey is provided at runtime in adapterOptions - }, - // Add other providers like Anthropic, Gemini, Ollama here - // { - // name: 'anthropic-claude3', - // adapter: AnthropicAdapter, - // isLocal: false, - // }, - ], - maxParallelApiInstancesPerProvider: 3, - apiInstanceIdleTimeoutSeconds: 180, - }, - tools: [ - new CalculatorTool(), - // new MyCustomTool(), - ], - // agentCore: MyCustomAgent, // If using a custom agent core - stateSavingStrategy: 'implicit', // Or 'explicit' - logger: { - level: LogLevel.INFO, // Adjust as needed (DEBUG, WARN, ERROR) - }, -}; -``` - -**Using the Centralized Config (`src/main.ts`):** - -```typescript -import { createArtInstance, AgentProps } from 'art-framework'; -import { myAppArtConfig } from './config/art-config'; // Import your centralized config - -async function startApp() { - try { - const art = await createArtInstance(myAppArtConfig); - console.log('ART Instance successfully initialized!'); - - // Example agent interaction - const agentProps: AgentProps = { - query: "What is 5 plus 7?", - threadId: "main-app-thread-001", - options: { - providerConfig: { - providerName: 'openai-gpt4', // Must match a name in availableProviders - modelId: 'gpt-4o-mini', // Specific model - adapterOptions: { - apiKey: process.env.OPENAI_API_KEY, // Load API key securely - }, - }, - }, - }; - - if (!process.env.OPENAI_API_KEY) { - console.error("Error: OPENAI_API_KEY environment variable is not set."); - return; - } - - const result = await art.process(agentProps); - console.log("Agent Response:", result.response.content); - - } catch (error) { - console.error("Failed to initialize or run ART agent:", error); - } -} - -startApp(); -``` - -## Managing API Keys and Sensitive Configuration - -**Never hardcode API keys directly in your source code.** Use environment variables or a secure configuration management system. - -* **Environment Variables:** - * Load API keys using `process.env.YOUR_API_KEY_NAME`. - * Use a `.env` file (e.g., with the `dotenv` package) for local development. Add `.env` to your `.gitignore`. -* **Secrets Management Services:** For production, use services like AWS Secrets Manager, Google Cloud Secret Manager, or HashiCorp Vault. - -## TypeScript Configuration (`tsconfig.json`) - -A basic `tsconfig.json` for an ART project might look like this: - -```json -{ - "compilerOptions": { - "target": "ES2020", // Modern JavaScript features - "module": "commonjs", // Or "ESNext" if using ES modules - "lib": ["ES2020", "DOM"], // Include DOM if targeting browser environments (e.g., for IndexedDB) - "strict": true, // Enable all strict type-checking options - "esModuleInterop": true, // Allows default imports from commonjs modules - "skipLibCheck": true, // Skip type checking of declaration files - "forceConsistentCasingInFileNames": true, - "outDir": "./dist", // Output directory for compiled files - "rootDir": "./src", - "resolveJsonModule": true, // Allows importing JSON files - "experimentalDecorators": true, // If using decorators - "emitDecoratorMetadata": true // If using decorators with reflection - }, - "include": ["src/**/*"], // Which files to include - "exclude": ["node_modules", "dist"] // Which files to exclude -} -``` - -Adjust `target`, `module`, and `lib` based on your specific environment and needs. - -## Next Steps - -* Explore the [Core Concepts](architecture-overview.md) to understand ART's building blocks. -* Dive into specific [How-To Guides](../how-to/configure-art-instance.md) for practical tasks. \ No newline at end of file diff --git a/Docs/getting-started/quick-start.md b/Docs/getting-started/quick-start.md deleted file mode 100644 index 22b3bca..0000000 --- a/Docs/getting-started/quick-start.md +++ /dev/null @@ -1,230 +0,0 @@ -# Quick Start: "Hello, Agent!" - -This guide will walk you through creating a minimal, runnable ART agent. This "Hello, Agent!" example will use an in-memory storage adapter and a mock LLM provider (or a real one if you have an API key) to demonstrate the basic setup and processing flow. - -## 1. Project Setup - -Ensure you have [installed the ART Framework](./installation.md). - -Create a new TypeScript file in your project, for example, `src/myFirstAgent.ts`. - -## 2. Import Necessary Components - -At the top of your `myFirstAgent.ts` file, import the core components you'll need: - -```typescript -import { - createArtInstance, - ArtInstanceConfig, - AgentProps, - LogLevel, - // For a real LLM, you'd import its adapter, e.g., OpenAIAdapter - // For this example, we'll mock a simple provider adapter - ProviderAdapter, - FormattedPrompt, - CallOptions, - StreamEvent -} from 'art-framework'; -``` - -## 3. Define a Simple Mock Provider Adapter (Optional) - -If you don't want to use a real LLM API key for this quick start, you can create a very simple mock adapter. If you have an API key (e.g., for OpenAI), you can skip this step and configure the real adapter in step 4. - -```typescript -// Simple Mock Adapter (if not using a real LLM for this example) -class MockGreeterAdapter implements ProviderAdapter { - providerName = 'mock-greeter'; - - constructor(private options: any) {} // Constructor to accept options - - async call(prompt: FormattedPrompt, options: CallOptions): Promise> { - const query = (prompt.find(msg => msg.role === 'user')?.content as string) || "no query"; - const responseText = `Hello from MockGreeter! You said: "${query}". My config: ${JSON.stringify(this.options)}`; - - // Simulate a stream - async function* generateStream(): AsyncIterable { - yield { type: 'TOKEN', data: responseText, threadId: options.threadId, traceId: options.traceId || 'mock-trace' }; - yield { type: 'METADATA', data: { inputTokens: 10, outputTokens: 5, stopReason: 'stop' }, threadId: options.threadId, traceId: options.traceId || 'mock-trace' }; - yield { type: 'END', data: null, threadId: options.threadId, traceId: options.traceId || 'mock-trace' }; - } - return generateStream(); - } - // Optional shutdown - async shutdown(): Promise { console.log(`${this.providerName} shutting down.`); } -} -``` - -## 4. Configure Your ART Instance - -The `createArtInstance` function takes an `ArtInstanceConfig` object. This configuration tells ART which components to use. - -```typescript -const artConfig: ArtInstanceConfig = { - // 1. Storage: Use in-memory storage for this example - storage: { type: 'memory' }, - - // 2. Providers: Configure the LLM provider(s) - providers: { - availableProviders: [ - { - name: 'my-mock-provider', // A unique name for this provider configuration - adapter: MockGreeterAdapter, // Use our mock adapter - isLocal: true, // Treat as a local provider for simplicity - // baseOptions: { greeting: "Aloha" } // Optional: Base options for the adapter constructor - }, - // Example for OpenAI (if you have an API key and want to use it): - /* - { - name: 'openai-main', - adapter: OpenAIAdapter, // Requires: import { OpenAIAdapter } from 'art-framework'; - isLocal: false, - } - */ - ], - // Default max instances for API providers (not strictly needed for a single local mock) - maxParallelApiInstancesPerProvider: 1, - // Default idle timeout (not strictly needed for a single local mock) - apiInstanceIdleTimeoutSeconds: 60, - }, - - // 3. Agent Core (Optional): Defaults to PESAgent, which is fine for this example. - // agentCore: PESAgent, - - // 4. Tools (Optional): No tools needed for this simple example. - // tools: [], - - // 5. State Saving Strategy (Optional): Defaults to 'explicit'. - // stateSavingStrategy: 'implicit', - - // 6. Logger (Optional): Configure logging level. - logger: { - level: LogLevel.DEBUG, // Show more detailed logs - }, -}; -``` - -## 5. Create the ART Instance and Process a Query - -Now, use `createArtInstance` with your configuration and then call the `process` method. - -```typescript -async function runAgent() { - try { - // Create and initialize the ART instance - console.log("Creating ART instance..."); - const art = await createArtInstance(artConfig); - console.log("ART instance created and initialized."); - - // Define the properties for the agent call - const agentProps: AgentProps = { - query: "How are you today?", - threadId: "quick-start-thread-1", // A unique ID for this conversation - userId: "user-001", - // Specify which provider configuration to use for this call - options: { - providerConfig: { - providerName: 'my-mock-provider', // Matches name in artConfig.providers.availableProviders - modelId: 'mock-model-v1', // A model identifier for this provider - adapterOptions: { // Options passed to the adapter's constructor - apiKey: 'mock-api-key', // Even mocks might expect an options structure - customSetting: "QuickStartSetting" - } - } - } - }; - - console.log(`\nProcessing query for thread ${agentProps.threadId}: "${agentProps.query}"`); - const finalResponse = await art.process(agentProps); - - console.log("\nAgent's Final Response:"); - console.log(` Role: ${finalResponse.response.role}`); - console.log(` Content: "${finalResponse.response.content}"`); - console.log("Execution Metadata:"); - console.log(` Status: ${finalResponse.metadata.status}`); - console.log(` LLM Calls: ${finalResponse.metadata.llmCalls}`); - console.log(` Total Duration: ${finalResponse.metadata.totalDurationMs}ms`); - if (finalResponse.metadata.error) { - console.error(` Error: ${finalResponse.metadata.error}`); - } - - } catch (error) { - console.error("An error occurred:", error); - } -} - -// Run the agent -runAgent(); -``` - -## 6. Run Your Agent - -Save your `myFirstAgent.ts` file. If you're using TypeScript, compile it: - -```bash -npx tsc src/myFirstAgent.ts --outDir dist --module commonjs --esModuleInterop --target es2020 --skipLibCheck -node dist/myFirstAgent.js -``` - -Or, if you have `ts-node` installed: - -```bash -npx ts-node src/myFirstAgent.ts -``` - -**Expected Output (using the MockGreeterAdapter):** - -You should see output similar to this (timestamps and exact log messages might vary): - -``` -Creating ART instance... -[ART] StateManager initialized with strategy: explicit -[ART] ToolRegistry initialized without StateManager. -[ART] ProviderManager initialized. -[ART] ReasoningEngine initialized with ProviderManager -[ART] PromptManager initialized. Default fragments loaded: ... -[ART] OutputParser initialized. -[ART] ToolSystem initialized. -[ART] ConversationRepository requires a valid StorageAdapter instance. (If using default PESAgent, it initializes this) -[ART] ObservationRepository requires a valid StorageAdapter instance. -[ART] StateRepository requires a valid StorageAdapter instance. -[ART] UISystem initialized with Observation, Conversation, and LLM Stream sockets. -[ART] ConversationManager initialized. -[ART] ObservationManager initialized. -ART instance created and initialized. - -Processing query for thread quick-start-thread-1: "How are you today?" -[ART] ReasoningEngine requesting adapter for provider: my-mock-provider, model: mock-model-v1 -[ART] Created new instance for signature: {"providerName":"my-mock-provider","modelId":"mock-model-v1",...} -... (other debug logs from PESAgent flow) ... -[ART] ReasoningEngine released adapter for signature: my-mock-provider - -Agent's Final Response: - Role: AI - Content: "Hello from MockGreeter! You said: "How are you today?". My config: {"apiKey":"mock-api-key","customSetting":"QuickStartSetting"}" -Execution Metadata: - Status: success - LLM Calls: 2 - Total Duration: ...ms -``` - -## Congratulations! - -You've successfully set up and run your first ART agent! - -**Key Takeaways:** - -* **`createArtInstance(artConfig)`:** The main entry point to initialize the framework. -* **`ArtInstanceConfig`:** Defines storage, LLM providers, tools, and other core settings. - * `storage`: Specifies how data like conversation history is stored. - * `providers`: Configures available LLM adapters (like `MockGreeterAdapter` or `OpenAIAdapter`) and their settings. -* **`art.process(agentProps)`:** The method to interact with the agent. -* **`AgentProps`:** Contains the user's query, thread ID, and importantly, `options.providerConfig` to select and configure the LLM for that specific call. -* **`ProviderAdapter`:** The interface that LLM-specific adapters implement. - -From here, you can explore: - -* **[Project Setup](./project-setup.md):** For structuring larger projects. -* **[Core Concepts](../core-concepts/architecture-overview.md):** To understand ART's architecture in more detail. -* **Using Real LLMs:** Replace the `MockGreeterAdapter` with an adapter for a provider like OpenAI, Anthropic, or Gemini, and provide your API key in the `adapterOptions` within `RuntimeProviderConfig`. -* **Adding Tools:** Explore how to define and use tools with your agent. \ No newline at end of file diff --git a/Docs/glossary.md b/Docs/glossary.md deleted file mode 100644 index 66f0f17..0000000 --- a/Docs/glossary.md +++ /dev/null @@ -1,252 +0,0 @@ -# Glossary of ART Framework Terms - -This glossary defines key terms and concepts used within the ART (Agent-Reasoning-Tooling) Framework documentation and codebase. - ---- - -**A** - -* **Adapter (`ProviderAdapter`, `StorageAdapter`)** - * A component that bridges the ART Framework's standard interfaces with the specific APIs or mechanisms of an external service (e.g., an LLM provider, a database). - * _See also: [ProviderAdapter](#provideradapter), [StorageAdapter](#storageadapter)_ - -* **Agent Core (`IAgentCore`)** - * The central orchestrator of an agent's decision-making and action cycle. Responsible for processing user input, interacting with various ART systems, and producing a final response. - * _Example: `PESAgent`_ - -* **`AgentFactory`** - * An internal class responsible for instantiating and wiring together all core ART components based on `ArtInstanceConfig`. Used by `createArtInstance`. - -* **`AgentFinalResponse`** - * The structured output from an `IAgentCore.process()` call, containing the final `ConversationMessage` from the AI and `ExecutionMetadata`. - -* **`AgentProps`** - * The input object for `IAgentCore.process()`, containing the user's `query`, `threadId`, and other optional parameters like `options` (which includes `RuntimeProviderConfig`). - -* **`AgentState`** - * Persistent, application-defined data associated with an agent's operation within a specific `ThreadContext`. Managed by `StateManager`. - -* **`ArtInstance`** - * The main object returned by `createArtInstance`, providing the primary interface for interacting with the initialized ART framework (e.g., `art.process()`, `art.uiSystem`). - -* **`ArtInstanceConfig`** - * The primary configuration object passed to `createArtInstance`. It defines storage, LLM providers (via `ProviderManagerConfig`), initial tools, agent core implementation, state saving strategy, and logger settings. - -* **`ArtStandardMessage`** - * A standardized object structure representing a single message within a prompt (e.g., with `role`, `content`, `tool_calls`). Used to build an `ArtStandardPrompt`. - -* **`ArtStandardPrompt`** - * An array of `ArtStandardMessage` objects. This is ART's universal, provider-agnostic format for representing the full sequence of messages to be sent to an LLM. Adapters translate this into provider-specific formats. - -* **`AvailableProviderEntry`** - * An entry within `ProviderManagerConfig` defining a specific LLM provider adapter that can be used, including its `name`, `adapter` class, and `isLocal` flag. - -**C** - -* **`CalculatorTool`** - * A built-in tool for evaluating mathematical expressions. - -* **`CallOptions`** - * An object passed to `ReasoningEngine.call()` and `ProviderAdapter.call()`, containing `threadId`, `stream` preference, `callContext`, and the crucial `RuntimeProviderConfig` for selecting and configuring the LLM for that specific call. - -* **Context System** - * A conceptual grouping of ART components responsible for managing conversation history (`ConversationManager`, `ConversationRepository`), thread configuration and state (`StateManager`, `StateRepository`), and potentially dynamic context retrieval (`ContextProvider`). - -* **`ConversationManager`** - * Manages the retrieval and addition of `ConversationMessage`s for threads, interacting with `ConversationRepository` and notifying `ConversationSocket`. - -* **`ConversationMessage`** - * An object representing a single message in a conversation thread, with properties like `messageId`, `threadId`, `role`, `content`, `timestamp`. - -* **`ConversationRepository`** - * Persists and retrieves `ConversationMessage`s using a `StorageAdapter`. - -* **`ConversationSocket`** - * A `TypedSocket` for broadcasting new `ConversationMessage`s to UI subscribers. - -* **`createArtInstance`** - * The main factory function used to initialize and configure a complete ART framework instance. - -**E** - -* **`ErrorCode`** - * An enum defining standardized error codes for issues within the ART framework (e.g., `INVALID_CONFIG`, `LLM_PROVIDER_ERROR`). - -* **`ExecutionMetadata`** - * Data summarizing an agent's execution cycle, including `status`, `duration`, `llmCalls`, `toolCalls`, and `error` messages. Part of `AgentFinalResponse`. - -* **`ExecutionContext`** - * Contextual information (like `threadId`, `traceId`) passed to an `IToolExecutor.execute()` method. - -**F** - -* **`FilterOptions`** - * Generic options for querying data from a `StorageAdapter`, including `filter`, `sort`, `limit`, and `skip`. - -* **`FormattedPrompt`** - * An alias for `ArtStandardPrompt` in `v0.2.7`. Represents the prompt ready to be sent to `ReasoningEngine.call()`. - -**I** - -* **`IAgentCore`** - * The interface defining the main contract for an agent's orchestration logic. - -* **`IndexedDBStorageAdapter`** - * A `StorageAdapter` implementation that uses the browser's IndexedDB for persistent client-side storage. - -* **`InMemoryStorageAdapter`** - * A `StorageAdapter` implementation that stores data in memory; data is lost when the session ends. - -* **`IToolExecutor`** - * The interface that all tools must implement, defining a `schema` and an `execute` method. - -* **`IProviderManager`** - * The interface for the `ProviderManager`, responsible for managing and providing access to `ProviderAdapter` instances. - -**J** - -* **`JsonSchema`** - * A type representing a JSON Schema object, used primarily for defining `ToolSchema.inputSchema` and `ToolSchema.outputSchema`. - -**L** - -* **`LLMMetadata`** - * Metadata about an LLM call, such as token counts and stop reason, often part of a `METADATA` `StreamEvent`. - -* **`LLMStreamSocket`** - * A `TypedSocket` for broadcasting `StreamEvent`s (tokens, metadata, errors) from LLM calls to UI subscribers. - -* **`Logger`** - * A static utility class for console logging at different levels (`DEBUG`, `INFO`, `WARN`, `ERROR`). - -* **`LogLevel`** - * An enum defining the severity levels for the `Logger`. - -**M** - -* **`ManagedAdapterAccessor`** - * An object returned by `ProviderManager.getAdapter()`, containing a `ProviderAdapter` instance and a `release()` function. - -* **`MessageRole`** - * An enum defining the role of a sender in a `ConversationMessage` (`USER`, `AI`, `SYSTEM`, `TOOL`). - -**O** - -* **Observation** - * A record of a significant event occurring during an agent's execution, with a `type`, `title`, `content`, etc. - -* **`ObservationManager`** - * Manages the recording and retrieval of `Observation`s, interacting with `ObservationRepository` and notifying `ObservationSocket`. - -* **`ObservationRepository`** - * Persists and retrieves `Observation`s using a `StorageAdapter`. - -* **`ObservationSocket`** - * A `TypedSocket` for broadcasting new `Observation`s to UI subscribers. - -* **`ObservationType`** - * An enum categorizing the type of an `Observation` (e.g., `INTENT`, `PLAN`, `TOOL_EXECUTION`, `ERROR`). - -* **`OutputParser`** - * A component in the Reasoning System responsible for parsing raw LLM string outputs into structured data (e.g., extracting intent, plan, tool calls, and `` tag content). - -**P** - -* **`ParsedToolCall`** - * A structured representation of an LLM's request to call a tool, as parsed by `OutputParser`. Contains `callId`, `toolName`, and `arguments`. - -* **`PESAgent` (Plan-Execute-Synthesize Agent)** - * The default `IAgentCore` implementation in ART, following a three-stage process. - -* **`PromptManager`** - * A component in the Reasoning System that provides access to named prompt fragments (`getFragment`) and validates `ArtStandardPrompt` objects (`validatePrompt`). - -* **`ProviderAdapter`** - * An adapter that implements `ReasoningEngine` to connect ART to a specific LLM provider's API (e.g., `OpenAIAdapter`, `AnthropicAdapter`). - -* **`ProviderManager` (`IProviderManager`, `ProviderManagerImpl`)** - * Manages the lifecycle and access to multiple `ProviderAdapter`s, enabling dynamic LLM selection. - -* **`ProviderManagerConfig`** - * Configuration for the `ProviderManager`, defining all `availableProviders` and global settings like concurrency limits. Passed in `ArtInstanceConfig`. - -**R** - -* **Reasoning System** - * A conceptual grouping of ART components responsible for LLM interactions (`ReasoningEngine`, `ProviderManager`, `ProviderAdapter`, `PromptManager`, `OutputParser`). - -* **`ReasoningEngine`** - * The interface (and its implementation `ReasoningEngineImpl`) used by agents to make calls to LLMs. It delegates to the `ProviderManager` to get an appropriate `ProviderAdapter`. - -* **`RuntimeProviderConfig`** - * Configuration passed in `CallOptions` for a *specific* LLM call, specifying the `providerName`, `modelId`, and `adapterOptions` (like API key). - -**S** - -* **`StateSavingStrategy`** - * A configuration option ('explicit' or 'implicit') in `ArtInstanceConfig` that determines how `AgentState` is persisted by the `StateManager`. - -* **`StateManager`** - * Manages `ThreadConfig` and `AgentState` for conversation threads, interacting with `StateRepository` and respecting the `StateSavingStrategy`. - -* **`StateRepository`** - * Persists and retrieves `ThreadContext` (which includes `ThreadConfig` and `AgentState`) using a `StorageAdapter`. - -* **Storage System** - * A conceptual grouping for data persistence, primarily the `StorageAdapter` interface and its implementations. - -* **`StorageAdapter`** - * An interface for abstracting data storage operations (get, set, delete, query). Implemented by `InMemoryStorageAdapter`, `IndexedDBStorageAdapter`. - -* **`StreamEvent`** - * A standardized object (`type`, `data`, `tokenType?`, `threadId`, etc.) representing a chunk of data from an LLM's streaming response. - -**T** - -* **`` Tags** - * XML-like tags (`...`) that can be used in LLM prompts to encourage the model to output its reasoning steps. `OutputParser` extracts content from these tags. - -* **`ThreadConfig`** - * Configuration specific to a conversation thread, including default `providerConfig`, `enabledTools`, and `historyLimit`. - -* **`ThreadContext`** - * An object bundling the `ThreadConfig` and `AgentState` for a specific thread. - -* **Tool** - * An external capability or action an agent can use, implemented via `IToolExecutor`. - -* **Tool System** - * A conceptual grouping of ART components for tool management and execution (`ToolRegistry`, `ToolSystem`, `IToolExecutor`). - -* **`ToolRegistry`** - * Manages the registration and retrieval of `IToolExecutor` instances. - -* **`ToolResult`** - * The standardized output from an `IToolExecutor.execute()` call, indicating `status` (success/error), `output` data, or an `error` message. - -* **`ToolSchema`** - * Metadata describing a tool, including its `name`, `description`, and `inputSchema` (JSON Schema). - -* **`ToolSystem`** - * Orchestrates the execution of `ParsedToolCall`s, including verification, validation, and calling the tool executor. - -* **`TypedSocket`** - * A generic base class for creating publish/subscribe channels with filtering, used by `LLMStreamSocket`, `ObservationSocket`, and `ConversationSocket`. - -**U** - -* **UI System** - * A conceptual grouping providing access to UI communication sockets (`UISystem`, `LLMStreamSocket`, `ObservationSocket`, `ConversationSocket`). - -* **`UISystem`** - * A service that instantiates and provides access to the specialized UI sockets. - -**V** - -* **`validateJsonSchema`** - * A utility function (`src/utils/validation.ts`) that uses Ajv to validate data against a JSON Schema. - -**X** - -* **`XmlMatcher`** - * A utility class (`src/utils/xml-matcher.ts`) for finding and extracting content within a specific XML-like tag from text, used by `OutputParser` for `` tags. \ No newline at end of file diff --git a/Docs/how-to/configure-art-instance.md b/Docs/how-to/configure-art-instance.md deleted file mode 100644 index 373be50..0000000 --- a/Docs/how-to/configure-art-instance.md +++ /dev/null @@ -1,285 +0,0 @@ -# How-To: Configure an ART Instance - -The foundation of any ART Framework application is the `ArtInstance`, which is created and configured using the `createArtInstance` function and an `ArtInstanceConfig` object. This guide provides examples of how to configure `ArtInstanceConfig` for various common scenarios. - -## Basic Structure of `ArtInstanceConfig` - -Recall the key properties of `ArtInstanceConfig` (from `src/types/index.ts`): - -```typescript -export interface ArtInstanceConfig { - storage: StorageAdapter | { type: 'memory' | 'indexedDB', ... }; // Required - providers: ProviderManagerConfig; // Required - agentCore?: new (dependencies: any) => IAgentCore; - tools?: IToolExecutor[]; - stateSavingStrategy?: StateSavingStrategy; - logger?: { level?: LogLevel }; -} -``` - -## Scenario 1: Simple In-Memory Agent (for Testing/Demos) - -This setup is quick and easy, perfect for testing, quick demos, or agents that don't need to remember anything between sessions. It uses `InMemoryStorageAdapter` and a mock or a single API-based LLM provider. - -```typescript -import { - ArtInstanceConfig, - // For a real LLM: - // OpenAIAdapter, - // AnthropicAdapter, - // For a local LLM via Ollama: - OllamaAdapter, - CalculatorTool, - LogLevel -} from 'art-framework'; - -// If using a real LLM, ensure API keys are handled securely (e.g., environment variables) -// const OPENAI_API_KEY = process.env.OPENAI_API_KEY; - -const simpleInMemoryConfig: ArtInstanceConfig = { - // 1. Storage: Use in-memory (data lost on session end) - storage: { - type: 'memory' - }, - - // 2. Providers: Configure LLM access - providers: { - availableProviders: [ - // Option A: Using Ollama for a local model (replace 'llama3' with your model) - { - name: 'local-llm', - adapter: OllamaAdapter, - isLocal: true, // Important for local provider behavior - }, - // Option B: Using a cloud provider (e.g., OpenAI - uncomment and add API key) - /* - { - name: 'openai-chat', - adapter: OpenAIAdapter, - isLocal: false, - }, - */ - ], - // Defaults are usually fine for a single provider setup - maxParallelApiInstancesPerProvider: 1, - apiInstanceIdleTimeoutSeconds: 300, - }, - - // 3. Tools (Optional): Add any tools the agent should use - tools: [ - new CalculatorTool(), - ], - - // 4. Agent Core (Optional): Defaults to PESAgent, which is suitable for most cases. - // agentCore: MyCustomAgentClass, - - // 5. State Saving Strategy (Optional): Defaults to 'explicit'. - // 'implicit' can be convenient if agent state changes should always be saved. - stateSavingStrategy: 'implicit', - - // 6. Logger (Optional): Configure logging verbosity - logger: { - level: LogLevel.DEBUG, // More verbose for development/testing - } -}; - -// To use this config: -// import { createArtInstance } from 'art-framework'; -// async function main() { -// const art = await createArtInstance(simpleInMemoryConfig); -// // Now you can use art.process(...) -// // Remember to provide RuntimeProviderConfig in AgentProps.options -// // For Ollama example: -// /* -// const response = await art.process({ -// query: "Hello!", -// threadId: "thread-ollama-test", -// options: { -// providerConfig: { -// providerName: 'local-llm', // Matches name in availableProviders -// modelId: 'llama3', // Your Ollama model -// adapterOptions: { -// // For Ollama, default ollamaBaseUrl and apiKey are often sufficient -// // ollamaBaseUrl: 'http://localhost:11434' // Default -// } -// } -// } -// }); -// */ -// // For OpenAI example: -// /* -// if (!OPENAI_API_KEY) throw new Error("OpenAI API key not set."); -// const response = await art.process({ -// query: "Hello!", -// threadId: "thread-openai-test", -// options: { -// providerConfig: { -// providerName: 'openai-chat', -// modelId: 'gpt-3.5-turbo', -// adapterOptions: { apiKey: OPENAI_API_KEY } -// } -// } -// }); -// console.log(response.response.content); -// */ -// } -// main(); -``` - -## Scenario 2: Persistent Web Agent with IndexedDB and Multiple LLM Options - -This setup is for web applications where conversation history and agent state need to persist across browser sessions. It also demonstrates configuring multiple LLM providers. - -```typescript -import { - ArtInstanceConfig, - OpenAIAdapter, - AnthropicAdapter, - CalculatorTool, - LogLevel - // Assuming you have a WeatherTool defined as per other guides - // import { WeatherTool } from './path/to/your/WeatherTool'; -} from 'art-framework'; - -// Ensure API keys are handled securely (e.g., from a backend or secure config) -// const OPENAI_API_KEY = process.env.REACT_APP_OPENAI_API_KEY; -// const ANTHROPIC_API_KEY = process.env.REACT_APP_ANTHROPIC_API_KEY; - -const persistentWebConfig: ArtInstanceConfig = { - // 1. Storage: Use IndexedDB for persistence in the browser - storage: { - type: 'indexedDB', - dbName: 'MyWebAppAgentDB_V1', // Choose a unique name for your app's DB - dbVersion: 1, // Increment if you change objectStores schema - // Default objectStores ('conversations', 'observations', 'state') are usually sufficient - }, - - // 2. Providers: Configure multiple LLM providers - providers: { - availableProviders: [ - { - name: 'openai-gpt4o-mini', - adapter: OpenAIAdapter, - isLocal: false, - }, - { - name: 'anthropic-claude3-haiku', - adapter: AnthropicAdapter, - isLocal: false, - } - // You could also add an OllamaAdapter entry here for local model support - ], - maxParallelApiInstancesPerProvider: 2, // Allow a couple of concurrent calls per provider type - apiInstanceIdleTimeoutSeconds: 180, // Evict idle adapters after 3 minutes - }, - - // 3. Tools: - tools: [ - new CalculatorTool(), - // new WeatherTool(), // Your custom tool - ], - - // 4. State Saving Strategy: - stateSavingStrategy: 'implicit', // Auto-save agent state changes - - // 5. Logger: - logger: { - level: LogLevel.INFO, // Less verbose for a web app, DEBUG during development - } -}; - -// How to use it (conceptual, assuming API keys are available): -// async function initializeWebAppAgent() { -// if (!OPENAI_API_KEY || !ANTHROPIC_API_KEY) { -// console.error("API keys are missing!"); -// return; -// } -// const art = await createArtInstance(persistentWebConfig); -// -// // Example: User chooses OpenAI for a query -// const openAIResponse = await art.process({ -// query: "Explain quantum entanglement simply.", -// threadId: "userXYZ-chat1", -// options: { -// providerConfig: { -// providerName: 'openai-gpt4o-mini', -// modelId: 'gpt-4o-mini', // Could also be just 'gpt-4o' if the entry name is generic -// adapterOptions: { apiKey: OPENAI_API_KEY } -// } -// } -// }); -// console.log("OpenAI says:", openAIResponse.response.content); - -// // Example: User chooses Anthropic for another query in the same thread -// const anthropicResponse = await art.process({ -// query: "Write a poem about a persistent database.", -// threadId: "userXYZ-chat1", // Same thread, history will be used -// options: { -// providerConfig: { -// providerName: 'anthropic-claude3-haiku', -// modelId: 'claude-3-haiku-20240307', -// adapterOptions: { apiKey: ANTHROPIC_API_KEY } -// } -// } -// }); -// console.log("Anthropic says:", anthropicResponse.response.content); -// } -``` - -## Scenario 3: Custom Agent Core and Explicit State Saving - -This example shows how to specify a custom agent core implementation and use explicit state saving. - -```typescript -import { - ArtInstanceConfig, - IAgentCore, // For typing MyCustomAgent - // ... other necessary imports - OpenAIAdapter, - LogLevel -} from 'art-framework'; - -// Assume MyCustomAgent is defined elsewhere and implements IAgentCore -// import { MyCustomAgent } from './my-custom-agent'; - -const customAgentConfig: ArtInstanceConfig = { - storage: { type: 'memory' }, // Or 'indexedDB' - providers: { - availableProviders: [ - { name: 'default-openai', adapter: OpenAIAdapter, isLocal: false } - ], - }, - // agentCore: MyCustomAgent, // Specify your custom agent class - tools: [ /* ... your tools ... */ ], - stateSavingStrategy: 'explicit', // Agent must call stateManager.setAgentState() - logger: { - level: LogLevel.DEBUG, - } -}; - -// Usage: -// const art = await createArtInstance(customAgentConfig); -// When art.process() is called, it will use MyCustomAgent. -// MyCustomAgent's logic would be responsible for calling: -// await stateManager.setAgentState(threadId, newAgentState); -// whenever it needs to persist changes to the AgentState. -// The PESAgent's automatic call to saveStateIfModified() will be a no-op for AgentState here. -``` - -## Key Configuration Points to Remember: - -* **`storage`**: Choose `'memory'` for transience or `'indexedDB'` for browser persistence. Provide `dbName` and `dbVersion` for IndexedDB. -* **`providers.availableProviders`**: - * Define each LLM provider setup you intend to use. - * `name` is how you'll refer to it in `RuntimeProviderConfig`. - * `adapter` is the specific adapter class (e.g., `OpenAIAdapter`). - * `isLocal: true` for providers like Ollama to enforce singleton behavior. -* **`RuntimeProviderConfig` (in `AgentProps.options`):** This is crucial for *every* call to `art.process()`. It tells ART: - * `providerName`: Which entry from `availableProviders` to use. - * `modelId`: The specific model for that provider (e.g., "gpt-4o-mini", "llama3"). - * `adapterOptions`: Runtime options for the adapter, most importantly the `apiKey` for cloud providers. -* **`tools`**: Provide instances of your `IToolExecutor` implementations. -* **`stateSavingStrategy`**: Decide if you want `'implicit'` state saving (convenient) or `'explicit'` control. -* **`logger.level`**: Adjust verbosity for development vs. production. - -By carefully crafting your `ArtInstanceConfig`, you can tailor the ART Framework to a wide variety of agent application needs. \ No newline at end of file diff --git a/Docs/how-to/configure-system-prompts.md b/Docs/how-to/configure-system-prompts.md deleted file mode 100644 index 0da2faa..0000000 --- a/Docs/how-to/configure-system-prompts.md +++ /dev/null @@ -1,118 +0,0 @@ -# How-To: Configuring System Prompts in ART Framework - -This guide explains how to configure and customize system prompts for your agents in the ART Framework (`v0.2.8` and later), leveraging the new hierarchical system. - -## Understanding the System Prompt Layers - -As detailed in the "Core Concept: System Prompt Hierarchy and Customization" document, system prompts are resolved in the following order of precedence (highest to lowest), with each level's custom prompt part (if present) being appended to the agent's internal base prompt: - -1. **Call-Level**: Via `AgentProps.options.systemPrompt` -2. **Thread-Level**: Via `ThreadConfig.systemPrompt` -3. **Instance-Level**: Via `ArtInstanceConfig.defaultSystemPrompt` -4. **Agent Base Prompt**: Internal to the agent (e.g., `PESAgent.defaultSystemPrompt`) - -The final system prompt is effectively: `Agent Base Prompt + "\n\n" + Highest Precedence Custom Prompt Part`. - -## 1. Setting an Instance-Level Default System Prompt - -This sets a default custom prompt for all agents created by a specific ART instance, unless overridden at a more specific level. - -**File**: Your ART instance creation script (e.g., `main.ts`, `index.ts`) -**Property**: `defaultSystemPrompt` in `ArtInstanceConfig` - -```typescript -// Example: main.ts -import { createArtInstance, ArtInstanceConfig } from '@art-framework/core'; // Adjust import path -// ... other imports - -async function initializeMyAgent() { - const config: ArtInstanceConfig = { - storage: { type: 'memory' }, - providers: { /* ... your provider manager config ... */ }, - // ... other instance configurations ... - defaultSystemPrompt: "You are a witty and slightly sarcastic assistant. You always try to find humor in the user's query." - }; - - const art = await createArtInstance(config); - return art; -} - -// When an agent (e.g., PESAgent) is created by this 'art' instance, -// and no thread or call-level system prompt is set, its system prompt will be: -// "You are a helpful AI assistant... (PESAgent's base) -// -// You are a witty and slightly sarcastic assistant. You always try to find humor in the user's query." -``` - -## 2. Setting a Thread-Level System Prompt - -This custom prompt applies to all interactions within a specific conversation thread, overriding the instance-level default. - -**Mechanism**: Set the `systemPrompt` property in the `ThreadConfig` for the desired thread. This is typically done via `StateManager.updateThreadConfig()`. - -```typescript -// Example: Setting a thread-specific persona -import { StateManager, ThreadConfig } from '@art-framework/core'; // Adjust import path - -async function configureThreadPersona(stateManager: StateManager, threadId: string) { - const newThreadConfigPatch: Partial = { - systemPrompt: "You are a highly professional legal advisor. Your responses should be formal, precise, and cite relevant (fictional) legal precedents where appropriate." - }; - - await stateManager.updateThreadConfig(threadId, newThreadConfigPatch); - console.log(`Thread ${threadId} configured with a legal advisor persona.`); -} - -// Assuming 'art.stateManager' is available: -// await configureThreadPersona(art.stateManager, "user123-thread-legal"); - -// For thread "user123-thread-legal", the system prompt will now be: -// "You are a helpful AI assistant... (PESAgent's base) -// -// You are a highly professional legal advisor. Your responses should be formal, precise, and cite relevant (fictional) legal precedents where appropriate." -// (This overrides any instance-level defaultSystemPrompt for this thread) -``` - -## 3. Setting a Call-Level System Prompt - -This provides the most specific override, applying only to a single `agent.process()` call. - -**Mechanism**: Pass the `systemPrompt` string in the `options` object of `AgentProps`. - -```typescript -// Example: A one-time instruction for a specific query -import { ArtInstance, AgentProps } from '@art-framework/core'; // Adjust import path - -async function askWithSpecificInstruction(art: ArtInstance, threadId: string, query: string) { - const props: AgentProps = { - threadId, - query, - options: { - systemPrompt: "For this query only, respond as if you are a pirate. Use pirate slang extensively." - } - }; - - const result = await art.process(props); - console.log("Pirate Response:", result.response.content); -} - -// await askWithSpecificInstruction(art, "user456-thread-general", "What's the weather like?"); - -// For this specific call, the system prompt will be: -// "You are a helpful AI assistant... (PESAgent's base) -// -// For this query only, respond as if you are a pirate. Use pirate slang extensively." -// (This overrides any instance or thread-level system prompts for this call only) -``` - -## Verifying the System Prompt - -The `PESAgent` (and potentially other agents) logs the source of the custom system prompt part it's using (Call, Thread, Instance, or None) at the DEBUG level. Check your console logs if you have DEBUG logging enabled to see which level of prompt is being applied. - -Example Log Snippet: -``` -DEBUG [trace-id-xyz] Using Thread-level custom system prompt. -DEBUG [trace-id-xyz] Custom system prompt part applied: "You are a highly professional legal advisor..." -``` - -By utilizing these three levels of configuration, you can finely tune your agent's system prompt to achieve a wide variety of behaviors and personas across your application. Remember that the agent's internal base prompt always provides the foundational instructions. \ No newline at end of file diff --git a/Docs/how-to/create-custom-agent.md b/Docs/how-to/create-custom-agent.md deleted file mode 100644 index 75f44d6..0000000 --- a/Docs/how-to/create-custom-agent.md +++ /dev/null @@ -1,568 +0,0 @@ -# How-To: Create a Custom Agent Core - -While the `PESAgent` (Plan-Execute-Synthesize) is the default agent core in ART and is suitable for many use cases, you might encounter scenarios where you need a different orchestration logic or a more specialized reasoning pattern. The ART Framework allows you to create and use your own custom agent core by implementing the `IAgentCore` interface. - -## 1. Understand `IAgentCore` - -First, familiarize yourself with the `IAgentCore` interface defined in `src/core/interfaces.ts`: - -```typescript -export interface IAgentCore { - process(props: AgentProps): Promise; -} -``` - -Your custom agent class must have a `process` method that: -* Accepts `AgentProps` (containing `query`, `threadId`, `options`, etc.). -* Returns a `Promise` (containing the final `ConversationMessage` and `ExecutionMetadata`). - -## 2. Define Your Agent's Logic - -Decide on the reasoning pattern your custom agent will follow. Some examples: - -* **Simple Echo Agent:** Directly responds with a modified version of the query. -* **ReAct (Reason-Act) Agent:** Iteratively reasons about what to do, takes an action (calls a tool or responds to user), observes the result, and repeats until the goal is met. -* **Specialized Task Agent:** An agent designed for a very specific task that might not fit the general PES flow, perhaps with a fixed sequence of LLM calls or tool uses. - -## 3. Create Your Custom Agent Class - -Create a new TypeScript file (e.g., `src/agents/my-custom-agent.ts`) for your agent. - -```typescript -// src/agents/my-custom-agent.ts -import { - IAgentCore, - AgentProps, - AgentFinalResponse, - ConversationMessage, - MessageRole, - ExecutionMetadata, - // Import any dependencies your agent will need from ART's core interfaces - StateManager, - ConversationManager, - ReasoningEngine, - ObservationManager, - ToolRegistry, // If your agent uses tools - OutputParser, // If your agent parses LLM output - ToolSystem, // If your agent executes tools - UISystem -} from 'art-framework'; -import { generateUUID } from 'art-framework'; // Assuming generateUUID is exported - -// Define the structure of dependencies your agent expects in its constructor -interface MyCustomAgentDependencies { - stateManager: StateManager; - conversationManager: ConversationManager; - reasoningEngine: ReasoningEngine; - observationManager: ObservationManager; - uiSystem: UISystem; - // Add other dependencies like ToolRegistry, OutputParser, ToolSystem if needed -} - -export class MyCustomAgent implements IAgentCore { - private deps: MyCustomAgentDependencies; - - constructor(dependencies: MyCustomAgentDependencies) { - this.deps = dependencies; - // Initialize any internal state for your agent if necessary - } - - async process(props: AgentProps): Promise { - const startTime = Date.now(); - const traceId = props.traceId || generateUUID(); - let status: ExecutionMetadata['status'] = 'success'; - let errorMessage: string | undefined; - let llmCalls = 0; - - console.log(`MyCustomAgent processing query for thread ${props.threadId}: "${props.query}"`); - - // --- 1. Load Context (Example) --- - // You'll likely need thread configuration and history - let threadContext; - try { - threadContext = await this.deps.stateManager.loadThreadContext(props.threadId, props.userId); - if (!threadContext) { - throw new Error("Thread context not found."); - } - } catch (e: any) { - // Handle error loading context - errorMessage = `Failed to load context: ${e.message}`; - status = 'error'; - // Construct and return an error response - const errorMsg: ConversationMessage = { /* ... */ messageId: generateUUID(), threadId: props.threadId, role: MessageRole.AI, content: errorMessage, timestamp: Date.now() }; - return { response: errorMsg, metadata: { /* fill metadata */ threadId: props.threadId, traceId, status, totalDurationMs: Date.now() - startTime, llmCalls, toolCalls: 0, error: errorMessage } }; - } - - // --- 2. Implement Your Agent's Core Logic --- - // This is where your custom reasoning pattern goes. - // For example, a simple agent that calls an LLM once: - - let finalContent = `MyCustomAgent processed: "${props.query}".`; - - if (props.options?.providerConfig) { // Check if providerConfig is available - try { - const systemPrompt = "You are MyCustomAgent. Be brief."; - const promptForLLM: FormattedPrompt = [ // FormattedPrompt is ArtStandardPrompt - { role: 'system', content: systemPrompt }, - { role: 'user', content: props.query } - ]; - - const llmCallOptions = { - threadId: props.threadId, - traceId, - stream: false, // Or true if you handle streaming - callContext: 'CUSTOM_AGENT_CALL', - providerConfig: props.options.providerConfig, - // Add any other LLM parameters from props.options.llmParams or threadContext.config - }; - - const llmResponseStream = await this.deps.reasoningEngine.call(promptForLLM, llmCallOptions); - llmCalls++; - - let streamedText = ""; - for await (const event of llmResponseStream) { - this.deps.uiSystem.getLLMStreamSocket().notify(event, { targetThreadId: props.threadId, targetSessionId: props.sessionId }); - if (event.type === 'TOKEN') { - streamedText += event.data; - } else if (event.type === 'ERROR') { - throw event.data instanceof Error ? event.data : new Error(String(event.data)); - } - } - finalContent = streamedText.trim(); - - } catch (e: any) { - console.error(`MyCustomAgent LLM call failed: ${e.message}`); - errorMessage = `LLM interaction failed: ${e.message}`; - status = 'error'; // Or 'partial' if some steps succeeded - finalContent = errorMessage; // Use error as content - } - } else { - finalContent = "MyCustomAgent: No LLM provider configured for this call."; - status = 'partial'; - errorMessage = "Missing providerConfig in AgentProps.options"; - } - - - // --- 3. Finalization (Example) --- - const finalTimestamp = Date.now(); - const aiResponseMessage: ConversationMessage = { - messageId: generateUUID(), - threadId: props.threadId, - role: MessageRole.AI, - content: finalContent, - timestamp: finalTimestamp, - metadata: { traceId }, - }; - - // Save user query and AI response to history - const userQueryMessage: ConversationMessage = { - messageId: generateUUID(), // Or a more specific ID if available - threadId: props.threadId, - role: MessageRole.USER, - content: props.query, - timestamp: startTime, // Approximate start time of user query - metadata: { traceId }, - }; - try { - await this.deps.conversationManager.addMessages(props.threadId, [userQueryMessage, aiResponseMessage]); - } catch (e: any) { - // Log error, but might still return the response - console.error(`MyCustomAgent: Failed to save messages: ${e.message}`); - if (status !== 'error') { // Don't overwrite a more critical error - status = 'partial'; - errorMessage = (errorMessage ? errorMessage + "; " : "") + "Failed to save conversation history."; - } - } - - // Save state if modified (respecting StateSavingStrategy) - try { - await this.deps.stateManager.saveStateIfModified(props.threadId); - } catch (e: any) { - console.error(`MyCustomAgent: Failed to save state: ${e.message}`); - if (status !== 'error') { - status = 'partial'; - errorMessage = (errorMessage ? errorMessage + "; " : "") + "Failed to save agent state."; - } - } - - // Record observations (example) - // await this.deps.observationManager.record({ type: ObservationType.FINAL_RESPONSE, ... }); - - - // --- 4. Return AgentFinalResponse --- - const metadata: ExecutionMetadata = { - threadId: props.threadId, - traceId: traceId, - userId: props.userId, - status: status, - totalDurationMs: Date.now() - startTime, - llmCalls: llmCalls, - toolCalls: 0, // Update if your agent uses tools - error: errorMessage, - // llmMetadata: aggregatedLlmMetadata // Collect if streaming and multiple calls - }; - - return { - response: aiResponseMessage, - metadata: metadata, - }; - } -} -``` - -**Key Considerations for Your Custom Agent:** - -* **Dependencies:** Define a constructor that accepts an object of dependencies. The `AgentFactory` will inject instances of `StateManager`, `ConversationManager`, `ReasoningEngine`, `ObservationManager`, `UISystem`, and potentially `ToolRegistry`, `OutputParser`, `ToolSystem` if your agent needs them. -* **Context Management:** Use `StateManager` to load `ThreadContext` (config and state) and `ConversationManager` to get message history. -* **Prompt Construction:** You are responsible for creating the `ArtStandardPrompt` array of `ArtStandardMessage` objects to send to the `ReasoningEngine`. You can use `PromptManager.getFragment()` for reusable text pieces. -* **LLM Interaction:** Use `ReasoningEngine.call(prompt, callOptions)`. - * Provide `CallOptions` including `stream` preference, `callContext`, and the crucial `providerConfig` (from `AgentProps.options.providerConfig` or resolved from `ThreadConfig`). - * Handle the `AsyncIterable` returned, especially if streaming. -* **Tool Usage (If Applicable):** - * Get available tools from `ToolRegistry`. - * If your LLM plan indicates tool use, parse it (perhaps using `OutputParser` or custom logic). - * Execute tools using `ToolSystem.executeTools()`. - * Incorporate `ToolResult`s into subsequent LLM prompts. -* **State Saving:** - * If using `'implicit'` `StateSavingStrategy`, modifications to `threadContext.state` will be auto-saved when `stateManager.saveStateIfModified()` is called (you should call this, typically in a `finally` block or at the end). - * If using `'explicit'` strategy, you **must** call `stateManager.setAgentState()` to persist any changes to agent state. -* **Observation Recording:** Use `ObservationManager.record()` to log significant events. -* **UI Notifications:** Use sockets from `UISystem` (`llmStreamSocket`, `conversationSocket`, `observationSocket`) to `notify` the UI of real-time events. -* **Error Handling:** Implement robust error handling. Catch errors from dependencies, set appropriate `status` and `errorMessage` in `ExecutionMetadata`, and potentially return an error message as the AI's content. -* **Final Response:** Ensure you construct and return a valid `AgentFinalResponse`. - -## 4. Configure ART to Use Your Custom Agent - -In your `ArtInstanceConfig`, set the `agentCore` property to your custom agent class: - -```typescript -// src/config/art-config.ts -import { ArtInstanceConfig /* ... */ } from 'art-framework'; -import { MyCustomAgent } from '../agents/my-custom-agent'; // Adjust path - -export const myAppArtConfig: ArtInstanceConfig = { - // ... storage and provider config ... - agentCore: MyCustomAgent, // Specify your custom agent - // ... tools, stateSavingStrategy, logger ... -}; -``` - -Now, when you call `createArtInstance(myAppArtConfig)`, the `AgentFactory` will instantiate `MyCustomAgent` and inject the necessary dependencies. Calls to `art.process()` will invoke your custom agent's logic. - -Creating a custom agent core gives you maximum flexibility to define unique agent behaviors and reasoning patterns within the ART Framework's structured environment. -``` - -```markdown -docs/how-to/add-llm-adapter.md -``` -```markdown -# How-To: Add a Custom LLM Provider Adapter - -The ART Framework's `ProviderManager` and `ProviderAdapter` interface allow you to integrate virtually any Large Language Model (LLM) provider. If ART doesn't have a built-in adapter for your desired LLM, you can create your own. - -## Steps to Create a Custom `ProviderAdapter` - -1. **Understand the `ProviderAdapter` Interface:** - Review `src/core/interfaces.ts`. Your adapter must implement: - ```typescript - export interface ProviderAdapter extends ReasoningEngine { - readonly providerName: string; - // call(prompt: FormattedPrompt, options: CallOptions): Promise>; // Inherited from ReasoningEngine - shutdown?(): Promise; - } - ``` - And `ReasoningEngine` requires: - ```typescript - export interface ReasoningEngine { - call(prompt: FormattedPrompt, options: CallOptions): Promise>; - } - ``` - * `FormattedPrompt` is an alias for `ArtStandardPrompt`. - -2. **Create Your Adapter Class:** - Create a new TypeScript file (e.g., `src/my-adapters/my-llm-adapter.ts`). - - ```typescript - // src/my-adapters/my-llm-adapter.ts - import { - ProviderAdapter, - ArtStandardPrompt, - ArtStandardMessage, // For prompt translation - CallOptions, - StreamEvent, - LLMMetadata, - Logger, - ARTError, - ErrorCode - } from 'art-framework'; - // Import any SDK or HTTP client for your target LLM API - // import MyLlmApiClient from 'my-llm-api-sdk'; - - export interface MyLlmAdapterOptions { - apiKey: string; - model?: string; // Default model for this adapter instance - baseURL?: string; - // Add other options your adapter needs - } - - export class MyLlmAdapter implements ProviderAdapter { - readonly providerName = 'my-custom-llm'; // Unique name - private options: MyLlmAdapterOptions; - // private apiClient: MyLlmApiClient; // Example SDK client - - constructor(options: MyLlmAdapterOptions) { - if (!options.apiKey) { - throw new ARTError('MyLlmAdapter requires an apiKey.', ErrorCode.MISSING_API_KEY); - } - this.options = options; - // this.apiClient = new MyLlmApiClient({ apiKey: options.apiKey, baseURL: options.baseURL }); - Logger.info(`${this.providerName} adapter initialized with model: ${options.model || 'not set'}`); - } - - async call( - prompt: ArtStandardPrompt, - callOptions: CallOptions - ): Promise> { - const modelToUse = callOptions.providerConfig.modelId || this.options.model; - if (!modelToUse) { - throw new ARTError(`Model ID not specified for ${this.providerName} call.`, ErrorCode.INVALID_CONFIG); - } - - Logger.debug(`[${this.providerName}] Calling model ${modelToUse} for thread ${callOptions.threadId}`, { callOptions }); - - // --- 1. Translate ArtStandardPrompt to Provider-Specific Format --- - const providerRequestPayload = this.translatePromptToMyLlmFormat(prompt, modelToUse, callOptions); - - // --- 2. Make the API Call (Streaming or Non-Streaming) --- - if (callOptions.stream) { - return this.handleStreamCall(providerRequestPayload, callOptions); - } else { - return this.handleNonStreamCall(providerRequestPayload, callOptions); - } - } - - private translatePromptToMyLlmFormat( - artPrompt: ArtStandardPrompt, - model: string, - callOptions: CallOptions - ): any { - // Example: Convert ArtStandardMessage roles/content to your LLM's format - // This is highly dependent on the target LLM's API - const messages = artPrompt.map(artMsg => { - let role = artMsg.role; - // Role mapping example - if (artMsg.role === 'assistant') role = 'model_assistant'; - else if (artMsg.role === 'tool_result') role = 'tool_feedback'; - - return { role_translated: role, content_translated: artMsg.content }; - }); - - const payload = { - model: model, - messages_provider_specific: messages, - temperature: callOptions.temperature, // Pass through common params - max_tokens: callOptions.max_tokens, - // Add tool definitions if your provider supports them - // tools: this.formatToolsForMyLlm(callOptions.tools), - }; - return payload; - } - - private async *handleStreamCall( - payload: any, - callOptions: CallOptions - ): AsyncIterable { - const startTime = Date.now(); - let timeToFirstTokenMs: number | undefined; - let outputTokens = 0; - - try { - // const stream = await this.apiClient.generateStream(payload); // Example SDK call - // For raw fetch with SSE: - // const response = await fetch(`${this.options.baseURL}/generate_stream`, { - // method: 'POST', body: JSON.stringify(payload), headers: { /* ... auth ... */ } - // }); - // if (!response.ok || !response.body) { /* throw error */ } - // const reader = response.body.pipeThrough(new TextDecoderStream()).getReader(); - - // --- Placeholder for actual streaming logic --- - Logger.warn(`[${this.providerName}] Streaming not fully implemented in this example adapter.`); - // Simulate a few token events for demonstration - const mockFullResponse = "This is a streamed response from MyCustomLLM."; - for (const word of mockFullResponse.split(" ")) { - await new Promise(r => setTimeout(r, 50)); // Simulate delay - if (!timeToFirstTokenMs) timeToFirstTokenMs = Date.now() - startTime; - outputTokens++; - yield { - type: 'TOKEN', - data: word + " ", - tokenType: callOptions.callContext === 'AGENT_THOUGHT' ? 'AGENT_THOUGHT_LLM_RESPONSE' : 'FINAL_SYNTHESIS_LLM_RESPONSE', - threadId: callOptions.threadId, - traceId: callOptions.traceId!, - sessionId: callOptions.sessionId, - }; - } - // --- End Placeholder --- - - // Example: Processing chunks from an actual SSE stream - // while (true) { - // const { value, done } = await reader.read(); - // if (done) break; - // // Parse SSE lines (data: {...}) - // // For each text chunk: - // // if (!timeToFirstTokenMs) timeToFirstTokenMs = Date.now() - startTime; - // // outputTokens++; - // // yield { type: 'TOKEN', data: textChunk, ... }; - // // For final metadata from stream (if provider sends it): - // // yield { type: 'METADATA', data: { ... }, ... }; - // } - - const metadata: LLMMetadata = { - stopReason: 'stop', // Or from provider - outputTokens, - timeToFirstTokenMs, - totalGenerationTimeMs: Date.now() - startTime, - // inputTokens: from_provider_if_available, - providerRawUsage: { /* any raw data from provider */ } - }; - yield { type: 'METADATA', data: metadata, threadId: callOptions.threadId, traceId: callOptions.traceId!, sessionId: callOptions.sessionId }; - - } catch (error: any) { - Logger.error(`[${this.providerName}] Stream call error: ${error.message}`, error); - yield { type: 'ERROR', data: new ARTError(error.message, ErrorCode.LLM_PROVIDER_ERROR, error), threadId: callOptions.threadId, traceId: callOptions.traceId!, sessionId: callOptions.sessionId }; - } finally { - yield { type: 'END', data: null, threadId: callOptions.threadId, traceId: callOptions.traceId!, sessionId: callOptions.sessionId }; - } - } - - private async *handleNonStreamCall( - payload: any, - callOptions: CallOptions - ): AsyncIterable { - const startTime = Date.now(); - try { - // const response = await this.apiClient.generate(payload); // Example SDK call - // const responseText = response.choices[0].text; - // const usage = response.usage; - - // --- Placeholder for actual non-streaming logic --- - Logger.warn(`[${this.providerName}] Non-streaming not fully implemented in this example adapter.`); - const responseText = "This is a non-streamed response from MyCustomLLM."; - const usage = { prompt_tokens: 10, completion_tokens: 7 }; // Mock usage - // --- End Placeholder --- - - - yield { - type: 'TOKEN', - data: responseText, - tokenType: callOptions.callContext === 'AGENT_THOUGHT' ? 'AGENT_THOUGHT_LLM_RESPONSE' : 'FINAL_SYNTHESIS_LLM_RESPONSE', - threadId: callOptions.threadId, - traceId: callOptions.traceId!, - sessionId: callOptions.sessionId, - }; - - const metadata: LLMMetadata = { - inputTokens: usage.prompt_tokens, - outputTokens: usage.completion_tokens, - stopReason: 'stop', // Or from provider - totalGenerationTimeMs: Date.now() - startTime, - providerRawUsage: { usage } - }; - yield { type: 'METADATA', data: metadata, threadId: callOptions.threadId, traceId: callOptions.traceId!, sessionId: callOptions.sessionId }; - - } catch (error: any) { - Logger.error(`[${this.providerName}] Non-stream call error: ${error.message}`, error); - yield { type: 'ERROR', data: new ARTError(error.message, ErrorCode.LLM_PROVIDER_ERROR, error), threadId: callOptions.threadId, traceId: callOptions.traceId!, sessionId: callOptions.sessionId }; - } finally { - yield { type: 'END', data: null, threadId: callOptions.threadId, traceId: callOptions.traceId!, sessionId: callOptions.sessionId }; - } - } - - // Optional: Implement if your adapter holds persistent resources - // async shutdown(): Promise { - // Logger.info(`${this.providerName} adapter shutting down.`); - // // await this.apiClient.closeConnection(); - // } - - // Optional: Helper to format tools for your LLM - // private formatToolsForMyLlm(artTools?: ToolSchema[]): any[] | undefined { /* ... */ } - } - ``` - -3. **Implement Prompt Translation:** - * In `translatePromptToMyLlmFormat` (or similar helper), convert the `ArtStandardPrompt` (array of `ArtStandardMessage`s) into the exact JSON payload structure your target LLM API expects. - * Pay close attention to how roles (`system`, `user`, `assistant`, `tool_result`) are mapped. - * Handle `ArtStandardMessage.tool_calls` and `tool_results` if your LLM supports function/tool calling. You'll need to format these according to your provider's specifications. - * If your provider requires tool schemas to be sent with the request (like OpenAI's `tools` parameter), format `ToolSchema` objects from `callOptions.tools` accordingly. - -4. **Implement API Call Logic:** - * **`handleStreamCall`:** - * Use your provider's SDK or an HTTP client (like `fetch`) to make a streaming request. - * Process the incoming stream (e.g., Server-Sent Events). For each piece of data: - * If it's a text chunk, `yield` a `TOKEN` `StreamEvent`. Set `tokenType` based on `callOptions.callContext`. - * If it's metadata (like final token counts or stop reason, some providers send this at the end of a stream), `yield` a `METADATA` `StreamEvent`. - * If an error occurs in the stream, `yield` an `ERROR` `StreamEvent`. - * Ensure you `yield` an `END` `StreamEvent` when the provider's stream finishes or an unrecoverable error occurs. - * **`handleNonStreamCall`:** - * Make a regular, non-streaming API request. - * Once the full response is received: - * `yield` one or more `TOKEN` `StreamEvent`s with the response content(s). - * `yield` a `METADATA` `StreamEvent` with token usage, stop reason, etc. - * `yield` an `END` `StreamEvent`. - -5. **Error Handling:** - * Wrap API errors or unexpected issues in `ARTError` with an appropriate `ErrorCode` (usually `LLM_PROVIDER_ERROR` or `NETWORK_ERROR`) and the original error. - * For streaming calls, yield these as `ERROR` `StreamEvent`s. For non-streaming, you might throw directly or yield an error stream. - -6. **Tool Support (If Applicable):** - * **Sending Tool Schemas:** If your LLM provider requires tool definitions to be sent with the prompt (like OpenAI's `tools` parameter), your adapter's `call` method (or a helper like `translatePromptToMyLlmFormat`) will need to access `callOptions.tools` (an array of `ToolSchema`) and format them into the provider-specific structure. - * **Receiving Tool Call Requests:** When the LLM responds with a request to call tools, your adapter needs to parse this from the provider's response format and ensure it can be understood by ART's `OutputParser` (ideally, translate it into a structure resembling `ArtStandardMessage.tool_calls` if the provider's format is very different, though often it's similar). - * **Sending Tool Results:** When the agent provides `tool_result` messages in the `ArtStandardPrompt`, your adapter must translate these into the format your LLM provider expects for tool execution feedback. - -7. **Register Your Adapter:** - Add an entry for your new adapter in the `availableProviders` array of your `ProviderManagerConfig` within `ArtInstanceConfig`. - - ```typescript - // src/config/art-config.ts - import { ArtInstanceConfig /* ... */ } from 'art-framework'; - import { MyLlmAdapter } from '../my-adapters/my-llm-adapter'; // Adjust path - - const artConfig: ArtInstanceConfig = { - // ... storage config ... - providers: { - availableProviders: [ - // ... other adapters ... - { - name: 'my-custom-llm-provider', // Unique name for ProviderManager - adapter: MyLlmAdapter, // Your adapter class - isLocal: false, // Or true if it's a local model - } - ], - // ... other ProviderManagerConfig settings ... - }, - // ... - }; - ``` - -8. **Use Your Adapter:** - In your `AgentProps.options`, specify the `providerName` (matching the name in `availableProviders`) and provide the necessary `adapterOptions` (like `apiKey`) for your adapter. - - ```typescript - // When calling art.process() - const agentProps: AgentProps = { - query: "Use my custom LLM", - threadId: "custom-llm-thread", - options: { - providerConfig: { - providerName: 'my-custom-llm-provider', - modelId: 'my-custom-model-v1', // Specific model your adapter will use - adapterOptions: { - apiKey: process.env.MY_CUSTOM_LLM_API_KEY, - // other options for MyLlmAdapter constructor - } - } - } - }; - ``` - -By following these steps, you can extend ART to support any LLM provider with an API. The key is careful translation between `ArtStandardPrompt`/`StreamEvent` and the provider's native formats. \ No newline at end of file diff --git a/Docs/how-to/define-tools.md b/Docs/how-to/define-tools.md deleted file mode 100644 index 9fa5936..0000000 --- a/Docs/how-to/define-tools.md +++ /dev/null @@ -1,228 +0,0 @@ -# How-To: Define and Use Tools - -Tools are a powerful feature of the ART Framework, enabling your AI agents to interact with external systems, fetch data, perform actions, and extend their capabilities beyond the LLM's inherent knowledge. This guide shows you how to define a custom tool and make it available to your agent. - -## 1. Understand `IToolExecutor` and `ToolSchema` - -Before creating a tool, review these core concepts: - -* **`IToolExecutor` (`src/core/interfaces.ts`):** The interface your custom tool class must implement. It has two main parts: - * `schema: ToolSchema` (readonly): Describes your tool to the LLM and ART. - * `async execute(input: any, context: ExecutionContext): Promise`: Contains your tool's logic. -* **`ToolSchema` (`src/types/index.ts`):** Defines the tool's metadata: - * `name: string`: Unique name (e.g., "get_stock_price"). - * `description: string`: Natural language description for the LLM. - * `inputSchema: JsonSchema`: JSON Schema for the tool's input arguments. - * `outputSchema?: JsonSchema` (Optional): JSON Schema for the tool's successful output. - * `examples?: Array<{...}>` (Optional): Usage examples. -* **`ToolResult` (`src/types/index.ts`):** The standardized return type from `execute()`: - * `callId: string`, `toolName: string`, `status: 'success' | 'error'`, `output?: any`, `error?: string`. - -(Refer to [Tools and Capabilities](tools-and-capabilities.md) for more details on these.) - -## 2. Create Your Custom Tool Class - -Let's create a simple tool that fetches a (mock) user's to-do list. - -```typescript -// src/tools/todo-list-tool.ts -import { - IToolExecutor, - ToolSchema, - JsonSchema, - ExecutionContext, - ToolResult, - Logger -} from 'art-framework'; - -// Mock data store for to-do items -const userTodoLists: Record = { - "user123": ["Buy groceries", "Book flight to Mars", "Walk the dog"], - "user456": ["Finish ART framework documentation", "Prepare presentation"] -}; - -export class TodoListTool implements IToolExecutor { - readonly schema: ToolSchema = { - name: "get_user_todos", - description: "Retrieves the to-do list for a specified user ID. If no user ID is provided, it attempts to fetch tasks for a default or currently inferred user (though this example requires userId).", - inputSchema: { - type: "object", - properties: { - userId: { - type: "string", - description: "The unique identifier of the user whose to-do list is being requested." - }, - filterStatus: { - type: "string", - description: "Optional. Filter tasks by status (e.g., 'pending', 'completed'). Not implemented in this mock.", - enum: ["pending", "completed", "all"] // Example enum - } - }, - required: ["userId"] - } as JsonSchema, // Cast if schema isn't fully exhaustive for JsonSchema type - outputSchema: { - type: "object", - properties: { - userId: { type: "string" }, - todos: { - type: "array", - items: { type: "string" } - } - }, - required: ["userId", "todos"] - } as JsonSchema, - examples: [ - { - input: { userId: "user123" }, - output: { userId: "user123", todos: ["Buy groceries", "Book flight to Mars", "Walk the dog"] }, - description: "Get to-do list for user123." - }, - { - input: { userId: "unknownUser" }, - error: "To-do list not found for user ID: unknownUser", - description: "Attempt to get to-dos for a non-existent user." - } - ] - }; - - async execute(input: { userId: string; filterStatus?: string }, context: ExecutionContext): Promise { - const callId = context.traceId || `todo-tool-${Date.now()}`; - Logger.info(`TodoListTool: Attempting to fetch to-dos for userId: ${input.userId}`, { callId, input, threadId: context.threadId }); - - if (!input.userId) { - const errorMsg = "userId is a required argument for get_user_todos."; - Logger.warn(`TodoListTool: ${errorMsg}`, { callId }); - return { callId, toolName: this.schema.name, status: 'error', error: errorMsg }; - } - - const todos = userTodoLists[input.userId]; - - if (todos) { - // In a real tool, you might apply input.filterStatus here - Logger.info(`TodoListTool: Found ${todos.length} to-dos for userId: ${input.userId}`, { callId }); - return { - callId, - toolName: this.schema.name, - status: 'success', - output: { - userId: input.userId, - todos: [...todos] // Return a copy - } - }; - } else { - const errorMessage = `To-do list not found for user ID: ${input.userId}`; - Logger.warn(`TodoListTool: ${errorMessage}`, { callId }); - return { - callId, - toolName: this.schema.name, - status: 'error', - error: errorMessage - }; - } - } -} -``` - -**Key points in this example:** -* **`schema`:** Defines the tool's name ("get_user_todos"), a description for the LLM, and an `inputSchema` requiring a `userId`. An `outputSchema` is also provided. -* **`execute` method:** - * Takes `input` (which will match the `inputSchema` after validation by `ToolSystem`) and `context`. - * Includes logging using `Logger`. - * Accesses a mock data store. In a real tool, this would be an API call, database query, etc. - * Returns a `ToolResult` with `status: 'success'` and the to-do list, or `status: 'error'` if the user is not found. - * Uses `context.traceId` for the `callId` in the result if available. - -## 3. Register Your Tool - -To make your `TodoListTool` available to agents, you need to register an instance of it with the `ToolRegistry`. The easiest way to do this is by including it in the `tools` array of your `ArtInstanceConfig` when calling `createArtInstance`. - -```typescript -// src/config/art-config.ts (or your main setup file) -import { - ArtInstanceConfig, - CalculatorTool, // Example of another tool - // ... other necessary imports from art-framework -} from 'art-framework'; -import { TodoListTool } from '../tools/todo-list-tool'; // Adjust path as needed - -export const myAppArtConfig: ArtInstanceConfig = { - storage: { type: 'memory' }, // Or your preferred storage - providers: { - availableProviders: [ - // ... your LLM provider configurations ... - // Example: - // { - // name: 'openai-chat', - // adapter: OpenAIAdapter, - // isLocal: false, - // } - ] - }, - tools: [ - new CalculatorTool(), - new TodoListTool() // Add an instance of your custom tool - ], - // ... other configurations (agentCore, stateSavingStrategy, logger) -}; - -// Then, when you create your ART instance: -// import { createArtInstance } from 'art-framework'; -// const art = await createArtInstance(myAppArtConfig); -``` -The `AgentFactory` (used by `createArtInstance`) will automatically register all tools provided in this array with the `ToolRegistry`. - -## 4. Enable the Tool for a Thread (Optional but Recommended) - -For better control, you can specify which tools are enabled for particular conversation threads using `ThreadConfig.enabledTools`. - -```typescript -// When setting up a thread or processing a query for a specific thread: -// import { StateManager, ThreadConfig, RuntimeProviderConfig } from 'art-framework'; - -// Assume 'stateManager' is available (e.g., from artInstance.stateManager) -// Assume 'OPENAI_API_KEY' is available - -// const threadId = "user123-chat-with-todos"; -// const initialThreadConfig: ThreadConfig = { -// providerConfig: { // Default provider for this thread -// providerName: 'openai-chat', // Matches a name in ArtInstanceConfig.providers.availableProviders -// modelId: 'gpt-3.5-turbo', -// adapterOptions: { apiKey: OPENAI_API_KEY } -// }, -// enabledTools: [ -// "get_user_todos", // Enable your custom tool by its schema.name -// "calculator" // Also enable the calculator -// ], -// historyLimit: 10, -// // systemPrompt: "You are a helpful assistant that can manage to-do lists." -// }; - -// await stateManager.setThreadConfig(threadId, initialThreadConfig); -``` -If `enabledTools` is configured for a thread, the `ToolRegistry.getAvailableTools({ enabledForThreadId: ... })` method (used by `PESAgent`) will only return these enabled tools to be included in the LLM's planning prompt. If `enabledTools` is not set or empty, the behavior might depend on the agent or registry configuration (often defaulting to all registered tools being available, or none if strict). - -## 5. Prompting the LLM to Use Your Tool - -The agent's planning prompt needs to inform the LLM about the `TodoListTool` so it knows it exists and how to use it. The `PESAgent` typically does this by: -1. Calling `toolRegistry.getAvailableTools({ enabledForThreadId: currentThreadId })`. -2. Including the `name`, `description`, and stringified `inputSchema` of each available tool in the planning prompt. - -The LLM will then use this information. If it decides `get_user_todos` is relevant, its planning output might include: - -``` -Tool Calls: [ - {"callId": "todo_call_1", "toolName": "get_user_todos", "arguments": {"userId": "user123"}} -] -``` - -The `OutputParser` extracts this, `ToolSystem` executes it, and the `ToolResult` (the to-do list or an error) is fed back into the agent's synthesis phase. - -## Summary - -Creating and using custom tools in ART involves: -1. Implementing `IToolExecutor` with a clear `ToolSchema`. -2. Registering an instance of your tool in `ArtInstanceConfig.tools`. -3. (Optionally) Enabling the tool for specific threads via `ThreadConfig.enabledTools`. -4. Ensuring your agent's planning prompt provides the LLM with information about available tools. - -This empowers your ART agents to perform a wide range of actions and access diverse information sources. \ No newline at end of file diff --git a/Docs/how-to/handle-streaming-ui.md b/Docs/how-to/handle-streaming-ui.md deleted file mode 100644 index 158598f..0000000 --- a/Docs/how-to/handle-streaming-ui.md +++ /dev/null @@ -1,239 +0,0 @@ -# How-To: Handle Streaming Events in a UI - -The ART Framework is designed to support real-time streaming of Large Language Model (LLM) responses and agent observations to a User Interface (UI). This is achieved through specialized "sockets" provided by the `UISystem`. This guide outlines how a hypothetical UI (client-side JavaScript) could subscribe to these sockets and display updates. - -**Assumptions:** - -* You have an ART backend running, and your UI can communicate with it (e.g., via WebSockets, Server-Sent Events, or another mechanism that allows the backend to push data to the frontend). -* The frontend has a way to get references to or emulate the `subscribe` methods of ART's UI sockets (`LLMStreamSocket`, `ObservationSocket`, `ConversationSocket`). For this guide, we'll assume a conceptual `artSockets` object on the client-side that provides this. - -## Key Sockets for UI Updates - -1. **`LLMStreamSocket`:** For `StreamEvent`s (`TOKEN`, `METADATA`, `ERROR`, `END`) from LLM calls. - * Used to display LLM responses token by token. - * Can also show metadata or errors related to the LLM call. -2. **`ObservationSocket`:** For `Observation` objects recorded by the agent. - * Used to display the agent's "thought process," tool usage, errors, etc. -3. **`ConversationSocket`:** For new `ConversationMessage`s added to a thread. - * Used to update the chat history display. - -## 1. Subscribing to `LLMStreamSocket` for Token Streaming - -This is essential for showing the AI's response as it's being generated. - -```html - -
    - -
    -
    -
    -``` - -```javascript -// Hypothetical client-side JavaScript - -// Assume 'artSockets.llmStream' is your client-side interface to LLMStreamSocket -// and 'currentAgentInteraction' holds { threadId, traceId, sessionId } - -const aiResponseElement = document.getElementById('current-ai-response'); -const llmStatusElement = document.getElementById('llm-status'); -let llmUnsubscribe = null; - -function subscribeToLLMStream(threadId, sessionId) { - if (llmUnsubscribe) llmUnsubscribe(); // Unsubscribe from previous if any - - aiResponseElement.innerHTML = ''; // Clear previous response - llmStatusElement.textContent = 'Agent is thinking...'; - - llmUnsubscribe = artSockets.llmStream.subscribe( - (event) => { // Callback function for each StreamEvent - if (event.threadId !== threadId) return; // Ensure event is for current thread - - switch (event.type) { - case 'TOKEN': - // Only display tokens intended as the final response - if (event.tokenType === 'FINAL_SYNTHESIS_LLM_RESPONSE' || event.tokenType === 'LLM_RESPONSE') { - const tokenSpan = document.createElement('span'); - tokenSpan.textContent = event.data; - aiResponseElement.appendChild(tokenSpan); - } else if (event.tokenType && event.tokenType.includes('THOUGHT')) { - // Optionally display "thinking" tokens differently or log them - console.debug('LLM Thought Token:', event.data); - // llmStatusElement.textContent = `Agent thinking: ${event.data.substring(0,30)}...`; - } - break; - case 'METADATA': - console.log('LLM Metadata:', event.data); - llmStatusElement.textContent = `LLM call finished. Stop reason: ${event.data.stopReason || 'N/A'}`; - break; - case 'ERROR': - console.error('LLM Stream Error:', event.data); - const errorText = event.data?.message || String(event.data); - aiResponseElement.innerHTML += `

    LLM Error: ${errorText}

    `; - llmStatusElement.textContent = 'Error during LLM call.'; - break; - case 'END': - console.log('LLM Stream ended.'); - if (llmStatusElement.textContent === 'Agent is thinking...') { // If no metadata/error set it - llmStatusElement.textContent = 'Done.'; - } - // Final response is now in aiResponseElement. - // You might move it to the main chat area here. - break; - } - }, - // Filter: We want all event types to handle them appropriately - ['TOKEN', 'METADATA', 'ERROR', 'END'], - // Options: Filter by threadId and potentially sessionId - { threadId: threadId, sessionId: sessionId } - ); -} - -// When a new agent interaction starts that involves an LLM call for synthesis: -// const currentThreadId = "thread-123"; -// const currentSessionId = "session-abc"; // If you use session IDs -// subscribeToLLMStream(currentThreadId, currentSessionId); - -// Remember to call llmUnsubscribe() when the component/view is destroyed -// or when you no longer need to listen for this specific stream. -// e.g., window.addEventListener('beforeunload', () => { if(llmUnsubscribe) llmUnsubscribe(); }); -``` - -## 2. Subscribing to `ObservationSocket` for Agent Activity - -This allows the UI to display what the agent is doing internally (planning, using tools). - -```html - -
      -``` - -```javascript -// Hypothetical client-side JavaScript - -// Assume 'artSockets.observation' is your client-side interface to ObservationSocket - -const activityLogElement = document.getElementById('agent-activity-log'); -let observationUnsubscribe = null; - -function subscribeToObservations(threadId) { - if (observationUnsubscribe) observationUnsubscribe(); - - observationUnsubscribe = artSockets.observation.subscribe( - (observation) => { - if (observation.threadId !== threadId) return; - - const logEntry = document.createElement('li'); - logEntry.className = `log-entry log-type-${observation.type.toLowerCase()}`; - - let contentDisplay = JSON.stringify(observation.content); - if (typeof observation.content === 'string') { - contentDisplay = observation.content; - } else if (observation.content && typeof observation.content.message === 'string') { - contentDisplay = observation.content.message; // For simple message content - } - - - logEntry.innerHTML = ` - ${observation.title} (Type: ${observation.type})
      - Content: ${contentDisplay.substring(0, 100)}${contentDisplay.length > 100 ? '...' : ''}
      - Time: ${new Date(observation.timestamp).toLocaleTimeString()} - `; - activityLogElement.prepend(logEntry); // Add new entries to the top - }, - // Filter: Subscribe to specific observation types you want to display - [ - 'INTENT', - 'PLAN', - 'TOOL_CALL', - 'TOOL_EXECUTION', - 'SYNTHESIS', - 'ERROR', - 'LLM_STREAM_START', // To show when LLM calls begin - 'LLM_STREAM_END' // To show when LLM calls end - ], - // Options: Filter by threadId - { threadId: threadId } - ); -} - -// When a new agent interaction starts or a thread view is loaded: -// const currentThreadId = "thread-123"; -// subscribeToObservations(currentThreadId); - -// Call observationUnsubscribe() on cleanup. -``` - -## 3. Subscribing to `ConversationSocket` for Chat History - -This updates the main chat display with new messages from both the user and the AI. - -```html - - -``` - -```javascript -// Hypothetical client-side JavaScript - -// Assume 'artSockets.conversation' is your client-side interface to ConversationSocket -// Assume 'chatAreaElement' is already defined (e.g., document.getElementById('chat-area')) - -let conversationUnsubscribe = null; - -function displayMessage(message) { - const messageDiv = document.createElement('div'); - messageDiv.classList.add('message', message.role.toLowerCase()); // e.g., 'message user', 'message ai' - messageDiv.innerHTML = ` - ${message.role} -

      ${message.content}

      - ${new Date(message.timestamp).toLocaleTimeString()} - `; - chatAreaElement.appendChild(messageDiv); - chatAreaElement.scrollTop = chatAreaElement.scrollHeight; // Scroll to bottom -} - -async function loadAndSubscribeToConversation(threadId) { - if (conversationUnsubscribe) conversationUnsubscribe(); - chatAreaElement.innerHTML = ''; // Clear previous messages - - // Load initial history (optional) - try { - const history = await artSockets.conversation.getHistory( - undefined, // No role filter, get all messages - { threadId: threadId, limit: 50 } // Load last 50 messages - ); - history.forEach(displayMessage); - } catch (e) { - console.error("Failed to load conversation history:", e); - } - - // Subscribe to new messages - conversationUnsubscribe = artSockets.conversation.subscribe( - (message) => { - if (message.threadId !== threadId) return; - displayMessage(message); - }, - undefined, // No role filter, receive all messages for the thread - { threadId: threadId } - ); -} - -// When a chat thread is opened/selected in the UI: -// const currentThreadId = "thread-123"; -// loadAndSubscribeToConversation(currentThreadId); - -// Call conversationUnsubscribe() on cleanup. -``` - -## Important Considerations: - -* **Client-Side Socket Interface (`artSockets`):** The `artSockets` object in these examples is conceptual. You'll need to implement the actual communication layer (e.g., using WebSockets, Server-Sent Events with a library like `EventSource`, or a state management library like Redux/ Zustand that syncs with the backend) to bridge events from your ART backend to your frontend. -* **Error Handling and Resilience:** Add robust error handling for socket connections and event processing in your UI. -* **Unsubscribing:** Always call the `unsubscribe` function returned by `subscribe()` when a UI component is destroyed or no longer needs to listen for events. This prevents memory leaks and unintended behavior. -* **Filtering:** Leverage the `filter` and `options` parameters in `subscribe()` to minimize the amount of data sent to the client and reduce unnecessary UI updates. -* **State Management:** For complex UIs, consider using a frontend state management library (Redux, Zustand, Vuex, etc.) to manage the data received from the sockets and drive UI rendering. The socket callbacks would dispatch actions to update the store. -* **Security:** If your application involves multiple users or sensitive data, ensure your real-time communication channel is secured (e.g., WSS for WebSockets, HTTPS for SSE) and that events are correctly scoped by `threadId` and potentially `userId` or `sessionId` on the backend before broadcasting. - -By subscribing to these sockets, you can create a rich, interactive, and informative user experience for your ART-powered agents. \ No newline at end of file diff --git a/Docs/how-to/manage-agent-state.md b/Docs/how-to/manage-agent-state.md deleted file mode 100644 index 52e0527..0000000 --- a/Docs/how-to/manage-agent-state.md +++ /dev/null @@ -1,153 +0,0 @@ -# How-To: Manage Agent State (`StateSavingStrategy`) - -The ART Framework provides flexibility in how an agent's persistent operational state (`AgentState`) is managed and saved. This is primarily controlled by the `StateSavingStrategy` option in your `ArtInstanceConfig`, which influences the behavior of the `StateManager`. - -**Recall `AgentState`:** -An `AgentState` object (`src/types/index.ts`) typically holds arbitrary, application-defined data that needs to persist for an agent within a specific conversation thread. For example: -```typescript -interface MyAgentStateData { - userPreferences?: { - language?: string; - notificationLevel?: 'all' | 'mentions'; - }; - lastTaskSummary?: string; - accumulatedData?: any[]; -} - -// An AgentState object -const agentStateExample: AgentState = { - data: { // The application-defined payload - userPreferences: { language: 'en-US' }, - lastTaskSummary: "Booked flight to Mars." - }, - version: 1 // Optional versioning -}; -``` - -## Understanding `StateSavingStrategy` - -When you configure your ART instance using `createArtInstance`, you can set `ArtInstanceConfig.stateSavingStrategy`. It can be one of two values: - -1. **`'explicit'` (Default):** - * In this mode, `AgentState` is **only** saved to persistent storage when your agent logic explicitly calls `stateManager.setAgentState(threadId, newState)`. - * If your agent modifies the `state` object it received from `stateManager.loadThreadContext()`, these changes **will not** be automatically saved at the end of the processing cycle by `PESAgent`'s call to `stateManager.saveStateIfModified()`. That method becomes a no-op for `AgentState` in this strategy. - * **When to use:** - * You need fine-grained control over when state is persisted. - * State changes are significant and shouldn't happen automatically after every minor interaction. - * You want to minimize writes to the storage layer. - -2. **`'implicit'`:** - * In this mode, the `StateManager` helps automate state saving. - * **Loading:** When `stateManager.loadThreadContext(threadId)` is called: - 1. It fetches the `ThreadContext` from the repository. - 2. It **deep clones** this context and stores this clone in an internal cache for the current `StateManager` instance and processing cycle. - 3. It creates a JSON snapshot of the `AgentState` part of this *cloned context*. This snapshot serves as the "original" version for comparison later. - 4. The agent logic receives this (cloned and cached) `ThreadContext`. - * **Modification:** Your agent logic can directly modify the `context.state` object it received (e.g., `context.state.data.userPreferences.language = 'fr-FR';`). - * **Saving:** When `stateManager.saveStateIfModified(threadId)` is called (typically by `PESAgent` at the end of its `process` method): - 1. The `StateManager` retrieves the current (potentially modified) `AgentState` from its internal cache for that `threadId`. - 2. It creates a JSON snapshot of this current cached `AgentState`. - 3. It compares this new snapshot with the `originalStateSnapshot` taken during `loadThreadContext`. - 4. **If the snapshots differ**, the `StateManager` calls `stateRepository.setAgentState(threadId, currentState)` to persist the changes. It then updates its internal `originalStateSnapshot` to this newly saved state. - 5. If the snapshots are the same, no save operation occurs. - * **Explicit Saves Still Work:** Even in `'implicit'` mode, calling `stateManager.setAgentState(threadId, newState)` will still explicitly save the state and also update the `StateManager`'s internal cache and snapshot for that thread. - * **When to use:** - * Convenience is desired, and any modification to `AgentState` during an agent's turn should generally be persisted. - * Reduces boilerplate for saving state. - -## Example: Configuring the Strategy - -```typescript -// src/config/art-config.ts -import { ArtInstanceConfig, LogLevel } from 'art-framework'; - -export const explicitSavingConfig: ArtInstanceConfig = { - storage: { type: 'memory' }, - providers: { /* ... */ }, - stateSavingStrategy: 'explicit', // Explicitly set - logger: { level: LogLevel.DEBUG } -}; - -export const implicitSavingConfig: ArtInstanceConfig = { - storage: { type: 'memory' }, - providers: { /* ... */ }, - stateSavingStrategy: 'implicit', // Use implicit saving - logger: { level: LogLevel.DEBUG } -}; -``` - -## Example: Agent Logic with `'explicit'` Strategy - -```typescript -// Conceptual agent logic (e.g., inside a custom IAgentCore or PESAgent modification) -// Assuming 'stateManager' is an injected StateManager instance. -// ArtInstanceConfig.stateSavingStrategy = 'explicit'; - -async function handleUserPreferenceUpdate(threadId: string, newLanguage: string) { - const context = await stateManager.loadThreadContext(threadId); - if (!context) throw new Error("Context not found"); - - // Ensure state and data objects exist - if (!context.state) { - context.state = { data: {} }; - } - if (!context.state.data.userPreferences) { - context.state.data.userPreferences = {}; - } - - // Modify the state - context.state.data.userPreferences.language = newLanguage; - Logger.info(`Agent state modified (language to ${newLanguage}), but not yet saved.`); - - // To persist this change, we MUST call setAgentState: - await stateManager.setAgentState(threadId, context.state); - Logger.info(`Agent state explicitly saved for thread ${threadId}.`); - - // If PESAgent calls stateManager.saveStateIfModified(threadId) later, - // it will be a no-op for this AgentState change because the strategy is 'explicit'. -} -``` - -## Example: Agent Logic with `'implicit'` Strategy - -```typescript -// Conceptual agent logic -// ArtInstanceConfig.stateSavingStrategy = 'implicit'; - -async function updateUserLastTask(threadId: string, taskSummary: string) { - const context = await stateManager.loadThreadContext(threadId); // Loads and caches state, snapshots original - if (!context) throw new Error("Context not found"); - - // Ensure state and data objects exist - if (!context.state) { - context.state = { data: {} }; - } - - // Modify the state object received from loadThreadContext - context.state.data.lastTaskSummary = taskSummary; - Logger.info(`Agent state modified (lastTaskSummary to "${taskSummary}"). Will be saved implicitly if different.`); - - // NO explicit call to stateManager.setAgentState() is strictly needed here - // for this particular change to be saved. - - // Later, when (for example) PESAgent calls stateManager.saveStateIfModified(threadId): - // The StateManager will compare the current context.state.data.lastTaskSummary - // with the snapshot taken during loadThreadContext. If it changed, it saves. -} - -// If you still want to force an immediate save within the turn in implicit mode: -async function forceSaveNow(threadId: string, updatedState: AgentState) { - await stateManager.setAgentState(threadId, updatedState); - // This also updates the StateManager's internal snapshot, so saveStateIfModified - // won't try to save it again unless it's modified further *after* this call. - Logger.info(`Agent state explicitly saved (even in implicit mode) for thread ${threadId}.`); -} -``` - -## Important Considerations for `'implicit'` Strategy: - -* **Object Modification:** For implicit saving to work, your agent logic **must modify the `state` object that was part of the `ThreadContext` returned by `loadThreadContext()`**. If you create a completely new state object and assign it to `context.state` (e.g., `context.state = { data: { newStuff: true } };`), this new object reference will be detected as a change. -* **Deep Cloning:** `StateManager` deep clones the context upon loading in implicit mode and when `setAgentState` is called in implicit mode to update the cache. This ensures that the snapshot comparison is reliable and that the agent is working with a mutable copy. -* **Null State:** If `context.state` is initially non-null and your agent sets `context.state = null;`, `saveStateIfModified` in `'implicit'` mode will detect this as a change. However, the current `StateRepository.setAgentState` does not allow saving `null` directly (it expects an `AgentState` object or will set state to null if passed null in its own `setAgentState` method). For implicit "clearing" of state by setting it to `null`, the `StateManager` currently logs a warning and doesn't persist the `null` state via `setAgentState` to avoid this error. To clear state, it's better to set `context.state = { data: null, version: newVersionIfApplicable };` or use `stateManager.setAgentState` explicitly with such an object. - -Choose the `StateSavingStrategy` that best fits your agent's complexity and your preferences for state persistence control. \ No newline at end of file diff --git a/Docs/how-to/manage-multiple-llms.md b/Docs/how-to/manage-multiple-llms.md deleted file mode 100644 index 34545f8..0000000 --- a/Docs/how-to/manage-multiple-llms.md +++ /dev/null @@ -1,181 +0,0 @@ -# How-To: Manage Multiple LLM Providers - -One of the key strengths of the ART Framework is its ability to work with multiple Large Language Model (LLM) providers simultaneously. This is facilitated by the `ProviderManager` and a flexible configuration system. This guide explains how to set up and use different LLM providers within your ART application. - -## 1. Configure `ProviderManagerConfig` - -The first step is to define all the LLM providers your application *might* use in the `ProviderManagerConfig`. This configuration is part of your main `ArtInstanceConfig` passed to `createArtInstance`. - -* **`availableProviders: AvailableProviderEntry[]`**: This array is where you list each provider setup. - * `name: string`: A unique string identifier for this specific provider configuration (e.g., "openai-gpt4o", "anthropic-claude3-sonnet", "ollama-llama3-local"). You'll use this name at runtime to select this provider. - * `adapter: new (options: any) => ProviderAdapter`: The constructor of the adapter class for this provider (e.g., `OpenAIAdapter`, `AnthropicAdapter`, `OllamaAdapter`). - * `isLocal?: boolean`: Set to `true` if this provider runs locally (like Ollama). This affects how the `ProviderManager` handles its instances (typically as a singleton). Defaults to `false`. - * `baseOptions?: any` (Optional): Base options passed to the adapter constructor if not overridden by `RuntimeProviderConfig.adapterOptions`. Often, API keys and model-specific defaults are better placed in `RuntimeProviderConfig`. - -**Example `ArtInstanceConfig` with multiple providers:** - -```typescript -// src/config/art-config.ts -import { - ArtInstanceConfig, - OpenAIAdapter, - AnthropicAdapter, - OllamaAdapter, - LogLevel -} from 'art-framework'; - -export const multiProviderArtConfig: ArtInstanceConfig = { - storage: { type: 'memory' }, // Or 'indexedDB' - providers: { - availableProviders: [ - { - name: 'openai-gpt4o-mini', // A descriptive, unique name - adapter: OpenAIAdapter, - isLocal: false, - }, - { - name: 'openai-gpt3.5-turbo', - adapter: OpenAIAdapter, - isLocal: false, - }, - { - name: 'anthropic-claude3-haiku', - adapter: AnthropicAdapter, - isLocal: false, - }, - { - name: 'ollama-local-model', - adapter: OllamaAdapter, - isLocal: true, // This is a local provider - } - ], - maxParallelApiInstancesPerProvider: 2, // Max active instances per API provider NAME - apiInstanceIdleTimeoutSeconds: 180, // Evict idle API adapters after 3 minutes - }, - tools: [ /* ... your tools ... */ ], - logger: { level: LogLevel.INFO }, -}; -``` -In this example, we've defined four potential LLM setups that the `ProviderManager` knows about. - -## 2. Select a Provider at Runtime using `RuntimeProviderConfig` - -When you make an LLM call using `art.process(agentProps)` (which internally calls `ReasoningEngine.call()`), you need to specify which provider configuration to use for *that specific call*. This is done via the `RuntimeProviderConfig` object within `AgentProps.options`. - -* **`AgentProps.options.providerConfig: RuntimeProviderConfig`**: - * `providerName: string`: This **must match** one of the `name`s you defined in `ProviderManagerConfig.availableProviders`. - * `modelId: string`: The specific model identifier for the chosen provider (e.g., "gpt-4o-mini", "claude-3-haiku-20240307", "llama3:latest"). - * `adapterOptions: any`: An object containing options required by the selected adapter's constructor for *this specific instance*. - * **API Keys are provided here:** For cloud-based providers like OpenAI or Anthropic, this is where you supply the `apiKey`. - * You can also provide other adapter-specific options (e.g., `baseURL` override for OpenAI, `defaultMaxTokens` for Anthropic, `ollamaBaseUrl` or `defaultModel` for Ollama if you want to override the constructor default for that specific instance). - -**Example: Calling `art.process()` with different providers:** - -```typescript -// main.ts -// import { createArtInstance, AgentProps } from 'art-framework'; -// import { multiProviderArtConfig } from './config/art-config'; // Your config from above - -// async function runMultiProviderAgent() { -// const art = await createArtInstance(multiProviderArtConfig); - -// // --- Interaction 1: Using OpenAI GPT-4o-mini --- -// const propsForOpenAI: AgentProps = { -// query: "Explain black holes to a 5-year-old.", -// threadId: "chat-thread-1", -// options: { -// providerConfig: { -// providerName: 'openai-gpt4o-mini', // Matches name in availableProviders -// modelId: 'gpt-4o-mini', // The specific model for this call -// adapterOptions: { -// apiKey: process.env.OPENAI_API_KEY, // API key for OpenAI -// } -// }, -// llmParams: { temperature: 0.5 } // Additional LLM params for this call -// } -// }; -// if (process.env.OPENAI_API_KEY) { -// const resultOpenAI = await art.process(propsForOpenAI); -// console.log("OpenAI GPT-4o mini says:", resultOpenAI.response.content); -// } else { -// console.warn("OPENAI_API_KEY not set. Skipping OpenAI call."); -// } - -// // --- Interaction 2: Using Anthropic Claude 3 Haiku (in the same thread or a new one) --- -// const propsForAnthropic: AgentProps = { -// query: "Write a short poem about a friendly robot.", -// threadId: "chat-thread-1", // Can be the same thread or a different one -// options: { -// providerConfig: { -// providerName: 'anthropic-claude3-haiku', // Selects the Anthropic config -// modelId: 'claude-3-haiku-20240307', -// adapterOptions: { -// apiKey: process.env.ANTHROPIC_API_KEY, // API key for Anthropic -// // defaultMaxTokens: 1000 // Adapter-specific option -// } -// }, -// llmParams: { temperature: 0.8 } -// } -// }; -// if (process.env.ANTHROPIC_API_KEY) { -// const resultAnthropic = await art.process(propsForAnthropic); -// console.log("Anthropic Haiku says:", resultAnthropic.response.content); -// } else { -// console.warn("ANTHROPIC_API_KEY not set. Skipping Anthropic call."); -// } - -// // --- Interaction 3: Using a local Ollama model --- -// const propsForOllama: AgentProps = { -// query: "What is 15 * 7?", -// threadId: "chat-thread-2", -// options: { -// providerConfig: { -// providerName: 'ollama-local-model', // Selects the Ollama config -// modelId: 'llama3:8b', // Specify the Ollama model tag -// adapterOptions: { -// // For Ollama, apiKey defaults to "ollama", ollamaBaseUrl to localhost. -// // Override if needed: -// // ollamaBaseUrl: 'http://192.168.1.100:11434', -// // defaultModel: 'llama3:8b' // Can also be set here if not in main config -// } -// } -// } -// }; -// const resultOllama = await art.process(propsForOllama); -// console.log("Local Ollama model says:", resultOllama.response.content); -// } - -// runMultiProviderAgent(); -``` - -## Thread-Level Default Provider Configuration - -You can also set a default `providerConfig` at the thread level within `ThreadConfig`. - -```typescript -// import { ThreadConfig, StateManager } from 'art-framework'; - -// async function setupThreadWithDefaultProvider(stateManager: StateManager, threadId: string) { -// const threadDefaultConfig: ThreadConfig = { -// providerConfig: { // This becomes the default for this thread -// providerName: 'anthropic-claude3-haiku', -// modelId: 'claude-3-haiku-20240307', -// adapterOptions: { apiKey: process.env.ANTHROPIC_API_KEY } -// }, -// enabledTools: ["calculator"], -// historyLimit: 20, -// }; -// await stateManager.setThreadConfig(threadId, threadDefaultConfig); -// } -``` - -If `AgentProps.options.providerConfig` is **not** provided when calling `art.process()`, the `PESAgent` (or other agent cores) will attempt to use the `providerConfig` defined in the `ThreadConfig` for that `threadId`. If neither is available, the call will fail. `AgentProps.options.providerConfig` always overrides the thread-level default. - -## Benefits of This Approach - -* **Flexibility:** Choose the best LLM provider and model for different tasks or user preferences at runtime. -* **Centralized Management:** `ProviderManager` handles the complexities of instance pooling, caching, and local provider constraints. -* **Simplified Agent Logic:** The agent core (`PESAgent`) doesn't need to know the specifics of each provider; it just uses the `ReasoningEngine` which gets the appropriate adapter from the `ProviderManager`. -* **Easy Configuration:** Define all potential providers in one place (`ArtInstanceConfig`) and then select them dynamically. - -By leveraging the `ProviderManager` and the two-tiered configuration system (`ProviderManagerConfig` and `RuntimeProviderConfig`), you can build sophisticated ART applications that effectively utilize a diverse range of LLM capabilities. \ No newline at end of file diff --git a/Docs/how-to/use-calculator-ans.md b/Docs/how-to/use-calculator-ans.md deleted file mode 100644 index c17fd21..0000000 --- a/Docs/how-to/use-calculator-ans.md +++ /dev/null @@ -1,211 +0,0 @@ -# How-To: Use the `ans` Variable in `CalculatorTool` - -The built-in `CalculatorTool` in the ART Framework has a handy feature: it remembers the result of the last calculation *within the same conversation thread* and makes this result available as a special variable named `ans`. This allows for multi-step calculations where the output of one calculation can be easily used as an input for the next. - -## How `ans` Works - -1. **Internal Storage:** The `CalculatorTool` maintains an internal `Map` (called `resultStore`) that stores the last successful calculation result, keyed by `threadId`. -2. **Execution Scope:** When `CalculatorTool.execute()` is called: - * It retrieves the `threadId` from the `ExecutionContext`. - * It looks up the `resultStore` for a previous result associated with that `threadId`. - * If a previous result exists, it's added to the `mathjs.evaluate()` scope as the variable `ans`. -3. **Updating `ans`:** After a successful calculation, the new `resultValue` (the actual numerical or complex object from `mathjs`, not just its string representation) is stored back into `resultStore` for the current `threadId`, overwriting any previous `ans` value for that thread. -4. **Isolation:** The `ans` variable is scoped per `threadId`. Calculations in one thread do not affect the `ans` variable in another thread. - -## Example Usage - -Let's say an agent needs to perform a sequence of calculations: -1. Calculate `(10 + 5) * 2`. -2. Then, take that result and find its square root. -3. Finally, add `7` to the square root. - -Here's how the LLM might request the `CalculatorTool` using the `ans` variable, and how the tool would process it: - -**User Query:** "Calculate (10 + 5) * 2. Then find the square root of that. Finally, add 7 to the square root." - -**Agent's Plan (Simplified LLM Output):** - -``` -Intent: Perform a sequence of three calculations. -Plan: -1. Calculate (10 + 5) * 2. -2. Calculate the square root of the previous result using 'ans'. -3. Add 7 to the result of the square root calculation, again using 'ans'. -Tool Calls: [ - {"callId": "calc1", "toolName": "calculator", "arguments": {"expression": "(10 + 5) * 2"}}, - {"callId": "calc2", "toolName": "calculator", "arguments": {"expression": "sqrt(ans)"}}, - {"callId": "calc3", "toolName": "calculator", "arguments": {"expression": "ans + 7"}} -] -``` - -**Execution by `ToolSystem` and `CalculatorTool`:** - -* **Call 1 (`calc1`):** - * Input: `{ expression: "(10 + 5) * 2" }` - * `ans` for this thread is initially undefined. - * `CalculatorTool` evaluates `(10 + 5) * 2` which is `30`. - * Result `30` is stored for the current `threadId` (becomes the new `ans`). - * `ToolResult`: `{ ..., status: 'success', output: { result: 30 } }` - -* **Call 2 (`calc2`):** - * Input: `{ expression: "sqrt(ans)" }` - * `CalculatorTool` retrieves `ans = 30` for the current `threadId`. - * It evaluates `sqrt(30)`, which is approximately `5.477225575`. - * Result `5.477225575` is stored for the current `threadId` (overwriting the previous `ans`). - * `ToolResult`: `{ ..., status: 'success', output: { result: 5.477225575051661 } }` (mathjs precision) - -* **Call 3 (`calc3`):** - * Input: `{ expression: "ans + 7" }` - * `CalculatorTool` retrieves `ans = 5.477225575051661` for the current `threadId`. - * It evaluates `5.477225575051661 + 7`, which is approximately `12.477225575`. - * Result `12.477225575051661` is stored for the current `threadId`. - * `ToolResult`: `{ ..., status: 'success', output: { result: 12.477225575051661 } }` - -**Agent's Synthesis Prompt Context (Simplified):** - -The `PESAgent` would then provide these `ToolResult`s to the LLM for the synthesis phase. The context for the LLM might include something like: - -``` -... -Tool Execution Results: -- Tool: calculator (Call ID: calc1) - Status: success - Output: {"result":30} -- Tool: calculator (Call ID: calc2) - Status: success - Output: {"result":5.477225575051661} -- Tool: calculator (Call ID: calc3) - Status: success - Output: {"result":12.477225575051661} - -Based on the user query and tool results, synthesize a final response... -``` - -The LLM can then formulate a response like: "First, (10 + 5) * 2 is 30. The square root of 30 is approximately 5.48. Adding 7 to that gives approximately 12.48." - -## Important Notes: - -* **Thread-Scoped:** The `ans` variable is specific to each `threadId`. One user's multi-step calculation won't interfere with another's. -* **Overwritten:** Each successful calculation by the `CalculatorTool` within a thread updates (overwrites) the `ans` value for that thread. -* **Availability:** `ans` is only available if a previous calculation *by the `CalculatorTool`* has occurred successfully in the *same thread* and was processed by the *same `CalculatorTool` instance*. -* **Error Handling:** If a calculation involving `ans` fails (e.g., `ans` is undefined because no prior calculation, or `ans` holds a value that leads to a math error like `log(ans)` if `ans` was 0), the `CalculatorTool` will return an error `ToolResult`. -* **LLM Awareness:** For the LLM to effectively use `ans`, its planning prompt should include a mention of this capability in the `CalculatorTool`'s description (as is done in the default schema). - -The `ans` variable makes the `CalculatorTool` more powerful for sequential calculations, reducing the need for the LLM to explicitly pass results from one calculation step to the next as a separate variable in the `scope`. -``` - -```markdown -docs/how-to/leverage-think-tags.md -``` -```markdown -# How-To: Leverage `` Tags for Agent Observability - -In complex AI agent interactions, it's often beneficial for the Large Language Model (LLM) to "show its work" or articulate its reasoning process before arriving at a plan or final answer. The ART Framework, through its `OutputParser`, supports a convention of using `...` XML-like tags in LLM prompts to encourage this behavior and to extract these "thoughts." - -## What are `` Tags? - -`` tags are a simple mechanism you can instruct your LLM to use in its responses, particularly during the planning phase. The content enclosed within these tags represents the LLM's intermediate reasoning, reflections, self-correction, or detailed breakdown of its understanding. - -**Example: LLM Planning Output with `` Tags** - -```text - -The user wants to know the capital of France and the weather there. -This requires two steps: -1. Find the capital of France. -2. Get the weather for that capital city. -I have tools for search and weather. - -Intent: Find the capital of France and then get its current weather. -Plan: -3. Use the 'search' tool to find the capital of France. -4. Use the 'get_weather' tool with the capital city found in step 1. -5. Synthesize the information into a coherent response. -Tool Calls: [ - {"callId": "search_capital", "toolName": "search", "arguments": {"query": "capital of France"}}, - {"callId": "weather_capital", "toolName": "get_weather", "arguments": {"location": "Paris"}} // LLM might pre-fill if confident -] -``` -*(Note: The LLM might not perfectly fill the second tool call's arguments until the first is executed; this is just an illustrative example of thought and plan separation.)* - -## How `OutputParser` Handles `` Tags - -The `OutputParser.parsePlanningOutput(output: string)` method in ART `v0.2.7` uses an `XmlMatcher` utility to specifically look for and extract content within `...` tags. - -1. **Extraction:** `XmlMatcher` processes the entire raw string output from the LLM. -2. **Separation:** - * Content found *inside* any `...` tags is collected. If multiple `` blocks exist, their content is aggregated, typically separated by `\n\n---\n\n`. This aggregated content becomes the `thoughts` field in the parsed result. - * Content *outside* the `` tags is considered the "non-thinking" or primary output, which is then parsed for "Intent:", "Plan:", and "Tool Calls:" sections. -3. **Result:** `parsePlanningOutput` returns an object like: - ```typescript - { - thoughts?: string; // Aggregated content from all tags - intent?: string; - plan?: string; - toolCalls?: ParsedToolCall[]; - } - ``` - -## Benefits of Using `` Tags - -1. **Improved Observability:** - * By examining the `thoughts` field, developers can gain deeper insights into the LLM's reasoning process. This is invaluable for debugging why an agent made a particular decision, chose certain tools, or misinterpreted a query. - * UI components can display these thoughts (e.g., in a "developer log" or an "agent thinking..." panel) to provide transparency. - -2. **Better Prompt Engineering:** - * Encouraging the LLM to "think out loud" within these tags can sometimes lead to better quality plans and tool usage, as it forces the model to break down the problem before committing to actions. This is related to "Chain of Thought" prompting techniques. - -3. **Structured Output:** - * It helps separate the LLM's verbose reasoning from the more structured and actionable parts of its plan (Intent, Plan, Tool Calls), making the latter easier to parse reliably. - -4. **Debugging LLM Failures:** - * If the LLM fails to produce a valid plan or makes incorrect tool calls, the content within the `` tags might reveal misunderstandings or flawed logic that can be addressed by refining the system prompt or tool descriptions. - -## How to Instruct the LLM to Use `` Tags - -You need to include instructions in your system prompt or the task-specific part of your planning prompt that tells the LLM to use these tags. - -**Example Prompt Instruction (for the planning phase):** - -``` -System Prompt: -You are a helpful AI assistant. Your goal is to understand the user's query, create a plan, and identify any tools needed. - -User Query Instructions: -When formulating your plan, first use ... tags to write out your step-by-step reasoning, analyze the query, and consider which tools might be useful. -After your thoughts, provide your response in the following structured format: -Intent: [Your understanding of the user's goal] -Plan: [Your step-by-step plan] -Tool Calls: [A JSON array of tool calls, or an empty array [] if no tools are needed. Format: [{"callId": "unique_id", "toolName": "tool_name", "arguments": {"arg_name": "value"}}]] - -User Query: {{user_query}} -Available Tools: {{tools_description}} -``` - -## Using the Extracted Thoughts - -Once `OutputParser.parsePlanningOutput()` returns the `thoughts` string, your agent logic (e.g., `PESAgent`) can: - -1. **Record an Observation:** - ```typescript - // In PESAgent, after parsing planning output: - // if (parsedPlanningOutput.thoughts) { - // await this.deps.observationManager.record({ - // threadId: props.threadId, - // traceId: traceId, - // type: ObservationType.THOUGHTS, // Assuming ObservationType.THOUGHTS exists - // content: { thoughts: parsedPlanningOutput.thoughts }, - // metadata: { timestamp: Date.now() } - // }); - // } - ``` - *(Note: `ObservationType.THOUGHTS` is used as an example; you might map it to an existing type or add a new one if needed. The `OutputParser` itself doesn't record observations; the consuming agent logic does.)* - -2. **Log for Debugging:** - ```typescript - // Logger.debug(`[${traceId}] LLM Thoughts:\n${parsedPlanningOutput.thoughts}`); - ``` - -3. **Display in UI:** The `Observation` containing the thoughts can be sent to the UI via `ObservationSocket` for display. - -By encouraging and correctly parsing `` tags, you can significantly enhance the transparency and debuggability of your ART agents. \ No newline at end of file diff --git a/Docs/how-to/use-prompt-fragments.md b/Docs/how-to/use-prompt-fragments.md deleted file mode 100644 index f26a79e..0000000 --- a/Docs/how-to/use-prompt-fragments.md +++ /dev/null @@ -1,134 +0,0 @@ -# How-To: Use Prompt Fragments with `PromptManager` - -In ART Framework `v0.2.7`, the `PromptManager`'s role has been streamlined. While agent logic (like `PESAgent`) is now directly responsible for assembling the final `ArtStandardPrompt` object (an array of `ArtStandardMessage`s), the `PromptManager` still offers a useful utility: providing reusable, named **prompt fragments** via its `getFragment()` method. - -These fragments are pre-defined pieces of text, potentially with simple template variables, that can be embedded into the `content` of your `ArtStandardMessage` objects. This promotes consistency and reduces redundancy in your prompt construction logic. - -## 1. Understanding `PromptManager.getFragment()` - -* **`getFragment(name: string, context?: Record): string`** - * `name`: The unique string identifier for the fragment (e.g., "common_error_handling_instructions", "tool_description_prefix"). - * `context` (Optional): A simple key-value object. If the fragment string contains placeholders like `{{myKey}}`, they will be replaced with the corresponding value from `context.myKey`. - * Returns the processed fragment string. - * Throws an `ARTError` with `ErrorCode.PROMPT_FRAGMENT_NOT_FOUND` if the `name` doesn't exist. - -## 2. Defining Prompt Fragments - -Currently, prompt fragments are defined directly within `src/systems/reasoning/PromptManager.ts` in a `PROMPT_FRAGMENTS` record: - -```typescript -// Inside PromptManager.ts -const PROMPT_FRAGMENTS: Record = { - pes_system_default: "You are a helpful AI assistant...", - pes_planning_instructions: "Based on the user query and conversation history, identify the user's intent and create a plan...", - pes_tool_format_instructions: "Respond in the following format:\nIntent: ...\nTool Calls: [Output *only* the JSON array...]", - // Add your custom fragments here - custom_greeting: "Hello, {{userName}}! Welcome to our {{appName}} service.", - error_prefix: "I encountered an issue: {{errorMessage}}" -}; -``` - -**To add your own fragments:** - -1. Modify this `PROMPT_FRAGMENTS` object in `PromptManager.ts` or consider a more dynamic loading mechanism if you have many fragments (though this is not built-in for `v0.2.7`). -2. Choose a unique, descriptive name for your fragment. -3. Write the fragment text. You can use `{{variableName}}` for simple substitutions. - -## 3. Using Fragments in Agent Logic (e.g., Custom Agent or `PESAgent` Customization) - -The `PESAgent` (and other `IAgentCore` implementations) are injected with a `PromptManager` instance by the `AgentFactory`. You can use this instance to retrieve fragments when constructing your `ArtStandardPrompt`. - -**Example: Customizing `PESAgent`'s Planning Prompt (Conceptual)** - -Let's say you want to add a standard preamble to the user query part of the `PESAgent`'s planning prompt. - -**Step 3.1: Define a Fragment** - -Add to `PROMPT_FRAGMENTS` in `PromptManager.ts`: -```typescript -const PROMPT_FRAGMENTS: Record = { - // ... other fragments ... - planning_query_preamble: "Please carefully consider the following user request and the available tools." -}; -``` - -**Step 3.2: Use the Fragment in Agent Logic** - -If you were customizing `PESAgent` (or building your own agent), you might do something like this: - -```typescript -// Inside your agent's process method, when constructing the planning prompt: -// Assuming 'this.deps.promptManager' is your PromptManager instance - -// ... (gathering systemPrompt, history, toolsDescription, props.query) ... - -const queryPreamble = this.deps.promptManager.getFragment('planning_query_preamble'); -const toolFormatInstructions = this.deps.promptManager.getFragment('pes_tool_format_instructions'); - -const planningUserContent = ` -${queryPreamble} - -User Query: ${props.query} - -Available Tools: -${toolsDescription} - -${toolFormatInstructions} -`; - -const planningPrompt: ArtStandardPrompt = [ - { role: 'system', content: systemPrompt }, - ...formattedHistory, - { role: 'user', content: planningUserContent.trim() } -]; - -// ... then send planningPrompt to reasoningEngine.call() ... -``` - -**Example: Using Fragments with Context Variables** - -**Fragment Definition (in `PromptManager.ts`):** -```typescript -const PROMPT_FRAGMENTS: Record = { - // ... - tool_specific_guideline: "When using the '{{toolName}}' tool, remember to provide the '{{requiredArg}}' argument clearly." -}; -``` - -**Usage in Agent Logic:** -```typescript -// const toolName = "weather_forecast"; -// const requiredArg = "location"; -// const guideline = this.deps.promptManager.getFragment( -// 'tool_specific_guideline', -// { toolName: toolName, requiredArg: requiredArg } -// ); -// // guideline would be: "When using the 'weather_forecast' tool, remember to provide the 'location' argument clearly." - -// This 'guideline' string can then be embedded into the content of an ArtStandardMessage. -``` - -## 4. Validating the Assembled Prompt (Optional) - -After your agent logic has fully constructed the `ArtStandardPrompt` object (an array of `ArtStandardMessage`s), potentially using several fragments, you can use `PromptManager.validatePrompt()` for an extra sanity check: - -```typescript -// const finalAssembledPrompt: ArtStandardPrompt = [ /* ... your messages ... */ ]; -// -// try { -// const validatedPrompt = this.deps.promptManager.validatePrompt(finalAssembledPrompt); -// // Send validatedPrompt to ReasoningEngine -// } catch (e) { -// // Handle prompt validation error (ARTError with ErrorCode.PROMPT_VALIDATION_FAILED) -// Logger.error("Constructed prompt failed validation:", e); -// } -``` -This validation uses Zod schemas defined in `src/types/schemas.ts`. - -## Benefits of Using Fragments - -* **Consistency:** Ensures standard phrasing for common instructions or warnings across different prompts or agents. -* **Maintainability:** If a common piece of instruction needs to change, you only need to update it in one place (the fragment definition). -* **Readability:** Can make your agent's prompt construction logic cleaner by referencing named fragments instead of having very long inline strings. - -While the `PromptManager` in ART `v0.2.7` doesn't handle full template rendering into the `ArtStandardPrompt` structure, its `getFragment()` method provides a valuable utility for managing and reusing common textual components of your prompts. \ No newline at end of file diff --git a/Docs/llm-full.txt b/Docs/llm-full.txt deleted file mode 100644 index 205a5cb..0000000 --- a/Docs/llm-full.txt +++ /dev/null @@ -1,703 +0,0 @@ -# ART (Agent-Reasoning-Tooling) Framework - Comprehensive Documentation - -This document provides a highly detailed overview of the ART (Agent Runtime) Framework, a comprehensive TypeScript library designed to simplify the development of sophisticated AI agents. It covers the framework's architecture, core components, key concepts, API reference, and practical usage examples. - -## 1. Introduction to ART Framework - -The ART Framework is a modular, extensible, and robust TypeScript library for building advanced AI agents. It aims to address common challenges in AI agent development by offering: - -- **Flexible Orchestration:** Decouples the agent's orchestration logic from its core functionalities (reasoning, tools, context), allowing custom agent core implementations. -- **Structured Yet Adaptable:** Provides patterns like Plan-Execute-Synthesize (`PESAgent`) while allowing diverse agent architectures. -- **Modularity:** Decoupled systems for reasoning, context management, tool usage, observation, and UI communication. -- **Provider Agnosticism:** Seamlessly switch between different LLM providers (OpenAI, Anthropic, Gemini, Ollama, etc.) via a flexible `ProviderManager` and adapter system. -- **Standardized Primitives:** Core abstractions like `ArtStandardPrompt` for LLM interactions and `StreamEvent` for real-time responses. -- **Robust Tool Integration:** A powerful `ToolSystem` and `ToolRegistry` for defining, registering, and executing custom capabilities. -- **Configurable State Management:** Built-in support for managing conversation history and agent state with explicit or implicit saving strategies. -- **Comprehensive Observability:** A dedicated `ObservationSystem` to track key events and data points for debugging and analysis. -- **Developer-Friendly API:** Intuitive design with clear interfaces and conventions. - -## 2. Core Philosophy & Design Principles - -- **Separation of Concerns:** Each component has a well-defined, single responsibility. -- **Extensibility:** Interfaces are designed to be implemented and extended, allowing developers to plug in custom components. -- **Developer Experience:** Focus on clear APIs, good documentation, and tools that make agent development faster and more reliable. -- **Standardization:** Promote common patterns and data structures (like `ArtStandardPrompt`) to reduce boilerplate and improve interoperability. - -## 3. High-Level Architecture - -The ART Framework is composed of several interconnected subsystems: - -```mermaid -flowchart TD - -%% Main Components - -User([User Input/External Triggers]) --> ArtInstance["ArtInstance\n(process method)"] - -%% Agent Core as the central orchestrator - -ArtInstance --> AgentCore["Agent Core (IAgentCore)\n(Swappable Component)\n(e.g., PESAgent)"] - -%% Major Subsystems - -subgraph ReasoningSystem ["Reasoning System"] - -ReasoningEngine["ReasoningEngine"] - -ProviderManager["ProviderManager"] - -ProviderAdapters["ProviderAdapters\n(OpenAI, Anthropic, Ollama)"] - -PromptManager["PromptManager\n(fragments/validation)"] - -OutputParser["OutputParser"] - -ExternalLLM["External LLM APIs"] - -ReasoningEngine --> ProviderManager - -ProviderManager --> ProviderAdapters - -ProviderAdapters <--> ExternalLLM - -PromptManager -.-> ReasoningEngine - -ReasoningEngine -.-> OutputParser - -end - -subgraph ToolSystem ["Tool System"] - -ToolSystemMain["ToolSystem"] - -ToolRegistry["ToolRegistry"] - -ToolExecutor["IToolExecutor\n(specific tools)"] - -ToolSystemMain --> ToolRegistry - -ToolSystemMain --> ToolExecutor - -end - -subgraph ContextSystem ["Context System"] - -StateManager["StateManager\n(ThreadConfig, AgentState)"] - -ConversationManager["ConversationManager\n(message history)"] - -ContextProvider["ContextProvider\n(future: RAG)"] - -StateRepository["StateRepository"] - -ConversationRepository["ConversationRepository"] - -StateManager --> StateRepository - -ConversationManager --> ConversationRepository - -ContextProvider -.-> AgentCore - -end - -subgraph ObservationSystem ["Observation System"] - -ObservationManager["ObservationManager"] - -ObservationRepository["ObservationRepository"] - -ObservationManager --> ObservationRepository - -end - -subgraph StorageSystem ["Storage System"] - -StorageAdapter["StorageAdapter\n(InMemory, IndexedDB, etc.)"] - -StateRepository --> StorageAdapter - -ConversationRepository --> StorageAdapter - -ObservationRepository --> StorageAdapter - -end - -subgraph UISystem ["UI System"] - -UISystemMain["UISystem"] - -LLMStreamSocket["LLMStreamSocket"] - -ObservationSocket["ObservationSocket"] - -ConversationSocket["ConversationSocket"] - -ExternalUI["External UI/Subscribers"] - -UISystemMain --> LLMStreamSocket -UISystemMain --> ObservationSocket -UISystemMain --> ConversationSocket - -LLMStreamSocket --> ExternalUI -ObservationSocket --> ExternalUI -ConversationSocket --> ExternalUI - -end - -%% Connections between Agent Core and Subsystems - -AgentCore --> ReasoningEngine -AgentCore --> ToolSystemMain -AgentCore --> StateManager -AgentCore --> ConversationManager - -%% Cross-system connections - -ReasoningEngine --> LLMStreamSocket -ToolSystemMain --> ObservationManager -ToolSystemMain <--> StateManager -ObservationManager --> ObservationSocket -ConversationManager --> ConversationSocket -AgentCore --> ObservationManager - -%% Key Data Flow Items - -ArtStandardPrompt["ArtStandardPrompt"] -.-> ReasoningEngine -StreamEvent["StreamEvent"] -.-> LLMStreamSocket -ToolResult["ToolResult"] -.-> AgentCore -Observation["Observation"] -.-> ObservationManager -ConversationMessage["ConversationMessage"] -.-> ConversationManager - -%% Configuration - -ArtInstanceConfig["ArtInstanceConfig"] -.-> ArtInstance - -%% Style - -classDef system fill:#f9f9f9,stroke:#999,stroke-width:1px -classDef core fill:#ffebcd,stroke:#ff8c00,stroke-width:2px -classDef component fill:#e6f7ff,stroke:#1890ff,stroke-width:1px -classDef external fill:#f0f0f0,stroke:#d9d9d9,stroke-width:1px -classDef dataitem fill:#f6ffed,stroke:#52c41a,stroke-width:1px,stroke-dasharray: 5 5 - -class ReasoningSystem,ToolSystem,ContextSystem,ObservationSystem,StorageSystem,UISystem system -class AgentCore core -class ReasoningEngine,ProviderManager,ProviderAdapters,PromptManager,OutputParser,ToolSystemMain,ToolRegistry,ToolExecutor,StateManager,ConversationManager,ContextProvider,ObservationManager,UISystemMain,LLMStreamSocket,ObservationSocket,ConversationSocket,StateRepository,ConversationRepository,ObservationRepository,StorageAdapter component -class User,ExternalLLM,ExternalUI external -class ArtStandardPrompt,StreamEvent,ToolResult,Observation,ConversationMessage,ArtInstanceConfig dataitem -``` - -## 4. Detailed Subsystems and Their Roles - -### 4.1. Agent Core (`IAgentCore`) - -- **Role:** The central brain and orchestrator. It defines the high-level logic for processing user queries and coordinating other systems. -- **Interface:** [`IAgentCore`](src/core/interfaces.ts:54) - - `process(props: AgentProps): Promise`: Main entry point to run the agent's reasoning cycle. -- **Default Implementation:** [`PESAgent`](src/core/agents/pes-agent.ts:91) (Plan-Execute-Synthesize Agent). - - **Workflow:** - 1. **Initiation & Config:** Loads thread configuration using [`StateManager.loadThreadContext()`](src/systems/context/managers/StateManager.ts:57), resolves system prompt hierarchy (Call-level > Thread-level > Instance-level > Agent Base Prompt). - 2. **Planning Context Assembly:** Fetches conversation history using [`ConversationManager.getMessages()`](src/systems/context/managers/ConversationManager.ts:66) and available tools using [`ToolRegistry.getAvailableTools()`](src/systems/tool/ToolRegistry.ts:64). - 3. **Planning Prompt Construction & LLM Call:** Constructs [`ArtStandardPrompt`](src/types/index.ts:502) for planning, calls [`ReasoningEngine.call()`](src/systems/reasoning/ReasoningEngine.ts:38), consumes [`StreamEvent`](src/types/index.ts:138)s, and uses [`OutputParser.parsePlanningOutput()`](src/systems/reasoning/OutputParser.ts:50) to extract intent, plan, and tool calls. Records `INTENT`, `PLAN`, `TOOL_CALL` observations via [`ObservationManager.record()`](src/systems/observation/observation-manager.ts:34). - 4. **Tool Execution:** If tool calls exist, passes them to [`ToolSystem.executeTools()`](src/systems/tool/ToolSystem.ts:52). Records `TOOL_EXECUTION` observations. - 5. **Synthesis Prompt Construction & LLM Call:** Constructs [`ArtStandardPrompt`](src/types/index.ts:502) for synthesis (including tool results), calls [`ReasoningEngine.call()`](src/systems/reasoning/ReasoningEngine.ts:38), consumes [`StreamEvent`](src/types/index.ts:138)s to form the final response. Records `SYNTHESIS` observations. - 6. **Finalization:** Saves final AI message to history using [`ConversationManager.addMessages()`](src/systems/context/managers/ConversationManager.ts:35), updates state (based on `StateSavingStrategy`) via [`StateManager.saveStateIfModified()`](src/systems/context/managers/StateManager.ts:135), records `FINAL_RESPONSE` observation, and returns [`AgentFinalResponse`](src/types/index.ts:357). - -### 4.2. Reasoning System - -- **Role:** Handles all aspects of interaction with Large Language Models (LLMs). -- **Components:** - - [`ReasoningEngine`](src/systems/reasoning/ReasoningEngine.ts:17): - - **Interface:** [`ReasoningEngine`](src/core/interfaces.ts:68) - - **Implementation:** `ReasoningEngineImpl` - - **Method:** `call(prompt: ArtStandardPrompt, options: CallOptions): Promise>` - - Delegates LLM calls to `ProviderAdapter`s via `ProviderManager`. Ensures adapter release using `ManagedAdapterAccessor.release()` in a `finally` block. - - [`ProviderManager`](src/providers/ProviderManagerImpl.ts:35): - - **Interface:** [`IProviderManager`](src/types/providers.ts:34) - - **Implementation:** `ProviderManagerImpl` - - **Responsibilities:** Centralized adapter access, lifecycle management (creation, caching, eviction), configuration handling (`ProviderManagerConfig`, `RuntimeProviderConfig`), and constraint enforcement (concurrency limits, local provider singletons). - - **Key Method:** `getAdapter(config: RuntimeProviderConfig): Promise`: Manages `ManagedInstance` objects (containing `adapter`, `configSignature`, `state: 'idle' | 'active'`, `lastUsedTimestamp`, `idleTimer`) and a `requestQueue` for concurrent requests. - - [`ProviderAdapter`](src/core/interfaces.ts:151)s: - - **Interface:** [`ProviderAdapter`](src/core/interfaces.ts:151) (extends `ReasoningEngine`) - - **Responsibilities:** - - `providerName: string` (readonly): Unique identifier. - - `call(prompt: ArtStandardPrompt, options: CallOptions): Promise>`: Translates `ArtStandardPrompt` to provider-specific API requests, makes API calls, and converts responses into `StreamEvent`s. - - `shutdown?(): Promise`: Optional method for graceful cleanup, called by `ProviderManager` during eviction. - - **Built-in Adapters:** - - [`AnthropicAdapter`](src/adapters/reasoning/anthropic.ts:55): Uses `@anthropic-ai/sdk`. Handles `system` prompt, message merging (alternating `user`/`assistant` roles), `tool_use` blocks, and `tool_result` blocks. - - [`DeepSeekAdapter`](src/adapters/reasoning/deepseek.ts:87): Uses raw `fetch` with OpenAI-compatible API. **Streaming not yet implemented**. Translates `ArtStandardPrompt` to OpenAI format. - - [`GeminiAdapter`](src/adapters/reasoning/gemini.ts:33): Uses `@google/genai` SDK. `system` prompt content is prepended to the first `user` message. `tool_result` maps to `user` role with `functionResponse` part. Ensures conversation doesn't start with `model` role. - - [`OllamaAdapter`](src/adapters/reasoning/ollama.ts:67): Uses `openai` SDK to interact with Ollama's OpenAI-compatible API. Supports R1-style message merging for specific models (e.g., `deepseek-r1`). Full tool support (translation of `ToolSchema`, `tool_calls`, `tool_result`). - - [`OpenAIAdapter`](src/adapters/reasoning/openai.ts:91): Uses raw `fetch` (as of v0.2.7). Translates `ArtStandardPrompt` to OpenAI format. Basic aggregation for streamed `tool_calls` deltas. - - [`OpenRouterAdapter`](src/adapters/reasoning/openrouter.ts:93): Uses raw `fetch` with OpenAI-compatible API. **Streaming not yet implemented**. Supports `HTTP-Referer` and `X-Title` headers. - - [`PromptManager`](src/systems/reasoning/PromptManager.ts:25): - - **Interface:** [`PromptManager`](src/core/interfaces.ts:92) - - **Implementation:** `PromptManagerImpl` - - **Methods:** - - `getFragment(name: string, context?: Record): string`: Retrieves reusable, named prompt fragments from an internal `PROMPT_FRAGMENTS` object with simple `{{key}}` substitution. Throws `PROMPT_FRAGMENT_NOT_FOUND` if not found. - - `validatePrompt(prompt: ArtStandardPrompt): ArtStandardPrompt`: Validates a constructed `ArtStandardPrompt` against `ArtStandardPromptSchema` using Zod. Throws `PROMPT_VALIDATION_FAILED` on failure. - - [`OutputParser`](src/systems/reasoning/OutputParser.ts:26): - - **Interface:** [`OutputParser`](src/core/interfaces.ts:123) - - **Implementation:** `OutputParserImpl` - - **Methods:** - - `parsePlanningOutput(output: string): Promise<{ intent?: string; plan?: string; toolCalls?: ParsedToolCall[]; thoughts?: string; }>`: Extracts structured information (Intent, Plan, Tool Calls) and content from `...` tags using [`XmlMatcher`](src/utils/xml-matcher.ts:25). Parses JSON arrays for tool calls and validates with Zod schema (`toolCallsSchema`). - - `parseSynthesisOutput(output: string): Promise`: Cleans up raw synthesis output by trimming whitespace. - -### 4.3. Tool System - -- **Role:** Enables the agent to use external capabilities or "tools." -- **Components:** - - [`IToolExecutor`](src/core/interfaces.ts:164): - - **Interface:** [`IToolExecutor`](src/core/interfaces.ts:164) - - **Properties:** `schema: ToolSchema` (readonly) - - **Method:** `execute(input: any, context: ExecutionContext): Promise`: Contains the tool's actual logic. - - [`ToolSchema`](src/types/index.ts:233): - - **Interface:** [`ToolSchema`](src/types/index.ts:233) - - Defines tool metadata: `name`, `description`, `inputSchema` (JSON Schema), `outputSchema?`, `examples?`. - - [`ToolRegistry`](src/systems/tool/ToolRegistry.ts:10): - - **Interface:** [`ToolRegistry`](src/core/interfaces.ts:180) - - **Implementation:** `ToolRegistryImpl` - - **Methods:** `registerTool(executor: IToolExecutor)`, `getToolExecutor(toolName: string)`, `getAvailableTools(filter?: { enabledForThreadId?: string })`. - - Manages registration and retrieval of `IToolExecutor` instances. Can filter tools based on `ThreadConfig.enabledTools` by interacting with `StateManager`. - - [`ToolSystem`](src/systems/tool/ToolSystem.ts:13): - - **Interface:** [`ToolSystem`](src/core/interfaces.ts:206) - - **Implementation:** `ToolSystemImpl` - - **Method:** `executeTools(toolCalls: ParsedToolCall[], threadId: string, traceId?: string): Promise` - - Orchestrates tool execution: verifies enablement via [`StateManager.isToolEnabled()`](src/systems/context/managers/StateManager.ts:95), retrieves executor from `ToolRegistry`, validates inputs using [`validateJsonSchema()`](src/utils/validation.ts:23), executes tool, and records `TOOL_EXECUTION` observations via [`ObservationManager.record()`](src/systems/observation/observation-manager.ts:34). Executes calls sequentially. -- **Built-in Tool:** [`CalculatorTool`](src/tools/CalculatorTool.ts:62): Safely evaluates mathematical expressions using `mathjs` in a sandboxed environment. Supports `ans` variable (stores last result per `threadId`) for chained calculations. - -### 4.4. Context System - -- **Role:** Manages all contextual information necessary for the agent's operation within a conversation thread. -- **Components:** - - [`StateManager`](src/systems/context/managers/StateManager.ts:34): - - **Interface:** [`StateManager`](src/core/interfaces.ts:225) - - **Implementation:** `StateManagerImpl` - - **Methods:** `loadThreadContext(threadId, userId?)`, `isToolEnabled(threadId, toolName)`, `getThreadConfigValue(threadId, key)`, `saveStateIfModified(threadId)`, `setAgentState(threadId, state)`, `setThreadConfig(threadId, config)`. - - Manages [`ThreadConfig`](src/types/index.ts:278) and [`AgentState`](src/types/index.ts:294). Its behavior is influenced by `StateSavingStrategy`. Uses `deepClone` for caching in `implicit` mode. - - [`ConversationManager`](src/systems/context/managers/ConversationManager.ts:10): - - **Interface:** [`ConversationManager`](src/core/interfaces.ts:292) - - **Implementation:** `ConversationManagerImpl` - - **Methods:** `addMessages(threadId, messages)`, `getMessages(threadId, options?)`. - - Manages the history of [`ConversationMessage`](src/types/index.ts:48)s. Notifies `ConversationSocket` on new messages. - - `ContextProvider`: - - **Source:** [`src/systems/context/ContextProvider.ts`](src/systems/context/ContextProvider.ts:17) - - **Role:** Placeholder for future Retrieval-Augmented Generation (RAG) capabilities. Currently returns empty context and logs a warning. - - Repositories: - - [`IStateRepository`](src/core/interfaces.ts:465): For `ThreadContext` (config and state). Implemented by [`StateRepository`](src/systems/context/repositories/StateRepository.ts:15). Stores `ThreadContext` as `StoredThreadContext` (adds `id` field) and removes it on retrieval. - - [`IConversationRepository`](src/core/interfaces.ts:452): For `ConversationMessage`s. Implemented by [`ConversationRepository`](src/systems/context/repositories/ConversationRepository.ts:14). Stores `ConversationMessage` as `StoredConversationMessage` (adds `id` field) and removes it on retrieval. Performs client-side sorting and filtering by timestamp. - - [`IObservationRepository`](src/core/interfaces.ts:459): For `Observation`s. Implemented by [`ObservationRepository`](src/systems/context/repositories/ObservationRepository.ts:14). Stores `Observation` directly using its `id`. Performs client-side sorting by timestamp and filtering by `ObservationType`. - -### 4.5. Observation System - -- **Role:** Provides observability into the agent's internal workings by recording significant events. -- **Components:** - - [`ObservationManager`](src/systems/observation/observation-manager.ts:12): - - **Interface:** [`ObservationManager`](src/core/interfaces.ts:317) - - **Implementation:** `ObservationManagerImpl` - - **Methods:** `record(observationData)`, `getObservations(threadId, filter?)`. - - Central service for creating, persisting, and broadcasting [`Observation`](src/types/index.ts:114) records. Automatically generates unique `id` (using [`generateUUID()`](src/utils/uuid.ts:8)), `timestamp`, and a default `title`. Notifies `ObservationSocket`. - - [`Observation`](src/types/index.ts:114): - - **Interface:** [`Observation`](src/types/index.ts:114) - - Defines the structure of a single observation record: `id`, `threadId`, `traceId?`, `timestamp`, `type`, `title`, `content`, `metadata?`. - - [`ObservationType`](src/types/index.ts:66): - - **Enum:** [`ObservationType`](src/types/index.ts:66) - - Categorizes events: `INTENT`, `PLAN`, `THOUGHTS`, `TOOL_CALL`, `TOOL_EXECUTION`, `SYNTHESIS`, `ERROR`, `FINAL_RESPONSE`, `STATE_UPDATE`, `LLM_STREAM_START/METADATA/ERROR/END`. - -### 4.6. Storage System - -- **Role:** Provides a generic persistence layer for all framework data. -- **Components:** - - [`StorageAdapter`](src/core/interfaces.ts:406): - - **Interface:** [`StorageAdapter`](src/core/interfaces.ts:406) - - **Methods:** `init?`, `get`, `set`, `delete`, `query`, `clearCollection?`, `clearAll?`. - - Abstracts data storage operations. - - Concrete Adapters: - - [`InMemoryStorageAdapter`](src/adapters/storage/inMemory.ts:16): Stores data in JavaScript Maps in memory. Non-persistent. Uses `JSON.parse(JSON.stringify(item))` for deep copies. Basic client-side filtering/limiting. - - [`IndexedDBStorageAdapter`](src/adapters/storage/indexedDB.ts:33): Uses browser's IndexedDB. Requires `init()` to be called. Configurable `dbName`, `dbVersion`, `objectStores`. Uses `structuredClone` for deep copies. Performs client-side filtering/sorting/limiting after `getAll()`. - -### 4.7. UI System - -- **Role:** Facilitates real-time communication from the agent's backend to user interfaces or other subscribed services. -- **Components:** - - [`UISystem`](src/systems/ui/ui-system.ts:16): - - **Interface:** [`UISystem`](src/core/interfaces.ts:393) - - **Implementation:** `UISystemImpl` - - **Methods:** `getObservationSocket()`, `getConversationSocket()`, `getLLMStreamSocket()`. - - Central service that instantiates and provides access to specialized sockets. - - [`TypedSocket`](src/systems/ui/typed-socket.ts:18): - - **Class:** [`TypedSocket`](src/systems/ui/typed-socket.ts:18) - - Generic base class for publish/subscribe with filtering. - - **Methods:** `subscribe(callback, filter?, options?)`, `notify(data, options?, filterCheck?)`, `clearAllSubscriptions()`, `getHistory?()`. Uses `uuidv4()` for subscription IDs. - - Specialized Sockets (extend `TypedSocket`): - - [`ConversationSocket`](src/systems/ui/conversation-socket.ts:12): For broadcasting new [`ConversationMessage`](src/types/index.ts:48) objects. Can fetch history via `IConversationRepository`. - - [`LLMStreamSocket`](src/systems/ui/llm-stream-socket.ts:13): For broadcasting [`StreamEvent`](src/types/index.ts:138) objects from LLM calls. Does not implement `getHistory` as stream events are transient. - - [`ObservationSocket`](src/systems/ui/observation-socket.ts:12): For broadcasting [`Observation`](src/types/index.ts:114) objects. Can fetch history via `IObservationRepository`. - -## 5. Key Concepts in Detail - -### 5.1. `ArtInstanceConfig` - -- **Interface:** [`ArtInstanceConfig`](src/types/index.ts:610) -- The single configuration object passed to [`createArtInstance`](src/core/agent-factory.ts:294) to initialize the entire framework. -- **Properties:** - - `storage`: Defines the storage adapter (e.g., `{ type: 'memory' }` or `{ type: 'indexedDB', dbName: 'MyDb', objectStores: ['conversations'] }`). Can also be a pre-instantiated `StorageAdapter`. - - `providers`: [`ProviderManagerConfig`](src/types/providers.ts:13) for LLM providers. - - `agentCore?`: Custom [`IAgentCore`](src/core/interfaces.ts:54) implementation class (defaults to `PESAgent`). - - `tools?`: Array of [`IToolExecutor`](src/core/interfaces.ts:164) instances to register. - - `stateSavingStrategy?`: [`StateSavingStrategy`](src/types/index.ts:602) (`'explicit'` or `'implicit'`). - - `logger?`: `{ level?: LogLevel }` for logging verbosity. - - `defaultSystemPrompt?`: Instance-level custom system prompt. - -### 5.2. `ArtStandardPrompt` and `ArtStandardMessage` - -- **`ArtStandardPrompt`**: [`ArtStandardMessage`](src/types/index.ts:457)[] (Type Alias: [`ArtStandardPrompt`](src/types/index.ts:502)). The universal, provider-agnostic format for LLM prompts. -- **`ArtStandardMessage`**: - - **Interface:** [`ArtStandardMessage`](src/types/index.ts:457) - - Represents a single message in the prompt. - - **Properties:** - - `role`: [`ArtStandardMessageRole`](src/types/index.ts:451) (Type Alias: `system`, `user`, `assistant`, `tool_request`, `tool_result`, `tool`). - - `content`: `string | object | null` (depends on role). - - `name?`: For `tool_result`, the tool name. - - `tool_calls?`: Array of objects detailing tools the `assistant` wants to call (`id`, `type: 'function'`, `function: { name, arguments: stringified JSON }`). - - `tool_call_id?`: For `tool_result`, links to the `tool_calls` ID. -- **Validation:** [`ArtStandardMessageSchema`](src/types/schemas.ts:8) and [`ArtStandardPromptSchema`](src/types/schemas.ts:54) (Zod schemas) are used for validation. -- **Purpose:** Abstract away provider-specific prompt formats, simplify agent logic, and ensure consistency. - -### 5.3. Streaming and `StreamEvent`s - -- **`StreamEvent`**: - - **Interface:** [`StreamEvent`](src/types/index.ts:138) - - Standardized event emitted from LLM streams. - - **Properties:** - - `type`: `'TOKEN'`, `'METADATA'`, `'ERROR'`, `'END'`. - - `data`: Content depends on `type`. - - `tokenType?`: More specific classification for `TOKEN` events (e.g., `LLM_THINKING`, `LLM_RESPONSE`, `AGENT_THOUGHT_LLM_RESPONSE`, `FINAL_SYNTHESIS_LLM_RESPONSE`). - - `threadId`, `traceId`, `sessionId?`. -- **Benefits:** Real-time feedback, improved perceived performance, handling intermediate thoughts. -- **UI Integration:** [`LLMStreamSocket`](src/systems/ui/llm-stream-socket.ts:13) broadcasts these events for real-time UI updates. - -### 5.4. System Prompt Hierarchy and Customization - -- The final system prompt is constructed by combining an **Agent Base Prompt** (internal to the agent, e.g., `PESAgent.defaultSystemPrompt` from [`src/core/agents/pes-agent.ts`](src/core/agents/pes-agent.ts:71)) with a **Custom Prompt Part**. -- **Precedence (highest to lowest):** - 1. **Call-Level:** `AgentProps.options.systemPrompt` (for a single `process()` call). - 2. **Thread-Level:** `ThreadConfig.systemPrompt` (for an entire conversation thread, retrieved via [`StateManager.getThreadConfigValue()`](src/systems/context/managers/StateManager.ts:113)). - 3. **Instance-Level:** `ArtInstanceConfig.defaultSystemPrompt` (default for the ART instance, passed to agent constructor). -- **Concatenation:** `Agent Base Prompt + "\n\n" + Resolved Custom Prompt Part`. - -### 5.5. State Management (`StateSavingStrategy`) - -- **`StateSavingStrategy`**: Type Alias: [`StateSavingStrategy`](src/types/index.ts:602) (`"explicit"` | `"implicit"`). -- Configured in `ArtInstanceConfig`. -- **`'explicit'` (Default):** `AgentState` is only saved when [`StateManager.setAgentState()`](src/systems/context/managers/StateManager.ts:215) is explicitly called by agent logic. [`StateManager.saveStateIfModified()`](src/systems/context/managers/StateManager.ts:135) is a no-op for `AgentState` persistence. -- **`'implicit'`:** [`StateManager.loadThreadContext()`](src/systems/context/managers/StateManager.ts:57) caches the state (deep clones it). If `AgentState` is modified, [`StateManager.saveStateIfModified()`](src/systems/context/managers/StateManager.ts:135) (called by `PESAgent` at end of cycle) automatically persists changes by comparing JSON snapshots. Explicit `setAgentState()` still works and updates the snapshot. - -## 6. Getting Started - -### 6.1. Installation - -- **Prerequisites:** Node.js (LTS version), npm or yarn. -- **Command:** `npm install art-framework` or `yarn add art-framework`. - -### 6.2. Project Setup Recommendations - -- **Directory Structure:** Organize code logically (e.g., `src/agents/`, `src/tools/`, `src/config/art-config.ts`, `src/main.ts`). -- **Centralized `ArtInstanceConfig`:** Define your main configuration in a dedicated file (e.g., `src/config/art-config.ts`). -- **Secure API Key Management:** - - **NEVER hardcode API keys.** - - Use environment variables (`process.env.YOUR_API_KEY`) for local development (with `.env` files). - - Use dedicated secrets management services (AWS Secrets Manager, Google Cloud Secret Manager) for production. - - For client-side apps, proxy LLM calls through a secure backend server. -- **TypeScript Configuration (`tsconfig.json`):** Essential for type checking and compilation. - -### 6.3. Quick Start: "Hello, Agent!" - -- **Steps:** - 1. Import `createArtInstance`, `ArtInstanceConfig`, `AgentProps`, `LogLevel`, and a `ProviderAdapter` (e.g., `OpenAIAdapter` or a mock). - 2. Define `ArtInstanceConfig` with `storage` (e.g., `{ type: 'memory' }`) and `providers`. - 3. Call `createArtInstance(artConfig)`. - 4. Call `art.process(agentProps)` with a `query`, `threadId`, and `options.providerConfig` (specifying `providerName`, `modelId`, `adapterOptions` like `apiKey`). -- **Example:** [`Docs/getting-started/quick-start.md`](Docs/getting-started/quick-start.md) - -## 7. How-To Guides (Detailed) - -### 7.1. Configure an ART Instance ([`Docs/how-to/configure-art-instance.md`](Docs/how-to/configure-art-instance.md)) - -- **Scenarios:** - - **Simple In-Memory Agent:** Uses [`InMemoryStorageAdapter`](src/adapters/storage/inMemory.ts:16) for testing/demos. - - **Persistent Web Agent:** Uses [`IndexedDBStorageAdapter`](src/adapters/storage/indexedDB.ts:33) for browser persistence and multiple LLM options. - - **Custom Agent Core:** Demonstrates specifying a custom `IAgentCore` implementation and explicit state saving. -- **Key Configuration Points:** `storage` (`'memory'` or `'indexedDB'`), `providers.availableProviders` (defining `name`, `adapter`, `isLocal`), `RuntimeProviderConfig` (in `AgentProps.options` for `providerName`, `modelId`, `adapterOptions`), `tools`, `stateSavingStrategy`, `logger.level`. - -### 7.2. Configure System Prompts ([`Docs/how-to/configure-system-prompts.md`](Docs/how-to/configure-system-prompts.md)) - -- Explains how to set custom system prompts at instance, thread, and call levels, leveraging the hierarchy. -- **Mechanism:** - - Instance-level: `ArtInstanceConfig.defaultSystemPrompt`. - - Thread-level: `ThreadConfig.systemPrompt` (set via [`StateManager.setThreadConfig()`](src/systems/context/managers/StateManager.ts:193)). - - Call-level: `AgentProps.options.systemPrompt` (passed to `art.process()`). -- The agent's base prompt is always included, and the highest precedence custom part is appended. - -### 7.3. Create a Custom Agent Core ([`Docs/how-to/create-custom-agent.md`](Docs/how-to/create-custom-agent.md)) - -- Guide to implementing the [`IAgentCore`](src/core/interfaces.ts:54) interface for custom orchestration logic. -- **Steps:** - 1. Understand `IAgentCore`'s `process` method signature. - 2. Define your agent's custom reasoning pattern (e.g., ReAct, specialized task flow). - 3. Create a class implementing `IAgentCore`, accepting necessary ART subsystem dependencies in its constructor (e.g., `StateManager`, `ReasoningEngine`). - 4. Implement the `process` method, handling context loading, prompt construction, LLM interaction, tool usage, state saving, and observation recording. - 5. Configure `ArtInstanceConfig.agentCore` to use your custom agent class. - -### 7.4. Define and Use Tools ([`Docs/how-to/define-tools.md`](Docs/how-to/define-tools.md)) - -- Guide to extending agent capabilities with custom tools. -- **Steps:** - 1. Understand [`IToolExecutor`](src/core/interfaces.ts:164) and [`ToolSchema`](src/types/index.ts:233). - 2. Create a custom tool class implementing `IToolExecutor`. - 3. Implement the `schema` property: define `name`, `description`, `inputSchema` (JSON Schema), `outputSchema?`, `examples?`. - 4. Implement the `async execute(input, context)` method: contains tool's logic, returns `ToolResult` (`status`, `output`/`error`). - 5. Register the tool: Add an instance to `ArtInstanceConfig.tools`. - 6. (Optional) Enable the tool for specific threads via `ThreadConfig.enabledTools`. - 7. Ensure agent's planning prompt informs LLM about the tool. - -### 7.5. Handle Streaming Events in a UI ([`Docs/how-to/handle-streaming-ui.md`](Docs/how-to/handle-streaming-ui.md)) - -- Conceptual guide for client-side UI integration with ART's UI Sockets for real-time updates. -- **Key Sockets:** - - [`LLMStreamSocket`](src/systems/ui/llm-stream-socket.ts:13): For `StreamEvent`s (token-by-token LLM responses). - - [`ObservationSocket`](src/systems/ui/observation-socket.ts:12): For `Observation` objects (agent's thought process, tool usage). - - [`ConversationSocket`](src/systems/ui/conversation-socket.ts:12): For new `ConversationMessage`s (chat history). -- **Usage:** Obtain socket instances from `artInstance.uiSystem`, then use their `subscribe()` methods with callbacks and optional filters (`threadId`, event types). - -### 7.6. Manage Agent State (`StateSavingStrategy`) ([`Docs/how-to/manage-agent-state.md`](Docs/how-to/manage-agent-state.md)) - -- Explains how `AgentState` persistence is controlled by `StateSavingStrategy` in `ArtInstanceConfig`. -- **`'explicit'` (Default):** Requires manual calls to [`StateManager.setAgentState()`](src/systems/context/managers/StateManager.ts:215) to save state. -- **`'implicit'`:** Automatically saves modified `AgentState` when [`StateManager.saveStateIfModified()`](src/systems/context/managers/StateManager.ts:135) is called (e.g., by `PESAgent` at end of cycle) by comparing snapshots. - -### 7.7. Manage Multiple LLM Providers ([`Docs/how-to/manage-multiple-llms.md`](Docs/how-to/manage-multiple-llms.md)) - -- Guide to configuring and using multiple LLM providers simultaneously. -- **Steps:** - 1. Configure `ProviderManagerConfig.availableProviders` in `ArtInstanceConfig`, defining unique names, adapter classes, and `isLocal` flag for each provider setup. - 2. Select a provider at runtime using `AgentProps.options.providerConfig` (specifying `providerName`, `modelId`, and `adapterOptions` like `apiKey`). - 3. (Optional) Set a thread-level default provider in `ThreadConfig.providerConfig`. - -### 7.8. Use the `ans` Variable in `CalculatorTool` ([`Docs/how-to/use-calculator-ans.md`](Docs/how-to/use-calculator-ans.md)) - -- Explains how the built-in [`CalculatorTool`](src/tools/CalculatorTool.ts:62) remembers the result of the last calculation within the same conversation thread as `ans`, enabling multi-step calculations. -- `ans` is thread-scoped and overwritten by each successful calculation. - -### 7.9. Leverage `` Tags for Agent Observability ([`Docs/how-to/leverage-think-tags.md`](Docs/how-to/leverage-think-tags.md)) - -- How to instruct LLMs to output reasoning within `...` XML-like tags. -- The [`OutputParser`](src/systems/reasoning/OutputParser.ts:26) extracts this content into a `thoughts` field, providing deeper insights into the LLM's reasoning for debugging and transparency. - -### 7.10. Use Prompt Fragments with `PromptManager` ([`Docs/how-to/use-prompt-fragments.md`](Docs/how-to/use-prompt-fragments.md)) - -- Explains how [`PromptManager.getFragment()`](src/systems/reasoning/PromptManager.ts:38) provides reusable, named text pieces (fragments) with optional variable substitution. -- These fragments can be embedded into the `content` of `ArtStandardMessage` objects during prompt construction by agent logic, promoting consistency and reducing redundancy. -- [`PromptManager.validatePrompt()`](src/systems/reasoning/PromptManager.ts:65) can be used to validate the assembled `ArtStandardPrompt`. - -## 8. Examples (Detailed) - -### 8.1. Basic Chatbot ([`Docs/examples/basic-chatbot.md`](Docs/examples/basic-chatbot.md)) - -- Demonstrates minimal setup for a simple conversational agent. -- Uses [`InMemoryStorageAdapter`](src/adapters/storage/inMemory.ts:16) (non-persistent history) and can be configured with a mock or real LLM adapter. -- Illustrates `ArtInstanceConfig`, `createArtInstance`, `AgentProps`, and basic `art.process()` interaction. - -### 8.2. Agent with Tools ([`Docs/examples/agent-with-tools.md`](Docs/examples/agent-with-tools.md)) - -- Shows how to integrate and use tools (e.g., built-in [`CalculatorTool`](src/tools/CalculatorTool.ts:62)) with `PESAgent`. -- **Key Concepts:** Tool registration in `ArtInstanceConfig.tools`, LLM prompting for tools, tool call detection by `OutputParser`, tool execution by `ToolSystem`, `ToolResult` handling, and synthesis with tool results. - -### 8.3. Multi-Provider Agent ([`Docs/examples/multi-provider-agent.md`](Docs/examples/multi-provider-agent.md)) - -- Demonstrates configuring and dynamically using multiple LLM providers (e.g., OpenAI, Anthropic, Ollama) at runtime. -- Highlights `ArtInstanceConfig.providers.availableProviders` and `AgentProps.options.providerConfig` for dynamic selection. - -### 8.4. Persistent Agent (using IndexedDB) ([`Docs/examples/persistent-agent.md`](Docs/examples/persistent-agent.md)) - -- Shows how to configure an agent to use [`IndexedDBStorageAdapter`](src/adapters/storage/indexedDB.ts:33) for persisting conversation history and agent state across browser sessions. -- Intended for browser environments. Demonstrates loading and saving history. - -## 9. Advanced Topics - -### 9.1. Debugging ART Applications ([`Docs/advanced/debugging-art-applications.md`](Docs/advanced/debugging-art-applications.md)) - -- **Strategies:** - - **`Logger`:** Set `LogLevel.DEBUG` for detailed internal logs. - - **`ObservationSystem`:** Subscribe to [`ObservationSocket`](src/systems/ui/observation-socket.ts:12) or query [`ObservationManager.getObservations()`](src/systems/observation/observation-manager.ts:64) to inspect agent's audit trail (`INTENT`, `PLAN`, `TOOL_EXECUTION`, `ERROR`). - - **Stored Data:** Inspect `IndexedDB` (browser dev tools) for `conversations`, `observations`, `state`. - - **LLM Prompts/Responses:** Log full `ArtStandardPrompt` before sending, and raw LLM output after receiving. Isolate LLM calls for testing. - - **Tool Debugging:** Validate `ToolSchema`, log inside `execute()`, test tools in isolation. - - **TypeScript & Static Analysis:** Leverage type checking and linters. - - **Step-Through Debugging:** Use breakpoints in agent logic, parsers, tool system, and adapters. - -### 9.2. Performance Tuning ([`Docs/advanced/performance-tuning.md`](Docs/advanced/performance-tuning.md)) - -- **LLM Interaction:** Model selection (latency vs. capability), always enable streaming for UX, concise/clear prompts, `max_tokens` limits, `ProviderManager` tuning (`maxParallelApiInstancesPerProvider`, `apiInstanceIdleTimeoutSeconds`). -- **Storage Adapter:** Choose appropriate adapter (`InMemory` for speed, `IndexedDB` for browser persistence). Optimize `query()` for large datasets (e.g., using IndexedDB indexes). -- **Agent Logic:** Minimize LLM calls, efficient context gathering (`historyLimit`), efficient tool execution, consider `StateSavingStrategy` overhead. -- **Asynchronous Operations:** Ensure proper `async/await` usage to avoid blocking. -- **Caching:** Implement application-level caching for tool results or frequently accessed data. -- **Observability & Profiling:** Use `LogLevel.DEBUG` and profiling tools. -- **Client-Side UI:** Efficiently render streamed tokens, debounce/throttle UI updates. - -### 9.3. Security Considerations ([`Docs/advanced/security-considerations.md`](Docs/advanced/security-considerations.md)) - -- **API Key Management:** Never hardcode. Use environment variables, secrets management services, or backend proxies. -- **Tool Security:** Strict `inputSchema` validation, principle of least privilege, sandboxing for code execution, output sanitization, `ThreadConfig.enabledTools` for access control. -- **LLM Prompt Injection:** Clear system prompts, input filtering (limited), robust output parsing/validation, defense in depth, use models with built-in defenses. -- **Data Privacy & Storage:** Be mindful of sensitive data in conversation history, agent state, and observations. Secure storage (encryption, access controls), retention policies, user data rights. -- **UI Socket Communication:** Secure channels (WSS/HTTPS), authentication/authorization for subscriptions, input validation for control messages. -- **Denial of Service (DoS) / Resource Exhaustion:** Implement rate limiting, quotas for LLM calls and tool execution, manage storage growth. -- **Third-Party Dependencies:** Keep updated, audit for vulnerabilities. -- **Secure Development Practices:** Follow secure coding, regular reviews, threat modeling. - -### 9.4. Understanding `ProviderManagerImpl` Internals ([`Docs/advanced/understanding-provider-manager.md`](Docs/advanced/understanding-provider-manager.md)) - -- Deep dive into the internal mechanisms of `ProviderManager`: - - **Configuration Signature:** Unique identifier for adapter configurations. - - **Managed Instances:** Internal map storing active/idle adapter instances. - - **Request Queue:** Holds requests when concurrency limits are reached. -- **Lifecycle:** Detailed explanation of adapter request, release, and eviction processes, including local provider constraints and API concurrency limits. -- **Trade-offs:** Discusses design choices like caching by signature and release responsibility. - -## 10. API Reference (Comprehensive) - -The ART Framework provides a rich API, documented in detail under the `Docs/API/` directory and directly from source code comments. - -### 10.1. Enumerations - -- [`ErrorCode`](src/errors.ts:6): Standardized error codes for framework issues. Includes categories for Configuration, Storage, Reasoning, Tool, Agent Core, General, and Provider Manager errors. -- [`LogLevel`](src/utils/logger.ts:4): Severity levels for the `Logger` (`DEBUG`, `INFO`, `WARN`, `ERROR`). -- [`MessageRole`](src/types/index.ts:38): Role of a message sender in a conversation (`USER`, `AI`, `SYSTEM`, `TOOL`). -- [`ModelCapability`](src/types/index.ts:99): Capabilities a model might possess (`TEXT`, `VISION`, `STREAMING`, `TOOL_USE`, `RAG`, `CODE`, `REASONING`). -- [`ObservationType`](src/types/index.ts:66): Types of events recorded during agent execution (`INTENT`, `PLAN`, `THOUGHTS`, `TOOL_CALL`, `TOOL_EXECUTION`, `SYNTHESIS`, `ERROR`, `FINAL_RESPONSE`, `STATE_UPDATE`, `LLM_STREAM_START/METADATA/ERROR/END`). - -### 10.2. Classes - -- **Error Classes (extend [`ARTError`](src/errors.ts:53)):** - - [`AdapterInstantiationError`](src/errors.ts:107): Thrown when an adapter fails to instantiate. - - [`ApiQueueTimeoutError`](src/errors/errors.ts:100): Thrown when waiting for an API provider instance times out. - - [`ARTError`](src/errors.ts:53): Base custom error class for ART framework specific errors. Includes `code` and `originalError`. - - [`LocalInstanceBusyError`](src/errors.ts:93): Thrown when a local provider instance is already active. - - [`LocalProviderConflictError`](src/errors.ts:86): Thrown when attempting to activate a local provider while another is active. - - [`UnknownProviderError`](src/errors.ts:79): Thrown when a requested provider is not configured. -- **Adapters:** - - [`AnthropicAdapter`](src/adapters/reasoning/anthropic.ts:55): Implements `ProviderAdapter` for Anthropic Messages API. - - [`DeepSeekAdapter`](src/adapters/reasoning/deepseek.ts:87): Implements `ProviderAdapter` for DeepSeek API (OpenAI-compatible). - - [`GeminiAdapter`](src/adapters/reasoning/gemini.ts:33): Implements `ProviderAdapter` for Google Gemini models. - - [`IndexedDBStorageAdapter`](src/adapters/storage/indexedDB.ts:33): Implements `StorageAdapter` for browser IndexedDB. - - [`InMemoryStorageAdapter`](src/adapters/storage/inMemory.ts:16): Implements `StorageAdapter` for in-memory storage. - - [`OllamaAdapter`](src/adapters/reasoning/ollama.ts:67): Implements `ProviderAdapter` for Ollama (OpenAI-compatible). - - [`OpenAIAdapter`](src/adapters/reasoning/openai.ts:91): Implements `ProviderAdapter` for OpenAI Chat Completions API. - - [`OpenRouterAdapter`](src/adapters/reasoning/openrouter.ts:93): Implements `ProviderAdapter` for OpenRouter API (OpenAI-compatible). -- **Core Components:** - - [`CalculatorTool`](src/tools/CalculatorTool.ts:62): Implements `IToolExecutor` for mathematical expressions. - - [`LLMStreamSocket`](src/systems/ui/llm-stream-socket.ts:13): Extends `TypedSocket` for broadcasting `StreamEvent`s. - - [`Logger`](src/utils/logger.ts:29): Static class for console logging with configurable levels. - - [`PESAgent`](src/core/agents/pes-agent.ts:91): Implements `IAgentCore` for Plan-Execute-Synthesize logic. - - [`TypedSocket`](src/systems/ui/typed-socket.ts:18): Generic base class for publish/subscribe pattern. - - [`XmlMatcher`](src/utils/xml-matcher.ts:25): Utility class to find and extract content within XML-like tags from text streams. -- **Other:** - - `AgentFactory` ([`src/core/agent-factory.ts`](src/core/agent-factory.ts:117)): Internal class responsible for instantiating and wiring all core ART components. Used by `createArtInstance`. - - `ProviderManagerImpl` ([`src/providers/ProviderManagerImpl.ts`](src/providers/ProviderManagerImpl.ts:35)): Implements `IProviderManager`. - - `ConversationManagerImpl` ([`src/systems/context/managers/ConversationManager.ts`](src/systems/context/managers/ConversationManager.ts:10)): Implements `ConversationManager`. - - `StateManagerImpl` ([`src/systems/context/managers/StateManager.ts`](src/systems/context/managers/StateManager.ts:34)): Implements `StateManager`. - - `ObservationManagerImpl` ([`src/systems/observation/observation-manager.ts`](src/systems/observation/observation-manager.ts:12)): Implements `ObservationManager`. - - `ToolRegistryImpl` ([`src/systems/tool/ToolRegistry.ts`](src/systems/tool/ToolRegistry.ts:10)): Implements `ToolRegistry`. - - `ToolSystemImpl` ([`src/systems/tool/ToolSystem.ts`](src/systems/tool/ToolSystem.ts:13)): Implements `ToolSystem`. - - `PromptManagerImpl` ([`src/systems/reasoning/PromptManager.ts`](src/systems/reasoning/PromptManager.ts:25)): Implements `PromptManager`. - - `ReasoningEngineImpl` ([`src/systems/reasoning/ReasoningEngine.ts`](src/systems/reasoning/ReasoningEngine.ts:17)): Implements `ReasoningEngine`. - - `OutputParserImpl` ([`src/systems/reasoning/OutputParser.ts`](src/systems/reasoning/OutputParser.ts:26)): Implements `OutputParser`. - - `UISystemImpl` ([`src/systems/ui/ui-system.ts`](src/systems/ui/ui-system.ts:16)): Implements `UISystem`. - - `ConversationRepository` ([`src/systems/context/repositories/ConversationRepository.ts`](src/systems/context/repositories/ConversationRepository.ts:14)): Implements `IConversationRepository`. - - `ObservationRepository` ([`src/systems/context/repositories/ObservationRepository.ts`](src/systems/context/repositories/ObservationRepository.ts:14)): Implements `IObservationRepository`. - - `StateRepository` ([`src/systems/context/repositories/StateRepository.ts`](src/systems/context/repositories/StateRepository.ts:15)): Implements `IStateRepository`. - - `ContextProvider` ([`src/systems/context/ContextProvider.ts`](src/systems/context/ContextProvider.ts:17)): Placeholder for RAG. - -### 10.3. Interfaces - -- **Agent Core & Execution:** - - [`AgentFinalResponse`](src/types/index.ts:357): Final structured response from agent core. - - `AgentOptions` ([`src/types/index.ts`](src/types/index.ts:336)): Options to override agent behavior at runtime. - - [`AgentProps`](src/types/index.ts:316): Properties to initiate an agent processing cycle. - - [`AgentState`](src/types/index.ts:294): Non-configuration state associated with an agent or thread. - - [`ArtInstance`](src/core/interfaces.ts:475): Fully initialized ART Framework client instance. - - [`ArtInstanceConfig`](src/types/index.ts:610): Configuration for creating an ART instance. - - [`ExecutionContext`](src/types/index.ts:393): Context provided to a tool during its execution. - - [`ExecutionMetadata`](src/types/index.ts:367): Metadata summarizing an agent execution cycle. - - [`IAgentCore`](src/core/interfaces.ts:54): Interface for the central agent orchestrator. -- **Messaging & Conversation:** - - [`ArtStandardMessage`](src/types/index.ts:457): Single message in `ArtStandardPrompt` format. - - [`ConversationManager`](src/core/interfaces.ts:292): Interface for managing conversation history. - - [`ConversationMessage`](src/types/index.ts:48): Single message within a conversation thread. - - `ConversationSocket` ([`src/core/interfaces.ts`](src/core/interfaces.ts:380)): TypedSocket for `ConversationMessage` data. - - [`IConversationRepository`](src/core/interfaces.ts:452): Repository for `ConversationMessage`s. - - `MessageOptions` ([`src/types/index.ts`](src/types/index.ts:566)): Options for retrieving conversation messages. -- **LLM & Reasoning:** - - `AvailableProviderEntry` ([`src/types/providers.ts`](src/types/providers.ts:6)): Entry defining an available provider adapter. - - `CallOptions` ([`src/types/index.ts`](src/types/index.ts:407)): Options for configuring an LLM call. - - `IProviderManager` ([`src/types/providers.ts`](src/types/providers.ts:34)): Interface for the ProviderManager. - - `LLMMetadata` ([`src/types/index.ts`](src/types/index.ts:210)): Metadata about an LLM call. - - `ManagedAdapterAccessor` ([`src/types/providers.ts`](src/types/providers.ts:28)): Object returned by ProviderManager granting access to an adapter instance. - - `OllamaAdapterOptions` ([`src/adapters/reasoning/ollama.ts`](src/adapters/reasoning/ollama.ts:21)): Configuration options for `OllamaAdapter`. - - [`OutputParser`](src/core/interfaces.ts:123): Interface for parsing structured output from LLM responses. - - [`ParsedToolCall`](src/types/index.ts:266): Parsed request from LLM to call a tool. - - `PromptContext` ([`src/types/index.ts`](src/types/index.ts:512)): Contextual data for prompt generation. - - [`PromptManager`](src/core/interfaces.ts:92): Interface for prompt fragment management and validation. - - [`ProviderAdapter`](src/core/interfaces.ts:151): Base interface for LLM Provider Adapters. - - [`ProviderManagerConfig`](src/types/providers.ts:13): Configuration for ProviderManager. - - [`ReasoningEngine`](src/core/interfaces.ts:68): Interface for interacting with LLMs. - - [`RuntimeProviderConfig`](src/types/providers.ts:21): Configuration passed at runtime for a specific LLM call. - - [`StreamEvent`](src/types/index.ts:138): Single event emitted from an asynchronous LLM stream. -- **Tools:** - - [`IToolExecutor`](src/core/interfaces.ts:164): Interface for executable tool logic. - - [`ToolRegistry`](src/core/interfaces.ts:180): Interface for managing tool registration. - - [`ToolResult`](src/types/index.ts:248): Structured result of a tool execution. - - [`ToolSchema`](src/types/index.ts:233): Defines the schema for a tool. - - [`ToolSystem`](src/core/interfaces.ts:206): Interface for orchestrating tool execution. -- **State & Storage:** - - `FilterOptions` ([`src/types/index.ts`](src/types/index.ts:551)): Options for filtering data from storage. - - `JsonObjectSchema` ([`src/types/index.ts`](src/types/index.ts:185)): Basic JSON Schema definition for objects. - - `IStateRepository` ([`src/core/interfaces.ts`](src/core/interfaces.ts:465)): Repository for `ThreadConfig` and `AgentState`. - - [`StateManager`](src/core/interfaces.ts:225): Interface for managing thread-specific configuration and state. - - [`StorageAdapter`](src/core/interfaces.ts:406): Interface for a generic persistence layer. - - [`ThreadConfig`](src/types/index.ts:278): Configuration specific to a conversation thread. - - [`ThreadContext`](src/types/index.ts:306): Encapsulates configuration and state for a thread. -- **Observability & UI:** - - `IObservationRepository` ([`src/core/interfaces.ts`](src/core/interfaces.ts:459)): Repository for `Observation` data. - - `ObservationFilter` ([`src/types/index.ts`](src/types/index.ts:580)): Options for filtering observations. - - [`ObservationManager`](src/core/interfaces.ts:317): Interface for managing observations. - - `ObservationSocket` ([`src/core/interfaces.ts`](src/core/interfaces.ts:378)): TypedSocket for `Observation` data. - - `ITypedSocket` ([`src/core/interfaces.ts`](src/core/interfaces.ts:339)): Generic interface for a typed publish/subscribe socket. - - [`UISystem`](src/core/interfaces.ts:393): Interface for providing access to UI communication sockets. - - `XmlMatcherChunk` ([`src/utils/xml-matcher.ts`](src/utils/xml-matcher.ts:7)): Chunk of text processed by `XmlMatcher`. - -### 10.4. Type Aliases - -- [`ArtStandardMessageRole`](src/types/index.ts:451): Defines standard roles for messages (`system`, `user`, `assistant`, `tool_request`, `tool_result`, `tool`). -- [`ArtStandardPrompt`](src/types/index.ts:502): Represents the entire prompt as an array of `ArtStandardMessage`s. -- `FormattedPrompt` ([`src/types/index.ts`](src/types/index.ts:545)): Deprecated, use `ArtStandardPrompt`. -- [`JsonSchema`](src/types/index.ts:204): Represents a JSON Schema object. -- [`StateSavingStrategy`](src/types/index.ts:602): Defines the strategy for saving `AgentState` (`explicit` | `implicit`). -- `UnsubscribeFunction` ([`src/systems/ui/typed-socket.ts`](src/systems/ui/typed-socket.ts:5)): Function type for unsubscribing from sockets. - -### 10.5. Functions - -- [`createArtInstance`](src/core/agent-factory.ts:294): High-level factory function to create and initialize an ART instance. -- [`generateUUID`](src/utils/uuid.ts:8): Generates a unique Version 4 UUID. -- `validateJsonSchema` ([`src/utils/validation.ts`](src/utils/validation.ts:23)): Utility for validating objects against JSON Schema using Ajv. Caches compiled validators. -- `clearJsonSchemaValidatorCache` ([`src/utils/validation.ts`](src/utils/validation.ts:67)): Clears internal cache for JSON schema validator. - -### 10.6. Variables - -- [`ArtStandardMessageSchema`](src/types/schemas.ts:8): Zod schema for validating `ArtStandardMessage`. -- [`ArtStandardPromptSchema`](src/types/schemas.ts:54): Zod schema for validating `ArtStandardPrompt`. -- [`VERSION`](src/index.ts:72): The current version of the ART Framework package. - -This comprehensive documentation aims to provide a deep understanding of the ART Framework, enabling developers to build, customize, and debug sophisticated AI agents effectively. \ No newline at end of file diff --git a/Docs/llm.txt b/Docs/llm.txt deleted file mode 100644 index 15a6ade..0000000 --- a/Docs/llm.txt +++ /dev/null @@ -1,704 +0,0 @@ -# ART (Agent-Reasoning-Tooling) Framework - Comprehensive Documentation - -This document provides a highly detailed overview of the ART (Agent Runtime) Framework, a comprehensive TypeScript library designed to simplify the development of sophisticated AI agents. It covers the framework's architecture, core components, key concepts, API reference, and practical usage examples. - -## 1. Introduction to ART Framework - -The ART Framework is a modular, extensible, and robust TypeScript library for building advanced AI agents. It aims to address common challenges in AI agent development by offering: - -- **Flexible Orchestration:** Decouples the agent's orchestration logic from its core functionalities (reasoning, tools, context), allowing custom agent core implementations. -- **Structured Yet Adaptable:** Provides patterns like Plan-Execute-Synthesize (`PESAgent`) while allowing diverse agent architectures. -- **Modularity:** Decoupled systems for reasoning, context management, tool usage, observation, and UI communication. -- **Provider Agnosticism:** Seamlessly switch between different LLM providers (OpenAI, Anthropic, Gemini, Ollama, etc.) via a flexible `ProviderManager` and adapter system. -- **Standardized Primitives:** Core abstractions like `ArtStandardPrompt` for LLM interactions and `StreamEvent` for real-time responses. -- **Robust Tool Integration:** A powerful `ToolSystem` and `ToolRegistry` for defining, registering, and executing custom capabilities. -- **Configurable State Management:** Built-in support for managing conversation history and agent state with explicit or implicit saving strategies. -- **Comprehensive Observability:** A dedicated `ObservationSystem` to track key events and data points for debugging and analysis. -- **Developer-Friendly API:** Intuitive design with clear interfaces and conventions. - -## 2. Core Philosophy & Design Principles - -- **Separation of Concerns:** Each component has a well-defined, single responsibility. -- **Extensibility:** Interfaces are designed to be implemented and extended, allowing developers to plug in custom components. -- **Developer Experience:** Focus on clear APIs, good documentation, and tools that make agent development faster and more reliable. -- **Standardization:** Promote common patterns and data structures (like `ArtStandardPrompt`) to reduce boilerplate and improve interoperability. - -## 3. High-Level Architecture - -The ART Framework is composed of several interconnected subsystems: - -```mermaid -flowchart TD - -%% Main Components - -User([User Input/External Triggers]) --> ArtInstance["ArtInstance\n(process method)"] - -%% Agent Core as the central orchestrator - -ArtInstance --> AgentCore["Agent Core (IAgentCore)\n(Swappable Component)\n(e.g., PESAgent)"] - -%% Major Subsystems - -subgraph ReasoningSystem ["Reasoning System"] - -ReasoningEngine["ReasoningEngine"] - -ProviderManager["ProviderManager"] - -ProviderAdapters["ProviderAdapters\n(OpenAI, Anthropic, Ollama)"] - -PromptManager["PromptManager\n(fragments/validation)"] - -OutputParser["OutputParser"] - -ExternalLLM["External LLM APIs"] - -ReasoningEngine --> ProviderManager - -ProviderManager --> ProviderAdapters - -ProviderAdapters <--> ExternalLLM - -PromptManager -.-> ReasoningEngine - -ReasoningEngine -.-> OutputParser - -end - -subgraph ToolSystem ["Tool System"] - -ToolSystemMain["ToolSystem"] - -ToolRegistry["ToolRegistry"] - -ToolExecutor["IToolExecutor\n(specific tools)"] - -ToolSystemMain --> ToolRegistry - -ToolSystemMain --> ToolExecutor - -end - -subgraph ContextSystem ["Context System"] - -StateManager["StateManager\n(ThreadConfig, AgentState)"] - -ConversationManager["ConversationManager\n(message history)"] - -ContextProvider["ContextProvider\n(future: RAG)"] - -StateRepository["StateRepository"] - -ConversationRepository["ConversationRepository"] - -StateManager --> StateRepository - -ConversationManager --> ConversationRepository - -ContextProvider -.-> AgentCore - -end - -subgraph ObservationSystem ["Observation System"] - -ObservationManager["ObservationManager"] - -ObservationRepository["ObservationRepository"] - -ObservationManager --> ObservationRepository - -end - -subgraph StorageSystem ["Storage System"] - -StorageAdapter["StorageAdapter\n(InMemory, IndexedDB, etc.)"] - -StateRepository --> StorageAdapter - -ConversationRepository --> StorageAdapter - -ObservationRepository --> StorageAdapter - -end - -subgraph UISystem ["UI System"] - -UISystemMain["UISystem"] - -LLMStreamSocket["LLMStreamSocket"] - -ObservationSocket["ObservationSocket"] - -ConversationSocket["ConversationSocket"] - -ExternalUI["External UI/Subscribers"] - -UISystemMain --> LLMStreamSocket - -UISystemMain --> ObservationSocket - -UISystemMain --> ConversationSocket - -LLMStreamSocket --> ExternalUI - -ObservationSocket --> ExternalUI - -ConversationSocket --> ExternalUI - -end - -%% Connections between Agent Core and Subsystems - -AgentCore --> ReasoningEngine - -AgentCore --> ToolSystemMain - -AgentCore --> StateManager - -AgentCore --> ConversationManager - -%% Cross-system connections - -ReasoningEngine --> LLMStreamSocket - -ToolSystemMain --> ObservationManager - -ToolSystemMain <--> StateManager - -ObservationManager --> ObservationSocket - -ConversationManager --> ConversationSocket - -AgentCore --> ObservationManager - -%% Key Data Flow Items - -ArtStandardPrompt["ArtStandardPrompt"] -.-> ReasoningEngine - -StreamEvent["StreamEvent"] -.-> LLMStreamSocket - -ToolResult["ToolResult"] -.-> AgentCore - -Observation["Observation"] -.-> ObservationManager - -ConversationMessage["ConversationMessage"] -.-> ConversationManager - -%% Configuration - -ArtInstanceConfig["ArtInstanceConfig"] -.-> ArtInstance - -%% Style - -classDef system fill:#f9f9f9,stroke:#999,stroke-width:1px - -classDef core fill:#ffebcd,stroke:#ff8c00,stroke-width:2px - -classDef component fill:#e6f7ff,stroke:#1890ff,stroke-width:1px - -classDef external fill:#f0f0f0,stroke:#d9d9d9,stroke-width:1px - -classDef dataitem fill:#f6ffed,stroke:#52c41a,stroke-width:1px,stroke-dasharray: 5 5 - -class ReasoningSystem,ToolSystem,ContextSystem,ObservationSystem,StorageSystem,UISystem system - -class AgentCore core - -class ReasoningEngine,ProviderManager,ProviderAdapters,PromptManager,OutputParser,ToolSystemMain,ToolRegistry,ToolExecutor,StateManager,ConversationManager,ContextProvider,ObservationManager,UISystemMain,LLMStreamSocket,ObservationSocket,ConversationSocket,StateRepository,ConversationRepository,ObservationRepository,StorageAdapter component - -class User,ExternalLLM,ExternalUI external - -class ArtStandardPrompt,StreamEvent,ToolResult,Observation,ConversationMessage,ArtInstanceConfig dataitem -``` - -## 4. Detailed Subsystems and Their Roles - -### 4.1. Agent Core (`IAgentCore`) - -- **Role:** The central brain and orchestrator. It defines the high-level logic for processing user queries and coordinating other systems. -- **Interface:** [`IAgentCore`](Docs/API/interfaces/IAgentCore.md) - - `process(props: AgentProps): Promise`: Main entry point to run the agent's reasoning cycle. -- **Default Implementation:** [`PESAgent`](Docs/API/classes/PESAgent.md) (Plan-Execute-Synthesize Agent). - - **Workflow:** - 1. **Initiation & Config:** Loads thread configuration, resolves system prompt hierarchy (Call-level > Thread-level > Instance-level > Agent Base Prompt). - 2. **Planning Context Assembly:** Fetches conversation history and available tools. - 3. **Planning Prompt Construction & LLM Call:** Constructs [`ArtStandardPrompt`](Docs/API/type-aliases/ArtStandardPrompt.md) for planning, calls [`ReasoningEngine.call()`](Docs/API/interfaces/ReasoningEngine.md), consumes [`StreamEvent`](Docs/API/interfaces/StreamEvent.md)s, and uses [`OutputParser.parsePlanningOutput()`](Docs/API/interfaces/OutputParser.md) to extract intent, plan, and tool calls. Records `INTENT`, `PLAN`, `TOOL_CALL` observations. - 4. **Tool Execution:** If tool calls exist, passes them to [`ToolSystem.executeTools()`](Docs/API/interfaces/ToolSystem.md). Records `TOOL_EXECUTION` observations. - 5. **Synthesis Prompt Construction & LLM Call:** Constructs [`ArtStandardPrompt`](Docs/API/type-aliases/ArtStandardPrompt.md) for synthesis (including tool results), calls [`ReasoningEngine.call()`](Docs/API/interfaces/ReasoningEngine.md), consumes [`StreamEvent`](Docs/API/interfaces/StreamEvent.md)s to form the final response. Records `SYNTHESIS` observations. - 6. **Finalization:** Saves final AI message to history, updates state (based on `StateSavingStrategy`), records `FINAL_RESPONSE` observation, and returns [`AgentFinalResponse`](Docs/API/interfaces/AgentFinalResponse.md). - -### 4.2. Reasoning System - -- **Role:** Handles all aspects of interaction with Large Language Models (LLMs). -- **Components:** - - [`ReasoningEngine`](Docs/API/interfaces/ReasoningEngine.md): - - **Interface:** [`ReasoningEngine`](Docs/API/interfaces/ReasoningEngine.md) - - **Method:** `call(prompt: ArtStandardPrompt, options: CallOptions): Promise>` - - Delegates LLM calls to `ProviderAdapter`s via `ProviderManager`. Ensures adapter release. - - [`ProviderManager`](Docs/components/providers/provider-manager.md): - - **Interface:** [`IProviderManager`](Docs/API/interfaces/IProviderManager.md) - - **Responsibilities:** Centralized adapter access, lifecycle management (creation, caching, eviction), configuration handling (`ProviderManagerConfig`, `RuntimeProviderConfig`), and constraint enforcement (concurrency limits, local provider singletons). - - **Key Method:** `getAdapter(config: RuntimeProviderConfig): Promise` - - [`ProviderAdapter`](Docs/API/interfaces/ProviderAdapter.md)s: - - **Interface:** [`ProviderAdapter`](Docs/API/interfaces/ProviderAdapter.md) (extends `ReasoningEngine`) - - **Responsibilities:** - - `providerName: string` (readonly): Unique identifier. - - `call(prompt: ArtStandardPrompt, options: CallOptions): Promise>`: Translates `ArtStandardPrompt` to provider-specific API requests, makes API calls, and converts responses into `StreamEvent`s. - - `shutdown?(): Promise`: Optional method for graceful cleanup. - - **Built-in Adapters:** - - [`AnthropicAdapter`](Docs/API/classes/AnthropicAdapter.md): For Claude models. Handles message merging, tool definitions, and results. - - [`DeepSeekAdapter`](Docs/API/classes/DeepSeekAdapter.md): For DeepSeek models (OpenAI-compatible API). Streaming not yet implemented. - - [`GeminiAdapter`](Docs/API/classes/GeminiAdapter.md): For Google's Gemini models. System prompt prepended to first user message. - - [`OllamaAdapter`](Docs/API/classes/OllamaAdapter.md): For locally hosted models via Ollama's OpenAI-compatible API. Supports R1-style merging for specific models. - - [`OpenAIAdapter`](Docs/API/classes/OpenAIAdapter.md): For OpenAI's GPT models. Uses raw `fetch` (as of v0.2.7). - - [`OpenRouterAdapter`](Docs/API/classes/OpenRouterAdapter.md): For various models via OpenRouter.ai (OpenAI-compatible API). Streaming not yet implemented. - - [`PromptManager`](Docs/API/interfaces/PromptManager.md): - - **Interface:** [`PromptManager`](Docs/API/interfaces/PromptManager.md) - - **Methods:** - - `getFragment(name: string, context?: Record): string`: Retrieves reusable, named prompt fragments with optional variable substitution. - - `validatePrompt(prompt: ArtStandardPrompt): ArtStandardPrompt`: Validates a constructed `ArtStandardPrompt` against its Zod schema. - - [`OutputParser`](Docs/API/interfaces/OutputParser.md): - - **Interface:** [`OutputParser`](Docs/API/interfaces/OutputParser.md) - - **Methods:** - - `parsePlanningOutput(output: string): Promise<{ intent?: string; plan?: string; toolCalls?: ParsedToolCall[]; thoughts?: string; }>`: Extracts structured information (intent, plan, tool calls) and content from `` tags from LLM planning output. - - `parseSynthesisOutput(output: string): Promise`: Cleans up raw synthesis output (primarily trims whitespace). - -### 4.3. Tool System - -- **Role:** Enables the agent to use external capabilities or "tools." -- **Components:** - - [`IToolExecutor`](Docs/API/interfaces/IToolExecutor.md): - - **Interface:** [`IToolExecutor`](Docs/API/interfaces/IToolExecutor.md) - - **Properties:** `schema: ToolSchema` (readonly) - - **Method:** `execute(input: any, context: ExecutionContext): Promise`: Contains the tool's actual logic. - - [`ToolSchema`](Docs/API/interfaces/ToolSchema.md): - - **Interface:** [`ToolSchema`](Docs/API/interfaces/ToolSchema.md) - - Defines tool metadata: `name`, `description`, `inputSchema` (JSON Schema), `outputSchema?`, `examples?`. - - [`ToolRegistry`](Docs/API/interfaces/ToolRegistry.md): - - **Interface:** [`ToolRegistry`](Docs/API/interfaces/ToolRegistry.md) - - **Methods:** `registerTool(executor: IToolExecutor)`, `getToolExecutor(toolName: string)`, `getAvailableTools(filter?: { enabledForThreadId?: string })`. - - Manages registration and retrieval of `IToolExecutor` instances. Can filter tools based on `ThreadConfig.enabledTools`. - - [`ToolSystem`](Docs/API/interfaces/ToolSystem.md): - - **Interface:** [`ToolSystem`](Docs/API/interfaces/ToolSystem.md) - - **Method:** `executeTools(toolCalls: ParsedToolCall[], threadId: string, traceId?: string): Promise` - - Orchestrates tool execution: verifies enablement, retrieves executor, validates inputs using `validateJsonSchema`, executes tool, and records `TOOL_EXECUTION` observations. -- **Built-in Tool:** [`CalculatorTool`](Docs/API/classes/CalculatorTool.md): Safely evaluates mathematical expressions, supports `ans` variable for chained calculations. - -### 4.4. Context System - -- **Role:** Manages all contextual information necessary for the agent's operation within a conversation thread. -- **Components:** - - [`StateManager`](Docs/API/interfaces/StateManager.md): - - **Interface:** [`StateManager`](Docs/API/interfaces/StateManager.md) - - **Methods:** `loadThreadContext(threadId, userId?)`, `isToolEnabled(threadId, toolName)`, `getThreadConfigValue(threadId, key)`, `saveStateIfModified(threadId)`, `setAgentState(threadId, state)`, `setThreadConfig(threadId, config)`. - - Manages [`ThreadConfig`](Docs/API/interfaces/ThreadConfig.md) and [`AgentState`](Docs/API/interfaces/AgentState.md). Its behavior is influenced by `StateSavingStrategy`. - - [`ConversationManager`](Docs/API/interfaces/ConversationManager.md): - - **Interface:** [`ConversationManager`](Docs/API/interfaces/ConversationManager.md) - - **Methods:** `addMessages(threadId, messages)`, `getMessages(threadId, options?)`. - - Manages the history of [`ConversationMessage`](Docs/API/interfaces/ConversationMessage.md)s. Notifies `ConversationSocket` on new messages. - - `ContextProvider`: - - **Source:** `src/systems/context/ContextProvider.ts` - - **Role:** Placeholder for future Retrieval-Augmented Generation (RAG) capabilities. Currently returns empty context. - - Repositories: - - [`IStateRepository`](Docs/API/interfaces/IStateRepository.md): For `ThreadContext` (config and state). - - [`IConversationRepository`](Docs/API/interfaces/IConversationRepository.md): For `ConversationMessage`s. - - [`IObservationRepository`](Docs/API/interfaces/IObservationRepository.md): For `Observation`s. - - These interfaces are implemented by `StateRepository`, `ConversationRepository`, and `ObservationRepository` respectively, which use a `StorageAdapter`. - -### 4.5. Observation System - -- **Role:** Provides observability into the agent's internal workings by recording significant events. -- **Components:** - - [`ObservationManager`](Docs/API/interfaces/ObservationManager.md): - - **Interface:** [`ObservationManager`](Docs/API/interfaces/ObservationManager.md) - - **Methods:** `record(observationData)`, `getObservations(threadId, filter?)`. - - Central service for creating, persisting, and broadcasting [`Observation`](Docs/API/interfaces/Observation.md) records. Automatically generates ID, timestamp, and title. - - [`Observation`](Docs/API/interfaces/Observation.md): - - **Interface:** [`Observation`](Docs/API/interfaces/Observation.md) - - Defines the structure of a single observation record: `id`, `threadId`, `traceId?`, `timestamp`, `type`, `title`, `content`, `metadata?`. - - [`ObservationType`](Docs/API/enumerations/ObservationType.md): - - **Enum:** [`ObservationType`](Docs/API/enumerations/ObservationType.md) - - Categorizes events: `INTENT`, `PLAN`, `THOUGHTS`, `TOOL_CALL`, `TOOL_EXECUTION`, `SYNTHESIS`, `ERROR`, `FINAL_RESPONSE`, `STATE_UPDATE`, `LLM_STREAM_START/METADATA/ERROR/END`. - -### 4.6. Storage System - -- **Role:** Provides a generic persistence layer for all framework data. -- **Components:** - - [`StorageAdapter`](Docs/API/interfaces/StorageAdapter.md): - - **Interface:** [`StorageAdapter`](Docs/API/interfaces/StorageAdapter.md) - - **Methods:** `init?`, `get`, `set`, `delete`, `query`, `clearCollection?`, `clearAll?`. - - Abstracts data storage operations. - - Concrete Adapters: - - [`InMemoryStorageAdapter`](Docs/API/classes/InMemoryStorageAdapter.md): Stores data in JavaScript Maps in memory. Non-persistent. Ideal for testing/demos. - - [`IndexedDBStorageAdapter`](Docs/API/classes/IndexedDBStorageAdapter.md): Uses browser's IndexedDB for persistent client-side storage. Suitable for web applications. - -### 4.7. UI System - -- **Role:** Facilitates real-time communication from the agent's backend to user interfaces or other subscribed services. -- **Components:** - - [`UISystem`](Docs/API/interfaces/UISystem.md): - - **Interface:** [`UISystem`](Docs/API/interfaces/UISystem.md) - - **Methods:** `getObservationSocket()`, `getConversationSocket()`, `getLLMStreamSocket()`. - - Central service providing access to specialized sockets. - - [`TypedSocket`](Docs/API/classes/TypedSocket.md): - - **Class:** [`TypedSocket`](Docs/API/classes/TypedSocket.md) - - Generic base class for publish/subscribe with filtering. - - **Methods:** `subscribe(callback, filter?, options?)`, `notify(data, options?, filterCheck?)`, `clearAllSubscriptions()`, `getHistory?()`. - - Specialized Sockets (extend `TypedSocket`): - - [`ConversationSocket`](Docs/components/systems/ui/conversation-socket.md): For broadcasting new [`ConversationMessage`](Docs/API/interfaces/ConversationMessage.md) objects. - - [`LLMStreamSocket`](Docs/API/classes/LLMStreamSocket.md): For broadcasting [`StreamEvent`](Docs/API/interfaces/StreamEvent.md) objects from LLM calls. - - [`ObservationSocket`](Docs/components/systems/ui/observation-socket.md): For broadcasting [`Observation`](Docs/API/interfaces/Observation.md) objects. - -## 5. Key Concepts in Detail - -### 5.1. `ArtInstanceConfig` - -- **Interface:** [`ArtInstanceConfig`](Docs/API/interfaces/ArtInstanceConfig.md) -- The single configuration object passed to [`createArtInstance`](Docs/API/functions/createArtInstance.md) to initialize the entire framework. -- **Properties:** - - `storage`: Defines the storage adapter (e.g., `{ type: 'memory' }` or `{ type: 'indexedDB', dbName: 'MyDb' }`). - - `providers`: [`ProviderManagerConfig`](Docs/API/interfaces/ProviderManagerConfig.md) for LLM providers. - - `agentCore?`: Custom [`IAgentCore`](Docs/API/interfaces/IAgentCore.md) implementation class (defaults to `PESAgent`). - - `tools?`: Array of [`IToolExecutor`](Docs/API/interfaces/IToolExecutor.md) instances to register. - - `stateSavingStrategy?`: [`StateSavingStrategy`](Docs/API/type-aliases/StateSavingStrategy.md) (`'explicit'` or `'implicit'`). - - `logger?`: `{ level?: LogLevel }` for logging verbosity. - - `defaultSystemPrompt?`: Instance-level custom system prompt. - -### 5.2. `ArtStandardPrompt` and `ArtStandardMessage` - -- **`ArtStandardPrompt`**: [`ArtStandardMessage`](Docs/API/interfaces/ArtStandardMessage.md)[] (Type Alias: [`ArtStandardPrompt`](Docs/API/type-aliases/ArtStandardPrompt.md)). The universal, provider-agnostic format for LLM prompts. -- **`ArtStandardMessage`**: - - **Interface:** [`ArtStandardMessage`](Docs/API/interfaces/ArtStandardMessage.md) - - Represents a single message in the prompt. - - **Properties:** - - `role`: [`ArtStandardMessageRole`](Docs/API/type-aliases/ArtStandardMessageRole.md) (Type Alias: `system`, `user`, `assistant`, `tool_request`, `tool_result`, `tool`). - - `content`: `string | object | null` (depends on role). - - `name?`: For `tool_result`, the tool name. - - `tool_calls?`: Array of objects detailing tools the `assistant` wants to call. - - `tool_call_id?`: For `tool_result`, links to the `tool_calls` ID. -- **Purpose:** Abstract away provider-specific prompt formats, simplify agent logic, and ensure consistency. - -### 5.3. Streaming and `StreamEvent`s - -- **`StreamEvent`**: - - **Interface:** [`StreamEvent`](Docs/API/interfaces/StreamEvent.md) - - Standardized event emitted from LLM streams. - - **Properties:** - - `type`: `'TOKEN'`, `'METADATA'`, `'ERROR'`, `'END'`. - - `data`: Content depends on `type`. - - `tokenType?`: More specific classification for `TOKEN` events (e.g., `LLM_THINKING`, `LLM_RESPONSE`, `AGENT_THOUGHT_LLM_RESPONSE`). - - `threadId`, `traceId`, `sessionId?`. -- **Benefits:** Real-time feedback, improved perceived performance, handling intermediate thoughts. -- **UI Integration:** [`LLMStreamSocket`](Docs/API/classes/LLMStreamSocket.md) broadcasts these events for real-time UI updates. - -### 5.4. System Prompt Hierarchy and Customization - -- The final system prompt is constructed by combining an **Agent Base Prompt** (internal to the agent, e.g., `PESAgent.defaultSystemPrompt`) with a **Custom Prompt Part**. -- **Precedence (highest to lowest):** - 1. **Call-Level:** `AgentProps.options.systemPrompt` (for a single `process()` call). - 2. **Thread-Level:** `ThreadConfig.systemPrompt` (for an entire conversation thread). - 3. **Instance-Level:** `ArtInstanceConfig.defaultSystemPrompt` (default for the ART instance). -- **Concatenation:** `Agent Base Prompt + "\n\n" + Resolved Custom Prompt Part`. - -### 5.5. State Management (`StateSavingStrategy`) - -- **`StateSavingStrategy`**: Type Alias: [`StateSavingStrategy`](Docs/API/type-aliases/StateSavingStrategy.md) (`"explicit"` | `"implicit"`). -- Configured in `ArtInstanceConfig`. -- **`'explicit'` (Default):** `AgentState` is only saved when `StateManager.setAgentState()` is explicitly called by agent logic. `StateManager.saveStateIfModified()` is a no-op for `AgentState`. -- **`'implicit'`:** `StateManager.loadThreadContext()` caches the state. If `AgentState` is modified, `StateManager.saveStateIfModified()` (called by `PESAgent` at end of cycle) automatically persists changes by comparing snapshots. Explicit `setAgentState()` still works. - -## 6. Getting Started - -### 6.1. Installation - -- **Prerequisites:** Node.js (LTS version), npm or yarn. -- **Command:** `npm install art-framework` or `yarn add art-framework`. - -### 6.2. Project Setup Recommendations - -- **Directory Structure:** Organize code logically (e.g., `src/agents/`, `src/tools/`, `src/config/art-config.ts`, `src/main.ts`). -- **Centralized `ArtInstanceConfig`:** Define your main configuration in a dedicated file (e.g., `src/config/art-config.ts`). -- **Secure API Key Management:** - - **NEVER hardcode API keys.** - - Use environment variables (`process.env.YOUR_API_KEY`) for local development (with `.env` files). - - Use dedicated secrets management services (AWS Secrets Manager, Google Cloud Secret Manager) for production. - - For client-side apps, proxy LLM calls through a secure backend server. -- **TypeScript Configuration (`tsconfig.json`):** Essential for type checking and compilation. - -### 6.3. Quick Start: "Hello, Agent!" - -- **Steps:** - 1. Import `createArtInstance`, `ArtInstanceConfig`, `AgentProps`, `LogLevel`, and a `ProviderAdapter` (e.g., `OpenAIAdapter` or a mock). - 2. Define `ArtInstanceConfig` with `storage` (e.g., `{ type: 'memory' }`) and `providers`. - 3. Call `createArtInstance(artConfig)`. - 4. Call `art.process(agentProps)` with a `query`, `threadId`, and `options.providerConfig` (specifying `providerName`, `modelId`, `adapterOptions` like `apiKey`). -- **Example:** [`Docs/getting-started/quick-start.md`](Docs/getting-started/quick-start.md) - -## 7. How-To Guides (Detailed) - -### 7.1. Configure an ART Instance ([`Docs/how-to/configure-art-instance.md`](Docs/how-to/configure-art-instance.md)) - -- **Scenarios:** - - **Simple In-Memory Agent:** Uses `InMemoryStorageAdapter` for testing/demos. - - **Persistent Web Agent:** Uses `IndexedDBStorageAdapter` for browser persistence and multiple LLM options. - - **Custom Agent Core:** Demonstrates specifying a custom `IAgentCore` implementation and explicit state saving. -- **Key Configuration Points:** `storage` (`'memory'` or `'indexedDB'`), `providers.availableProviders` (defining `name`, `adapter`, `isLocal`), `RuntimeProviderConfig` (in `AgentProps.options` for `providerName`, `modelId`, `adapterOptions`), `tools`, `stateSavingStrategy`, `logger.level`. - -### 7.2. Configure System Prompts ([`Docs/how-to/configure-system-prompts.md`](Docs/how/configure-system-prompts.md)) - -- Explains how to set custom system prompts at instance, thread, and call levels, leveraging the hierarchy. -- **Mechanism:** - - Instance-level: `ArtInstanceConfig.defaultSystemPrompt`. - - Thread-level: `ThreadConfig.systemPrompt` (set via `StateManager.setThreadConfig()`). - - Call-level: `AgentProps.options.systemPrompt` (passed to `art.process()`). -- The agent's base prompt is always included, and the highest precedence custom part is appended. - -### 7.3. Create a Custom Agent Core ([`Docs/how-to/create-custom-agent.md`](Docs/how-to/create-custom-agent.md)) - -- Guide to implementing the [`IAgentCore`](Docs/API/interfaces/IAgentCore.md) interface for custom orchestration logic. -- **Steps:** - 1. Understand `IAgentCore`'s `process` method signature. - 2. Define your agent's custom reasoning pattern (e.g., ReAct, specialized task flow). - 3. Create a class implementing `IAgentCore`, accepting necessary ART subsystem dependencies in its constructor (e.g., `StateManager`, `ReasoningEngine`). - 4. Implement the `process` method, handling context loading, prompt construction, LLM interaction, tool usage, state saving, and observation recording. - 5. Configure `ArtInstanceConfig.agentCore` to use your custom agent class. - -### 7.4. Define and Use Tools ([`Docs/how-to/define-tools.md`](Docs/how-to/define-tools.md)) - -- Guide to extending agent capabilities with custom tools. -- **Steps:** - 1. Understand [`IToolExecutor`](Docs/API/interfaces/IToolExecutor.md) and [`ToolSchema`](Docs/API/interfaces/ToolSchema.md). - 2. Create a custom tool class implementing `IToolExecutor`. - 3. Implement the `schema` property: define `name`, `description`, `inputSchema` (JSON Schema), `outputSchema?`, `examples?`. - 4. Implement the `async execute(input, context)` method: contains tool's logic, returns `ToolResult` (`status`, `output`/`error`). - 5. Register the tool: Add an instance to `ArtInstanceConfig.tools`. - 6. (Optional) Enable the tool for specific threads via `ThreadConfig.enabledTools`. - 7. Ensure agent's planning prompt informs LLM about the tool. - -### 7.5. Handle Streaming Events in a UI ([`Docs/how-to/handle-streaming-ui.md`](Docs/how-to/handle-streaming-ui.md)) - -- Conceptual guide for client-side UI integration with ART's UI Sockets for real-time updates. -- **Key Sockets:** - - [`LLMStreamSocket`](Docs/API/classes/LLMStreamSocket.md): For `StreamEvent`s (token-by-token LLM responses). - - [`ObservationSocket`](Docs/components/systems/ui/observation-socket.md): For `Observation` objects (agent's thought process, tool usage). - - [`ConversationSocket`](Docs/components/systems/ui/conversation-socket.md): For new `ConversationMessage`s (chat history). -- **Usage:** Obtain socket instances from `artInstance.uiSystem`, then use their `subscribe()` methods with callbacks and optional filters (`threadId`, event types). - -### 7.6. Manage Agent State (`StateSavingStrategy`) ([`Docs/how-to/manage-agent-state.md`](Docs/how-to/manage-agent-state.md)) - -- Explains how `AgentState` persistence is controlled by `StateSavingStrategy` in `ArtInstanceConfig`. -- **`'explicit'` (Default):** Requires manual calls to `StateManager.setAgentState()` to save state. -- **`'implicit'`:** Automatically saves modified `AgentState` when `StateManager.saveStateIfModified()` is called (e.g., by `PESAgent` at end of cycle) by comparing snapshots. - -### 7.7. Manage Multiple LLM Providers ([`Docs/how-to/manage-multiple-llms.md`](Docs/how-to/manage-multiple-llms.md)) - -- Guide to configuring and using multiple LLM providers simultaneously. -- **Steps:** - 1. Configure `ProviderManagerConfig.availableProviders` in `ArtInstanceConfig`, defining unique names, adapter classes, and `isLocal` flag for each provider setup. - 2. Select a provider at runtime using `AgentProps.options.providerConfig` (specifying `providerName`, `modelId`, and `adapterOptions` like `apiKey`). - 3. (Optional) Set a thread-level default provider in `ThreadConfig.providerConfig`. - -### 7.8. Use the `ans` Variable in `CalculatorTool` ([`Docs/how-to/use-calculator-ans.md`](Docs/how-to/use-calculator-ans.md)) - -- Explains how the built-in [`CalculatorTool`](Docs/API/classes/CalculatorTool.md) remembers the result of the last calculation within the same conversation thread as `ans`, enabling multi-step calculations. -- `ans` is thread-scoped and overwritten by each successful calculation. - -### 7.9. Leverage `` Tags for Agent Observability ([`Docs/how-to/leverage-think-tags.md`](Docs/how-to/leverage-think-tags.md)) - -- How to instruct LLMs to output reasoning within `...` XML-like tags. -- The [`OutputParser`](Docs/API/interfaces/OutputParser.md) extracts this content into a `thoughts` field, providing deeper insights into the LLM's reasoning for debugging and transparency. - -### 7.10. Use Prompt Fragments with `PromptManager` ([`Docs/how-to/use-prompt-fragments.md`](Docs/how-to/use-prompt-fragments.md)) - -- Explains how `PromptManager.getFragment()` provides reusable, named text pieces (fragments) with optional variable substitution. -- These fragments can be embedded into the `content` of `ArtStandardMessage` objects during prompt construction by agent logic, promoting consistency and reducing redundancy. -- `PromptManager.validatePrompt()` can be used to validate the assembled `ArtStandardPrompt`. - -## 8. Examples (Detailed) - -### 8.1. Basic Chatbot ([`Docs/examples/basic-chatbot.md`](Docs/examples/basic-chatbot.md)) - -- Demonstrates minimal setup for a simple conversational agent. -- Uses `InMemoryStorageAdapter` (non-persistent history) and can be configured with a mock or real LLM adapter. -- Illustrates `ArtInstanceConfig`, `createArtInstance`, `AgentProps`, and basic `art.process()` interaction. - -### 8.2. Agent with Tools ([`Docs/examples/agent-with-tools.md`](Docs/examples/agent-with-tools.md)) - -- Shows how to integrate and use tools (e.g., built-in [`CalculatorTool`](Docs/API/classes/CalculatorTool.md)) with `PESAgent`. -- **Key Concepts:** Tool registration in `ArtInstanceConfig.tools`, LLM prompting for tools, tool call detection by `OutputParser`, tool execution by `ToolSystem`, `ToolResult` handling, and synthesis with tool results. - -### 8.3. Multi-Provider Agent ([`Docs/examples/multi-provider-agent.md`](Docs/examples/multi-provider-agent.md)) - -- Demonstrates configuring and dynamically using multiple LLM providers (e.g., OpenAI, Anthropic, Ollama) at runtime. -- Highlights `ArtInstanceConfig.providers.availableProviders` and `AgentProps.options.providerConfig` for dynamic selection. - -### 8.4. Persistent Agent (using IndexedDB) ([`Docs/examples/persistent-agent.md`](Docs/examples/persistent-agent.md)) - -- Shows how to configure an ART agent to use `IndexedDBStorageAdapter` for persisting conversation history and agent state across browser sessions. -- Intended for browser environments. Demonstrates loading and saving history. - -## 9. Advanced Topics - -### 9.1. Debugging ART Applications ([`Docs/advanced/debugging-art-applications.md`](Docs/advanced/debugging-art-applications.md)) - -- **Strategies:** - - **`Logger`:** Set `LogLevel.DEBUG` for detailed internal logs. - - **`ObservationSystem`:** Subscribe to `ObservationSocket` or query `ObservationManager.getObservations()` to inspect agent's audit trail (`INTENT`, `PLAN`, `TOOL_EXECUTION`, `ERROR`). - - **Stored Data:** Inspect `IndexedDB` (browser dev tools) for `conversations`, `observations`, `state`. - - **LLM Prompts/Responses:** Log full `ArtStandardPrompt` before sending, and raw LLM output after receiving. Isolate LLM calls for testing. - - **Tool Debugging:** Validate `ToolSchema`, log inside `execute()`, test tools in isolation. - - **TypeScript & Static Analysis:** Leverage type checking and linters. - - **Step-Through Debugging:** Use breakpoints in agent logic, parsers, tool system, and adapters. - -### 9.2. Performance Tuning ([`Docs/advanced/performance-tuning.md`](Docs/advanced/performance-tuning.md)) - -- **LLM Interaction:** Model selection (latency vs. capability), always enable streaming for UX, concise/clear prompts, `max_tokens` limits, `ProviderManager` tuning (`maxParallelApiInstancesPerProvider`, `apiInstanceIdleTimeoutSeconds`). -- **Storage Adapter:** Choose appropriate adapter (`InMemory` for speed, `IndexedDB` for browser persistence). Optimize `query()` for large datasets (e.g., using IndexedDB indexes). -- **Agent Logic:** Minimize LLM calls, efficient context gathering (`historyLimit`), efficient tool execution, consider `StateSavingStrategy` overhead. -- **Asynchronous Operations:** Ensure proper `async/await` usage to avoid blocking. -- **Caching:** Implement application-level caching for tool results or frequently accessed data. -- **Observability & Profiling:** Use `LogLevel.DEBUG` and profiling tools. -- **Client-Side UI:** Efficiently render streamed tokens, debounce/throttle UI updates. - -### 9.3. Security Considerations ([`Docs/advanced/security-considerations.md`](Docs/advanced/security-considerations.md)) - -- **API Key Management:** Never hardcode. Use environment variables, secrets management services, or backend proxies. -- **Tool Security:** Strict `inputSchema` validation, principle of least privilege, sandboxing for code execution, output sanitization, `ThreadConfig.enabledTools` for access control. -- **LLM Prompt Injection:** Clear system prompts, input filtering (limited), robust output parsing/validation, defense in depth, use models with built-in defenses. -- **Data Privacy & Storage:** Be mindful of sensitive data in conversation history, agent state, and observations. Secure storage (encryption, access controls), retention policies, user data rights. -- **UI Socket Communication:** Secure channels (WSS/HTTPS), authentication/authorization for subscriptions, input validation for control messages. -- **Denial of Service (DoS) / Resource Exhaustion:** Implement rate limiting, quotas for LLM calls and tool execution, manage storage growth. -- **Third-Party Dependencies:** Keep updated, audit for vulnerabilities. -- **Secure Development Practices:** Follow secure coding, regular reviews, threat modeling. - -### 9.4. Understanding `ProviderManagerImpl` Internals ([`Docs/advanced/understanding-provider-manager.md`](Docs/advanced/understanding-provider-manager.md)) - -- Deep dive into the internal mechanisms of `ProviderManager`: - - **Configuration Signature:** Unique identifier for adapter configurations. - - **Managed Instances:** Internal map storing active/idle adapter instances. - - **Request Queue:** Holds requests when concurrency limits are reached. -- **Lifecycle:** Detailed explanation of adapter request, release, and eviction processes, including local provider constraints and API concurrency limits. -- **Trade-offs:** Discusses design choices like caching by signature and release responsibility. - -## 10. API Reference (Comprehensive) - -The ART Framework provides a rich API, documented in detail under the `Docs/API/` directory. - -### 10.1. Enumerations - -- [`ErrorCode`](Docs/API/enumerations/ErrorCode.md): Standardized error codes for framework issues. -- [`LogLevel`](Docs/API/enumerations/LogLevel.md): Severity levels for the `Logger`. -- [`MessageRole`](Docs/API/enumerations/MessageRole.md): Role of a message sender in a conversation (`AI`, `SYSTEM`, `TOOL`, `USER`). -- [`ModelCapability`](Docs/API/enumerations/ModelCapability.md): Capabilities a model might possess (`TEXT`, `VISION`, `STREAMING`, `TOOL_USE`, `RAG`, `CODE`, `REASONING`). -- [`ObservationType`](Docs/API/enumerations/ObservationType.md): Types of events recorded during agent execution (`INTENT`, `PLAN`, `THOUGHTS`, `TOOL_CALL`, `TOOL_EXECUTION`, `SYNTHESIS`, `ERROR`, `FINAL_RESPONSE`, `STATE_UPDATE`, `LLM_STREAM_START/METADATA/ERROR/END`). - -### 10.2. Classes - -- **Error Classes (extend `ARTError`):** - - [`AdapterInstantiationError`](Docs/API/classes/AdapterInstantiationError.md) - - [`ApiQueueTimeoutError`](Docs/API/classes/ApiQueueTimeoutError.md) - - [`ARTError`](Docs/API/classes/ARTError.md) (Base custom error class) - - [`LocalInstanceBusyError`](Docs/API/classes/LocalInstanceBusyError.md) - - [`LocalProviderConflictError`](Docs/API/classes/LocalProviderConflictError.md) - - [`UnknownProviderError`](Docs/API/classes/UnknownProviderError.md) -- **Adapters:** - - [`AnthropicAdapter`](Docs/API/classes/AnthropicAdapter.md) - - [`DeepSeekAdapter`](Docs/API/classes/DeepSeekAdapter.md) - - [`GeminiAdapter`](Docs/API/classes/GeminiAdapter.md) - - [`IndexedDBStorageAdapter`](Docs/API/classes/IndexedDBStorageAdapter.md) - - [`InMemoryStorageAdapter`](Docs/API/classes/InMemoryStorageAdapter.md) - - [`OllamaAdapter`](Docs/API/classes/OllamaAdapter.md) - - [`OpenAIAdapter`](Docs/API/classes/OpenAIAdapter.md) - - [`OpenRouterAdapter`](Docs/API/classes/OpenRouterAdapter.md) -- **Core Components:** - - [`CalculatorTool`](Docs/API/classes/CalculatorTool.md) - - [`LLMStreamSocket`](Docs/API/classes/LLMStreamSocket.md) - - [`Logger`](Docs/API/classes/Logger.md) - - [`PESAgent`](Docs/API/classes/PESAgent.md) - - [`TypedSocket`](Docs/API/classes/TypedSocket.md) - - [`XmlMatcher`](Docs/API/classes/XmlMatcher.md) -- **Other:** - - `AgentFactory` (internal, used by `createArtInstance`) - -### 10.3. Interfaces - -- **Agent Core & Execution:** - - [`AgentFinalResponse`](Docs/API/interfaces/AgentFinalResponse.md) - - `AgentOptions` - - [`AgentProps`](Docs/API/interfaces/AgentProps.md) - - [`AgentState`](Docs/API/interfaces/AgentState.md) - - [`ArtInstance`](Docs/API/interfaces/ArtInstance.md) - - [`ArtInstanceConfig`](Docs/API/interfaces/ArtInstanceConfig.md) - - [`ExecutionContext`](Docs/API/interfaces/ExecutionContext.md) - - [`ExecutionMetadata`](Docs/API/interfaces/ExecutionMetadata.md) - - [`IAgentCore`](Docs/API/interfaces/IAgentCore.md) -- **Messaging & Conversation:** - - [`ArtStandardMessage`](Docs/API/interfaces/ArtStandardMessage.md) - - [`ConversationManager`](Docs/API/interfaces/ConversationManager.md) - - [`ConversationMessage`](Docs/API/interfaces/ConversationMessage.md) - - `ConversationSocket` - - [`IConversationRepository`](Docs/API/interfaces/IConversationRepository.md) - - `MessageOptions` -- **LLM & Reasoning:** - - `AvailableProviderEntry` - - `CallOptions` - - `IProviderManager` - - `LLMMetadata` - - `ManagedAdapterAccessor` - - `OllamaAdapterOptions` - - [`OutputParser`](Docs/API/interfaces/OutputParser.md) - - [`ParsedToolCall`](Docs/API/interfaces/ParsedToolCall.md) - - `PromptContext` - - [`PromptManager`](Docs/API/interfaces/PromptManager.md) - - [`ProviderAdapter`](Docs/API/interfaces/ProviderAdapter.md) - - [`ProviderManagerConfig`](Docs/API/interfaces/ProviderManagerConfig.md) - - [`ReasoningEngine`](Docs/API/interfaces/ReasoningEngine.md) - - [`RuntimeProviderConfig`](Docs/API/interfaces/RuntimeProviderConfig.md) - - [`StreamEvent`](Docs/API/interfaces/StreamEvent.md) -- **Tools:** - - [`IToolExecutor`](Docs/API/interfaces/IToolExecutor.md) - - [`ToolRegistry`](Docs/API/interfaces/ToolRegistry.md) - - [`ToolResult`](Docs/API/interfaces/ToolResult.md) - - [`ToolSchema`](Docs/API/interfaces/ToolSchema.md) - - [`ToolSystem`](Docs/API/interfaces/ToolSystem.md) -- **State & Storage:** - - `FilterOptions` - - `IStateRepository` - - `JsonObjectSchema` - - `IStateRepository` - - [`StateManager`](Docs/API/interfaces/StateManager.md) - - [`StorageAdapter`](Docs/API/interfaces/StorageAdapter.md) - - [`ThreadConfig`](Docs/API/interfaces/ThreadConfig.md) - - [`ThreadContext`](Docs/API/interfaces/ThreadContext.md) -- **Observability & UI:** - - `IObservationRepository` - - `ObservationFilter` - - [`ObservationManager`](Docs/API/interfaces/ObservationManager.md) - - `ObservationSocket` - - `ITypedSocket` - - [`UISystem`](Docs/API/interfaces/UISystem.md) - - `XmlMatcherChunk` - -### 10.4. Type Aliases - -- [`ArtStandardMessageRole`](Docs/API/type-aliases/ArtStandardMessageRole.md) -- [`ArtStandardPrompt`](Docs/API/type-aliases/ArtStandardPrompt.md) -- `FormattedPrompt` (Deprecated, use `ArtStandardPrompt`) -- [`JsonSchema`](Docs/API/type-aliases/JsonSchema.md) -- [`StateSavingStrategy`](Docs/API/type-aliases/StateSavingStrategy.md) -- `UnsubscribeFunction` (Function type for unsubscribing from sockets) - -### 10.5. Functions - -- [`createArtInstance`](Docs/API/functions/createArtInstance.md): High-level factory function to create and initialize an ART instance. -- [`generateUUID`](Docs/API/functions/generateUUID.md): Generates a unique Version 4 UUID. -- `validateJsonSchema`: Utility for validating objects against JSON Schema. -- `clearJsonSchemaValidatorCache`: Clears internal cache for JSON schema validator. - -### 10.6. Variables - -- [`ArtStandardMessageSchema`](Docs/API/variables/ArtStandardMessageSchema.md): Zod schema for validating `ArtStandardMessage`. -- [`ArtStandardPromptSchema`](Docs/API/variables/ArtStandardPromptSchema.md): Zod schema for validating `ArtStandardPrompt`. -- [`VERSION`](Docs/API/variables/VERSION.md): The current version of the ART Framework package. - -This comprehensive documentation aims to provide a deep understanding of the ART Framework, enabling developers to build, customize, and debug sophisticated AI agents effectively. \ No newline at end of file diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 39a47d3..a59bf45 --- a/README.md +++ b/README.md @@ -1,161 +1,172 @@ -# ✨ ART: Agent Runtime Framework Version 0.2.8 - -**ART is a powerful, modular, and browser-first JavaScript/TypeScript framework for building sophisticated LLM-powered intelligent agents capable of complex reasoning, planning, and tool usage.** - -It provides the building blocks for sophisticated agent systems that can run entirely client-side, emphasizing privacy, offline capability, and observability, while also supporting server integration. - -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) -[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) - -[![Sponsor on Patreon](https://img.shields.io/badge/Sponsor%20on-Patreon-F96854?logo=patreon&style=flat)](https://www.patreon.com/HashanWickramasinghe) - - -## Overview - -Existing agent frameworks often require server-side components, limiting their use in purely web-based applications where privacy or offline capabilities are crucial. ART addresses this by offering a comprehensive, standalone toolkit designed for the browser environment, leveraging WebAssembly (WASM) where feasible for local processing (LLMs, vector stores) and providing robust components for building production-ready agents. - -**Core Goals:** -* **Browser-First:** Enable complex agent logic directly in the user's browser. -* **Modularity:** Offer distinct, replaceable components (storage, providers, agent logic). -* **Observability:** Provide deep insights into the agent's internal workings. -* **Developer Experience:** Offer a layered approach, simple for basic use, powerful for advanced customization. - -**Target Audience:** Web developers (JavaScript/TypeScript) building applications requiring agentic capabilities (chatbots, assistants, automation tools) directly within the browser, ranging from simple integrations to complex, custom agent behaviors. - -## Key Features - -* **Browser-First Design:** Built to run fully in the browser, enabling privacy-preserving and offline-capable applications (when used with local models/WASM). -* **Modular Architecture:** Comprises specialized subsystems with clear boundaries, enabling mix-and-match capabilities and easy extension. (See Architecture below). -* **Decoupled Orchestration:** Agent reasoning patterns (like Plan-Execute-Synthesize) are decoupled from execution mechanics, allowing patterns to be swapped or customized. -* **Real-time Streaming:** Natively supports streaming LLM responses for interactive, real-time user experiences. -* **Flexible Prompt Management:** Advanced system using blueprints and dynamic context injection for fine-grained control over prompt construction. -* **Dynamic Provider Management:** Centralized `ProviderManager` allows runtime selection and configuration of multiple LLM providers (OpenAI, Anthropic, Gemini, DeepSeek, OpenRouter, local models via adapters). -* **Flexible State Management:** Pluggable `StorageAdapter` interface allows integration with various storage backends (IndexedDB, server APIs, custom solutions). -* **Rich Observability:** Detailed, typed `Observation` system provides transparent insights into agent operations for debugging, monitoring, and visualization. -* **Robust Tool Integration:** Schema-driven tool system (Schema-Registry-Executor) with validation and secure execution. -* **Flexible UI Integration:** Typed socket system (publish/subscribe) for reactive UI updates with fine-grained filtering. -* **Multiple Reasoning Patterns:** Supports Plan-Execute-Synthesize (PES) as default, with the ability to implement and integrate custom patterns like ReAct, Chain of Thought (CoT), etc. - -## Architecture: The 3 Nodes - -ART's architecture can be understood as three interconnected nodes: - -```mermaid -flowchart LR - A["Node 1: Developer Interface\n(Your Code & Config)"] -- Configures & Invokes --> B["Node 2: ART Core Orchestration\n(The Framework's Brain)"] - B -- Manages & Uses --> C["Node 3: External Dependencies & Interactions\n(LLMs, Tools, Storage)"] - C -- Provides Data/Services --> B - B -- Streams Results/Updates --> A -``` - -* **Node 1: Developer Interface (Your Code & Config):** This is where you interact with ART. You use `createArtInstance` to configure the framework, selecting your desired agent core (e.g., `PESAgent`), storage adapter, provider configurations, and tools. You then interact with the created `ArtInstance` (e.g., calling `art.process()`). -* **Node 2: ART Core Orchestration (The Framework's Brain):** This is the internal engine that manages the agent's execution flow based on your configuration. It handles state management (via `StateManager` & `ConversationManager`), interacts with LLMs (via `ProviderManager` & `ReasoningEngine`), manages prompt construction (`PromptManager`), executes tools (`ToolSystem`), logs events (`ObservationManager`), and broadcasts updates for the UI (`UISystem`). The selected `Agent Core` (e.g., `PESAgent`) dictates the high-level reasoning pattern used here. -* **Node 3: External Dependencies & Interactions (The Outside World):** This node represents the external services and logic ART connects to. This includes: - * **LLM Providers:** APIs (OpenAI, Anthropic, etc.) or local models accessed via specific `ProviderAdapter` implementations managed by the `ProviderManager`. - * **Tools:** Your custom tool logic, implemented according to the `IToolExecutor` interface and managed by the `ToolSystem`. - * **Storage:** Databases, browser storage (like IndexedDB), or remote APIs accessed via a `StorageAdapter`. - -*(For more details, see the [Comprehensive Developer Guide](link/to/ART-Guide.html) or the [Architecture Overview Section](link/to/ART-Guide.html#architecture))* - -## Installation - -```bash -npm install art-framework -# or -yarn add art-framework -``` - -## Quick Start - -This example demonstrates setting up a simple agent using the `PESAgent`, persisting history in `IndexedDB`, and configuring the `OpenAIAdapter` via the `ProviderManager`. - -```typescript -import { - createArtInstance, - PESAgent, // Default Agent Core - IndexedDBStorageAdapter, // Browser-persistent storage - OpenAIAdapter, // OpenAI Provider Adapter - ProviderManagerConfig, // Type for configuring providers - RuntimeProviderConfig, // Type for runtime provider settings - // Import any tools you want to use, e.g.: import { YourTool } from './your-tool'; -} from 'art-framework'; - -async function runSimpleAgent() { - // 1. Define Provider Configuration for the ProviderManager - const providerConfig: ProviderManagerConfig = { - availableProviders: [ - { - name: 'openai', // Unique name for this provider config - adapter: OpenAIAdapter, // The adapter class - // Default options for this adapter (can be overridden at runtime) - defaultOptions: { /* e.g., specific parameters if needed */ } - } - // Add other providers like GeminiAdapter, AnthropicAdapter here - // { name: 'gemini', adapter: GeminiAdapter } - ] - // Optional global settings like rate limits can be defined here - }; - - // 2. Configure and create the ART instance - const art = await createArtInstance({ - agentCore: PESAgent, // Use the Plan-Execute-Synthesize agent - storage: new IndexedDBStorageAdapter({ dbName: 'artQuickstartHistory' }), // Use IndexedDB for storage - providers: providerConfig, // Pass the provider manager config - // tools: [new YourTool()], // Register any tools here - }); - - // 3. Define a unique thread ID for the conversation - const threadId = 'quickstart-thread-' + Date.now(); - - // 4. Set the runtime provider configuration for this specific thread - // This tells ART which provider and model to use for this conversation. - const runtimeConfig: RuntimeProviderConfig = { - providerName: 'openai', // Use the 'openai' provider defined above - modelId: 'gpt-4o-mini', // Specify the desired model - adapterOptions: { // Pass API key securely (use env vars in production) - apiKey: 'YOUR_OPENAI_API_KEY' - } - }; - await art.stateManager.setThreadConfigValue(threadId, 'runtimeProviderConfig', runtimeConfig); - - console.log(`Starting agent process for thread: ${threadId}`); - - try { - // 5. Process a user query - // The agent core will automatically load the runtimeProviderConfig from the thread's state. - const result = await art.process({ - query: "What is the capital of France and what is its population?", - threadId: threadId, - // Optional: userId, sessionId, traceId for tracking - // Optional: configOverrides to temporarily change config for this call - }); - - // 6. Log the result - console.log("Agent Response Text:", result.responseText); // Direct access to the final text response - console.log("Full Result:", result); // Explore the full result object (metadata, observations, etc.) - - } catch (error) { - console.error("Agent processing failed:", error); - } -} - -runSimpleAgent(); -``` - -*(Note: Replace `'YOUR_OPENAI_API_KEY'` with your actual key, preferably loaded from environment variables in a real application. This example uses `IndexedDBStorageAdapter` for browser-based persistence and the new `ProviderManager` system.)* - -## Documentation - -* **[Comprehensive Developer Guide](link/to/ART-Guide.html):** The primary guide covering concepts, architecture, scenarios, and API usage. **(Start Here!)** -* **[Core Concepts](link/to/ART-Guide.html#core-concepts):** Understand fundamental ideas like Threads, Observations, Adapters, and Sockets within the main guide. -* **[Architecture Overview](link/to/ART-Guide.html#architecture):** Learn about the 3-node architecture and design principles in the main guide. -* **[Usage Scenarios / Tutorials](link/to/ART-Guide.html#scenarios):** Step-by-step examples for common tasks (Chatbot, Custom Tools, Custom Adapters). -* **[API Reference](Docs/API/):** (Coming Soon) Auto-generated API documentation. - -## Contributing - -Contributions are welcome! Please refer to the Contributing Guide (TODO: Create and Link Contributing.md) for details on how to submit issues, feature requests, and pull requests. - -## License - -ART Framework is released under the [MIT License](https://opensource.org/licenses/MIT). + + +# ✨ ART: Agentic Runtime Framework Version 0.3.7 + +

      + ART Framework Logo +

      + +**ART is a powerful, modular, and browser-first TypeScript framework for building sophisticated LLM-powered agents capable of complex reasoning, planning, and tool usage.** + +It provides the building blocks for creating robust agentic systems that can run entirely client-side, emphasizing user privacy, offline capability, and deep observability, while also supporting server-side deployments. + +[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) +[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com) + +[![Sponsor on Patreon](https://img.shields.io/badge/Sponsor%20on-Patreon-F96854?logo=patreon&style=flat)](https://www.patreon.com/HashanWickramasinghe) + +## Overview + +Existing agent frameworks often rely on server-side components, limiting their use in web applications where user privacy or offline functionality is critical. ART is engineered to address this gap by providing a comprehensive, standalone toolkit designed for the browser, while remaining powerful enough for server-side execution. + +**Core Goals:** +* **Browser-First:** Enable complex agent logic to run directly in the user's browser, enhancing privacy and reducing server costs. +* **Modularity:** Offer distinct, replaceable components for storage, reasoning, and tools. +* **Observability:** Provide deep, real-time insights into the agent's internal thought process. +* **Developer Experience:** Deliver a layered API that is simple for basic use cases yet powerful enough for advanced customization. + +## Key Features + +#### Reasoning & Orchestration +* **Swappable Agent Cores:** Start with the default Plan-Execute-Synthesize (`PESAgent`) pattern and seamlessly switch to or create custom reasoning patterns (e.g., ReAct, Chain of Thought). +* **Streaming-First:** Native support for streaming LLM responses, enabling real-time, interactive user experiences. +* **Dynamic Prompt Management:** A powerful system for constructing prompts from blueprints with dynamic context injection. +* **Agent Persona Customization:** Easily define your agent's identity and default system prompt through a simple configuration object. +* **Rich Observability:** A detailed, typed `Observation` system provides transparent insights into every step of an agent's operation for debugging, monitoring, and visualization. + +#### Connectivity & Data +* **Multi-Provider Support:** A centralized `ProviderManager` allows runtime selection and configuration of multiple LLM providers (OpenAI, Anthropic, Gemini, OpenRouter, and local models via Ollama). +* **Pluggable Storage:** A flexible `StorageAdapter` interface allows easy integration with any storage backend (default support for IndexedDB, InMemory, and Supabase). +* **Schema-Driven Tooling:** A robust tool integration system with automatic schema validation and secure execution. +* **Dynamic Tool Loading (MCP):** Support for the Model Context Protocol (MCP) enables agents to dynamically discover and use tools from compliant external servers. + +#### Developer Experience +* **Browser-First Design:** Built to run fully in the browser, enabling privacy-preserving and offline-capable applications. +* **Flexible UI Integration:** A typed, publish/subscribe socket system allows for reactive UI updates with fine-grained event filtering. +* **TypeScript-Native:** Engineered from the ground up with TypeScript for a robust, type-safe development experience. + +## Architecture: The 3 Nodes + +ART's architecture is best understood as three interconnected nodes: + +```mermaid +flowchart LR + A["Node 1: Developer Interface\n(Your Code & Config)"] -- Configures & Invokes --> B["Node 2: ART Core Orchestration\n(The Framework's Brain)"] + B -- Manages & Uses --> C["Node 3: External Dependencies & Interactions\n(LLMs, Tools, Storage)"] + C -- Provides Data/Services --> B + B -- Streams Results/Updates --> A +``` + +* **Node 1: Developer Interface (Your Code & Config):** This is your interaction point with ART. You use `createArtInstance` to configure the framework, selecting your storage, LLM providers, and tools. You then invoke the agent via the `art.process()` method. +* **Node 2: ART Core Orchestration (The Framework's Brain):** This is the internal engine that manages the agent's lifecycle. It orchestrates state, reasons with LLMs, constructs prompts, executes tools, and broadcasts updates to your UI. The selected `Agent Core` (e.g., `PESAgent`) dictates the high-level reasoning strategy used here. +* **Node 3: External Dependencies & Interactions (The Outside World):** This node represents the external services ART connects to. This includes LLM APIs (like OpenAI), your custom tool logic, and storage backends (like IndexedDB or a remote database). + +## Installation + +```bash +npm install art-framework +# or +pnpm install art-framework +# or +yarn add art-framework +``` + +## Quick Start + +This example demonstrates setting up a simple agent that uses OpenAI and runs in-memory. For a complete example with all configurations, see the [Comprehensive Developer Guide](./docs/README.md). + +```typescript +import { + createArtInstance, + ArtInstanceConfig, + ThreadConfig, + CalculatorTool, + OpenAIAdapter, + GeminiAdapter +} from 'art-framework'; + +// --- 1. Configure the ART Instance --- +// Note: No API keys or secrets are present here. + +const artConfig: ArtInstanceConfig = { + storage: { + type: 'indexedDB', + dbName: 'MyCorrectChatDB' + }, + providers: { + availableProviders: [ + { name: 'openai', adapter: OpenAIAdapter }, + { name: 'gemini', adapter: GeminiAdapter } + ] + }, + tools: [new CalculatorTool()], + persona: { + name: 'ConfigExpert', + prompts: { + synthesis: 'You explain configurations clearly.' + } + }, + logger: { level: 'info' } +}; + + +// --- 2. Main Application Logic --- + +async function initializeAndRun() { + // Create the ART instance with the high-level configuration. + const art = await createArtInstance(artConfig); + console.log('ART Instance Initialized.'); + + // --- 3. Set Up a New Conversation Thread --- + const threadId = 'user-123-session-1'; + + // Create the thread-specific configuration. + // THIS is where you specify the provider, model, and API key. + const threadConfig: ThreadConfig = { + providerConfig: { + providerName: 'openai', // Must match a name from availableProviders + modelId: 'gpt-4o', + adapterOptions: { + apiKey: 'sk-your-real-openai-api-key', // Securely provide your API key here + temperature: 0.7 + } + }, + // Other thread settings + enabledTools: ['CalculatorTool'], + historyLimit: 20 + }; + + // Save this configuration for the new thread. + // This step is crucial and must be done before the first `process` call. + await art.stateManager.setThreadConfig(threadId, threadConfig); + console.log(`ThreadConfig set for threadId: ${threadId}`); + + // Now the ART instance is ready to process requests for this thread. + console.log('Sending first message...'); + const response = await art.process({ + query: 'What is 2 + 2?', + threadId: threadId + }); + + console.log('Final response:', response.response.content); +} + +initializeAndRun().catch(console.error); +``` + +*(Note: Replace `'YOUR_OPENAI_API_KEY'` with your actual key. In a real application, load this from a secure source like environment variables or a secrets manager.)* + +## Documentation + +* **[Comprehensive Developer Guide](docs/README.md):** The primary guide covering concepts, architecture, and API usage. **(Start Here!)** +* **[How-To Guides](./docs/how-to):** Practical guides for specific tasks, such as [Customizing the Agent's Persona](./docs/how-to/customizing-agent-persona.md). +* **[API Reference](./docs/components):** Auto-generated API documentation. +* **[Examples](./examples):** Find practical examples, including a full React chatbot implementation. + +## Contributing + +Contributions are welcome! Please refer to the [Contributing Guide](./CONTRIBUTING.md) for details on how to submit issues, feature requests, and pull requests. + +## License + +ART Framework is released under the [MIT License](https://opensource.org/licenses/MIT). diff --git a/docs/art-framework-api-guide.md b/docs/art-framework-api-guide.md new file mode 100644 index 0000000..567a268 --- /dev/null +++ b/docs/art-framework-api-guide.md @@ -0,0 +1,452 @@ +# ART Framework Public API Guide + +Welcome to the ART (Agentic Reasoning & Tool-use) Framework! This guide provides a comprehensive overview of the public API surface, helping you understand how to use, configure, and extend the framework. + +The main entry point for the library is structured to provide a clear and intuitive experience for developers. For most common use cases, you'll only need `createArtInstance` and the associated configuration types. + +## 1. Core Factory + +This is the recommended starting point for all users. It simplifies setup by assembling all necessary components based on your configuration. + +### `createArtInstance` + +The main factory function to create and initialize a complete ART framework instance. + +- **Usage**: `createArtInstance(config: ArtInstanceConfig): Promise` +- **Description**: This function takes a configuration object and returns a fully initialized instance of the ART framework, ready to process requests. It handles the instantiation and wiring of all underlying systems like storage, reasoning providers, tools, and agents. +- **When to use**: Always use this function to create an ART instance. It ensures all components are set up correctly. +- **See also**: `ArtInstanceConfig` for all available configuration options. + +**Example:** +```ts +import { createArtInstance } from 'art-framework'; +import type { ArtInstanceConfig } from 'art-framework'; + +const config: ArtInstanceConfig = { + storage: { type: 'memory' }, + providers: { + openai: { adapter: 'openai', apiKey: '...' } + }, + tools: [new CalculatorTool()], + persona: { + name: 'MyAgent', + prompts: { + synthesis: 'You are MyAgent. Always answer in rhyme.' + } + } +}; + +const art = await createArtInstance(config); +const response = await art.process({ query: "Hello, world!" }); +``` + +--- + +## 2. Primary Interfaces & Types + +These are the core data structures, enums, and type definitions used throughout the framework. Use them to understand the shape of data and to build your own custom components. + +### Core Interfaces (`@/core/interfaces`) + +These interfaces define the contracts for key components of the ART framework. If you want to create your own agent, tool, or storage adapter, you should implement these interfaces. + +### Core Types (`@/types`) + +This module exports essential data structures, including: +- Message formats (`ArtStandardMessage`). +- Observation types. +- Agent state definitions. +- `ArtInstanceConfig`: The main configuration object for `createArtInstance`. +- `AgentPersona`: Defines the agent's identity, including its name and system prompts. + +### Provider Management Types (`@/types/providers`) + +These types are useful for advanced scenarios, such as dynamically configuring LLM providers at runtime. +- `ProviderManagerConfig` +- `AvailableProviderEntry` +- `RuntimeProviderConfig` +- `ManagedAdapterAccessor` +- `IProviderManager` + +--- + +## 3. Built-in Components + +ART comes with a set of pre-built components to get you started quickly. + +### Agent Implementations + +#### `PESAgent` + +The default agent core implementation based on the **P**lan-**E**xecute-**S**ynthesize model. +- **Description**: This agent is designed for general-purpose tasks. It first creates a plan, then executes tools according to the plan, and finally synthesizes the results into a final answer. +- **When to use**: Use this as your default reasoning engine unless you have a specific need for a different agent architecture (e.g., ReAct, Chain-of-Thought). + +### Storage Adapters + +Storage adapters handle the persistence of conversation history and agent state. + +#### `InMemoryStorageAdapter` + +A non-persistent storage adapter that keeps all data in memory. +- **When to use**: Ideal for testing, short-lived scripts, or any scenario where data persistence across sessions is not required. Data will be lost when the process terminates. + +#### `IndexedDBStorageAdapter` + +A persistent storage adapter that uses the browser's IndexedDB. +- **When to use**: The recommended choice for web-based applications to persist data on the client-side. It's efficient and works offline. + +#### `SupabaseStorageAdapter` + +A persistent storage adapter for connecting to a Supabase (Postgres) database. +- **When to use**: Suitable for server-side environments or applications that require data to be shared across users or persisted in the cloud. + +### Reasoning Provider Adapters + +These adapters connect ART to various Large Language Models (LLMs). + +- **`GeminiAdapter`**: For Google's Gemini models. +- **`OpenAIAdapter`**: For OpenAI's models (e.g., GPT-3.5, GPT-4). +- **`AnthropicAdapter`**: For Anthropic's Claude models. +- **`OpenRouterAdapter`**: Acts as a proxy to a wide variety of models from different providers. +- **`DeepSeekAdapter`**: For DeepSeek models. +- **`OllamaAdapter`**: For running local LLMs through the Ollama service. + +Each adapter comes with its own options type for specific configurations: +- `GeminiAdapterOptions` +- `OpenAIAdapterOptions` +- `AnthropicAdapterOptions` +- `OpenRouterAdapterOptions` +- `DeepSeekAdapterOptions` +- `OllamaAdapterOptions` + +### Built-in Tools + +#### `CalculatorTool` + +A basic tool that allows the agent to evaluate mathematical expressions. +- **When to use**: A good example of a simple tool. Include it when you expect the agent to perform calculations. + +--- + +## 4. Advanced Systems & Managers + +For developers who need to directly interact with or extend ART's internal systems. + +### UI & Sockets + +These components provide real-time data streams, useful for building custom user interfaces. + +#### `ConversationSocket` + +Provides a real-time connection to an agent's conversation history. +- **When to use**: For building custom UI components that display the back-and-forth interaction between a user and the agent, like a chat window. + +#### `ObservationSocket` + +Provides a real-time stream of an agent's internal "thoughts" and actions. +- **When to use**: For building developer tools, debug panels, or UIs that visualize the agent's reasoning process, such as tool calls and state changes. + +#### `LLMStreamSocket` + +Provides a real-time stream of the raw token output from the Language Model as it's being generated. +- **When to use**: For creating a "typewriter" effect in the UI, showing the agent's response as it's being formed token by token. This provides immediate feedback to the user. +- **Associated Types**: + - `StreamEventTypeFilter`: A type used to filter the events received from the LLM stream. + +#### Rendering Execution Metadata (Run Metrics) + +You can surface execution metrics like token counts, durations, and stop reasons in a small UI card by listening to the final agent event via the `ObservationSocket`. + +- **What to listen to**: Subscribe to `FINAL_RESPONSE` on `art.uiSystem.getObservationSocket()` scoped by `threadId`. +- **Where the fields live**: + - From `ExecutionMetadata` (`response.metadata`): `totalDurationMs`, `llmCalls`, `toolCalls`. + - From `LLMMetadata` (`response.metadata.llmMetadata`): `inputTokens`, `outputTokens`, `timeToFirstTokenMs`, `stopReason`. + +```tsx +import React from 'react'; + +type MetaMap = Record; + +export function RunMetricsCard({ art, threadId }: { art: any; threadId: string }) { + const [meta, setMeta] = React.useState(null); + + React.useEffect(() => { + const observationSocket = art.uiSystem.getObservationSocket(); + const unsubscribe = observationSocket.subscribe( + (observation: any) => { + if (observation.type !== 'FINAL_RESPONSE') return; + + const response = observation.content; // AgentFinalResponse + const exec = response.metadata; // ExecutionMetadata + const llm = exec.llmMetadata ?? {}; // LLMMetadata + + const totalInputTokens = llm.inputTokens ?? 0; + const totalOutputTokens = llm.outputTokens ?? 0; + const timeToFirstTokenMs = llm.timeToFirstTokenMs ?? undefined; + const lastStopReason = llm.stopReason ?? undefined; + + const metaMap: MetaMap = { + 'Input Tokens': totalInputTokens, + 'Output Tokens': totalOutputTokens, + 'Total Tokens': totalInputTokens + totalOutputTokens, + 'First Token MS': timeToFirstTokenMs, + 'Total Time MS': exec.totalDurationMs, + 'Finish Reason': lastStopReason ?? 'stop', + 'LLM Calls': exec.llmCalls, + 'Tool Calls': exec.toolCalls, + }; + setMeta(metaMap); + }, + 'FINAL_RESPONSE', + { threadId } + ); + + return () => unsubscribe(); + }, [art, threadId]); + + if (!meta) return null; + + return ( +
      +
      Run Metrics
      +
      + {Object.entries(meta).map(([label, value]) => ( + +
      {label}
      +
      {value ?? '—'}
      +
      + ))} +
      +
      + ); +} +``` + +If you want earlier values for fields like "First Token MS" or an interim stop reason, also subscribe to the `LLMStreamSocket` and handle `METADATA` events (availability varies by adapter). Update the same state as tokens arrive, and let the `FINAL_RESPONSE` overwrite with authoritative values at the end. + +--- + +## 6. Gemini Thinking Tokens & THOUGHTS Observations + +The Gemini adapter now supports optional separation of thought (reasoning) tokens from response tokens on models that expose this feature (e.g., `gemini-2.5-*`). + +### Enabling Thinking Output + +Pass provider-specific options on the call: + +```ts +const stream = await art.reasoningEngine.call(prompt, { + threadId, + stream: true, + callContext: 'FINAL_SYNTHESIS', + providerConfig, // your configured Gemini provider + gemini: { + thinking: { includeThoughts: true, thinkingBudget: 8096 } + } +}); +``` + +The adapter forwards these to the GenAI SDK via `config.thinkingConfig` and, when available, distinguishes thought vs response parts. + +### Stream Event Token Typing + +When thought markers are available, `StreamEvent.tokenType` will be set to one of the agent-context-aware variants: + +- `AGENT_THOUGHT_LLM_THINKING` / `AGENT_THOUGHT_LLM_RESPONSE` +- `FINAL_SYNTHESIS_LLM_THINKING` / `FINAL_SYNTHESIS_LLM_RESPONSE` + +If unsupported, tokens fall back to `...LLM_RESPONSE`. + +### Observations: THOUGHTS + +The `PESAgent` now emits `ObservationType.THOUGHTS` entries whenever a thinking token is received during planning or synthesis. Each observation contains: + +- `content.text`: the token text +- `metadata.phase`: `planning` or `synthesis` +- `metadata.tokenType`: the specific token type + +### Metadata + +When provided by the SDK, `LLMMetadata.thinkingTokens` is populated in the final `METADATA` stream event. + +### Example: Streaming THOUGHTS to a UI element + +```ts +// Given an initialized ART instance `art` and a known `threadId` +const obsSocket = art.uiSystem.getObservationSocket(); + +// Subscribe only to THOUGHTS for a specific thread +const unsubscribe = obsSocket.subscribe( + (observation) => { + if (observation.type !== ObservationType.THOUGHTS) return; + + const phase = observation.metadata?.phase; // 'planning' | 'synthesis' + const token = typeof observation.content?.text === 'string' ? observation.content.text : ''; + + // Route to your UI components + if (phase === 'planning') { + appendToPlanningThoughts(token); // your UI helper + } else if (phase === 'synthesis') { + appendToSynthesisThoughts(token); // your UI helper + } + }, + ObservationType.THOUGHTS, + { threadId } +); + +// Later, to stop streaming thoughts for this thread: +// unsubscribe(); +``` + +#### `A2ATaskSocket` + +Provides real-time updates on the status of tasks delegated between agents in a multi-agent system. +- **When to use**: For building dashboards or monitoring tools that track the lifecycle of agent-to-agent tasks, showing statuses like `PENDING`, `IN_PROGRESS`, `COMPLETED`, or `FAILED`. + +#### `UISystem` + +Facade providing access to all UI sockets (`ConversationSocket`, `ObservationSocket`, `LLMStreamSocket`, `A2ATaskSocket`). +- **When to use**: To conveniently retrieve socket instances without managing their lifecycles yourself. +- **Example**: +```ts +const ui = art.uiSystem; +const conv = ui.getConversationSocket(); +const obs = ui.getObservationSocket(); +const llm = ui.getLlmStreamSocket(); +const tasks = ui.getA2ATaskSocket(); +``` + +### Authentication + +#### `AuthManager` + +Manages authentication strategies and token lifecycle for external services. +- **When to use**: When your tools or providers require secure authentication (e.g., OAuth2). You can register different strategies with this manager to handle various auth flows. + +#### `PKCEOAuthStrategy` + +An implementation of the PKCE (Proof Key for Code Exchange) OAuth2 flow. +- **When to use**: As a strategy in the `AuthManager` for services that support the PKCE flow. This is common in public clients and Single-Page Applications (SPAs). +- **Configuration**: Use the `PKCEOAuthConfig` interface to configure the strategy. + +#### `ApiKeyStrategy` + +Simple API key authentication strategy. +- **When to use**: For providers or tools that accept a static API key. +- **Example**: Register with `AuthManager` and attach the key via headers or params. + +#### `GenericOAuthStrategy` + +Generic OAuth2 strategy for providers that follow standard OAuth flows. +- **When to use**: When you need a configurable OAuth flow beyond PKCE specifics. +- **Configuration**: `OAuthConfig` + +#### `ZyntopiaOAuthStrategy` + +Provider-specific OAuth strategy for Zyntopia integrations. +- **When to use**: If integrating with Zyntopia services. +- **Configuration**: `ZyntopiaOAuthConfig` + +### MCP (Model Context Protocol) + +MCP allows agents to dynamically discover and use tools and other resources from a server. + +#### `McpManager` + +The core manager for handling connections to MCP servers. +- **When to use**: When integrating ART with an MCP server to dynamically load tools and resources, making the agent more extensible. +- **Configuration**: `McpManagerConfig` + +#### `McpProxyTool` + +A special tool that acts as a proxy for all tools provided by an MCP server. +- **When to use**: This is typically registered automatically when MCP is configured, but can be used manually for advanced MCP integrations. + +#### `McpClientController` + +A client for making direct requests to an MCP server. +- **When to use**: If you need to interact with an MCP server's resources outside of the standard agent tool-use loop. + +#### MCP Types + +The following types are used for configuring and interacting with MCP servers: +- `McpServerConfig`: Defines the connection details for an MCP server. +- `McpToolDefinition`: The structure of a tool as defined by an MCP server. +- `McpResource`: Represents a generic resource provided by the server. +- `McpResourceTemplate`: Represents a template for creating resources. +- `McpServerStatus`: Represents the health and status of the MCP server. + +### A2A (Agent-to-Agent Communication) + +These services enable agents to collaborate by delegating tasks to one another. + +#### `AgentDiscoveryService` + +A service for discovering other agents available on an A2A network. +- **When to use**: When building collaborative agent systems where one agent needs to find another agent with a specific capability. +- **Configuration**: `AgentDiscoveryConfig` + +#### `TaskDelegationService` + +A service for delegating tasks to other agents and monitoring their status. +- **When to use**: After discovering a suitable agent, use this service to assign it a task and receive updates on its progress. +- **Configuration**: `TaskDelegationConfig` + +#### A2A Types + +- `TaskStatusResponse`: The object returned when checking the status of a delegated task. +- `A2ATaskEvent`: Represents an event related to a delegated task (e.g., status change). +- `A2ATaskFilter`: Used to filter which task events you want to listen for. + +--- + +## 5. Utilities + +Helper functions and classes. + +### Managers & Registries (advanced) + +These are advanced components for deeper customization and control. + +#### `StateManager` + +State manager for thread configuration and state with explicit/implicit save strategies. +- **When to use**: When you need direct control over thread state persistence and retrieval. + +#### `ToolRegistry` + +In-memory registry for registering and querying tool executors. +- **When to use**: To dynamically add, remove, or look up tools at runtime. + +#### `ProviderManagerImpl` + +Provider manager implementation controlling adapter lifecycles and concurrency. +- **When to use**: For advanced control of provider adapters, including pooling, rate limits, and concurrency. + +### `Logger` & `LogLevel` + +A simple logging utility with configurable levels (`DEBUG`, `INFO`, `WARN`, `ERROR`). +- **When to use**: For adding consistent logging throughout your custom components. An instance is available on `ArtInstance.logger`. +- **Configuration**: `LoggerConfig` + +### `generateUUID` + +A function to generate RFC4122 v4 compliant UUIDs. +- **When to use**: For creating unique identifiers for threads, messages, or other entities in your application. + +--- + +## Framework Version + +### `VERSION` + +The current version of the ART Framework package. +- **Usage**: `console.log(VERSION);` +- **Value**: `'0.3.7'` (at the time of writing) diff --git a/docs/art-logo.jpeg b/docs/art-logo.jpeg new file mode 100755 index 0000000..4d48b0d Binary files /dev/null and b/docs/art-logo.jpeg differ diff --git a/docs/components/.nojekyll b/docs/components/.nojekyll new file mode 100644 index 0000000..e2ac661 --- /dev/null +++ b/docs/components/.nojekyll @@ -0,0 +1 @@ +TypeDoc added this file to prevent GitHub Pages from using Jekyll. You can turn off this behavior by setting the `githubPages` option to false. \ No newline at end of file diff --git a/docs/components/assets/hierarchy.js b/docs/components/assets/hierarchy.js new file mode 100644 index 0000000..d7ee5aa --- /dev/null +++ b/docs/components/assets/hierarchy.js @@ -0,0 +1 @@ +window.hierarchyData = "eJyVlk1P4zAQhv+Lz2Y3dj7dWykVQoBgafeyiINJhhI1tSPHYakQ/32V0rJ2m9bOxYf2nTzv2OMZfyAlpW7Q6JFkjGKKKUlwxGIcRzjBhFBMWEyfMFLwUkGuSykaNPpAtFsEXwEaoavxAoSeSAUIo2UpCjSicYJRqyo0QqXQoF54Ds3P/8Ifr3pVIYzyijcNGiHdFGdd5Nm3uvvztawKBQKNHuOAPH1ilBjUB+CNFKVYTMWiFC70nnooP0o6fGTy75V8KwtQ44LXGpSDv6ceyk+TBGc0xCkNcRZRnEYhzoKgMxVH5lHMpaym75C3WrosWdqhhrI0wCSMs84BIWY1zLRUfAF+22KLh5pIghgnYYqTNO18UJJYVdnq15lWXMNi7SxMQzvUBSFZigkNAkxIuNmQiMWmkd3Z33LBF84t2ZcPtpNEbFMXATGrdTrbXL5vOKHZDr75clejW81R4tcP3T0MrATFLaykWh85+R5Sf4QHN0wtbgHvUFycDwH3hniQU5M8a2v+zBvwB/dHuLkpDQ3uJaxKUXrgLKEHJTIpdzWI8ZUHxRJ6UBLzfo6FflWyLnMP0L7WzcqCYC+jB9nqw259JCtL7EGzTukCoJ4BLD1Ye1IPUmT22ruq4ivuk5Mp9KCk5u5NeJW3FddSdRPjFMZWenAyiyPFG6iGd4+MmcyXcLJbHardPEatqnhuQL154g7EHrTE7MA3N7czrYCv3Kw9qQeJMfNm0fGcN0s3xxK6Kd14M0fK9WR61ztk+2bLvtgHl5k9d1yX17D2YdlKDxC1msUlCFBl7p1an94BtQc2jeLNM4pG5lT9sxZa1iX39tEb4JF9GJunepvX90q+r11X3dR5QJKI9bydt0+cq1V9ktUj90BmzGyV44f5VCl5esxsNYNOjwURJoyEmDDaLWG3RHRzoiwwH+e/xVLIv2KXjdNOn94jb0bMYXQjc17tPjGR4qUqc+1EH4/yMUAPDFyJRnORw3nbrP3gBxE+4DC0G8avFlqYlyuQrTvnPr0P1JrI2xH75V6Xm3nhJh8L8sHHJn6+rqFwN35DNqTWsyzAjAaYJQQzxp4+Pz//AZCpWUQ=" \ No newline at end of file diff --git a/docs/components/assets/highlight.css b/docs/components/assets/highlight.css new file mode 100644 index 0000000..8cd12db --- /dev/null +++ b/docs/components/assets/highlight.css @@ -0,0 +1,99 @@ +:root { + --light-hl-0: #795E26; + --dark-hl-0: #DCDCAA; + --light-hl-1: #000000; + --dark-hl-1: #D4D4D4; + --light-hl-2: #A31515; + --dark-hl-2: #CE9178; + --light-hl-3: #008000; + --dark-hl-3: #6A9955; + --light-hl-4: #AF00DB; + --dark-hl-4: #C586C0; + --light-hl-5: #001080; + --dark-hl-5: #9CDCFE; + --light-hl-6: #0000FF; + --dark-hl-6: #569CD6; + --light-hl-7: #0070C1; + --dark-hl-7: #4FC1FF; + --light-hl-8: #267F99; + --dark-hl-8: #4EC9B0; + --light-hl-9: #098658; + --dark-hl-9: #B5CEA8; + --light-hl-10: #000000; + --dark-hl-10: #C8C8C8; + --light-code-background: #FFFFFF; + --dark-code-background: #1E1E1E; +} + +@media (prefers-color-scheme: light) { :root { + --hl-0: var(--light-hl-0); + --hl-1: var(--light-hl-1); + --hl-2: var(--light-hl-2); + --hl-3: var(--light-hl-3); + --hl-4: var(--light-hl-4); + --hl-5: var(--light-hl-5); + --hl-6: var(--light-hl-6); + --hl-7: var(--light-hl-7); + --hl-8: var(--light-hl-8); + --hl-9: var(--light-hl-9); + --hl-10: var(--light-hl-10); + --code-background: var(--light-code-background); +} } + +@media (prefers-color-scheme: dark) { :root { + --hl-0: var(--dark-hl-0); + --hl-1: var(--dark-hl-1); + --hl-2: var(--dark-hl-2); + --hl-3: var(--dark-hl-3); + --hl-4: var(--dark-hl-4); + --hl-5: var(--dark-hl-5); + --hl-6: var(--dark-hl-6); + --hl-7: var(--dark-hl-7); + --hl-8: var(--dark-hl-8); + --hl-9: var(--dark-hl-9); + --hl-10: var(--dark-hl-10); + --code-background: var(--dark-code-background); +} } + +:root[data-theme='light'] { + --hl-0: var(--light-hl-0); + --hl-1: var(--light-hl-1); + --hl-2: var(--light-hl-2); + --hl-3: var(--light-hl-3); + --hl-4: var(--light-hl-4); + --hl-5: var(--light-hl-5); + --hl-6: var(--light-hl-6); + --hl-7: var(--light-hl-7); + --hl-8: var(--light-hl-8); + --hl-9: var(--light-hl-9); + --hl-10: var(--light-hl-10); + --code-background: var(--light-code-background); +} + +:root[data-theme='dark'] { + --hl-0: var(--dark-hl-0); + --hl-1: var(--dark-hl-1); + --hl-2: var(--dark-hl-2); + --hl-3: var(--dark-hl-3); + --hl-4: var(--dark-hl-4); + --hl-5: var(--dark-hl-5); + --hl-6: var(--dark-hl-6); + --hl-7: var(--dark-hl-7); + --hl-8: var(--dark-hl-8); + --hl-9: var(--dark-hl-9); + --hl-10: var(--dark-hl-10); + --code-background: var(--dark-code-background); +} + +.hl-0 { color: var(--hl-0); } +.hl-1 { color: var(--hl-1); } +.hl-2 { color: var(--hl-2); } +.hl-3 { color: var(--hl-3); } +.hl-4 { color: var(--hl-4); } +.hl-5 { color: var(--hl-5); } +.hl-6 { color: var(--hl-6); } +.hl-7 { color: var(--hl-7); } +.hl-8 { color: var(--hl-8); } +.hl-9 { color: var(--hl-9); } +.hl-10 { color: var(--hl-10); } +pre, code { background: var(--code-background); } diff --git a/docs/components/assets/icons.js b/docs/components/assets/icons.js new file mode 100644 index 0000000..58882d7 --- /dev/null +++ b/docs/components/assets/icons.js @@ -0,0 +1,18 @@ +(function() { + addIcons(); + function addIcons() { + if (document.readyState === "loading") return document.addEventListener("DOMContentLoaded", addIcons); + const svg = document.body.appendChild(document.createElementNS("http://www.w3.org/2000/svg", "svg")); + svg.innerHTML = `MMNEPVFCICPMFPCPTTAAATR`; + svg.style.display = "none"; + if (location.protocol === "file:") updateUseElements(); + } + + function updateUseElements() { + document.querySelectorAll("use").forEach(el => { + if (el.getAttribute("href").includes("#icon-")) { + el.setAttribute("href", el.getAttribute("href").replace(/.*#/, "#")); + } + }); + } +})() \ No newline at end of file diff --git a/docs/components/assets/icons.svg b/docs/components/assets/icons.svg new file mode 100644 index 0000000..50ad579 --- /dev/null +++ b/docs/components/assets/icons.svg @@ -0,0 +1 @@ +MMNEPVFCICPMFPCPTTAAATR \ No newline at end of file diff --git a/docs/components/assets/main.js b/docs/components/assets/main.js new file mode 100644 index 0000000..19bbb7a --- /dev/null +++ b/docs/components/assets/main.js @@ -0,0 +1,60 @@ +"use strict"; +window.translations={"copy":"Copy","copied":"Copied!","normally_hidden":"This member is normally hidden due to your filter settings.","hierarchy_expand":"Expand","hierarchy_collapse":"Collapse","folder":"Folder","search_index_not_available":"The search index is not available","search_no_results_found_for_0":"No results found for {0}","kind_1":"Project","kind_2":"Module","kind_4":"Namespace","kind_8":"Enumeration","kind_16":"Enumeration Member","kind_32":"Variable","kind_64":"Function","kind_128":"Class","kind_256":"Interface","kind_512":"Constructor","kind_1024":"Property","kind_2048":"Method","kind_4096":"Call Signature","kind_8192":"Index Signature","kind_16384":"Constructor Signature","kind_32768":"Parameter","kind_65536":"Type Literal","kind_131072":"Type Parameter","kind_262144":"Accessor","kind_524288":"Get Signature","kind_1048576":"Set Signature","kind_2097152":"Type Alias","kind_4194304":"Reference","kind_8388608":"Document"}; +"use strict";(()=>{var Ke=Object.create;var he=Object.defineProperty;var Ge=Object.getOwnPropertyDescriptor;var Ze=Object.getOwnPropertyNames;var Xe=Object.getPrototypeOf,Ye=Object.prototype.hasOwnProperty;var et=(t,e)=>()=>(e||t((e={exports:{}}).exports,e),e.exports);var tt=(t,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of Ze(e))!Ye.call(t,i)&&i!==n&&he(t,i,{get:()=>e[i],enumerable:!(r=Ge(e,i))||r.enumerable});return t};var nt=(t,e,n)=>(n=t!=null?Ke(Xe(t)):{},tt(e||!t||!t.__esModule?he(n,"default",{value:t,enumerable:!0}):n,t));var ye=et((me,ge)=>{(function(){var t=function(e){var n=new t.Builder;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),n.searchPipeline.add(t.stemmer),e.call(n,n),n.build()};t.version="2.3.9";t.utils={},t.utils.warn=function(e){return function(n){e.console&&console.warn&&console.warn(n)}}(this),t.utils.asString=function(e){return e==null?"":e.toString()},t.utils.clone=function(e){if(e==null)return e;for(var n=Object.create(null),r=Object.keys(e),i=0;i0){var d=t.utils.clone(n)||{};d.position=[a,l],d.index=s.length,s.push(new t.Token(r.slice(a,o),d))}a=o+1}}return s},t.tokenizer.separator=/[\s\-]+/;t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions=Object.create(null),t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn(`Function is not registered with pipeline. This may cause problems when serialising the index. +`,e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(r){var i=t.Pipeline.registeredFunctions[r];if(i)n.add(i);else throw new Error("Cannot load unregistered function: "+r)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(n){t.Pipeline.warnIfFunctionNotRegistered(n),this._stack.push(n)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");r=r+1,this._stack.splice(r,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var r=this._stack.indexOf(e);if(r==-1)throw new Error("Cannot find existingFn");this._stack.splice(r,0,n)},t.Pipeline.prototype.remove=function(e){var n=this._stack.indexOf(e);n!=-1&&this._stack.splice(n,1)},t.Pipeline.prototype.run=function(e){for(var n=this._stack.length,r=0;r1&&(oe&&(r=s),o!=e);)i=r-n,s=n+Math.floor(i/2),o=this.elements[s*2];if(o==e||o>e)return s*2;if(oc?d+=2:a==c&&(n+=r[l+1]*i[d+1],l+=2,d+=2);return n},t.Vector.prototype.similarity=function(e){return this.dot(e)/this.magnitude()||0},t.Vector.prototype.toArray=function(){for(var e=new Array(this.elements.length/2),n=1,r=0;n0){var o=s.str.charAt(0),a;o in s.node.edges?a=s.node.edges[o]:(a=new t.TokenSet,s.node.edges[o]=a),s.str.length==1&&(a.final=!0),i.push({node:a,editsRemaining:s.editsRemaining,str:s.str.slice(1)})}if(s.editsRemaining!=0){if("*"in s.node.edges)var c=s.node.edges["*"];else{var c=new t.TokenSet;s.node.edges["*"]=c}if(s.str.length==0&&(c.final=!0),i.push({node:c,editsRemaining:s.editsRemaining-1,str:s.str}),s.str.length>1&&i.push({node:s.node,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)}),s.str.length==1&&(s.node.final=!0),s.str.length>=1){if("*"in s.node.edges)var l=s.node.edges["*"];else{var l=new t.TokenSet;s.node.edges["*"]=l}s.str.length==1&&(l.final=!0),i.push({node:l,editsRemaining:s.editsRemaining-1,str:s.str.slice(1)})}if(s.str.length>1){var d=s.str.charAt(0),f=s.str.charAt(1),p;f in s.node.edges?p=s.node.edges[f]:(p=new t.TokenSet,s.node.edges[f]=p),s.str.length==1&&(p.final=!0),i.push({node:p,editsRemaining:s.editsRemaining-1,str:d+s.str.slice(2)})}}}return r},t.TokenSet.fromString=function(e){for(var n=new t.TokenSet,r=n,i=0,s=e.length;i=e;n--){var r=this.uncheckedNodes[n],i=r.child.toString();i in this.minimizedNodes?r.parent.edges[r.char]=this.minimizedNodes[i]:(r.child._str=i,this.minimizedNodes[i]=r.child),this.uncheckedNodes.pop()}};t.Index=function(e){this.invertedIndex=e.invertedIndex,this.fieldVectors=e.fieldVectors,this.tokenSet=e.tokenSet,this.fields=e.fields,this.pipeline=e.pipeline},t.Index.prototype.search=function(e){return this.query(function(n){var r=new t.QueryParser(e,n);r.parse()})},t.Index.prototype.query=function(e){for(var n=new t.Query(this.fields),r=Object.create(null),i=Object.create(null),s=Object.create(null),o=Object.create(null),a=Object.create(null),c=0;c1?this._b=1:this._b=e},t.Builder.prototype.k1=function(e){this._k1=e},t.Builder.prototype.add=function(e,n){var r=e[this._ref],i=Object.keys(this._fields);this._documents[r]=n||{},this.documentCount+=1;for(var s=0;s=this.length)return t.QueryLexer.EOS;var e=this.str.charAt(this.pos);return this.pos+=1,e},t.QueryLexer.prototype.width=function(){return this.pos-this.start},t.QueryLexer.prototype.ignore=function(){this.start==this.pos&&(this.pos+=1),this.start=this.pos},t.QueryLexer.prototype.backup=function(){this.pos-=1},t.QueryLexer.prototype.acceptDigitRun=function(){var e,n;do e=this.next(),n=e.charCodeAt(0);while(n>47&&n<58);e!=t.QueryLexer.EOS&&this.backup()},t.QueryLexer.prototype.more=function(){return this.pos1&&(e.backup(),e.emit(t.QueryLexer.TERM)),e.ignore(),e.more())return t.QueryLexer.lexText},t.QueryLexer.lexEditDistance=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.EDIT_DISTANCE),t.QueryLexer.lexText},t.QueryLexer.lexBoost=function(e){return e.ignore(),e.acceptDigitRun(),e.emit(t.QueryLexer.BOOST),t.QueryLexer.lexText},t.QueryLexer.lexEOS=function(e){e.width()>0&&e.emit(t.QueryLexer.TERM)},t.QueryLexer.termSeparator=t.tokenizer.separator,t.QueryLexer.lexText=function(e){for(;;){var n=e.next();if(n==t.QueryLexer.EOS)return t.QueryLexer.lexEOS;if(n.charCodeAt(0)==92){e.escapeCharacter();continue}if(n==":")return t.QueryLexer.lexField;if(n=="~")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexEditDistance;if(n=="^")return e.backup(),e.width()>0&&e.emit(t.QueryLexer.TERM),t.QueryLexer.lexBoost;if(n=="+"&&e.width()===1||n=="-"&&e.width()===1)return e.emit(t.QueryLexer.PRESENCE),t.QueryLexer.lexText;if(n.match(t.QueryLexer.termSeparator))return t.QueryLexer.lexTerm}},t.QueryParser=function(e,n){this.lexer=new t.QueryLexer(e),this.query=n,this.currentClause={},this.lexemeIdx=0},t.QueryParser.prototype.parse=function(){this.lexer.run(),this.lexemes=this.lexer.lexemes;for(var e=t.QueryParser.parseClause;e;)e=e(this);return this.query},t.QueryParser.prototype.peekLexeme=function(){return this.lexemes[this.lexemeIdx]},t.QueryParser.prototype.consumeLexeme=function(){var e=this.peekLexeme();return this.lexemeIdx+=1,e},t.QueryParser.prototype.nextClause=function(){var e=this.currentClause;this.query.clause(e),this.currentClause={}},t.QueryParser.parseClause=function(e){var n=e.peekLexeme();if(n!=null)switch(n.type){case t.QueryLexer.PRESENCE:return t.QueryParser.parsePresence;case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expected either a field or a term, found "+n.type;throw n.str.length>=1&&(r+=" with value '"+n.str+"'"),new t.QueryParseError(r,n.start,n.end)}},t.QueryParser.parsePresence=function(e){var n=e.consumeLexeme();if(n!=null){switch(n.str){case"-":e.currentClause.presence=t.Query.presence.PROHIBITED;break;case"+":e.currentClause.presence=t.Query.presence.REQUIRED;break;default:var r="unrecognised presence operator'"+n.str+"'";throw new t.QueryParseError(r,n.start,n.end)}var i=e.peekLexeme();if(i==null){var r="expecting term or field, found nothing";throw new t.QueryParseError(r,n.start,n.end)}switch(i.type){case t.QueryLexer.FIELD:return t.QueryParser.parseField;case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var r="expecting term or field, found '"+i.type+"'";throw new t.QueryParseError(r,i.start,i.end)}}},t.QueryParser.parseField=function(e){var n=e.consumeLexeme();if(n!=null){if(e.query.allFields.indexOf(n.str)==-1){var r=e.query.allFields.map(function(o){return"'"+o+"'"}).join(", "),i="unrecognised field '"+n.str+"', possible fields: "+r;throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.fields=[n.str];var s=e.peekLexeme();if(s==null){var i="expecting term, found nothing";throw new t.QueryParseError(i,n.start,n.end)}switch(s.type){case t.QueryLexer.TERM:return t.QueryParser.parseTerm;default:var i="expecting term, found '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseTerm=function(e){var n=e.consumeLexeme();if(n!=null){e.currentClause.term=n.str.toLowerCase(),n.str.indexOf("*")!=-1&&(e.currentClause.usePipeline=!1);var r=e.peekLexeme();if(r==null){e.nextClause();return}switch(r.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+r.type+"'";throw new t.QueryParseError(i,r.start,r.end)}}},t.QueryParser.parseEditDistance=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="edit distance must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.editDistance=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},t.QueryParser.parseBoost=function(e){var n=e.consumeLexeme();if(n!=null){var r=parseInt(n.str,10);if(isNaN(r)){var i="boost must be numeric";throw new t.QueryParseError(i,n.start,n.end)}e.currentClause.boost=r;var s=e.peekLexeme();if(s==null){e.nextClause();return}switch(s.type){case t.QueryLexer.TERM:return e.nextClause(),t.QueryParser.parseTerm;case t.QueryLexer.FIELD:return e.nextClause(),t.QueryParser.parseField;case t.QueryLexer.EDIT_DISTANCE:return t.QueryParser.parseEditDistance;case t.QueryLexer.BOOST:return t.QueryParser.parseBoost;case t.QueryLexer.PRESENCE:return e.nextClause(),t.QueryParser.parsePresence;default:var i="Unexpected lexeme type '"+s.type+"'";throw new t.QueryParseError(i,s.start,s.end)}}},function(e,n){typeof define=="function"&&define.amd?define(n):typeof me=="object"?ge.exports=n():e.lunr=n()}(this,function(){return t})})()});var M,G={getItem(){return null},setItem(){}},K;try{K=localStorage,M=K}catch{K=G,M=G}var S={getItem:t=>M.getItem(t),setItem:(t,e)=>M.setItem(t,e),disableWritingLocalStorage(){M=G},disable(){localStorage.clear(),M=G},enable(){M=K}};window.TypeDoc||={disableWritingLocalStorage(){S.disableWritingLocalStorage()},disableLocalStorage:()=>{S.disable()},enableLocalStorage:()=>{S.enable()}};window.translations||={copy:"Copy",copied:"Copied!",normally_hidden:"This member is normally hidden due to your filter settings.",hierarchy_expand:"Expand",hierarchy_collapse:"Collapse",search_index_not_available:"The search index is not available",search_no_results_found_for_0:"No results found for {0}",folder:"Folder",kind_1:"Project",kind_2:"Module",kind_4:"Namespace",kind_8:"Enumeration",kind_16:"Enumeration Member",kind_32:"Variable",kind_64:"Function",kind_128:"Class",kind_256:"Interface",kind_512:"Constructor",kind_1024:"Property",kind_2048:"Method",kind_4096:"Call Signature",kind_8192:"Index Signature",kind_16384:"Constructor Signature",kind_32768:"Parameter",kind_65536:"Type Literal",kind_131072:"Type Parameter",kind_262144:"Accessor",kind_524288:"Get Signature",kind_1048576:"Set Signature",kind_2097152:"Type Alias",kind_4194304:"Reference",kind_8388608:"Document"};var pe=[];function X(t,e){pe.push({selector:e,constructor:t})}var Z=class{alwaysVisibleMember=null;constructor(){this.createComponents(document.body),this.ensureFocusedElementVisible(),this.listenForCodeCopies(),window.addEventListener("hashchange",()=>this.ensureFocusedElementVisible()),document.body.style.display||(this.ensureFocusedElementVisible(),this.updateIndexVisibility(),this.scrollToHash())}createComponents(e){pe.forEach(n=>{e.querySelectorAll(n.selector).forEach(r=>{r.dataset.hasInstance||(new n.constructor({el:r,app:this}),r.dataset.hasInstance=String(!0))})})}filterChanged(){this.ensureFocusedElementVisible()}showPage(){document.body.style.display&&(document.body.style.removeProperty("display"),this.ensureFocusedElementVisible(),this.updateIndexVisibility(),this.scrollToHash())}scrollToHash(){if(location.hash){let e=document.getElementById(location.hash.substring(1));if(!e)return;e.scrollIntoView({behavior:"instant",block:"start"})}}ensureActivePageVisible(){let e=document.querySelector(".tsd-navigation .current"),n=e?.parentElement;for(;n&&!n.classList.contains(".tsd-navigation");)n instanceof HTMLDetailsElement&&(n.open=!0),n=n.parentElement;if(e&&!rt(e)){let r=e.getBoundingClientRect().top-document.documentElement.clientHeight/4;document.querySelector(".site-menu").scrollTop=r,document.querySelector(".col-sidebar").scrollTop=r}}updateIndexVisibility(){let e=document.querySelector(".tsd-index-content"),n=e?.open;e&&(e.open=!0),document.querySelectorAll(".tsd-index-section").forEach(r=>{r.style.display="block";let i=Array.from(r.querySelectorAll(".tsd-index-link")).every(s=>s.offsetParent==null);r.style.display=i?"none":"block"}),e&&(e.open=n)}ensureFocusedElementVisible(){if(this.alwaysVisibleMember&&(this.alwaysVisibleMember.classList.remove("always-visible"),this.alwaysVisibleMember.firstElementChild.remove(),this.alwaysVisibleMember=null),!location.hash)return;let e=document.getElementById(location.hash.substring(1));if(!e)return;let n=e.parentElement;for(;n&&n.tagName!=="SECTION";)n=n.parentElement;if(!n)return;let r=n.offsetParent==null,i=n;for(;i!==document.body;)i instanceof HTMLDetailsElement&&(i.open=!0),i=i.parentElement;if(n.offsetParent==null){this.alwaysVisibleMember=n,n.classList.add("always-visible");let s=document.createElement("p");s.classList.add("warning"),s.textContent=window.translations.normally_hidden,n.prepend(s)}r&&e.scrollIntoView()}listenForCodeCopies(){document.querySelectorAll("pre > button").forEach(e=>{let n;e.addEventListener("click",()=>{e.previousElementSibling instanceof HTMLElement&&navigator.clipboard.writeText(e.previousElementSibling.innerText.trim()),e.textContent=window.translations.copied,e.classList.add("visible"),clearTimeout(n),n=setTimeout(()=>{e.classList.remove("visible"),n=setTimeout(()=>{e.textContent=window.translations.copy},100)},1e3)})})}};function rt(t){let e=t.getBoundingClientRect(),n=Math.max(document.documentElement.clientHeight,window.innerHeight);return!(e.bottom<0||e.top-n>=0)}var fe=(t,e=100)=>{let n;return()=>{clearTimeout(n),n=setTimeout(()=>t(),e)}};var Ie=nt(ye(),1);async function R(t){let e=Uint8Array.from(atob(t),s=>s.charCodeAt(0)),r=new Blob([e]).stream().pipeThrough(new DecompressionStream("deflate")),i=await new Response(r).text();return JSON.parse(i)}var Y="closing",ae="tsd-overlay";function it(){let t=Math.abs(window.innerWidth-document.documentElement.clientWidth);document.body.style.overflow="hidden",document.body.style.paddingRight=`${t}px`}function st(){document.body.style.removeProperty("overflow"),document.body.style.removeProperty("padding-right")}function xe(t,e){t.addEventListener("animationend",()=>{t.classList.contains(Y)&&(t.classList.remove(Y),document.getElementById(ae)?.remove(),t.close(),st())}),t.addEventListener("cancel",n=>{n.preventDefault(),ve(t)}),e?.closeOnClick&&document.addEventListener("click",n=>{t.open&&!t.contains(n.target)&&ve(t)},!0)}function Ee(t){if(t.open)return;let e=document.createElement("div");e.id=ae,document.body.appendChild(e),t.showModal(),it()}function ve(t){if(!t.open)return;document.getElementById(ae)?.classList.add(Y),t.classList.add(Y)}var I=class{el;app;constructor(e){this.el=e.el,this.app=e.app}};var be=document.head.appendChild(document.createElement("style"));be.dataset.for="filters";var le={};function we(t){for(let e of t.split(/\s+/))if(le.hasOwnProperty(e)&&!le[e])return!0;return!1}var ee=class extends I{key;value;constructor(e){super(e),this.key=`filter-${this.el.name}`,this.value=this.el.checked,this.el.addEventListener("change",()=>{this.setLocalStorage(this.el.checked)}),this.setLocalStorage(this.fromLocalStorage()),be.innerHTML+=`html:not(.${this.key}) .tsd-is-${this.el.name} { display: none; } +`,this.app.updateIndexVisibility()}fromLocalStorage(){let e=S.getItem(this.key);return e?e==="true":this.el.checked}setLocalStorage(e){S.setItem(this.key,e.toString()),this.value=e,this.handleValueChange()}handleValueChange(){this.el.checked=this.value,document.documentElement.classList.toggle(this.key,this.value),le[`tsd-is-${this.el.name}`]=this.value,this.app.filterChanged(),this.app.updateIndexVisibility()}};var Le=0;async function Se(t,e){if(!window.searchData)return;let n=await R(window.searchData);t.data=n,t.index=Ie.Index.load(n.index),e.innerHTML=""}function _e(){let t=document.getElementById("tsd-search-trigger"),e=document.getElementById("tsd-search"),n=document.getElementById("tsd-search-input"),r=document.getElementById("tsd-search-results"),i=document.getElementById("tsd-search-script"),s=document.getElementById("tsd-search-status");if(!(t&&e&&n&&r&&i&&s))throw new Error("Search controls missing");let o={base:document.documentElement.dataset.base};o.base.endsWith("/")||(o.base+="/"),i.addEventListener("error",()=>{let a=window.translations.search_index_not_available;Pe(s,a)}),i.addEventListener("load",()=>{Se(o,s)}),Se(o,s),ot({trigger:t,searchEl:e,results:r,field:n,status:s},o)}function ot(t,e){let{field:n,results:r,searchEl:i,status:s,trigger:o}=t;xe(i,{closeOnClick:!0});function a(){Ee(i),n.setSelectionRange(0,n.value.length)}o.addEventListener("click",a),n.addEventListener("input",fe(()=>{at(r,n,s,e)},200)),n.addEventListener("keydown",l=>{if(r.childElementCount===0||l.ctrlKey||l.metaKey||l.altKey)return;let d=n.getAttribute("aria-activedescendant"),f=d?document.getElementById(d):null;if(f){let p=!1,v=!1;switch(l.key){case"Home":case"End":case"ArrowLeft":case"ArrowRight":v=!0;break;case"ArrowDown":case"ArrowUp":p=l.shiftKey;break}(p||v)&&ke(n)}if(!l.shiftKey)switch(l.key){case"Enter":f?.querySelector("a")?.click();break;case"ArrowUp":Te(r,n,f,-1),l.preventDefault();break;case"ArrowDown":Te(r,n,f,1),l.preventDefault();break}});function c(){ke(n)}n.addEventListener("change",c),n.addEventListener("blur",c),n.addEventListener("click",c),document.body.addEventListener("keydown",l=>{if(l.altKey||l.metaKey||l.shiftKey)return;let d=l.ctrlKey&&l.key==="k",f=!l.ctrlKey&&!ut()&&l.key==="/";(d||f)&&(l.preventDefault(),a())})}function at(t,e,n,r){if(!r.index||!r.data)return;t.innerHTML="",n.innerHTML="",Le+=1;let i=e.value.trim(),s;if(i){let a=i.split(" ").map(c=>c.length?`*${c}*`:"").join(" ");s=r.index.search(a).filter(({ref:c})=>{let l=r.data.rows[Number(c)].classes;return!l||!we(l)})}else s=[];if(s.length===0&&i){let a=window.translations.search_no_results_found_for_0.replace("{0}",` "${te(i)}" `);Pe(n,a);return}for(let a=0;ac.score-a.score);let o=Math.min(10,s.length);for(let a=0;a`,f=Ce(c.name,i);globalThis.DEBUG_SEARCH_WEIGHTS&&(f+=` (score: ${s[a].score.toFixed(2)})`),c.parent&&(f=` + ${Ce(c.parent,i)}.${f}`);let p=document.createElement("li");p.id=`tsd-search:${Le}-${a}`,p.role="option",p.ariaSelected="false",p.classList.value=c.classes??"";let v=document.createElement("a");v.tabIndex=-1,v.href=r.base+c.url,v.innerHTML=d+`${f}`,p.append(v),t.appendChild(p)}}function Te(t,e,n,r){let i;if(r===1?i=n?.nextElementSibling||t.firstElementChild:i=n?.previousElementSibling||t.lastElementChild,i!==n){if(!i||i.role!=="option"){console.error("Option missing");return}i.ariaSelected="true",i.scrollIntoView({behavior:"smooth",block:"nearest"}),e.setAttribute("aria-activedescendant",i.id),n?.setAttribute("aria-selected","false")}}function ke(t){let e=t.getAttribute("aria-activedescendant");(e?document.getElementById(e):null)?.setAttribute("aria-selected","false"),t.setAttribute("aria-activedescendant","")}function Ce(t,e){if(e==="")return t;let n=t.toLocaleLowerCase(),r=e.toLocaleLowerCase(),i=[],s=0,o=n.indexOf(r);for(;o!=-1;)i.push(te(t.substring(s,o)),`${te(t.substring(o,o+r.length))}`),s=o+r.length,o=n.indexOf(r,s);return i.push(te(t.substring(s))),i.join("")}var lt={"&":"&","<":"<",">":">","'":"'",'"':"""};function te(t){return t.replace(/[&<>"'"]/g,e=>lt[e])}function Pe(t,e){t.innerHTML=e?`
      ${e}
      `:""}var ct=["button","checkbox","file","hidden","image","radio","range","reset","submit"];function ut(){let t=document.activeElement;return t?t.isContentEditable||t.tagName==="TEXTAREA"||t.tagName==="SEARCH"?!0:t.tagName==="INPUT"&&!ct.includes(t.type):!1}var D="mousedown",Me="mousemove",$="mouseup",ne={x:0,y:0},Qe=!1,ce=!1,dt=!1,F=!1,Oe=/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);document.documentElement.classList.add(Oe?"is-mobile":"not-mobile");Oe&&"ontouchstart"in document.documentElement&&(dt=!0,D="touchstart",Me="touchmove",$="touchend");document.addEventListener(D,t=>{ce=!0,F=!1;let e=D=="touchstart"?t.targetTouches[0]:t;ne.y=e.pageY||0,ne.x=e.pageX||0});document.addEventListener(Me,t=>{if(ce&&!F){let e=D=="touchstart"?t.targetTouches[0]:t,n=ne.x-(e.pageX||0),r=ne.y-(e.pageY||0);F=Math.sqrt(n*n+r*r)>10}});document.addEventListener($,()=>{ce=!1});document.addEventListener("click",t=>{Qe&&(t.preventDefault(),t.stopImmediatePropagation(),Qe=!1)});var re=class extends I{active;className;constructor(e){super(e),this.className=this.el.dataset.toggle||"",this.el.addEventListener($,n=>this.onPointerUp(n)),this.el.addEventListener("click",n=>n.preventDefault()),document.addEventListener(D,n=>this.onDocumentPointerDown(n)),document.addEventListener($,n=>this.onDocumentPointerUp(n))}setActive(e){if(this.active==e)return;this.active=e,document.documentElement.classList.toggle("has-"+this.className,e),this.el.classList.toggle("active",e);let n=(this.active?"to-has-":"from-has-")+this.className;document.documentElement.classList.add(n),setTimeout(()=>document.documentElement.classList.remove(n),500)}onPointerUp(e){F||(this.setActive(!0),e.preventDefault())}onDocumentPointerDown(e){if(this.active){if(e.target.closest(".col-sidebar, .tsd-filter-group"))return;this.setActive(!1)}}onDocumentPointerUp(e){if(!F&&this.active&&e.target.closest(".col-sidebar")){let n=e.target.closest("a");if(n){let r=window.location.href;r.indexOf("#")!=-1&&(r=r.substring(0,r.indexOf("#"))),n.href.substring(0,r.length)==r&&setTimeout(()=>this.setActive(!1),250)}}}};var ue=new Map,de=class{open;accordions=[];key;constructor(e,n){this.key=e,this.open=n}add(e){this.accordions.push(e),e.open=this.open,e.addEventListener("toggle",()=>{this.toggle(e.open)})}toggle(e){for(let n of this.accordions)n.open=e;S.setItem(this.key,e.toString())}},ie=class extends I{constructor(e){super(e);let n=this.el.querySelector("summary"),r=n.querySelector("a");r&&r.addEventListener("click",()=>{location.assign(r.href)});let i=`tsd-accordion-${n.dataset.key??n.textContent.trim().replace(/\s+/g,"-").toLowerCase()}`,s;if(ue.has(i))s=ue.get(i);else{let o=S.getItem(i),a=o?o==="true":this.el.open;s=new de(i,a),ue.set(i,s)}s.add(this.el)}};function He(t){let e=S.getItem("tsd-theme")||"os";t.value=e,Ae(e),t.addEventListener("change",()=>{S.setItem("tsd-theme",t.value),Ae(t.value)})}function Ae(t){document.documentElement.dataset.theme=t}var se;function Ne(){let t=document.getElementById("tsd-nav-script");t&&(t.addEventListener("load",Re),Re())}async function Re(){let t=document.getElementById("tsd-nav-container");if(!t||!window.navigationData)return;let e=await R(window.navigationData);se=document.documentElement.dataset.base,se.endsWith("/")||(se+="/"),t.innerHTML="";for(let n of e)Be(n,t,[]);window.app.createComponents(t),window.app.showPage(),window.app.ensureActivePageVisible()}function Be(t,e,n){let r=e.appendChild(document.createElement("li"));if(t.children){let i=[...n,t.text],s=r.appendChild(document.createElement("details"));s.className=t.class?`${t.class} tsd-accordion`:"tsd-accordion";let o=s.appendChild(document.createElement("summary"));o.className="tsd-accordion-summary",o.dataset.key=i.join("$"),o.innerHTML='',De(t,o);let a=s.appendChild(document.createElement("div"));a.className="tsd-accordion-details";let c=a.appendChild(document.createElement("ul"));c.className="tsd-nested-navigation";for(let l of t.children)Be(l,c,i)}else De(t,r,t.class)}function De(t,e,n){if(t.path){let r=e.appendChild(document.createElement("a"));if(r.href=se+t.path,n&&(r.className=n),location.pathname===r.pathname&&!r.href.includes("#")&&(r.classList.add("current"),r.ariaCurrent="page"),t.kind){let i=window.translations[`kind_${t.kind}`].replaceAll('"',""");r.innerHTML=``}r.appendChild(Fe(t.text,document.createElement("span")))}else{let r=e.appendChild(document.createElement("span")),i=window.translations.folder.replaceAll('"',""");r.innerHTML=``,r.appendChild(Fe(t.text,document.createElement("span")))}}function Fe(t,e){let n=t.split(/(?<=[^A-Z])(?=[A-Z])|(?<=[A-Z])(?=[A-Z][a-z])|(?<=[_-])(?=[^_-])/);for(let r=0;r{let i=r.target;for(;i.parentElement&&i.parentElement.tagName!="LI";)i=i.parentElement;i.dataset.dropdown&&(i.dataset.dropdown=String(i.dataset.dropdown!=="true"))});let t=new Map,e=new Set;for(let r of document.querySelectorAll(".tsd-full-hierarchy [data-refl]")){let i=r.querySelector("ul");t.has(r.dataset.refl)?e.add(r.dataset.refl):i&&t.set(r.dataset.refl,i)}for(let r of e)n(r);function n(r){let i=t.get(r).cloneNode(!0);i.querySelectorAll("[id]").forEach(s=>{s.removeAttribute("id")}),i.querySelectorAll("[data-dropdown]").forEach(s=>{s.dataset.dropdown="false"});for(let s of document.querySelectorAll(`[data-refl="${r}"]`)){let o=gt(),a=s.querySelector("ul");s.insertBefore(o,a),o.dataset.dropdown=String(!!a),a||s.appendChild(i.cloneNode(!0))}}}function pt(){let t=document.getElementById("tsd-hierarchy-script");t&&(t.addEventListener("load",Ve),Ve())}async function Ve(){let t=document.querySelector(".tsd-panel.tsd-hierarchy:has(h4 a)");if(!t||!window.hierarchyData)return;let e=+t.dataset.refl,n=await R(window.hierarchyData),r=t.querySelector("ul"),i=document.createElement("ul");if(i.classList.add("tsd-hierarchy"),ft(i,n,e),r.querySelectorAll("li").length==i.querySelectorAll("li").length)return;let s=document.createElement("span");s.classList.add("tsd-hierarchy-toggle"),s.textContent=window.translations.hierarchy_expand,t.querySelector("h4 a")?.insertAdjacentElement("afterend",s),s.insertAdjacentText("beforebegin",", "),s.addEventListener("click",()=>{s.textContent===window.translations.hierarchy_expand?(r.insertAdjacentElement("afterend",i),r.remove(),s.textContent=window.translations.hierarchy_collapse):(i.insertAdjacentElement("afterend",r),i.remove(),s.textContent=window.translations.hierarchy_expand)})}function ft(t,e,n){let r=e.roots.filter(i=>mt(e,i,n));for(let i of r)t.appendChild(je(e,i,n))}function je(t,e,n,r=new Set){if(r.has(e))return;r.add(e);let i=t.reflections[e],s=document.createElement("li");if(s.classList.add("tsd-hierarchy-item"),e===n){let o=s.appendChild(document.createElement("span"));o.textContent=i.name,o.classList.add("tsd-hierarchy-target")}else{for(let a of i.uniqueNameParents||[]){let c=t.reflections[a],l=s.appendChild(document.createElement("a"));l.textContent=c.name,l.href=oe+c.url,l.className=c.class+" tsd-signature-type",s.append(document.createTextNode("."))}let o=s.appendChild(document.createElement("a"));o.textContent=t.reflections[e].name,o.href=oe+i.url,o.className=i.class+" tsd-signature-type"}if(i.children){let o=s.appendChild(document.createElement("ul"));o.classList.add("tsd-hierarchy");for(let a of i.children){let c=je(t,a,n,r);c&&o.appendChild(c)}}return r.delete(e),s}function mt(t,e,n){if(e===n)return!0;let r=new Set,i=[t.reflections[e]];for(;i.length;){let s=i.pop();if(!r.has(s)){r.add(s);for(let o of s.children||[]){if(o===n)return!0;i.push(t.reflections[o])}}}return!1}function gt(){let t=document.createElementNS("http://www.w3.org/2000/svg","svg");return t.setAttribute("width","20"),t.setAttribute("height","20"),t.setAttribute("viewBox","0 0 24 24"),t.setAttribute("fill","none"),t.innerHTML='',t}X(re,"a[data-toggle]");X(ie,".tsd-accordion");X(ee,".tsd-filter-item input[type=checkbox]");var qe=document.getElementById("tsd-theme");qe&&He(qe);var yt=new Z;Object.defineProperty(window,"app",{value:yt});_e();Ne();$e();"virtualKeyboard"in navigator&&(navigator.virtualKeyboard.overlaysContent=!0);})(); +/*! Bundled license information: + +lunr/lunr.js: + (** + * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 2.3.9 + * Copyright (C) 2020 Oliver Nightingale + * @license MIT + *) + (*! + * lunr.utils + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Set + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.tokenizer + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Pipeline + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Vector + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.stemmer + * Copyright (C) 2020 Oliver Nightingale + * Includes code from - http://tartarus.org/~martin/PorterStemmer/js.txt + *) + (*! + * lunr.stopWordFilter + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.trimmer + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.TokenSet + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Index + * Copyright (C) 2020 Oliver Nightingale + *) + (*! + * lunr.Builder + * Copyright (C) 2020 Oliver Nightingale + *) +*/ diff --git a/docs/components/assets/navigation.js b/docs/components/assets/navigation.js new file mode 100644 index 0000000..f2081cd --- /dev/null +++ b/docs/components/assets/navigation.js @@ -0,0 +1 @@ +window.navigationData = "eJyVmktz5DQQgP+LzymWDewCuWUnE2rYDAnjhAMUB43dcURkSUjykKkt/jtlex6S3Gp5r9OfP8tW69WeP78UDt5ccVVcX14/Mvv6YLgy3O2Li0Iz91JcFSC71r6Lwt+8uFYUF8Url3Vx9eN/F7GndMx1NmEZg2nH0hhlFqqG+PpTIH3tnWruYAcivvT4e/rKNVjLGtgoMbmvFyKuVzWIBdNsywXyBqNw2nO/tWB2zHElH/d60pYonO8JVb2CO1sqwayFc18M4dDy/jLw1Ew7MCtpHZOOD3ceOgJxplDS34B0N9xWagdmX4LZ8QoQN4aRXulejNK8OrQKUUYEadP8M+xLZ5iDZo+4gnjG9FsHHTzyFlTnUq8SoUjr5jFlOkTIqzv3smaSNehrOgcpx4KJqhPMKfOolJhqwjhpUnIHxg7pk0rfKUMZbwB0CfCaTIUIoFw/Q8slT5qCMO2RYHh137/edF5h1MR6MeLFVVGDNlAxB3Xh3Wola3iD+uZT6ZRhDSQbnwCpx1jJNbTK7PNqjKPMd3fr0hlgbSoHIoB0qYqJcV6q4FNn94nBgnNZ84NRO16DWSj5LHiVGtRplr5Dg47L8XfqynWlF4KDdAslnVFCYBoEyjiTM8U5ljE8GPW2x6cJP0pZvHUwlR8ThPQJwVqWTN8gTHo0yOtV2uOHc56N6hwY0hUglO9hWQ5L6FRzjJBXf14sMzPVBCF9h0FwSJdVq5FUQCDK2W8rIZmbfpS0dJptmYXcfIZzlLnfbt2AgGbMyNRGB8VIr1JiAw23ziDd4kdJy15DnRpJXpByPK3KvXXQTgXHCHm1fJXqX3ns9cQcilGU9Y+9dEpzlsleFCO3TJfXw6hZyWd11nHpwDyzatxgn4BQdPnh43SfnnL0sRmXL3fB2J46BmCG6JaLIN+nppGYoVqDYzVzjJIdmRm6DdhOkM84EqQqOEX0SzBvcCMCZsW3XDKxAauVtJDWBlhWeq/7ecCmdQcgK3oAY5VM9IYH5EVGaaI9QzgrGebjtGQIk5Lo8Ea+Jpwl9cYdt4G48hyfqaGSLaYyytIxWTNTH+oSKWeEkdId44JtBZzmVRmsJr4YRSn5gglBdY8XJzXekW+yzPu6KTdbS7xQhCO1BpiD08T0TwcWn7swkBJHR1XqxeIoJV++QdX1VH8Y6H/CtDE0S0guBhOKUo7rD/XcAUGpgsM6ZcRASrw69adWljuVGEtTjJY2wzHN4Al6DtMSdB8UeJJboEjlD4nck+IsqffObzk7ipLy6HCBayOIFA4rVq6dEUQK+537ODBUonk+QauwzX1gSm3wQ9EvVsn77d9QubJ6gRYfzDFECe/u1uTE4MVJzVAKIVZYH6BEY0fXh4F+XVVgbeLt4ygpP5VHiJbGUEa4Aas6k9ikePGZmkdotUhtzBAuo+1Pr2Dij0Gh0mcyuj7fb+CZS94P9JQwpEjluIxTE3+IULLh5Eh0rBcnNeeZDNec4zM1xIluQs1UUpPmFCOlfl2N6ggMJMV+oY0UI2BOHFTdcnIMJm/QOd25B2Zs6g17ACUaiLofDv0OG1WFCCk7lveIFI8YUmdUq90n0YE2PFG5iJi8jtq0BkReRWV4QGRUw/ZhUkQMZT4zR5dfRFCSUm+AWSW5bJay4RKf/iOG1HXS8Rb8Tx2JlqIkpS4da6DUUPFnXo09gQ89DKTFeME3UKZrvbGs/y6VLsp5cVIzFE3Hxt/vwBhe432DgXPF/ZoudqlHRsC54v7lZ6U9NFdop2XuhNXiJe9QHVbaiSTFwJx43NCQxcApRkpfDLCaaqUHzBIl58qAIFXDx4VkWfYczkmI48Q5nJVEHx9iCfIFIpQ86XpezQYDKXHwdYHoQoT7ulJg+O8lt9doJXD6R6bLb3/64f2HS9w9DilCOwI5460yLXMOEr4ojNpyf3Toj55xKo32cyTXzNORJO6nURSFc7bhwF+yHZfNtOgyGhEkbz0tH/3JPd7hH70IlDV7k+gaTAPJVqfA3B2epO22tjJ8C7edrMKDzuhGkK9I10OSx3mwY4b3ZWtsQGCZ8R05GmbZfZSQ/77clKv7XzHZIURcXI3lY+xzxfPh3dl3EygUfvzeEzb9P46Yg6en1Q3m8uMTzV//Azipolk=" \ No newline at end of file diff --git a/docs/components/assets/search.js b/docs/components/assets/search.js new file mode 100644 index 0000000..32a4827 --- /dev/null +++ b/docs/components/assets/search.js @@ -0,0 +1 @@ +window.searchData = "eJy0vV9327iSr/1dkttMj4i/Ut+5E3e3351OMrazZ+b0muXFSLTNE0nUJql0svea7/4uAKIMFn8AQUnnzomIqiJZAIF6CoV/vaqrv5pXP//5r1dfy+3q1c/zN6+2+aZ49fOrK3Z1nzdfP9VlVZftj1dvXu3r9aufXxXb/ab5d/LrT8/tZv3qzavlOm+aonn186tX//umk5mpo9Dfb377PUHS6+fy6bkv7s2rXV4X2xZYBjW9//ifKYrW1V/n6fnj+t3N5z9SVG2KVbnfnKft8+1v1x/uU7Tt6ycjd7q2gQfctXm7b7BO91vq23979eHt9fv31+9Ghb1e5ttlsV4Xq7E7OFiH9X3849P76/skfdVmty7a8/T9enWTdHOPeXnmnd18ePh0+/G32+u7u3F15fZhV1dPddE05+j8dP3h3c2H38b17Yrtqtw+naPr9vrvN9eBDuyrqotvZTHag2Oa/vPq5j7prv7Ky/aUu3rpT9d1XdVvq1VBlB3/P7UfXb27+nR/fftw8+Hu/urD/c3V/c3HDw/Xt7cfb6OiX+erfNcW9UO5bdp825Z5W1bbh8JcFLyvF6uxLWZAMs749vru7ubDb0lmmKHJ+OSyaJpy+3SmBe9vr6/e/ffD248fPly/HfZ2qnxdF/nqx8Oy2m6LZazHj+n9dPPwH5+vP18/3N/8cf3xMx2Wqd5d+fCPfbEvHtpyU1T78Ng8ovftxw+/3vz2+Tb5rS+r7WP5tK8v8Lbffry9e7j+r/vrD3dG+e31f3y+uR174suqbh6K722xbYwBdfGPfVmf/tytDZ+ub/+4uZtqxK6oN2VzESveXb+//s29AjjsE/WrYl08uRcwMvqP6f386f3N26v764f7q7u/PdyM6d3v1uUyb4uHNm++PpQn6zUv/fbD1fuHu+vbv9+8vU5xPPPO622+fmiK+lu5LM7zvd+vr97f//7w9vfrt39LeubPRb5unx+Wz8Xy65lP/ff7+08pd/zctrvz7vLmw9+v3t+8e3C9PK6t3H7L1+XqwXXwczWafnR9NzKKdSpN9ymak8ew9+//MN+Mv9+8u75Nea7r9cZ8L76Vq6I+7/m+//j26v3hy/n2+uGXz3f/PaK6WubrwxdzWTx82Tc/ztN9vG/zit/fvB154k7/8ebNu16Xy5OfvB01P/z2YL5eXwu6rCO67WC5fXow3y538Vk6U3y6U3meT3+4vv/Pj7d/S3GtbdH+VdVfz/OqDx8f7BDx+fb9iLbqwY4R5pLTdd3dv7v5MKqoaVfl9nQt96kzqm3Vnj+bMvpuzHLtj+sPSRpLs2DbFNszdH78fP/p8/3Dp6tb654p35Rq3+727cMur62XnvdV+fT+6sOHVM27db7dXkDn7cc/Pt0/XN3dXf/xy/v/TlNdV5td+2C0bb6sf1zGgl9vr34z7/rBvPlfP37+kGbEY50/mbf+YHzgsdpvz7Xjt+sP17fpE7mDGU/FtqgvMZ87WHF/e/Xh7v1kM9o63zbrC9phpwKTzbBzgktYcXv96ePdzf3H2/9OGbrrYlc1ZVvVP84bvQ8zn7R13GHmc+4q7u7q79dJj7jJvxVnPlUzZb++Te1oZrJe1Of3r7v7j7dXvyUtFJq2qvOnM9cHd//94f7367ubu7TH+mPbPhdN2Zz5bO0qLPHJ2iXY2c/1/ncT70jW+WzCHRfQmtI3zuwTBx0pHnPQdJ7H3H/8+P7h3c3d1S+j7tJW1fphVTb5l3N85aDv7ce/X9+mfXo7vcvqW1Gf++W1+q//6/rt59TQkVVffC+W+/NjR0R78t2/qL/A3af2GqP4/D5jNN69/f36j6upH1ZrQLN8Ljb55b6unz/87cPH/0x68fvt123115lvvNPXrXjTVHZL3dO13n3+9Onj7f31OzetMn+PqW72u11Vt8XKTanM36fq9950woP2Xu70Z/3CFt5XT++Lb8WaKOv+O5UsvLv+5TNdoPdkvF4VX/bhZfnRDBxDBI+jLz3+COLSbz78+jEqvNw+VifK/s+rW7re7sv+K6/DS20g++XN/VE0Tf5U3FZryoW8X5LJ0M2IjNd5GTTTtyQww7q7v6ase6Ch+dG0RZhzj2oxo+aYDjM8nq7h891gLBpo2DeREQhr8N5ptSrWb/Nd/qVcD3MnyK/J9Pzju+sESa+XjjAGLCeW4fXQFR0DoKI6Dw8EaXqur+4+fhjSV6ytyJtqGyOwSTrv7m+vr/5I1Nm0dZFvztZ5f/1f9AME1bXF9/BXJ02TmXF8vkvyEzvF2Ddn+srfbwyES9H3rTTg7QRtL/3q4xezOLVfy/sfOzpekl9T+xX6KiFRIx8nahvOELkxCO32+u7Txw+DtwSVPpYGoNVFs6u2kXeVpP3mw/0wewhqLbdtLHsoSZthPK63PVwP5ttQq6E8rss9FJFZ92TtqS/Y13/+u/Ys+OP6/urd1f3VRCM2RZuv8ja/mB1391eDqfCYEU2bR+bCSRaYOHeKVhPiPk/T3b0h458/vbu6T+pdTWvQ+H63ytsz+9Yx+pSktgs+nafz/vePn3/7/T5JZftc7Z+e23M13ty/T3qwbdmuz3yi9lv29uo9nQxifeZjtszX4Vlhus5jjCJZ8TFEcYp2Nsy4rJZfi/ao/SDx33u/Rr9uMmNHmctq27T1ftna8WxM4uv+5fFUN2fmi1o2Ey/3slwXeX21Xt/tvzTLutyZW2+SLDAN8/W6IQ1fbGmb1b+Vzb+V2+eiLh3/m2bbU9H+Xpqg848Ug56K9vl49RlPZFu15WOSxuOVF7xnJ9Nc99bLdU00xUSu01NkU+2oi3y6FcdGF7HhncvLmmrFymt2ETuuv7n51gQbim8JCd6p+n/tAosTDEhMY0604LP9CE80YX9sdIYNh4HmS5Gi27/4vN7ZG/hdYu6Nn5d7fZiCEpNCV17mgxCVnvZxCN6Kd+szJjx7VuDJjxmymvACplq0Ktq8XIOPVdyol2b/j+yq6vLJLAdP8YzXXePhyuZcG3udqa3u2tpFTCaZ11ZN1+6CT8/vYibp/F1H0u5cRurQSnTVZbpWUHJat4Lmx+Zeb/Pl85QbdBOv5aHVBazosKVtBHpT2JKuZd61vIA1j+V25Sz55ccxzFQWk+wyMpxNX34s+zIuZOF9tXNG/lrV5qsx1bq22jkDH6u6de1Ps6zXdbbtc13tyuWhzw2NIhdcpsMgoWl9hdobGE870vjB/DNNfddk65pM1t/vpm69mnTbsaVt7H7917gr/1b8uGvrvC2ewDqk9/NlXuFQZNoL7FsaXsVd7dvn34t8VdSgHwPlT0Wb79vn52OTM/U73dh/sHqnOu4+SdrL5rNJQTVPoKrLf9rvnzMnyZSy2Zvmud/8uWs+0S7iZP9hdjnduwSdwFQFXHQph8OCU91uaPukWWtE/ZQJ6wQ7gnPVoCmTp6kTrBmZoQZtOnFyGrcscV4aNGr6lHTkSfnd5PY+8IwOP1ymO/jC0rpAZ9cktydqIvx5TH7QnXsqkAtP0TLipj1dYdcc0Zjofj1l0OXG7sx3q337/Ee+zZ/QV+Dlt8s4F5GX5l+egWOBY/ehgVP0geouZuy3OdmC44c9QfPxk36uxtviqWzaoi5W3Rf2ZpWmvz62PNz+j3J1ljXP+Xa1Lm6LVVkXSxCVpDa46+uX68/Q3ITnp0O1TfNy8ck6y8ZcVGxbu08WBCCp3rLJSYOTda+rJ7tFa0Rjd9k5elxe9riiWP52gqbOGdNfY9fiEu+yLjbVt2KKbnP9iZr9gfdtvl7u13lb1fcuNa2vuP/zRYZfIDJpBCaWBr6QLvU4Senx0nP0GYwKl1FIo7k4uoIK6uw5i6O2aSpfrp16l76TVNtvRd3YtVaA8Q4vuYyzYLFpDjO0+izkG7TlLO6bbmUE/oZMSyDA6foDGDikeyILnmrHIZV1ojmbY6tzn0YYvoUsmE7gotb4HfRdUezuiuJrKM5Jfr9I10Qyk/olNfaUICdUnhTjDGsfD3HiW45FOCP36r2+34pNuS1DL6/360Ve3VBi0ovrm3nKawOKk15aSPP4K0O3GnthwXvsva5tUZfLj2Z2FZyyoYsu9PICghPfIbA99lm8r74WW4zkIpaYlq1pGcdyU6wZiZqHjUmMnU+05W1X52OCGSO1QSZaYN/MjdsbNMEI+1qiW4qm2FEXj3XRPFtbJthxaNYemp1kh98lb7ar4nuxevfLnduRHRpLA9ddpGPGZCf1zdBNjMxaJxpymK1e1Iq31XpdLA+JpFONWfqNL2KTyXID66OoKcc2F7HgCSyRoupdg4voLrflROWHFhfR/o99ARYoUfVdk4vob6Y++easJ98fhP4oNlX9Y3QMQpddaAgKik4cgeAdTB+AImaMjz+TbYgOPyOmJI0+UywKDj5hQ0bHnin68dATVh4feaZoDgw8YdUj484U3aFhJ6x8bNSZoh0POmHd8TFnRLM/5Lx//8ed3e4UCMuR3y8yyCCZSaMLNfasaBy24qxQXKJ9kTgcNCoQhLuAJYGIHLRiYjhukgXuSrwVIGKM26gX3w6QaEc4Ggf1Tw/Fhe3odUdT8/LmUHLzl33zA4N6fNllOmdYdFofxXcwJasibsKEdKJptoQyMGLmTE0pmmZRPFsjZtdpaUWj1qVldsQMm5xaNP7EaPf5dAgIvj0UjI08PXjp5bpRWHx6V8J3M7k7RU2Z2qUm2RTtVhGzTupakyxL6F4R+87oYmNWTuhmEQNP62qjT7DX3Z5QvpX77wt1o6dJWVYHi0ITw8N5AKiP9PQcrzpFS1coKqxhtJRURHoRcNYX6aOlpGIpQSga7AsfKyUVkX2oFBWWPVZKKpyE8sdy93ZdFlsTVG9rsyAfPiJwTdRFe0PFl7wpPtfDQEVI6GvTYB8pdY0sjmApmFsTVG5axAtFTdDu6ltPUH5scLbuYtvs6+KtV2E70QbXcLw09wRbxpLlgrakJs1NsGVdNq3xiOFHNWiFadIempyvv8pX19/LxhwLdFc0DYqbhS2p8lVxaNwcG1/AJpjoFzEjmvA3QfMm//Gl+N1mgr7N1+sv+XK4eS1ohm3s0kiXL43PtsnWrrHcK90U26bKXZvzxw1brmDCsNFdf4pm8i0IJYK//HSRyQkRlzRB8awb2zz6LS/XpurunS1LDft6T/1x72jXsDk2PNWWp6L9WLtqFYdRONDVaWZ2Vbv3ufRbnWqFifKW+br8J3Snfoayf+np+po2X6/dc09Qaa9uuqtP1do879tV9df44/UuPFXXfjvtHo/Xn3KXpHN+qqvvP0LzmeOPl+qgfYGpXfTFxmlZwkOFIznCAV1J2bpDZWO5uinabJd3K9v7UGryULPt8q7VaI5yohXONQNZMtAC55wjOTKJ2s3P74pHO57gIW+o39z5ym8zzb+8buIVzQpwmcEVF+kwWGpSrxmafBadCVlyFp9JtjFCaAKGJSRKJ2sPUJmA5olcZqIV3uXTDKp6Dc98ImE6E7BhOp+J2dLrmut1vslDqRm9Xy/TJQcS07pjz8xTUm2B4qRU25Dm8VRbdKvRwoYpmoLTKqBtdGYVfKq+g+yK7dVN0EH8Xy/jIAOJaQ7SM/MkBxkqTnOQgOYEBwG3GnWQ0D2S13Vb7duijr2y3hUXe21Dqcmvrm/yqa8PGJD8CkMWpL1GdOtjrzJ4z97r/HR9d/WE0gi6Hy7y8nrCkt7Z0a7AgzqcCT2i6eWqZC29h/O3t9fxTQeDKy7zuKDUtOc2MPm07P6ACYmp/clWjGwgD1iRuI082YqxWHXAjNRIdbIdeJN3QHt8q/cUnSgOHFYaiwLHtPY61mHQPAQ/bja74agHrrlM5wrITetewPBIBwt8IYMmPNk67oc2F7Ggi212zUBPjxnTNd95zU+xy3/5d6aUeijk7P94kdc9EJj0nns2RjOh4UYtoHS8ZGKKzsPBchZmmcJ/9sy+BPWHdpZomYJ/XbvTLSm2Jxniml3QjqeivbYyV5NteSpaZ87qsvY4A1wk7u/5ep/iHyYcZpu5cNy3Q7PT7Sgb8zwOjybBABOMqdbFNn5uYYpmAyyPj+BwUs2YdtPmeP/R021SLDAnodrrbh7/qFblY5n0BEwre8xD+bh5aXWGFUVrJ5f22hT9ResqcrYxsJeo2ffBNN2++03V3hve97vcZHOMbMrBl11myA+LThv88R1M3ZQTNWNsU84JNkQ25YyakrApZ5pFgU05MUNGNuVM04825cSUxzblTNMMN+XEVEc35UzTjTflxJTHN+VM04425cR0xzbljGr2hxzvfAYTjg5U7IZXXWTACUtOGm+w+cEI0XZZrGHF55gZtlW0zvM0K56L5Vd7WEGbt/vhoiJmimlqLGm6phewpztmY+pz6dpd7sn4lkx6Lr4pF3oq7tALe2pHXW1ui03VFtNfmJNiz/Goq01tpZz57nqdt6rWrqQhGLr8Hy/TVanAtB7q2zgyD8CJhkDvYQoQzzJM0eyv81O1+4v7i1hgVxs2nyLpqR/wf/HS4nTtXV1AmCQzVN1dHs34TdG7307U/NLgwrpT3nhf+eT33euyP3bFKpBo4f12mQ5L5KX1V8/As9IqhtpHEyom2hFJnRgoT0iaSNAYSJcYaAOJEhM1hdMQBspwAsK4Pt8tP9/cdSdK97V1P1zEIXvCkrzxaFdk/I6e59dXaYZulttpQnf5yXoTCk0OlC+9NudbMLahfqB+vd64fczn6x5PGxto99J0puvvOev267b6a9uFzfGeOnTRZZw4JDjNoZHtU7ZYxtRP2Fw5xY7QtsqwKVM3VE6xJr6VMmzTaZsoRyxL2z4ZNmryxsmxJ+V1k//zY9tWuzKPY3h41UU6SlhyUk/B5semJJHyfzFbIvX/Ym9ikn0jKQMR8yJpA5e0LhDujhsGIt6XtOl6+62sq+0G5djEDSt6LS/gX9EShnFbcA3DSz6n7vqT3uE/D7+O0ItJNpXNu+Jbsa52U19d2ax6DS9iy6e6Wu1xcD9qys5vdwFLouUnI5YE609ezIceq/rEF/ZY1Rd/Y49Vfdore6zqS7+zx6q+a/Mn9FGPG9IcW11m9HlXPOb7dXu3rHbgrJZ4F1+5tk3X9oLj4fV2tavKyeOz9eXipe0FLPqWr0sTbD19MOwkXGpElC9H3l+xK8uze5+PctsW9WO+dGcgH3+Pzr16M2GLvG9WSQJf24vL6CnOLybGFPYyfMdVRpN7k5WaCMYEpa27/AylL9mJ/iAU10zbnK5+ic5OjSpPOyk1QXVBe3RU7WgfTlHZ9LlKVOEIPQmoI32xh7r66sxP6T2w20fv1+sIyHvdXbuPlOrobAsuxHfFdlVsl2G3eNFHLj5J4cYmVbb5qDLvwpMU7fIfJo9pVM/LdaepqcuqLtsf43peLjxJUV00+3WoD72oOV52kpKm2tfLor8HIaTJXZs/xWZpY+pi3dTTNNpDY0ravH46JH+NanLXnnVPJhQc/IL6mpqv8W9nVIlND0tRYy+cpAiMbP3alkNd9vf0Mc7WvIx8f/siX9vLx76/L2aePvB4OlNHn6jKXV18K6t9czfm5p7irk2az0fVt/Fvkqc0fuR4iqpyY7IQNrtEfd7lk5QC3/y1XPsZjUO97oJ070wY0T2RyeP6wc7xgTfaq33N3gA83sFH1I95aE9vkmvGFXqDcvL9eoPzufdrHH5kAOprbr6mDEAjSscH7Z7SxKF7oBR0kj/GB7/ukglT1WqzM0miq6vYt6En9/WxTT76gT3aHFRf18Xaroyiz5QacGw1/mhHTbBlgibdv2tx/t13CWpTlB/bnK++aNpyY0S9dS+0rLZ/xMaPviHH1stj683ogDJmkque1BarX2JDd9+QY5svo+P3mPp13rSfbXJeujOaNvtjm7PUb/Lvt0Vbx5dxfe2b/Ht9bHKWciPmx9tqH50k9pXbJstDk7OU28pvk/rBocX5vaDNn9If9+Hi8xS6I+ondLVDi/O718FPJzzmQ4uTHjP4ht2OLYDdBenfr5EPoifudcpS4GBfSNm+zkdHyZ7KQ4PxNxdX3C+5G9cZL76bpC5hmeVrTF1nxZU2+2Wv/kBc58vV01T2fNLMQt8dahb+IGTAVw+umxIMXD4X9+064DQh2a9tu7Zdx3wH3UDId7vLBmwmyZpj8/HQ7gSj3OZIk5vho7Qkg1zT5bHp+cbEx+WgIQmDc9yIgUv+avKRbotmV20bvLoZXJXujtG+jeUmdPCh2eEI6NTbeu21OUH94PF+JJnJ1ILD7+mP9LGql2SbQEzma3t9PGW8Z2hosrrefMrrfJOodb3e7LrLT1dqXLguV8Uf1arAcGOguGuyOTQ5XfmuqJtqG3bdntqXi89QWFebXXtfbHZrs/cZLwqGmm2r9tAqtkJNM+F4GkLk80QNsG1GUHWKepcYnKb2eO0Z6myC7yf7ABOV2ha7rsUk1YOh4dOIgx1+Tx8atiEqTqW9jgNx37ior4YHg562l4snKRw+sLraRVSaX9MfVjUyML+Ie12NbBPxjAso62/sjaiK7+cdV3SoMB8ZPDxlh4vHxoyowmiIkugbj0+Oq6vzZWxo9LWZS89Stm+KOk2XuXKqqoF79wtNUG321wssVfuyRtapL2YF1JidJKHkFKLp5dIJynoPads+19WuXB52k8emVvjSCWlNu/IXcgZKovjX+a4cOw0ldCdhY/5W4OFjxJCvRWQwmWbEIYHvj/y7Tbqb/NhfHwRs8u9tJ+CShpl5U1HnrX/c0UTT2p6Iixi3Cc5cY/aMTF5HTej1mrrtjpODdrz8PKF37NtnWgEsItNmpW2O1wfuyrMzyG9edq5NUe+3u4AZ3h6yKVZ4zS5gBC2gGdM8VkYzQV2Dir7FdNoGF7jPFpUXiCk2DeqXBicr3pdkN2pM6b5suounKAz008jqi140oc8ymo48Kvd1zsYSkIdWxzJo31aBwTmg3rRZVrHROKLe3yL28NCG2P2I6mPLRAN+ernRyOA5/U3s2+dLvYp1/xjDceXHBmcq3ix3k298s9xd6r5jAR2sfDSqk6x6UL4zQflozc5k9XYwvsu/mfPL6B7McUNs68a2bl5an22SLQw1yYyuxZmq22DwFCseCZ5G1JLx/a7Nt6u8Xv1RNE343slVU7Jrtm0o6xKLff3SJHhz1OipsaeA5ngEKlltXa0nqT1cf65a4xIPJpn+ocTxgYB60u5iZoTcOW5E1KnDJvS8mhYovt6GJmrwygnzF1KIMk3067F6zIEbmDyNGDdhbCaBJeTDynn0oNZYHCRilmk6Gtkcezr9fKrGHqk81ZCyWR+aXcKI4EAUsSA+GI2p9/uDOREz8j68n6dt8KGleCMy7SafsTK8vp0ns6CB5kQUlKA8Gsce6B0PZKeoDMKnob44e0pQFgubD9SNxs1TFIYD50N9I5HzBHXh0PlA20jsHCvr9bm0sBC4LNoHezt781X3IcT9OiD7db5abV7aBe4Q2B8w46loTzLjqWjPNSP0wMNzWXDZRSazIbmjs1lkdzBxxf4ccOGQAYdWMW+eYkI4dyZiwUjyzAQDQnProPLo5HqC4ujgGFI+PkhOMCC2OSlswegepbgJvS5ms/6PeYX/2BcN7gvgumkzi8jW4aDwpH3E8BaCDCe+qThsSdIO4ymmlNvdftqjft01uYRyV5IqOH+M2NBreb4p8e0BYUMS9ghMMcNmkRVtIHQWNqPX7gJm1MVjUdfF6j6+NzhiUCchZcfwNNPCuw9j5oxsQpxiwsgm8LAVKTvCpxgS2l4RtiC6x2Ka6vAGwZj6kX2Ck0yI5RRHbBjNKR4xwv9wvSuK3V1RfB3P0cBXXipFIyI9JUMjcBuTEzRGzIjlZ0wzIZhoELMgnmcwaoD/3l3t8LLaRiIV9Jr0dx2bEUKp49PBgcHTF84BzSOr51TF4SU01juyjo6ohe8xtgF4cFH6mwxuLsIyRzYYDa0Np6+/DcXJA5rX6008SD5JeYXn7xHdrsX5qqe/SKN+dCGZbEK4UkBA+0i1gGTFSYMG2fuYPGqMKq+q9VSPM20u5HJt1ebrd9EdhEEj2nydsJUw3ZSEAZSYkDqCju5AHR9CyQbUxDF0ZP+pK7AQmfv0Lpiw9ydYuWQo8PXxYnwvfRtDw0e5KeG4BfR1156hrvlawpAL0Ha49BxlVZ16a4dLpynzHeK3YlNuy/E5MbruUjPioOyU+TC8gcmz4agJsbnwRPV/D2elR00YS1GfYkZwQh62ID4dH1Huu9vNcam2q5qydziJZ8jwqnQe4qqShGoYBiQfaplEa0cB0wMmuPMGp5rgWl3IBFOBdqJ+U3j2osqbX34EAy8jRjRffsRDL6cYEy5dNm7NyMzvFHPIacKTzBk5TjjdnJeD3KYY8nJw24km9EaEWP7ty6/pI0AkAZ2IG80/94wLWY9Oj+hpTD04IuVEhKjg2GEI/ZtKKBj9nG9X6+K2WJV1sQx04YEBrlH90ugMA8rm6qViMK5DBCwom5y0OsOEdfVUwk81UNxde566CgMerK+KoJ2gQt93feg38kHGl14sSyEmPylTIXQvp2UrRM1JyVhIMMd/Ed5xUSPvAV456TV4EiZqMC+i6rUO3Dy+nfCr8K7HryNiEzk56wyj/BfSJdRFknboNdPG9nDKKJRrh/aRfNGB0RH1NHEQP/agJV3z8Y0AMaP8B2531474Prlm2gOPbmOGol93LLQ5NAvcITU9MvGzs7Zw1mLQDDfdG8ldPMWQEA8ZtySaw5lqSnPai2ku+mKaU19Mc+EX05z8YppLvBi/O8Izd30z/AvSw0DN8rnYwHD/UODr48WBW+nZGHik7hRg7FpDjS9XT1TZe3TgCNue2sRjbMfOco3JTDnP9Wb6ga5RlSOHuqaoG57qGtU4frJrSKn3vv6/ptp+/PJ/i2V7F3ROes2UrSGr0sw48rWpsVHUoRNLoIbXL613fmt8r4MbCSfPTzbkgurr4h/7ssbrOazca3Ge6tAOGaw2mvsSUek71/v3f8QYp/dzukvZlL5woQsq06UAjtS18O0MqK327TS9rsH5irs55m3+1+dQPvdAedeozv/aN7GtmQkGNG21uy3yBq+XBqrN5XV3+clK2+dy+7XcPk144F2T8x+5Sbu6r34t68a9cExphwaUm6KtHk0za0ME0aYYYWjvb8W2cLz3vtwUqXaYlk/HlsasM00Jc+Kh8hFCjNX1Bg27pz08GfV/Tx821uYcwiRxr7tLAzfgmxfJSS2/p2k7XjtJnf/A3NJydVhTX9mCuHjaiq+8yE7PiOjRnZ6BGwh+QddFjiuHxox4aXaiEb1HvtwdFvRhP6XXpD/mpBq9UPyE+ryDWwilhdkCu7DzYxNeGkxWTB7xbeGykAO6u58nPNjCTJh3odgflfm6f33wdo52hoCz+Z4EJl8Dnebi6NwrQWFop+1AWXR7bYKifV0m6XHXTVETcIWuBuuI1u6y/xeu0ZM91UWO9p/nKn0bprjMmAEJrtNXnupCY4r3dXnKyzWu1b60O8UM4mp3Rf2tqMOwnFwyYeUSGkQH4l5HJlDUwtB8J2/Mqe3bYhmAh1CvabX0Wp1twnUoqTioPp5WnKg6nNkK9Y5kNyQqtYmloYNToF6bVho9NyWsmnitCc29Kx7tITjBIax/0SUHRyA5dWgklseW/eEQVcAE22okkJpsQmRoRLrHBsY0pS6MMPnGXbMz7rznXg73RrIj+1dMWFA8tkV9H9vTCyS/tq3G9/QSswMmfCkeq7qYbINrdikjgtm8SHU8nTdNodkQnvomX3cXT1Tou5A9Bj28VvJ+Tnee5boMHjlIBb52F0e+q76FUYV3xbLGbCOgtOkanKz4qc7Dh6wOtNqro/PBBJXNstphDxnoO156sjIbLostdgc6bYvRNW6q6tvisS6a51/2j49FjaNs2ILaNfxiG0aCbOmG2B2ckbS3kB223VjmW6oZ97HtqtiC8a2qWHlvkIin5ng/TxgkwtVKqLzRKiW+fZPm+ANNsXFoXEms/shA1eh2sQSFsf1aA4WjO7VSFMY+x0ONo1/hJJUtLqoC1LWRaiopqsLx9KGykXh6irrQh2OgK/rNgIoC3Td8kPPgoktOFrHw1Pni0P7Tp4wBS1JnjcmmmFeGR2lsQHf9dLWBNx3JEBxeNSnhYywrMiA+OSMS3ETAmLpYVvVYd+3ZcGxximr/Qa/X+SYf352Grpu0Oy2wLSwod2xbGDQ8GF1w51eEtmWFjegOrojuzppiSmWvjWzVC9vimo7t1hsxpvfud8X26ibh3YPrLrUzMSg7ZWcivIHpLhgzIeqCE9QHtwSGtY84XVw5fc+31d5Ax6R3ja695PsOyk995/BmTnrvUVPG3v00M3YfAtG9MTt20TjfVEOijhg2Y9wZpxjRlO1pDmIanukdvZ5hg5if8roJTDC83ydsjzPXf1rn2225fXIikoS/tg13h4ZV1zBwp77pMUPufmzb56Ipm8mWNF3LE03xHrT9cXV/KIyBbOhfMWG4qZ/2GxMDSxT62m+A74cYG1r35+s1XmIhrebqyCIrTaWhOaFRBCk110cHj6Da3rv729vrkegquWTC29u3z1Vd/tPOVGPxOaThda/1aKyO3kfovT7n220Rfs7IkEOb+LNOVB+JOWPdY3HnRMXVrtjebD8Uf93nX5KVm0bldlv81dpGZxnQ7Wr9jFM+oP6uTSz9I1l9OBcooPvY4CzF4UA4VDsSDE9UOhoQh7rTguJhE3rDij0Z9pf1vtjVIRv6l6QPK20kzwMJfT2a4EGtjd1TZHdR74IJw2S3HzB4+PdQ8Otjo/ghNn2bAwY8h/fGAM1jO2OSVAbPzQUK40fnJqkbOxAaaE06ETpJuTvprtmvA9OYoW531F3XYprqocdGYmy9C9LnwOb3jdv/Gn2g/Yr5h0ZJj3R8E+6vdf60CaAZoP2paB9fWpyh+lu+Lk35jkn33jU69d7779TuzYjsgSaXpI9E3b6P4PQICD5uFonPj4jVgYe7DK0fkOLDxS8K22b1b2Xzb+X2uTBZfasTDGie9+2q+gsCRGiE12DynYO3OpoWDi+cFL/pDjW7Wa2LA6m9K5bVdhUanQL6TBClPMgqV+vigHCbo6z480jKHs+TdtrHbEzfaz/JsE3+/VNe5+t1sb56eaTNp6LuxEw0dJN/3x0Ees+12RX17kXgaYb7fuZ2YpXbp+vtU7mFnZxckv5VCHVeJHDYef07olYG7mVv0wa62w/3GXjh5G0rkbhqWEG3eWXsPC58L7EoH15ERiyxrSIryUkmjH0pInYkfS/GjPH94M6UM7jbFcvysVy6Tyh8S+i6Cd/GQ+RukuTXXit8o9D44Cz2ELKbZoPf7CQj+g/bHtYZmX30r5gwfKyLvL7CQwiQ+dpeHxtFiKkxtW+r9bpYhjKHgtqXfrNzjHDFC1N1H68+R+UTTkJE+p4i6YdpykyCcKq2w7XnqAuuLpG++PIyTWGT/jCbkx5mrweaM+quvwXWPt7PEzL0A+lgVNjraCqYb1loCIsd/zfQNn78X4LKWPbZQONo9lmKQpsDGciaGmq06Y+x1KkUleGUsKHCkZSwFHXJNzf9vnqu7oVtPn4r6rpcYb3guovkeAYFjyZ7QtOD243CBTDDFowe2T3FhDbHE5ugdtfgfMXf8ro06zM8pwmq95udZETIzcxGv/W3wMwGXJc+v6ldi0mCX780Gr/Lo+njd2nmemOGmGum7PGyuVR/T32dR+ldFta0N2pvYFISNVYeGwcT1W2K+qmI1bDFmm2zSX04ZkSMiWD9o1AkojrkVs1t8VQ2gXPC4YWTHex+fKDqC+/8K3XAermH0Gi9K5aj7k1s6Nqcpt5/3KYo9LtiXTxZLB6OeaDrJnwS4+dHBoUnnR8Jb2Hkrcd2lISt6V796OaSKSbFz08MG5NwfuIUM4ysH++Kdf5j6lOxLVem5YWeyL4prr/vTJJGW+brX/Ll1+rxcZpN+6YoXkR8OYo4yTjaX9zm59ui2VVbXPlleFV6XwkefBUQOnLyFTD4hH08Id2j23nS1e/q6qkOFIoPqffanKve8dEpyo8tzlUdLg8QUj1SISBdtTk0AK/zQqpNi8gsJ6q615FGirz6v0/oPK7aTzDzYSC1qw8UT3voGRvPengf2js9VH1oEd9AnaJ6V9RNtcUdd6D15eIzFI4yEqD30GakPG+K+rH0i6HypOyLgGrotaGcnd4Fk2IGYw/yJZ0j9QlGM1hCNZ6Bvnhh55C63mM7pqxAlcdfp80oAwNXX9pYMq1n2uQPMtE08iEeVRT9ABNd4x/eUXVVMMWbKhtJ6R5XFfnCEVVjX7ZRVbG0Z6psNOUZqqOOHa6G8vLrlHVptLgNEZlU1cYzMuTi3/PNLhBloRq9a09VN1I9h2pMKZszrnQbcQpf26hDxNWMVcih6pJK40C1Az+037igTvtrenjxUH09PJPqy+yqtY/Mo17MxPfx2R5lRQ4QB9rRdel9LDbQBiWPD7nQ+MnLjbABIwuOKerDA3JY/cjQPEV9m9fdKSDTbHAN44fRTTMktP6J2RBdAY2o9739//zYttWuzEc2zIDLJkyUIltEQoLHt4kgy6MGhMsUjRgxUq5oiiH7pq02kWI2YUtsy7FyNhNMKbbfyrrahvKNg4b0251tRngzSdCCkQ0lE5SPbioJ2pC2sWSqKQlVl+IWpVZfmmpYNFgdN2k8Uh03hs0WOpPsaM9VbQ4H2q7yujs/7rbyytTYch7/ji8amXkE9ZBV/kCF+32S9F+repO3bYFlk18nSTYHUZCpnxP68sMkecd6m+Tj4ISSXydFG7YkPS0s8XXvauxF1M4Ja5uI4sSKnUmay2a3zn/0FoYxze7y6FIgUTMtWB7RmlCqPEVjmaQspabviB6TVL5e56mvk1x/lu5uO2WToti/+CJau6rNk7S3XqOzrDgM6im6Xy49T2NvERjTF139pWrzs8FiykZqjAd00THWnsF2l38rt0+DrAunHVwxaRT3EtNMGh+pRtbpANdM0+IFxf+AOSQHTaHrJmn7vD2e9/Xrfou+JeCKqAYem2aQj+oxuQdMNhI+s1jVITUlQZN/Zaqiv1/f3t18/AAEH36JClLex7suzPqybrtdQkeRj4fH3Pz74JpU4YdzeorPn2/eAbn+z0jk/7x5VW5XxfdXP//rlTlw13jFz6/YT/ynxas3rx7LYr1qXv38ZxeLW1abw1JmVS1tnY1X/3O47O/Fsq1qc7G7+t9nr978OXuj+E8zpv7nf9782TW2P9j/6GS8/I9tmL1682eGGmaDhlmvIXv15k+GGrJBQ9ZryF+9+ZOjhnzQkPcaildv/hSooRg0FL2G8tWbPyVqKAcNZa+hevXmT4UaqkFD1WuoX735U6OGetBQ9xrOX735c44azgcN572Gi1dv/lyghotBw0XfAYw/ZNB3sqHzZMR7rPtg/wEO1PegzPhFBn0oGzpR1veizPhGBv0oGzpS1vekzPhHBn0pGzpT1vemzPhIBv0pGzpU1veozPhJBn0qGzpV1veqzPhKBv0qGzpW1veszPhLBn0rGzpX1veuzPhMBv0rGzpY1vcwZnyGQQ9jQw9jfQ9jxmcY9DA29DBGxig7SOFRCgxTfQ9jxmcY9DA29DDW9zBmfIZBD2NDD2N9D2PGZxj0MDb0MNb3MGZ8hkEPY0MPY30PY8ZnGPQwNvQw1vcwZnyGQQ9jQw9jfQ9jxmcY9DA29DDW9zBufIZDD+NDD+N9D+PGZzj0MD70MN73MG58hkMP40MP4+RLaD+F+FsIPoZ9D+PGZzj0MD70MN73MG58hkMP40MP430P48ZnOPQwPvQw3vcwbnyGQw/jQw/jfQ/jxmc49DA+9DDe9zBufIZDD+NDD+N9DxPGZwT0MDH0MNH3MGF8RkAPE0MPE30PE8ZnBPQwMfQw0fcwYXxGQA8TQw8TZL5lJ1x4xgWmXH0PE8ZnBPQwMfQw0fcwYXxGQA8TQw8TfQ8TxmcE9DAx9DDR9zBhfEZADxNDDxN9DxPGZwT0MDH0MNH3MGl8RkIPk0MPk30Pk8ZnJPQwOfQw2fcwaXxGQg+TQw+TfQ+TxmckfyP1T4ts3m889DDZ9zBpfEZCD5NDD5NkVm+n9XheDyb2fQ+Txmck9DA59DDZ9zBpfEZCD5NDD5N9D5PGZyT0MDn0MNn3MGl8RkIPk0MPk30PU8ZnFPQwNfQw1fcwZXxGQQ9TQw9TfQ9TxmcU9DA19DDV9zBlfEbBMUwNPUz1PUwZn1HQw9TQw1Tfw5TxGQU9TA09TJG1o108KtQxFFg+9j1MGZ9R+o1QPy046zceepjqe5gyPqPmUPPQw1Tfw5TxGbWAjYcepvoepo3PaOhheuhhuu9h2viMhh6mhx6m+x6mjc9o6GF66GG672Ha+IyGHqaHHqb7HqaNz2joYXroYbrvYdr4jIYepocepvsepo3PaIWcRA89TJMIhQ1R4BgFCFL0PUwbn9FwDNNDD9N9D9PGZzQcw/TQw3Tfw+bGZ+bQw+ZDD5v3PWxufGYOPWw+9LB538Pmxmfm0MPmQw+b9z1sbnxmDj1sPvSwed/D5iI4GMyHHjbve9jc+Mwcuud86GHzvofNjc/MoXvOhx4273vY3PjMHH5i50MPm5M4mA2EQfecg1BY38PmxmfmOIw29LB538MW1sNwKG3oYYu+hy2Mzyygey6GHrboe9jC+MwCuudi6GGLvoctjM8sGBq3F0MPW/Q9bGF8ZgHdczH0sEXfwxbGZxYCah562KLvYQvjMwvoYYuhhy36HrYwPrOAHrYYetii72EL4zML6GGLoYctSLTVhlvnb3j2UzYj9wwCrjTiapxmsXgjZz/NOO+1dr/1m3v/d2hvo66z2Rsx/4krKgDEXWck8DqzkddZhgWA2OuMBF9nNvo6w7HbGYi/zkgAdmYjsDMcv52BGOyMBGFnNgo7wzHcGYjDzkggdmYjsTMcx52BWOyMBGNnNho7w7HcGYjHzkhAdmYjsjMcz52BmOyMBGVnNio7m+PXCOKyM+KIh9g/juui6P8g/J8F+0EGAQBxRBvUx1OYDDEACgEcBchwT0AcgIIARwIy3BMQC6AwwNGAjGEBwA8pEHBEIEAyEBOgUMDG+UPvALgh5QIODGRwAM8QGqBswMGBABFBeIDwgcyG/LMAFQGIICOMIGMOQ+GeBDBBRjhBZkP/WYCOAFSQEVaQ2fB/4CUAWpARXJAx54eLN0L+pGh74IaEGGQWAmRsBtsDLyTQILMcIMOcJQPcICPgIGMRLwToICPsILM4IGMMfhQBPsgIP8gsEsgwr8kAQsgIQ8gsFsgws8kARsgIR8gsGsgwt8kASsgIS8gsHgg8Q0ATMoITMksIAqMpAAoZIQoZF5HRFECFjFCFjMvIaArAQkbIQsZVZDQFcCEjdCGzwCDD+CsDgCEjhCGz0CD0DoAbEsiQWW4QegfACwlnyMQs8g4AasgIa8hEFnkHADdkhDdkgkXeAUAOGWEOmcUIGdPwgwKwQ0a4Q2ZRQuAdAPKQEfSQCTcY4tEc0IeM4IdMuNEQz4sAgcgIgsgsVcgwkcwAhcgIhsgsWch49kaKn6SkLwH4IUERmaULGSaTGaARGcERmSUMGedvJPtpJvrtAZDICJHILGTIuIB3AKBERqhEZkFDxiU0ALghAROZdBkieCgAbCIjcCKzvCHDrDIDfCIjgCKzzCHDvDIDjCIjkCKz3CHQEQCmyAinyKRzwwV+B8ANCavILH7IxAwLAG5IeEVmEUQmsB8DZJERZpFZDJFh/pkBbJERbpGpyBIFkIuMoIvM0ojAYh3Ai4zQi0zxyGIdAIyMEIxMichiHUCMjFCMzIKJDFPgDICMjJCMTKnIOhPAjIzQjMwCigyj5AwAjYwQjUxFvsqAaWQEamRqEZ5eA6yREa6R6Vl4eg3IRkbQRmZpRYZxeAboRkbwRqYjU0MAODJCODLNww8AMI6MQI7McovQAwA+SDhHpp0P4sEYoI6MsI5MR4ZCQDsygjsy7VwQT0oA8cgI8sh0bIECqEdGsEem3VAIuVwGyEdG0Ec2d0MhZHMZoB8ZwR+ZJRqZnGEBwAsJAsks1chwnkEGKEhGMEg2jyyTAQjJCAnJLNwwifZgTgBYSEZgSDZ3uZtwUgNwSEZ4SGYRRyYFbA+8kCCRzFKOTMI5DYAiGaEimQUdmVSwPcriJD5oWUcmNRzJARvJCBzJLO/I5BwZAPBIRvhItnAuGMgkBS5IGEm2iAyEgJJkBJNklnwEPAiAkoyQkmwhwh4EWElGYEm2kGEPArgkI7wkW6iwBwFikhFkki102IMANMkINckW84gHAXCSEXKSLRYRD0K5xDSZ2HogTmNhgJ4wQk/YLDwhZACeMAJP2Cw8IWSAnTDCTtgsMiFkgJ0wwk7YLDIhZICdMMJOmGMnOJmHAXbCCDths8iEkAF2wgg7YY6d4IwgBtgJI+yEzcITQgbQCSPohM3CYRoGyAkj5IRlkTANA+SEEXLCskiYhgF0wgg6YVkkTMMAO2GEnTDHTnBiFQPshBF2wrJwmIYBdMIIOmGWhATeASAnjJATdiAngXcAvJCQE+b2U4TeAfBCgk7YAZ0E3gFwQ4JOmEMnCrIXBtAJo1srLAkJvAO0uYLurnDkBOe4MbTBYrDDggXT3BjcY0G80IIQnNzC0DYLus/CghCc7MbQTgu61cKCEJzvxtBmC7rbwoEThfdboA0XdMcFc0Mh3nOBNl3QXReOnCi87wJtvKA7Lxw5UXjvBdp8QcgJc+QE5/0xQE4YISfMkRMYa2QAnDACTpgFIRnOHWSAnDBCTpglIRnOH2QAnTCCTphDJzBYyQA5YYScMEdOcA4iA+SEEXLCHDnBeYgMkBNGyAlz5ATnIjJAThghJ8ySkEzjngDQCSPohPFwUg0D6IQRdMIcOsE5jQygE0bQCXPoBOc1MoBOGEEnzKETnNvIADphBJ0wh05wfiMD6IQRdMIsCsnmMN7KADthhJ0wx05wniMD7IQRdsIcO5ljTwbshBF2wkSYJDOAThhBJ+yATmDQmwF0wgg6YSISs2YAnTCCTphDJzjpkgF2wgg7YY6d4MRLBtgJI+yEOXaCky8ZgCeMwBPm4AlOwGQAnjACT5iMTA4BO2GEnTCLQgKrLIBOGEEnTKrIKguwE0bYCXPsJLDKAuyEEXbCHDvBaagMsBNG2AmTkfQuBtgJI+yEOXaCc1kZYCeMsBMWYScMsBNG2AlTLBh1ZoCdMMJOmGMnMOrMADphBJ0wFRsNATphBJ0wh05wQi8D6IQRdMJUOGzNADlhhJwwR04CTxA4IQEnTM0jTxD4IAEnzIETnJTMADlhhJwwHVmgAHLCCDlhjpzgBwDACSPghGkWfgAAnDACTpgDJwv8PQTkhBFywnRkIATkhBFywhw5WXDow4CcMEJOmCUh2QJ/jQA6YQSdMB35IANywgg5YTFywgA5YYScMEdOcDIEA+SEEXLC5uFcBgbACSPghM0juQwMgBNGwAmbh3MZGOAmjHATNndeiCcEAJwwAk7YPOKFAJwwAk6YAycLvM4H5IQRcsIcOVlA/sYAOmEEnTCHThZ4pQ/YCSPshM0jIUPAThhhJ8yxE5wnywA7YYSdMMdOFoEaB8ANCTxhloWwGf4aAXjCCDxhFoawGR7NAT1hhJ4wS0MYzvtnAJ8wgk+YxSEM5/0zwE8Y4SfM8hCG8/4ZACiMABRmgQjDef8MEBRGCAqzRITNcFcACIURhMIsEWEz3BUAQmEEoTCLRNgMzywBQ2GEofBZ+KPMAULhBKFwtwEFQjQOEAonCIW7/ScQonGAUDhBKNwhFAjROCAonBAU7ggKhGgcABROAAp3AAVCNA74CSf8hDt+giEaB/yEE37CHT+BEI0DfMIJPuEz54K4GAbgJ5zwEz4Lx2o44Cec8BNucQjDZac44Cec8BOeubpAgbItqG4L8UGLQxguP8UBP+GEn3CLQxjeuMEBP+GEn3DLQxguQ8UBQOEEoHALRFgm0UDCAUHhhKDwLLw64QCgcAJQuOUhDG/c4ACgcAJQuOUhDG/c4ACgcAJQuOUhDG/c4ACgcAJQuCtOhUtbcUBQOCEo3BWowuWtOCAonBAUfihShT0ZIBROEAp3hapwmSsOGAonDIWz8OSQA4bCCUPhLByr4YChcMJQOIvEajhgKJwwFM4isRoOGAonDIU7hoJDLRwwFE4YCnflqxisg8IBQ+G0ghWPfJJRDStaxIo7N8SDCapjRQtZceeGuCYUqmU1KGbl3BAPBrCeFXFDy0QYrj7GUU0rWtTKMhGG8/45qmtFC1vxyHiISlvR2lYWiWCizVF1K1reyiEUTLQ5qnBFS1zxRZhoc1TlijAUfth+Aok2BwyFE4bChfNDPJ4ChsIJQ+EinODFAULhBKFwh1BwoicHCIUThMIdQsHhCg4QCicIhTuEghM9OUAonCAUbokIC9SzAwiFE4TC3fYTnCnKAUPhhKFwi0RYoCgeYCicMBRukQgLFMYDDIUThsItEmGB4niAoXDCULiMJLtywFA4YSjcIhEWqLAHGAonDIVLV0AyUGUPeCJhKNwyERaotAcgCicQhVsowgLV9gBF4YSicOk8EY+ogKJwQlG4hSIsUHUPUBROKAq3UIThynscUBROKAq3UITh6nscUBROKAq3UIThHSgcUBROKAq3VITh/RccYBROMAq3WITh7RMccBROOAq3XITh7QccgBROQApXrpxpoOYj8EQCUrjlIkxoEIbngKNwwlG45SIMF+bjAKRwAlK4BSNMQCrMAUnhhKRwS0ZYYDwBKIUTlMItGWEyeyPET3LwDIAjEpTCLRphuFAfByyFE5bCLRthEqIEDmAKJzCFWzjCJIyDc0BTOKEp3MIRJvGKFdAUTmgK1yLsR4CmcEJTuHaldWHwjgOawglN4RaOMKnxIwCOSGgKt3SEyTl0A4BTOMEpXDtHxEMqwCmc4BRu6QjDGdQc4BROcAqfzyKeDHgKJzyFWzzCcAIyBzyFE57CLR9hOH+YA6DCCVDhlo8whbsCACqcABVuAQnDlQU5ICqcEBU+l5HOCIgKJ0SFz12hZzyoA6LCCVHhcx3uSwCocAJUuAUkDKc+ckBUOCEqfO4cEU/VAVHhhKjwxSzSlwBR4YSocEdUcO4kB0SFE6LCHVHBuZMcEBVOiAp3RAXnTnJAVDghKtwRFZz7yAFR4YSocEdUcO4jB0SFE6LCHVHBuYscEBVOiAp3RAXnLnJAVDghKtwRFZy7yAFR4YSocEdUtIKdERAVToiKsISE4dxDAZCKIEhFWETCcO6hAExFEKYiLCNhGq75BIAqgkAVYSEJm8O93gJQFUGoirCUhOH6igJgFUGwirCYhOHcQwG4iiBcRVhMwuZwTBWAqwjCVYTlJAxn7gkAVgQBK8JyEpzOLgBXEYSriFlkkigAWBEErAgHVnDqoABgRRCwIhxYwamDAoAVQcCKcGAFpw4KAFYEASvCgZU5jJ8IAFYEASvCgRWc9yYAWBEErAgHVgJdAYAVQcCKsKCE4bwxAciKIGRFOLIS8ANAVgQhK8KRFZy4JQBZEYSsCEdWcOKTAGRFELIiHFnBVSUFICuCkBXhyApOXBKArAhCVoQjKzhrRgCyIghZEY6sLOBnQQCyIghZEe4YEFxlUgC0IghaEe4oEJP1giwAnkjYinDHgSzwZwGwFUHYirCohM9wXwBsRRC2Iiwq4TjpRAC2IghbERaV8BmDgypgK4KwFXE4HiRwDALwRAJXhDsiBCedCABXBIErwh0TgpNOBIArgsAV4Tao4IwBAeCKIHBFuONCZtiVAVwRBK4IB1fwXFsAuCIIXBHu2JAZ/jYCuiIIXRHu6JAZSnoQgK4IQleEOz0EJz0IQFcEoSvCwpLQ9ALQFUEPEbGwhGcwhiTQOSL0IBHhzqrBfQmdJUIPE7G0hGcQbgh0ngg9UMTSEp5x6IjoTJHBoSLWEXHWg4DnihBHtLSE43KTAp0tQg8XsbSEZwo/A+CI9IARS0s4zloQ6IwResiI26KCK6QJdM4IPWjE0hKe4SkSOmuE4BUhnSfizwLAK4LgFeHwCk5LFgCvCIJXhNuigvM5BcArguAV4fAKzn4RAK8IgleEwyuY2QuAVwTBK8LSEo5TPwTAK4LgFWFpCcepHwLgFUHwirC0hOPUDwHwiiB4RVhawkPPAHgiwSvC0hKO8w4EwCuC4BXhNqngLdAC4BVB8IqwtITjxAUB8IogeEU4vBKY5QG8IgheEZaWcJz5IABeEQSvCEtLeGA8AHhFELwilPNEHD0AfEUQviKU80Q8HgC+IghfERaXcMysBeArgvAVYXEJN0n+w687wCuC4BWhYrNEgFcEwSvC0hLOYQl9AfCKIHhFWFrCMbIWAK8IgleEpSUcE2cB8IogeEVYWsIxcRYArwiCV4TFJZxDPCIAXxGErwgtI+MJ4CuC8BVhcQnHyFoAviIIXxHaOSLuCoCvCMJXhJ5HHAnwFUH4irC4hGPmLQBfEYSvCItLeOC0OcBXBOErwvGVwKoR8BVB+IqYs8hqAfAVQfiKcHwlsOwEfEUQviIcXwksNwBfEYSvCItLQssNwFcE4StirsLLDYBXBMErYq4jczTAVwThK8LiEm72ISMBwBEJXxEWl3CBRzTAVwThK2LhHBGPaICvCMJXxCILD+oArwiCV4SlJTxwBiHAK4LgFeHwSiCOBvCKIHhFLETkqwDwiiB4RSxi62aAVwTBK8LhFYwqBcArguAVYWkJD5zFCPCKIHhFOLyCcycEwCuC4BXh8ArOnRAArwiCV+TMOSI+rw/gFUnwirS0hONTISXAK5LgFXnAK3BElACvSIJXpKUlHGewSIBXJMEr0tISjo+XlACvSIJX5CxCnCXAK5LgFenwCs7ekACvSIJXpMMrmFFJgFckwSvS7VvBxFgCviIJX5GOr+DIvgR8RRK+Ii0u4YFzOgFfkYSvyCwLR2Ak4CuS8BWZsXAERgK+IglfkRkPxz8k4CuS8BVpcQkPHTcKPJHwFZlFxkQJ+IokfEVmkViiBHxFEr4is3AsUQK8IglekZaW8MChqQCvSIJXpKUlGBRKQFckoSuSOT+En2YJ6IokdEVaWMIDh68CuiIJXZEWlvDAaADoiiR0RTq6AvNPJIArksAVySJTRAngiiRwRVpWwgOnwAK4IglckZaV8MBJsACuSAJX5AGuYDcAcEUSuCIPcAX6MWArkrAV6dhK4DhawFYkYSvSsZXAkbSArUjCVqRjKwrODSRgK5KwFenYCk4mk4CtSMJWpDuGHSeTScBWJGEr0rEVXElRArYiCVuR7jj2wDcBsBVJ2Ip0bCXwTQBsRRK2Ih1bwelsEsAVSeCKdHAl8FEBcEUSuCLd8ew4nU0CuCIJXJEOruB0NAngiiRwRTq4givxSQBXJIEr0sEVnE0mAVyRBK5IB1dwNpkEcEUSuCIdXMHZZBLAFUnginRwBWeTSQBXJIEr0sEVnE0mAVyRBK5IB1dwNpkEcEUSuCIdXMFkQgK4IglckQ6u4HQ0CeCKpCe5u/pfeAeRRIe509PcD2enwIInEh3oTk90P5ydgjbYS3SmOz3U/XB2Ckz0luhcd3qwuwzXQ5ToaPfB2e7ODwOnuwM/pOe7O7SCgycSHfFOz3h3aAUHTyQ65p2e8+7QCq6HKNFR7/Ssd4dWcE6hRMe9E7QiLSnhGkagJEArkqAV6dAKrmcoAVqRBK1IVwAMl42RAK1IglakqwCGy8ZIgFYkQSvSoRVcUVECtCIJWpEOreCsRgnQiiRoRTq0grMaJUArkqAV6dDKHI+IAK1Iglak27qCK5ZIwFYkYSvSbV3BFUskYCuSsBXp2ArOq5SArUjCVqRjKzitUQK2Iglbka4OGK4KKQFbkYStSFcIDFeFlICtSMJWpGMrOLFSArYiCVuRrhIY3iYvAVuRhK1IVwkMb5OXgK1IwlakO0QFb5OXgK1IwlakYys4N1QCtiIJW5GOreCiihKwFUnYinRsBeeGSsBWJGEr0qISjlM7JWArkrAV6djKAsXEJUArkqAVaUlJaN0N0IokaEVaUsJxZqcEaEUStCIdWsGZnRKgFUnQinRoBWd2SsBWJGEr0rEVnNkpAVuRhK1Ix1bw2eESsBVJ2Ip0bAVndkrAViRhK9KxlQX2ZMBWJGEr0rGVQOwAwBVJ4Ip0cAXXI5MArkgCV6RlJQLXI5MArkgCV6RlJQKnhkoAVySBK9KyEoHrkUkAVySBK3KhwsBbArgiCVyRlpUInFsqAVyRBK5Iy0oEzi2VAK5IAlekgys4XV4CuCIJXFGWlYgZHFAUgCuKwBVlWYnAJ6ErAFcUgSvKshJh5hfDBZMCcEURuKJmzhPhM1AArigCV5SDKxj6KwBXFIErauY8EXYmBeCKInBFWVYicEUsBeCKInBFzXTsIQ49URG4ombz2EMceqIicEXNIik4CsAVReCKsqxE4PRWBeCKInBFWVYicFEvBeCKInBFWVYiMrRwVoCtKMJWlEUlAme3KsBWFGEryqISgbNbFWArirAVlYV32iuAVhRBKypzfog7M0AriqAVZVGJwNmxCrAVRdiKyuYRRwZsRRG2oiwrETjzQgG4oghcUQ6uBBwZwBVF4Ipizg8h6FQArigCV5RlJQKnlioAVxSBK8rCEsFg/EMBuqIIXVEWlggG4x8K0BVF6IpydAUH9hWgK4rQFWVhicAnuitAVxShK8rCEoFzUxWgK4rQFWVpiWASrfkUwCuK4BVlaYlgcHqhAF5RBK8oS0sEromlAF5RBK8oS0sEg6lgCuAVRfCK4s4T4cJZAbyiCF5RlpYIjv0A4BVF8IqytETgYkQK4BVF8IqytETgHB4F8IoieEVZWiJwZqcCeEURvKIcXoF5UArQFUXoirKwJPBZAnBFEbiieGRbqQJwRRG4okRkp70CcEURuKJcXTCcxaQAXFEErihXFwymiSvAVhRhK8qxFbxcUoCtKMJWlGMrcN2uAFpRBK0o4bwQj0YArSiCVpRQkSEdoBVF0IoSOjKkA7SiCFpRlpQInF+sAFpRBK2ow74V/F0EaEURtKJkJKStAFpRBK0oS0oErqmlAFpRBK0oi0oETlBWgK0owlaUjOygUoCtKMJWlHTjIYwcKABXFIErSjpPxGsVAFcUgSvKshKBE5QVgCuKwBXl4AoG3grAFUXginJwJfQQgScSuKIcXMG8WgG4oghcUZaVCFxXTAG4oghcUSqSCKYAXFEErigVSQRTAK4oAleUZSUCVzZTAK4oAleUgyuBhwjgiiJwRVlWInCCsQJwRRG4opTzRDyoAriiCFxRlpUInByrAFxRBK4oy0oETk1VAK4oAleUZSUCp6YqAFcUgStKO0/E4wGAK4rAFWVZicDlIhWAK4rAFeXgioBZlQrAFUXgirKsROCsSgXgiiJwRVlWInBKogJwRRG4oiwrETihTwG4oghcUVpF1goArigCV5RlJQJn9CkAVxSBK8qyEoEz+hSAK4rAFWVZiZC4LwC4oghcUfNZZLEB4IoicEXNs8hiA8AVReCKsrBE4JQ+BeiKInRFzZ0nQtSpAF1RhK6oufNE3BsBXVGErqi580T8dQZ0RRG6oiwsEbi+mwJ0RRG6og6n1MNiAwrQFUXoinJ0BdeMUICuKEJXlIUlAuf0KUBXFKErysISgXP6FKAritAVZWGJwDl9CtAVReiKsrBE4Iw6BeiKInRFObqCE+IUoCuK0BXl6ApOiFOArihCV5Q7qx6evaUAXFEErih3Vj08e0sBtqIIW1HurHp8fJsCbEURtqIcW8EZfQqwFUXYilo4P8SdGbAVRdiKdmwFZ/RpwFY0YSvasRWc0acBW9GErWjHVnBGnwZsRRO2ot1hK/AtaoBWNEEr2pISgTMCNUArmqAV7dAKzgjUAK1ogla0Qys4oU8DtKIJWtHuuBXYETQgK5qQFe3ICs5m04CsaEJWtAUlAueSaUBWNCEr2oKSBVz5awBWNAEr2oEVnIumAVjRBKxod1w9PDJIA7CiCVjR7rR6eGSQBlxFE66iMxE8MkgDrKIJVtGZDB4ZpAFW0QSraHdYPTwySAOqoglV0Vnkm6wBVdGEqmh3Vj08MkgDqKIJVNEOquAChRpAFU2ginb1wHD1HA2giiZQRbsdK3hTsgZQRROool09MBzE1ACqaAJVtIMqOB9SA6iiCVTRTISDkBpAFU2ginZQBQYhNWAqmjAV7ZgKTofUgKlowlQ0C0eyNUAqmiAV7ZAKTqfUAKloglS0Qyo4nVIDpKIJUtEOqczx5wQgFU2QinZIBSczaoBUNEEq2iEVnMyoAVLRBKloh1RwKqEGSEUTpKIdUsF5eBogFU2QinZIBQIJDYiKJkRFO6KC8/g0ICqaEBXNdXidpgFS0QSpaIdUcCKgBkxFE6aiLSIROBFQA6aiCVPRFpEIXKJRA6aiCVPRFpEInMinAVPRhKlowcIbuzWAKppAFW0ZicCZgBpAFU2gihYivK1aA6qiCVXRjqrgVEINqIomVEU7qoJTCTWgKppQFe2oCk4l1ICqaEJVtAjXjNUAqmgCVbSIwD0NoIomUEVL54h4NABQRROoomUWPhdAA6iiCVTR7qwVmLSiAVPRhKloVwsMV+XXgKlowlS0Yyo4G1MDpqIJU9GOqeBkSg2YiiZMRVtEInEypQZMRROmot1RK7iMlQZMRROmot1RK7hqjAZMRROmoh1TwWEfDZiKJkxFW0QicT6oBkxFE6aiLSKROB9UA6aiCVPRFpFInM6pAVPRhKloi0gkTufUgKlowlS0RSSBYLwGTEUTpqItIgkMJwCpaIJUtDtqJTCcAKSiCVLRlpBIXOxUA6SiCVLRbr8KHg0AUdGEqGh3aD3GERoQFU2IitbOD/GQDoiKJkRFO6KCU9g0ICqaEBWtnR/iIRkQFU2IinZEBefAaUBUNCEqWkcyYjUgKpoQFe2ICmb9GhAVTYiK1m5ExGMyICqaEBWtnSPiMRkQFU2IiraAROKcXA2IiiZERevYpxkQFU2Iij4ctYK/rICoaEJUtCsFhvsSACqaABXtTlrBB+ZoAFQ0ASp6Hvs0A6CiCVDRlo9InBSsAVDRBKhoB1QwmdMAqGgCVLQDKjiLTwOgoglQ0ZaPSJyWrAFQ0QSo6LlzRPxZAkBFE6CiHVDBZE4DoKIJUNEOqGAypwFQ0QSoaAdUcBqgBkBFE6CiHVDBWXwaABVNgIq2fETi3GwNgIomQEUvnCfiDxsAKpoAFW0BicS51RoQFU2IiraEROLcag2QiiZIRS+cJ+IxFSAVTZCKXjhPxGMqQCqaIBXtkErg0wiQiiZIZW4JicSp0XOAVOYEqcwP21Xgfpc5QCpzglTms/AmgTkgKnNCVOaWkEhc9ncOkMqcIJW5JSQSl/2dA6QyJ0hlbgmJxKnVc4BU5gSpzC0hkbDM5xwQlTkhKvOZDtebnQOkMidIZT6bBwOhc0BU5oSozN1eFVxydw6IypwQlXnm3BCOJnOAVOYEqcwtIZG4bvEcIJU5QSpzi0gkLjs8B0xlTpjKPHN+CEeTOYAqcwJV5pnzQziazAFVmROqMs9c4Rv4UZgDrDInWGVuMYnExw3PAVeZE64yt5hE4rrFc8BVuv/7nzevyu23om6L1c12VXx/9fOff756eGh/7IpXb/716qF0/2lK4VpNr37+1ytTPPvnf/3vm1em6u3P//rf/33TqXL/3SmxvxmtOcvzp2LbltvHypdqzkM9SuVOaoqwZbV9LJ/69mW+fSpVUps3X/sWzT2L1CQ5xTfzn74wufCE6eTbM8Iey3Vb1D1pSnjS5mKKtE3R5qu8zfvy/FtdZFPk7eqyqsv2hy/Pe5WzKbLqotmv+89tzryXOUv2MSOtqZZfi560hX4Rtpj0Dpo2b/eNL0u+iEq0apXvyHs0u3Rf7k4L19JsyJ0g8KHcNm2+bcu8LavtQ1HXVU9J5vlKlugqTnJP8FDuzHPpLEt80U5ytTMie8/TZEMcxenUN71alUZSvt7V1a6o27LoCTVlFV5ek16kCt0UTZM/EVnCH1fmh3FPpg4wq1X1pSnqb/Zh9uRqzytNwZskcY+tudtN0bT5Ztd7jv7wZ7bAWQFm40SSXDM2P+zqalk0Tbl9Au7kOX6W+JaM0GVVk8+I37OlTpe0Kptl9a2ofwzHfnPI24vQLHEg6wk176hc9kzNMu57+oQn+Vhu83VdNLtq2/REmoPUPEMniCxX/Y9U5n82E53HyLGNepKY/7lL7M5GEujM5pA17/YmmLUr6qba9r5O5qCtF2Escdy2wupq1+/DM28wNEdaJYsyH4C+//rDnzlXKVkUnVCZc9S9J59oVOmL0N4T0okC1nWRr348LKvttli2Rc+tMq8bpTrntn2uq125BN+5LPOG4YyxkwQCNzPHRr28A5F447vy4R/7Yl88mPGz2vdmCJk3FmeJY9Ku/JI3xb5e903ze4Bgh6+FG5LevDLlLt3A7Ea+N69U6ovfle67vCzK1bo43ENTLKvtqv9B9Sd1JoszUfrX4kf/RvzpvuDdjXR3xFV3I92nplsSmM056Tqbts7b4qmnO/O/ZRlLdMRdaV/v4ckMP2DM/4KljgG78ltRN/TT7c/DTf3QNFE7OvYKf+w1W5KS5NRP9j/6L91ftJhdMWmS0FPyh4DUW6vbzjf7LqR9F5osC63x/M+nTJyG1GYU367yupvf9efivkiVbCQRWVfrnljpT79N+PU0sc3yudj0voomyHEUbMIYEwXv6mqza/umSt/UxKUClYgsnfuWJsptmmLzZV0MzTQ7GLxxLbH/7ttn5Eb+dCB19rRvn808bDmYyTPhL8tTR799+7zJt8Z1+v3P/xJ1w645NS9VaFWX/3Qrt+1qV5X9eITZV+aNE4nv5FternP3Ur6Vq6Iutm3d/1hwz4XMUUwniSWfMW+eZfYSTBLZVtW6L84PxJh9RinizPcdTT+4P67ptM8TmCtkypPDWNrQ86V4rOoisAT0PyfsEFZQiQPvMl8+F2273vRn9HP/XrM0317m6+V+nbdVbd5D75a5PyNMHMCX+bovxP8KZOwwo8rcV8/8cbhzpnj3x2FqwvRh+qIWh+mL2eORasOXfPmVvEKTceh1/cOcTiwO+rRIfmDrZbVti++93sr94Kg5GitVVn+xKHwjlT5MRU22Tao82An8dVBiiMXIGriEP19licu8pZkfrNf91Ys3c0nrk07KIACc+SHpxADXMt/lX8p1SSNRTEjfQRKd7Tnfbov1YLoo/f6dGHhfPhfLrziUyfxlFE+MmizXRV7TDukbls0P3S9bHLofn3Uulzp+HHQc1gbkkWb+vCITiY+hE7n/0izrcujPCz+qOeuGEnUYL9is+0MehhvOpikefJGYv9jmiYtOK82O1P11th/rzbrBbp7YKa3Mar0ulnRmY3YpeS+2G2kXonuxrHuxiY5tVLXV12I7vAfRW4IfRlIuUgWXgxiZ8Bd8inWrU92N/ImTACe6KZZ1HyoIf6Vkql0dpCYOPdWqd/vaE9ZZmHWL7Yzz7o9F54/dH1nnj4lrtWW12a0LEvfxHv1EKXkf2/iTNr5I7O2D+blJe/WeRuLAZMXs6xAO8QeNxI/MQWLfT5X0P1fJtplgW1/OwpeT2FWdHNJLTQ6Lt4BLvrmmrffLtv+YFt5jWiw6P8y6Pw7dMuv4Qsa6/+FHXz10tEx03wHZ+bPq5HTzsaybj2VHn593khfHoTfr/ugGtqyb4LHDOM2O/ULobpw+TgK75uqggnUTRXacKHbDDeu+XazjPLz7FPCux/FMdV+Abhjk3TVdUIynzvvMnK+/QjMb0rx4RIfZF4e7UPxgqk5cLywrw/Yb2yvAepP7/cKcre7UzU8QDmIrfoTbnKg5VeYQ5WZ+yCxLxBXLqq6LtZVIMIr2p3qJUZplVTcPxfe22Jq44ENd/GNf1iSO7k8mUrt23TzsinpTNkGx/rqHJd56XRCAkWl/AEv9algxR1z/j33RkJWKHwBYTBKKg4cmE8aLHiV+Va1E+lHyKQlPjG85SXRpYM5kegn8isRXsG/aavNc5DTEIX1WoBO73CCHY+73sdlhABLdgKgT/WRVfNn3vsH+nR5HzkSEsyqKXVMUXxES8mNlWWK4lchDq1HpdQ2ZuGZbFY/5ft1u8u92SkoQkx8iFGlO0wmsVkVvfST8qIeSk4S1ee+1CB8ga542tnSiis2uqPOWzGi4H/8VieupTqSDLf2YkdlF+WJj4gz+IPBbXpcmgNcX6AehzAbeNIHr4gmNBj7vXqTerZM1DBX4whJXt74wsiL0gXDikuogzXwyHvOSRER8jpY4VTXyyAdD+l123k3UFt3CY3aYsenEEL/TMBxa/XSYRKa7KnbFdlVslzTq4g8H/GUSldpdjiGCnhfOPAtVt/Q1tefdH926Wx8jbMn62rzsBwcyPwaVZcflXzelFt0UNjv+0U09E1MSVmVzDJQ/VnX7bNIC+nMYf4GSOHnr0mlc7kT/jnz8mjgpOorr4vomS4d8RTM/j4olfpOPaT8IkjA/e0x0D1+mvs2y2a3zHzR4J/3J2zyRZ6z2u7UBTsWD6S4PZPLqjT2pH+bD8pjG+P1v3Sztm1xszfswYZxyS3Kx/MBw4pjgpPXDNzM/fNMtw+aztJHhIHDIgXyv1okAwgkLdxU28yfmiWgSep7wY4KJAfpi2+zrAufz+OsbxtOcrth+K2uzntsSTOx/1edpo8wgDOOP8h0uOS66u6iC6Fb6MuumsaIbXFXiKzOKaZCtl8+X9nktmrbcmFnEIeI17Dx+/ipPTOG1eeKDfDDlf7QSiUrxPTd29dcV/odK67ShofheLPfkw+8nGWbyGGI5/CETOe9B8qArSj+TTuvEYccKK6stwmU+3JapI08nECXIcx9syMSwoQkN1Nt8/XBIKR3GIv2dFCztIQ7ndn5yRZqIwX4C7kNxmTg8ODFwDeYnXSdGNG2m7ANKlfU/Somh+sdyu3Izjy8/QkAu6+U4Jq6OjeC22jnZ5hNAJq9ZL38wcab9WNXLYa9g/uJJpNpX1aviW7GudnTUZtzPTZFpY8FjVW/yti1gspAPKhKXT49Vvaur1X4QuWZ+3giXiV2hqps2f6LTDn9PBU9cYz8Vm3JbwjCFP1tNTK3tSUMdxM9gkonL2Kdia9bsxX7fn/1JP29tnogPrbByWZk8IZh46c8/skTC/EQitNJ/dPOOD3QJF3x2+NrrxF0ET0Ub3NjD/EQunpjT+WQH+sEbX3i3zjrUKROzuYxMnC4+979JiZMXI23fPoOQYeZP+jN2xCjH/JYOW3TwxRzInaoymo+V+ZuoWBcFkIkZDb54QMI90TzxK/tUtENwmPlpsJnuiE1iTMuJjMAH5hNlzpNd4xDbapbVjsQp/EwynrgaeSpaf3UTWJH4kZ9EEGsFw7k/8wcbnrin6KloH+v8icoSfvK0SjfN9Qa6rM78uVSWOOk4SiN9y6c26Tf5XDZt1c+HzPwFYTY7Ys8uH60LmTF5ZIldh0ofdNfrTdPWRb5Bjup/DHlyH8X73/wdDfNu8p+4c+upaL39b33B2p8vqsMCX6UPWL5g8Aj8rpX8sW2r2qEfjNoz32aWGKW0UssnM9M1PXbgwv5Ml6Xffl08lU1b1MWq+5SX/Z0gmd9rs8Q00KeidUE2MLrOfXIok29+GOr1X3wiKj/Iab78sB/avjx/GZPIG17kDRPjuB82kYnw50XgcDjmPoKU6Z8jJwkksPvbo2XiHnUi71u+3vfjD37WDUuE4b7QwXrcR5MykfUZgYbGwfCYz9F44g7cTiCtPJD5WbHZvEvhSO8mpi+visdyWw5GCX87KktcdB0kungEiRf4SRo8MXb+VLT//GF2aZagWALzs0x44u6CpzofRq2EP86qxBjCc75drc3IVdY0Lco3LBPHee3xs5M26jznDVzfcH/6LNIe5HORr9vnB5tIixibP3qnDRXP5dNzzyzPqEQBgymH8KOHKjEL8SBnXW7K/irfn7/oxI723LY7EOvqfTOSBJXHPJNd1ZT0RrmfgCcTCXiJ96L7sVuZ2PPL0OKZa39XYKJzlf6KI3DDfsKOTFwkkFRYP/KturRS1aXq6W5X6nyWNlaVW1Mr4Kkumn4OtZc7mChnVXwvVqsvxg3zpwKty/2gbjZPta8/1ve2xHZjSmJnNeN73yA/RtLlCWaLLmN5dniWOjFnyX4/8nX5T5Kl5dPXxDmSE9UWqy89B2K+Y/LE5Kxyuyk2Vf0j9mZ6WW5pI1e53e1J5pifUpXIRa2U4Y5D4X8n1ZEdJXIKKxRkAvk1DWRi0R2b0bZeD7YKSj8jY5649+ggzE3L+/MMH+8lTnzLQ97vYDnmJ+DLRMxaDvJX/TVC4leo3H7L1+XqAUxT/HnUNGEgSdGfqSRmz5beGjM0Ovv+m1jAquxCbCgj1+/5MjH5vWy87amEAXM/QiKPGdNdWnQ385WJ89SyCaIGPxkq9fvXrKtl3i+h4M/yRSIXLJsQYfDxbOLiurRh3MD79vucTET0ZppVrUGSA5v5KDAxN7Vs9qZGT2+zr4tn9cNZftpW4sS8DC1BuN+vZSIQKc1iYTWMzXB/fSQTdyH/36baVl/+b7EEAz/3EwRlYpk1IxDsWveD0TqR56/zpoUJGMJPI1WJOQdG2mAeLfz8KZUIt42k/W5FhwTmzyh54oaRten1/QQdvyckxgsGSw3ur1tkNyqpxKXCumzaAU/I/GgLSwzTr9ebh25UBqsYP+yX+LzWmwcXn30otn1y73l/Yta3L4za5vt+YlqOJw6lPfj5b4mbCD2JTZvX/SmBvy5IG4fW643ZK0zyC/zVWiIZN4IqslfBz2eVibB+vd7gBBF/WGRdcZx5YmdYb3Z5nZOEooWfjZduXogFZKq3ayTxsVX5qvheNm25fWqKhhbAyfwkapbIF4zMYKyQ+RW6WGJegZ06PHS7Rx6+7Jv+uqeXwDpB4nEcMDPSddmPUPVQWOrTXObrzkxj5XB3ovIfaGIKphXb2dqZCkT7U4zUT1D1RAuT+NiOdWsrkbgDy8kDgWw/HVMmwsB19VT23dFPcsnkcWbbFd1KTCxZV0+Dj5wfbEqk9+vqiVYX473iid3GRn7cbNiNG4lpK+vqr56fey8mqb1bdawOa/p8aYo+ktmGzwJkYnfc5N93dq97sfaqlTW7ou6ctKfChyw6cb25yb/XRVvTdH9/Dca7bavyuDs9keBs8h9fChea7sp99Ae9Xtpe4jNZ7twGcjPm1WaTPelV/go3cYlrZIKaRv4unsRl42a5QzWI/MfJEvcTvIga2ib8wV0mzjc3y92urr7/GNQL8akSS8T0m+WuLppqX/c3GYqZv8st1QdfZJkdVWuS8SP8rRtqlmxfiLpKP6ilE6N3R3lDuCn8PUsqserHZrkL4y7hL5lUYirapliV+03Pg70+nCiifipQJF74E1jNE1+By33oB865v11RJH6fDpJQsWN/E4hK3LQRqDDXHz4TJYEa4H58nasuZaqLColu27vo9v6LrqyLOu4x7TLCdbdRVCdmr2/KTTEAijM/iNtlyqhZ4qhRuvrFptrnoKKlD1EnSUPDrScs8T3SbaHcz6UVossAOm446vCM6lLvVWK4yWo6JkD3HoK/8k9MNbLSCE/yiYJOHONo3gv35xiCHWeU3R9dLqPqMkZV54uqq/ugE2NH26L9q6q/DtfOvehg2qizrR4s6aSFX33GkmhV9dC0q/5Utp8QnSimxdV8exnRie+oah9Ks6HE/C+R5udTpY3x26otH0linE/zuglaprqZcPeqWVcel3cFRmRinT2nExSjyPxiFFniXN5JC1Rwz/zPDEsM/TuJbrE+OC4iU37kKrEYvpNogDms7ZP53SxLRE6eTFdSoS/Rf5KzVGfvJB43Zvdl+ku4yXc+fJL+7sEsdYQ6yhumeWT+VDFLXKG/CARR2MzfppUlft8qXNFU+MF+lQi3Am4t/EFRJQ4cnqzhPiPhD44qMf3Nkwjr1vi7TDuqpRKpUzRzNPMDqiwxduBJpBMaf72SGBis1ut8kyPm7sdSWWLwpScNzUr9oV0lYkAnFFQ1FX5hSJWYrlLtim0ON+L49S5Y4qjdk4Zu2K+rqRLTm4zQcrst/mrzLz1hflhaJeJKI6y2VcrhPftfAZXo0lQivG+/+m+q94CNTP7gKhKnv10K9DBA6ZehzLraXlmXk5SJLp6XHf/oJgeJ2V/VviVZJ9K/A52YmurEPOzy2i4Kht+IXnpq4nhuZRqRZMj0F54qMcPXCUN5MX6XZF15isT5v5OKEmN8HpO4RdMUXajLVTFYDLGF71OJS2NLT4qWbOTg/i4gmTjjsa/A7qih5YaFnxijErujFbdb59ttuX0a+p/w9xeqRP+zMpsf2/a5aMoGCe3VbEpzwF3+w4CZfkjAX9wmxhZMIRayJbNXwyRVyuAYGOZvzBPHEgFdZVaduBFlVzSDjQOZn9rFEtPEdl+XRWgW5pedUVPlwYRlHwayxCWQcTtfiP8JTUzT6zy3v+j3t/7OEvvBQRAaLXu1QtOk1cVjUdfFqs3rbstlv+f7OClxZWKElt/7ISh/u0ZiVs6uLr6V1b4BdZb9VR2fJ74BcL4e86cavCszxI+bVROXTYdjvvp+5gfV9UGg6FCaTNwhgJKChb9xVCdmYLmN5w+H0yB+AO/plUafJLTblPhggh2P1X5LMnY8uamvyso97NTGlbh6m+gSP25ObFvn22YdlOtXC0gccJxcmyYZFNurfjdB7Jf1vtjVg1Mn/A9TYg63kwdSBYTsZXNPsQ4sJIVP3lViesrhyJP+nLj3JqbI6SgSKe/k9xuRmKweOg7RHxYTzxHomC1YoIheccjk8fElUYFk+fpFh0V3noPo8L1OjKyRnFrwee4VH0rEkESqCY72B05/f0vi8r6TSSPiWa9ubFdeOOsi4pk+nmfRpRB0JZRY9zFQXVk+nRii6myp87/2g/q9/uxDJmZzw+oB3M/kFolFA/6xL8i2aulHzLqtyFl32gZ/qX7aUaOu/IROpJJ1v9qm7hVSSpNQ5E1Fp07+ruHE7NSjnGL7VG77hKx37F/ilh1TIawmnw6/FydurOv27O3rsj8m+8vV5Ft8rIvm2a4s+6/ZXzh0wwBPttBti8b7//wgbmJorxNIExGY31t5Yj5iXayLvCHA019HJwL+uthU3yD8zvxoXpaYUfSS6z5kZL3SzmkzzMPmC3TSougNBMnSaCls7i9qZOKc2qRtrL/1H76f164TQ1kwlcTPBFWJ/LsT1K+L5td4mScuYmhGCpHoh6ATVwn4+Nre7Di1mw9O9/ZHC66PK/nug584QzGZYD+W1Z5sQ/EHbZGY72pFrYp1/oOWMvZBd7L3fyuLv/ofdj/CmSaEpHtwP+NAdEcYiMTJl5FGMlH8qHVi4lm935oeHZ7JCT8vWCe6bpN/K9ASpHfIWrIku3WnfNxUq/KxpJtt/Lla4taOYTQ18wMXWQeqWbdXXSYWXBxWAxL+LgN13ArRpeLoxFR8l/gVWN36M+207ntI/yZ5UT4NFV0iq+gSWXVi2npDS4f55ZsW3SFMXUInnx1nc6mmB6pyMd981m3dlYkh0yZcmIP5TJd1E1OZGDRuosU0/Ll4YlC2ed63q+ovkrXg06WuThjrUjBU4gSkKdsB+fODESqR1TVfy94hhtwPlsnED3JT1WRTkZ++nJjY4z6gg5gi8z/svFuCycSUAk8oWd77meU8cW3V7Iol+T75S4HEOJipnmjSspflY7kEoQzRSxJLTEywu36Gxfb98SYxv9ZKshHxntv6KWcsMSth0PGlP9fWicX9rJQHl8HRi6t7zz4xNdSKQinXi94Gsy7VMpHFW6lN/s1s1kGFKfyNz6Lr6PPECD6IZ/ufZq66cwC605R4Z77sYI3qDinT3d4H3VVh0IlT96atdm5J3F8F+NuvEvfSHSoa9J+Q76epI5eTAxZMfmpK6kMOVVkQvRhE4uQRJ0X7Q0XiJkaXp9ZfAvh315WtE4mRr0Dem+gFSBILHHmyTMrNMO1I+klR80QC6aTS+E3vgLU0Oe6gyS/9AJ+f25x16azZ8XydLoDFuoxfzo6zykTn3i8p22H+ElekPob9zib3hB2T+ffCEg9HONLr3jjqfay75HKdamcnEKwgemcCpYpr2qLn770VTeJwbIUMaydzf8O06BJbVVdCRiceRO6LD26BkP52oHnqsOFJ7hI1+kOIv+cgcdHoCz0EYPoDnD+x1YmJ+b5QM5PpC/Q5derkzxfoIn6kvpbPUHRidg89vGnec6a0193mT2Szmz8AdynUMjHcHwDnzCd0vOO/OhHVeULpJNcXm7g5fXDIkj+Z58kmNV/xErh/SECysJdzlkDYwx/BdCI17gs9nBXQH2D9+HLiNNxIJe9A9hL3ux06shtoE7/cL0dIo8Cg8JN0dGK4xogcHoLhW3usNpt692g/nn//qjteVCduYfj/O7uW3bZhIPgvPfdikaLU/koRBG4hxUIcSZDFpj3k3wtKWnqWooxJbzkNYpuv3ZmdScvwWqX4cBCXrn/t+pecgg59UNjtcRn8y0VXbKjeIDuCa6PhYItg9Uzut4OGiMXCpiLZiMMmSInCnIoUsK5o6aZAqWZMm5aWkzWRhJbWlvCqpdQypfCzTsK4KlK1mGFFlLXFtkRrssWwwe3rEOVzQX7zuTy/olZaG1HgxS+CLCQD9m0+v416v6OkSXanlbQAxx6mYZBwaLvptgpV35J9hvZAZBt17mbdgUcqQFaDI7U8h5a2Fk0qnIQou6h9IAUpC/7Gp/70bdtMCY+BrhVO6PGKVANu6AunlzFOtzhZ6cjhtwUzHx+JTIeTnViRHZYVN50pVQUcGbmT8r04/k9qOwPEc6onxp4FSUJEnCQCzuCojiVduSKY3iM4o2PJSmeB2pIE9Q2iLEs/hbXm8uXKObwsP/G9xYQn9SMAGNnx1mCZ41Z5kP0PZOYzo5KdfB8EzPy1rrxWeLCVAnssGFTuw+yZNVyffRL6hPaY/HLOeEXhYiHNxBaklE62OKTtSE/XrM0/KlZPpQw3R/ab5IgCdK4+LdAfzpyigpc/qPY8fYlDmRWp2rpD6VMdeR3H3sGptZvB69JK36xmi98At3f8QzKwIpm1BWrXLCqxJ1aRcv15uM1TOjqBJh0n+TVPRsJ3rQgAT/GPmPzDfoD5fM3ngRp1kpFtngXvLoEON3v6CMOzjH3XTOdfqSUHUqzWxAZ0fJ+Lj0KcHP8mTLqVdw+ppk2fEQYZn1LIbiccaiXS1ZotV/P2mEWhzCXIbfc3VROglYAjyX7f7Rd1gVIRE30ayIrC9w/si3H8hhTX+P61H94z1686X7irQ7By9lRKFs69hjY4QdubSCLLZEh3B98f6g/RTMaQigsNp8s89KY2ZC3r+0h0tL7f2e+WqPutyYD0gDmOQ6CT1+mHMaH3nRpQ5zAX9jYGC+y8oUscVqtIAes21J9w3viGsaQGakXaBeUg+VCSask7VDsNb0EnOjcZDheNaQ1pJ+untG+MNQMJoXXD2ON0pDLRT13eeEudANwF429N82cc+lCLnhfLt6FtdQMLxRDsb5BM8yq7HPKLujVTevEhSW1EIxCj+E6RdudW7/aeb/ZElVWuh6Szr8A9Cp3BhjZZIkHVsT/yla0ECTd1S5C85mVUac+tnGCulpx2Bg8RK23Bmgy6/N2leHg/krzH+7mb07ekiowkUSb1j2DAlkyjFGRVJevhYGa2xF1bkdNcCjNHfxZYJximifj09cvYjc01zFp8//H08fEP066pVA=="; \ No newline at end of file diff --git a/docs/components/assets/style.css b/docs/components/assets/style.css new file mode 100755 index 0000000..5ba5a2a --- /dev/null +++ b/docs/components/assets/style.css @@ -0,0 +1,1633 @@ +@layer typedoc { + :root { + --dim-toolbar-contents-height: 2.5rem; + --dim-toolbar-border-bottom-width: 1px; + --dim-header-height: calc( + var(--dim-toolbar-border-bottom-width) + + var(--dim-toolbar-contents-height) + ); + + /* 0rem For mobile; unit is required for calculation in `calc` */ + --dim-container-main-margin-y: 0rem; + + --dim-footer-height: 3.5rem; + + --modal-animation-duration: 0.2s; + } + + :root { + /* Light */ + --light-color-background: #f2f4f8; + --light-color-background-secondary: #eff0f1; + /* Not to be confused with [:active](https://developer.mozilla.org/en-US/docs/Web/CSS/:active) */ + --light-color-background-active: #d6d8da; + --light-color-background-warning: #e6e600; + --light-color-warning-text: #222; + --light-color-accent: #c5c7c9; + --light-color-active-menu-item: var(--light-color-background-active); + --light-color-text: #222; + --light-color-contrast-text: #000; + --light-color-text-aside: #5e5e5e; + + --light-color-icon-background: var(--light-color-background); + --light-color-icon-text: var(--light-color-text); + + --light-color-comment-tag-text: var(--light-color-text); + --light-color-comment-tag: var(--light-color-background); + + --light-color-link: #1f70c2; + --light-color-focus-outline: #3584e4; + + --light-color-ts-keyword: #056bd6; + --light-color-ts-project: #b111c9; + --light-color-ts-module: var(--light-color-ts-project); + --light-color-ts-namespace: var(--light-color-ts-project); + --light-color-ts-enum: #7e6f15; + --light-color-ts-enum-member: var(--light-color-ts-enum); + --light-color-ts-variable: #4760ec; + --light-color-ts-function: #572be7; + --light-color-ts-class: #1f70c2; + --light-color-ts-interface: #108024; + --light-color-ts-constructor: var(--light-color-ts-class); + --light-color-ts-property: #9f5f30; + --light-color-ts-method: #be3989; + --light-color-ts-reference: #ff4d82; + --light-color-ts-call-signature: var(--light-color-ts-method); + --light-color-ts-index-signature: var(--light-color-ts-property); + --light-color-ts-constructor-signature: var( + --light-color-ts-constructor + ); + --light-color-ts-parameter: var(--light-color-ts-variable); + /* type literal not included as links will never be generated to it */ + --light-color-ts-type-parameter: #a55c0e; + --light-color-ts-accessor: #c73c3c; + --light-color-ts-get-signature: var(--light-color-ts-accessor); + --light-color-ts-set-signature: var(--light-color-ts-accessor); + --light-color-ts-type-alias: #d51270; + /* reference not included as links will be colored with the kind that it points to */ + --light-color-document: #000000; + + --light-color-alert-note: #0969d9; + --light-color-alert-tip: #1a7f37; + --light-color-alert-important: #8250df; + --light-color-alert-warning: #9a6700; + --light-color-alert-caution: #cf222e; + + --light-external-icon: url("data:image/svg+xml;utf8,"); + --light-color-scheme: light; + } + + :root { + /* Dark */ + --dark-color-background: #2b2e33; + --dark-color-background-secondary: #1e2024; + /* Not to be confused with [:active](https://developer.mozilla.org/en-US/docs/Web/CSS/:active) */ + --dark-color-background-active: #5d5d6a; + --dark-color-background-warning: #bebe00; + --dark-color-warning-text: #222; + --dark-color-accent: #9096a2; + --dark-color-active-menu-item: var(--dark-color-background-active); + --dark-color-text: #f5f5f5; + --dark-color-contrast-text: #ffffff; + --dark-color-text-aside: #dddddd; + + --dark-color-icon-background: var(--dark-color-background-secondary); + --dark-color-icon-text: var(--dark-color-text); + + --dark-color-comment-tag-text: var(--dark-color-text); + --dark-color-comment-tag: var(--dark-color-background); + + --dark-color-link: #00aff4; + --dark-color-focus-outline: #4c97f2; + + --dark-color-ts-keyword: #3399ff; + --dark-color-ts-project: #e358ff; + --dark-color-ts-module: var(--dark-color-ts-project); + --dark-color-ts-namespace: var(--dark-color-ts-project); + --dark-color-ts-enum: #f4d93e; + --dark-color-ts-enum-member: var(--dark-color-ts-enum); + --dark-color-ts-variable: #798dff; + --dark-color-ts-function: #a280ff; + --dark-color-ts-class: #8ac4ff; + --dark-color-ts-interface: #6cff87; + --dark-color-ts-constructor: var(--dark-color-ts-class); + --dark-color-ts-property: #ff984d; + --dark-color-ts-method: #ff4db8; + --dark-color-ts-reference: #ff4d82; + --dark-color-ts-call-signature: var(--dark-color-ts-method); + --dark-color-ts-index-signature: var(--dark-color-ts-property); + --dark-color-ts-constructor-signature: var(--dark-color-ts-constructor); + --dark-color-ts-parameter: var(--dark-color-ts-variable); + /* type literal not included as links will never be generated to it */ + --dark-color-ts-type-parameter: #e07d13; + --dark-color-ts-accessor: #ff6060; + --dark-color-ts-get-signature: var(--dark-color-ts-accessor); + --dark-color-ts-set-signature: var(--dark-color-ts-accessor); + --dark-color-ts-type-alias: #ff6492; + /* reference not included as links will be colored with the kind that it points to */ + --dark-color-document: #ffffff; + + --dark-color-alert-note: #0969d9; + --dark-color-alert-tip: #1a7f37; + --dark-color-alert-important: #8250df; + --dark-color-alert-warning: #9a6700; + --dark-color-alert-caution: #cf222e; + + --dark-external-icon: url("data:image/svg+xml;utf8,"); + --dark-color-scheme: dark; + } + + @media (prefers-color-scheme: light) { + :root { + --color-background: var(--light-color-background); + --color-background-secondary: var( + --light-color-background-secondary + ); + --color-background-active: var(--light-color-background-active); + --color-background-warning: var(--light-color-background-warning); + --color-warning-text: var(--light-color-warning-text); + --color-accent: var(--light-color-accent); + --color-active-menu-item: var(--light-color-active-menu-item); + --color-text: var(--light-color-text); + --color-contrast-text: var(--light-color-contrast-text); + --color-text-aside: var(--light-color-text-aside); + + --color-icon-background: var(--light-color-icon-background); + --color-icon-text: var(--light-color-icon-text); + + --color-comment-tag-text: var(--light-color-text); + --color-comment-tag: var(--light-color-background); + + --color-link: var(--light-color-link); + --color-focus-outline: var(--light-color-focus-outline); + + --color-ts-keyword: var(--light-color-ts-keyword); + --color-ts-project: var(--light-color-ts-project); + --color-ts-module: var(--light-color-ts-module); + --color-ts-namespace: var(--light-color-ts-namespace); + --color-ts-enum: var(--light-color-ts-enum); + --color-ts-enum-member: var(--light-color-ts-enum-member); + --color-ts-variable: var(--light-color-ts-variable); + --color-ts-function: var(--light-color-ts-function); + --color-ts-class: var(--light-color-ts-class); + --color-ts-interface: var(--light-color-ts-interface); + --color-ts-constructor: var(--light-color-ts-constructor); + --color-ts-property: var(--light-color-ts-property); + --color-ts-method: var(--light-color-ts-method); + --color-ts-reference: var(--light-color-ts-reference); + --color-ts-call-signature: var(--light-color-ts-call-signature); + --color-ts-index-signature: var(--light-color-ts-index-signature); + --color-ts-constructor-signature: var( + --light-color-ts-constructor-signature + ); + --color-ts-parameter: var(--light-color-ts-parameter); + --color-ts-type-parameter: var(--light-color-ts-type-parameter); + --color-ts-accessor: var(--light-color-ts-accessor); + --color-ts-get-signature: var(--light-color-ts-get-signature); + --color-ts-set-signature: var(--light-color-ts-set-signature); + --color-ts-type-alias: var(--light-color-ts-type-alias); + --color-document: var(--light-color-document); + + --color-alert-note: var(--light-color-alert-note); + --color-alert-tip: var(--light-color-alert-tip); + --color-alert-important: var(--light-color-alert-important); + --color-alert-warning: var(--light-color-alert-warning); + --color-alert-caution: var(--light-color-alert-caution); + + --external-icon: var(--light-external-icon); + --color-scheme: var(--light-color-scheme); + } + } + + @media (prefers-color-scheme: dark) { + :root { + --color-background: var(--dark-color-background); + --color-background-secondary: var( + --dark-color-background-secondary + ); + --color-background-active: var(--dark-color-background-active); + --color-background-warning: var(--dark-color-background-warning); + --color-warning-text: var(--dark-color-warning-text); + --color-accent: var(--dark-color-accent); + --color-active-menu-item: var(--dark-color-active-menu-item); + --color-text: var(--dark-color-text); + --color-contrast-text: var(--dark-color-contrast-text); + --color-text-aside: var(--dark-color-text-aside); + + --color-icon-background: var(--dark-color-icon-background); + --color-icon-text: var(--dark-color-icon-text); + + --color-comment-tag-text: var(--dark-color-text); + --color-comment-tag: var(--dark-color-background); + + --color-link: var(--dark-color-link); + --color-focus-outline: var(--dark-color-focus-outline); + + --color-ts-keyword: var(--dark-color-ts-keyword); + --color-ts-project: var(--dark-color-ts-project); + --color-ts-module: var(--dark-color-ts-module); + --color-ts-namespace: var(--dark-color-ts-namespace); + --color-ts-enum: var(--dark-color-ts-enum); + --color-ts-enum-member: var(--dark-color-ts-enum-member); + --color-ts-variable: var(--dark-color-ts-variable); + --color-ts-function: var(--dark-color-ts-function); + --color-ts-class: var(--dark-color-ts-class); + --color-ts-interface: var(--dark-color-ts-interface); + --color-ts-constructor: var(--dark-color-ts-constructor); + --color-ts-property: var(--dark-color-ts-property); + --color-ts-method: var(--dark-color-ts-method); + --color-ts-reference: var(--dark-color-ts-reference); + --color-ts-call-signature: var(--dark-color-ts-call-signature); + --color-ts-index-signature: var(--dark-color-ts-index-signature); + --color-ts-constructor-signature: var( + --dark-color-ts-constructor-signature + ); + --color-ts-parameter: var(--dark-color-ts-parameter); + --color-ts-type-parameter: var(--dark-color-ts-type-parameter); + --color-ts-accessor: var(--dark-color-ts-accessor); + --color-ts-get-signature: var(--dark-color-ts-get-signature); + --color-ts-set-signature: var(--dark-color-ts-set-signature); + --color-ts-type-alias: var(--dark-color-ts-type-alias); + --color-document: var(--dark-color-document); + + --color-alert-note: var(--dark-color-alert-note); + --color-alert-tip: var(--dark-color-alert-tip); + --color-alert-important: var(--dark-color-alert-important); + --color-alert-warning: var(--dark-color-alert-warning); + --color-alert-caution: var(--dark-color-alert-caution); + + --external-icon: var(--dark-external-icon); + --color-scheme: var(--dark-color-scheme); + } + } + + :root[data-theme="light"] { + --color-background: var(--light-color-background); + --color-background-secondary: var(--light-color-background-secondary); + --color-background-active: var(--light-color-background-active); + --color-background-warning: var(--light-color-background-warning); + --color-warning-text: var(--light-color-warning-text); + --color-icon-background: var(--light-color-icon-background); + --color-accent: var(--light-color-accent); + --color-active-menu-item: var(--light-color-active-menu-item); + --color-text: var(--light-color-text); + --color-contrast-text: var(--light-color-contrast-text); + --color-text-aside: var(--light-color-text-aside); + --color-icon-text: var(--light-color-icon-text); + + --color-comment-tag-text: var(--light-color-text); + --color-comment-tag: var(--light-color-background); + + --color-link: var(--light-color-link); + --color-focus-outline: var(--light-color-focus-outline); + + --color-ts-keyword: var(--light-color-ts-keyword); + --color-ts-project: var(--light-color-ts-project); + --color-ts-module: var(--light-color-ts-module); + --color-ts-namespace: var(--light-color-ts-namespace); + --color-ts-enum: var(--light-color-ts-enum); + --color-ts-enum-member: var(--light-color-ts-enum-member); + --color-ts-variable: var(--light-color-ts-variable); + --color-ts-function: var(--light-color-ts-function); + --color-ts-class: var(--light-color-ts-class); + --color-ts-interface: var(--light-color-ts-interface); + --color-ts-constructor: var(--light-color-ts-constructor); + --color-ts-property: var(--light-color-ts-property); + --color-ts-method: var(--light-color-ts-method); + --color-ts-reference: var(--light-color-ts-reference); + --color-ts-call-signature: var(--light-color-ts-call-signature); + --color-ts-index-signature: var(--light-color-ts-index-signature); + --color-ts-constructor-signature: var( + --light-color-ts-constructor-signature + ); + --color-ts-parameter: var(--light-color-ts-parameter); + --color-ts-type-parameter: var(--light-color-ts-type-parameter); + --color-ts-accessor: var(--light-color-ts-accessor); + --color-ts-get-signature: var(--light-color-ts-get-signature); + --color-ts-set-signature: var(--light-color-ts-set-signature); + --color-ts-type-alias: var(--light-color-ts-type-alias); + --color-document: var(--light-color-document); + + --color-note: var(--light-color-note); + --color-tip: var(--light-color-tip); + --color-important: var(--light-color-important); + --color-warning: var(--light-color-warning); + --color-caution: var(--light-color-caution); + + --external-icon: var(--light-external-icon); + --color-scheme: var(--light-color-scheme); + } + + :root[data-theme="dark"] { + --color-background: var(--dark-color-background); + --color-background-secondary: var(--dark-color-background-secondary); + --color-background-active: var(--dark-color-background-active); + --color-background-warning: var(--dark-color-background-warning); + --color-warning-text: var(--dark-color-warning-text); + --color-icon-background: var(--dark-color-icon-background); + --color-accent: var(--dark-color-accent); + --color-active-menu-item: var(--dark-color-active-menu-item); + --color-text: var(--dark-color-text); + --color-contrast-text: var(--dark-color-contrast-text); + --color-text-aside: var(--dark-color-text-aside); + --color-icon-text: var(--dark-color-icon-text); + + --color-comment-tag-text: var(--dark-color-text); + --color-comment-tag: var(--dark-color-background); + + --color-link: var(--dark-color-link); + --color-focus-outline: var(--dark-color-focus-outline); + + --color-ts-keyword: var(--dark-color-ts-keyword); + --color-ts-project: var(--dark-color-ts-project); + --color-ts-module: var(--dark-color-ts-module); + --color-ts-namespace: var(--dark-color-ts-namespace); + --color-ts-enum: var(--dark-color-ts-enum); + --color-ts-enum-member: var(--dark-color-ts-enum-member); + --color-ts-variable: var(--dark-color-ts-variable); + --color-ts-function: var(--dark-color-ts-function); + --color-ts-class: var(--dark-color-ts-class); + --color-ts-interface: var(--dark-color-ts-interface); + --color-ts-constructor: var(--dark-color-ts-constructor); + --color-ts-property: var(--dark-color-ts-property); + --color-ts-method: var(--dark-color-ts-method); + --color-ts-reference: var(--dark-color-ts-reference); + --color-ts-call-signature: var(--dark-color-ts-call-signature); + --color-ts-index-signature: var(--dark-color-ts-index-signature); + --color-ts-constructor-signature: var( + --dark-color-ts-constructor-signature + ); + --color-ts-parameter: var(--dark-color-ts-parameter); + --color-ts-type-parameter: var(--dark-color-ts-type-parameter); + --color-ts-accessor: var(--dark-color-ts-accessor); + --color-ts-get-signature: var(--dark-color-ts-get-signature); + --color-ts-set-signature: var(--dark-color-ts-set-signature); + --color-ts-type-alias: var(--dark-color-ts-type-alias); + --color-document: var(--dark-color-document); + + --color-note: var(--dark-color-note); + --color-tip: var(--dark-color-tip); + --color-important: var(--dark-color-important); + --color-warning: var(--dark-color-warning); + --color-caution: var(--dark-color-caution); + + --external-icon: var(--dark-external-icon); + --color-scheme: var(--dark-color-scheme); + } + + html { + color-scheme: var(--color-scheme); + @media (prefers-reduced-motion: no-preference) { + scroll-behavior: smooth; + } + } + + *:focus-visible, + .tsd-accordion-summary:focus-visible svg { + outline: 2px solid var(--color-focus-outline); + } + + .always-visible, + .always-visible .tsd-signatures { + display: inherit !important; + } + + h1, + h2, + h3, + h4, + h5, + h6 { + line-height: 1.2; + } + + h1 { + font-size: 1.875rem; + margin: 0.67rem 0; + } + + h2 { + font-size: 1.5rem; + margin: 0.83rem 0; + } + + h3 { + font-size: 1.25rem; + margin: 1rem 0; + } + + h4 { + font-size: 1.05rem; + margin: 1.33rem 0; + } + + h5 { + font-size: 1rem; + margin: 1.5rem 0; + } + + h6 { + font-size: 0.875rem; + margin: 2.33rem 0; + } + + dl, + menu, + ol, + ul { + margin: 1em 0; + } + + dd { + margin: 0 0 0 34px; + } + + .container { + max-width: 1700px; + padding: 0 2rem; + } + + /* Footer */ + footer { + border-top: 1px solid var(--color-accent); + padding-top: 1rem; + padding-bottom: 1rem; + max-height: var(--dim-footer-height); + } + footer > p { + margin: 0 1em; + } + + .container-main { + margin: var(--dim-container-main-margin-y) auto; + /* toolbar, footer, margin */ + min-height: calc( + 100svh - var(--dim-header-height) - var(--dim-footer-height) - + 2 * var(--dim-container-main-margin-y) + ); + } + + @keyframes fade-in { + from { + opacity: 0; + } + to { + opacity: 1; + } + } + @keyframes fade-out { + from { + opacity: 1; + visibility: visible; + } + to { + opacity: 0; + } + } + @keyframes pop-in-from-right { + from { + transform: translate(100%, 0); + } + to { + transform: translate(0, 0); + } + } + @keyframes pop-out-to-right { + from { + transform: translate(0, 0); + visibility: visible; + } + to { + transform: translate(100%, 0); + } + } + body { + background: var(--color-background); + font-family: + -apple-system, BlinkMacSystemFont, "Segoe UI", "Noto Sans", + Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji"; + font-size: 16px; + color: var(--color-text); + margin: 0; + } + + a { + color: var(--color-link); + text-decoration: none; + } + a:hover { + text-decoration: underline; + } + a.external[target="_blank"] { + background-image: var(--external-icon); + background-position: top 3px right; + background-repeat: no-repeat; + padding-right: 13px; + } + a.tsd-anchor-link { + color: var(--color-text); + } + :target { + scroll-margin-block: calc(var(--dim-header-height) + 0.5rem); + } + + code, + pre { + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + padding: 0.2em; + margin: 0; + font-size: 0.875rem; + border-radius: 0.8em; + } + + pre { + position: relative; + white-space: pre-wrap; + word-wrap: break-word; + padding: 10px; + border: 1px solid var(--color-accent); + margin-bottom: 8px; + } + pre code { + padding: 0; + font-size: 100%; + } + pre > button { + position: absolute; + top: 10px; + right: 10px; + opacity: 0; + transition: opacity 0.1s; + box-sizing: border-box; + } + pre:hover > button, + pre > button.visible, + pre > button:focus-visible { + opacity: 1; + } + + blockquote { + margin: 1em 0; + padding-left: 1em; + border-left: 4px solid gray; + } + + img { + max-width: 100%; + } + + * { + scrollbar-width: thin; + scrollbar-color: var(--color-accent) var(--color-icon-background); + } + + *::-webkit-scrollbar { + width: 0.75rem; + } + + *::-webkit-scrollbar-track { + background: var(--color-icon-background); + } + + *::-webkit-scrollbar-thumb { + background-color: var(--color-accent); + border-radius: 999rem; + border: 0.25rem solid var(--color-icon-background); + } + + dialog { + border: none; + outline: none; + padding: 0; + background-color: var(--color-background); + } + dialog::backdrop { + display: none; + } + #tsd-overlay { + background-color: rgba(0, 0, 0, 0.5); + position: fixed; + z-index: 9999; + top: 0; + left: 0; + right: 0; + bottom: 0; + animation: fade-in var(--modal-animation-duration) forwards; + } + #tsd-overlay.closing { + animation-name: fade-out; + } + + .tsd-typography { + line-height: 1.333em; + } + .tsd-typography ul { + list-style: square; + padding: 0 0 0 20px; + margin: 0; + } + .tsd-typography .tsd-index-panel h3, + .tsd-index-panel .tsd-typography h3, + .tsd-typography h4, + .tsd-typography h5, + .tsd-typography h6 { + font-size: 1em; + } + .tsd-typography h5, + .tsd-typography h6 { + font-weight: normal; + } + .tsd-typography p, + .tsd-typography ul, + .tsd-typography ol { + margin: 1em 0; + } + .tsd-typography table { + border-collapse: collapse; + border: none; + } + .tsd-typography td, + .tsd-typography th { + padding: 6px 13px; + border: 1px solid var(--color-accent); + } + .tsd-typography thead, + .tsd-typography tr:nth-child(even) { + background-color: var(--color-background-secondary); + } + + .tsd-alert { + padding: 8px 16px; + margin-bottom: 16px; + border-left: 0.25em solid var(--alert-color); + } + .tsd-alert blockquote > :last-child, + .tsd-alert > :last-child { + margin-bottom: 0; + } + .tsd-alert-title { + color: var(--alert-color); + display: inline-flex; + align-items: center; + } + .tsd-alert-title span { + margin-left: 4px; + } + + .tsd-alert-note { + --alert-color: var(--color-alert-note); + } + .tsd-alert-tip { + --alert-color: var(--color-alert-tip); + } + .tsd-alert-important { + --alert-color: var(--color-alert-important); + } + .tsd-alert-warning { + --alert-color: var(--color-alert-warning); + } + .tsd-alert-caution { + --alert-color: var(--color-alert-caution); + } + + .tsd-breadcrumb { + margin: 0; + margin-top: 1rem; + padding: 0; + color: var(--color-text-aside); + } + .tsd-breadcrumb a { + color: var(--color-text-aside); + text-decoration: none; + } + .tsd-breadcrumb a:hover { + text-decoration: underline; + } + .tsd-breadcrumb li { + display: inline; + } + .tsd-breadcrumb li:after { + content: " / "; + } + + .tsd-comment-tags { + display: flex; + flex-direction: column; + } + dl.tsd-comment-tag-group { + display: flex; + align-items: center; + overflow: hidden; + margin: 0.5em 0; + } + dl.tsd-comment-tag-group dt { + display: flex; + margin-right: 0.5em; + font-size: 0.875em; + font-weight: normal; + } + dl.tsd-comment-tag-group dd { + margin: 0; + } + code.tsd-tag { + padding: 0.25em 0.4em; + border: 0.1em solid var(--color-accent); + margin-right: 0.25em; + font-size: 70%; + } + h1 code.tsd-tag:first-of-type { + margin-left: 0.25em; + } + + dl.tsd-comment-tag-group dd:before, + dl.tsd-comment-tag-group dd:after { + content: " "; + } + dl.tsd-comment-tag-group dd pre, + dl.tsd-comment-tag-group dd:after { + clear: both; + } + dl.tsd-comment-tag-group p { + margin: 0; + } + + .tsd-panel.tsd-comment .lead { + font-size: 1.1em; + line-height: 1.333em; + margin-bottom: 2em; + } + .tsd-panel.tsd-comment .lead:last-child { + margin-bottom: 0; + } + + .tsd-filter-visibility h4 { + font-size: 1rem; + padding-top: 0.75rem; + padding-bottom: 0.5rem; + margin: 0; + } + .tsd-filter-item:not(:last-child) { + margin-bottom: 0.5rem; + } + .tsd-filter-input { + display: flex; + width: -moz-fit-content; + width: fit-content; + align-items: center; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; + } + .tsd-filter-input input[type="checkbox"] { + cursor: pointer; + position: absolute; + width: 1.5em; + height: 1.5em; + opacity: 0; + } + .tsd-filter-input input[type="checkbox"]:disabled { + pointer-events: none; + } + .tsd-filter-input svg { + cursor: pointer; + width: 1.5em; + height: 1.5em; + margin-right: 0.5em; + border-radius: 0.33em; + /* Leaving this at full opacity breaks event listeners on Firefox. + Don't remove unless you know what you're doing. */ + opacity: 0.99; + } + .tsd-filter-input input[type="checkbox"]:focus-visible + svg { + outline: 2px solid var(--color-focus-outline); + } + .tsd-checkbox-background { + fill: var(--color-accent); + } + input[type="checkbox"]:checked ~ svg .tsd-checkbox-checkmark { + stroke: var(--color-text); + } + .tsd-filter-input input:disabled ~ svg > .tsd-checkbox-background { + fill: var(--color-background); + stroke: var(--color-accent); + stroke-width: 0.25rem; + } + .tsd-filter-input input:disabled ~ svg > .tsd-checkbox-checkmark { + stroke: var(--color-accent); + } + + .settings-label { + font-weight: bold; + text-transform: uppercase; + display: inline-block; + } + + .tsd-filter-visibility .settings-label { + margin: 0.75rem 0 0.5rem 0; + } + + .tsd-theme-toggle .settings-label { + margin: 0.75rem 0.75rem 0 0; + } + + .tsd-hierarchy h4 label:hover span { + text-decoration: underline; + } + + .tsd-hierarchy { + list-style: square; + margin: 0; + } + .tsd-hierarchy-target { + font-weight: bold; + } + .tsd-hierarchy-toggle { + color: var(--color-link); + cursor: pointer; + } + + .tsd-full-hierarchy:not(:last-child) { + margin-bottom: 1em; + padding-bottom: 1em; + border-bottom: 1px solid var(--color-accent); + } + .tsd-full-hierarchy, + .tsd-full-hierarchy ul { + list-style: none; + margin: 0; + padding: 0; + } + .tsd-full-hierarchy ul { + padding-left: 1.5rem; + } + .tsd-full-hierarchy a { + padding: 0.25rem 0 !important; + font-size: 1rem; + display: inline-flex; + align-items: center; + color: var(--color-text); + } + .tsd-full-hierarchy svg[data-dropdown] { + cursor: pointer; + } + .tsd-full-hierarchy svg[data-dropdown="false"] { + transform: rotate(-90deg); + } + .tsd-full-hierarchy svg[data-dropdown="false"] ~ ul { + display: none; + } + + .tsd-panel-group.tsd-index-group { + margin-bottom: 0; + } + .tsd-index-panel .tsd-index-list { + list-style: none; + line-height: 1.333em; + margin: 0; + padding: 0.25rem 0 0 0; + overflow: hidden; + display: grid; + grid-template-columns: repeat(3, 1fr); + column-gap: 1rem; + grid-template-rows: auto; + } + @media (max-width: 1024px) { + .tsd-index-panel .tsd-index-list { + grid-template-columns: repeat(2, 1fr); + } + } + @media (max-width: 768px) { + .tsd-index-panel .tsd-index-list { + grid-template-columns: repeat(1, 1fr); + } + } + .tsd-index-panel .tsd-index-list li { + -webkit-page-break-inside: avoid; + -moz-page-break-inside: avoid; + -ms-page-break-inside: avoid; + -o-page-break-inside: avoid; + page-break-inside: avoid; + } + + .tsd-flag { + display: inline-block; + padding: 0.25em 0.4em; + border-radius: 4px; + color: var(--color-comment-tag-text); + background-color: var(--color-comment-tag); + text-indent: 0; + font-size: 75%; + line-height: 1; + font-weight: normal; + } + + .tsd-anchor { + position: relative; + top: -100px; + } + + .tsd-member { + position: relative; + } + .tsd-member .tsd-anchor + h3 { + display: flex; + align-items: center; + margin-top: 0; + margin-bottom: 0; + border-bottom: none; + } + + .tsd-navigation.settings { + margin: 0; + margin-bottom: 1rem; + } + .tsd-navigation > a, + .tsd-navigation .tsd-accordion-summary { + width: calc(100% - 0.25rem); + display: flex; + align-items: center; + } + .tsd-navigation a, + .tsd-navigation summary > span, + .tsd-page-navigation a { + display: flex; + width: calc(100% - 0.25rem); + align-items: center; + padding: 0.25rem; + color: var(--color-text); + text-decoration: none; + box-sizing: border-box; + } + .tsd-navigation a.current, + .tsd-page-navigation a.current { + background: var(--color-active-menu-item); + color: var(--color-contrast-text); + } + .tsd-navigation a:hover, + .tsd-page-navigation a:hover { + text-decoration: underline; + } + .tsd-navigation ul, + .tsd-page-navigation ul { + margin-top: 0; + margin-bottom: 0; + padding: 0; + list-style: none; + } + .tsd-navigation li, + .tsd-page-navigation li { + padding: 0; + max-width: 100%; + } + .tsd-navigation .tsd-nav-link { + display: none; + } + .tsd-nested-navigation { + margin-left: 3rem; + } + .tsd-nested-navigation > li > details { + margin-left: -1.5rem; + } + .tsd-small-nested-navigation { + margin-left: 1.5rem; + } + .tsd-small-nested-navigation > li > details { + margin-left: -1.5rem; + } + + .tsd-page-navigation-section > summary { + padding: 0.25rem; + } + .tsd-page-navigation-section > summary > svg { + margin-right: 0.25rem; + } + .tsd-page-navigation-section > div { + margin-left: 30px; + } + .tsd-page-navigation ul { + padding-left: 1.75rem; + } + + #tsd-sidebar-links a { + margin-top: 0; + margin-bottom: 0.5rem; + line-height: 1.25rem; + } + #tsd-sidebar-links a:last-of-type { + margin-bottom: 0; + } + + a.tsd-index-link { + padding: 0.25rem 0 !important; + font-size: 1rem; + line-height: 1.25rem; + display: inline-flex; + align-items: center; + color: var(--color-text); + } + .tsd-accordion-summary { + list-style-type: none; /* hide marker on non-safari */ + outline: none; /* broken on safari, so just hide it */ + display: flex; + align-items: center; + gap: 0.25rem; + box-sizing: border-box; + } + .tsd-accordion-summary::-webkit-details-marker { + display: none; /* hide marker on safari */ + } + .tsd-accordion-summary, + .tsd-accordion-summary a { + -moz-user-select: none; + -webkit-user-select: none; + -ms-user-select: none; + user-select: none; + + cursor: pointer; + } + .tsd-accordion-summary a { + width: calc(100% - 1.5rem); + } + .tsd-accordion-summary > * { + margin-top: 0; + margin-bottom: 0; + padding-top: 0; + padding-bottom: 0; + } + /* + * We need to be careful to target the arrow indicating whether the accordion + * is open, but not any other SVGs included in the details element. + */ + .tsd-accordion:not([open]) > .tsd-accordion-summary > svg:first-child { + transform: rotate(-90deg); + } + .tsd-index-content > :not(:first-child) { + margin-top: 0.75rem; + } + .tsd-index-summary { + margin-top: 1.5rem; + margin-bottom: 0.75rem; + display: flex; + align-content: center; + } + + .tsd-no-select { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + } + .tsd-kind-icon { + margin-right: 0.5rem; + width: 1.25rem; + height: 1.25rem; + min-width: 1.25rem; + min-height: 1.25rem; + } + .tsd-signature > .tsd-kind-icon { + margin-right: 0.8rem; + } + + .tsd-panel { + margin-bottom: 2.5rem; + } + .tsd-panel.tsd-member { + margin-bottom: 4rem; + } + .tsd-panel:empty { + display: none; + } + .tsd-panel > h1, + .tsd-panel > h2, + .tsd-panel > h3 { + margin: 1.5rem -1.5rem 0.75rem -1.5rem; + padding: 0 1.5rem 0.75rem 1.5rem; + } + .tsd-panel > h1.tsd-before-signature, + .tsd-panel > h2.tsd-before-signature, + .tsd-panel > h3.tsd-before-signature { + margin-bottom: 0; + border-bottom: none; + } + + .tsd-panel-group { + margin: 2rem 0; + } + .tsd-panel-group.tsd-index-group { + margin: 2rem 0; + } + .tsd-panel-group.tsd-index-group details { + margin: 2rem 0; + } + .tsd-panel-group > .tsd-accordion-summary { + margin-bottom: 1rem; + } + + #tsd-search[open] { + animation: fade-in var(--modal-animation-duration) ease-out forwards; + } + #tsd-search[open].closing { + animation-name: fade-out; + } + + /* Avoid setting `display` on closed dialog */ + #tsd-search[open] { + display: flex; + flex-direction: column; + padding: 1rem; + width: 32rem; + max-width: 90vw; + max-height: calc(100vh - env(keyboard-inset-height, 0px) - 25vh); + /* Anchor dialog to top */ + margin-top: 10vh; + border-radius: 6px; + will-change: max-height; + } + #tsd-search-input { + box-sizing: border-box; + width: 100%; + padding: 0 0.625rem; /* 10px */ + outline: 0; + border: 2px solid var(--color-accent); + background-color: transparent; + color: var(--color-text); + border-radius: 4px; + height: 2.5rem; + flex: 0 0 auto; + font-size: 0.875rem; + transition: border-color 0.2s, background-color 0.2s; + } + #tsd-search-input:focus-visible { + background-color: var(--color-background-active); + border-color: transparent; + color: var(--color-contrast-text); + } + #tsd-search-input::placeholder { + color: inherit; + opacity: 0.8; + } + #tsd-search-results { + margin: 0; + padding: 0; + list-style: none; + flex: 1 1 auto; + display: flex; + flex-direction: column; + overflow-y: auto; + } + #tsd-search-results:not(:empty) { + margin-top: 0.5rem; + } + #tsd-search-results > li { + background-color: var(--color-background); + line-height: 1.5; + box-sizing: border-box; + border-radius: 4px; + } + #tsd-search-results > li:nth-child(even) { + background-color: var(--color-background-secondary); + } + #tsd-search-results > li:is(:hover, [aria-selected="true"]) { + background-color: var(--color-background-active); + color: var(--color-contrast-text); + } + /* It's important that this takes full size of parent `li`, to capture a click on `li` */ + #tsd-search-results > li > a { + display: flex; + align-items: center; + padding: 0.5rem 0.25rem; + box-sizing: border-box; + width: 100%; + } + #tsd-search-results > li > a > .text { + flex: 1 1 auto; + min-width: 0; + overflow-wrap: anywhere; + } + #tsd-search-results > li > a .parent { + color: var(--color-text-aside); + } + #tsd-search-results > li > a mark { + color: inherit; + background-color: inherit; + font-weight: bold; + } + #tsd-search-status { + flex: 1; + display: grid; + place-content: center; + text-align: center; + overflow-wrap: anywhere; + } + #tsd-search-status:not(:empty) { + min-height: 6rem; + } + + .tsd-signature { + margin: 0 0 1rem 0; + padding: 1rem 0.5rem; + border: 1px solid var(--color-accent); + font-family: Menlo, Monaco, Consolas, "Courier New", monospace; + font-size: 14px; + overflow-x: auto; + } + + .tsd-signature-keyword { + color: var(--color-ts-keyword); + font-weight: normal; + } + + .tsd-signature-symbol { + color: var(--color-text-aside); + font-weight: normal; + } + + .tsd-signature-type { + font-style: italic; + font-weight: normal; + } + + .tsd-signatures { + padding: 0; + margin: 0 0 1em 0; + list-style-type: none; + } + .tsd-signatures .tsd-signature { + margin: 0; + border-color: var(--color-accent); + border-width: 1px 0; + transition: background-color 0.1s; + } + .tsd-signatures .tsd-index-signature:not(:last-child) { + margin-bottom: 1em; + } + .tsd-signatures .tsd-index-signature .tsd-signature { + border-width: 1px; + } + .tsd-description .tsd-signatures .tsd-signature { + border-width: 1px; + } + + ul.tsd-parameter-list, + ul.tsd-type-parameter-list { + list-style: square; + margin: 0; + padding-left: 20px; + } + ul.tsd-parameter-list > li.tsd-parameter-signature, + ul.tsd-type-parameter-list > li.tsd-parameter-signature { + list-style: none; + margin-left: -20px; + } + ul.tsd-parameter-list h5, + ul.tsd-type-parameter-list h5 { + font-size: 16px; + margin: 1em 0 0.5em 0; + } + .tsd-sources { + margin-top: 1rem; + font-size: 0.875em; + } + .tsd-sources a { + color: var(--color-text-aside); + text-decoration: underline; + } + .tsd-sources ul { + list-style: none; + padding: 0; + } + + .tsd-page-toolbar { + position: sticky; + z-index: 1; + top: 0; + left: 0; + width: 100%; + color: var(--color-text); + background: var(--color-background-secondary); + border-bottom: var(--dim-toolbar-border-bottom-width) + var(--color-accent) solid; + transition: transform 0.3s ease-in-out; + } + .tsd-page-toolbar a { + color: var(--color-text); + } + .tsd-toolbar-contents { + display: flex; + align-items: center; + height: var(--dim-toolbar-contents-height); + margin: 0 auto; + } + .tsd-toolbar-contents > .title { + font-weight: bold; + margin-right: auto; + } + #tsd-toolbar-links { + display: flex; + align-items: center; + gap: 1.5rem; + margin-right: 1rem; + } + + .tsd-widget { + box-sizing: border-box; + display: inline-block; + opacity: 0.8; + height: 2.5rem; + width: 2.5rem; + transition: opacity 0.1s, background-color 0.1s; + text-align: center; + cursor: pointer; + border: none; + background-color: transparent; + } + .tsd-widget:hover { + opacity: 0.9; + } + .tsd-widget:active { + opacity: 1; + background-color: var(--color-accent); + } + #tsd-toolbar-menu-trigger { + display: none; + } + + .tsd-member-summary-name { + display: inline-flex; + align-items: center; + padding: 0.25rem; + text-decoration: none; + } + + .tsd-anchor-icon { + display: inline-flex; + align-items: center; + margin-left: 0.5rem; + color: var(--color-text); + vertical-align: middle; + } + + .tsd-anchor-icon svg { + width: 1em; + height: 1em; + visibility: hidden; + } + + .tsd-member-summary-name:hover > .tsd-anchor-icon svg, + .tsd-anchor-link:hover > .tsd-anchor-icon svg, + .tsd-anchor-icon:focus-visible svg { + visibility: visible; + } + + .deprecated { + text-decoration: line-through !important; + } + + .warning { + padding: 1rem; + color: var(--color-warning-text); + background: var(--color-background-warning); + } + + .tsd-kind-project { + color: var(--color-ts-project); + } + .tsd-kind-module { + color: var(--color-ts-module); + } + .tsd-kind-namespace { + color: var(--color-ts-namespace); + } + .tsd-kind-enum { + color: var(--color-ts-enum); + } + .tsd-kind-enum-member { + color: var(--color-ts-enum-member); + } + .tsd-kind-variable { + color: var(--color-ts-variable); + } + .tsd-kind-function { + color: var(--color-ts-function); + } + .tsd-kind-class { + color: var(--color-ts-class); + } + .tsd-kind-interface { + color: var(--color-ts-interface); + } + .tsd-kind-constructor { + color: var(--color-ts-constructor); + } + .tsd-kind-property { + color: var(--color-ts-property); + } + .tsd-kind-method { + color: var(--color-ts-method); + } + .tsd-kind-reference { + color: var(--color-ts-reference); + } + .tsd-kind-call-signature { + color: var(--color-ts-call-signature); + } + .tsd-kind-index-signature { + color: var(--color-ts-index-signature); + } + .tsd-kind-constructor-signature { + color: var(--color-ts-constructor-signature); + } + .tsd-kind-parameter { + color: var(--color-ts-parameter); + } + .tsd-kind-type-parameter { + color: var(--color-ts-type-parameter); + } + .tsd-kind-accessor { + color: var(--color-ts-accessor); + } + .tsd-kind-get-signature { + color: var(--color-ts-get-signature); + } + .tsd-kind-set-signature { + color: var(--color-ts-set-signature); + } + .tsd-kind-type-alias { + color: var(--color-ts-type-alias); + } + + /* if we have a kind icon, don't color the text by kind */ + .tsd-kind-icon ~ span { + color: var(--color-text); + } + + /* mobile */ + @media (max-width: 769px) { + #tsd-toolbar-menu-trigger { + display: inline-block; + /* temporary fix to vertically align, for compatibility */ + line-height: 2.5; + } + #tsd-toolbar-links { + display: none; + } + + .container-main { + display: flex; + } + .col-content { + float: none; + max-width: 100%; + width: 100%; + } + .col-sidebar { + position: fixed !important; + overflow-y: auto; + -webkit-overflow-scrolling: touch; + z-index: 1024; + top: 0 !important; + bottom: 0 !important; + left: auto !important; + right: 0 !important; + padding: 1.5rem 1.5rem 0 0; + width: 75vw; + visibility: hidden; + background-color: var(--color-background); + transform: translate(100%, 0); + } + .col-sidebar > *:last-child { + padding-bottom: 20px; + } + .overlay { + content: ""; + display: block; + position: fixed; + z-index: 1023; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.75); + visibility: hidden; + } + + .to-has-menu .overlay { + animation: fade-in 0.4s; + } + + .to-has-menu .col-sidebar { + animation: pop-in-from-right 0.4s; + } + + .from-has-menu .overlay { + animation: fade-out 0.4s; + } + + .from-has-menu .col-sidebar { + animation: pop-out-to-right 0.4s; + } + + .has-menu body { + overflow: hidden; + } + .has-menu .overlay { + visibility: visible; + } + .has-menu .col-sidebar { + visibility: visible; + transform: translate(0, 0); + display: flex; + flex-direction: column; + gap: 1.5rem; + max-height: 100vh; + padding: 1rem 2rem; + } + .has-menu .tsd-navigation { + max-height: 100%; + } + .tsd-navigation .tsd-nav-link { + display: flex; + } + } + + /* one sidebar */ + @media (min-width: 770px) { + .container-main { + display: grid; + grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); + grid-template-areas: "sidebar content"; + --dim-container-main-margin-y: 2rem; + } + + .tsd-breadcrumb { + margin-top: 0; + } + + .col-sidebar { + grid-area: sidebar; + } + .col-content { + grid-area: content; + padding: 0 1rem; + } + } + @media (min-width: 770px) and (max-width: 1399px) { + .col-sidebar { + max-height: calc( + 100vh - var(--dim-header-height) - var(--dim-footer-height) - + 2 * var(--dim-container-main-margin-y) + ); + overflow: auto; + position: sticky; + top: calc( + var(--dim-header-height) + var(--dim-container-main-margin-y) + ); + } + .site-menu { + margin-top: 1rem; + } + } + + /* two sidebars */ + @media (min-width: 1200px) { + .container-main { + grid-template-columns: + minmax(0, 1fr) minmax(0, 2.5fr) minmax( + 0, + 20rem + ); + grid-template-areas: "sidebar content toc"; + } + + .col-sidebar { + display: contents; + } + + .page-menu { + grid-area: toc; + padding-left: 1rem; + } + .site-menu { + grid-area: sidebar; + } + + .site-menu { + margin-top: 0rem; + } + + .page-menu, + .site-menu { + max-height: calc( + 100vh - var(--dim-header-height) - var(--dim-footer-height) - + 2 * var(--dim-container-main-margin-y) + ); + overflow: auto; + position: sticky; + top: calc( + var(--dim-header-height) + var(--dim-container-main-margin-y) + ); + } + } +} diff --git a/docs/components/classes/A2ATaskSocket.html b/docs/components/classes/A2ATaskSocket.html new file mode 100644 index 0000000..ee0d9bd --- /dev/null +++ b/docs/components/classes/A2ATaskSocket.html @@ -0,0 +1,63 @@ +A2ATaskSocket | ART Framework API Docs
      ART Framework API Docs
        Preparing search index...

        Class A2ATaskSocket

        A specialized TypedSocket for handling A2A task status updates and events. +Allows filtering by task status, type, agent, and other criteria. +Can optionally fetch historical task data from a repository.

        +

        Hierarchy (View Summary)

        Index

        Constructors

        Methods

        • Retrieves historical A2A task events, optionally filtered by criteria. +Note: This method constructs events from stored tasks, not from a dedicated event log.

          +

          Parameters

          • Optionalfilter: A2ATaskFilter

            Optional A2ATaskFilter to filter the tasks.

            +
          • Optionaloptions: { limit?: number; threadId?: string }

            Optional threadId and limit.

            +

          Returns Promise<A2ATaskEvent[]>

          A promise resolving to an array of A2A task events.

          +
        • Notifies all relevant subscribers with new data.

          +

          Parameters

          • data: A2ATaskEvent

            The data payload to send to subscribers.

            +
          • Optionaloptions: { targetSessionId?: string; targetThreadId?: string }

            Optional targeting options (e.g., targetThreadId).

            +
          • OptionalfilterCheck: (data: A2ATaskEvent, filter?: A2ATaskFilter) => boolean

            A function to check if a subscription's filter matches the data.

            +

          Returns void

        • Convenience method to notify about task completion.

          +

          Parameters

          • task: A2ATask

            The completed A2A task.

            +
          • Optionalmetadata: { automatic?: boolean; context?: Record<string, any>; source?: string }

            Optional additional metadata about the completion.

            +
            • Optionalautomatic?: boolean

              Whether this was an automatic update or manual

              +
            • Optionalcontext?: Record<string, any>

              Any additional context

              +
            • Optionalsource?: string

              The component that triggered the update

              +

          Returns void

        • Convenience method to notify about a task creation.

          +

          Parameters

          • task: A2ATask

            The newly created A2A task.

            +
          • Optionalmetadata: { automatic?: boolean; context?: Record<string, any>; source?: string }

            Optional additional metadata about the creation.

            +
            • Optionalautomatic?: boolean

              Whether this was an automatic update or manual

              +
            • Optionalcontext?: Record<string, any>

              Any additional context

              +
            • Optionalsource?: string

              The component that triggered the update

              +

          Returns void

        • Convenience method to notify about task delegation.

          +

          Parameters

          • task: A2ATask

            The delegated A2A task.

            +
          • Optionalmetadata: { automatic?: boolean; context?: Record<string, any>; source?: string }

            Optional additional metadata about the delegation.

            +
            • Optionalautomatic?: boolean

              Whether this was an automatic update or manual

              +
            • Optionalcontext?: Record<string, any>

              Any additional context

              +
            • Optionalsource?: string

              The component that triggered the update

              +

          Returns void

        • Convenience method to notify about task failure.

          +

          Parameters

          • task: A2ATask

            The failed A2A task.

            +
          • Optionalmetadata: { automatic?: boolean; context?: Record<string, any>; source?: string }

            Optional additional metadata about the failure.

            +
            • Optionalautomatic?: boolean

              Whether this was an automatic update or manual

              +
            • Optionalcontext?: Record<string, any>

              Any additional context

              +
            • Optionalsource?: string

              The component that triggered the update

              +

          Returns void

        • Convenience method to notify about a task update.

          +

          Parameters

          • task: A2ATask

            The updated A2A task.

            +
          • OptionalpreviousStatus: A2ATaskStatus

            The previous status of the task (if status changed).

            +
          • Optionalmetadata: { automatic?: boolean; context?: Record<string, any>; source?: string }

            Optional additional metadata about the update.

            +
            • Optionalautomatic?: boolean

              Whether this was an automatic update or manual

              +
            • Optionalcontext?: Record<string, any>

              Any additional context

              +
            • Optionalsource?: string

              The component that triggered the update

              +

          Returns void

        diff --git a/docs/components/classes/ARTError.html b/docs/components/classes/ARTError.html new file mode 100644 index 0000000..3e35f27 --- /dev/null +++ b/docs/components/classes/ARTError.html @@ -0,0 +1,19 @@ +ARTError | ART Framework API Docs
        ART Framework API Docs
          Preparing search index...

          Class ARTError

          Custom error class for ART framework specific errors. +It includes an error code, an optional original error for chaining, +and a details object for additional context.

          +

          Hierarchy (View Summary)

          Index

          Constructors

          Properties

          Methods

          Constructors

          • Creates an instance of ARTError.

            +

            Parameters

            • message: string

              The error message.

              +
            • code: ErrorCode

              The error code.

              +
            • OptionaloriginalError: Error

              The original error, if any.

              +
            • Optionaldetails: Record<string, any> = {}

              Additional details about the error.

              +

            Returns ARTError

          Properties

          code: ErrorCode

          The specific error code from the ErrorCode enum.

          +
          details: Record<string, any>

          A record of additional details about the error.

          +
          originalError?: Error

          The original error that caused this error, if any.

          +

          Methods

          • Returns a string representation of the error, including the original error if present.

            +

            Returns string

            The string representation of the error.

            +
          diff --git a/docs/components/classes/AdapterInstantiationError.html b/docs/components/classes/AdapterInstantiationError.html new file mode 100644 index 0000000..1d40877 --- /dev/null +++ b/docs/components/classes/AdapterInstantiationError.html @@ -0,0 +1,12 @@ +AdapterInstantiationError | ART Framework API Docs
          ART Framework API Docs
            Preparing search index...

            Class AdapterInstantiationError

            Error thrown when an adapter for a provider fails to instantiate.

            +

            Hierarchy (View Summary)

            Index

            Constructors

            Properties

            Methods

            Constructors

            Properties

            code: ErrorCode

            The specific error code from the ErrorCode enum.

            +
            details: Record<string, any>

            A record of additional details about the error.

            +
            originalError?: Error

            The original error that caused this error, if any.

            +

            Methods

            • Returns a string representation of the error, including the original error if present.

              +

              Returns string

              The string representation of the error.

              +
            diff --git a/docs/components/classes/AgentDiscoveryService.html b/docs/components/classes/AgentDiscoveryService.html new file mode 100644 index 0000000..734d369 --- /dev/null +++ b/docs/components/classes/AgentDiscoveryService.html @@ -0,0 +1,28 @@ +AgentDiscoveryService | ART Framework API Docs
            ART Framework API Docs
              Preparing search index...

              Class AgentDiscoveryService

              Service for discovering A2A protocol compatible agents. +Implements the A2A discovery standards for finding and identifying compatible agents.

              +
              Index

              Constructors

              Methods

              • Discovers all available A2A agents from the discovery endpoint.

                +

                Parameters

                • OptionaltraceId: string

                  Optional trace ID for request tracking

                  +

                Returns Promise<A2AAgentInfo[]>

                Promise resolving to array of discovered A2A agents

                +

                If discovery fails or no agents are found

                +
              • Finds agents by specific capabilities.

                +

                Parameters

                • capabilities: string[]

                  Array of required capabilities

                  +
                • OptionaltraceId: string

                  Optional trace ID for request tracking

                  +

                Returns Promise<A2AAgentInfo[]>

                Promise resolving to agents that have all specified capabilities

                +
              • Finds the top K A2A agents for a specific task type, ranked by suitability. +This method acts as a pre-filter, returning a list of the most promising candidates +for an LLM to make the final selection from.

                +

                Parameters

                • taskType: string

                  The type of task (e.g., 'analysis', 'research', 'generation')

                  +
                • topK: number = 3

                  The maximum number of agents to return.

                  +
                • OptionaltraceId: string

                  Optional trace ID for request tracking.

                  +

                Returns Promise<A2AAgentInfo[]>

                Promise resolving to a ranked array of matching agents.

                +

                TODO: Revisit and enhance the scoring algorithm.

                +
              diff --git a/docs/components/classes/AnthropicAdapter.html b/docs/components/classes/AnthropicAdapter.html new file mode 100644 index 0000000..0841dda --- /dev/null +++ b/docs/components/classes/AnthropicAdapter.html @@ -0,0 +1,22 @@ +AnthropicAdapter | ART Framework API Docs
              ART Framework API Docs
                Preparing search index...

                Class AnthropicAdapter

                Implements the ProviderAdapter interface for interacting with Anthropic's +Messages API (Claude models) using the official SDK.

                +

                Handles formatting requests, parsing responses, streaming, and tool use.

                +
                +

                Implements

                Index

                Constructors

                Properties

                Methods

                Constructors

                Properties

                providerName: "anthropic" = 'anthropic'

                The unique identifier name for this provider (e.g., 'openai', 'anthropic').

                +

                Methods

                • Sends a request to the Anthropic Messages API. +Translates ArtStandardPrompt to the Anthropic format and handles streaming and tool use.

                  +

                  Parameters

                  • prompt: ArtStandardPrompt

                    The standardized prompt messages.

                    +
                  • options: CallOptions

                    Call options, including threadId, traceId, stream, callContext, +model (override), tools (available tools), and Anthropic-specific +generation parameters from providerConfig.adapterOptions.

                    +

                  Returns Promise<AsyncIterable<StreamEvent, any, any>>

                  A promise resolving to an AsyncIterable of StreamEvent objects.

                  +
                diff --git a/docs/components/classes/ApiKeyStrategy.html b/docs/components/classes/ApiKeyStrategy.html new file mode 100644 index 0000000..a1b1787 --- /dev/null +++ b/docs/components/classes/ApiKeyStrategy.html @@ -0,0 +1,17 @@ +ApiKeyStrategy | ART Framework API Docs
                ART Framework API Docs
                  Preparing search index...

                  Class ApiKeyStrategy

                  Simple API key authentication strategy. +Supports configurable header names for different service requirements.

                  +

                  Implements

                  Index

                  Constructors

                  • Creates a new API key authentication strategy.

                    +

                    Parameters

                    • apiKey: string

                      The API key to use for authentication

                      +
                    • headerName: string = 'Authorization'

                      The header name to use (defaults to 'Authorization')

                      +

                    Returns ApiKeyStrategy

                  Methods

                  • Generates authentication headers for API key-based authentication. +Uses Bearer token format for Authorization header, plain key for custom headers.

                    +

                    Returns Promise<Record<string, string>>

                    Promise resolving to authentication headers

                    +
                  • Gets the configured header name for this strategy.

                    +

                    Returns string

                    The header name that will be used

                    +
                  • Checks if this strategy uses the standard Authorization header.

                    +

                    Returns boolean

                    True if using Authorization header, false for custom headers

                    +
                  diff --git a/docs/components/classes/ApiQueueTimeoutError.html b/docs/components/classes/ApiQueueTimeoutError.html new file mode 100644 index 0000000..8541c1e --- /dev/null +++ b/docs/components/classes/ApiQueueTimeoutError.html @@ -0,0 +1,12 @@ +ApiQueueTimeoutError | ART Framework API Docs
                  ART Framework API Docs
                    Preparing search index...

                    Class ApiQueueTimeoutError

                    Error thrown when a timeout occurs while waiting for an available instance of an API provider.

                    +

                    Hierarchy (View Summary)

                    Index

                    Constructors

                    Properties

                    Methods

                    Constructors

                    Properties

                    code: ErrorCode

                    The specific error code from the ErrorCode enum.

                    +
                    details: Record<string, any>

                    A record of additional details about the error.

                    +
                    originalError?: Error

                    The original error that caused this error, if any.

                    +

                    Methods

                    • Returns a string representation of the error, including the original error if present.

                      +

                      Returns string

                      The string representation of the error.

                      +
                    diff --git a/docs/components/classes/AuthManager.html b/docs/components/classes/AuthManager.html new file mode 100644 index 0000000..3602252 --- /dev/null +++ b/docs/components/classes/AuthManager.html @@ -0,0 +1,47 @@ +AuthManager | ART Framework API Docs
                    ART Framework API Docs
                      Preparing search index...

                      Class AuthManager

                      Central authentication manager for handling multiple authentication strategies. +Manages registration and retrieval of different auth strategies for secure connections +to remote services like MCP servers and A2A agents.

                      +
                      Index

                      Constructors

                      Methods

                      • Retrieves authentication headers from the specified strategy.

                        +

                        Parameters

                        • strategyId: string

                          The ID of the registered strategy to use

                          +

                        Returns Promise<Record<string, string>>

                        Promise resolving to authentication headers

                        +

                        If strategy is not found or authentication fails

                        +
                      • Handles the redirect from an OAuth provider.

                        +

                        Parameters

                        • strategyId: string

                          The ID of the strategy that initiated the redirect.

                          +

                        Returns Promise<void>

                        A promise that resolves when the redirect has been handled.

                        +

                        If the strategy is not found or does not support handling redirects.

                        +
                      • Checks if a strategy with the given ID is registered.

                        +

                        Parameters

                        • strategyId: string

                          The ID to check

                          +

                        Returns boolean

                        True if the strategy exists, false otherwise

                        +
                      • Checks if the user is authenticated with a specific strategy.

                        +

                        Parameters

                        • strategyId: string

                          The ID of the strategy to check.

                          +

                        Returns Promise<boolean>

                        A promise that resolves to true if authenticated, false otherwise.

                        +
                      • Initiates the login flow for a specific strategy.

                        +

                        Parameters

                        • strategyId: string

                          The ID of the strategy to use for login.

                          +

                        Returns Promise<void>

                        A promise that resolves when the login process is initiated.

                        +

                        If the strategy is not found or does not support login.

                        +
                      • Logs the user out of a specific strategy.

                        +

                        Parameters

                        • strategyId: string

                          The ID of the strategy to use for logout.

                          +

                        Returns void

                        If the strategy is not found or does not support logout.

                        +
                      • Registers an authentication strategy with the given ID.

                        +

                        Parameters

                        • strategyId: string

                          Unique identifier for the strategy (e.g., 'default_zyntopia_auth', 'api_key_strategy')

                          +
                        • strategy: IAuthStrategy

                          Implementation of IAuthStrategy

                          +

                        Returns void

                        If strategyId is empty or null

                        +
                      • Removes a registered strategy.

                        +

                        Parameters

                        • strategyId: string

                          The ID of the strategy to remove

                          +

                        Returns boolean

                        True if strategy was removed, false if it didn't exist

                        +
                      diff --git a/docs/components/classes/CalculatorTool.html b/docs/components/classes/CalculatorTool.html new file mode 100644 index 0000000..6dad23d --- /dev/null +++ b/docs/components/classes/CalculatorTool.html @@ -0,0 +1,27 @@ +CalculatorTool | ART Framework API Docs
                      ART Framework API Docs
                        Preparing search index...

                        Class CalculatorTool

                        An ART Framework tool that safely evaluates mathematical expressions using the mathjs library. +It supports basic arithmetic, variables via a scope, complex numbers, and a predefined list of safe functions.

                        +

                        This tool is designed to be used within the ART framework's ToolSystem. +It provides a safe way to perform mathematical calculations by leveraging +the mathjs library. The tool validates the input expression to ensure it's a +single, valid mathematical expression before evaluation.

                        +
                        +

                        Implements

                        Index

                        Constructors

                        Properties

                        Methods

                        Constructors

                        Properties

                        schema: ToolSchema = ...

                        The schema definition for the CalculatorTool, conforming to the ToolSchema interface. +It defines the tool's name, description, input parameters (expression and optional scope), +and provides examples for the LLM.

                        +
                        toolName: "calculator"

                        The unique name identifier for this tool.

                        +

                        Methods

                        • Executes the calculator tool by evaluating the provided mathematical expression. +It uses a restricted scope including only allowed mathjs functions and any variables +passed in the input.scope. Handles basic number and complex number results.

                          +

                          Parameters

                          • input: any

                            An object containing the expression (string) and optional scope (object). Must match inputSchema.

                            +
                          • context: ExecutionContext

                            The execution context containing threadId, traceId, etc.

                            +

                          Returns Promise<ToolResult>

                          A promise resolving to a ToolResult object. +On success, status is 'success' and output is { result: number | string }. +On failure, status is 'error' and error contains the error message.

                          +
                        diff --git a/docs/components/classes/ConversationSocket.html b/docs/components/classes/ConversationSocket.html new file mode 100644 index 0000000..8cb6ce0 --- /dev/null +++ b/docs/components/classes/ConversationSocket.html @@ -0,0 +1,27 @@ +ConversationSocket | ART Framework API Docs
                        ART Framework API Docs
                          Preparing search index...

                          Class ConversationSocket

                          A specialized TypedSocket for handling ConversationMessage data. +Allows filtering by MessageRole. +Can optionally fetch historical messages from a repository.

                          +

                          Hierarchy (View Summary)

                          Index

                          Constructors

                          Methods

                          diff --git a/docs/components/classes/DeepSeekAdapter.html b/docs/components/classes/DeepSeekAdapter.html new file mode 100644 index 0000000..84abdd9 --- /dev/null +++ b/docs/components/classes/DeepSeekAdapter.html @@ -0,0 +1,20 @@ +DeepSeekAdapter | ART Framework API Docs
                          ART Framework API Docs
                            Preparing search index...

                            Class DeepSeekAdapter

                            This adapter provides a consistent interface for ART agents to use DeepSeek models, +handling the conversion of standard ART prompts to the DeepSeek API format and +parsing the responses into the ART StreamEvent format.

                            +

                            ProviderAdapter for the interface it implements.

                            +

                            Implements

                            Index

                            Constructors

                            Properties

                            Methods

                            Constructors

                            Properties

                            providerName: "deepseek" = 'deepseek'

                            The unique identifier name for this provider (e.g., 'openai', 'anthropic').

                            +

                            Methods

                            diff --git a/docs/components/classes/GeminiAdapter.html b/docs/components/classes/GeminiAdapter.html new file mode 100644 index 0000000..0871e19 --- /dev/null +++ b/docs/components/classes/GeminiAdapter.html @@ -0,0 +1,55 @@ +GeminiAdapter | ART Framework API Docs
                            ART Framework API Docs
                              Preparing search index...

                              Class GeminiAdapter

                              Adapter for Google's Gemini models.

                              +

                              Implements

                              Index

                              Constructors

                              Properties

                              Methods

                              Constructors

                              Properties

                              providerName: "gemini" = 'gemini'

                              The unique identifier name for this provider (e.g., 'openai', 'anthropic').

                              +

                              Methods

                              • Makes a call to the configured Gemini model. +Translates the ArtStandardPrompt into the Gemini API format, sends the request +using the @google/genai SDK, and yields StreamEvent objects representing +the response (tokens, metadata, errors, end signal).

                                +

                                Handles both streaming and non-streaming requests based on options.stream.

                                +

                                Thinking tokens (Gemini):

                                +
                                  +
                                • On supported Gemini models (e.g., gemini-2.5-*), you can enable thought output via config.thinkingConfig.
                                • +
                                • This adapter reads provider-specific flags from the call options: +
                                    +
                                  • options.gemini.thinking.includeThoughts: boolean — when true, requests thought (reasoning) output.
                                  • +
                                  • options.gemini.thinking.thinkingBudget?: number — optional token budget for thinking.
                                  • +
                                  +
                                • +
                                • When enabled and supported, the adapter will attempt to differentiate thought vs response parts and set +StreamEvent.tokenType accordingly: +
                                    +
                                  • For planning calls (callContext === 'AGENT_THOUGHT'): AGENT_THOUGHT_LLM_THINKING or AGENT_THOUGHT_LLM_RESPONSE.
                                  • +
                                  • For synthesis calls (callContext === 'FINAL_SYNTHESIS'): FINAL_SYNTHESIS_LLM_THINKING or FINAL_SYNTHESIS_LLM_RESPONSE.
                                  • +
                                  +
                                • +
                                • LLMMetadata.thinkingTokens will be populated if the provider reports separate thinking token usage.
                                • +
                                • If the SDK/model does not expose thought parts, the adapter falls back to labeling tokens as ...LLM_RESPONSE.
                                • +
                                +

                                Parameters

                                • prompt: ArtStandardPrompt

                                  The standardized prompt messages.

                                  +
                                • options: CallOptions

                                  Options for the LLM call, including streaming preference, model override, and execution context.

                                  +

                                Returns Promise<AsyncIterable<StreamEvent, any, any>>

                                An async iterable that yields StreamEvent objects.

                                +
                                  +
                                • TOKEN: Contains a chunk of the response text. tokenType indicates if it's part of agent thought or final synthesis. +When Gemini thinking is enabled and available, tokenType may be one of the ...LLM_THINKING or +...LLM_RESPONSE variants to separate thought vs response tokens.
                                • +
                                • METADATA: Contains information like stop reason, token counts, and timing, yielded once at the end.
                                • +
                                • ERROR: Contains any error encountered during translation, SDK call, or response processing.
                                • +
                                • END: Signals the completion of the stream.
                                • +
                                +
                                // Enable Gemini thinking (if supported by the selected model)
                                const stream = await geminiAdapter.call(prompt, {
                                threadId,
                                stream: true,
                                callContext: 'FINAL_SYNTHESIS',
                                providerConfig, // your RuntimeProviderConfig
                                gemini: {
                                thinking: { includeThoughts: true, thinkingBudget: 8096 }
                                }
                                });
                                for await (const evt of stream) {
                                if (evt.type === 'TOKEN') {
                                // evt.tokenType may be FINAL_SYNTHESIS_LLM_THINKING or FINAL_SYNTHESIS_LLM_RESPONSE
                                }
                                } +
                                + +
                              diff --git a/docs/components/classes/GenericOAuthStrategy.html b/docs/components/classes/GenericOAuthStrategy.html new file mode 100644 index 0000000..b72e34a --- /dev/null +++ b/docs/components/classes/GenericOAuthStrategy.html @@ -0,0 +1,21 @@ +GenericOAuthStrategy | ART Framework API Docs
                              ART Framework API Docs
                                Preparing search index...

                                Class GenericOAuthStrategy

                                Generic OAuth 2.0 authentication strategy with token caching and refresh capabilities. +Supports client credentials flow and authorization code flow with automatic token refresh.

                                +

                                This strategy is not recommended for browser-based applications as it uses the insecure client_credentials grant type. Please use PKCEOAuthStrategy instead.

                                +

                                Hierarchy (View Summary)

                                Implements

                                Index

                                Constructors

                                Methods

                                • Gets authentication headers, automatically handling token refresh if needed.

                                  +

                                  Returns Promise<Record<string, string>>

                                  A promise that resolves to the authentication headers.

                                  +
                                • Gets information about the current cached token.

                                  +

                                  Returns null | { expiresAt: Date; hasRefreshToken: boolean; scope?: string }

                                  Token information or null if no token is cached.

                                  +
                                • Manually refreshes the cached token.

                                  +

                                  Returns Promise<Record<string, string>>

                                  A promise that resolves to new authentication headers.

                                  +
                                diff --git a/docs/components/classes/InMemoryStorageAdapter.html b/docs/components/classes/InMemoryStorageAdapter.html new file mode 100644 index 0000000..95f1333 --- /dev/null +++ b/docs/components/classes/InMemoryStorageAdapter.html @@ -0,0 +1,61 @@ +InMemoryStorageAdapter | ART Framework API Docs
                                ART Framework API Docs
                                  Preparing search index...

                                  Class InMemoryStorageAdapter

                                  An in-memory implementation of the StorageAdapter interface. +Stores all data in JavaScript Maps within the current process memory. +Data is not persisted and will be lost when the application session ends.

                                  +

                                  Useful for:

                                  +
                                    +
                                  • Unit and integration testing (fast, no external dependencies).
                                  • +
                                  • Simple demos or examples where persistence isn't needed.
                                  • +
                                  • Ephemeral agents that don't require long-term memory.
                                  • +
                                  +

                                  It provides a simple key-value store for various data types used within the +ART framework, such as conversation history, agent state, and observations.

                                  +

                                  StorageAdapter for the interface definition.

                                  +

                                  Implements

                                  Index

                                  Constructors

                                  Methods

                                  • Removes all items from a specific collection within the in-memory store.

                                    +

                                    Parameters

                                    • collection: string

                                      The name of the collection to clear.

                                      +

                                    Returns Promise<void>

                                    A promise that resolves when the collection is cleared.

                                    +
                                  • Deletes an item from a specified collection using its ID. +If the collection or item does not exist, the operation completes silently.

                                    +

                                    Parameters

                                    • collection: string

                                      The name of the collection.

                                      +
                                    • id: string

                                      The unique ID of the item to delete.

                                      +

                                    Returns Promise<void>

                                    A promise that resolves when the deletion attempt is complete.

                                    +
                                  • Retrieves a single item (as a deep copy) from a specified collection by its ID.

                                    +

                                    Type Parameters

                                    • T

                                      The expected type of the retrieved item.

                                      +

                                    Parameters

                                    • collection: string

                                      The name of the data collection (e.g., 'messages', 'observations').

                                      +
                                    • id: string

                                      The unique ID of the item within the collection.

                                      +

                                    Returns Promise<null | T>

                                    A promise resolving to a deep copy of the item if found, or null otherwise.

                                    +
                                  • Initializes the adapter. This is a no-op for the in-memory adapter +and is provided for interface compatibility.

                                    +

                                    Parameters

                                    • Optional_config: any

                                      Optional configuration (ignored by this adapter).

                                      +

                                    Returns Promise<void>

                                    A promise that resolves immediately.

                                    +
                                  • Queries items within a collection based on provided filter options. +Note: This in-memory implementation provides basic filtering capabilities:

                                    +
                                      +
                                    • Supports exact matches on top-level properties specified in filterOptions.filter.
                                    • +
                                    • Supports limiting results via filterOptions.limit.
                                    • +
                                    • Does not support sorting (filterOptions.sort), skipping (filterOptions.skip), complex operators (like $gt, $in), or nested property filtering.
                                    • +
                                    +

                                    Type Parameters

                                    • T

                                      The expected type of the items in the collection.

                                      +

                                    Parameters

                                    • collection: string

                                      The name of the collection to query.

                                      +
                                    • filterOptions: FilterOptions

                                      Options for filtering and limiting the results.

                                      +

                                    Returns Promise<T[]>

                                    A promise resolving to an array of deep copies of the matching items.

                                    +
                                  • Saves (creates or updates) an item in a specified collection. +Stores a deep copy of the provided data to prevent external mutations.

                                    +

                                    Type Parameters

                                    • T

                                      The type of the data being saved.

                                      +

                                    Parameters

                                    • collection: string

                                      The name of the collection.

                                      +
                                    • id: string

                                      The unique ID for the item.

                                      +
                                    • data: T

                                      The data object to save.

                                      +

                                    Returns Promise<void>

                                    A promise that resolves when the data is saved in memory.

                                    +
                                  diff --git a/docs/components/classes/IndexedDBStorageAdapter.html b/docs/components/classes/IndexedDBStorageAdapter.html new file mode 100644 index 0000000..a194e2e --- /dev/null +++ b/docs/components/classes/IndexedDBStorageAdapter.html @@ -0,0 +1,70 @@ +IndexedDBStorageAdapter | ART Framework API Docs
                                  ART Framework API Docs
                                    Preparing search index...

                                    Class IndexedDBStorageAdapter

                                    An implementation of the StorageAdapter interface that uses the browser's +IndexedDB API for persistent, client-side storage.

                                    +

                                    This adapter is suitable for web applications where conversation history, +agent state, and observations need to persist across sessions.

                                    +

                                    Important: The init() method must be called and awaited before performing +any other database operations (get, set, delete, query).

                                    +
                                      +
                                    • StorageAdapter for the interface it implements.
                                    • +
                                    • IndexedDBConfig for configuration options.
                                    • +
                                    +

                                    Implements

                                    Index

                                    Constructors

                                    Methods

                                    • Removes all data from all object stores managed by this adapter instance within the database. +Use with caution as this is destructive.

                                      +

                                      Returns Promise<void>

                                      A promise that resolves when all specified object stores have been cleared.

                                      +

                                      If the database is not initialized or a transaction error occurs.

                                      +
                                    • Removes all items from a specific object store (collection).

                                      +

                                      Parameters

                                      • collection: string

                                        The name of the object store to clear.

                                        +

                                      Returns Promise<void>

                                      A promise that resolves when the collection is successfully cleared.

                                      +

                                      If the database is not initialized, the store doesn't exist, or a database error occurs.

                                      +
                                    • Deletes an item from the specified object store (collection) by its ID.

                                      +

                                      Parameters

                                      • collection: string

                                        The name of the object store.

                                        +
                                      • id: string

                                        The ID (key) of the item to delete.

                                        +

                                      Returns Promise<void>

                                      A promise that resolves when the deletion is successful.

                                      +

                                      If the database is not initialized, the store doesn't exist, or a database error occurs.

                                      +
                                    • Retrieves a single item by its ID from the specified object store (collection).

                                      +

                                      Type Parameters

                                      • T

                                        The expected type of the retrieved item.

                                        +

                                      Parameters

                                      • collection: string

                                        The name of the object store.

                                        +
                                      • id: string

                                        The ID (key) of the item to retrieve.

                                        +

                                      Returns Promise<null | T>

                                      A promise resolving to a copy of the item if found, or null otherwise.

                                      +

                                      If the database is not initialized, the store doesn't exist, or a database error occurs.

                                      +
                                    • Opens the IndexedDB database connection and ensures the required object stores +are created or updated based on the configured dbVersion. +This method MUST be called and awaited successfully before using other adapter methods. +It handles the onupgradeneeded event to create stores.

                                      +

                                      Returns Promise<void>

                                      A promise that resolves when the database is successfully opened and ready, or rejects on error.

                                      +
                                    • Queries items within a collection based on provided filter options. +Note: This implementation uses getAll() and performs filtering, sorting, +and limiting client-side. For large datasets, performance may be suboptimal. +A more advanced version would leverage IndexedDB indexes and cursors for +efficient querying directly within the database. +Supports basic exact-match filtering and single-key sorting.

                                      +

                                      Type Parameters

                                      • T

                                        The expected type of the items in the collection.

                                        +

                                      Parameters

                                      • collection: string

                                        The name of the object store to query.

                                        +
                                      • filterOptions: FilterOptions

                                        Options for filtering, sorting, skipping, and limiting results.

                                        +

                                      Returns Promise<T[]>

                                      A promise resolving to an array of deep copies of the matching items.

                                      +

                                      If the database is not initialized, the store doesn't exist, or a database error occurs.

                                      +

                                      TODO: Implement more advanced querying using IndexedDB indexes and cursors. +This will improve performance for large datasets.

                                      +
                                    • Saves (creates or updates) an item in the specified object store (collection). +Assumes the object store uses 'id' as its keyPath. The id parameter provided +should match the id property within the data object. +Uses structuredClone to store a deep copy.

                                      +

                                      Type Parameters

                                      • T

                                        The type of the data being saved. Must have an 'id' property.

                                        +

                                      Parameters

                                      • collection: string

                                        The name of the object store.

                                        +
                                      • id: string

                                        The unique ID of the item (should match data.id).

                                        +
                                      • data: T

                                        The data object to save. Must contain an id property matching the id parameter.

                                        +

                                      Returns Promise<void>

                                      A promise that resolves when the data is successfully saved.

                                      +

                                      If the database is not initialized, the store doesn't exist, data is missing the 'id' property, or a database error occurs.

                                      +
                                    diff --git a/docs/components/classes/LLMStreamSocket.html b/docs/components/classes/LLMStreamSocket.html new file mode 100644 index 0000000..51a3ccb --- /dev/null +++ b/docs/components/classes/LLMStreamSocket.html @@ -0,0 +1,24 @@ +LLMStreamSocket | ART Framework API Docs
                                    ART Framework API Docs
                                      Preparing search index...

                                      Class LLMStreamSocket

                                      A dedicated socket for broadcasting LLM stream events (StreamEvent) to UI subscribers. +Extends the generic TypedSocket and implements filtering based on StreamEvent.type.

                                      +

                                      Hierarchy (View Summary)

                                      Index

                                      Constructors

                                      Methods

                                      • Notifies all relevant subscribers with new data.

                                        +

                                        Parameters

                                        • data: StreamEvent

                                          The data payload to send to subscribers.

                                          +
                                        • Optionaloptions: { targetSessionId?: string; targetThreadId?: string }

                                          Optional targeting options (e.g., targetThreadId).

                                          +
                                        • OptionalfilterCheck: (data: StreamEvent, filter?: StreamEventTypeFilter) => boolean

                                          A function to check if a subscription's filter matches the data.

                                          +

                                        Returns void

                                      diff --git a/docs/components/classes/LocalInstanceBusyError.html b/docs/components/classes/LocalInstanceBusyError.html new file mode 100644 index 0000000..fd4a742 --- /dev/null +++ b/docs/components/classes/LocalInstanceBusyError.html @@ -0,0 +1,12 @@ +LocalInstanceBusyError | ART Framework API Docs
                                      ART Framework API Docs
                                        Preparing search index...

                                        Class LocalInstanceBusyError

                                        Error thrown when a requested local LLM instance is currently busy.

                                        +

                                        Hierarchy (View Summary)

                                        Index

                                        Constructors

                                        Properties

                                        Methods

                                        Constructors

                                        Properties

                                        code: ErrorCode

                                        The specific error code from the ErrorCode enum.

                                        +
                                        details: Record<string, any>

                                        A record of additional details about the error.

                                        +
                                        originalError?: Error

                                        The original error that caused this error, if any.

                                        +

                                        Methods

                                        • Returns a string representation of the error, including the original error if present.

                                          +

                                          Returns string

                                          The string representation of the error.

                                          +
                                        diff --git a/docs/components/classes/LocalProviderConflictError.html b/docs/components/classes/LocalProviderConflictError.html new file mode 100644 index 0000000..5033ee6 --- /dev/null +++ b/docs/components/classes/LocalProviderConflictError.html @@ -0,0 +1,12 @@ +LocalProviderConflictError | ART Framework API Docs
                                        ART Framework API Docs
                                          Preparing search index...

                                          Class LocalProviderConflictError

                                          Error thrown when attempting to activate a local provider while another is already active.

                                          +

                                          Hierarchy (View Summary)

                                          Index

                                          Constructors

                                          Properties

                                          Methods

                                          Constructors

                                          Properties

                                          code: ErrorCode

                                          The specific error code from the ErrorCode enum.

                                          +
                                          details: Record<string, any>

                                          A record of additional details about the error.

                                          +
                                          originalError?: Error

                                          The original error that caused this error, if any.

                                          +

                                          Methods

                                          • Returns a string representation of the error, including the original error if present.

                                            +

                                            Returns string

                                            The string representation of the error.

                                            +
                                          diff --git a/docs/components/classes/Logger.html b/docs/components/classes/Logger.html new file mode 100644 index 0000000..90f780c --- /dev/null +++ b/docs/components/classes/Logger.html @@ -0,0 +1,28 @@ +Logger | ART Framework API Docs
                                          ART Framework API Docs
                                            Preparing search index...

                                            Class Logger

                                            A simple static logger class for outputting messages to the console at different levels.

                                            +

                                            Configuration is global via the static configure method.

                                            +

                                            Logger

                                            +
                                            Index

                                            Constructors

                                            Methods

                                            Constructors

                                            Methods

                                            • Configures the static logger settings.

                                              +

                                              Parameters

                                              • config: Partial<LoggerConfig>

                                                A partial LoggerConfig object. Provided settings will override defaults.

                                                +

                                              Returns void

                                            • Logs a message at the DEBUG level.

                                              +

                                              Parameters

                                              • message: string

                                                The main log message string.

                                                +
                                              • ...args: any[]

                                                Additional arguments to include in the console output (e.g., objects, arrays).

                                                +

                                              Returns void

                                              Only outputs if the configured log level is DEBUG.

                                              +
                                            • Logs a message at the ERROR level.

                                              +

                                              Parameters

                                              • message: string

                                                The main log message string.

                                                +
                                              • ...args: any[]

                                                Additional arguments to include in the console output (often an error object).

                                                +

                                              Returns void

                                              Outputs if the configured log level is ERROR, WARN, INFO, or DEBUG.

                                              +
                                            • Logs a message at the INFO level.

                                              +

                                              Parameters

                                              • message: string

                                                The main log message string.

                                                +
                                              • ...args: any[]

                                                Additional arguments to include in the console output.

                                                +

                                              Returns void

                                              Outputs if the configured log level is INFO or DEBUG.

                                              +
                                            • Logs a message at the WARN level.

                                              +

                                              Parameters

                                              • message: string

                                                The main log message string.

                                                +
                                              • ...args: any[]

                                                Additional arguments to include in the console output.

                                                +

                                              Returns void

                                              Outputs if the configured log level is WARN, INFO, or DEBUG.

                                              +
                                            diff --git a/docs/components/classes/McpClientController.html b/docs/components/classes/McpClientController.html new file mode 100644 index 0000000..15e2b31 --- /dev/null +++ b/docs/components/classes/McpClientController.html @@ -0,0 +1,33 @@ +McpClientController | ART Framework API Docs
                                            ART Framework API Docs
                                              Preparing search index...

                                              Class McpClientController

                                              McpClientController +Controls the MCP client, including OAuth flow, connection, and tool calls.

                                              +
                                              Index

                                              Properties

                                              baseUrl: URL

                                              Methods

                                              • Calls a tool on the MCP server.

                                                +

                                                Parameters

                                                • name: string

                                                  The name of the tool to call.

                                                  +
                                                • args: any

                                                  The arguments to pass to the tool.

                                                  +

                                                Returns Promise<any>

                                                A promise that resolves to the result of the tool call.

                                                +
                                              • Checks if the user is authenticated.

                                                +

                                                Returns boolean

                                                True if the user is authenticated, false otherwise.

                                                +
                                              • Lists the available tools on the MCP server.

                                                +

                                                Returns Promise<{ description?: string; name: string }[]>

                                                A promise that resolves to a list of tools.

                                                +
                                              • Handles the OAuth callback, exchanging the authorization code for an access token.

                                                +

                                                Returns Promise<boolean>

                                                A promise that resolves to true if the callback was handled, false otherwise.

                                                +
                                              • Starts the OAuth flow by redirecting the user to the authorization server.

                                                +

                                                Returns Promise<void>

                                              diff --git a/docs/components/classes/McpManager.html b/docs/components/classes/McpManager.html new file mode 100644 index 0000000..101ea92 --- /dev/null +++ b/docs/components/classes/McpManager.html @@ -0,0 +1,49 @@ +McpManager | ART Framework API Docs
                                              ART Framework API Docs
                                                Preparing search index...

                                                Class McpManager

                                                Manages MCP (Model Context Protocol) server connections and tool registration.

                                                +

                                                The McpManager is responsible for:

                                                +
                                                  +
                                                • Connecting to configured MCP servers.
                                                • +
                                                • Discovering available tools from servers.
                                                • +
                                                • Creating proxy tools that wrap MCP server tools.
                                                • +
                                                • Registering proxy tools with the ToolRegistry.
                                                • +
                                                • Managing server health and status.
                                                • +
                                                • Handling thread-specific tool activation/deactivation.
                                                • +
                                                +

                                                This enables dynamic tool loading from external MCP servers while maintaining +seamless integration with the ART Framework's tool system.

                                                +
                                                +

                                                McpManager

                                                +
                                                Index

                                                Constructors

                                                • Creates an instance of McpManager.

                                                  +

                                                  Parameters

                                                  • toolRegistry: ToolRegistry

                                                    The tool registry to register proxy tools with.

                                                    +
                                                  • _stateManager: StateManager

                                                    The state manager (not currently used).

                                                    +
                                                  • OptionalauthManager: AuthManager

                                                    The authentication manager.

                                                    +

                                                  Returns McpManager

                                                Methods

                                                • Searches a discovery service for available MCP servers.

                                                  +

                                                  Parameters

                                                  • OptionaldiscoveryEndpoint: string

                                                    The URL of the discovery service.

                                                    +

                                                  Returns Promise<McpServerConfig[]>

                                                  A promise resolving to an array of McpServerConfig.

                                                  +
                                                • Initializes the McpManager, discovers and registers tools from configured servers.

                                                  +

                                                  Parameters

                                                  • OptionalmcpConfig: { discoveryEndpoint?: string; enabled?: boolean }

                                                    The MCP configuration.

                                                    +
                                                    • OptionaldiscoveryEndpoint?: string

                                                      The endpoint for discovering MCP servers.

                                                      +
                                                    • Optionalenabled?: boolean

                                                      Whether MCP is enabled.

                                                      +

                                                  Returns Promise<void>

                                                  A promise that resolves when initialization is complete.

                                                  +
                                                • Shuts down all active MCP connections.

                                                  +

                                                  Returns Promise<void>

                                                  A promise that resolves when all connections are shut down.

                                                  +
                                                • Uninstalls a server: disconnects, removes registered proxy tools, and deletes config.

                                                  +

                                                  Parameters

                                                  • serverId: string

                                                    The ID of the server to uninstall.

                                                    +

                                                  Returns Promise<void>

                                                  A promise that resolves when the server is uninstalled.

                                                  +
                                                diff --git a/docs/components/classes/McpProxyTool.html b/docs/components/classes/McpProxyTool.html new file mode 100644 index 0000000..2ccdf3f --- /dev/null +++ b/docs/components/classes/McpProxyTool.html @@ -0,0 +1,29 @@ +McpProxyTool | ART Framework API Docs
                                                ART Framework API Docs
                                                  Preparing search index...

                                                  Class McpProxyTool

                                                  A proxy tool that wraps an MCP server tool and implements the IToolExecutor interface.

                                                  +

                                                  This allows MCP server tools to be used seamlessly within the ART Framework.

                                                  +
                                                  +

                                                  McpProxyTool

                                                  +

                                                  Implements

                                                  Index

                                                  Constructors

                                                  Properties

                                                  schema: ToolSchema

                                                  The schema definition for this tool.

                                                  +

                                                  Methods

                                                  diff --git a/docs/components/classes/ObservationSocket.html b/docs/components/classes/ObservationSocket.html new file mode 100644 index 0000000..a286642 --- /dev/null +++ b/docs/components/classes/ObservationSocket.html @@ -0,0 +1,27 @@ +ObservationSocket | ART Framework API Docs
                                                  ART Framework API Docs
                                                    Preparing search index...

                                                    Class ObservationSocket

                                                    A specialized TypedSocket for handling Observation data. +Allows filtering by ObservationType. +Can optionally fetch historical observations from a repository.

                                                    +

                                                    Hierarchy (View Summary)

                                                    Index

                                                    Constructors

                                                    Methods

                                                    diff --git a/docs/components/classes/OllamaAdapter.html b/docs/components/classes/OllamaAdapter.html new file mode 100644 index 0000000..2fb47c2 --- /dev/null +++ b/docs/components/classes/OllamaAdapter.html @@ -0,0 +1,23 @@ +OllamaAdapter | ART Framework API Docs
                                                    ART Framework API Docs
                                                      Preparing search index...

                                                      Class OllamaAdapter

                                                      Implements the ProviderAdapter interface for interacting with Ollama's +OpenAI-compatible API endpoint.

                                                      +

                                                      Handles formatting requests, parsing responses, streaming, and tool use.

                                                      +
                                                      +

                                                      Implements

                                                      Index

                                                      Constructors

                                                      Properties

                                                      Methods

                                                      Constructors

                                                      Properties

                                                      providerName: "ollama" = 'ollama'

                                                      The unique identifier name for this provider (e.g., 'openai', 'anthropic').

                                                      +

                                                      Methods

                                                      • Optional method for graceful shutdown. For Ollama, which is typically a separate +local server, this adapter doesn't manage persistent connections that need explicit closing.

                                                        +

                                                        Returns Promise<void>

                                                        A promise that resolves when the shutdown is complete.

                                                        +
                                                      diff --git a/docs/components/classes/OpenAIAdapter.html b/docs/components/classes/OpenAIAdapter.html new file mode 100644 index 0000000..5745b44 --- /dev/null +++ b/docs/components/classes/OpenAIAdapter.html @@ -0,0 +1,20 @@ +OpenAIAdapter | ART Framework API Docs
                                                      ART Framework API Docs
                                                        Preparing search index...

                                                        Class OpenAIAdapter

                                                        Implements the ProviderAdapter interface for interacting with OpenAI's +Chat Completions API (compatible models like GPT-3.5, GPT-4, GPT-4o).

                                                        +

                                                        Handles formatting requests and parsing responses for OpenAI. +Uses raw fetch for now.

                                                        +

                                                        ProviderAdapter for the interface definition.

                                                        +

                                                        Implements

                                                        Index

                                                        Constructors

                                                        Properties

                                                        Methods

                                                        Constructors

                                                        Properties

                                                        providerName: "openai" = 'openai'

                                                        The unique identifier name for this provider (e.g., 'openai', 'anthropic').

                                                        +

                                                        Methods

                                                        diff --git a/docs/components/classes/OpenRouterAdapter.html b/docs/components/classes/OpenRouterAdapter.html new file mode 100644 index 0000000..5687d09 --- /dev/null +++ b/docs/components/classes/OpenRouterAdapter.html @@ -0,0 +1,22 @@ +OpenRouterAdapter | ART Framework API Docs
                                                        ART Framework API Docs
                                                          Preparing search index...

                                                          Class OpenRouterAdapter

                                                          This adapter provides a unified interface for various LLM providers through OpenRouter, +handling prompt conversion and response parsing into the ART StreamEvent format.

                                                          +
                                                          +

                                                          Implements

                                                          Index

                                                          Constructors

                                                          Properties

                                                          Methods

                                                          Constructors

                                                          Properties

                                                          providerName: "openrouter" = 'openrouter'

                                                          The unique identifier name for this provider (e.g., 'openai', 'anthropic').

                                                          +

                                                          Methods

                                                          diff --git a/docs/components/classes/PESAgent.html b/docs/components/classes/PESAgent.html new file mode 100644 index 0000000..6581f48 --- /dev/null +++ b/docs/components/classes/PESAgent.html @@ -0,0 +1,35 @@ +PESAgent | ART Framework API Docs
                                                          ART Framework API Docs
                                                            Preparing search index...

                                                            Class PESAgent

                                                            Implements the Plan-Execute-Synthesize (PES) agent orchestration logic. +This agent follows a structured approach:

                                                            +
                                                              +
                                                            1. Plan: Understand the user query, determine intent, and create a plan (potentially involving tool calls).
                                                            2. +
                                                            3. Execute: Run any necessary tools identified in the planning phase.
                                                            4. +
                                                            5. Synthesize: Generate a final response based on the query, plan, and tool results.
                                                            6. +
                                                            +

                                                            It constructs standardized prompts (ArtStandardPrompt) directly as JavaScript objects +for the ReasoningEngine. It processes the StreamEvent output from the reasoning engine for both planning and synthesis.

                                                            +

                                                            //

                                                            +
                                                              +
                                                            • // Removed
                                                            • +
                                                            • +
                                                            • +
                                                            • +
                                                            +

                                                            Implements

                                                            Index

                                                            Constructors

                                                            Methods

                                                            Constructors

                                                            • Creates an instance of the PESAgent.

                                                              +

                                                              Parameters

                                                              • dependencies: PESAgentDependencies

                                                                An object containing instances of all required subsystems (managers, registries, etc.).

                                                                +

                                                              Returns PESAgent

                                                            Methods

                                                            • Executes the full Plan-Execute-Synthesize cycle for a given user query.

                                                              +

                                                              Workflow:

                                                              +
                                                                +
                                                              1. Initiation & Config: Loads thread configuration and resolves system prompt
                                                              2. +
                                                              3. Data Gathering: Gathers history, available tools
                                                              4. +
                                                              5. Planning: LLM call for planning and parsing
                                                              6. +
                                                              7. A2A Discovery & Delegation: Identifies and delegates A2A tasks to remote agents
                                                              8. +
                                                              9. Tool Execution: Executes identified local tool calls
                                                              10. +
                                                              11. Synthesis: LLM call for final response generation including A2A results
                                                              12. +
                                                              13. Finalization: Saves messages and cleanup
                                                              14. +
                                                              +

                                                              Parameters

                                                              • props: AgentProps

                                                                The input properties containing the user query, threadId, userId, traceId, etc.

                                                                +

                                                              Returns Promise<AgentFinalResponse>

                                                              A promise resolving to the final response, including the AI message and execution metadata.

                                                              +

                                                              If a critical error occurs that prevents the agent from completing the process.

                                                              +
                                                            diff --git a/docs/components/classes/PKCEOAuthStrategy.html b/docs/components/classes/PKCEOAuthStrategy.html new file mode 100644 index 0000000..478205b --- /dev/null +++ b/docs/components/classes/PKCEOAuthStrategy.html @@ -0,0 +1,22 @@ +PKCEOAuthStrategy | ART Framework API Docs
                                                            ART Framework API Docs
                                                              Preparing search index...

                                                              Class PKCEOAuthStrategy

                                                              Implements the OAuth 2.0 Authorization Code Flow with PKCE (Proof Key for Code Exchange). +This is the recommended, most secure method for authenticating users in browser-based applications.

                                                              +

                                                              Implements

                                                              Index

                                                              Constructors

                                                              Methods

                                                              • Gets the authentication headers, automatically handling token refresh if needed.

                                                                +

                                                                Returns Promise<Record<string, string>>

                                                                A promise that resolves to the authentication headers.

                                                                +
                                                              • Handles the redirect from the authorization server. +This method should be called on the redirect URI page. +It exchanges the authorization code for an access token.

                                                                +

                                                                Returns Promise<void>

                                                                A promise that resolves when the redirect has been handled.

                                                                +
                                                              • Initiates the PKCE login flow by redirecting the user to the authorization endpoint.

                                                                +

                                                                Returns Promise<void>

                                                                A promise that resolves when the login process is complete.

                                                                +
                                                              diff --git a/docs/components/classes/ProviderManagerImpl.html b/docs/components/classes/ProviderManagerImpl.html new file mode 100644 index 0000000..d198b0d --- /dev/null +++ b/docs/components/classes/ProviderManagerImpl.html @@ -0,0 +1,9 @@ +ProviderManagerImpl | ART Framework API Docs
                                                              ART Framework API Docs
                                                                Preparing search index...

                                                                Class ProviderManagerImpl

                                                                Manages the lifecycle and access to multiple ProviderAdapter implementations.

                                                                +

                                                                Implements

                                                                Index

                                                                Constructors

                                                                Methods

                                                                diff --git a/docs/components/classes/StateManager.html b/docs/components/classes/StateManager.html new file mode 100644 index 0000000..03f680b --- /dev/null +++ b/docs/components/classes/StateManager.html @@ -0,0 +1,79 @@ +StateManager | ART Framework API Docs
                                                                ART Framework API Docs
                                                                  Preparing search index...

                                                                  Class StateManager

                                                                  Manages thread-specific configuration (ThreadConfig) and state (AgentState) +using an underlying StateRepository. Supports explicit and implicit state saving strategies.

                                                                  +

                                                                  Implements

                                                                  • StateManager
                                                                  Index

                                                                  Constructors

                                                                  Methods

                                                                  • Clears the internal context cache. Useful if the underlying storage is manipulated externally +during an agent's processing cycle, though this is generally not recommended. +Or for testing purposes.

                                                                    +

                                                                    Returns void

                                                                  • Disables specific tools for a conversation thread by removing them from the thread's enabled tools list. +This method loads the current thread configuration, updates the enabledTools array, +and persists the changes. Cache is invalidated to ensure fresh data on next load.

                                                                    +

                                                                    Parameters

                                                                    • threadId: string

                                                                      The unique identifier of the thread.

                                                                      +
                                                                    • toolNames: string[]

                                                                      Array of tool names to disable for this thread.

                                                                      +

                                                                    Returns Promise<void>

                                                                    A promise that resolves when the tools are disabled.

                                                                    +

                                                                    If threadId is empty, toolNames is empty, or if the repository fails.

                                                                    +
                                                                  • Enables specific tools for a conversation thread by adding them to the thread's enabled tools list. +This method loads the current thread configuration, updates the enabledTools array, +and persists the changes. Cache is invalidated to ensure fresh data on next load.

                                                                    +

                                                                    Parameters

                                                                    • threadId: string

                                                                      The unique identifier of the thread.

                                                                      +
                                                                    • toolNames: string[]

                                                                      Array of tool names to enable for this thread.

                                                                      +

                                                                    Returns Promise<void>

                                                                    A promise that resolves when the tools are enabled.

                                                                    +

                                                                    If threadId is empty, toolNames is empty, or if the repository fails.

                                                                    +
                                                                  • Gets the list of currently enabled tools for a specific thread. +This is a convenience method that loads the thread context and returns the enabledTools array.

                                                                    +

                                                                    Parameters

                                                                    • threadId: string

                                                                      The unique identifier of the thread.

                                                                      +

                                                                    Returns Promise<string[]>

                                                                    A promise that resolves to an array of enabled tool names, or empty array if no tools are enabled.

                                                                    +

                                                                    If the thread context cannot be loaded.

                                                                    +
                                                                  • Retrieves a specific value from the thread's configuration (ThreadConfig). +Loads the context first (which might come from cache in implicit mode).

                                                                    +

                                                                    Type Parameters

                                                                    • T

                                                                      The expected type of the configuration value.

                                                                      +

                                                                    Parameters

                                                                    • threadId: string

                                                                      The ID of the thread.

                                                                      +
                                                                    • key: string

                                                                      The top-level configuration key.

                                                                      +

                                                                    Returns Promise<undefined | T>

                                                                    A promise resolving to the configuration value, or undefined.

                                                                    +
                                                                  • Checks if a specific tool is permitted for use within a given thread. +It loads the thread's context and checks the enabledTools array in the configuration.

                                                                    +

                                                                    Parameters

                                                                    • threadId: string

                                                                      The ID of the thread.

                                                                      +
                                                                    • toolName: string

                                                                      The name of the tool to check.

                                                                      +

                                                                    Returns Promise<boolean>

                                                                    A promise resolving to true if the tool is listed in the thread's enabledTools config, false otherwise or if the context/config cannot be loaded.

                                                                    +
                                                                  • Loads the complete context (ThreadConfig and AgentState) for a specific thread. +If in 'implicit' state saving strategy, it caches the loaded context and a snapshot +of its AgentState for later comparison in saveStateIfModified.

                                                                    +

                                                                    Parameters

                                                                    • threadId: string

                                                                      The unique identifier for the thread.

                                                                      +
                                                                    • Optional_userId: string

                                                                      Optional user identifier (currently unused).

                                                                      +

                                                                    Returns Promise<ThreadContext>

                                                                    A promise resolving to the ThreadContext object.

                                                                    +

                                                                    If threadId is empty or if the repository fails to find the context.

                                                                    +
                                                                  • Persists the thread's AgentState if it has been modified. +Behavior depends on the stateSavingStrategy:

                                                                    +
                                                                      +
                                                                    • 'explicit': This method is a no-op for AgentState persistence and logs a warning.
                                                                    • +
                                                                    • 'implicit': Compares the current AgentState (from the cached ThreadContext modified by the agent) +with the snapshot taken during loadThreadContext. If different, saves the state +to the repository and updates the snapshot.
                                                                    • +
                                                                    +

                                                                    Parameters

                                                                    • threadId: string

                                                                      The ID of the thread whose state might need saving.

                                                                      +

                                                                    Returns Promise<void>

                                                                    A promise that resolves when the state is saved or the operation is skipped.

                                                                    +
                                                                  • Explicitly sets or updates the AgentState for a specific thread by calling the underlying state repository. +If in 'implicit' mode, this also updates the cached snapshot to prevent saveStateIfModified +from re-saving the same state immediately.

                                                                    +

                                                                    Parameters

                                                                    • threadId: string

                                                                      The unique identifier of the thread.

                                                                      +
                                                                    • state: AgentState

                                                                      The AgentState object to save. Must not be undefined or null.

                                                                      +

                                                                    Returns Promise<void>

                                                                    A promise that resolves when the state is saved.

                                                                    +

                                                                    If threadId or state is undefined/null, or if the repository fails.

                                                                    +
                                                                  • Sets or completely replaces the configuration (ThreadConfig) for a specific thread +by calling the underlying state repository. This also clears any cached context for the thread.

                                                                    +

                                                                    Parameters

                                                                    • threadId: string

                                                                      The ID of the thread.

                                                                      +
                                                                    • config: ThreadConfig

                                                                      The complete ThreadConfig object.

                                                                      +

                                                                    Returns Promise<void>

                                                                    A promise that resolves when the configuration is saved.

                                                                    +
                                                                  diff --git a/docs/components/classes/SupabaseStorageAdapter.html b/docs/components/classes/SupabaseStorageAdapter.html new file mode 100644 index 0000000..916d769 --- /dev/null +++ b/docs/components/classes/SupabaseStorageAdapter.html @@ -0,0 +1,44 @@ +SupabaseStorageAdapter | ART Framework API Docs
                                                                  ART Framework API Docs
                                                                    Preparing search index...

                                                                    Class SupabaseStorageAdapter

                                                                    A Supabase-backed StorageAdapter implementation.

                                                                    +

                                                                    Expectations/assumptions:

                                                                    +
                                                                      +
                                                                    • Each collection maps to a table with a primary key column named 'id' (text/uuid).
                                                                    • +
                                                                    • We store JSON columns for flexible data where needed. However, repositories +store fully shaped rows; this adapter just persists and retrieves whole objects.
                                                                    • +
                                                                    • For query(), we implement basic equality filters per FilterOptions.filter keys, +plus limit/skip and a single-key sort.
                                                                    • +
                                                                    +

                                                                    Implements

                                                                    Index

                                                                    Constructors

                                                                    Methods

                                                                    • Deletes an item from a collection by its ID.

                                                                      +

                                                                      Parameters

                                                                      • collection: string

                                                                        The name of the collection.

                                                                        +
                                                                      • id: string

                                                                        The ID of the item to delete.

                                                                        +

                                                                      Returns Promise<void>

                                                                      A promise that resolves when the item is deleted.

                                                                      +
                                                                    • Retrieves a single item from a collection by its ID.

                                                                      +

                                                                      Type Parameters

                                                                      • T

                                                                      Parameters

                                                                      • collection: string

                                                                        The name of the collection.

                                                                        +
                                                                      • id: string

                                                                        The ID of the item to retrieve.

                                                                        +

                                                                      Returns Promise<null | T>

                                                                      A promise that resolves with the item, or null if not found.

                                                                      +
                                                                    • Saves (upserts) an item in a collection.

                                                                      +

                                                                      Type Parameters

                                                                      • T

                                                                      Parameters

                                                                      • collection: string

                                                                        The name of the collection.

                                                                        +
                                                                      • id: string

                                                                        The ID of the item to save.

                                                                        +
                                                                      • data: T

                                                                        The data to save.

                                                                        +

                                                                      Returns Promise<void>

                                                                      A promise that resolves when the item is saved.

                                                                      +
                                                                    diff --git a/docs/components/classes/TaskDelegationService.html b/docs/components/classes/TaskDelegationService.html new file mode 100644 index 0000000..a4eef86 --- /dev/null +++ b/docs/components/classes/TaskDelegationService.html @@ -0,0 +1,43 @@ +TaskDelegationService | ART Framework API Docs
                                                                    ART Framework API Docs
                                                                      Preparing search index...

                                                                      Class TaskDelegationService

                                                                      Service responsible for delegating A2A tasks to remote agents. +Implements the A2A protocol for task submission, tracking, and completion.

                                                                      +

                                                                      This service handles:

                                                                      +
                                                                        +
                                                                      • Finding suitable agents for specific task types
                                                                      • +
                                                                      • Submitting tasks to remote agents via HTTP API
                                                                      • +
                                                                      • Tracking task status and handling updates
                                                                      • +
                                                                      • Managing task lifecycle according to A2A protocol
                                                                      • +
                                                                      • Error handling and retry logic
                                                                      • +
                                                                      • Integration with local task repository for persistence
                                                                      • +
                                                                      +
                                                                      Index

                                                                      Constructors

                                                                      Methods

                                                                      • Cancels a delegated task on the remote agent.

                                                                        +

                                                                        Parameters

                                                                        • task: A2ATask

                                                                          The A2A task to cancel

                                                                          +
                                                                        • OptionaltraceId: string

                                                                          Optional trace ID for request tracking

                                                                          +

                                                                        Returns Promise<boolean>

                                                                        Promise resolving to whether cancellation was successful

                                                                        +
                                                                      • Delegates a single A2A task to a suitable remote agent.

                                                                        +

                                                                        Parameters

                                                                        • task: A2ATask

                                                                          The A2A task to delegate

                                                                          +
                                                                        • OptionaltraceId: string

                                                                          Optional trace ID for request tracking

                                                                          +

                                                                        Returns Promise<null | A2ATask>

                                                                        Promise resolving to the updated task or null if delegation failed

                                                                        +
                                                                      • Delegates a list of A2A tasks to suitable remote agents. +For each task, finds the best agent and submits the task.

                                                                        +

                                                                        Parameters

                                                                        • tasks: A2ATask[]

                                                                          Array of A2A tasks to delegate

                                                                          +
                                                                        • OptionaltraceId: string

                                                                          Optional trace ID for request tracking

                                                                          +

                                                                        Returns Promise<A2ATask[]>

                                                                        Promise resolving to array of successfully delegated tasks

                                                                        +
                                                                      diff --git a/docs/components/classes/ToolRegistry.html b/docs/components/classes/ToolRegistry.html new file mode 100644 index 0000000..f486cdb --- /dev/null +++ b/docs/components/classes/ToolRegistry.html @@ -0,0 +1,31 @@ +ToolRegistry | ART Framework API Docs
                                                                      ART Framework API Docs
                                                                        Preparing search index...

                                                                        Class ToolRegistry

                                                                        A simple in-memory implementation of the ToolRegistry interface. +Stores tool executors in a Map, keyed by the tool's unique name.

                                                                        +

                                                                        Implements

                                                                        • ToolRegistry
                                                                        Index

                                                                        Constructors

                                                                        Methods

                                                                        • Removes all registered tool executors from the registry. +Primarily useful for resetting state during testing or specific application scenarios.

                                                                          +

                                                                          Returns Promise<void>

                                                                          A promise that resolves when all tools have been cleared.

                                                                          +
                                                                        • Retrieves the schemas of all currently registered tools. +Retrieves the schemas of available tools, optionally filtering by those enabled for a specific thread. +If filter.enabledForThreadId is provided and a StateManager was injected, it attempts to load the thread's configuration +and return only the schemas for tools listed in enabledTools. Otherwise, it returns all registered tool schemas.

                                                                          +

                                                                          Parameters

                                                                          • Optionalfilter: { enabledForThreadId?: string }

                                                                            Optional filter criteria. enabledForThreadId triggers filtering based on thread config.

                                                                            +

                                                                          Returns Promise<ToolSchema[]>

                                                                          A promise resolving to an array containing the ToolSchema of the available tools based on the filter.

                                                                          +
                                                                        • Retrieves a registered tool executor instance by its unique name.

                                                                          +

                                                                          Parameters

                                                                          • toolName: string

                                                                            The name property defined in the tool's schema.

                                                                            +

                                                                          Returns Promise<undefined | IToolExecutor>

                                                                          A promise resolving to the IToolExecutor instance, or undefined if no tool with that name is registered.

                                                                          +
                                                                        • Registers a tool executor instance, making it available for lookup via getToolExecutor. +If a tool with the same name (from executor.schema.name) already exists, it will be overwritten, and a warning will be logged.

                                                                          +

                                                                          Parameters

                                                                          • executor: IToolExecutor

                                                                            The instance of the class implementing IToolExecutor. Must have a valid schema with a name.

                                                                            +

                                                                          Returns Promise<void>

                                                                          A promise that resolves when the tool is registered.

                                                                          +

                                                                          If the provided executor or its schema is invalid.

                                                                          +
                                                                        • Unregister a single tool by name.

                                                                          +

                                                                          Parameters

                                                                          • toolName: string

                                                                          Returns Promise<void>

                                                                        • Unregister tools matching a predicate; returns count removed.

                                                                          +

                                                                          Parameters

                                                                          Returns Promise<number>

                                                                        diff --git a/docs/components/classes/TypedSocket.html b/docs/components/classes/TypedSocket.html new file mode 100644 index 0000000..f83967c --- /dev/null +++ b/docs/components/classes/TypedSocket.html @@ -0,0 +1,20 @@ +TypedSocket | ART Framework API Docs
                                                                        ART Framework API Docs
                                                                          Preparing search index...

                                                                          Class TypedSocket<DataType, FilterType>

                                                                          A generic class for implementing a publish/subscribe pattern with filtering capabilities. +Designed for decoupling components, particularly UI updates from backend events.

                                                                          +

                                                                          Type Parameters

                                                                          • DataType
                                                                          • FilterType = any

                                                                          Hierarchy (View Summary)

                                                                          Index

                                                                          Constructors

                                                                          Methods

                                                                          • Optional: Retrieves historical data. This base implementation is empty. +Subclasses might implement this by interacting with repositories.

                                                                            +

                                                                            Parameters

                                                                            • Optional_filter: FilterType
                                                                            • Optional_options: { limit?: number; threadId?: string }

                                                                            Returns Promise<DataType[]>

                                                                          • Notifies all relevant subscribers with new data.

                                                                            +

                                                                            Parameters

                                                                            • data: DataType

                                                                              The data payload to send to subscribers.

                                                                              +
                                                                            • Optionaloptions: { targetSessionId?: string; targetThreadId?: string }

                                                                              Optional targeting options (e.g., targetThreadId).

                                                                              +
                                                                            • OptionalfilterCheck: (data: DataType, filter?: FilterType) => boolean

                                                                              A function to check if a subscription's filter matches the data.

                                                                              +

                                                                            Returns void

                                                                          • Subscribes a callback function to receive notifications.

                                                                            +

                                                                            Parameters

                                                                            • callback: (data: DataType) => void

                                                                              The function to call when new data is notified.

                                                                              +
                                                                            • Optionalfilter: FilterType

                                                                              An optional filter to only receive specific types of data.

                                                                              +
                                                                            • Optionaloptions: { threadId?: string }

                                                                              Optional configuration, like a threadId for filtering.

                                                                              +

                                                                            Returns UnsubscribeFunction

                                                                            An unsubscribe function.

                                                                            +
                                                                          diff --git a/docs/components/classes/UISystem.html b/docs/components/classes/UISystem.html new file mode 100644 index 0000000..cd8a294 --- /dev/null +++ b/docs/components/classes/UISystem.html @@ -0,0 +1,20 @@ +UISystem | ART Framework API Docs
                                                                          ART Framework API Docs
                                                                            Preparing search index...

                                                                            Class UISystem

                                                                            Provides access to the UI communication sockets (Observation, Conversation, LLM Stream, and A2A Task). +Instantiates the sockets with their required dependencies.

                                                                            +

                                                                            Implements

                                                                            • UISystem
                                                                            Index

                                                                            Constructors

                                                                            Methods

                                                                            diff --git a/docs/components/classes/UnknownProviderError.html b/docs/components/classes/UnknownProviderError.html new file mode 100644 index 0000000..67a8a5e --- /dev/null +++ b/docs/components/classes/UnknownProviderError.html @@ -0,0 +1,12 @@ +UnknownProviderError | ART Framework API Docs
                                                                            ART Framework API Docs
                                                                              Preparing search index...

                                                                              Class UnknownProviderError

                                                                              Error thrown when a requested LLM provider is not known or configured.

                                                                              +

                                                                              Hierarchy (View Summary)

                                                                              Index

                                                                              Constructors

                                                                              Properties

                                                                              Methods

                                                                              Constructors

                                                                              Properties

                                                                              code: ErrorCode

                                                                              The specific error code from the ErrorCode enum.

                                                                              +
                                                                              details: Record<string, any>

                                                                              A record of additional details about the error.

                                                                              +
                                                                              originalError?: Error

                                                                              The original error that caused this error, if any.

                                                                              +

                                                                              Methods

                                                                              • Returns a string representation of the error, including the original error if present.

                                                                                +

                                                                                Returns string

                                                                                The string representation of the error.

                                                                                +
                                                                              diff --git a/docs/components/classes/ZyntopiaOAuthStrategy.html b/docs/components/classes/ZyntopiaOAuthStrategy.html new file mode 100644 index 0000000..74128aa --- /dev/null +++ b/docs/components/classes/ZyntopiaOAuthStrategy.html @@ -0,0 +1,63 @@ +ZyntopiaOAuthStrategy | ART Framework API Docs
                                                                              ART Framework API Docs
                                                                                Preparing search index...

                                                                                Class ZyntopiaOAuthStrategy

                                                                                Zyntopia-specific OAuth 2.0 authentication strategy. +Pre-configured for Zyntopia services with standard endpoints, scopes, and authentication flows. +Extends GenericOAuthStrategy with Zyntopia-specific defaults and configurations.

                                                                                +

                                                                                Hierarchy (View Summary)

                                                                                Index

                                                                                Constructors

                                                                                Methods

                                                                                • Gets the current environment this strategy is configured for.

                                                                                  +

                                                                                  Returns "production" | "staging" | "development"

                                                                                  The environment ('production', 'staging', or 'development').

                                                                                  +
                                                                                • Gets information about the current cached token.

                                                                                  +

                                                                                  Returns null | { expiresAt: Date; hasRefreshToken: boolean; scope?: string }

                                                                                  Token information or null if no token is cached.

                                                                                  +
                                                                                • Checks if this strategy is configured for development/testing.

                                                                                  +

                                                                                  Returns boolean

                                                                                  True if configured for development or staging, false for production.

                                                                                  +
                                                                                • Checks if this strategy is configured for production environment.

                                                                                  +

                                                                                  Returns boolean

                                                                                  True if configured for production, false otherwise.

                                                                                  +
                                                                                • Creates a ZyntopiaOAuthStrategy instance pre-configured for development.

                                                                                  +

                                                                                  Parameters

                                                                                  • clientId: string

                                                                                    Zyntopia client ID

                                                                                    +
                                                                                  • clientSecret: string

                                                                                    Zyntopia client secret

                                                                                    +
                                                                                  • OptionalcustomScopes: string

                                                                                    Optional custom scopes (defaults to development scopes)

                                                                                    +

                                                                                  Returns ZyntopiaOAuthStrategy

                                                                                  Configured ZyntopiaOAuthStrategy for development.

                                                                                  +
                                                                                • Creates a ZyntopiaOAuthStrategy instance pre-configured for production.

                                                                                  +

                                                                                  Parameters

                                                                                  • clientId: string

                                                                                    Zyntopia client ID

                                                                                    +
                                                                                  • clientSecret: string

                                                                                    Zyntopia client secret

                                                                                    +
                                                                                  • OptionalcustomScopes: string

                                                                                    Optional custom scopes (defaults to production scopes)

                                                                                    +

                                                                                  Returns ZyntopiaOAuthStrategy

                                                                                  Configured ZyntopiaOAuthStrategy for production.

                                                                                  +
                                                                                • Creates a ZyntopiaOAuthStrategy instance pre-configured for staging.

                                                                                  +

                                                                                  Parameters

                                                                                  • clientId: string

                                                                                    Zyntopia client ID

                                                                                    +
                                                                                  • clientSecret: string

                                                                                    Zyntopia client secret

                                                                                    +
                                                                                  • OptionalcustomScopes: string

                                                                                    Optional custom scopes (defaults to staging scopes)

                                                                                    +

                                                                                  Returns ZyntopiaOAuthStrategy

                                                                                  Configured ZyntopiaOAuthStrategy for staging.

                                                                                  +
                                                                                • Gets the default scopes for a specific environment.

                                                                                  +

                                                                                  Parameters

                                                                                  • environment: "production" | "staging" | "development"

                                                                                    The environment to get scopes for

                                                                                    +

                                                                                  Returns string

                                                                                  Default scopes for the specified environment.

                                                                                  +
                                                                                • Gets the token endpoint for a specific environment.

                                                                                  +

                                                                                  Parameters

                                                                                  • environment: "production" | "staging" | "development"

                                                                                    The environment to get endpoint for

                                                                                    +

                                                                                  Returns string

                                                                                  Token endpoint URL for the specified environment.

                                                                                  +
                                                                                diff --git a/docs/components/enums/A2ATaskPriority.html b/docs/components/enums/A2ATaskPriority.html new file mode 100644 index 0000000..2a534e7 --- /dev/null +++ b/docs/components/enums/A2ATaskPriority.html @@ -0,0 +1,10 @@ +A2ATaskPriority | ART Framework API Docs
                                                                                ART Framework API Docs
                                                                                  Preparing search index...

                                                                                  Enumeration A2ATaskPriority

                                                                                  Represents the priority level of an A2A task.

                                                                                  +
                                                                                  Index

                                                                                  Enumeration Members

                                                                                  Enumeration Members

                                                                                  HIGH: "HIGH"

                                                                                  High priority.

                                                                                  +
                                                                                  LOW: "LOW"

                                                                                  Low priority.

                                                                                  +
                                                                                  MEDIUM: "MEDIUM"

                                                                                  Medium priority.

                                                                                  +
                                                                                  URGENT: "URGENT"

                                                                                  Urgent priority.

                                                                                  +
                                                                                  diff --git a/docs/components/enums/A2ATaskStatus.html b/docs/components/enums/A2ATaskStatus.html new file mode 100644 index 0000000..eba70a5 --- /dev/null +++ b/docs/components/enums/A2ATaskStatus.html @@ -0,0 +1,16 @@ +A2ATaskStatus | ART Framework API Docs
                                                                                  ART Framework API Docs
                                                                                    Preparing search index...

                                                                                    Enumeration A2ATaskStatus

                                                                                    Represents the possible states of an A2A (Agent-to-Agent) task.

                                                                                    +
                                                                                    Index

                                                                                    Enumeration Members

                                                                                    CANCELLED: "CANCELLED"

                                                                                    Task has been cancelled before completion.

                                                                                    +
                                                                                    COMPLETED: "COMPLETED"

                                                                                    Task has been completed successfully.

                                                                                    +
                                                                                    FAILED: "FAILED"

                                                                                    Task has failed during execution.

                                                                                    +
                                                                                    IN_PROGRESS: "IN_PROGRESS"

                                                                                    Task has been assigned to an agent and is being processed.

                                                                                    +
                                                                                    PENDING: "PENDING"

                                                                                    Task has been created but not yet assigned to an agent.

                                                                                    +
                                                                                    REVIEW: "REVIEW"

                                                                                    Task is being reviewed for quality assurance.

                                                                                    +
                                                                                    WAITING: "WAITING"

                                                                                    Task is waiting for external dependencies or manual intervention.

                                                                                    +
                                                                                    diff --git a/docs/components/enums/ErrorCode.html b/docs/components/enums/ErrorCode.html new file mode 100644 index 0000000..fc2b204 --- /dev/null +++ b/docs/components/enums/ErrorCode.html @@ -0,0 +1,105 @@ +ErrorCode | ART Framework API Docs
                                                                                    ART Framework API Docs
                                                                                      Preparing search index...

                                                                                      Enumeration ErrorCode

                                                                                      Defines standard error codes for the ART framework. +These codes categorize errors originating from different subsystems.

                                                                                      +
                                                                                      Index

                                                                                      Enumeration Members

                                                                                      ADAPTER_INSTANTIATION_ERROR: "ADAPTER_INSTANTIATION_ERROR"

                                                                                      Failed to instantiate an adapter for a provider.

                                                                                      +
                                                                                      AGENT_PROCESSING_ERROR: "AGENT_PROCESSING_ERROR"

                                                                                      A general error occurred during the agent's process method.

                                                                                      +
                                                                                      ALREADY_CONNECTED: "ALREADY_CONNECTED"

                                                                                      A connection is already established.

                                                                                      +
                                                                                      API_QUEUE_TIMEOUT: "API_QUEUE_TIMEOUT"

                                                                                      Timeout waiting for an available instance of an API provider.

                                                                                      +
                                                                                      CONFIGURATION_ERROR: "CONFIGURATION_ERROR"

                                                                                      General configuration-related error.

                                                                                      +
                                                                                      CORS_EXTENSION_REQUIRED: "CORS_EXTENSION_REQUIRED"

                                                                                      A CORS browser extension is required to proceed.

                                                                                      +
                                                                                      CORS_PERMISSION_REQUIRED: "CORS_PERMISSION_REQUIRED"

                                                                                      CORS permissions are required but have not been granted.

                                                                                      +
                                                                                      DELEGATION_FAILED: "DELEGATION_FAILED"

                                                                                      An A2A (Agent-to-Agent) task delegation failed.

                                                                                      +
                                                                                      DUPLICATE_TASK_ID: "DUPLICATE_TASK_ID"

                                                                                      A task with the same ID already exists.

                                                                                      +
                                                                                      EXTERNAL_SERVICE_ERROR: "EXTERNAL_SERVICE_ERROR"

                                                                                      An error occurred with an external service.

                                                                                      +
                                                                                      HEALTH_CHECK_FAILED: "HEALTH_CHECK_FAILED"

                                                                                      A health check for a service failed.

                                                                                      +
                                                                                      HTTP_ERROR: "HTTP_ERROR"

                                                                                      An HTTP error occurred.

                                                                                      +
                                                                                      INVALID_CONFIG: "INVALID_CONFIG"

                                                                                      Invalid or malformed configuration provided.

                                                                                      +
                                                                                      INVALID_REQUEST: "INVALID_REQUEST"

                                                                                      The request was invalid or malformed.

                                                                                      +
                                                                                      LLM_PROVIDER_ERROR: "LLM_PROVIDER_ERROR"

                                                                                      An error occurred while communicating with the LLM provider.

                                                                                      +
                                                                                      LOCAL_INSTANCE_BUSY: "LOCAL_INSTANCE_BUSY"

                                                                                      The requested local LLM instance is currently busy.

                                                                                      +
                                                                                      LOCAL_PROVIDER_CONFLICT: "LOCAL_PROVIDER_CONFLICT"

                                                                                      Attempted to activate a local provider when another is already active.

                                                                                      +
                                                                                      MISSING_API_key: "MISSING_API_KEY"

                                                                                      A required API key was not provided.

                                                                                      +
                                                                                      MISSING_CONFIG: "MISSING_CONFIG"

                                                                                      A required configuration is missing.

                                                                                      +
                                                                                      NETWORK_ERROR: "NETWORK_ERROR"

                                                                                      A network error occurred.

                                                                                      +
                                                                                      NO_HTTP_URL: "NO_HTTP_URL"

                                                                                      The provided URL is not an HTTP/HTTPS URL.

                                                                                      +
                                                                                      NO_STDIN: "NO_STDIN"

                                                                                      Standard input is not available.

                                                                                      +
                                                                                      NOT_CONNECTED: "NOT_CONNECTED"

                                                                                      No active connection is available.

                                                                                      +
                                                                                      NOT_IMPLEMENTED: "NOT_IMPLEMENTED"

                                                                                      The requested feature is not implemented.

                                                                                      +
                                                                                      OUTPUT_PARSING_FAILED: "OUTPUT_PARSING_FAILED"

                                                                                      Failed to parse the output from the LLM.

                                                                                      +
                                                                                      PLANNING_FAILED: "PLANNING_FAILED"

                                                                                      The planning phase of the agent failed.

                                                                                      +
                                                                                      PROMPT_ASSEMBLY_FAILED: "PROMPT_ASSEMBLY_FAILED"

                                                                                      Error during prompt template rendering or initial structure creation.

                                                                                      +
                                                                                      PROMPT_FRAGMENT_NOT_FOUND: "PROMPT_FRAGMENT_NOT_FOUND"

                                                                                      The requested prompt fragment does not exist.

                                                                                      +
                                                                                      PROMPT_GENERATION_FAILED: "PROMPT_GENERATION_FAILED"

                                                                                      Failed to generate a prompt.

                                                                                      +
                                                                                      PROMPT_TRANSLATION_FAILED: "PROMPT_TRANSLATION_FAILED"

                                                                                      Failed to translate the ART standard prompt to a provider-specific format.

                                                                                      +
                                                                                      PROMPT_VALIDATION_FAILED: "PROMPT_VALIDATION_FAILED"

                                                                                      The constructed prompt object failed schema validation.

                                                                                      +
                                                                                      REPOSITORY_ERROR: "REPOSITORY_ERROR"

                                                                                      A generic error occurred in a repository.

                                                                                      +
                                                                                      REQUEST_TIMEOUT: "REQUEST_TIMEOUT"

                                                                                      The request timed out.

                                                                                      +
                                                                                      SAVE_FAILED: "SAVE_FAILED"

                                                                                      Failed to save data to the storage layer.

                                                                                      +
                                                                                      SERVER_NOT_FOUND: "SERVER_NOT_FOUND"

                                                                                      The requested server was not found.

                                                                                      +
                                                                                      STORAGE_ERROR: "STORAGE_ERROR"

                                                                                      A generic error occurred in the storage layer.

                                                                                      +
                                                                                      SYNTHESIS_FAILED: "SYNTHESIS_FAILED"

                                                                                      The synthesis phase of the agent failed.

                                                                                      +
                                                                                      TASK_NOT_FOUND: "TASK_NOT_FOUND"

                                                                                      The requested task was not found.

                                                                                      +
                                                                                      THREAD_NOT_FOUND: "THREAD_NOT_FOUND"

                                                                                      The requested thread could not be found in storage.

                                                                                      +
                                                                                      TIMEOUT: "TIMEOUT"

                                                                                      An operation timed out (duplicate of TIMEOUT_ERROR).

                                                                                      +
                                                                                      TIMEOUT_ERROR: "TIMEOUT_ERROR"

                                                                                      An operation timed out.

                                                                                      +
                                                                                      TOOL_DISABLED: "TOOL_DISABLED"

                                                                                      The requested tool is disabled for the current thread.

                                                                                      +
                                                                                      TOOL_DISCOVERY_FAILED: "TOOL_DISCOVERY_FAILED"

                                                                                      Failed to discover tools from a remote source.

                                                                                      +
                                                                                      TOOL_EXECUTION_ERROR: "TOOL_EXECUTION_ERROR"

                                                                                      A generic error occurred during tool execution.

                                                                                      +
                                                                                      TOOL_EXECUTION_FAILED: "TOOL_EXECUTION_FAILED"

                                                                                      An error occurred within the ToolSystem execution loop.

                                                                                      +
                                                                                      TOOL_NOT_FOUND: "TOOL_NOT_FOUND"

                                                                                      The requested tool could not be found in the registry.

                                                                                      +
                                                                                      TOOL_SCHEMA_VALIDATION_FAILED: "TOOL_SCHEMA_VALIDATION_FAILED"

                                                                                      The provided tool schema failed validation.

                                                                                      +
                                                                                      UNKNOWN_ERROR: "UNKNOWN_ERROR"

                                                                                      An unknown or unexpected error occurred.

                                                                                      +
                                                                                      UNKNOWN_PROVIDER: "UNKNOWN_PROVIDER"

                                                                                      The requested LLM provider is not known or configured.

                                                                                      +
                                                                                      UNSUPPORTED_TRANSPORT: "UNSUPPORTed_TRANSPORT"

                                                                                      The requested transport protocol is not supported.

                                                                                      +
                                                                                      VALIDATION_ERROR: "VALIDATION_ERROR"

                                                                                      Input data failed validation.

                                                                                      +
                                                                                      diff --git a/docs/components/enums/LogLevel.html b/docs/components/enums/LogLevel.html new file mode 100644 index 0000000..aa5f82f --- /dev/null +++ b/docs/components/enums/LogLevel.html @@ -0,0 +1,10 @@ +LogLevel | ART Framework API Docs
                                                                                      ART Framework API Docs
                                                                                        Preparing search index...

                                                                                        Enumeration LogLevel

                                                                                        Defines the available logging levels, ordered from most verbose to least verbose.

                                                                                        +
                                                                                        Index

                                                                                        Enumeration Members

                                                                                        Enumeration Members

                                                                                        DEBUG: 0

                                                                                        Detailed debugging information, useful for development.

                                                                                        +
                                                                                        ERROR: 3

                                                                                        Errors that indicate a failure or problem.

                                                                                        +
                                                                                        INFO: 1

                                                                                        General informational messages about application flow.

                                                                                        +
                                                                                        WARN: 2

                                                                                        Potential issues or unexpected situations that don't prevent execution.

                                                                                        +
                                                                                        diff --git a/docs/components/enums/MessageRole.html b/docs/components/enums/MessageRole.html new file mode 100644 index 0000000..762ebb4 --- /dev/null +++ b/docs/components/enums/MessageRole.html @@ -0,0 +1,10 @@ +MessageRole | ART Framework API Docs
                                                                                        ART Framework API Docs
                                                                                          Preparing search index...

                                                                                          Enumeration MessageRole

                                                                                          Represents the role of a message sender in a conversation.

                                                                                          +
                                                                                          Index

                                                                                          Enumeration Members

                                                                                          Enumeration Members

                                                                                          AI: "AI"

                                                                                          The AI agent.

                                                                                          +
                                                                                          SYSTEM: "SYSTEM"

                                                                                          A system-level message providing context or instructions.

                                                                                          +
                                                                                          TOOL: "TOOL"

                                                                                          A message containing the result of a tool execution.

                                                                                          +
                                                                                          USER: "USER"

                                                                                          The end-user interacting with the agent.

                                                                                          +
                                                                                          diff --git a/docs/components/enums/ModelCapability.html b/docs/components/enums/ModelCapability.html new file mode 100644 index 0000000..1cd76b8 --- /dev/null +++ b/docs/components/enums/ModelCapability.html @@ -0,0 +1,17 @@ +ModelCapability | ART Framework API Docs
                                                                                          ART Framework API Docs
                                                                                            Preparing search index...

                                                                                            Enumeration ModelCapability

                                                                                            Represents the different capabilities a model might possess. +Used for model selection and validation.

                                                                                            +
                                                                                            Index

                                                                                            Enumeration Members

                                                                                            Enumeration Members

                                                                                            CODE: "code"

                                                                                            Specialized in understanding or generating code.

                                                                                            +
                                                                                            RAG: "rag"

                                                                                            Built-in or optimized for Retrieval-Augmented Generation.

                                                                                            +
                                                                                            REASONING: "reasoning"

                                                                                            Advanced reasoning, planning, complex instruction following.

                                                                                            +
                                                                                            STREAMING: "streaming"

                                                                                            Supports streaming responses chunk by chunk.

                                                                                            +
                                                                                            TEXT: "text"

                                                                                            Basic text generation/understanding.

                                                                                            +
                                                                                            TOOL_USE: "tool_use"

                                                                                            Capable of using tools/function calling.

                                                                                            +
                                                                                            VISION: "vision"

                                                                                            Ability to process and understand images.

                                                                                            +
                                                                                            diff --git a/docs/components/enums/ObservationType.html b/docs/components/enums/ObservationType.html new file mode 100644 index 0000000..7e78066 --- /dev/null +++ b/docs/components/enums/ObservationType.html @@ -0,0 +1,30 @@ +ObservationType | ART Framework API Docs
                                                                                            ART Framework API Docs
                                                                                              Preparing search index...

                                                                                              Enumeration ObservationType

                                                                                              Represents the type of an observation record, capturing significant events during agent execution.

                                                                                              +
                                                                                              Index

                                                                                              Enumeration Members

                                                                                              ERROR: "ERROR"

                                                                                              Records an error encountered during any phase of execution.

                                                                                              +
                                                                                              FINAL_RESPONSE: "FINAL_RESPONSE"

                                                                                              Records the final AI response message generated by the agent.

                                                                                              +
                                                                                              INTENT: "INTENT"

                                                                                              The user's inferred intent.

                                                                                              +
                                                                                              LLM_STREAM_END: "LLM_STREAM_END"

                                                                                              Logged by Agent Core upon receiving an END stream event.

                                                                                              +
                                                                                              LLM_STREAM_ERROR: "LLM_STREAM_ERROR"

                                                                                              Logged by Agent Core upon receiving an ERROR stream event. Content should be Error object or message.

                                                                                              +
                                                                                              LLM_STREAM_METADATA: "LLM_STREAM_METADATA"

                                                                                              Logged by Agent Core upon receiving a METADATA stream event. Content should be LLMMetadata.

                                                                                              +
                                                                                              LLM_STREAM_START: "LLM_STREAM_START"

                                                                                              Logged by Agent Core when LLM stream consumption begins.

                                                                                              +
                                                                                              PLAN: "PLAN"

                                                                                              The agent's step-by-step plan to address the intent.

                                                                                              +
                                                                                              STATE_UPDATE: "STATE_UPDATE"

                                                                                              Records changes made to the agent's persistent state.

                                                                                              +
                                                                                              SYNTHESIS: "SYNTHESIS"

                                                                                              Records events specifically related to the synthesis phase (e.g., the LLM call).

                                                                                              +
                                                                                              THOUGHTS: "THOUGHTS"

                                                                                              The agent's internal monologue or reasoning process.

                                                                                              +
                                                                                              TITLE: "TITLE"

                                                                                              The generated concise thread title.

                                                                                              +
                                                                                              TOOL_CALL: "TOOL_CALL"

                                                                                              Records the LLM's decision to call one or more tools (part of the plan).

                                                                                              +
                                                                                              TOOL_EXECUTION: "TOOL_EXECUTION"

                                                                                              Records the actual execution attempt and result of a specific tool call.

                                                                                              +
                                                                                              diff --git a/docs/components/functions/createArtInstance.html b/docs/components/functions/createArtInstance.html new file mode 100644 index 0000000..44dca5a --- /dev/null +++ b/docs/components/functions/createArtInstance.html @@ -0,0 +1,16 @@ +createArtInstance | ART Framework API Docs
                                                                                              ART Framework API Docs
                                                                                                Preparing search index...

                                                                                                Function createArtInstance

                                                                                                The main factory function to create and initialize a complete ART framework instance. +This is the recommended starting point for all users. It simplifies setup by +assembling all necessary components based on the provided configuration.

                                                                                                +

                                                                                                The configuration object for the ART instance.

                                                                                                +

                                                                                                A promise that resolves to a ready-to-use ART instance.

                                                                                                +

                                                                                                ArtInstanceConfig for configuration options.

                                                                                                +
                                                                                                • High-level factory function to create and initialize a complete ART framework instance. +This simplifies the setup process by handling the instantiation and wiring of all +necessary components based on the provided configuration.

                                                                                                  +

                                                                                                  Parameters

                                                                                                  • config: ArtInstanceConfig

                                                                                                    The configuration object specifying storage, reasoning, tools, etc.

                                                                                                    +

                                                                                                  Returns Promise<ArtInstance>

                                                                                                  A promise that resolves to a ready-to-use ArtInstance object, providing access to the core process method and essential managers/systems.

                                                                                                  +

                                                                                                  If initialization fails (e.g., invalid config, storage connection error).

                                                                                                  +
                                                                                                  const art = await createArtInstance({
                                                                                                  storage: { type: 'indexedDB', dbName: 'myAgentDb' },
                                                                                                  reasoning: { provider: 'openai', apiKey: '...' },
                                                                                                  tools: [new CalculatorTool()]
                                                                                                  });
                                                                                                  const response = await art.process({ query: "Calculate 5*5", threadId: "thread1" }); +
                                                                                                  + +
                                                                                                diff --git a/docs/components/functions/generateUUID.html b/docs/components/functions/generateUUID.html new file mode 100644 index 0000000..cd8d67c --- /dev/null +++ b/docs/components/functions/generateUUID.html @@ -0,0 +1,5 @@ +generateUUID | ART Framework API Docs
                                                                                                ART Framework API Docs
                                                                                                  Preparing search index...

                                                                                                  Function generateUUID

                                                                                                  • Generates a unique Version 4 UUID (Universally Unique Identifier) string.

                                                                                                    +

                                                                                                    Returns string

                                                                                                    A randomly generated UUID string (e.g., "f47ac10b-58cc-4372-a567-0e02b2c3d479").

                                                                                                    +

                                                                                                    Uses the underlying 'uuid' library's v4 implementation.

                                                                                                    +
                                                                                                  diff --git a/docs/components/hierarchy.html b/docs/components/hierarchy.html new file mode 100644 index 0000000..b7e4a98 --- /dev/null +++ b/docs/components/hierarchy.html @@ -0,0 +1 @@ +ART Framework API Docs
                                                                                                  ART Framework API Docs
                                                                                                    Preparing search index...
                                                                                                    diff --git a/docs/components/index.html b/docs/components/index.html new file mode 100644 index 0000000..7feedfa --- /dev/null +++ b/docs/components/index.html @@ -0,0 +1,64 @@ +ART Framework API Docs
                                                                                                    ART Framework API Docs
                                                                                                      Preparing search index...

                                                                                                      ART Framework API Docs

                                                                                                      ✨ ART: Agentic Runtime Framework Version 0.3.7

                                                                                                      + ART Framework Logo +

                                                                                                      +

                                                                                                      ART is a powerful, modular, and browser-first TypeScript framework for building sophisticated LLM-powered agents capable of complex reasoning, planning, and tool usage.

                                                                                                      +

                                                                                                      It provides the building blocks for creating robust agentic systems that can run entirely client-side, emphasizing user privacy, offline capability, and deep observability, while also supporting server-side deployments.

                                                                                                      +

                                                                                                      License: MIT +PRs Welcome

                                                                                                      +

                                                                                                      Sponsor on Patreon

                                                                                                      +

                                                                                                      Existing agent frameworks often rely on server-side components, limiting their use in web applications where user privacy or offline functionality is critical. ART is engineered to address this gap by providing a comprehensive, standalone toolkit designed for the browser, while remaining powerful enough for server-side execution.

                                                                                                      +

                                                                                                      Core Goals:

                                                                                                      +
                                                                                                        +
                                                                                                      • Browser-First: Enable complex agent logic to run directly in the user's browser, enhancing privacy and reducing server costs.
                                                                                                      • +
                                                                                                      • Modularity: Offer distinct, replaceable components for storage, reasoning, and tools.
                                                                                                      • +
                                                                                                      • Observability: Provide deep, real-time insights into the agent's internal thought process.
                                                                                                      • +
                                                                                                      • Developer Experience: Deliver a layered API that is simple for basic use cases yet powerful enough for advanced customization.
                                                                                                      • +
                                                                                                      +
                                                                                                        +
                                                                                                      • Swappable Agent Cores: Start with the default Plan-Execute-Synthesize (PESAgent) pattern and seamlessly switch to or create custom reasoning patterns (e.g., ReAct, Chain of Thought).
                                                                                                      • +
                                                                                                      • Streaming-First: Native support for streaming LLM responses, enabling real-time, interactive user experiences.
                                                                                                      • +
                                                                                                      • Dynamic Prompt Management: A powerful system for constructing prompts from blueprints with dynamic context injection.
                                                                                                      • +
                                                                                                      • Agent Persona Customization: Easily define your agent's identity and default system prompt through a simple configuration object.
                                                                                                      • +
                                                                                                      • Rich Observability: A detailed, typed Observation system provides transparent insights into every step of an agent's operation for debugging, monitoring, and visualization.
                                                                                                      • +
                                                                                                      +
                                                                                                        +
                                                                                                      • Multi-Provider Support: A centralized ProviderManager allows runtime selection and configuration of multiple LLM providers (OpenAI, Anthropic, Gemini, OpenRouter, and local models via Ollama).
                                                                                                      • +
                                                                                                      • Pluggable Storage: A flexible StorageAdapter interface allows easy integration with any storage backend (default support for IndexedDB, InMemory, and Supabase).
                                                                                                      • +
                                                                                                      • Schema-Driven Tooling: A robust tool integration system with automatic schema validation and secure execution.
                                                                                                      • +
                                                                                                      • Dynamic Tool Loading (MCP): Support for the Model Context Protocol (MCP) enables agents to dynamically discover and use tools from compliant external servers.
                                                                                                      • +
                                                                                                      +
                                                                                                        +
                                                                                                      • Browser-First Design: Built to run fully in the browser, enabling privacy-preserving and offline-capable applications.
                                                                                                      • +
                                                                                                      • Flexible UI Integration: A typed, publish/subscribe socket system allows for reactive UI updates with fine-grained event filtering.
                                                                                                      • +
                                                                                                      • TypeScript-Native: Engineered from the ground up with TypeScript for a robust, type-safe development experience.
                                                                                                      • +
                                                                                                      +

                                                                                                      ART's architecture is best understood as three interconnected nodes:

                                                                                                      +
                                                                                                      flowchart LR
                                                                                                      +    A["Node 1: Developer Interface\n(Your Code & Config)"] -- Configures & Invokes --> B["Node 2: ART Core Orchestration\n(The Framework's Brain)"]
                                                                                                      +    B -- Manages & Uses --> C["Node 3: External Dependencies & Interactions\n(LLMs, Tools, Storage)"]
                                                                                                      +    C -- Provides Data/Services --> B
                                                                                                      +    B -- Streams Results/Updates --> A
                                                                                                      +
                                                                                                      + +
                                                                                                        +
                                                                                                      • Node 1: Developer Interface (Your Code & Config): This is your interaction point with ART. You use createArtInstance to configure the framework, selecting your storage, LLM providers, and tools. You then invoke the agent via the art.process() method.
                                                                                                      • +
                                                                                                      • Node 2: ART Core Orchestration (The Framework's Brain): This is the internal engine that manages the agent's lifecycle. It orchestrates state, reasons with LLMs, constructs prompts, executes tools, and broadcasts updates to your UI. The selected Agent Core (e.g., PESAgent) dictates the high-level reasoning strategy used here.
                                                                                                      • +
                                                                                                      • Node 3: External Dependencies & Interactions (The Outside World): This node represents the external services ART connects to. This includes LLM APIs (like OpenAI), your custom tool logic, and storage backends (like IndexedDB or a remote database).
                                                                                                      • +
                                                                                                      +
                                                                                                      npm install art-framework
                                                                                                      # or
                                                                                                      pnpm install art-framework
                                                                                                      # or
                                                                                                      yarn add art-framework +
                                                                                                      + +

                                                                                                      This example demonstrates setting up a simple agent that uses OpenAI and runs in-memory. For a complete example with all configurations, see the Comprehensive Developer Guide.

                                                                                                      +
                                                                                                      import { 
                                                                                                      createArtInstance,
                                                                                                      ArtInstanceConfig,
                                                                                                      ThreadConfig,
                                                                                                      CalculatorTool,
                                                                                                      OpenAIAdapter,
                                                                                                      GeminiAdapter
                                                                                                      } from 'art-framework';

                                                                                                      // --- 1. Configure the ART Instance ---
                                                                                                      // Note: No API keys or secrets are present here.

                                                                                                      const artConfig: ArtInstanceConfig = {
                                                                                                      storage: {
                                                                                                      type: 'indexedDB',
                                                                                                      dbName: 'MyCorrectChatDB'
                                                                                                      },
                                                                                                      providers: {
                                                                                                      availableProviders: [
                                                                                                      { name: 'openai', adapter: OpenAIAdapter },
                                                                                                      { name: 'gemini', adapter: GeminiAdapter }
                                                                                                      ]
                                                                                                      },
                                                                                                      tools: [new CalculatorTool()],
                                                                                                      persona: {
                                                                                                      name: 'ConfigExpert',
                                                                                                      prompts: {
                                                                                                      synthesis: 'You explain configurations clearly.'
                                                                                                      }
                                                                                                      },
                                                                                                      logger: { level: 'info' }
                                                                                                      };


                                                                                                      // --- 2. Main Application Logic ---

                                                                                                      async function initializeAndRun() {
                                                                                                      // Create the ART instance with the high-level configuration.
                                                                                                      const art = await createArtInstance(artConfig);
                                                                                                      console.log('ART Instance Initialized.');

                                                                                                      // --- 3. Set Up a New Conversation Thread ---
                                                                                                      const threadId = 'user-123-session-1';

                                                                                                      // Create the thread-specific configuration.
                                                                                                      // THIS is where you specify the provider, model, and API key.
                                                                                                      const threadConfig: ThreadConfig = {
                                                                                                      providerConfig: {
                                                                                                      providerName: 'openai', // Must match a name from availableProviders
                                                                                                      modelId: 'gpt-4o',
                                                                                                      adapterOptions: {
                                                                                                      apiKey: 'sk-your-real-openai-api-key', // Securely provide your API key here
                                                                                                      temperature: 0.7
                                                                                                      }
                                                                                                      },
                                                                                                      // Other thread settings
                                                                                                      enabledTools: ['CalculatorTool'],
                                                                                                      historyLimit: 20
                                                                                                      };

                                                                                                      // Save this configuration for the new thread.
                                                                                                      // This step is crucial and must be done before the first `process` call.
                                                                                                      await art.stateManager.setThreadConfig(threadId, threadConfig);
                                                                                                      console.log(`ThreadConfig set for threadId: ${threadId}`);

                                                                                                      // Now the ART instance is ready to process requests for this thread.
                                                                                                      console.log('Sending first message...');
                                                                                                      const response = await art.process({
                                                                                                      query: 'What is 2 + 2?',
                                                                                                      threadId: threadId
                                                                                                      });

                                                                                                      console.log('Final response:', response.response.content);
                                                                                                      }

                                                                                                      initializeAndRun().catch(console.error); +
                                                                                                      + +

                                                                                                      (Note: Replace 'YOUR_OPENAI_API_KEY' with your actual key. In a real application, load this from a secure source like environment variables or a secrets manager.)

                                                                                                      + +

                                                                                                      Contributions are welcome! Please refer to the Contributing Guide for details on how to submit issues, feature requests, and pull requests.

                                                                                                      +

                                                                                                      ART Framework is released under the MIT License.

                                                                                                      +
                                                                                                      diff --git a/docs/components/interfaces/A2AAgentInfo.html b/docs/components/interfaces/A2AAgentInfo.html new file mode 100644 index 0000000..456a4d8 --- /dev/null +++ b/docs/components/interfaces/A2AAgentInfo.html @@ -0,0 +1,20 @@ +A2AAgentInfo | ART Framework API Docs
                                                                                                      ART Framework API Docs
                                                                                                        Preparing search index...

                                                                                                        Interface A2AAgentInfo

                                                                                                        Represents agent information for A2A task assignment.

                                                                                                        +

                                                                                                        A2AAgentInfo

                                                                                                        +
                                                                                                        interface A2AAgentInfo {
                                                                                                            agentId: string;
                                                                                                            agentName: string;
                                                                                                            agentType: string;
                                                                                                            authentication?: {
                                                                                                                apiKey?: string;
                                                                                                                token?: string;
                                                                                                                type: "bearer" | "api_key" | "none";
                                                                                                            };
                                                                                                            capabilities?: string[];
                                                                                                            endpoint?: string;
                                                                                                            status?: "available"
                                                                                                            | "busy"
                                                                                                            | "offline";
                                                                                                        }
                                                                                                        Index

                                                                                                        Properties

                                                                                                        agentId: string

                                                                                                        Unique identifier for the agent.

                                                                                                        +
                                                                                                        agentName: string

                                                                                                        Human-readable name for the agent.

                                                                                                        +
                                                                                                        agentType: string

                                                                                                        The type or role of the agent (e.g., 'reasoning', 'data-processing', 'synthesis').

                                                                                                        +
                                                                                                        authentication?: {
                                                                                                            apiKey?: string;
                                                                                                            token?: string;
                                                                                                            type: "bearer" | "api_key" | "none";
                                                                                                        }

                                                                                                        Authentication configuration for communicating with the agent.

                                                                                                        +

                                                                                                        Type declaration

                                                                                                        • OptionalapiKey?: string

                                                                                                          API key for authorization (if type is 'api_key').

                                                                                                          +
                                                                                                        • Optionaltoken?: string

                                                                                                          Bearer token for authorization (if type is 'bearer').

                                                                                                          +
                                                                                                        • type: "bearer" | "api_key" | "none"

                                                                                                          Type of authentication required.

                                                                                                          +
                                                                                                        capabilities?: string[]

                                                                                                        Agent capabilities or specializations.

                                                                                                        +
                                                                                                        endpoint?: string

                                                                                                        Base URL or endpoint for communicating with the agent.

                                                                                                        +
                                                                                                        status?: "available" | "busy" | "offline"

                                                                                                        Current load or availability status of the agent.

                                                                                                        +
                                                                                                        diff --git a/docs/components/interfaces/A2ATask.html b/docs/components/interfaces/A2ATask.html new file mode 100644 index 0000000..972ed84 --- /dev/null +++ b/docs/components/interfaces/A2ATask.html @@ -0,0 +1,30 @@ +A2ATask | ART Framework API Docs
                                                                                                        ART Framework API Docs
                                                                                                          Preparing search index...

                                                                                                          Interface A2ATask

                                                                                                          Represents a task for Agent-to-Agent (A2A) communication and delegation. +Used for asynchronous task delegation between AI agents in distributed systems.

                                                                                                          +

                                                                                                          A2ATask

                                                                                                          +
                                                                                                          interface A2ATask {
                                                                                                              callbackUrl?: string;
                                                                                                              dependencies?: string[];
                                                                                                              metadata: A2ATaskMetadata;
                                                                                                              payload: {
                                                                                                                  input: any;
                                                                                                                  instructions?: string;
                                                                                                                  parameters?: Record<string, any>;
                                                                                                                  taskType: string;
                                                                                                              };
                                                                                                              priority: A2ATaskPriority;
                                                                                                              result?: A2ATaskResult;
                                                                                                              sourceAgent: A2AAgentInfo;
                                                                                                              status: A2ATaskStatus;
                                                                                                              targetAgent?: A2AAgentInfo;
                                                                                                              taskId: string;
                                                                                                              threadId: string;
                                                                                                          }
                                                                                                          Index

                                                                                                          Properties

                                                                                                          callbackUrl?: string

                                                                                                          Callback URL or identifier for task completion notifications.

                                                                                                          +
                                                                                                          dependencies?: string[]

                                                                                                          Dependencies that must be completed before this task can start.

                                                                                                          +
                                                                                                          metadata: A2ATaskMetadata

                                                                                                          Task execution metadata.

                                                                                                          +
                                                                                                          payload: {
                                                                                                              input: any;
                                                                                                              instructions?: string;
                                                                                                              parameters?: Record<string, any>;
                                                                                                              taskType: string;
                                                                                                          }

                                                                                                          The data payload containing task parameters and context.

                                                                                                          +

                                                                                                          Type declaration

                                                                                                          • input: any

                                                                                                            Input data required for task execution.

                                                                                                            +
                                                                                                          • Optionalinstructions?: string

                                                                                                            Instructions or configuration for the task.

                                                                                                            +
                                                                                                          • Optionalparameters?: Record<string, any>

                                                                                                            Additional parameters specific to the task type.

                                                                                                            +
                                                                                                          • taskType: string

                                                                                                            The type of task to be executed (e.g., 'analyze', 'synthesize', 'transform').

                                                                                                            +
                                                                                                          priority: A2ATaskPriority

                                                                                                          Task priority level.

                                                                                                          +
                                                                                                          result?: A2ATaskResult

                                                                                                          The result of task execution (if completed).

                                                                                                          +
                                                                                                          sourceAgent: A2AAgentInfo

                                                                                                          Information about the agent that created/requested this task.

                                                                                                          +

                                                                                                          Current status of the task.

                                                                                                          +
                                                                                                          targetAgent?: A2AAgentInfo

                                                                                                          Information about the agent assigned to execute this task (if assigned).

                                                                                                          +
                                                                                                          taskId: string

                                                                                                          Unique identifier for the task.

                                                                                                          +
                                                                                                          threadId: string

                                                                                                          The thread this task belongs to (top-level for efficient filtering).

                                                                                                          +
                                                                                                          diff --git a/docs/components/interfaces/A2ATaskEvent.html b/docs/components/interfaces/A2ATaskEvent.html new file mode 100644 index 0000000..835d00e --- /dev/null +++ b/docs/components/interfaces/A2ATaskEvent.html @@ -0,0 +1,16 @@ +A2ATaskEvent | ART Framework API Docs
                                                                                                          ART Framework API Docs
                                                                                                            Preparing search index...

                                                                                                            Interface A2ATaskEvent

                                                                                                            Event data structure for A2A task updates. +Contains the updated task and metadata about the change.

                                                                                                            +
                                                                                                            interface A2ATaskEvent {
                                                                                                                eventType:
                                                                                                                    | "created"
                                                                                                                    | "updated"
                                                                                                                    | "completed"
                                                                                                                    | "failed"
                                                                                                                    | "cancelled"
                                                                                                                    | "status_changed"
                                                                                                                    | "delegated";
                                                                                                                metadata?: {
                                                                                                                    automatic?: boolean;
                                                                                                                    context?: Record<string, any>;
                                                                                                                    source?: string;
                                                                                                                };
                                                                                                                previousStatus?: A2ATaskStatus;
                                                                                                                task: A2ATask;
                                                                                                                timestamp: number;
                                                                                                            }
                                                                                                            Index

                                                                                                            Properties

                                                                                                            eventType:
                                                                                                                | "created"
                                                                                                                | "updated"
                                                                                                                | "completed"
                                                                                                                | "failed"
                                                                                                                | "cancelled"
                                                                                                                | "status_changed"
                                                                                                                | "delegated"

                                                                                                            The type of event that occurred

                                                                                                            +
                                                                                                            metadata?: {
                                                                                                                automatic?: boolean;
                                                                                                                context?: Record<string, any>;
                                                                                                                source?: string;
                                                                                                            }

                                                                                                            Additional metadata about the event

                                                                                                            +

                                                                                                            Type declaration

                                                                                                            • Optionalautomatic?: boolean

                                                                                                              Whether this was an automatic update or manual

                                                                                                              +
                                                                                                            • Optionalcontext?: Record<string, any>

                                                                                                              Any additional context

                                                                                                              +
                                                                                                            • Optionalsource?: string

                                                                                                              The component that triggered the update

                                                                                                              +
                                                                                                            previousStatus?: A2ATaskStatus

                                                                                                            Previous status (if applicable) for status change events

                                                                                                            +
                                                                                                            task: A2ATask

                                                                                                            The A2A task that was updated

                                                                                                            +
                                                                                                            timestamp: number

                                                                                                            Timestamp when the event occurred

                                                                                                            +
                                                                                                            diff --git a/docs/components/interfaces/A2ATaskFilter.html b/docs/components/interfaces/A2ATaskFilter.html new file mode 100644 index 0000000..5c0a5cf --- /dev/null +++ b/docs/components/interfaces/A2ATaskFilter.html @@ -0,0 +1,15 @@ +A2ATaskFilter | ART Framework API Docs
                                                                                                            ART Framework API Docs
                                                                                                              Preparing search index...

                                                                                                              Interface A2ATaskFilter

                                                                                                              Filter type for A2A task notifications. +Allows filtering by task status, task type, agent, or priority.

                                                                                                              +
                                                                                                              interface A2ATaskFilter {
                                                                                                                  priority?: string;
                                                                                                                  sourceAgentId?: string;
                                                                                                                  status?: A2ATaskStatus | A2ATaskStatus[];
                                                                                                                  targetAgentId?: string;
                                                                                                                  taskType?: string | string[];
                                                                                                                  threadId?: string;
                                                                                                              }
                                                                                                              Index

                                                                                                              Properties

                                                                                                              priority?: string

                                                                                                              Filter by task priority

                                                                                                              +
                                                                                                              sourceAgentId?: string

                                                                                                              Filter by source agent ID

                                                                                                              +

                                                                                                              Filter by task status (single status or array of statuses)

                                                                                                              +
                                                                                                              targetAgentId?: string

                                                                                                              Filter by target agent ID

                                                                                                              +
                                                                                                              taskType?: string | string[]

                                                                                                              Filter by task type (e.g., 'analyze', 'synthesize', 'transform')

                                                                                                              +
                                                                                                              threadId?: string

                                                                                                              Filter by thread ID

                                                                                                              +
                                                                                                              diff --git a/docs/components/interfaces/A2ATaskMetadata.html b/docs/components/interfaces/A2ATaskMetadata.html new file mode 100644 index 0000000..70dc801 --- /dev/null +++ b/docs/components/interfaces/A2ATaskMetadata.html @@ -0,0 +1,29 @@ +A2ATaskMetadata | ART Framework API Docs
                                                                                                              ART Framework API Docs
                                                                                                                Preparing search index...

                                                                                                                Interface A2ATaskMetadata

                                                                                                                Represents metadata about A2A task execution.

                                                                                                                +

                                                                                                                A2ATaskMetadata

                                                                                                                +
                                                                                                                interface A2ATaskMetadata {
                                                                                                                    completedAt?: number;
                                                                                                                    correlationId?: string;
                                                                                                                    createdAt: number;
                                                                                                                    delegatedAt?: number;
                                                                                                                    estimatedCompletionMs?: number;
                                                                                                                    initiatedBy?: string;
                                                                                                                    lastUpdated?: number;
                                                                                                                    maxRetries?: number;
                                                                                                                    retryCount?: number;
                                                                                                                    startedAt?: number;
                                                                                                                    tags?: string[];
                                                                                                                    timeoutMs?: number;
                                                                                                                    updatedAt: number;
                                                                                                                }
                                                                                                                Index

                                                                                                                Properties

                                                                                                                completedAt?: number

                                                                                                                Timestamp when the task was completed/failed (if applicable).

                                                                                                                +
                                                                                                                correlationId?: string

                                                                                                                Correlation ID for tracking related tasks across the system.

                                                                                                                +
                                                                                                                createdAt: number

                                                                                                                Timestamp when the task was created (Unix timestamp in milliseconds).

                                                                                                                +
                                                                                                                delegatedAt?: number

                                                                                                                Timestamp when the task was delegated to a remote agent (if applicable).

                                                                                                                +
                                                                                                                estimatedCompletionMs?: number

                                                                                                                Estimated completion time in milliseconds (if provided by remote agent).

                                                                                                                +
                                                                                                                initiatedBy?: string

                                                                                                                The user or system that initiated this task.

                                                                                                                +
                                                                                                                lastUpdated?: number

                                                                                                                Timestamp when the task was last updated (for compatibility).

                                                                                                                +
                                                                                                                maxRetries?: number

                                                                                                                Maximum number of retry attempts allowed.

                                                                                                                +
                                                                                                                retryCount?: number

                                                                                                                Number of retry attempts made for this task.

                                                                                                                +
                                                                                                                startedAt?: number

                                                                                                                Timestamp when the task was started (if applicable).

                                                                                                                +
                                                                                                                tags?: string[]

                                                                                                                Tags or labels for categorizing tasks.

                                                                                                                +
                                                                                                                timeoutMs?: number

                                                                                                                Timeout duration in milliseconds.

                                                                                                                +
                                                                                                                updatedAt: number

                                                                                                                Timestamp when the task was last updated (Unix timestamp in milliseconds).

                                                                                                                +
                                                                                                                diff --git a/docs/components/interfaces/A2ATaskResult.html b/docs/components/interfaces/A2ATaskResult.html new file mode 100644 index 0000000..7325226 --- /dev/null +++ b/docs/components/interfaces/A2ATaskResult.html @@ -0,0 +1,13 @@ +A2ATaskResult | ART Framework API Docs
                                                                                                                ART Framework API Docs
                                                                                                                  Preparing search index...

                                                                                                                  Interface A2ATaskResult

                                                                                                                  Represents the result of an A2A task execution.

                                                                                                                  +

                                                                                                                  A2ATaskResult

                                                                                                                  +
                                                                                                                  interface A2ATaskResult {
                                                                                                                      data?: any;
                                                                                                                      durationMs?: number;
                                                                                                                      error?: string;
                                                                                                                      metadata?: {
                                                                                                                          sources?: { sourceName: string; url?: string; [key: string]: any }[];
                                                                                                                          [key: string]: any;
                                                                                                                      };
                                                                                                                      success: boolean;
                                                                                                                  }
                                                                                                                  Index

                                                                                                                  Properties

                                                                                                                  data?: any

                                                                                                                  The data returned by the task execution.

                                                                                                                  +
                                                                                                                  durationMs?: number

                                                                                                                  Execution duration in milliseconds.

                                                                                                                  +
                                                                                                                  error?: string

                                                                                                                  Error message if the task failed.

                                                                                                                  +
                                                                                                                  metadata?: {
                                                                                                                      sources?: { sourceName: string; url?: string; [key: string]: any }[];
                                                                                                                      [key: string]: any;
                                                                                                                  }

                                                                                                                  Additional metadata about the execution.

                                                                                                                  +
                                                                                                                  success: boolean

                                                                                                                  Whether the task execution was successful.

                                                                                                                  +
                                                                                                                  diff --git a/docs/components/interfaces/AgentDiscoveryConfig.html b/docs/components/interfaces/AgentDiscoveryConfig.html new file mode 100644 index 0000000..72c2122 --- /dev/null +++ b/docs/components/interfaces/AgentDiscoveryConfig.html @@ -0,0 +1,10 @@ +AgentDiscoveryConfig | ART Framework API Docs
                                                                                                                  ART Framework API Docs
                                                                                                                    Preparing search index...

                                                                                                                    Interface AgentDiscoveryConfig

                                                                                                                    Configuration for the AgentDiscoveryService

                                                                                                                    +
                                                                                                                    interface AgentDiscoveryConfig {
                                                                                                                        cacheTtlMs?: number;
                                                                                                                        discoveryEndpoint?: string;
                                                                                                                        enableCaching?: boolean;
                                                                                                                        timeoutMs?: number;
                                                                                                                    }
                                                                                                                    Index

                                                                                                                    Properties

                                                                                                                    cacheTtlMs?: number

                                                                                                                    Cache TTL in milliseconds

                                                                                                                    +
                                                                                                                    discoveryEndpoint?: string

                                                                                                                    Base URL for the discovery endpoint. If not provided, a default will be used.

                                                                                                                    +
                                                                                                                    enableCaching?: boolean

                                                                                                                    Whether to cache discovered agents

                                                                                                                    +
                                                                                                                    timeoutMs?: number

                                                                                                                    Timeout for discovery requests in milliseconds

                                                                                                                    +
                                                                                                                    diff --git a/docs/components/interfaces/AgentFinalResponse.html b/docs/components/interfaces/AgentFinalResponse.html new file mode 100644 index 0000000..15716a7 --- /dev/null +++ b/docs/components/interfaces/AgentFinalResponse.html @@ -0,0 +1,7 @@ +AgentFinalResponse | ART Framework API Docs
                                                                                                                    ART Framework API Docs
                                                                                                                      Preparing search index...

                                                                                                                      Interface AgentFinalResponse

                                                                                                                      The final structured response returned by the agent core after processing.

                                                                                                                      +

                                                                                                                      AgentFinalResponse

                                                                                                                      +
                                                                                                                      interface AgentFinalResponse {
                                                                                                                          metadata: ExecutionMetadata;
                                                                                                                          response: ConversationMessage;
                                                                                                                      }
                                                                                                                      Index

                                                                                                                      Properties

                                                                                                                      Properties

                                                                                                                      Metadata summarizing the execution cycle that produced this response.

                                                                                                                      +

                                                                                                                      The final ConversationMessage generated by the AI, which has also been persisted.

                                                                                                                      +
                                                                                                                      diff --git a/docs/components/interfaces/AgentOptions.html b/docs/components/interfaces/AgentOptions.html new file mode 100644 index 0000000..497268e --- /dev/null +++ b/docs/components/interfaces/AgentOptions.html @@ -0,0 +1,20 @@ +AgentOptions | ART Framework API Docs
                                                                                                                      ART Framework API Docs
                                                                                                                        Preparing search index...

                                                                                                                        Interface AgentOptions

                                                                                                                        Options to override agent behavior at runtime.

                                                                                                                        +

                                                                                                                        AgentOptions

                                                                                                                        +
                                                                                                                        interface AgentOptions {
                                                                                                                            forceTools?: string[];
                                                                                                                            llmParams?: Record<string, any>;
                                                                                                                            overrideModel?: { model: string; provider: string };
                                                                                                                            persona?: Partial<AgentPersona>;
                                                                                                                            promptTemplateId?: string;
                                                                                                                            providerConfig?: RuntimeProviderConfig;
                                                                                                                            stream?: boolean;
                                                                                                                            systemPrompt?: string | SystemPromptOverride;
                                                                                                                        }
                                                                                                                        Index

                                                                                                                        Properties

                                                                                                                        forceTools?: string[]

                                                                                                                        Force the use of specific tools, potentially overriding the thread's enabledTools for this call (use with caution).

                                                                                                                        +
                                                                                                                        llmParams?: Record<string, any>

                                                                                                                        Override specific LLM parameters (e.g., temperature, max_tokens) for this call only.

                                                                                                                        +
                                                                                                                        overrideModel?: { model: string; provider: string }

                                                                                                                        Specify a particular reasoning model to use for this call, overriding the thread's default.

                                                                                                                        +
                                                                                                                        persona?: Partial<AgentPersona>

                                                                                                                        Optional: Defines the identity and high-level guidance for the agent for this specific call. +This overrides both the instance-level and thread-level persona.

                                                                                                                        +
                                                                                                                        promptTemplateId?: string

                                                                                                                        Override the prompt template used for this specific call.

                                                                                                                        +
                                                                                                                        providerConfig?: RuntimeProviderConfig

                                                                                                                        Override provider configuration for this specific call.

                                                                                                                        +
                                                                                                                        stream?: boolean

                                                                                                                        Request a streaming response for this specific agent process call.

                                                                                                                        +
                                                                                                                        systemPrompt?: string | SystemPromptOverride

                                                                                                                        Optional system prompt override/tag to override thread, instance, or agent defaults for this specific call.

                                                                                                                        +
                                                                                                                        diff --git a/docs/components/interfaces/AgentPersona.html b/docs/components/interfaces/AgentPersona.html new file mode 100644 index 0000000..86d2dbc --- /dev/null +++ b/docs/components/interfaces/AgentPersona.html @@ -0,0 +1,10 @@ +AgentPersona | ART Framework API Docs
                                                                                                                        ART Framework API Docs
                                                                                                                          Preparing search index...

                                                                                                                          Interface AgentPersona

                                                                                                                          Defines the default identity and high-level guidance for an agent. +This is provided at the instance level and can be overridden by thread or call-specific prompts.

                                                                                                                          +

                                                                                                                          AgentPersona

                                                                                                                          +
                                                                                                                          interface AgentPersona {
                                                                                                                              name: string;
                                                                                                                              prompts: StageSpecificPrompts;
                                                                                                                          }
                                                                                                                          Index

                                                                                                                          Properties

                                                                                                                          Properties

                                                                                                                          name: string

                                                                                                                          The name or identity of the agent (e.g., "Zoi"). +This will be used in the synthesis prompt.

                                                                                                                          +

                                                                                                                          The default system prompt that provides high-level guidance. +This serves as the base layer in the system prompt resolution hierarchy.

                                                                                                                          +
                                                                                                                          diff --git a/docs/components/interfaces/AgentProps.html b/docs/components/interfaces/AgentProps.html new file mode 100644 index 0000000..1fff0ee --- /dev/null +++ b/docs/components/interfaces/AgentProps.html @@ -0,0 +1,15 @@ +AgentProps | ART Framework API Docs
                                                                                                                          ART Framework API Docs
                                                                                                                            Preparing search index...

                                                                                                                            Interface AgentProps

                                                                                                                            Properties required to initiate an agent processing cycle.

                                                                                                                            +

                                                                                                                            AgentProps

                                                                                                                            +
                                                                                                                            interface AgentProps {
                                                                                                                                options?: AgentOptions;
                                                                                                                                query: string;
                                                                                                                                sessionId?: string;
                                                                                                                                threadId: string;
                                                                                                                                traceId?: string;
                                                                                                                                userId?: string;
                                                                                                                            }
                                                                                                                            Index

                                                                                                                            Properties

                                                                                                                            options?: AgentOptions

                                                                                                                            Optional runtime options that can override default behaviors for this specific process call.

                                                                                                                            +
                                                                                                                            query: string

                                                                                                                            The user's input query or request to the agent.

                                                                                                                            +
                                                                                                                            sessionId?: string

                                                                                                                            An optional identifier for the specific UI session, useful for targeting UI updates.

                                                                                                                            +
                                                                                                                            threadId: string

                                                                                                                            The mandatory identifier for the conversation thread. All context is scoped to this ID.

                                                                                                                            +
                                                                                                                            traceId?: string

                                                                                                                            An optional identifier used for tracing a request across multiple systems or services.

                                                                                                                            +
                                                                                                                            userId?: string

                                                                                                                            An optional identifier for the user interacting with the agent.

                                                                                                                            +
                                                                                                                            diff --git a/docs/components/interfaces/AgentState.html b/docs/components/interfaces/AgentState.html new file mode 100644 index 0000000..940fdc3 --- /dev/null +++ b/docs/components/interfaces/AgentState.html @@ -0,0 +1,9 @@ +AgentState | ART Framework API Docs
                                                                                                                            ART Framework API Docs
                                                                                                                              Preparing search index...

                                                                                                                              Interface AgentState

                                                                                                                              Represents non-configuration state associated with an agent or thread. +Could include user preferences, accumulated knowledge, etc. (Less defined for v1.0)

                                                                                                                              +

                                                                                                                              AgentState

                                                                                                                              +
                                                                                                                              interface AgentState {
                                                                                                                                  data: any;
                                                                                                                                  version?: number;
                                                                                                                                  [key: string]: any;
                                                                                                                              }

                                                                                                                              Indexable

                                                                                                                              • [key: string]: any

                                                                                                                                Allows for other arbitrary properties to be stored in the agent's state.

                                                                                                                                +
                                                                                                                              Index

                                                                                                                              Properties

                                                                                                                              Properties

                                                                                                                              data: any

                                                                                                                              The primary data payload of the agent's state. Structure is application-defined.

                                                                                                                              +
                                                                                                                              version?: number

                                                                                                                              An optional version number for the agent's state, useful for migrations or tracking changes.

                                                                                                                              +
                                                                                                                              diff --git a/docs/components/interfaces/AnthropicAdapterOptions.html b/docs/components/interfaces/AnthropicAdapterOptions.html new file mode 100644 index 0000000..dac56d8 --- /dev/null +++ b/docs/components/interfaces/AnthropicAdapterOptions.html @@ -0,0 +1,12 @@ +AnthropicAdapterOptions | ART Framework API Docs
                                                                                                                              ART Framework API Docs
                                                                                                                                Preparing search index...

                                                                                                                                Interface AnthropicAdapterOptions

                                                                                                                                Configuration options required for the AnthropicAdapter.

                                                                                                                                +
                                                                                                                                interface AnthropicAdapterOptions {
                                                                                                                                    apiBaseUrl?: string;
                                                                                                                                    apiKey: string;
                                                                                                                                    defaultMaxTokens?: number;
                                                                                                                                    defaultTemperature?: number;
                                                                                                                                    model?: string;
                                                                                                                                }
                                                                                                                                Index

                                                                                                                                Properties

                                                                                                                                apiBaseUrl?: string

                                                                                                                                Optional: Override the base URL for the Anthropic API.

                                                                                                                                +
                                                                                                                                apiKey: string

                                                                                                                                Your Anthropic API key. Handle securely.

                                                                                                                                +
                                                                                                                                defaultMaxTokens?: number

                                                                                                                                Optional: Default maximum tokens for responses.

                                                                                                                                +
                                                                                                                                defaultTemperature?: number

                                                                                                                                Optional: Default temperature for responses.

                                                                                                                                +
                                                                                                                                model?: string

                                                                                                                                The default Anthropic model ID to use (e.g., 'claude-3-opus-20240229', 'claude-3-5-sonnet-20240620').

                                                                                                                                +
                                                                                                                                diff --git a/docs/components/interfaces/ArtInstance.html b/docs/components/interfaces/ArtInstance.html new file mode 100644 index 0000000..0a08bd7 --- /dev/null +++ b/docs/components/interfaces/ArtInstance.html @@ -0,0 +1,20 @@ +ArtInstance | ART Framework API Docs
                                                                                                                                ART Framework API Docs
                                                                                                                                  Preparing search index...

                                                                                                                                  Interface ArtInstance

                                                                                                                                  interface ArtInstance {
                                                                                                                                      authManager?: null | AuthManager;
                                                                                                                                      conversationManager: ConversationManager;
                                                                                                                                      observationManager: ObservationManager;
                                                                                                                                      process: (props: AgentProps) => Promise<AgentFinalResponse>;
                                                                                                                                      stateManager: StateManager;
                                                                                                                                      toolRegistry: ToolRegistry;
                                                                                                                                      uiSystem: UISystem;
                                                                                                                                  }
                                                                                                                                  Index

                                                                                                                                  Properties

                                                                                                                                  authManager?: null | AuthManager

                                                                                                                                  Accessor for the Auth Manager, used for handling authentication.

                                                                                                                                  +
                                                                                                                                  conversationManager: ConversationManager

                                                                                                                                  Accessor for the Conversation Manager, used for managing message history.

                                                                                                                                  +
                                                                                                                                  observationManager: ObservationManager

                                                                                                                                  Accessor for the Observation Manager, used for recording and retrieving observations.

                                                                                                                                  +
                                                                                                                                  process: (props: AgentProps) => Promise<AgentFinalResponse>

                                                                                                                                  The main method to process a user query using the configured Agent Core.

                                                                                                                                  +

                                                                                                                                  Type declaration

                                                                                                                                    • (props: AgentProps): Promise<AgentFinalResponse>
                                                                                                                                    • Processes a user query through the configured agent reasoning pattern (e.g., PES). +Orchestrates interactions between various ART subsystems.

                                                                                                                                      +

                                                                                                                                      Parameters

                                                                                                                                      • props: AgentProps

                                                                                                                                        The input properties for the agent execution, including the query, thread ID, and injected dependencies.

                                                                                                                                        +

                                                                                                                                      Returns Promise<AgentFinalResponse>

                                                                                                                                      A promise that resolves with the final agent response and execution metadata.

                                                                                                                                      +

                                                                                                                                      If a critical error occurs during orchestration that prevents completion.

                                                                                                                                      +
                                                                                                                                  stateManager: StateManager

                                                                                                                                  Accessor for the State Manager, used for managing thread configuration and state.

                                                                                                                                  +
                                                                                                                                  toolRegistry: ToolRegistry

                                                                                                                                  Accessor for the Tool Registry, used for managing available tools.

                                                                                                                                  +
                                                                                                                                  uiSystem: UISystem

                                                                                                                                  Accessor for the UI System, used to get sockets for subscriptions.

                                                                                                                                  +
                                                                                                                                  diff --git a/docs/components/interfaces/ArtInstanceConfig.html b/docs/components/interfaces/ArtInstanceConfig.html new file mode 100644 index 0000000..1a84774 --- /dev/null +++ b/docs/components/interfaces/ArtInstanceConfig.html @@ -0,0 +1,47 @@ +ArtInstanceConfig | ART Framework API Docs
                                                                                                                                  ART Framework API Docs
                                                                                                                                    Preparing search index...

                                                                                                                                    Interface ArtInstanceConfig

                                                                                                                                    Configuration for creating an ART instance.

                                                                                                                                    +

                                                                                                                                    ArtInstanceConfig

                                                                                                                                    +
                                                                                                                                    interface ArtInstanceConfig {
                                                                                                                                        a2aConfig?: { callbackUrl?: string; discoveryEndpoint?: string };
                                                                                                                                        agentCore?: new (dependencies: any) => IAgentCore;
                                                                                                                                        authConfig?: {
                                                                                                                                            enabled?: boolean;
                                                                                                                                            strategies?: { id: string; strategy: any }[];
                                                                                                                                        };
                                                                                                                                        logger?: { level?: LogLevel };
                                                                                                                                        mcpConfig?: McpManagerConfig;
                                                                                                                                        persona?: AgentPersona;
                                                                                                                                        providers: ProviderManagerConfig;
                                                                                                                                        stateSavingStrategy?: StateSavingStrategy;
                                                                                                                                        storage:
                                                                                                                                            | StorageAdapter
                                                                                                                                            | {
                                                                                                                                                dbName?: string;
                                                                                                                                                objectStores?: any[];
                                                                                                                                                type: "memory"
                                                                                                                                                | "indexedDB";
                                                                                                                                                version?: number;
                                                                                                                                            };
                                                                                                                                        tools?: IToolExecutor[];
                                                                                                                                    }
                                                                                                                                    Index

                                                                                                                                    Properties

                                                                                                                                    a2aConfig?: { callbackUrl?: string; discoveryEndpoint?: string }

                                                                                                                                    Optional: Configuration for A2A services.

                                                                                                                                    +

                                                                                                                                    Type declaration

                                                                                                                                    • OptionalcallbackUrl?: string

                                                                                                                                      The callback URL for receiving A2A task updates.

                                                                                                                                      +
                                                                                                                                    • OptionaldiscoveryEndpoint?: string

                                                                                                                                      The endpoint for discovering A2A agents.

                                                                                                                                      +
                                                                                                                                    agentCore?: new (dependencies: any) => IAgentCore

                                                                                                                                    The agent core implementation class to use. +Defaults to PESAgent if not provided.

                                                                                                                                    +
                                                                                                                                    MyCustomAgentClass
                                                                                                                                    +
                                                                                                                                    + +
                                                                                                                                    authConfig?: { enabled?: boolean; strategies?: { id: string; strategy: any }[] }

                                                                                                                                    Optional configuration for authentication strategies. +Used for secure connections to external services and MCP servers.

                                                                                                                                    +

                                                                                                                                    Type declaration

                                                                                                                                    • Optionalenabled?: boolean

                                                                                                                                      Whether to enable authentication manager. Defaults to false.

                                                                                                                                      +
                                                                                                                                    • Optionalstrategies?: { id: string; strategy: any }[]

                                                                                                                                      Pre-configured authentication strategies to register at startup.

                                                                                                                                      +
                                                                                                                                    logger?: { level?: LogLevel }

                                                                                                                                    Optional configuration for the framework's logger.

                                                                                                                                    +

                                                                                                                                    Type declaration

                                                                                                                                    • Optionallevel?: LogLevel

                                                                                                                                      Minimum log level to output. Defaults to 'info'.

                                                                                                                                      +
                                                                                                                                    mcpConfig?: McpManagerConfig

                                                                                                                                    Optional configuration for MCP (Model Context Protocol) manager. +Enables connection to external MCP servers for dynamic tool loading.

                                                                                                                                    +
                                                                                                                                    persona?: AgentPersona

                                                                                                                                    Optional: Defines the default identity and high-level guidance for the agent. +This can be overridden at the thread or call level.

                                                                                                                                    +

                                                                                                                                    Configuration for the ProviderManager, defining available LLM provider adapters.

                                                                                                                                    +
                                                                                                                                    stateSavingStrategy?: StateSavingStrategy

                                                                                                                                    Defines the strategy for saving AgentState. Defaults to 'explicit'.

                                                                                                                                    +
                                                                                                                                      +
                                                                                                                                    • 'explicit': AgentState is only saved when StateManager.setAgentState() is explicitly called by the agent. +StateManager.saveStateIfModified() will be a no-op for AgentState persistence.
                                                                                                                                    • +
                                                                                                                                    • 'implicit': AgentState is loaded by StateManager.loadThreadContext(). If modified by the agent, +StateManager.saveStateIfModified() will attempt to automatically persist these changes. +StateManager.setAgentState() will still work for explicit saves in this mode.
                                                                                                                                    • +
                                                                                                                                    +
                                                                                                                                    storage:
                                                                                                                                        | StorageAdapter
                                                                                                                                        | {
                                                                                                                                            dbName?: string;
                                                                                                                                            objectStores?: any[];
                                                                                                                                            type: "memory"
                                                                                                                                            | "indexedDB";
                                                                                                                                            version?: number;
                                                                                                                                        }

                                                                                                                                    Configuration for the storage adapter. +Can be a pre-configured StorageAdapter instance, +or an object specifying the type and options for a built-in adapter.

                                                                                                                                    +
                                                                                                                                    { type: 'indexedDB', dbName: 'MyArtDB' }
                                                                                                                                    +
                                                                                                                                    + +
                                                                                                                                    tools?: IToolExecutor[]

                                                                                                                                    An optional array of tool executor instances to register at initialization.

                                                                                                                                    +
                                                                                                                                    diff --git a/docs/components/interfaces/ArtStandardMessage.html b/docs/components/interfaces/ArtStandardMessage.html new file mode 100644 index 0000000..ef31d89 --- /dev/null +++ b/docs/components/interfaces/ArtStandardMessage.html @@ -0,0 +1,30 @@ +ArtStandardMessage | ART Framework API Docs
                                                                                                                                    ART Framework API Docs
                                                                                                                                      Preparing search index...

                                                                                                                                      Interface ArtStandardMessage

                                                                                                                                      Represents a single message in the standardized, provider-agnostic ArtStandardPrompt format.

                                                                                                                                      +

                                                                                                                                      This structure aims to capture common message elements used by various LLM APIs.

                                                                                                                                      +

                                                                                                                                      ArtStandardMessage

                                                                                                                                      +
                                                                                                                                      interface ArtStandardMessage {
                                                                                                                                          content: null | string | object;
                                                                                                                                          name?: string;
                                                                                                                                          role: ArtStandardMessageRole;
                                                                                                                                          tool_call_id?: string;
                                                                                                                                          tool_calls?: {
                                                                                                                                              function: { arguments: string; name: string };
                                                                                                                                              id: string;
                                                                                                                                              type: "function";
                                                                                                                                          }[];
                                                                                                                                      }
                                                                                                                                      Index

                                                                                                                                      Properties

                                                                                                                                      content: null | string | object

                                                                                                                                      The primary content of the message. The type and interpretation depend on the role:

                                                                                                                                      +
                                                                                                                                        +
                                                                                                                                      • system: string (The system instruction).
                                                                                                                                      • +
                                                                                                                                      • user: string (The user's text input).
                                                                                                                                      • +
                                                                                                                                      • assistant: string | null (The AI's text response, or null/empty if only making tool_calls).
                                                                                                                                      • +
                                                                                                                                      • tool_request: object | null (Structured representation of the tool call, often implicitly handled via assistant message's tool_calls).
                                                                                                                                      • +
                                                                                                                                      • tool_result: string (Stringified JSON output or error message from the tool execution).
                                                                                                                                      • +
                                                                                                                                      +
                                                                                                                                      name?: string

                                                                                                                                      Optional name associated with the message. Primarily used for tool_result role to specify the name of the tool that was executed.

                                                                                                                                      +

                                                                                                                                      The role indicating the source or type of the message.

                                                                                                                                      +
                                                                                                                                      tool_call_id?: string

                                                                                                                                      Optional identifier linking a 'tool_result' message back to the specific 'tool_calls' entry +in the preceding 'assistant' message that requested it. +Required for 'tool_result' role.

                                                                                                                                      +
                                                                                                                                      tool_calls?: {
                                                                                                                                          function: { arguments: string; name: string };
                                                                                                                                          id: string;
                                                                                                                                          type: "function";
                                                                                                                                      }[]

                                                                                                                                      Optional array of tool calls requested by the assistant.

                                                                                                                                      +

                                                                                                                                      Type declaration

                                                                                                                                      • function: { arguments: string; name: string }

                                                                                                                                        Details of the function to be called.

                                                                                                                                        +
                                                                                                                                        • arguments: string

                                                                                                                                          A stringified JSON object representing the arguments for the function.

                                                                                                                                          +
                                                                                                                                        • name: string

                                                                                                                                          The name of the function/tool to call.

                                                                                                                                          +
                                                                                                                                      • id: string

                                                                                                                                        A unique identifier for this specific tool call request.

                                                                                                                                        +
                                                                                                                                      • type: "function"

                                                                                                                                        The type of the tool call, typically 'function'.

                                                                                                                                        +

                                                                                                                                      Only relevant for 'assistant' role messages that trigger tool usage. +Structure mirrors common provider formats (e.g., OpenAI).

                                                                                                                                      +
                                                                                                                                      diff --git a/docs/components/interfaces/AvailableProviderEntry.html b/docs/components/interfaces/AvailableProviderEntry.html new file mode 100644 index 0000000..dc0ad0f --- /dev/null +++ b/docs/components/interfaces/AvailableProviderEntry.html @@ -0,0 +1,11 @@ +AvailableProviderEntry | ART Framework API Docs
                                                                                                                                      ART Framework API Docs
                                                                                                                                        Preparing search index...

                                                                                                                                        Interface AvailableProviderEntry

                                                                                                                                        Entry defining an available provider adapter.

                                                                                                                                        +

                                                                                                                                        AvailableProviderEntry

                                                                                                                                        +
                                                                                                                                        interface AvailableProviderEntry {
                                                                                                                                            adapter: new (options: any) => ProviderAdapter;
                                                                                                                                            baseOptions?: any;
                                                                                                                                            isLocal?: boolean;
                                                                                                                                            name: string;
                                                                                                                                        }
                                                                                                                                        Index

                                                                                                                                        Properties

                                                                                                                                        adapter: new (options: any) => ProviderAdapter

                                                                                                                                        The adapter class.

                                                                                                                                        +
                                                                                                                                        baseOptions?: any

                                                                                                                                        Optional base config (rarely needed if options are per-call).

                                                                                                                                        +
                                                                                                                                        isLocal?: boolean

                                                                                                                                        Default: false. Determines singleton vs. pooling behavior.

                                                                                                                                        +
                                                                                                                                        name: string

                                                                                                                                        Unique key, e.g., 'openai', 'anthropic', 'ollama_local'.

                                                                                                                                        +
                                                                                                                                        diff --git a/docs/components/interfaces/CallOptions.html b/docs/components/interfaces/CallOptions.html new file mode 100644 index 0000000..a1222c3 --- /dev/null +++ b/docs/components/interfaces/CallOptions.html @@ -0,0 +1,21 @@ +CallOptions | ART Framework API Docs
                                                                                                                                        ART Framework API Docs
                                                                                                                                          Preparing search index...

                                                                                                                                          Interface CallOptions

                                                                                                                                          Options for configuring an LLM call, including streaming and context information.

                                                                                                                                          +

                                                                                                                                          CallOptions

                                                                                                                                          +
                                                                                                                                          interface CallOptions {
                                                                                                                                              callContext?: string;
                                                                                                                                              providerConfig: RuntimeProviderConfig;
                                                                                                                                              sessionId?: string;
                                                                                                                                              stream?: boolean;
                                                                                                                                              threadId: string;
                                                                                                                                              traceId?: string;
                                                                                                                                              userId?: string;
                                                                                                                                              [key: string]: any;
                                                                                                                                          }

                                                                                                                                          Indexable

                                                                                                                                          • [key: string]: any

                                                                                                                                            Additional key-value pairs representing provider-specific parameters (e.g., temperature, max_tokens, top_p). These often override defaults set in ThreadConfig.

                                                                                                                                            +
                                                                                                                                          Index

                                                                                                                                          Properties

                                                                                                                                          callContext?: string

                                                                                                                                          Provides context for the LLM call, allowing adapters to differentiate +between agent-level thoughts and final synthesis calls for token typing. +Agent Core MUST provide this.

                                                                                                                                          +
                                                                                                                                          providerConfig: RuntimeProviderConfig

                                                                                                                                          Carries the specific target provider and configuration for this call.

                                                                                                                                          +
                                                                                                                                          sessionId?: string

                                                                                                                                          Optional session ID.

                                                                                                                                          +
                                                                                                                                          stream?: boolean

                                                                                                                                          Request a streaming response from the LLM provider. +Adapters MUST check this flag.

                                                                                                                                          +
                                                                                                                                          threadId: string

                                                                                                                                          The mandatory thread ID, used by the ReasoningEngine to fetch thread-specific configuration (e.g., model, params) via StateManager.

                                                                                                                                          +
                                                                                                                                          traceId?: string

                                                                                                                                          Optional trace ID for correlation.

                                                                                                                                          +
                                                                                                                                          userId?: string

                                                                                                                                          Optional user ID.

                                                                                                                                          +
                                                                                                                                          diff --git a/docs/components/interfaces/ConversationManager.html b/docs/components/interfaces/ConversationManager.html new file mode 100644 index 0000000..3611b8a --- /dev/null +++ b/docs/components/interfaces/ConversationManager.html @@ -0,0 +1,13 @@ +ConversationManager | ART Framework API Docs
                                                                                                                                          ART Framework API Docs
                                                                                                                                            Preparing search index...

                                                                                                                                            Interface ConversationManager

                                                                                                                                            Interface for managing conversation history.

                                                                                                                                            +
                                                                                                                                            interface ConversationManager {
                                                                                                                                                addMessages(
                                                                                                                                                    threadId: string,
                                                                                                                                                    messages: ConversationMessage[],
                                                                                                                                                ): Promise<void>;
                                                                                                                                                getMessages(
                                                                                                                                                    threadId: string,
                                                                                                                                                    options?: MessageOptions,
                                                                                                                                                ): Promise<ConversationMessage[]>;
                                                                                                                                            }
                                                                                                                                            Index

                                                                                                                                            Methods

                                                                                                                                            • Appends one or more ConversationMessage objects to the history of a specific thread. +Typically called at the end of an execution cycle to save the user query and the final AI response.

                                                                                                                                              +

                                                                                                                                              Parameters

                                                                                                                                              • threadId: string

                                                                                                                                                The ID of the thread to add messages to.

                                                                                                                                                +
                                                                                                                                              • messages: ConversationMessage[]

                                                                                                                                                An array containing the ConversationMessage objects to add.

                                                                                                                                                +

                                                                                                                                              Returns Promise<void>

                                                                                                                                              A promise that resolves when the messages have been successfully added to storage.

                                                                                                                                              +
                                                                                                                                            • Retrieves messages from a specific thread's history, usually in reverse chronological order.

                                                                                                                                              +

                                                                                                                                              Parameters

                                                                                                                                              • threadId: string

                                                                                                                                                The ID of the thread whose history is needed.

                                                                                                                                                +
                                                                                                                                              • Optionaloptions: MessageOptions

                                                                                                                                                Optional parameters to control retrieval, such as limit (max number of messages) or beforeTimestamp (for pagination). See MessageOptions type.

                                                                                                                                                +

                                                                                                                                              Returns Promise<ConversationMessage[]>

                                                                                                                                              A promise resolving to an array of ConversationMessage objects, ordered according to the implementation (typically newest first if not specified otherwise).

                                                                                                                                              +
                                                                                                                                            diff --git a/docs/components/interfaces/ConversationMessage.html b/docs/components/interfaces/ConversationMessage.html new file mode 100644 index 0000000..528a1bd --- /dev/null +++ b/docs/components/interfaces/ConversationMessage.html @@ -0,0 +1,15 @@ +ConversationMessage | ART Framework API Docs
                                                                                                                                            ART Framework API Docs
                                                                                                                                              Preparing search index...

                                                                                                                                              Interface ConversationMessage

                                                                                                                                              Represents a single message within a conversation thread.

                                                                                                                                              +

                                                                                                                                              ConversationMessage

                                                                                                                                              +
                                                                                                                                              interface ConversationMessage {
                                                                                                                                                  content: string;
                                                                                                                                                  messageId: string;
                                                                                                                                                  metadata?: Record<string, any>;
                                                                                                                                                  role: MessageRole;
                                                                                                                                                  threadId: string;
                                                                                                                                                  timestamp: number;
                                                                                                                                              }
                                                                                                                                              Index

                                                                                                                                              Properties

                                                                                                                                              content: string

                                                                                                                                              The textual content of the message.

                                                                                                                                              +
                                                                                                                                              messageId: string

                                                                                                                                              A unique identifier for this specific message.

                                                                                                                                              +
                                                                                                                                              metadata?: Record<string, any>

                                                                                                                                              Optional metadata associated with the message (e.g., related observation IDs, tool call info, UI state).

                                                                                                                                              +

                                                                                                                                              The role of the sender (User, AI, System, or Tool).

                                                                                                                                              +
                                                                                                                                              threadId: string

                                                                                                                                              The identifier of the conversation thread this message belongs to.

                                                                                                                                              +
                                                                                                                                              timestamp: number

                                                                                                                                              A Unix timestamp (in milliseconds) indicating when the message was created.

                                                                                                                                              +
                                                                                                                                              diff --git a/docs/components/interfaces/CreateA2ATaskRequest.html b/docs/components/interfaces/CreateA2ATaskRequest.html new file mode 100644 index 0000000..361da7f --- /dev/null +++ b/docs/components/interfaces/CreateA2ATaskRequest.html @@ -0,0 +1,27 @@ +CreateA2ATaskRequest | ART Framework API Docs
                                                                                                                                              ART Framework API Docs
                                                                                                                                                Preparing search index...

                                                                                                                                                Interface CreateA2ATaskRequest

                                                                                                                                                Represents a request to create a new A2A task.

                                                                                                                                                +

                                                                                                                                                CreateA2ATaskRequest

                                                                                                                                                +
                                                                                                                                                interface CreateA2ATaskRequest {
                                                                                                                                                    callbackUrl?: string;
                                                                                                                                                    dependencies?: string[];
                                                                                                                                                    input: any;
                                                                                                                                                    instructions?: string;
                                                                                                                                                    maxRetries?: number;
                                                                                                                                                    parameters?: Record<string, any>;
                                                                                                                                                    preferredTargetAgent?: A2AAgentInfo;
                                                                                                                                                    priority?: A2ATaskPriority;
                                                                                                                                                    sourceAgent: A2AAgentInfo;
                                                                                                                                                    tags?: string[];
                                                                                                                                                    taskType: string;
                                                                                                                                                    timeoutMs?: number;
                                                                                                                                                }
                                                                                                                                                Index

                                                                                                                                                Properties

                                                                                                                                                callbackUrl?: string

                                                                                                                                                Callback URL for notifications.

                                                                                                                                                +
                                                                                                                                                dependencies?: string[]

                                                                                                                                                Task dependencies.

                                                                                                                                                +
                                                                                                                                                input: any

                                                                                                                                                Input data for the task.

                                                                                                                                                +
                                                                                                                                                instructions?: string

                                                                                                                                                Instructions for task execution.

                                                                                                                                                +
                                                                                                                                                maxRetries?: number

                                                                                                                                                Maximum retry attempts.

                                                                                                                                                +
                                                                                                                                                parameters?: Record<string, any>

                                                                                                                                                Task parameters.

                                                                                                                                                +
                                                                                                                                                preferredTargetAgent?: A2AAgentInfo

                                                                                                                                                Preferred target agent (if any).

                                                                                                                                                +
                                                                                                                                                priority?: A2ATaskPriority

                                                                                                                                                Task priority.

                                                                                                                                                +
                                                                                                                                                sourceAgent: A2AAgentInfo

                                                                                                                                                Source agent information.

                                                                                                                                                +
                                                                                                                                                tags?: string[]

                                                                                                                                                Task tags.

                                                                                                                                                +
                                                                                                                                                taskType: string

                                                                                                                                                The type of task to be executed.

                                                                                                                                                +
                                                                                                                                                timeoutMs?: number

                                                                                                                                                Task timeout in milliseconds.

                                                                                                                                                +
                                                                                                                                                diff --git a/docs/components/interfaces/DeepSeekAdapterOptions.html b/docs/components/interfaces/DeepSeekAdapterOptions.html new file mode 100644 index 0000000..4f4b18d --- /dev/null +++ b/docs/components/interfaces/DeepSeekAdapterOptions.html @@ -0,0 +1,8 @@ +DeepSeekAdapterOptions | ART Framework API Docs
                                                                                                                                                ART Framework API Docs
                                                                                                                                                  Preparing search index...

                                                                                                                                                  Interface DeepSeekAdapterOptions

                                                                                                                                                  Configuration options required for the DeepSeekAdapter.

                                                                                                                                                  +
                                                                                                                                                  interface DeepSeekAdapterOptions {
                                                                                                                                                      apiBaseUrl?: string;
                                                                                                                                                      apiKey: string;
                                                                                                                                                      model?: string;
                                                                                                                                                  }
                                                                                                                                                  Index

                                                                                                                                                  Properties

                                                                                                                                                  Properties

                                                                                                                                                  apiBaseUrl?: string

                                                                                                                                                  Optional: Override the base URL for the DeepSeek API. Defaults to 'https://api.deepseek.com/v1'.

                                                                                                                                                  +
                                                                                                                                                  apiKey: string

                                                                                                                                                  Your DeepSeek API key. Handle securely.

                                                                                                                                                  +
                                                                                                                                                  model?: string

                                                                                                                                                  The default DeepSeek model ID to use (e.g., 'deepseek-chat', 'deepseek-coder'). Defaults to 'deepseek-chat' if not provided.

                                                                                                                                                  +
                                                                                                                                                  diff --git a/docs/components/interfaces/ExecutionContext.html b/docs/components/interfaces/ExecutionContext.html new file mode 100644 index 0000000..192dc9b --- /dev/null +++ b/docs/components/interfaces/ExecutionContext.html @@ -0,0 +1,9 @@ +ExecutionContext | ART Framework API Docs
                                                                                                                                                  ART Framework API Docs
                                                                                                                                                    Preparing search index...

                                                                                                                                                    Interface ExecutionContext

                                                                                                                                                    Context provided to a tool during its execution.

                                                                                                                                                    +

                                                                                                                                                    ExecutionContext

                                                                                                                                                    +
                                                                                                                                                    interface ExecutionContext {
                                                                                                                                                        threadId: string;
                                                                                                                                                        traceId?: string;
                                                                                                                                                        userId?: string;
                                                                                                                                                    }
                                                                                                                                                    Index

                                                                                                                                                    Properties

                                                                                                                                                    Properties

                                                                                                                                                    threadId: string

                                                                                                                                                    The ID of the thread in which the tool is being executed.

                                                                                                                                                    +
                                                                                                                                                    traceId?: string

                                                                                                                                                    The trace ID for this execution cycle, if available.

                                                                                                                                                    +
                                                                                                                                                    userId?: string

                                                                                                                                                    The user ID associated with the execution, if available.

                                                                                                                                                    +
                                                                                                                                                    diff --git a/docs/components/interfaces/ExecutionMetadata.html b/docs/components/interfaces/ExecutionMetadata.html new file mode 100644 index 0000000..dd73d2f --- /dev/null +++ b/docs/components/interfaces/ExecutionMetadata.html @@ -0,0 +1,23 @@ +ExecutionMetadata | ART Framework API Docs
                                                                                                                                                    ART Framework API Docs
                                                                                                                                                      Preparing search index...

                                                                                                                                                      Interface ExecutionMetadata

                                                                                                                                                      Metadata summarizing an agent execution cycle, including performance metrics and outcomes.

                                                                                                                                                      +

                                                                                                                                                      ExecutionMetadata

                                                                                                                                                      +
                                                                                                                                                      interface ExecutionMetadata {
                                                                                                                                                          error?: string;
                                                                                                                                                          llmCalls: number;
                                                                                                                                                          llmCost?: number;
                                                                                                                                                          llmMetadata?: LLMMetadata;
                                                                                                                                                          status: "error" | "success" | "partial";
                                                                                                                                                          threadId: string;
                                                                                                                                                          toolCalls: number;
                                                                                                                                                          totalDurationMs: number;
                                                                                                                                                          traceId?: string;
                                                                                                                                                          userId?: string;
                                                                                                                                                      }
                                                                                                                                                      Index

                                                                                                                                                      Properties

                                                                                                                                                      error?: string

                                                                                                                                                      A top-level error message if the overall status is 'error' or 'partial'.

                                                                                                                                                      +
                                                                                                                                                      llmCalls: number

                                                                                                                                                      The number of calls made to the ReasoningEngine.

                                                                                                                                                      +
                                                                                                                                                      llmCost?: number

                                                                                                                                                      An optional estimated cost for the LLM calls made during this execution.

                                                                                                                                                      +
                                                                                                                                                      llmMetadata?: LLMMetadata

                                                                                                                                                      Aggregated metadata from LLM calls made during the execution.

                                                                                                                                                      +
                                                                                                                                                      status: "error" | "success" | "partial"

                                                                                                                                                      The overall status of the execution ('success', 'error', or 'partial' if some steps failed but a response was generated).

                                                                                                                                                      +
                                                                                                                                                      threadId: string

                                                                                                                                                      The thread ID associated with this execution cycle.

                                                                                                                                                      +
                                                                                                                                                      toolCalls: number

                                                                                                                                                      The number of tool execution attempts made by the ToolSystem.

                                                                                                                                                      +
                                                                                                                                                      totalDurationMs: number

                                                                                                                                                      The total duration of the agent.process() call in milliseconds.

                                                                                                                                                      +
                                                                                                                                                      traceId?: string

                                                                                                                                                      The trace ID used during this execution, if provided.

                                                                                                                                                      +
                                                                                                                                                      userId?: string

                                                                                                                                                      The user ID associated with the execution, if provided.

                                                                                                                                                      +
                                                                                                                                                      diff --git a/docs/components/interfaces/FilterOptions.html b/docs/components/interfaces/FilterOptions.html new file mode 100644 index 0000000..5ad73e0 --- /dev/null +++ b/docs/components/interfaces/FilterOptions.html @@ -0,0 +1,12 @@ +FilterOptions | ART Framework API Docs
                                                                                                                                                      ART Framework API Docs
                                                                                                                                                        Preparing search index...

                                                                                                                                                        Interface FilterOptions

                                                                                                                                                        Options for filtering data retrieved from storage. +Structure depends heavily on the underlying adapter's capabilities.

                                                                                                                                                        +

                                                                                                                                                        FilterOptions

                                                                                                                                                        +
                                                                                                                                                        interface FilterOptions {
                                                                                                                                                            filter?: Record<string, any>;
                                                                                                                                                            limit?: number;
                                                                                                                                                            skip?: number;
                                                                                                                                                            sort?: Record<string, "asc" | "desc">;
                                                                                                                                                        }
                                                                                                                                                        Index

                                                                                                                                                        Properties

                                                                                                                                                        Properties

                                                                                                                                                        filter?: Record<string, any>

                                                                                                                                                        An object defining filter criteria (e.g., { threadId: 'abc', type: 'TOOL_EXECUTION' }). Structure may depend on adapter capabilities.

                                                                                                                                                        +
                                                                                                                                                        limit?: number

                                                                                                                                                        The maximum number of records to return.

                                                                                                                                                        +
                                                                                                                                                        skip?: number

                                                                                                                                                        The number of records to skip (for pagination).

                                                                                                                                                        +
                                                                                                                                                        sort?: Record<string, "asc" | "desc">

                                                                                                                                                        An object defining sorting criteria (e.g., { timestamp: 'desc' }).

                                                                                                                                                        +
                                                                                                                                                        diff --git a/docs/components/interfaces/GeminiAdapterOptions.html b/docs/components/interfaces/GeminiAdapterOptions.html new file mode 100644 index 0000000..3009758 --- /dev/null +++ b/docs/components/interfaces/GeminiAdapterOptions.html @@ -0,0 +1,10 @@ +GeminiAdapterOptions | ART Framework API Docs
                                                                                                                                                        ART Framework API Docs
                                                                                                                                                          Preparing search index...

                                                                                                                                                          Interface GeminiAdapterOptions

                                                                                                                                                          Configuration options required for the GeminiAdapter.

                                                                                                                                                          +
                                                                                                                                                          interface GeminiAdapterOptions {
                                                                                                                                                              apiBaseUrl?: string;
                                                                                                                                                              apiKey: string;
                                                                                                                                                              apiVersion?: string;
                                                                                                                                                              model?: string;
                                                                                                                                                          }
                                                                                                                                                          Index

                                                                                                                                                          Properties

                                                                                                                                                          apiBaseUrl?: string

                                                                                                                                                          Optional: Override the base URL for the Google Generative AI API.

                                                                                                                                                          +
                                                                                                                                                          apiKey: string

                                                                                                                                                          Your Google AI API key (e.g., from Google AI Studio). Handle securely.

                                                                                                                                                          +
                                                                                                                                                          apiVersion?: string

                                                                                                                                                          Optional: Specify the API version to use (e.g., 'v1beta'). Defaults to 'v1beta'.

                                                                                                                                                          +
                                                                                                                                                          model?: string

                                                                                                                                                          The default Gemini model ID to use (e.g., 'gemini-1.5-flash-latest', 'gemini-pro'). Defaults to 'gemini-1.5-flash-latest' if not provided.

                                                                                                                                                          +
                                                                                                                                                          diff --git a/docs/components/interfaces/IA2ATaskRepository.html b/docs/components/interfaces/IA2ATaskRepository.html new file mode 100644 index 0000000..4ce30db --- /dev/null +++ b/docs/components/interfaces/IA2ATaskRepository.html @@ -0,0 +1,38 @@ +IA2ATaskRepository | ART Framework API Docs
                                                                                                                                                          ART Framework API Docs
                                                                                                                                                            Preparing search index...

                                                                                                                                                            Interface IA2ATaskRepository

                                                                                                                                                            Interface for managing A2A (Agent-to-Agent) task persistence and retrieval.

                                                                                                                                                            +
                                                                                                                                                            interface IA2ATaskRepository {
                                                                                                                                                                createTask(task: A2ATask): Promise<void>;
                                                                                                                                                                deleteTask(taskId: string): Promise<void>;
                                                                                                                                                                getTask(taskId: string): Promise<null | A2ATask>;
                                                                                                                                                                getTasksByAgent(
                                                                                                                                                                    agentId: string,
                                                                                                                                                                    filter?: {
                                                                                                                                                                        priority?: A2ATaskPriority;
                                                                                                                                                                        status?: A2ATaskStatus | A2ATaskStatus[];
                                                                                                                                                                    },
                                                                                                                                                                ): Promise<A2ATask[]>;
                                                                                                                                                                getTasksByStatus(
                                                                                                                                                                    status: A2ATaskStatus | A2ATaskStatus[],
                                                                                                                                                                    options?: { limit?: number; offset?: number },
                                                                                                                                                                ): Promise<A2ATask[]>;
                                                                                                                                                                getTasksByThread(
                                                                                                                                                                    threadId: string,
                                                                                                                                                                    filter?: {
                                                                                                                                                                        assignedAgentId?: string;
                                                                                                                                                                        priority?: A2ATaskPriority;
                                                                                                                                                                        status?: A2ATaskStatus | A2ATaskStatus[];
                                                                                                                                                                    },
                                                                                                                                                                ): Promise<A2ATask[]>;
                                                                                                                                                                updateTask(taskId: string, updates: Partial<A2ATask>): Promise<void>;
                                                                                                                                                            }
                                                                                                                                                            Index

                                                                                                                                                            Methods

                                                                                                                                                            • Creates a new A2A task in the repository.

                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              • task: A2ATask

                                                                                                                                                                The A2ATask object to create.

                                                                                                                                                                +

                                                                                                                                                              Returns Promise<void>

                                                                                                                                                              A promise that resolves when the task is successfully stored.

                                                                                                                                                              +

                                                                                                                                                              If the task cannot be created (e.g., duplicate taskId, validation errors).

                                                                                                                                                              +
                                                                                                                                                            • Removes an A2A task from the repository.

                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              • taskId: string

                                                                                                                                                                The unique identifier of the task to delete.

                                                                                                                                                                +

                                                                                                                                                              Returns Promise<void>

                                                                                                                                                              A promise that resolves when the task is successfully deleted.

                                                                                                                                                              +

                                                                                                                                                              If the task is not found or cannot be deleted.

                                                                                                                                                              +
                                                                                                                                                            • Retrieves an A2A task by its unique identifier.

                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              • taskId: string

                                                                                                                                                                The unique identifier of the task.

                                                                                                                                                                +

                                                                                                                                                              Returns Promise<null | A2ATask>

                                                                                                                                                              A promise resolving to the A2ATask object if found, or null if not found.

                                                                                                                                                              +

                                                                                                                                                              If an error occurs during retrieval.

                                                                                                                                                              +
                                                                                                                                                            • Retrieves tasks based on their current status.

                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              • status: A2ATaskStatus | A2ATaskStatus[]

                                                                                                                                                                The task status(es) to filter by.

                                                                                                                                                                +
                                                                                                                                                              • Optionaloptions: { limit?: number; offset?: number }

                                                                                                                                                                Optional query parameters like limit and pagination.

                                                                                                                                                                +

                                                                                                                                                              Returns Promise<A2ATask[]>

                                                                                                                                                              A promise resolving to an array of A2ATask objects with the specified status.

                                                                                                                                                              +
                                                                                                                                                            • Retrieves tasks associated with a specific thread.

                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              • threadId: string

                                                                                                                                                                The thread identifier to filter tasks.

                                                                                                                                                                +
                                                                                                                                                              • Optionalfilter: {
                                                                                                                                                                    assignedAgentId?: string;
                                                                                                                                                                    priority?: A2ATaskPriority;
                                                                                                                                                                    status?: A2ATaskStatus | A2ATaskStatus[];
                                                                                                                                                                }

                                                                                                                                                                Optional filter criteria for task status, priority, or assigned agent.

                                                                                                                                                                +

                                                                                                                                                              Returns Promise<A2ATask[]>

                                                                                                                                                              A promise resolving to an array of A2ATask objects matching the criteria.

                                                                                                                                                              +
                                                                                                                                                            • Updates an existing A2A task with new information.

                                                                                                                                                              +

                                                                                                                                                              Parameters

                                                                                                                                                              • taskId: string

                                                                                                                                                                The unique identifier of the task to update.

                                                                                                                                                                +
                                                                                                                                                              • updates: Partial<A2ATask>

                                                                                                                                                                Partial A2ATask object containing the fields to update.

                                                                                                                                                                +

                                                                                                                                                              Returns Promise<void>

                                                                                                                                                              A promise that resolves when the task is successfully updated.

                                                                                                                                                              +

                                                                                                                                                              If the task is not found or cannot be updated.

                                                                                                                                                              +
                                                                                                                                                            diff --git a/docs/components/interfaces/IAgentCore.html b/docs/components/interfaces/IAgentCore.html new file mode 100644 index 0000000..996ccbf --- /dev/null +++ b/docs/components/interfaces/IAgentCore.html @@ -0,0 +1,8 @@ +IAgentCore | ART Framework API Docs
                                                                                                                                                            ART Framework API Docs
                                                                                                                                                              Preparing search index...

                                                                                                                                                              Interface IAgentCore

                                                                                                                                                              Interface for the central agent orchestrator.

                                                                                                                                                              +
                                                                                                                                                              interface IAgentCore {
                                                                                                                                                                  process(props: AgentProps): Promise<AgentFinalResponse>;
                                                                                                                                                              }

                                                                                                                                                              Implemented by

                                                                                                                                                              Index

                                                                                                                                                              Methods

                                                                                                                                                              Methods

                                                                                                                                                              • Processes a user query through the configured agent reasoning pattern (e.g., PES). +Orchestrates interactions between various ART subsystems.

                                                                                                                                                                +

                                                                                                                                                                Parameters

                                                                                                                                                                • props: AgentProps

                                                                                                                                                                  The input properties for the agent execution, including the query, thread ID, and injected dependencies.

                                                                                                                                                                  +

                                                                                                                                                                Returns Promise<AgentFinalResponse>

                                                                                                                                                                A promise that resolves with the final agent response and execution metadata.

                                                                                                                                                                +

                                                                                                                                                                If a critical error occurs during orchestration that prevents completion.

                                                                                                                                                                +
                                                                                                                                                              diff --git a/docs/components/interfaces/IAuthStrategy.html b/docs/components/interfaces/IAuthStrategy.html new file mode 100644 index 0000000..8d6187a --- /dev/null +++ b/docs/components/interfaces/IAuthStrategy.html @@ -0,0 +1,16 @@ +IAuthStrategy | ART Framework API Docs
                                                                                                                                                              ART Framework API Docs
                                                                                                                                                                Preparing search index...

                                                                                                                                                                Interface IAuthStrategy

                                                                                                                                                                Interface for an authentication strategy that can provide authorization headers. +This enables pluggable security for remote service connections (MCP servers, A2A agents, etc.)

                                                                                                                                                                +
                                                                                                                                                                interface IAuthStrategy {
                                                                                                                                                                    getAuthHeaders(): Promise<Record<string, string>>;
                                                                                                                                                                    handleRedirect(): Promise<void>;
                                                                                                                                                                    isAuthenticated(): Promise<boolean>;
                                                                                                                                                                    login(): Promise<void>;
                                                                                                                                                                    logout(): void;
                                                                                                                                                                }

                                                                                                                                                                Implemented by

                                                                                                                                                                Index

                                                                                                                                                                Methods

                                                                                                                                                                • Asynchronously retrieves the authentication headers. +This might involve checking a cached token, refreshing it if expired, and then returning it.

                                                                                                                                                                  +

                                                                                                                                                                  Returns Promise<Record<string, string>>

                                                                                                                                                                  A promise that resolves to a record of header keys and values.

                                                                                                                                                                  +

                                                                                                                                                                  If authentication fails or cannot be obtained.

                                                                                                                                                                  +
                                                                                                                                                                • Optional: Handles the redirect from the authentication server.

                                                                                                                                                                  +

                                                                                                                                                                  Returns Promise<void>

                                                                                                                                                                • Optional: Checks if the user is authenticated.

                                                                                                                                                                  +

                                                                                                                                                                  Returns Promise<boolean>

                                                                                                                                                                • Optional: Initiates the login flow for the strategy.

                                                                                                                                                                  +

                                                                                                                                                                  Returns Promise<void>

                                                                                                                                                                diff --git a/docs/components/interfaces/IConversationRepository.html b/docs/components/interfaces/IConversationRepository.html new file mode 100644 index 0000000..36605c6 --- /dev/null +++ b/docs/components/interfaces/IConversationRepository.html @@ -0,0 +1,4 @@ +IConversationRepository | ART Framework API Docs
                                                                                                                                                                ART Framework API Docs
                                                                                                                                                                  Preparing search index...

                                                                                                                                                                  Interface IConversationRepository

                                                                                                                                                                  Repository for managing ConversationMessages.

                                                                                                                                                                  +
                                                                                                                                                                  interface IConversationRepository {
                                                                                                                                                                      addMessages(
                                                                                                                                                                          threadId: string,
                                                                                                                                                                          messages: ConversationMessage[],
                                                                                                                                                                      ): Promise<void>;
                                                                                                                                                                      getMessages(
                                                                                                                                                                          threadId: string,
                                                                                                                                                                          options?: MessageOptions,
                                                                                                                                                                      ): Promise<ConversationMessage[]>;
                                                                                                                                                                  }
                                                                                                                                                                  Index

                                                                                                                                                                  Methods

                                                                                                                                                                  diff --git a/docs/components/interfaces/IObservationRepository.html b/docs/components/interfaces/IObservationRepository.html new file mode 100644 index 0000000..e8ebfac --- /dev/null +++ b/docs/components/interfaces/IObservationRepository.html @@ -0,0 +1,4 @@ +IObservationRepository | ART Framework API Docs
                                                                                                                                                                  ART Framework API Docs
                                                                                                                                                                    Preparing search index...

                                                                                                                                                                    Interface IObservationRepository

                                                                                                                                                                    Repository for managing Observations.

                                                                                                                                                                    +
                                                                                                                                                                    interface IObservationRepository {
                                                                                                                                                                        addObservation(observation: Observation): Promise<void>;
                                                                                                                                                                        getObservations(
                                                                                                                                                                            threadId: string,
                                                                                                                                                                            filter?: ObservationFilter,
                                                                                                                                                                        ): Promise<Observation[]>;
                                                                                                                                                                    }
                                                                                                                                                                    Index

                                                                                                                                                                    Methods

                                                                                                                                                                    diff --git a/docs/components/interfaces/IProviderManager.html b/docs/components/interfaces/IProviderManager.html new file mode 100644 index 0000000..f858a89 --- /dev/null +++ b/docs/components/interfaces/IProviderManager.html @@ -0,0 +1,9 @@ +IProviderManager | ART Framework API Docs
                                                                                                                                                                    ART Framework API Docs
                                                                                                                                                                      Preparing search index...

                                                                                                                                                                      Interface IProviderManager

                                                                                                                                                                      Interface for the ProviderManager.

                                                                                                                                                                      +

                                                                                                                                                                      IProviderManager

                                                                                                                                                                      +
                                                                                                                                                                      interface IProviderManager {
                                                                                                                                                                          getAdapter(
                                                                                                                                                                              config: RuntimeProviderConfig,
                                                                                                                                                                          ): Promise<ManagedAdapterAccessor>;
                                                                                                                                                                          getAvailableProviders(): string[];
                                                                                                                                                                      }

                                                                                                                                                                      Implemented by

                                                                                                                                                                      Index

                                                                                                                                                                      Methods

                                                                                                                                                                      • Returns identifiers for all registered potential providers.

                                                                                                                                                                        +

                                                                                                                                                                        Returns string[]

                                                                                                                                                                      diff --git a/docs/components/interfaces/IStateRepository.html b/docs/components/interfaces/IStateRepository.html new file mode 100644 index 0000000..d9f3e50 --- /dev/null +++ b/docs/components/interfaces/IStateRepository.html @@ -0,0 +1,8 @@ +IStateRepository | ART Framework API Docs
                                                                                                                                                                      ART Framework API Docs
                                                                                                                                                                        Preparing search index...

                                                                                                                                                                        Interface IStateRepository

                                                                                                                                                                        Repository for managing ThreadConfig and AgentState.

                                                                                                                                                                        +
                                                                                                                                                                        interface IStateRepository {
                                                                                                                                                                            getAgentState(threadId: string): Promise<null | AgentState>;
                                                                                                                                                                            getThreadConfig(threadId: string): Promise<null | ThreadConfig>;
                                                                                                                                                                            getThreadContext(threadId: string): Promise<null | ThreadContext>;
                                                                                                                                                                            setAgentState(threadId: string, state: AgentState): Promise<void>;
                                                                                                                                                                            setThreadConfig(threadId: string, config: ThreadConfig): Promise<void>;
                                                                                                                                                                            setThreadContext(threadId: string, context: ThreadContext): Promise<void>;
                                                                                                                                                                        }
                                                                                                                                                                        Index

                                                                                                                                                                        Methods

                                                                                                                                                                        diff --git a/docs/components/interfaces/IToolExecutor.html b/docs/components/interfaces/IToolExecutor.html new file mode 100644 index 0000000..6c8d0fd --- /dev/null +++ b/docs/components/interfaces/IToolExecutor.html @@ -0,0 +1,9 @@ +IToolExecutor | ART Framework API Docs
                                                                                                                                                                        ART Framework API Docs
                                                                                                                                                                          Preparing search index...

                                                                                                                                                                          Interface IToolExecutor

                                                                                                                                                                          Interface for the executable logic of a tool.

                                                                                                                                                                          +
                                                                                                                                                                          interface IToolExecutor {
                                                                                                                                                                              schema: ToolSchema;
                                                                                                                                                                              execute(input: any, context: ExecutionContext): Promise<ToolResult>;
                                                                                                                                                                          }

                                                                                                                                                                          Implemented by

                                                                                                                                                                          Index

                                                                                                                                                                          Properties

                                                                                                                                                                          Methods

                                                                                                                                                                          Properties

                                                                                                                                                                          schema: ToolSchema

                                                                                                                                                                          The schema definition for this tool.

                                                                                                                                                                          +

                                                                                                                                                                          Methods

                                                                                                                                                                          diff --git a/docs/components/interfaces/ITypedSocket.html b/docs/components/interfaces/ITypedSocket.html new file mode 100644 index 0000000..0e1cb52 --- /dev/null +++ b/docs/components/interfaces/ITypedSocket.html @@ -0,0 +1,16 @@ +ITypedSocket | ART Framework API Docs
                                                                                                                                                                          ART Framework API Docs
                                                                                                                                                                            Preparing search index...

                                                                                                                                                                            Interface ITypedSocket<DataType, FilterType>

                                                                                                                                                                            Generic interface for a typed publish/subscribe socket.

                                                                                                                                                                            +
                                                                                                                                                                            interface ITypedSocket<DataType, FilterType = any> {
                                                                                                                                                                                getHistory(
                                                                                                                                                                                    filter?: FilterType,
                                                                                                                                                                                    options?: { limit?: number; threadId?: string },
                                                                                                                                                                                ): Promise<DataType[]>;
                                                                                                                                                                                notify(
                                                                                                                                                                                    data: DataType,
                                                                                                                                                                                    options?: { targetSessionId?: string; targetThreadId?: string },
                                                                                                                                                                                ): void;
                                                                                                                                                                                subscribe(
                                                                                                                                                                                    callback: (data: DataType) => void,
                                                                                                                                                                                    filter?: FilterType,
                                                                                                                                                                                    options?: { threadId?: string },
                                                                                                                                                                                ): () => void;
                                                                                                                                                                            }

                                                                                                                                                                            Type Parameters

                                                                                                                                                                            • DataType
                                                                                                                                                                            • FilterType = any
                                                                                                                                                                            Index

                                                                                                                                                                            Methods

                                                                                                                                                                            • Optional method to retrieve historical data from the socket's source.

                                                                                                                                                                              +

                                                                                                                                                                              Parameters

                                                                                                                                                                              • Optionalfilter: FilterType

                                                                                                                                                                                Optional filter criteria.

                                                                                                                                                                                +
                                                                                                                                                                              • Optionaloptions: { limit?: number; threadId?: string }

                                                                                                                                                                                Optional configuration like threadId and limit.

                                                                                                                                                                                +

                                                                                                                                                                              Returns Promise<DataType[]>

                                                                                                                                                                            • Notifies subscribers of new data.

                                                                                                                                                                              +

                                                                                                                                                                              Parameters

                                                                                                                                                                              • data: DataType

                                                                                                                                                                                The data payload.

                                                                                                                                                                                +
                                                                                                                                                                              • Optionaloptions: { targetSessionId?: string; targetThreadId?: string }

                                                                                                                                                                                Optional targeting information (e.g., specific thread).

                                                                                                                                                                                +

                                                                                                                                                                              Returns void

                                                                                                                                                                            • Subscribes a callback function to receive data updates.

                                                                                                                                                                              +

                                                                                                                                                                              Parameters

                                                                                                                                                                              • callback: (data: DataType) => void

                                                                                                                                                                                The function to call with new data.

                                                                                                                                                                                +
                                                                                                                                                                              • Optionalfilter: FilterType

                                                                                                                                                                                Optional filter criteria specific to the socket type.

                                                                                                                                                                                +
                                                                                                                                                                              • Optionaloptions: { threadId?: string }

                                                                                                                                                                                Optional configuration like target threadId.

                                                                                                                                                                                +

                                                                                                                                                                              Returns () => void

                                                                                                                                                                              An unsubscribe function.

                                                                                                                                                                              +
                                                                                                                                                                            diff --git a/docs/components/interfaces/JsonObjectSchema.html b/docs/components/interfaces/JsonObjectSchema.html new file mode 100644 index 0000000..6f84cf0 --- /dev/null +++ b/docs/components/interfaces/JsonObjectSchema.html @@ -0,0 +1,8 @@ +JsonObjectSchema | ART Framework API Docs
                                                                                                                                                                            ART Framework API Docs
                                                                                                                                                                              Preparing search index...

                                                                                                                                                                              Interface JsonObjectSchema

                                                                                                                                                                              Represents a basic JSON Schema definition, focusing on object types commonly used for tool inputs/outputs. +This is a simplified representation and doesn't cover all JSON Schema features.

                                                                                                                                                                              +

                                                                                                                                                                              JsonObjectSchema

                                                                                                                                                                              +
                                                                                                                                                                              interface JsonObjectSchema {
                                                                                                                                                                                  additionalProperties?: boolean;
                                                                                                                                                                                  properties: {
                                                                                                                                                                                      [key: string]: {
                                                                                                                                                                                          additionalProperties?: boolean | { type: string };
                                                                                                                                                                                          default?: any;
                                                                                                                                                                                          description?: string;
                                                                                                                                                                                          items?: JsonObjectSchema | { type: string };
                                                                                                                                                                                          properties?: { [key: string]: { [key: string]: any; type: string; description?: string | undefined; default?: any; items?: JsonObjectSchema | { type: string; } | undefined; properties?: ... | undefined; required?: string[] | undefined; additionalProperties?: boolean | ... 1 more ... | undefined; }; };
                                                                                                                                                                                          required?: string[];
                                                                                                                                                                                          type: string;
                                                                                                                                                                                          [key: string]: any;
                                                                                                                                                                                      };
                                                                                                                                                                                  };
                                                                                                                                                                                  required?: string[];
                                                                                                                                                                                  type: "object";
                                                                                                                                                                              }
                                                                                                                                                                              Index

                                                                                                                                                                              Properties

                                                                                                                                                                              additionalProperties?: boolean
                                                                                                                                                                              properties: {
                                                                                                                                                                                  [key: string]: {
                                                                                                                                                                                      additionalProperties?: boolean | { type: string };
                                                                                                                                                                                      default?: any;
                                                                                                                                                                                      description?: string;
                                                                                                                                                                                      items?: JsonObjectSchema | { type: string };
                                                                                                                                                                                      properties?: { [key: string]: { [key: string]: any; type: string; description?: string | undefined; default?: any; items?: JsonObjectSchema | { type: string; } | undefined; properties?: ... | undefined; required?: string[] | undefined; additionalProperties?: boolean | ... 1 more ... | undefined; }; };
                                                                                                                                                                                      required?: string[];
                                                                                                                                                                                      type: string;
                                                                                                                                                                                      [key: string]: any;
                                                                                                                                                                                  };
                                                                                                                                                                              }
                                                                                                                                                                              required?: string[]
                                                                                                                                                                              type: "object"
                                                                                                                                                                              diff --git a/docs/components/interfaces/LLMMetadata.html b/docs/components/interfaces/LLMMetadata.html new file mode 100644 index 0000000..6ae6228 --- /dev/null +++ b/docs/components/interfaces/LLMMetadata.html @@ -0,0 +1,20 @@ +LLMMetadata | ART Framework API Docs
                                                                                                                                                                              ART Framework API Docs
                                                                                                                                                                                Preparing search index...

                                                                                                                                                                                Interface LLMMetadata

                                                                                                                                                                                Structure for holding metadata about an LLM call, typically received via a METADATA StreamEvent +or parsed from a non-streaming response. Fields are optional as availability varies by provider and stream state.

                                                                                                                                                                                +

                                                                                                                                                                                LLMMetadata

                                                                                                                                                                                +
                                                                                                                                                                                interface LLMMetadata {
                                                                                                                                                                                    inputTokens?: number;
                                                                                                                                                                                    outputTokens?: number;
                                                                                                                                                                                    providerRawUsage?: any;
                                                                                                                                                                                    stopReason?: string;
                                                                                                                                                                                    thinkingTokens?: number;
                                                                                                                                                                                    timeToFirstTokenMs?: number;
                                                                                                                                                                                    totalGenerationTimeMs?: number;
                                                                                                                                                                                    traceId?: string;
                                                                                                                                                                                }
                                                                                                                                                                                Index

                                                                                                                                                                                Properties

                                                                                                                                                                                inputTokens?: number

                                                                                                                                                                                The number of tokens in the input prompt, if available.

                                                                                                                                                                                +
                                                                                                                                                                                outputTokens?: number

                                                                                                                                                                                The number of tokens generated in the output response, if available.

                                                                                                                                                                                +
                                                                                                                                                                                providerRawUsage?: any

                                                                                                                                                                                Optional raw usage data provided directly by the LLM provider for extensibility (structure depends on provider).

                                                                                                                                                                                +
                                                                                                                                                                                stopReason?: string

                                                                                                                                                                                The reason the LLM stopped generating tokens (e.g., 'stop_sequence', 'max_tokens', 'tool_calls'), if available.

                                                                                                                                                                                +
                                                                                                                                                                                thinkingTokens?: number

                                                                                                                                                                                The number of tokens identified as part of the LLM's internal thinking process (if available from provider).

                                                                                                                                                                                +
                                                                                                                                                                                timeToFirstTokenMs?: number

                                                                                                                                                                                The time elapsed (in milliseconds) until the first token was generated in a streaming response, if applicable and available.

                                                                                                                                                                                +
                                                                                                                                                                                totalGenerationTimeMs?: number

                                                                                                                                                                                The total time elapsed (in milliseconds) for the entire generation process, if available.

                                                                                                                                                                                +
                                                                                                                                                                                traceId?: string

                                                                                                                                                                                The trace ID associated with the LLM call, useful for correlating metadata with the specific request.

                                                                                                                                                                                +
                                                                                                                                                                                diff --git a/docs/components/interfaces/LoggerConfig.html b/docs/components/interfaces/LoggerConfig.html new file mode 100644 index 0000000..44a483f --- /dev/null +++ b/docs/components/interfaces/LoggerConfig.html @@ -0,0 +1,7 @@ +LoggerConfig | ART Framework API Docs
                                                                                                                                                                                ART Framework API Docs
                                                                                                                                                                                  Preparing search index...

                                                                                                                                                                                  Interface LoggerConfig

                                                                                                                                                                                  Configuration options for the static Logger class.

                                                                                                                                                                                  +

                                                                                                                                                                                  LoggerConfig

                                                                                                                                                                                  +
                                                                                                                                                                                  interface LoggerConfig {
                                                                                                                                                                                      level: LogLevel;
                                                                                                                                                                                      prefix?: string;
                                                                                                                                                                                  }
                                                                                                                                                                                  Index

                                                                                                                                                                                  Properties

                                                                                                                                                                                  Properties

                                                                                                                                                                                  level: LogLevel

                                                                                                                                                                                  The minimum log level to output messages for. Messages below this level will be ignored.

                                                                                                                                                                                  +
                                                                                                                                                                                  prefix?: string

                                                                                                                                                                                  An optional prefix string to prepend to all log messages (e.g., '[MyApp]'). Defaults to '[ART]'.

                                                                                                                                                                                  +
                                                                                                                                                                                  diff --git a/docs/components/interfaces/ManagedAdapterAccessor.html b/docs/components/interfaces/ManagedAdapterAccessor.html new file mode 100644 index 0000000..1c8841b --- /dev/null +++ b/docs/components/interfaces/ManagedAdapterAccessor.html @@ -0,0 +1,7 @@ +ManagedAdapterAccessor | ART Framework API Docs
                                                                                                                                                                                  ART Framework API Docs
                                                                                                                                                                                    Preparing search index...

                                                                                                                                                                                    Interface ManagedAdapterAccessor

                                                                                                                                                                                    Object returned by ProviderManager granting access to an adapter instance.

                                                                                                                                                                                    +

                                                                                                                                                                                    ManagedAdapterAccessor

                                                                                                                                                                                    +
                                                                                                                                                                                    interface ManagedAdapterAccessor {
                                                                                                                                                                                        adapter: ProviderAdapter;
                                                                                                                                                                                        release: () => void;
                                                                                                                                                                                    }
                                                                                                                                                                                    Index

                                                                                                                                                                                    Properties

                                                                                                                                                                                    Properties

                                                                                                                                                                                    The ready-to-use adapter instance.

                                                                                                                                                                                    +
                                                                                                                                                                                    release: () => void

                                                                                                                                                                                    Signals that the current call using this adapter instance is finished.

                                                                                                                                                                                    +
                                                                                                                                                                                    diff --git a/docs/components/interfaces/McpManagerConfig.html b/docs/components/interfaces/McpManagerConfig.html new file mode 100644 index 0000000..8436e2e --- /dev/null +++ b/docs/components/interfaces/McpManagerConfig.html @@ -0,0 +1,8 @@ +McpManagerConfig | ART Framework API Docs
                                                                                                                                                                                    ART Framework API Docs
                                                                                                                                                                                      Preparing search index...

                                                                                                                                                                                      Interface McpManagerConfig

                                                                                                                                                                                      Defines the configuration for the McpManager.

                                                                                                                                                                                      +

                                                                                                                                                                                      McpManagerConfig

                                                                                                                                                                                      +
                                                                                                                                                                                      interface McpManagerConfig {
                                                                                                                                                                                          discoveryEndpoint?: string;
                                                                                                                                                                                          enabled: boolean;
                                                                                                                                                                                      }
                                                                                                                                                                                      Index

                                                                                                                                                                                      Properties

                                                                                                                                                                                      discoveryEndpoint?: string

                                                                                                                                                                                      An optional endpoint URL for discovering MCP servers. +Defaults to the Zyntopia API if not provided.

                                                                                                                                                                                      +
                                                                                                                                                                                      enabled: boolean

                                                                                                                                                                                      Whether to enable MCP functionality. Defaults to false.

                                                                                                                                                                                      +
                                                                                                                                                                                      diff --git a/docs/components/interfaces/McpResource.html b/docs/components/interfaces/McpResource.html new file mode 100644 index 0000000..2d3c1db --- /dev/null +++ b/docs/components/interfaces/McpResource.html @@ -0,0 +1,11 @@ +McpResource | ART Framework API Docs
                                                                                                                                                                                      ART Framework API Docs
                                                                                                                                                                                        Preparing search index...

                                                                                                                                                                                        Interface McpResource

                                                                                                                                                                                        Defines a static resource provided by an MCP server.

                                                                                                                                                                                        +

                                                                                                                                                                                        McpResource

                                                                                                                                                                                        +
                                                                                                                                                                                        interface McpResource {
                                                                                                                                                                                            description?: string;
                                                                                                                                                                                            mimeType?: string;
                                                                                                                                                                                            name: string;
                                                                                                                                                                                            uri: string;
                                                                                                                                                                                        }
                                                                                                                                                                                        Index

                                                                                                                                                                                        Properties

                                                                                                                                                                                        description?: string

                                                                                                                                                                                        A description of the resource.

                                                                                                                                                                                        +
                                                                                                                                                                                        mimeType?: string

                                                                                                                                                                                        The MIME type of the resource.

                                                                                                                                                                                        +
                                                                                                                                                                                        name: string

                                                                                                                                                                                        The name of the resource.

                                                                                                                                                                                        +
                                                                                                                                                                                        uri: string

                                                                                                                                                                                        The URI of the resource.

                                                                                                                                                                                        +
                                                                                                                                                                                        diff --git a/docs/components/interfaces/McpResourceTemplate.html b/docs/components/interfaces/McpResourceTemplate.html new file mode 100644 index 0000000..8df1459 --- /dev/null +++ b/docs/components/interfaces/McpResourceTemplate.html @@ -0,0 +1,11 @@ +McpResourceTemplate | ART Framework API Docs
                                                                                                                                                                                        ART Framework API Docs
                                                                                                                                                                                          Preparing search index...

                                                                                                                                                                                          Interface McpResourceTemplate

                                                                                                                                                                                          Defines a template for a resource provided by an MCP server.

                                                                                                                                                                                          +

                                                                                                                                                                                          McpResourceTemplate

                                                                                                                                                                                          +
                                                                                                                                                                                          interface McpResourceTemplate {
                                                                                                                                                                                              description?: string;
                                                                                                                                                                                              mimeType?: string;
                                                                                                                                                                                              name: string;
                                                                                                                                                                                              uriTemplate: string;
                                                                                                                                                                                          }
                                                                                                                                                                                          Index

                                                                                                                                                                                          Properties

                                                                                                                                                                                          description?: string

                                                                                                                                                                                          A description of the resource template.

                                                                                                                                                                                          +
                                                                                                                                                                                          mimeType?: string

                                                                                                                                                                                          The MIME type of the resource.

                                                                                                                                                                                          +
                                                                                                                                                                                          name: string

                                                                                                                                                                                          The name of the resource template.

                                                                                                                                                                                          +
                                                                                                                                                                                          uriTemplate: string

                                                                                                                                                                                          The URI template for the resource.

                                                                                                                                                                                          +
                                                                                                                                                                                          diff --git a/docs/components/interfaces/McpServerStatus.html b/docs/components/interfaces/McpServerStatus.html new file mode 100644 index 0000000..4d164e0 --- /dev/null +++ b/docs/components/interfaces/McpServerStatus.html @@ -0,0 +1,14 @@ +McpServerStatus | ART Framework API Docs
                                                                                                                                                                                          ART Framework API Docs
                                                                                                                                                                                            Preparing search index...

                                                                                                                                                                                            Interface McpServerStatus

                                                                                                                                                                                            Represents the internal status of an MCP server connection. +This is not part of the public configuration.

                                                                                                                                                                                            +

                                                                                                                                                                                            McpServerStatus

                                                                                                                                                                                            +
                                                                                                                                                                                            interface McpServerStatus {
                                                                                                                                                                                                id: string;
                                                                                                                                                                                                lastConnected?: Date;
                                                                                                                                                                                                lastError?: string;
                                                                                                                                                                                                status: "connected" | "disconnected" | "error" | "connecting";
                                                                                                                                                                                                toolCount: number;
                                                                                                                                                                                            }
                                                                                                                                                                                            Index

                                                                                                                                                                                            Properties

                                                                                                                                                                                            id: string

                                                                                                                                                                                            The unique identifier for the server.

                                                                                                                                                                                            +
                                                                                                                                                                                            lastConnected?: Date

                                                                                                                                                                                            The timestamp of the last successful connection.

                                                                                                                                                                                            +
                                                                                                                                                                                            lastError?: string

                                                                                                                                                                                            The last error message received from the server.

                                                                                                                                                                                            +
                                                                                                                                                                                            status: "connected" | "disconnected" | "error" | "connecting"

                                                                                                                                                                                            The current connection status of the server.

                                                                                                                                                                                            +
                                                                                                                                                                                            toolCount: number

                                                                                                                                                                                            The number of tools registered from this server.

                                                                                                                                                                                            +
                                                                                                                                                                                            diff --git a/docs/components/interfaces/McpToolDefinition.html b/docs/components/interfaces/McpToolDefinition.html new file mode 100644 index 0000000..28d3613 --- /dev/null +++ b/docs/components/interfaces/McpToolDefinition.html @@ -0,0 +1,11 @@ +McpToolDefinition | ART Framework API Docs
                                                                                                                                                                                            ART Framework API Docs
                                                                                                                                                                                              Preparing search index...

                                                                                                                                                                                              Interface McpToolDefinition

                                                                                                                                                                                              Defines the schema for a tool provided by an MCP server.

                                                                                                                                                                                              +

                                                                                                                                                                                              McpToolDefinition

                                                                                                                                                                                              +
                                                                                                                                                                                              interface McpToolDefinition {
                                                                                                                                                                                                  description?: string;
                                                                                                                                                                                                  inputSchema: any;
                                                                                                                                                                                                  name: string;
                                                                                                                                                                                                  outputSchema?: any;
                                                                                                                                                                                              }
                                                                                                                                                                                              Index

                                                                                                                                                                                              Properties

                                                                                                                                                                                              description?: string

                                                                                                                                                                                              A description of what the tool does.

                                                                                                                                                                                              +
                                                                                                                                                                                              inputSchema: any

                                                                                                                                                                                              The JSON schema for the tool's input.

                                                                                                                                                                                              +
                                                                                                                                                                                              name: string

                                                                                                                                                                                              The name of the tool.

                                                                                                                                                                                              +
                                                                                                                                                                                              outputSchema?: any

                                                                                                                                                                                              The JSON schema for the tool's output.

                                                                                                                                                                                              +
                                                                                                                                                                                              diff --git a/docs/components/interfaces/MessageOptions.html b/docs/components/interfaces/MessageOptions.html new file mode 100644 index 0000000..0430676 --- /dev/null +++ b/docs/components/interfaces/MessageOptions.html @@ -0,0 +1,11 @@ +MessageOptions | ART Framework API Docs
                                                                                                                                                                                              ART Framework API Docs
                                                                                                                                                                                                Preparing search index...

                                                                                                                                                                                                Interface MessageOptions

                                                                                                                                                                                                Options for retrieving conversation messages.

                                                                                                                                                                                                +

                                                                                                                                                                                                MessageOptions

                                                                                                                                                                                                +
                                                                                                                                                                                                interface MessageOptions {
                                                                                                                                                                                                    afterTimestamp?: number;
                                                                                                                                                                                                    beforeTimestamp?: number;
                                                                                                                                                                                                    limit?: number;
                                                                                                                                                                                                    roles?: MessageRole[];
                                                                                                                                                                                                }
                                                                                                                                                                                                Index

                                                                                                                                                                                                Properties

                                                                                                                                                                                                afterTimestamp?: number

                                                                                                                                                                                                Retrieve messages created after this Unix timestamp (milliseconds).

                                                                                                                                                                                                +
                                                                                                                                                                                                beforeTimestamp?: number

                                                                                                                                                                                                Retrieve messages created before this Unix timestamp (milliseconds).

                                                                                                                                                                                                +
                                                                                                                                                                                                limit?: number

                                                                                                                                                                                                The maximum number of messages to retrieve.

                                                                                                                                                                                                +
                                                                                                                                                                                                roles?: MessageRole[]

                                                                                                                                                                                                Optionally filter messages by role (e.g., retrieve only 'AI' messages).

                                                                                                                                                                                                +
                                                                                                                                                                                                diff --git a/docs/components/interfaces/OAuthConfig.html b/docs/components/interfaces/OAuthConfig.html new file mode 100644 index 0000000..5710573 --- /dev/null +++ b/docs/components/interfaces/OAuthConfig.html @@ -0,0 +1,18 @@ +OAuthConfig | ART Framework API Docs
                                                                                                                                                                                                ART Framework API Docs
                                                                                                                                                                                                  Preparing search index...

                                                                                                                                                                                                  Interface OAuthConfig

                                                                                                                                                                                                  Configuration for OAuth 2.0 authentication strategy

                                                                                                                                                                                                  +
                                                                                                                                                                                                  interface OAuthConfig {
                                                                                                                                                                                                      clientId: string;
                                                                                                                                                                                                      clientSecret: string;
                                                                                                                                                                                                      grantType?: "refresh_token" | "authorization_code" | "client_credentials";
                                                                                                                                                                                                      scopes?: string;
                                                                                                                                                                                                      tokenEndpoint: string;
                                                                                                                                                                                                      tokenRefreshBufferMs?: number;
                                                                                                                                                                                                      tokenRequestHeaders?: Record<string, string>;
                                                                                                                                                                                                      tokenTimeoutMs?: number;
                                                                                                                                                                                                  }
                                                                                                                                                                                                  Index

                                                                                                                                                                                                  Properties

                                                                                                                                                                                                  clientId: string

                                                                                                                                                                                                  Client ID for OAuth authentication

                                                                                                                                                                                                  +
                                                                                                                                                                                                  clientSecret: string

                                                                                                                                                                                                  Client secret for OAuth authentication

                                                                                                                                                                                                  +
                                                                                                                                                                                                  grantType?: "refresh_token" | "authorization_code" | "client_credentials"

                                                                                                                                                                                                  Grant type to use (defaults to 'client_credentials')

                                                                                                                                                                                                  +
                                                                                                                                                                                                  scopes?: string

                                                                                                                                                                                                  OAuth scopes to request (space-separated)

                                                                                                                                                                                                  +
                                                                                                                                                                                                  tokenEndpoint: string

                                                                                                                                                                                                  OAuth token endpoint URL

                                                                                                                                                                                                  +
                                                                                                                                                                                                  tokenRefreshBufferMs?: number

                                                                                                                                                                                                  Buffer time before token expiry to trigger refresh (default: 300000 = 5 minutes)

                                                                                                                                                                                                  +
                                                                                                                                                                                                  tokenRequestHeaders?: Record<string, string>

                                                                                                                                                                                                  Additional headers to send with token requests

                                                                                                                                                                                                  +
                                                                                                                                                                                                  tokenTimeoutMs?: number

                                                                                                                                                                                                  Custom timeout for token requests in milliseconds (default: 30000)

                                                                                                                                                                                                  +
                                                                                                                                                                                                  diff --git a/docs/components/interfaces/Observation.html b/docs/components/interfaces/Observation.html new file mode 100644 index 0000000..a50a116 --- /dev/null +++ b/docs/components/interfaces/Observation.html @@ -0,0 +1,28 @@ +Observation | ART Framework API Docs
                                                                                                                                                                                                  ART Framework API Docs
                                                                                                                                                                                                    Preparing search index...

                                                                                                                                                                                                    Interface Observation

                                                                                                                                                                                                    Represents a recorded event during the agent's execution.

                                                                                                                                                                                                    +

                                                                                                                                                                                                    Observation

                                                                                                                                                                                                    +
                                                                                                                                                                                                    interface Observation {
                                                                                                                                                                                                        content: any;
                                                                                                                                                                                                        id: string;
                                                                                                                                                                                                        metadata?: Record<string, any>;
                                                                                                                                                                                                        threadId: string;
                                                                                                                                                                                                        timestamp: number;
                                                                                                                                                                                                        title: string;
                                                                                                                                                                                                        traceId?: string;
                                                                                                                                                                                                        type: ObservationType;
                                                                                                                                                                                                    }
                                                                                                                                                                                                    Index

                                                                                                                                                                                                    Properties

                                                                                                                                                                                                    content: any

                                                                                                                                                                                                    The main data payload of the observation, structure depends on the type.

                                                                                                                                                                                                    +

                                                                                                                                                                                                    Common content shapes by type:

                                                                                                                                                                                                    +
                                                                                                                                                                                                      +
                                                                                                                                                                                                    • TITLE: { title: string } — a concise thread title (<= 10 words)
                                                                                                                                                                                                    • +
                                                                                                                                                                                                    • INTENT: { intent: string }
                                                                                                                                                                                                    • +
                                                                                                                                                                                                    • PLAN: { plan: string; rawOutput?: string }
                                                                                                                                                                                                    • +
                                                                                                                                                                                                    • TOOL_CALL: { toolCalls: ParsedToolCall[] }
                                                                                                                                                                                                    • +
                                                                                                                                                                                                    • TOOL_EXECUTION: { callId: string; toolName: string; status: 'success' | 'error'; output?: any; error?: string }
                                                                                                                                                                                                    • +
                                                                                                                                                                                                    • FINAL_RESPONSE: { message: ConversationMessage; uiMetadata?: object }
                                                                                                                                                                                                    • +
                                                                                                                                                                                                    +
                                                                                                                                                                                                    id: string

                                                                                                                                                                                                    A unique identifier for this specific observation record.

                                                                                                                                                                                                    +
                                                                                                                                                                                                    metadata?: Record<string, any>

                                                                                                                                                                                                    Optional metadata providing additional context (e.g., source phase, related IDs, status).

                                                                                                                                                                                                    +
                                                                                                                                                                                                    threadId: string

                                                                                                                                                                                                    The identifier of the conversation thread this observation relates to.

                                                                                                                                                                                                    +
                                                                                                                                                                                                    timestamp: number

                                                                                                                                                                                                    A Unix timestamp (in milliseconds) indicating when the observation was recorded.

                                                                                                                                                                                                    +
                                                                                                                                                                                                    title: string

                                                                                                                                                                                                    A concise, human-readable title summarizing the observation (often generated based on type/metadata).

                                                                                                                                                                                                    +
                                                                                                                                                                                                    traceId?: string

                                                                                                                                                                                                    An optional identifier for tracing a request across multiple systems or components.

                                                                                                                                                                                                    +

                                                                                                                                                                                                    The category of the event being observed (e.g., PLAN, THOUGHTS, TOOL_EXECUTION).

                                                                                                                                                                                                    +
                                                                                                                                                                                                    diff --git a/docs/components/interfaces/ObservationFilter.html b/docs/components/interfaces/ObservationFilter.html new file mode 100644 index 0000000..0e43b31 --- /dev/null +++ b/docs/components/interfaces/ObservationFilter.html @@ -0,0 +1,9 @@ +ObservationFilter | ART Framework API Docs
                                                                                                                                                                                                    ART Framework API Docs
                                                                                                                                                                                                      Preparing search index...

                                                                                                                                                                                                      Interface ObservationFilter

                                                                                                                                                                                                      Options for filtering observations.

                                                                                                                                                                                                      +

                                                                                                                                                                                                      ObservationFilter

                                                                                                                                                                                                      +
                                                                                                                                                                                                      interface ObservationFilter {
                                                                                                                                                                                                          afterTimestamp?: number;
                                                                                                                                                                                                          beforeTimestamp?: number;
                                                                                                                                                                                                          types?: ObservationType[];
                                                                                                                                                                                                      }
                                                                                                                                                                                                      Index

                                                                                                                                                                                                      Properties

                                                                                                                                                                                                      afterTimestamp?: number

                                                                                                                                                                                                      Retrieve observations recorded after this Unix timestamp (milliseconds).

                                                                                                                                                                                                      +
                                                                                                                                                                                                      beforeTimestamp?: number

                                                                                                                                                                                                      Retrieve observations recorded before this Unix timestamp (milliseconds).

                                                                                                                                                                                                      +
                                                                                                                                                                                                      types?: ObservationType[]

                                                                                                                                                                                                      An array of ObservationType enums to filter by. If provided, only observations matching these types are returned.

                                                                                                                                                                                                      +
                                                                                                                                                                                                      diff --git a/docs/components/interfaces/ObservationManager.html b/docs/components/interfaces/ObservationManager.html new file mode 100644 index 0000000..6194c35 --- /dev/null +++ b/docs/components/interfaces/ObservationManager.html @@ -0,0 +1,13 @@ +ObservationManager | ART Framework API Docs
                                                                                                                                                                                                      ART Framework API Docs
                                                                                                                                                                                                        Preparing search index...

                                                                                                                                                                                                        Interface ObservationManager

                                                                                                                                                                                                        Interface for managing the recording and retrieval of observations.

                                                                                                                                                                                                        +
                                                                                                                                                                                                        interface ObservationManager {
                                                                                                                                                                                                            getObservations(
                                                                                                                                                                                                                threadId: string,
                                                                                                                                                                                                                filter?: ObservationFilter,
                                                                                                                                                                                                            ): Promise<Observation[]>;
                                                                                                                                                                                                            record(
                                                                                                                                                                                                                observationData: Omit<Observation, "id" | "timestamp" | "title">,
                                                                                                                                                                                                            ): Promise<void>;
                                                                                                                                                                                                        }
                                                                                                                                                                                                        Index

                                                                                                                                                                                                        Methods

                                                                                                                                                                                                        • Retrieves historical observations stored for a specific thread.

                                                                                                                                                                                                          +

                                                                                                                                                                                                          Parameters

                                                                                                                                                                                                          • threadId: string

                                                                                                                                                                                                            The ID of the thread whose observations are to be retrieved.

                                                                                                                                                                                                            +
                                                                                                                                                                                                          • Optionalfilter: ObservationFilter

                                                                                                                                                                                                            Optional criteria to filter the observations, e.g., by ObservationType. See ObservationFilter.

                                                                                                                                                                                                            +

                                                                                                                                                                                                          Returns Promise<Observation[]>

                                                                                                                                                                                                          A promise resolving to an array of Observation objects matching the criteria.

                                                                                                                                                                                                          +
                                                                                                                                                                                                        • Creates, persists, and broadcasts a new observation record. +This is the primary method used by other systems to log significant events. +It automatically generates a unique ID, timestamp, and potentially a title.

                                                                                                                                                                                                          +

                                                                                                                                                                                                          Parameters

                                                                                                                                                                                                          • observationData: Omit<Observation, "id" | "timestamp" | "title">

                                                                                                                                                                                                            An object containing the core data for the observation (threadId, type, content, metadata, etc.), excluding fields generated by the manager (id, timestamp, title).

                                                                                                                                                                                                            +

                                                                                                                                                                                                          Returns Promise<void>

                                                                                                                                                                                                          A promise that resolves when the observation has been recorded and notified.

                                                                                                                                                                                                          +
                                                                                                                                                                                                        diff --git a/docs/components/interfaces/OllamaAdapterOptions.html b/docs/components/interfaces/OllamaAdapterOptions.html new file mode 100644 index 0000000..56810fd --- /dev/null +++ b/docs/components/interfaces/OllamaAdapterOptions.html @@ -0,0 +1,11 @@ +OllamaAdapterOptions | ART Framework API Docs
                                                                                                                                                                                                        ART Framework API Docs
                                                                                                                                                                                                          Preparing search index...

                                                                                                                                                                                                          Interface OllamaAdapterOptions

                                                                                                                                                                                                          Configuration options required for the OllamaAdapter.

                                                                                                                                                                                                          +
                                                                                                                                                                                                          interface OllamaAdapterOptions {
                                                                                                                                                                                                              apiKey?: string;
                                                                                                                                                                                                              defaultModel?: string;
                                                                                                                                                                                                              ollamaBaseUrl?: string;
                                                                                                                                                                                                          }
                                                                                                                                                                                                          Index

                                                                                                                                                                                                          Properties

                                                                                                                                                                                                          apiKey?: string

                                                                                                                                                                                                          API key for Ollama (if secured). Defaults to "ollama" as commonly used.

                                                                                                                                                                                                          +
                                                                                                                                                                                                          defaultModel?: string

                                                                                                                                                                                                          The default Ollama model ID to use (e.g., 'llama3', 'mistral'). +This can be overridden by RuntimeProviderConfig.modelId or CallOptions.model. +It's recommended to set this if you primarily use one model with Ollama.

                                                                                                                                                                                                          +
                                                                                                                                                                                                          ollamaBaseUrl?: string

                                                                                                                                                                                                          The base URL for the Ollama API. Defaults to 'http://localhost:11434'. +The '/v1' suffix for OpenAI compatibility will be added automatically.

                                                                                                                                                                                                          +
                                                                                                                                                                                                          diff --git a/docs/components/interfaces/OpenAIAdapterOptions.html b/docs/components/interfaces/OpenAIAdapterOptions.html new file mode 100644 index 0000000..de2c317 --- /dev/null +++ b/docs/components/interfaces/OpenAIAdapterOptions.html @@ -0,0 +1,8 @@ +OpenAIAdapterOptions | ART Framework API Docs
                                                                                                                                                                                                          ART Framework API Docs
                                                                                                                                                                                                            Preparing search index...

                                                                                                                                                                                                            Interface OpenAIAdapterOptions

                                                                                                                                                                                                            Configuration options required for the OpenAIAdapter.

                                                                                                                                                                                                            +
                                                                                                                                                                                                            interface OpenAIAdapterOptions {
                                                                                                                                                                                                                apiBaseUrl?: string;
                                                                                                                                                                                                                apiKey: string;
                                                                                                                                                                                                                model?: string;
                                                                                                                                                                                                            }
                                                                                                                                                                                                            Index

                                                                                                                                                                                                            Properties

                                                                                                                                                                                                            Properties

                                                                                                                                                                                                            apiBaseUrl?: string

                                                                                                                                                                                                            Optional: Override the base URL for the OpenAI API (e.g., for Azure OpenAI or custom proxies).

                                                                                                                                                                                                            +
                                                                                                                                                                                                            apiKey: string

                                                                                                                                                                                                            Your OpenAI API key. Handle securely.

                                                                                                                                                                                                            +
                                                                                                                                                                                                            model?: string

                                                                                                                                                                                                            The default OpenAI model ID to use (e.g., 'gpt-4o', 'gpt-4o-mini'). Defaults to 'gpt-3.5-turbo' if not provided.

                                                                                                                                                                                                            +
                                                                                                                                                                                                            diff --git a/docs/components/interfaces/OpenRouterAdapterOptions.html b/docs/components/interfaces/OpenRouterAdapterOptions.html new file mode 100644 index 0000000..f69d556 --- /dev/null +++ b/docs/components/interfaces/OpenRouterAdapterOptions.html @@ -0,0 +1,12 @@ +OpenRouterAdapterOptions | ART Framework API Docs
                                                                                                                                                                                                            ART Framework API Docs
                                                                                                                                                                                                              Preparing search index...

                                                                                                                                                                                                              Interface OpenRouterAdapterOptions

                                                                                                                                                                                                              Configuration options required for the OpenRouterAdapter.

                                                                                                                                                                                                              +
                                                                                                                                                                                                              interface OpenRouterAdapterOptions {
                                                                                                                                                                                                                  apiBaseUrl?: string;
                                                                                                                                                                                                                  apiKey: string;
                                                                                                                                                                                                                  appName?: string;
                                                                                                                                                                                                                  model: string;
                                                                                                                                                                                                                  siteUrl?: string;
                                                                                                                                                                                                              }
                                                                                                                                                                                                              Index

                                                                                                                                                                                                              Properties

                                                                                                                                                                                                              apiBaseUrl?: string

                                                                                                                                                                                                              Optional: Override the base URL for the OpenRouter API. Defaults to 'https://openrouter.ai/api/v1'.

                                                                                                                                                                                                              +
                                                                                                                                                                                                              apiKey: string

                                                                                                                                                                                                              Your OpenRouter API key. Handle securely.

                                                                                                                                                                                                              +
                                                                                                                                                                                                              appName?: string

                                                                                                                                                                                                              Optional: Your application's name, sent as the 'X-Title' header (recommended by OpenRouter).

                                                                                                                                                                                                              +
                                                                                                                                                                                                              model: string

                                                                                                                                                                                                              The required OpenRouter model identifier string (e.g., 'google/gemini-pro', 'anthropic/claude-3-haiku', 'openai/gpt-4o'). This specifies which underlying model OpenRouter should use.

                                                                                                                                                                                                              +
                                                                                                                                                                                                              siteUrl?: string

                                                                                                                                                                                                              Optional: Your application's site URL, sent as the 'HTTP-Referer' header (recommended by OpenRouter).

                                                                                                                                                                                                              +
                                                                                                                                                                                                              diff --git a/docs/components/interfaces/OutputParser.html b/docs/components/interfaces/OutputParser.html new file mode 100644 index 0000000..c7004ae --- /dev/null +++ b/docs/components/interfaces/OutputParser.html @@ -0,0 +1,20 @@ +OutputParser | ART Framework API Docs
                                                                                                                                                                                                              ART Framework API Docs
                                                                                                                                                                                                                Preparing search index...

                                                                                                                                                                                                                Interface OutputParser

                                                                                                                                                                                                                Interface for parsing structured output from LLM responses.

                                                                                                                                                                                                                +
                                                                                                                                                                                                                interface OutputParser {
                                                                                                                                                                                                                    parsePlanningOutput(
                                                                                                                                                                                                                        output: string,
                                                                                                                                                                                                                    ): Promise<
                                                                                                                                                                                                                        {
                                                                                                                                                                                                                            intent?: string;
                                                                                                                                                                                                                            plan?: string;
                                                                                                                                                                                                                            thoughts?: string;
                                                                                                                                                                                                                            title?: string;
                                                                                                                                                                                                                            toolCalls?: ParsedToolCall[];
                                                                                                                                                                                                                        },
                                                                                                                                                                                                                    >;
                                                                                                                                                                                                                    parseSynthesisOutput(output: string): Promise<string>;
                                                                                                                                                                                                                }
                                                                                                                                                                                                                Index

                                                                                                                                                                                                                Methods

                                                                                                                                                                                                                • Parses the raw planning LLM output into structured fields.

                                                                                                                                                                                                                  +

                                                                                                                                                                                                                  Parameters

                                                                                                                                                                                                                  • output: string

                                                                                                                                                                                                                  Returns Promise<
                                                                                                                                                                                                                      {
                                                                                                                                                                                                                          intent?: string;
                                                                                                                                                                                                                          plan?: string;
                                                                                                                                                                                                                          thoughts?: string;
                                                                                                                                                                                                                          title?: string;
                                                                                                                                                                                                                          toolCalls?: ParsedToolCall[];
                                                                                                                                                                                                                      },
                                                                                                                                                                                                                  >

                                                                                                                                                                                                                  This method should be resilient to provider-specific wrappers and formats. +Implementations MUST attempt JSON-first parsing and then fall back to parsing +labeled sections. Supported fields:

                                                                                                                                                                                                                  +
                                                                                                                                                                                                                    +
                                                                                                                                                                                                                  • title?: A concise thread title (<= 10 words), derived from the user's intent and context.
                                                                                                                                                                                                                  • +
                                                                                                                                                                                                                  • intent?: A short summary of the user's goal.
                                                                                                                                                                                                                  • +
                                                                                                                                                                                                                  • plan?: A human-readable list/description of steps.
                                                                                                                                                                                                                  • +
                                                                                                                                                                                                                  • toolCalls?: Structured tool call intents parsed from the output.
                                                                                                                                                                                                                  • +
                                                                                                                                                                                                                  • thoughts?: Aggregated content extracted from tags when present.
                                                                                                                                                                                                                  • +
                                                                                                                                                                                                                  +
                                                                                                                                                                                                                • Parses the raw string output from the synthesis LLM call to extract the final, user-facing response content. +This might involve removing extraneous tags or formatting.

                                                                                                                                                                                                                  +

                                                                                                                                                                                                                  Parameters

                                                                                                                                                                                                                  • output: string

                                                                                                                                                                                                                    The raw string response from the synthesis LLM call.

                                                                                                                                                                                                                    +

                                                                                                                                                                                                                  Returns Promise<string>

                                                                                                                                                                                                                  A promise resolving to the clean, final response string.

                                                                                                                                                                                                                  +

                                                                                                                                                                                                                  If the final response cannot be extracted (typically code OUTPUT_PARSING_FAILED).

                                                                                                                                                                                                                  +
                                                                                                                                                                                                                diff --git a/docs/components/interfaces/PKCEOAuthConfig.html b/docs/components/interfaces/PKCEOAuthConfig.html new file mode 100644 index 0000000..b8d812a --- /dev/null +++ b/docs/components/interfaces/PKCEOAuthConfig.html @@ -0,0 +1,18 @@ +PKCEOAuthConfig | ART Framework API Docs
                                                                                                                                                                                                                ART Framework API Docs
                                                                                                                                                                                                                  Preparing search index...

                                                                                                                                                                                                                  Interface PKCEOAuthConfig

                                                                                                                                                                                                                  Configuration for the PKCE OAuth 2.0 authentication strategy.

                                                                                                                                                                                                                  +
                                                                                                                                                                                                                  interface PKCEOAuthConfig {
                                                                                                                                                                                                                      authorizationEndpoint: string;
                                                                                                                                                                                                                      channelName?: string;
                                                                                                                                                                                                                      clientId: string;
                                                                                                                                                                                                                      openInNewTab?: boolean;
                                                                                                                                                                                                                      redirectUri: string;
                                                                                                                                                                                                                      resource?: string;
                                                                                                                                                                                                                      scopes: string;
                                                                                                                                                                                                                      tokenEndpoint: string;
                                                                                                                                                                                                                  }
                                                                                                                                                                                                                  Index

                                                                                                                                                                                                                  Properties

                                                                                                                                                                                                                  authorizationEndpoint: string

                                                                                                                                                                                                                  The OAuth 2.0 authorization endpoint URL.

                                                                                                                                                                                                                  +
                                                                                                                                                                                                                  channelName?: string

                                                                                                                                                                                                                  BroadcastChannel name used to receive auth codes from callback tab (default 'art-auth').

                                                                                                                                                                                                                  +
                                                                                                                                                                                                                  clientId: string

                                                                                                                                                                                                                  The client ID for the application.

                                                                                                                                                                                                                  +
                                                                                                                                                                                                                  openInNewTab?: boolean

                                                                                                                                                                                                                  Open login in a new tab (default true for ART MCP flows).

                                                                                                                                                                                                                  +
                                                                                                                                                                                                                  redirectUri: string

                                                                                                                                                                                                                  The redirect URI for the application.

                                                                                                                                                                                                                  +
                                                                                                                                                                                                                  resource?: string

                                                                                                                                                                                                                  Optional: The resource parameter to specify the target audience (for MCP servers).

                                                                                                                                                                                                                  +
                                                                                                                                                                                                                  scopes: string

                                                                                                                                                                                                                  The scopes to request (space-separated).

                                                                                                                                                                                                                  +
                                                                                                                                                                                                                  tokenEndpoint: string

                                                                                                                                                                                                                  The OAuth 2.0 token endpoint URL.

                                                                                                                                                                                                                  +
                                                                                                                                                                                                                  diff --git a/docs/components/interfaces/ParsedToolCall.html b/docs/components/interfaces/ParsedToolCall.html new file mode 100644 index 0000000..ef69fa5 --- /dev/null +++ b/docs/components/interfaces/ParsedToolCall.html @@ -0,0 +1,9 @@ +ParsedToolCall | ART Framework API Docs
                                                                                                                                                                                                                  ART Framework API Docs
                                                                                                                                                                                                                    Preparing search index...

                                                                                                                                                                                                                    Interface ParsedToolCall

                                                                                                                                                                                                                    Represents a parsed request from the LLM to call a specific tool.

                                                                                                                                                                                                                    +

                                                                                                                                                                                                                    ParsedToolCall

                                                                                                                                                                                                                    +
                                                                                                                                                                                                                    interface ParsedToolCall {
                                                                                                                                                                                                                        arguments: any;
                                                                                                                                                                                                                        callId: string;
                                                                                                                                                                                                                        toolName: string;
                                                                                                                                                                                                                    }
                                                                                                                                                                                                                    Index

                                                                                                                                                                                                                    Properties

                                                                                                                                                                                                                    Properties

                                                                                                                                                                                                                    arguments: any

                                                                                                                                                                                                                    The arguments object, parsed from the LLM response, intended to be passed to the tool's execute method after validation.

                                                                                                                                                                                                                    +
                                                                                                                                                                                                                    callId: string

                                                                                                                                                                                                                    A unique identifier generated by the OutputParser for this specific tool call request within a plan.

                                                                                                                                                                                                                    +
                                                                                                                                                                                                                    toolName: string

                                                                                                                                                                                                                    The name of the tool the LLM intends to call. Must match a registered tool's schema name.

                                                                                                                                                                                                                    +
                                                                                                                                                                                                                    diff --git a/docs/components/interfaces/PromptBlueprint.html b/docs/components/interfaces/PromptBlueprint.html new file mode 100644 index 0000000..471d81a --- /dev/null +++ b/docs/components/interfaces/PromptBlueprint.html @@ -0,0 +1,6 @@ +PromptBlueprint | ART Framework API Docs
                                                                                                                                                                                                                    ART Framework API Docs
                                                                                                                                                                                                                      Preparing search index...

                                                                                                                                                                                                                      Interface PromptBlueprint

                                                                                                                                                                                                                      Represents a Mustache template that can be rendered with a PromptContext to produce an ArtStandardPrompt. +Used by the PromptManager.assemblePrompt method.

                                                                                                                                                                                                                      +

                                                                                                                                                                                                                      PromptBlueprint

                                                                                                                                                                                                                      +
                                                                                                                                                                                                                      interface PromptBlueprint {
                                                                                                                                                                                                                          template: string;
                                                                                                                                                                                                                      }
                                                                                                                                                                                                                      Index

                                                                                                                                                                                                                      Properties

                                                                                                                                                                                                                      Properties

                                                                                                                                                                                                                      template: string

                                                                                                                                                                                                                      The Mustache template string that will be rendered with context data to produce a JSON string representing an ArtStandardPrompt

                                                                                                                                                                                                                      +
                                                                                                                                                                                                                      diff --git a/docs/components/interfaces/PromptContext.html b/docs/components/interfaces/PromptContext.html new file mode 100644 index 0000000..97162d9 --- /dev/null +++ b/docs/components/interfaces/PromptContext.html @@ -0,0 +1,22 @@ +PromptContext | ART Framework API Docs
                                                                                                                                                                                                                      ART Framework API Docs
                                                                                                                                                                                                                        Preparing search index...

                                                                                                                                                                                                                        Interface PromptContext

                                                                                                                                                                                                                        Represents the contextual data gathered by Agent Logic (e.g., PESAgent) to be injected +into a Mustache blueprint/template by the PromptManager.assemblePrompt method.

                                                                                                                                                                                                                        +

                                                                                                                                                                                                                        Contains standard fields commonly needed for prompts, plus allows for arbitrary +additional properties required by specific agent blueprints. Agent logic is responsible +for populating this context appropriately before calling assemblePrompt.

                                                                                                                                                                                                                        +

                                                                                                                                                                                                                        PromptContext

                                                                                                                                                                                                                        +
                                                                                                                                                                                                                        interface PromptContext {
                                                                                                                                                                                                                            availableTools?: (ToolSchema & { inputSchemaJson?: string })[];
                                                                                                                                                                                                                            history?: { content: string; role: string; [key: string]: any }[];
                                                                                                                                                                                                                            query?: string;
                                                                                                                                                                                                                            systemPrompt?: string;
                                                                                                                                                                                                                            toolResults?: (ToolResult & { outputJson?: string })[];
                                                                                                                                                                                                                            [key: string]: any;
                                                                                                                                                                                                                        }

                                                                                                                                                                                                                        Indexable

                                                                                                                                                                                                                        • [key: string]: any

                                                                                                                                                                                                                          Allows agent patterns (like PES) to pass any other custom data needed by their specific blueprints (e.g., intent, plan).

                                                                                                                                                                                                                          +
                                                                                                                                                                                                                        Index

                                                                                                                                                                                                                        Properties

                                                                                                                                                                                                                        availableTools?: (ToolSchema & { inputSchemaJson?: string })[]

                                                                                                                                                                                                                        The schemas of the tools available for use, potentially pre-formatted for the blueprint +(e.g., with inputSchemaJson pre-stringified).

                                                                                                                                                                                                                        +
                                                                                                                                                                                                                        history?: { content: string; role: string; [key: string]: any }[]

                                                                                                                                                                                                                        The conversation history, typically formatted as an array suitable for the blueprint +(e.g., array of objects with role and content). Agent logic should pre-format this.

                                                                                                                                                                                                                        +

                                                                                                                                                                                                                        While ArtStandardPrompt could be used, simpler structures might be preferred for blueprints.

                                                                                                                                                                                                                        +
                                                                                                                                                                                                                        query?: string

                                                                                                                                                                                                                        The user's current query or input relevant to this prompt generation step.

                                                                                                                                                                                                                        +
                                                                                                                                                                                                                        systemPrompt?: string

                                                                                                                                                                                                                        The system prompt string to be used (resolved by agent logic from config or defaults).

                                                                                                                                                                                                                        +
                                                                                                                                                                                                                        toolResults?: (ToolResult & { outputJson?: string })[]

                                                                                                                                                                                                                        The results from any tools executed in a previous step, potentially pre-formatted for the blueprint +(e.g., with outputJson pre-stringified).

                                                                                                                                                                                                                        +
                                                                                                                                                                                                                        diff --git a/docs/components/interfaces/PromptManager.html b/docs/components/interfaces/PromptManager.html new file mode 100644 index 0000000..12ed453 --- /dev/null +++ b/docs/components/interfaces/PromptManager.html @@ -0,0 +1,23 @@ +PromptManager | ART Framework API Docs
                                                                                                                                                                                                                        ART Framework API Docs
                                                                                                                                                                                                                          Preparing search index...

                                                                                                                                                                                                                          Interface PromptManager

                                                                                                                                                                                                                          Interface for the stateless prompt assembler. +Uses a blueprint (template) and context provided by Agent Logic +to create a standardized prompt format (ArtStandardPrompt).

                                                                                                                                                                                                                          +
                                                                                                                                                                                                                          interface PromptManager {
                                                                                                                                                                                                                              assemblePrompt(
                                                                                                                                                                                                                                  blueprint: PromptBlueprint,
                                                                                                                                                                                                                                  context: PromptContext,
                                                                                                                                                                                                                              ): Promise<ArtStandardPrompt>;
                                                                                                                                                                                                                              getFragment(name: string, context?: Record<string, any>): string;
                                                                                                                                                                                                                              validatePrompt(prompt: ArtStandardPrompt): ArtStandardPrompt;
                                                                                                                                                                                                                          }
                                                                                                                                                                                                                          Index

                                                                                                                                                                                                                          Methods

                                                                                                                                                                                                                          • Assembles a prompt using a Mustache template (blueprint) and context data. +Renders the template with the provided context and parses the result as an ArtStandardPrompt.

                                                                                                                                                                                                                            +

                                                                                                                                                                                                                            Parameters

                                                                                                                                                                                                                            • blueprint: PromptBlueprint

                                                                                                                                                                                                                              The Mustache template containing the prompt structure.

                                                                                                                                                                                                                              +
                                                                                                                                                                                                                            • context: PromptContext

                                                                                                                                                                                                                              The context data to inject into the template.

                                                                                                                                                                                                                              +

                                                                                                                                                                                                                            Returns Promise<ArtStandardPrompt>

                                                                                                                                                                                                                            A promise resolving to the assembled ArtStandardPrompt.

                                                                                                                                                                                                                            +

                                                                                                                                                                                                                            If template rendering or JSON parsing fails.

                                                                                                                                                                                                                            +
                                                                                                                                                                                                                          • Retrieves a named prompt fragment (e.g., a piece of instruction text). +Optionally allows for simple variable substitution if the fragment is a basic template.

                                                                                                                                                                                                                            +

                                                                                                                                                                                                                            Parameters

                                                                                                                                                                                                                            • name: string

                                                                                                                                                                                                                              The unique identifier for the fragment.

                                                                                                                                                                                                                              +
                                                                                                                                                                                                                            • Optionalcontext: Record<string, any>

                                                                                                                                                                                                                              Optional data for simple variable substitution within the fragment.

                                                                                                                                                                                                                              +

                                                                                                                                                                                                                            Returns string

                                                                                                                                                                                                                            The processed prompt fragment string.

                                                                                                                                                                                                                            +

                                                                                                                                                                                                                            If the fragment is not found.

                                                                                                                                                                                                                            +
                                                                                                                                                                                                                          diff --git a/docs/components/interfaces/ProviderAdapter.html b/docs/components/interfaces/ProviderAdapter.html new file mode 100644 index 0000000..deea5f6 --- /dev/null +++ b/docs/components/interfaces/ProviderAdapter.html @@ -0,0 +1,19 @@ +ProviderAdapter | ART Framework API Docs
                                                                                                                                                                                                                          ART Framework API Docs
                                                                                                                                                                                                                            Preparing search index...

                                                                                                                                                                                                                            Interface ProviderAdapter

                                                                                                                                                                                                                            Base interface for LLM Provider Adapters, extending the core ReasoningEngine. +Implementations will handle provider-specific API calls, authentication, etc.

                                                                                                                                                                                                                            +
                                                                                                                                                                                                                            interface ProviderAdapter {
                                                                                                                                                                                                                                providerName: string;
                                                                                                                                                                                                                                call(
                                                                                                                                                                                                                                    prompt: ArtStandardPrompt,
                                                                                                                                                                                                                                    options: CallOptions,
                                                                                                                                                                                                                                ): Promise<AsyncIterable<StreamEvent, any, any>>;
                                                                                                                                                                                                                                shutdown(): Promise<void>;
                                                                                                                                                                                                                            }

                                                                                                                                                                                                                            Hierarchy (View Summary)

                                                                                                                                                                                                                            Implemented by

                                                                                                                                                                                                                            Index

                                                                                                                                                                                                                            Properties

                                                                                                                                                                                                                            Methods

                                                                                                                                                                                                                            Properties

                                                                                                                                                                                                                            providerName: string

                                                                                                                                                                                                                            The unique identifier name for this provider (e.g., 'openai', 'anthropic').

                                                                                                                                                                                                                            +

                                                                                                                                                                                                                            Methods

                                                                                                                                                                                                                            • Executes a call to the configured Large Language Model (LLM). +This method is typically implemented by a specific ProviderAdapter. +When streaming is requested via options.stream, it returns an AsyncIterable +that yields StreamEvent objects as they are generated by the LLM provider. +When streaming is not requested, it should still return an AsyncIterable +that yields a minimal sequence of events (e.g., a single TOKEN event with the full response, +a METADATA event if available, and an END event).

                                                                                                                                                                                                                              +

                                                                                                                                                                                                                              Parameters

                                                                                                                                                                                                                              • prompt: ArtStandardPrompt

                                                                                                                                                                                                                                The prompt to send to the LLM, potentially formatted specifically for the provider.

                                                                                                                                                                                                                                +
                                                                                                                                                                                                                              • options: CallOptions

                                                                                                                                                                                                                                Options controlling the LLM call, including mandatory threadId, tracing IDs, model parameters (like temperature), streaming preference, and call context.

                                                                                                                                                                                                                                +

                                                                                                                                                                                                                              Returns Promise<AsyncIterable<StreamEvent, any, any>>

                                                                                                                                                                                                                              A promise resolving to an AsyncIterable of StreamEvent objects.

                                                                                                                                                                                                                              +

                                                                                                                                                                                                                              If a critical error occurs during the initial call setup or if the stream itself errors out (typically code LLM_PROVIDER_ERROR).

                                                                                                                                                                                                                              +
                                                                                                                                                                                                                            diff --git a/docs/components/interfaces/ProviderManagerConfig.html b/docs/components/interfaces/ProviderManagerConfig.html new file mode 100644 index 0000000..f5687c5 --- /dev/null +++ b/docs/components/interfaces/ProviderManagerConfig.html @@ -0,0 +1,8 @@ +ProviderManagerConfig | ART Framework API Docs
                                                                                                                                                                                                                            ART Framework API Docs
                                                                                                                                                                                                                              Preparing search index...

                                                                                                                                                                                                                              Interface ProviderManagerConfig

                                                                                                                                                                                                                              Configuration for the ProviderManager passed during ART initialization.

                                                                                                                                                                                                                              +

                                                                                                                                                                                                                              ProviderManagerConfig

                                                                                                                                                                                                                              +
                                                                                                                                                                                                                              interface ProviderManagerConfig {
                                                                                                                                                                                                                                  apiInstanceIdleTimeoutSeconds?: number;
                                                                                                                                                                                                                                  availableProviders: AvailableProviderEntry[];
                                                                                                                                                                                                                                  maxParallelApiInstancesPerProvider?: number;
                                                                                                                                                                                                                              }
                                                                                                                                                                                                                              Index

                                                                                                                                                                                                                              Properties

                                                                                                                                                                                                                              apiInstanceIdleTimeoutSeconds?: number

                                                                                                                                                                                                                              Time in seconds an API adapter instance can be idle before being eligible for removal. Default: 300.

                                                                                                                                                                                                                              +
                                                                                                                                                                                                                              availableProviders: AvailableProviderEntry[]
                                                                                                                                                                                                                              maxParallelApiInstancesPerProvider?: number

                                                                                                                                                                                                                              Max concurrent ACTIVE instances per API-based provider NAME. Default: 5.

                                                                                                                                                                                                                              +
                                                                                                                                                                                                                              diff --git a/docs/components/interfaces/ReasoningEngine.html b/docs/components/interfaces/ReasoningEngine.html new file mode 100644 index 0000000..4dc8dbf --- /dev/null +++ b/docs/components/interfaces/ReasoningEngine.html @@ -0,0 +1,14 @@ +ReasoningEngine | ART Framework API Docs
                                                                                                                                                                                                                              ART Framework API Docs
                                                                                                                                                                                                                                Preparing search index...

                                                                                                                                                                                                                                Interface ReasoningEngine

                                                                                                                                                                                                                                Interface for the component responsible for interacting with LLMs.

                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                interface ReasoningEngine {
                                                                                                                                                                                                                                    call(
                                                                                                                                                                                                                                        prompt: ArtStandardPrompt,
                                                                                                                                                                                                                                        options: CallOptions,
                                                                                                                                                                                                                                    ): Promise<AsyncIterable<StreamEvent, any, any>>;
                                                                                                                                                                                                                                }

                                                                                                                                                                                                                                Hierarchy (View Summary)

                                                                                                                                                                                                                                Index

                                                                                                                                                                                                                                Methods

                                                                                                                                                                                                                                Methods

                                                                                                                                                                                                                                • Executes a call to the configured Large Language Model (LLM). +This method is typically implemented by a specific ProviderAdapter. +When streaming is requested via options.stream, it returns an AsyncIterable +that yields StreamEvent objects as they are generated by the LLM provider. +When streaming is not requested, it should still return an AsyncIterable +that yields a minimal sequence of events (e.g., a single TOKEN event with the full response, +a METADATA event if available, and an END event).

                                                                                                                                                                                                                                  +

                                                                                                                                                                                                                                  Parameters

                                                                                                                                                                                                                                  • prompt: ArtStandardPrompt

                                                                                                                                                                                                                                    The prompt to send to the LLM, potentially formatted specifically for the provider.

                                                                                                                                                                                                                                    +
                                                                                                                                                                                                                                  • options: CallOptions

                                                                                                                                                                                                                                    Options controlling the LLM call, including mandatory threadId, tracing IDs, model parameters (like temperature), streaming preference, and call context.

                                                                                                                                                                                                                                    +

                                                                                                                                                                                                                                  Returns Promise<AsyncIterable<StreamEvent, any, any>>

                                                                                                                                                                                                                                  A promise resolving to an AsyncIterable of StreamEvent objects.

                                                                                                                                                                                                                                  +

                                                                                                                                                                                                                                  If a critical error occurs during the initial call setup or if the stream itself errors out (typically code LLM_PROVIDER_ERROR).

                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                diff --git a/docs/components/interfaces/RuntimeProviderConfig.html b/docs/components/interfaces/RuntimeProviderConfig.html new file mode 100644 index 0000000..f598815 --- /dev/null +++ b/docs/components/interfaces/RuntimeProviderConfig.html @@ -0,0 +1,9 @@ +RuntimeProviderConfig | ART Framework API Docs
                                                                                                                                                                                                                                ART Framework API Docs
                                                                                                                                                                                                                                  Preparing search index...

                                                                                                                                                                                                                                  Interface RuntimeProviderConfig

                                                                                                                                                                                                                                  Configuration passed AT RUNTIME for a specific LLM call.

                                                                                                                                                                                                                                  +

                                                                                                                                                                                                                                  RuntimeProviderConfig

                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                  interface RuntimeProviderConfig {
                                                                                                                                                                                                                                      adapterOptions: any;
                                                                                                                                                                                                                                      modelId: string;
                                                                                                                                                                                                                                      providerName: string;
                                                                                                                                                                                                                                  }
                                                                                                                                                                                                                                  Index

                                                                                                                                                                                                                                  Properties

                                                                                                                                                                                                                                  adapterOptions: any

                                                                                                                                                                                                                                  Specific options for THIS instance (apiKey, temperature, contextSize, baseUrl, etc.).

                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                  modelId: string

                                                                                                                                                                                                                                  Specific model identifier (e.g., 'gpt-4o', 'llama3:latest').

                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                  providerName: string

                                                                                                                                                                                                                                  Must match a name in AvailableProviderEntry.

                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                  diff --git a/docs/components/interfaces/StageSpecificPrompts.html b/docs/components/interfaces/StageSpecificPrompts.html new file mode 100644 index 0000000..8e1b9a0 --- /dev/null +++ b/docs/components/interfaces/StageSpecificPrompts.html @@ -0,0 +1,9 @@ +StageSpecificPrompts | ART Framework API Docs
                                                                                                                                                                                                                                  ART Framework API Docs
                                                                                                                                                                                                                                    Preparing search index...

                                                                                                                                                                                                                                    Interface StageSpecificPrompts

                                                                                                                                                                                                                                    Defines stage-specific system prompts for planning and synthesis.

                                                                                                                                                                                                                                    +

                                                                                                                                                                                                                                    StageSpecificPrompts

                                                                                                                                                                                                                                    +
                                                                                                                                                                                                                                    interface StageSpecificPrompts {
                                                                                                                                                                                                                                        planning?: string;
                                                                                                                                                                                                                                        synthesis?: string;
                                                                                                                                                                                                                                    }
                                                                                                                                                                                                                                    Index

                                                                                                                                                                                                                                    Properties

                                                                                                                                                                                                                                    Properties

                                                                                                                                                                                                                                    planning?: string

                                                                                                                                                                                                                                    System prompt to guide the planning phase. +Focuses on reasoning, expertise, and tool selection.

                                                                                                                                                                                                                                    +
                                                                                                                                                                                                                                    synthesis?: string

                                                                                                                                                                                                                                    System prompt to guide the synthesis phase. +Focuses on tone, formatting, and final response structure.

                                                                                                                                                                                                                                    +
                                                                                                                                                                                                                                    diff --git a/docs/components/interfaces/StorageAdapter.html b/docs/components/interfaces/StorageAdapter.html new file mode 100644 index 0000000..b39f771 --- /dev/null +++ b/docs/components/interfaces/StorageAdapter.html @@ -0,0 +1,27 @@ +StorageAdapter | ART Framework API Docs
                                                                                                                                                                                                                                    ART Framework API Docs
                                                                                                                                                                                                                                      Preparing search index...

                                                                                                                                                                                                                                      Interface StorageAdapter

                                                                                                                                                                                                                                      Interface for a storage adapter, providing a generic persistence layer.

                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                      interface StorageAdapter {
                                                                                                                                                                                                                                          clearAll(): Promise<void>;
                                                                                                                                                                                                                                          clearCollection(collection: string): Promise<void>;
                                                                                                                                                                                                                                          delete(collection: string, id: string): Promise<void>;
                                                                                                                                                                                                                                          get<T>(collection: string, id: string): Promise<null | T>;
                                                                                                                                                                                                                                          init(config?: any): Promise<void>;
                                                                                                                                                                                                                                          query<T>(collection: string, filterOptions: FilterOptions): Promise<T[]>;
                                                                                                                                                                                                                                          set<T>(collection: string, id: string, data: T): Promise<void>;
                                                                                                                                                                                                                                      }

                                                                                                                                                                                                                                      Implemented by

                                                                                                                                                                                                                                      Index

                                                                                                                                                                                                                                      Methods

                                                                                                                                                                                                                                      • Optional: Clears all data managed by the adapter. Use with caution!

                                                                                                                                                                                                                                        +

                                                                                                                                                                                                                                        Returns Promise<void>

                                                                                                                                                                                                                                      • Optional: Clears all items from a specific collection.

                                                                                                                                                                                                                                        +

                                                                                                                                                                                                                                        Parameters

                                                                                                                                                                                                                                        • collection: string

                                                                                                                                                                                                                                        Returns Promise<void>

                                                                                                                                                                                                                                      • Deletes an item from a collection by its ID.

                                                                                                                                                                                                                                        +

                                                                                                                                                                                                                                        Parameters

                                                                                                                                                                                                                                        • collection: string

                                                                                                                                                                                                                                          The name of the collection.

                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                        • id: string

                                                                                                                                                                                                                                          The unique ID of the item.

                                                                                                                                                                                                                                          +

                                                                                                                                                                                                                                        Returns Promise<void>

                                                                                                                                                                                                                                      • Retrieves a single item from a collection by its ID.

                                                                                                                                                                                                                                        +

                                                                                                                                                                                                                                        Type Parameters

                                                                                                                                                                                                                                        • T

                                                                                                                                                                                                                                        Parameters

                                                                                                                                                                                                                                        • collection: string

                                                                                                                                                                                                                                          The name of the data collection (e.g., 'conversations', 'observations').

                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                        • id: string

                                                                                                                                                                                                                                          The unique ID of the item.

                                                                                                                                                                                                                                          +

                                                                                                                                                                                                                                        Returns Promise<null | T>

                                                                                                                                                                                                                                        The item or null if not found.

                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                      • Optional initialization method (e.g., connecting to DB).

                                                                                                                                                                                                                                        +

                                                                                                                                                                                                                                        Parameters

                                                                                                                                                                                                                                        • Optionalconfig: any

                                                                                                                                                                                                                                        Returns Promise<void>

                                                                                                                                                                                                                                      • Queries items in a collection based on filter options.

                                                                                                                                                                                                                                        +

                                                                                                                                                                                                                                        Type Parameters

                                                                                                                                                                                                                                        • T

                                                                                                                                                                                                                                        Parameters

                                                                                                                                                                                                                                        • collection: string

                                                                                                                                                                                                                                          The name of the collection.

                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                        • filterOptions: FilterOptions

                                                                                                                                                                                                                                          Filtering, sorting, and pagination options.

                                                                                                                                                                                                                                          +

                                                                                                                                                                                                                                        Returns Promise<T[]>

                                                                                                                                                                                                                                        An array of matching items.

                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                      • Saves (creates or updates) an item in a collection.

                                                                                                                                                                                                                                        +

                                                                                                                                                                                                                                        Type Parameters

                                                                                                                                                                                                                                        • T

                                                                                                                                                                                                                                        Parameters

                                                                                                                                                                                                                                        • collection: string

                                                                                                                                                                                                                                          The name of the collection.

                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                        • id: string

                                                                                                                                                                                                                                          The unique ID of the item.

                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                        • data: T

                                                                                                                                                                                                                                          The data to save.

                                                                                                                                                                                                                                          +

                                                                                                                                                                                                                                        Returns Promise<void>

                                                                                                                                                                                                                                      diff --git a/docs/components/interfaces/StreamEvent.html b/docs/components/interfaces/StreamEvent.html new file mode 100644 index 0000000..e4a972a --- /dev/null +++ b/docs/components/interfaces/StreamEvent.html @@ -0,0 +1,43 @@ +StreamEvent | ART Framework API Docs
                                                                                                                                                                                                                                      ART Framework API Docs
                                                                                                                                                                                                                                        Preparing search index...

                                                                                                                                                                                                                                        Interface StreamEvent

                                                                                                                                                                                                                                        Represents a single event emitted from an asynchronous LLM stream (ReasoningEngine.call).

                                                                                                                                                                                                                                        +

                                                                                                                                                                                                                                        Allows for real-time delivery of tokens, metadata, errors, and lifecycle signals. +Adapters are responsible for translating provider-specific stream chunks into these standard events.

                                                                                                                                                                                                                                        +

                                                                                                                                                                                                                                        StreamEvent

                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                        interface StreamEvent {
                                                                                                                                                                                                                                            data: any;
                                                                                                                                                                                                                                            sessionId?: string;
                                                                                                                                                                                                                                            threadId: string;
                                                                                                                                                                                                                                            tokenType?:
                                                                                                                                                                                                                                                | "LLM_THINKING"
                                                                                                                                                                                                                                                | "LLM_RESPONSE"
                                                                                                                                                                                                                                                | "AGENT_THOUGHT_LLM_THINKING"
                                                                                                                                                                                                                                                | "AGENT_THOUGHT_LLM_RESPONSE"
                                                                                                                                                                                                                                                | "FINAL_SYNTHESIS_LLM_THINKING"
                                                                                                                                                                                                                                                | "FINAL_SYNTHESIS_LLM_RESPONSE";
                                                                                                                                                                                                                                            traceId: string;
                                                                                                                                                                                                                                            type: "TOKEN"
                                                                                                                                                                                                                                            | "METADATA"
                                                                                                                                                                                                                                            | "ERROR"
                                                                                                                                                                                                                                            | "END";
                                                                                                                                                                                                                                        }
                                                                                                                                                                                                                                        Index

                                                                                                                                                                                                                                        Properties

                                                                                                                                                                                                                                        data: any

                                                                                                                                                                                                                                        The actual content of the event.

                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                        • For TOKEN: string (the text chunk).
                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                        • For METADATA: LLMMetadata object.
                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                        • For ERROR: Error object or error details.
                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                        • For END: null.
                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                        sessionId?: string

                                                                                                                                                                                                                                        Optional identifier linking the event to a specific UI tab/window.

                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                        threadId: string

                                                                                                                                                                                                                                        The identifier of the conversation thread this event belongs to.

                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                        tokenType?:
                                                                                                                                                                                                                                            | "LLM_THINKING"
                                                                                                                                                                                                                                            | "LLM_RESPONSE"
                                                                                                                                                                                                                                            | "AGENT_THOUGHT_LLM_THINKING"
                                                                                                                                                                                                                                            | "AGENT_THOUGHT_LLM_RESPONSE"
                                                                                                                                                                                                                                            | "FINAL_SYNTHESIS_LLM_THINKING"
                                                                                                                                                                                                                                            | "FINAL_SYNTHESIS_LLM_RESPONSE"

                                                                                                                                                                                                                                        Optional: Provides a more specific classification for TOKEN events, +combining LLM-level detection (thinking/response, if available from adapter) +and agent-level context (callContext from CallOptions). +Used by consumers (like UI) to differentiate between intermediate thoughts and the final response.

                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                        • LLM_THINKING: Token identified by the adapter as part of the LLM's internal reasoning/thought process.
                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                        • LLM_RESPONSE: Token identified by the adapter as part of the LLM's final response content.
                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                        • AGENT_THOUGHT_LLM_THINKING: Token from an LLM call made in the 'AGENT_THOUGHT' context, identified as thinking.
                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                        • AGENT_THOUGHT_LLM_RESPONSE: Token from an LLM call made in the 'AGENT_THOUGHT' context, identified as response (e.g., the raw planning output).
                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                        • FINAL_SYNTHESIS_LLM_THINKING: Token from an LLM call made in the 'FINAL_SYNTHESIS' context, identified as thinking.
                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                        • FINAL_SYNTHESIS_LLM_RESPONSE: Token from an LLM call made in the 'FINAL_SYNTHESIS' context, identified as response (part of the final answer to the user).
                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                        +

                                                                                                                                                                                                                                        Not all adapters can reliably distinguish 'LLM_THINKING' vs 'LLM_RESPONSE'. +Adapters should prioritize setting the agent context part (AGENT_THOUGHT_... or FINAL_SYNTHESIS_...) based on CallOptions.callContext. +If thinking detection is unavailable, adapters should default to AGENT_THOUGHT_LLM_RESPONSE or FINAL_SYNTHESIS_LLM_RESPONSE.

                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                        traceId: string

                                                                                                                                                                                                                                        The identifier tracing the specific agent execution cycle this event is part of.

                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                        type: "TOKEN" | "METADATA" | "ERROR" | "END"

                                                                                                                                                                                                                                        The type of the stream event.

                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                        • TOKEN: A chunk of text generated by the LLM.
                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                        • METADATA: Information about the LLM call (e.g., token counts, stop reason), typically sent once at the end.
                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                        • ERROR: An error occurred during the LLM call or stream processing. data will contain the Error object.
                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                        • END: Signals the successful completion of the stream. data is typically null.
                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                        diff --git a/docs/components/interfaces/SystemPromptOverride.html b/docs/components/interfaces/SystemPromptOverride.html new file mode 100644 index 0000000..71c5b07 --- /dev/null +++ b/docs/components/interfaces/SystemPromptOverride.html @@ -0,0 +1,12 @@ +SystemPromptOverride | ART Framework API Docs
                                                                                                                                                                                                                                        ART Framework API Docs
                                                                                                                                                                                                                                          Preparing search index...

                                                                                                                                                                                                                                          Interface SystemPromptOverride

                                                                                                                                                                                                                                          Override provided at instance/thread/call level to select a tag and/or provide variables, +or to provide freeform content and a merge strategy.

                                                                                                                                                                                                                                          +

                                                                                                                                                                                                                                          SystemPromptOverride

                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                          interface SystemPromptOverride {
                                                                                                                                                                                                                                              content?: string;
                                                                                                                                                                                                                                              strategy?: SystemPromptMergeStrategy;
                                                                                                                                                                                                                                              tag?: string;
                                                                                                                                                                                                                                              variables?: Record<string, any>;
                                                                                                                                                                                                                                          }
                                                                                                                                                                                                                                          Index

                                                                                                                                                                                                                                          Properties

                                                                                                                                                                                                                                          content?: string

                                                                                                                                                                                                                                          Freeform content to apply directly (escape hatch).

                                                                                                                                                                                                                                          +

                                                                                                                                                                                                                                          Merge behavior against previous level: append | prepend.

                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                          tag?: string

                                                                                                                                                                                                                                          Preset tag from the registry (e.g., 'default', 'legal_advisor').

                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                          variables?: Record<string, any>

                                                                                                                                                                                                                                          Variables to substitute in the selected template.

                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                          diff --git a/docs/components/interfaces/SystemPromptResolver.html b/docs/components/interfaces/SystemPromptResolver.html new file mode 100644 index 0000000..05070cf --- /dev/null +++ b/docs/components/interfaces/SystemPromptResolver.html @@ -0,0 +1,4 @@ +SystemPromptResolver | ART Framework API Docs
                                                                                                                                                                                                                                          ART Framework API Docs
                                                                                                                                                                                                                                            Preparing search index...

                                                                                                                                                                                                                                            Interface SystemPromptResolver

                                                                                                                                                                                                                                            Resolves the final system prompt from base + instance/thread/call overrides +using tag+variables and merge strategies.

                                                                                                                                                                                                                                            +
                                                                                                                                                                                                                                            interface SystemPromptResolver {
                                                                                                                                                                                                                                                resolve(
                                                                                                                                                                                                                                                    input: {
                                                                                                                                                                                                                                                        base: string;
                                                                                                                                                                                                                                                        call?: string | SystemPromptOverride;
                                                                                                                                                                                                                                                        instance?: string | SystemPromptOverride;
                                                                                                                                                                                                                                                        thread?: string | SystemPromptOverride;
                                                                                                                                                                                                                                                    },
                                                                                                                                                                                                                                                    traceId?: string,
                                                                                                                                                                                                                                                ): Promise<string>;
                                                                                                                                                                                                                                            }
                                                                                                                                                                                                                                            Index

                                                                                                                                                                                                                                            Methods

                                                                                                                                                                                                                                            Methods

                                                                                                                                                                                                                                            diff --git a/docs/components/interfaces/SystemPromptSpec.html b/docs/components/interfaces/SystemPromptSpec.html new file mode 100644 index 0000000..90a368e --- /dev/null +++ b/docs/components/interfaces/SystemPromptSpec.html @@ -0,0 +1,11 @@ +SystemPromptSpec | ART Framework API Docs
                                                                                                                                                                                                                                            ART Framework API Docs
                                                                                                                                                                                                                                              Preparing search index...

                                                                                                                                                                                                                                              Interface SystemPromptSpec

                                                                                                                                                                                                                                              Named preset for system prompts, supporting variables and a default merge strategy.

                                                                                                                                                                                                                                              +

                                                                                                                                                                                                                                              SystemPromptSpec

                                                                                                                                                                                                                                              +
                                                                                                                                                                                                                                              interface SystemPromptSpec {
                                                                                                                                                                                                                                                  defaultVariables?: Record<string, any>;
                                                                                                                                                                                                                                                  id?: string;
                                                                                                                                                                                                                                                  mergeStrategy?: SystemPromptMergeStrategy;
                                                                                                                                                                                                                                                  template: string;
                                                                                                                                                                                                                                              }
                                                                                                                                                                                                                                              Index

                                                                                                                                                                                                                                              Properties

                                                                                                                                                                                                                                              defaultVariables?: Record<string, any>

                                                                                                                                                                                                                                              Default variables applied if not provided at use time.

                                                                                                                                                                                                                                              +
                                                                                                                                                                                                                                              id?: string

                                                                                                                                                                                                                                              Optional explicit ID; when in a registry map, the key is typically the tag.

                                                                                                                                                                                                                                              +

                                                                                                                                                                                                                                              Default strategy to combine this spec with lower levels. Defaults to 'append'.

                                                                                                                                                                                                                                              +
                                                                                                                                                                                                                                              template: string

                                                                                                                                                                                                                                              Template string. Supports simple {{variable}} placeholders and {{fragment:name}} for PromptManager fragments.

                                                                                                                                                                                                                                              +
                                                                                                                                                                                                                                              diff --git a/docs/components/interfaces/SystemPromptsRegistry.html b/docs/components/interfaces/SystemPromptsRegistry.html new file mode 100644 index 0000000..7a00fcd --- /dev/null +++ b/docs/components/interfaces/SystemPromptsRegistry.html @@ -0,0 +1,7 @@ +SystemPromptsRegistry | ART Framework API Docs
                                                                                                                                                                                                                                              ART Framework API Docs
                                                                                                                                                                                                                                                Preparing search index...

                                                                                                                                                                                                                                                Interface SystemPromptsRegistry

                                                                                                                                                                                                                                                Registry of available system prompt presets (tags) at the instance level.

                                                                                                                                                                                                                                                +

                                                                                                                                                                                                                                                SystemPromptsRegistry

                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                interface SystemPromptsRegistry {
                                                                                                                                                                                                                                                    defaultTag?: string;
                                                                                                                                                                                                                                                    specs: Record<string, SystemPromptSpec>;
                                                                                                                                                                                                                                                }
                                                                                                                                                                                                                                                Index

                                                                                                                                                                                                                                                Properties

                                                                                                                                                                                                                                                Properties

                                                                                                                                                                                                                                                defaultTag?: string

                                                                                                                                                                                                                                                Tag to use when no other tag is specified.

                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                specs: Record<string, SystemPromptSpec>

                                                                                                                                                                                                                                                Mapping of tag -> spec.

                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                diff --git a/docs/components/interfaces/TaskDelegationConfig.html b/docs/components/interfaces/TaskDelegationConfig.html new file mode 100644 index 0000000..ef8d7a6 --- /dev/null +++ b/docs/components/interfaces/TaskDelegationConfig.html @@ -0,0 +1,12 @@ +TaskDelegationConfig | ART Framework API Docs
                                                                                                                                                                                                                                                ART Framework API Docs
                                                                                                                                                                                                                                                  Preparing search index...

                                                                                                                                                                                                                                                  Interface TaskDelegationConfig

                                                                                                                                                                                                                                                  Configuration options for the TaskDelegationService

                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                  interface TaskDelegationConfig {
                                                                                                                                                                                                                                                      callbackUrl?: string;
                                                                                                                                                                                                                                                      defaultTimeoutMs?: number;
                                                                                                                                                                                                                                                      maxRetries?: number;
                                                                                                                                                                                                                                                      retryDelayMs?: number;
                                                                                                                                                                                                                                                      useExponentialBackoff?: boolean;
                                                                                                                                                                                                                                                  }
                                                                                                                                                                                                                                                  Index

                                                                                                                                                                                                                                                  Properties

                                                                                                                                                                                                                                                  callbackUrl?: string

                                                                                                                                                                                                                                                  The base callback URL for receiving A2A task updates.

                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                  defaultTimeoutMs?: number

                                                                                                                                                                                                                                                  Default timeout for task delegation requests in milliseconds

                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                  maxRetries?: number

                                                                                                                                                                                                                                                  Maximum number of retry attempts for failed requests

                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                  retryDelayMs?: number

                                                                                                                                                                                                                                                  Base delay between retry attempts in milliseconds

                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                  useExponentialBackoff?: boolean

                                                                                                                                                                                                                                                  Whether to use exponential backoff for retries

                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                  diff --git a/docs/components/interfaces/TaskStatusResponse.html b/docs/components/interfaces/TaskStatusResponse.html new file mode 100644 index 0000000..1a80f47 --- /dev/null +++ b/docs/components/interfaces/TaskStatusResponse.html @@ -0,0 +1,14 @@ +TaskStatusResponse | ART Framework API Docs
                                                                                                                                                                                                                                                  ART Framework API Docs
                                                                                                                                                                                                                                                    Preparing search index...

                                                                                                                                                                                                                                                    Interface TaskStatusResponse

                                                                                                                                                                                                                                                    Response structure for A2A task status queries

                                                                                                                                                                                                                                                    +
                                                                                                                                                                                                                                                    interface TaskStatusResponse {
                                                                                                                                                                                                                                                        error?: string;
                                                                                                                                                                                                                                                        metadata?: Record<string, any>;
                                                                                                                                                                                                                                                        progress?: number;
                                                                                                                                                                                                                                                        result?: A2ATaskResult;
                                                                                                                                                                                                                                                        status: A2ATaskStatus;
                                                                                                                                                                                                                                                        taskId: string;
                                                                                                                                                                                                                                                    }
                                                                                                                                                                                                                                                    Index

                                                                                                                                                                                                                                                    Properties

                                                                                                                                                                                                                                                    error?: string

                                                                                                                                                                                                                                                    Error information if failed

                                                                                                                                                                                                                                                    +
                                                                                                                                                                                                                                                    metadata?: Record<string, any>

                                                                                                                                                                                                                                                    Additional metadata

                                                                                                                                                                                                                                                    +
                                                                                                                                                                                                                                                    progress?: number

                                                                                                                                                                                                                                                    Progress percentage (0-100) if available

                                                                                                                                                                                                                                                    +
                                                                                                                                                                                                                                                    result?: A2ATaskResult

                                                                                                                                                                                                                                                    Task result if completed

                                                                                                                                                                                                                                                    +

                                                                                                                                                                                                                                                    Current status of the task

                                                                                                                                                                                                                                                    +
                                                                                                                                                                                                                                                    taskId: string

                                                                                                                                                                                                                                                    The task ID

                                                                                                                                                                                                                                                    +
                                                                                                                                                                                                                                                    diff --git a/docs/components/interfaces/ThreadConfig.html b/docs/components/interfaces/ThreadConfig.html new file mode 100644 index 0000000..bb0bfb5 --- /dev/null +++ b/docs/components/interfaces/ThreadConfig.html @@ -0,0 +1,14 @@ +ThreadConfig | ART Framework API Docs
                                                                                                                                                                                                                                                    ART Framework API Docs
                                                                                                                                                                                                                                                      Preparing search index...

                                                                                                                                                                                                                                                      Interface ThreadConfig

                                                                                                                                                                                                                                                      Configuration specific to a conversation thread.

                                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                                      ThreadConfig

                                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                                      interface ThreadConfig {
                                                                                                                                                                                                                                                          enabledTools: string[];
                                                                                                                                                                                                                                                          historyLimit: number;
                                                                                                                                                                                                                                                          persona?: Partial<AgentPersona>;
                                                                                                                                                                                                                                                          providerConfig: RuntimeProviderConfig;
                                                                                                                                                                                                                                                          systemPrompt?: string | SystemPromptOverride;
                                                                                                                                                                                                                                                      }
                                                                                                                                                                                                                                                      Index

                                                                                                                                                                                                                                                      Properties

                                                                                                                                                                                                                                                      enabledTools: string[]

                                                                                                                                                                                                                                                      An array of tool names (matching ToolSchema.name) that are permitted for use within this thread.

                                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                                      historyLimit: number

                                                                                                                                                                                                                                                      The maximum number of past messages (ConversationMessage objects) to retrieve for context.

                                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                                      persona?: Partial<AgentPersona>

                                                                                                                                                                                                                                                      Optional: Defines the identity and high-level guidance for the agent for this specific thread. +This overrides the instance-level persona.

                                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                                      providerConfig: RuntimeProviderConfig

                                                                                                                                                                                                                                                      Default provider configuration for this thread.

                                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                                      systemPrompt?: string | SystemPromptOverride

                                                                                                                                                                                                                                                      Optional system prompt override to be used for this thread, overriding instance or agent defaults.

                                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                                      diff --git a/docs/components/interfaces/ThreadContext.html b/docs/components/interfaces/ThreadContext.html new file mode 100644 index 0000000..d07fa22 --- /dev/null +++ b/docs/components/interfaces/ThreadContext.html @@ -0,0 +1,7 @@ +ThreadContext | ART Framework API Docs
                                                                                                                                                                                                                                                      ART Framework API Docs
                                                                                                                                                                                                                                                        Preparing search index...

                                                                                                                                                                                                                                                        Interface ThreadContext

                                                                                                                                                                                                                                                        Encapsulates the configuration and state for a specific thread.

                                                                                                                                                                                                                                                        +

                                                                                                                                                                                                                                                        ThreadContext

                                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                                        interface ThreadContext {
                                                                                                                                                                                                                                                            config: ThreadConfig;
                                                                                                                                                                                                                                                            state: null | AgentState;
                                                                                                                                                                                                                                                        }
                                                                                                                                                                                                                                                        Index

                                                                                                                                                                                                                                                        Properties

                                                                                                                                                                                                                                                        Properties

                                                                                                                                                                                                                                                        config: ThreadConfig

                                                                                                                                                                                                                                                        The configuration settings (ThreadConfig) currently active for the thread.

                                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                                        state: null | AgentState

                                                                                                                                                                                                                                                        The persistent state (AgentState) associated with the thread, or null if no state exists.

                                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                                        diff --git a/docs/components/interfaces/ToolResult.html b/docs/components/interfaces/ToolResult.html new file mode 100644 index 0000000..da2de6c --- /dev/null +++ b/docs/components/interfaces/ToolResult.html @@ -0,0 +1,15 @@ +ToolResult | ART Framework API Docs
                                                                                                                                                                                                                                                        ART Framework API Docs
                                                                                                                                                                                                                                                          Preparing search index...

                                                                                                                                                                                                                                                          Interface ToolResult

                                                                                                                                                                                                                                                          Represents the structured result of a tool execution.

                                                                                                                                                                                                                                                          +

                                                                                                                                                                                                                                                          ToolResult

                                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                                          interface ToolResult {
                                                                                                                                                                                                                                                              callId: string;
                                                                                                                                                                                                                                                              error?: string;
                                                                                                                                                                                                                                                              metadata?: {
                                                                                                                                                                                                                                                                  sources?: { sourceName: string; url?: string; [key: string]: any }[];
                                                                                                                                                                                                                                                                  [key: string]: any;
                                                                                                                                                                                                                                                              };
                                                                                                                                                                                                                                                              output?: any;
                                                                                                                                                                                                                                                              status: "error"
                                                                                                                                                                                                                                                              | "success";
                                                                                                                                                                                                                                                              toolName: string;
                                                                                                                                                                                                                                                          }
                                                                                                                                                                                                                                                          Index

                                                                                                                                                                                                                                                          Properties

                                                                                                                                                                                                                                                          callId: string

                                                                                                                                                                                                                                                          The unique identifier of the corresponding ParsedToolCall that initiated this execution attempt.

                                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                                          error?: string

                                                                                                                                                                                                                                                          A descriptive error message if the execution failed (status is 'error').

                                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                                          metadata?: {
                                                                                                                                                                                                                                                              sources?: { sourceName: string; url?: string; [key: string]: any }[];
                                                                                                                                                                                                                                                              [key: string]: any;
                                                                                                                                                                                                                                                          }

                                                                                                                                                                                                                                                          Optional metadata about the execution (e.g., duration, cost, logs).

                                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                                          output?: any

                                                                                                                                                                                                                                                          The data returned by the tool upon successful execution. Structure may be validated against outputSchema.

                                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                                          status: "error" | "success"

                                                                                                                                                                                                                                                          Indicates whether the tool execution succeeded or failed.

                                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                                          toolName: string

                                                                                                                                                                                                                                                          The name of the tool that was executed.

                                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                                          diff --git a/docs/components/interfaces/ToolSchema.html b/docs/components/interfaces/ToolSchema.html new file mode 100644 index 0000000..0bf7a70 --- /dev/null +++ b/docs/components/interfaces/ToolSchema.html @@ -0,0 +1,14 @@ +ToolSchema | ART Framework API Docs
                                                                                                                                                                                                                                                          ART Framework API Docs
                                                                                                                                                                                                                                                            Preparing search index...

                                                                                                                                                                                                                                                            Interface ToolSchema

                                                                                                                                                                                                                                                            Defines the schema for a tool, including its input parameters. +Uses JSON Schema format for inputSchema.

                                                                                                                                                                                                                                                            +

                                                                                                                                                                                                                                                            ToolSchema

                                                                                                                                                                                                                                                            +
                                                                                                                                                                                                                                                            interface ToolSchema {
                                                                                                                                                                                                                                                                description: string;
                                                                                                                                                                                                                                                                examples?: { description?: string; input: any; output?: any }[];
                                                                                                                                                                                                                                                                inputSchema: JsonSchema;
                                                                                                                                                                                                                                                                name: string;
                                                                                                                                                                                                                                                                outputSchema?: JsonSchema;
                                                                                                                                                                                                                                                            }
                                                                                                                                                                                                                                                            Index

                                                                                                                                                                                                                                                            Properties

                                                                                                                                                                                                                                                            description: string

                                                                                                                                                                                                                                                            A clear description of what the tool does, intended for the LLM to understand its purpose and usage.

                                                                                                                                                                                                                                                            +
                                                                                                                                                                                                                                                            examples?: { description?: string; input: any; output?: any }[]

                                                                                                                                                                                                                                                            Optional array of examples demonstrating how to use the tool, useful for few-shot prompting of the LLM.

                                                                                                                                                                                                                                                            +
                                                                                                                                                                                                                                                            inputSchema: JsonSchema

                                                                                                                                                                                                                                                            A JSON Schema object defining the structure, types, and requirements of the input arguments the tool expects.

                                                                                                                                                                                                                                                            +
                                                                                                                                                                                                                                                            name: string

                                                                                                                                                                                                                                                            A unique name identifying the tool (used in LLM prompts and registry lookups). Must be unique.

                                                                                                                                                                                                                                                            +
                                                                                                                                                                                                                                                            outputSchema?: JsonSchema

                                                                                                                                                                                                                                                            An optional JSON Schema object defining the expected structure of the data returned in the output field of a successful ToolResult.

                                                                                                                                                                                                                                                            +
                                                                                                                                                                                                                                                            diff --git a/docs/components/interfaces/ToolSystem.html b/docs/components/interfaces/ToolSystem.html new file mode 100644 index 0000000..009c101 --- /dev/null +++ b/docs/components/interfaces/ToolSystem.html @@ -0,0 +1,9 @@ +ToolSystem | ART Framework API Docs
                                                                                                                                                                                                                                                            ART Framework API Docs
                                                                                                                                                                                                                                                              Preparing search index...

                                                                                                                                                                                                                                                              Interface ToolSystem

                                                                                                                                                                                                                                                              Interface for the system responsible for orchestrating tool execution.

                                                                                                                                                                                                                                                              +
                                                                                                                                                                                                                                                              interface ToolSystem {
                                                                                                                                                                                                                                                                  executeTools(
                                                                                                                                                                                                                                                                      toolCalls: ParsedToolCall[],
                                                                                                                                                                                                                                                                      threadId: string,
                                                                                                                                                                                                                                                                      traceId?: string,
                                                                                                                                                                                                                                                                  ): Promise<ToolResult[]>;
                                                                                                                                                                                                                                                              }
                                                                                                                                                                                                                                                              Index

                                                                                                                                                                                                                                                              Methods

                                                                                                                                                                                                                                                              Methods

                                                                                                                                                                                                                                                              • Orchestrates the execution of a sequence of tool calls determined during the planning phase. +This involves verifying permissions, validating inputs, calling the tool executor, and recording observations.

                                                                                                                                                                                                                                                                +

                                                                                                                                                                                                                                                                Parameters

                                                                                                                                                                                                                                                                • toolCalls: ParsedToolCall[]

                                                                                                                                                                                                                                                                  An array of ParsedToolCall objects generated by the OutputParser.

                                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                                • threadId: string

                                                                                                                                                                                                                                                                  The ID of the current thread, used for context and checking tool permissions via StateManager.

                                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                                • OptionaltraceId: string

                                                                                                                                                                                                                                                                  Optional trace ID for correlating observations.

                                                                                                                                                                                                                                                                  +

                                                                                                                                                                                                                                                                Returns Promise<ToolResult[]>

                                                                                                                                                                                                                                                                A promise resolving to an array of ToolResult objects, one for each attempted tool call (including errors).

                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                              diff --git a/docs/components/interfaces/UpdateA2ATaskRequest.html b/docs/components/interfaces/UpdateA2ATaskRequest.html new file mode 100644 index 0000000..8e13526 --- /dev/null +++ b/docs/components/interfaces/UpdateA2ATaskRequest.html @@ -0,0 +1,13 @@ +UpdateA2ATaskRequest | ART Framework API Docs
                                                                                                                                                                                                                                                              ART Framework API Docs
                                                                                                                                                                                                                                                                Preparing search index...

                                                                                                                                                                                                                                                                Interface UpdateA2ATaskRequest

                                                                                                                                                                                                                                                                Represents an update to an existing A2A task.

                                                                                                                                                                                                                                                                +

                                                                                                                                                                                                                                                                UpdateA2ATaskRequest

                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                interface UpdateA2ATaskRequest {
                                                                                                                                                                                                                                                                    metadata?: Partial<A2ATaskMetadata>;
                                                                                                                                                                                                                                                                    result?: A2ATaskResult;
                                                                                                                                                                                                                                                                    status?: A2ATaskStatus;
                                                                                                                                                                                                                                                                    targetAgent?: A2AAgentInfo;
                                                                                                                                                                                                                                                                    taskId: string;
                                                                                                                                                                                                                                                                }
                                                                                                                                                                                                                                                                Index

                                                                                                                                                                                                                                                                Properties

                                                                                                                                                                                                                                                                metadata?: Partial<A2ATaskMetadata>

                                                                                                                                                                                                                                                                Additional metadata updates.

                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                result?: A2ATaskResult

                                                                                                                                                                                                                                                                Task result (if completing).

                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                status?: A2ATaskStatus

                                                                                                                                                                                                                                                                New task status (if changing).

                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                targetAgent?: A2AAgentInfo

                                                                                                                                                                                                                                                                Target agent assignment (if assigning/reassigning).

                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                taskId: string

                                                                                                                                                                                                                                                                Task ID to update.

                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                diff --git a/docs/components/interfaces/ZyntopiaOAuthConfig.html b/docs/components/interfaces/ZyntopiaOAuthConfig.html new file mode 100644 index 0000000..2490d46 --- /dev/null +++ b/docs/components/interfaces/ZyntopiaOAuthConfig.html @@ -0,0 +1,18 @@ +ZyntopiaOAuthConfig | ART Framework API Docs
                                                                                                                                                                                                                                                                ART Framework API Docs
                                                                                                                                                                                                                                                                  Preparing search index...

                                                                                                                                                                                                                                                                  Interface ZyntopiaOAuthConfig

                                                                                                                                                                                                                                                                  Configuration specific to Zyntopia OAuth strategy

                                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                                  interface ZyntopiaOAuthConfig {
                                                                                                                                                                                                                                                                      clientId: string;
                                                                                                                                                                                                                                                                      clientSecret: string;
                                                                                                                                                                                                                                                                      customHeaders?: Record<string, string>;
                                                                                                                                                                                                                                                                      environment?: "production" | "staging" | "development";
                                                                                                                                                                                                                                                                      scopes?: string;
                                                                                                                                                                                                                                                                      tokenEndpoint?: string;
                                                                                                                                                                                                                                                                      tokenRefreshBufferMs?: number;
                                                                                                                                                                                                                                                                      tokenTimeoutMs?: number;
                                                                                                                                                                                                                                                                  }
                                                                                                                                                                                                                                                                  Index

                                                                                                                                                                                                                                                                  Properties

                                                                                                                                                                                                                                                                  clientId: string

                                                                                                                                                                                                                                                                  Client ID for Zyntopia OAuth authentication

                                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                                  clientSecret: string

                                                                                                                                                                                                                                                                  Client secret for Zyntopia OAuth authentication

                                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                                  customHeaders?: Record<string, string>

                                                                                                                                                                                                                                                                  Additional custom headers for Zyntopia API requirements

                                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                                  environment?: "production" | "staging" | "development"

                                                                                                                                                                                                                                                                  Optional environment ('production' | 'staging' | 'development')

                                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                                  scopes?: string

                                                                                                                                                                                                                                                                  Optional custom scopes (defaults to Zyntopia's standard scopes)

                                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                                  tokenEndpoint?: string

                                                                                                                                                                                                                                                                  Optional custom token endpoint (defaults to Zyntopia's standard endpoint)

                                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                                  tokenRefreshBufferMs?: number

                                                                                                                                                                                                                                                                  Optional custom buffer time before token expiry to trigger refresh

                                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                                  tokenTimeoutMs?: number

                                                                                                                                                                                                                                                                  Optional custom timeout for token requests in milliseconds

                                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                                  diff --git a/docs/components/media/CONTRIBUTING.md b/docs/components/media/CONTRIBUTING.md new file mode 100755 index 0000000..8f8644c --- /dev/null +++ b/docs/components/media/CONTRIBUTING.md @@ -0,0 +1,27 @@ +# Contributing to ART + +First off, thank you for considering contributing to the Agentic Runtime Framework (ART)! Your help is invaluable in making this project better. + +We welcome contributions in various forms, including: +- Reporting bugs and issues +- Suggesting new features or enhancements +- Improving documentation +- Submitting pull requests for bug fixes or new features + +## How to Contribute + +*(This is a placeholder. A more detailed guide on our development process, coding standards, and pull request guidelines will be added here soon.)* + +### Reporting Issues + +If you encounter a bug or have a suggestion, please open an issue on our GitHub repository. Provide as much detail as possible to help us understand and address the problem quickly. + +### Submitting Pull Requests + +1. Fork the repository and create your branch from `main`. +2. If you've added code that should be tested, add tests. +3. Ensure the test suite passes. +4. Make sure your code lints. +5. Issue that pull request! + +We look forward to your contributions! diff --git a/docs/components/media/art-logo.jpeg b/docs/components/media/art-logo.jpeg new file mode 100755 index 0000000..4d48b0d Binary files /dev/null and b/docs/components/media/art-logo.jpeg differ diff --git a/docs/components/media/customizing-agent-persona.md b/docs/components/media/customizing-agent-persona.md new file mode 100755 index 0000000..2661118 --- /dev/null +++ b/docs/components/media/customizing-agent-persona.md @@ -0,0 +1,114 @@ +# How to Customize the Agent's Persona + +The ART framework provides a powerful, multi-layered system for customizing the identity and behavior of your agent. This is achieved by defining an `AgentPersona` at the instance, thread, or even individual call level, allowing for incredible flexibility. + +This guide will walk you through the advanced features of agent persona customization. + +## What is an Agent Persona? + +The `AgentPersona` is a configuration object that defines two key aspects of your agent: + +- `name`: A string that sets the agent's identity (e.g., "Zoi", "CodeBot"). This is used in the final **synthesis** stage to instruct the LLM on who it should be. +- `prompts`: An object containing separate system prompts for the two main stages of the agent's reasoning process: + - `planning`: A system prompt that guides the agent's reasoning, expertise, and tool selection. + - `synthesis`: A system prompt that shapes the agent's tone, formatting, and final response structure. + +By separating these prompts, you can fine-tune the agent's behavior with precision. For example, you can have a highly technical and analytical prompt for planning, and a friendly, easy-to-understand prompt for synthesis. + +Here is the interface definition: + +```typescript +export interface AgentPersona { + name: string; + prompts: { + planning?: string; + synthesis?: string; + }; +} +``` + +## The Override Hierarchy + +The agent's final persona is resolved using a clear hierarchy. Settings at a more specific level will always override those at a broader level: + +1. **Call-level Persona**: Defined in the `options` of an `art.process()` call. This is the most specific and will override all other settings for that single execution. +2. **Thread-level Persona**: Defined in the `threadConfig` when a thread is created or updated. This applies to all executions within that specific conversation thread. +3. **Instance-level Persona**: Defined in the `ArtInstanceConfig` when you create your ART instance. This is the default persona for all agents in the instance. + +## How to Use Personas + +### 1. Instance-Level (Default Persona) + +This is the most common way to set a default character for your agent. + +```typescript:main.ts +import { createArtInstance } from 'art-framework'; +import type { ArtInstanceConfig, AgentPersona } from 'art-framework'; + +const defaultPersona: AgentPersona = { + name: 'CodeBot', + prompts: { + planning: 'You are an expert software engineer. Your task is to analyze the user query and create a precise plan to solve it. Identify the best tools and functions for the job.', + synthesis: 'You are CodeBot, a friendly and helpful coding assistant. Synthesize the results into a clear, well-formatted response with code examples.' + } +}; + +const config: ArtInstanceConfig = { + storage: { type: 'memory' }, + providers: { /* ... */ }, + persona: defaultPersona, +}; + +const art = await createArtInstance(config); +``` + +### 2. Thread-Level (Mode Switching) + +You can override the persona for a specific conversation, which is great for implementing different "modes" in your application. For example, a "beginner" mode vs. an "expert" mode. + +```typescript +const expertModePersona: Partial = { + prompts: { + synthesis: 'You are CodeBot, speaking to an expert user. Be concise, technical, and skip the introductory explanations.' + } +}; + +const result = await art.process({ + query: 'Implement a binary search tree in Rust.', + threadId: 'expert-thread-1', + threadConfig: { + providerConfig: { /* ... */ }, + persona: expertModePersona, + }, +}); +``` + +In this example, the agent will still use the `name` ("CodeBot") and the `planning` prompt from the instance-level persona, but it will use the new, more direct `synthesis` prompt for the final response. + +### 3. Call-Level (Dynamic, One-Time Changes) + +For ultimate flexibility, you can change the persona for a single call. This is useful for one-off requests where you need a very specific behavior. + +```typescript +const oneTimePersona: Partial = { + name: 'SecurityAnalyst', + prompts: { + planning: 'You are a security analyst. Analyze the following code for potential vulnerabilities. Focus on injection attacks and improper error handling.', + } +}; + +const result = await art.process({ + query: 'Review this login function for security issues: `...`', + threadId: 'expert-thread-1', + options: { + persona: oneTimePersona, + } +}); +``` + +In this case, for this single execution: +- The agent's name will be **"SecurityAnalyst"**. +- It will use the specialized `planning` prompt. +- It will fall back to the thread-level `synthesis` prompt ("Be concise, technical..."). + +By combining these three levels, you have complete control over your agent's identity and behavior, allowing you to create dynamic, context-aware, and highly specialized AI applications. diff --git a/docs/components/modules.html b/docs/components/modules.html new file mode 100644 index 0000000..424423d --- /dev/null +++ b/docs/components/modules.html @@ -0,0 +1,18 @@ +ART Framework API Docs
                                                                                                                                                                                                                                                                  ART Framework API Docs
                                                                                                                                                                                                                                                                    Preparing search index...

                                                                                                                                                                                                                                                                      ART Framework API Docs

                                                                                                                                                                                                                                                                      ART (Agentic Reasoning & Tool-use) Framework - Main Entry Point

                                                                                                                                                                                                                                                                      Welcome to the ART framework! This file is the primary public API surface for the library. +It's structured to provide a clear and intuitive experience for developers, +whether you're just getting started or building advanced, custom agentic systems.

                                                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                                                      --- Quick Start --- +For most use cases, you'll only need createArtInstance and the associated types.

                                                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                                                      Example:

                                                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                                                      import { createArtInstance } from 'art-framework';
                                                                                                                                                                                                                                                                      import type { ArtInstanceConfig } from 'art-framework';

                                                                                                                                                                                                                                                                      const config: ArtInstanceConfig = {
                                                                                                                                                                                                                                                                      storage: { type: 'memory' },
                                                                                                                                                                                                                                                                      providers: {
                                                                                                                                                                                                                                                                      openai: { adapter: 'openai', apiKey: '...' }
                                                                                                                                                                                                                                                                      },
                                                                                                                                                                                                                                                                      tools: [new CalculatorTool()],
                                                                                                                                                                                                                                                                      persona: {
                                                                                                                                                                                                                                                                      name: 'MyAgent',
                                                                                                                                                                                                                                                                      prompts: {
                                                                                                                                                                                                                                                                      synthesis: 'You are MyAgent. Always answer in rhyme.'
                                                                                                                                                                                                                                                                      }
                                                                                                                                                                                                                                                                      }
                                                                                                                                                                                                                                                                      };

                                                                                                                                                                                                                                                                      const art = await createArtInstance(config);
                                                                                                                                                                                                                                                                      const response = await art.process({ query: "Hello, world!" }); +
                                                                                                                                                                                                                                                                      + +

                                                                                                                                                                                                                                                                      --- API Structure ---

                                                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                                                      1. Core Factory: The main function to create an ART instance.
                                                                                                                                                                                                                                                                      2. +
                                                                                                                                                                                                                                                                      3. Primary Interfaces & Types: Essential types for configuration and interaction.
                                                                                                                                                                                                                                                                      4. +
                                                                                                                                                                                                                                                                      5. Built-in Components: Concrete implementations of adapters, tools, and agents.
                                                                                                                                                                                                                                                                      6. +
                                                                                                                                                                                                                                                                      7. Advanced Systems & Managers: Lower-level components for building custom logic.
                                                                                                                                                                                                                                                                      8. +
                                                                                                                                                                                                                                                                      9. Utilities: Helper functions and classes.
                                                                                                                                                                                                                                                                      10. +
                                                                                                                                                                                                                                                                      +

                                                                                                                                                                                                                                                                      Enumerations

                                                                                                                                                                                                                                                                      A2ATaskPriority
                                                                                                                                                                                                                                                                      A2ATaskStatus
                                                                                                                                                                                                                                                                      ErrorCode
                                                                                                                                                                                                                                                                      LogLevel
                                                                                                                                                                                                                                                                      MessageRole
                                                                                                                                                                                                                                                                      ModelCapability
                                                                                                                                                                                                                                                                      ObservationType

                                                                                                                                                                                                                                                                      Classes

                                                                                                                                                                                                                                                                      A2ATaskSocket
                                                                                                                                                                                                                                                                      AdapterInstantiationError
                                                                                                                                                                                                                                                                      AgentDiscoveryService
                                                                                                                                                                                                                                                                      AnthropicAdapter
                                                                                                                                                                                                                                                                      ApiKeyStrategy
                                                                                                                                                                                                                                                                      ApiQueueTimeoutError
                                                                                                                                                                                                                                                                      ARTError
                                                                                                                                                                                                                                                                      AuthManager
                                                                                                                                                                                                                                                                      CalculatorTool
                                                                                                                                                                                                                                                                      ConversationSocket
                                                                                                                                                                                                                                                                      DeepSeekAdapter
                                                                                                                                                                                                                                                                      GeminiAdapter
                                                                                                                                                                                                                                                                      GenericOAuthStrategy
                                                                                                                                                                                                                                                                      IndexedDBStorageAdapter
                                                                                                                                                                                                                                                                      InMemoryStorageAdapter
                                                                                                                                                                                                                                                                      LLMStreamSocket
                                                                                                                                                                                                                                                                      LocalInstanceBusyError
                                                                                                                                                                                                                                                                      LocalProviderConflictError
                                                                                                                                                                                                                                                                      Logger
                                                                                                                                                                                                                                                                      McpClientController
                                                                                                                                                                                                                                                                      McpManager
                                                                                                                                                                                                                                                                      McpProxyTool
                                                                                                                                                                                                                                                                      ObservationSocket
                                                                                                                                                                                                                                                                      OllamaAdapter
                                                                                                                                                                                                                                                                      OpenAIAdapter
                                                                                                                                                                                                                                                                      OpenRouterAdapter
                                                                                                                                                                                                                                                                      PESAgent
                                                                                                                                                                                                                                                                      PKCEOAuthStrategy
                                                                                                                                                                                                                                                                      ProviderManagerImpl
                                                                                                                                                                                                                                                                      StateManager
                                                                                                                                                                                                                                                                      SupabaseStorageAdapter
                                                                                                                                                                                                                                                                      TaskDelegationService
                                                                                                                                                                                                                                                                      ToolRegistry
                                                                                                                                                                                                                                                                      TypedSocket
                                                                                                                                                                                                                                                                      UISystem
                                                                                                                                                                                                                                                                      UnknownProviderError
                                                                                                                                                                                                                                                                      ZyntopiaOAuthStrategy

                                                                                                                                                                                                                                                                      Interfaces

                                                                                                                                                                                                                                                                      A2AAgentInfo
                                                                                                                                                                                                                                                                      A2ATask
                                                                                                                                                                                                                                                                      A2ATaskEvent
                                                                                                                                                                                                                                                                      A2ATaskFilter
                                                                                                                                                                                                                                                                      A2ATaskMetadata
                                                                                                                                                                                                                                                                      A2ATaskResult
                                                                                                                                                                                                                                                                      AgentDiscoveryConfig
                                                                                                                                                                                                                                                                      AgentFinalResponse
                                                                                                                                                                                                                                                                      AgentOptions
                                                                                                                                                                                                                                                                      AgentPersona
                                                                                                                                                                                                                                                                      AgentProps
                                                                                                                                                                                                                                                                      AgentState
                                                                                                                                                                                                                                                                      AnthropicAdapterOptions
                                                                                                                                                                                                                                                                      ArtInstance
                                                                                                                                                                                                                                                                      ArtInstanceConfig
                                                                                                                                                                                                                                                                      ArtStandardMessage
                                                                                                                                                                                                                                                                      AvailableProviderEntry
                                                                                                                                                                                                                                                                      CallOptions
                                                                                                                                                                                                                                                                      ConversationManager
                                                                                                                                                                                                                                                                      ConversationMessage
                                                                                                                                                                                                                                                                      CreateA2ATaskRequest
                                                                                                                                                                                                                                                                      DeepSeekAdapterOptions
                                                                                                                                                                                                                                                                      ExecutionContext
                                                                                                                                                                                                                                                                      ExecutionMetadata
                                                                                                                                                                                                                                                                      FilterOptions
                                                                                                                                                                                                                                                                      GeminiAdapterOptions
                                                                                                                                                                                                                                                                      IA2ATaskRepository
                                                                                                                                                                                                                                                                      IAgentCore
                                                                                                                                                                                                                                                                      IAuthStrategy
                                                                                                                                                                                                                                                                      IConversationRepository
                                                                                                                                                                                                                                                                      IObservationRepository
                                                                                                                                                                                                                                                                      IProviderManager
                                                                                                                                                                                                                                                                      IStateRepository
                                                                                                                                                                                                                                                                      IToolExecutor
                                                                                                                                                                                                                                                                      ITypedSocket
                                                                                                                                                                                                                                                                      JsonObjectSchema
                                                                                                                                                                                                                                                                      LLMMetadata
                                                                                                                                                                                                                                                                      LoggerConfig
                                                                                                                                                                                                                                                                      ManagedAdapterAccessor
                                                                                                                                                                                                                                                                      McpManagerConfig
                                                                                                                                                                                                                                                                      McpResource
                                                                                                                                                                                                                                                                      McpResourceTemplate
                                                                                                                                                                                                                                                                      McpServerStatus
                                                                                                                                                                                                                                                                      McpToolDefinition
                                                                                                                                                                                                                                                                      MessageOptions
                                                                                                                                                                                                                                                                      OAuthConfig
                                                                                                                                                                                                                                                                      Observation
                                                                                                                                                                                                                                                                      ObservationFilter
                                                                                                                                                                                                                                                                      ObservationManager
                                                                                                                                                                                                                                                                      OllamaAdapterOptions
                                                                                                                                                                                                                                                                      OpenAIAdapterOptions
                                                                                                                                                                                                                                                                      OpenRouterAdapterOptions
                                                                                                                                                                                                                                                                      OutputParser
                                                                                                                                                                                                                                                                      ParsedToolCall
                                                                                                                                                                                                                                                                      PKCEOAuthConfig
                                                                                                                                                                                                                                                                      PromptBlueprint
                                                                                                                                                                                                                                                                      PromptContext
                                                                                                                                                                                                                                                                      PromptManager
                                                                                                                                                                                                                                                                      ProviderAdapter
                                                                                                                                                                                                                                                                      ProviderManagerConfig
                                                                                                                                                                                                                                                                      ReasoningEngine
                                                                                                                                                                                                                                                                      RuntimeProviderConfig
                                                                                                                                                                                                                                                                      StageSpecificPrompts
                                                                                                                                                                                                                                                                      StorageAdapter
                                                                                                                                                                                                                                                                      StreamEvent
                                                                                                                                                                                                                                                                      SystemPromptOverride
                                                                                                                                                                                                                                                                      SystemPromptResolver
                                                                                                                                                                                                                                                                      SystemPromptSpec
                                                                                                                                                                                                                                                                      SystemPromptsRegistry
                                                                                                                                                                                                                                                                      TaskDelegationConfig
                                                                                                                                                                                                                                                                      TaskStatusResponse
                                                                                                                                                                                                                                                                      ThreadConfig
                                                                                                                                                                                                                                                                      ThreadContext
                                                                                                                                                                                                                                                                      ToolResult
                                                                                                                                                                                                                                                                      ToolSchema
                                                                                                                                                                                                                                                                      ToolSystem
                                                                                                                                                                                                                                                                      UpdateA2ATaskRequest
                                                                                                                                                                                                                                                                      ZyntopiaOAuthConfig

                                                                                                                                                                                                                                                                      Type Aliases

                                                                                                                                                                                                                                                                      ArtStandardMessageRole
                                                                                                                                                                                                                                                                      ArtStandardPrompt
                                                                                                                                                                                                                                                                      FormattedPrompt
                                                                                                                                                                                                                                                                      JsonSchema
                                                                                                                                                                                                                                                                      McpServerConfig
                                                                                                                                                                                                                                                                      StateSavingStrategy
                                                                                                                                                                                                                                                                      StreamEventTypeFilter
                                                                                                                                                                                                                                                                      SystemPromptMergeStrategy
                                                                                                                                                                                                                                                                      UnsubscribeFunction

                                                                                                                                                                                                                                                                      Variables

                                                                                                                                                                                                                                                                      ArtStandardMessageSchema
                                                                                                                                                                                                                                                                      ArtStandardPromptSchema
                                                                                                                                                                                                                                                                      VERSION

                                                                                                                                                                                                                                                                      Functions

                                                                                                                                                                                                                                                                      createArtInstance
                                                                                                                                                                                                                                                                      generateUUID
                                                                                                                                                                                                                                                                      diff --git a/docs/components/types/ArtStandardMessageRole.html b/docs/components/types/ArtStandardMessageRole.html new file mode 100644 index 0000000..bf8a6f3 --- /dev/null +++ b/docs/components/types/ArtStandardMessageRole.html @@ -0,0 +1,12 @@ +ArtStandardMessageRole | ART Framework API Docs
                                                                                                                                                                                                                                                                      ART Framework API Docs
                                                                                                                                                                                                                                                                        Preparing search index...

                                                                                                                                                                                                                                                                        Type Alias ArtStandardMessageRole

                                                                                                                                                                                                                                                                        ArtStandardMessageRole:
                                                                                                                                                                                                                                                                            | "system"
                                                                                                                                                                                                                                                                            | "user"
                                                                                                                                                                                                                                                                            | "assistant"
                                                                                                                                                                                                                                                                            | "tool_request"
                                                                                                                                                                                                                                                                            | "tool_result"
                                                                                                                                                                                                                                                                            | "tool"

                                                                                                                                                                                                                                                                        Defines the standard roles for messages within the ArtStandardPrompt format.

                                                                                                                                                                                                                                                                        +

                                                                                                                                                                                                                                                                        These roles are chosen for broad compatibility across major LLM providers (like OpenAI, Anthropic, Gemini). +Provider Adapters are responsible for translating these standard roles into the specific formats +required by their respective APIs (e.g., 'assistant' might become 'model' for Gemini).

                                                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                                                        • system: Instructions or context provided to the AI, typically at the beginning.
                                                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                                                        • user: Input or queries from the end-user. Also used to wrap tool_result content for some providers (e.g., Gemini).
                                                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                                                        • assistant: Responses generated by the AI model. Can contain text content and/or tool_calls.
                                                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                                                        • tool_request: Represents the LLM's request to use tools (often implicitly part of an assistant message with tool_calls). Included for potential future explicit use.
                                                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                                                        • tool_result: The outcome (output or error) of executing a requested tool call.
                                                                                                                                                                                                                                                                        • +
                                                                                                                                                                                                                                                                        +
                                                                                                                                                                                                                                                                        diff --git a/docs/components/types/ArtStandardPrompt.html b/docs/components/types/ArtStandardPrompt.html new file mode 100644 index 0000000..eda02ee --- /dev/null +++ b/docs/components/types/ArtStandardPrompt.html @@ -0,0 +1,5 @@ +ArtStandardPrompt | ART Framework API Docs
                                                                                                                                                                                                                                                                        ART Framework API Docs
                                                                                                                                                                                                                                                                          Preparing search index...

                                                                                                                                                                                                                                                                          Type Alias ArtStandardPrompt

                                                                                                                                                                                                                                                                          ArtStandardPrompt: ArtStandardMessage[]

                                                                                                                                                                                                                                                                          Represents the entire prompt as an array of standardized messages (ArtStandardMessage).

                                                                                                                                                                                                                                                                          +

                                                                                                                                                                                                                                                                          Constructed by agent logic (e.g., PESAgent) and optionally validated via +PromptManager.validatePrompt before being sent to the ReasoningEngine and +translated by a ProviderAdapter for provider-specific API formats.

                                                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                                                          diff --git a/docs/components/types/FormattedPrompt.html b/docs/components/types/FormattedPrompt.html new file mode 100644 index 0000000..e2fe420 --- /dev/null +++ b/docs/components/types/FormattedPrompt.html @@ -0,0 +1,4 @@ +FormattedPrompt | ART Framework API Docs
                                                                                                                                                                                                                                                                          ART Framework API Docs
                                                                                                                                                                                                                                                                            Preparing search index...

                                                                                                                                                                                                                                                                            Type Alias FormattedPrompt

                                                                                                                                                                                                                                                                            FormattedPrompt: ArtStandardPrompt

                                                                                                                                                                                                                                                                            Represents the prompt data formatted for a specific LLM provider. +Can be a simple string or a complex object (e.g., for OpenAI Chat Completion API).

                                                                                                                                                                                                                                                                            +

                                                                                                                                                                                                                                                                            Use ArtStandardPrompt as the standard intermediate format. ProviderAdapters handle final formatting.

                                                                                                                                                                                                                                                                            +
                                                                                                                                                                                                                                                                            diff --git a/docs/components/types/JsonSchema.html b/docs/components/types/JsonSchema.html new file mode 100644 index 0000000..d5586b3 --- /dev/null +++ b/docs/components/types/JsonSchema.html @@ -0,0 +1 @@ +JsonSchema | ART Framework API Docs
                                                                                                                                                                                                                                                                            ART Framework API Docs
                                                                                                                                                                                                                                                                              Preparing search index...

                                                                                                                                                                                                                                                                              Type Alias JsonSchema

                                                                                                                                                                                                                                                                              JsonSchema:
                                                                                                                                                                                                                                                                                  | JsonObjectSchema
                                                                                                                                                                                                                                                                                  | { type: "string"
                                                                                                                                                                                                                                                                                  | "number"
                                                                                                                                                                                                                                                                                  | "boolean"
                                                                                                                                                                                                                                                                                  | "array"; [key: string]: any }
                                                                                                                                                                                                                                                                              diff --git a/docs/components/types/McpServerConfig.html b/docs/components/types/McpServerConfig.html new file mode 100644 index 0000000..f08d8b8 --- /dev/null +++ b/docs/components/types/McpServerConfig.html @@ -0,0 +1,27 @@ +McpServerConfig | ART Framework API Docs
                                                                                                                                                                                                                                                                              ART Framework API Docs
                                                                                                                                                                                                                                                                                Preparing search index...

                                                                                                                                                                                                                                                                                Type Alias McpServerConfig

                                                                                                                                                                                                                                                                                Represents the configuration for a single MCP server.

                                                                                                                                                                                                                                                                                +

                                                                                                                                                                                                                                                                                This is the format for each server entry in the art_mcp_config.json file. +It contains all the necessary information for discovering, installing, and connecting to an MCP server.

                                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                                type McpServerConfig = {
                                                                                                                                                                                                                                                                                    connection: StreamableHttpConnection;
                                                                                                                                                                                                                                                                                    description?: string;
                                                                                                                                                                                                                                                                                    displayName?: string;
                                                                                                                                                                                                                                                                                    enabled: boolean;
                                                                                                                                                                                                                                                                                    id: string;
                                                                                                                                                                                                                                                                                    installation?: { source: "git" | "npm" | "manual"; [key: string]: any };
                                                                                                                                                                                                                                                                                    resources: McpResource[];
                                                                                                                                                                                                                                                                                    resourceTemplates: McpResourceTemplate[];
                                                                                                                                                                                                                                                                                    timeout?: number;
                                                                                                                                                                                                                                                                                    tools: McpToolDefinition[];
                                                                                                                                                                                                                                                                                    type: "streamable-http";
                                                                                                                                                                                                                                                                                }
                                                                                                                                                                                                                                                                                Index

                                                                                                                                                                                                                                                                                Properties

                                                                                                                                                                                                                                                                                connection: StreamableHttpConnection

                                                                                                                                                                                                                                                                                The connection details for the server.

                                                                                                                                                                                                                                                                                +

                                                                                                                                                                                                                                                                                module:systems/mcp/types.StreamableHttpConnection

                                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                                description?: string

                                                                                                                                                                                                                                                                                A description of the server and its capabilities.

                                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                                displayName?: string

                                                                                                                                                                                                                                                                                A user-friendly name for the server.

                                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                                enabled: boolean

                                                                                                                                                                                                                                                                                Whether the server is enabled and should be connected to.

                                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                                id: string

                                                                                                                                                                                                                                                                                A unique identifier for the server.

                                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                                installation?: { source: "git" | "npm" | "manual"; [key: string]: any }

                                                                                                                                                                                                                                                                                Information about how the server was installed (e.g., 'git', 'npm', 'manual').

                                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                                resources: McpResource[]

                                                                                                                                                                                                                                                                                The static resources provided by the server.

                                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                                resourceTemplates: McpResourceTemplate[]

                                                                                                                                                                                                                                                                                The resource templates provided by the server.

                                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                                timeout?: number

                                                                                                                                                                                                                                                                                The timeout in milliseconds for requests to the server.

                                                                                                                                                                                                                                                                                +

                                                                                                                                                                                                                                                                                The tools provided by the server.

                                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                                type: "streamable-http"

                                                                                                                                                                                                                                                                                The transport type for the server, currently only 'streamable-http' is supported.

                                                                                                                                                                                                                                                                                +
                                                                                                                                                                                                                                                                                diff --git a/docs/components/types/StateSavingStrategy.html b/docs/components/types/StateSavingStrategy.html new file mode 100644 index 0000000..7e23a16 --- /dev/null +++ b/docs/components/types/StateSavingStrategy.html @@ -0,0 +1,10 @@ +StateSavingStrategy | ART Framework API Docs
                                                                                                                                                                                                                                                                                ART Framework API Docs
                                                                                                                                                                                                                                                                                  Preparing search index...

                                                                                                                                                                                                                                                                                  Type Alias StateSavingStrategy

                                                                                                                                                                                                                                                                                  StateSavingStrategy: "explicit" | "implicit"

                                                                                                                                                                                                                                                                                  Defines the strategy for saving AgentState.

                                                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                                                    +
                                                                                                                                                                                                                                                                                  • 'explicit': AgentState is only saved when StateManager.setAgentState() is explicitly called by the agent. +StateManager.saveStateIfModified() will be a no-op for AgentState persistence.
                                                                                                                                                                                                                                                                                  • +
                                                                                                                                                                                                                                                                                  • 'implicit': AgentState is loaded by StateManager.loadThreadContext(), and if modified by the agent, +StateManager.saveStateIfModified() will attempt to automatically persist these changes +by comparing the current state with a snapshot taken at load time. +StateManager.setAgentState() will still work for explicit saves.
                                                                                                                                                                                                                                                                                  • +
                                                                                                                                                                                                                                                                                  +
                                                                                                                                                                                                                                                                                  diff --git a/docs/components/types/StreamEventTypeFilter.html b/docs/components/types/StreamEventTypeFilter.html new file mode 100644 index 0000000..17b9741 --- /dev/null +++ b/docs/components/types/StreamEventTypeFilter.html @@ -0,0 +1 @@ +StreamEventTypeFilter | ART Framework API Docs
                                                                                                                                                                                                                                                                                  ART Framework API Docs
                                                                                                                                                                                                                                                                                    Preparing search index...

                                                                                                                                                                                                                                                                                    Type Alias StreamEventTypeFilter

                                                                                                                                                                                                                                                                                    StreamEventTypeFilter: StreamEvent["type"] | StreamEvent["type"][]
                                                                                                                                                                                                                                                                                    diff --git a/docs/components/types/SystemPromptMergeStrategy.html b/docs/components/types/SystemPromptMergeStrategy.html new file mode 100644 index 0000000..49ea451 --- /dev/null +++ b/docs/components/types/SystemPromptMergeStrategy.html @@ -0,0 +1,2 @@ +SystemPromptMergeStrategy | ART Framework API Docs
                                                                                                                                                                                                                                                                                    ART Framework API Docs
                                                                                                                                                                                                                                                                                      Preparing search index...

                                                                                                                                                                                                                                                                                      Type Alias SystemPromptMergeStrategy

                                                                                                                                                                                                                                                                                      SystemPromptMergeStrategy: "append" | "prepend"

                                                                                                                                                                                                                                                                                      Strategy for combining custom system prompt content across precedence levels.

                                                                                                                                                                                                                                                                                      +
                                                                                                                                                                                                                                                                                      diff --git a/docs/components/types/UnsubscribeFunction.html b/docs/components/types/UnsubscribeFunction.html new file mode 100644 index 0000000..d3eec04 --- /dev/null +++ b/docs/components/types/UnsubscribeFunction.html @@ -0,0 +1 @@ +UnsubscribeFunction | ART Framework API Docs
                                                                                                                                                                                                                                                                                      ART Framework API Docs
                                                                                                                                                                                                                                                                                        Preparing search index...

                                                                                                                                                                                                                                                                                        Type Alias UnsubscribeFunction

                                                                                                                                                                                                                                                                                        UnsubscribeFunction: () => void

                                                                                                                                                                                                                                                                                        Type declaration

                                                                                                                                                                                                                                                                                          • (): void
                                                                                                                                                                                                                                                                                          • Returns void

                                                                                                                                                                                                                                                                                        diff --git a/docs/components/variables/ArtStandardMessageSchema.html b/docs/components/variables/ArtStandardMessageSchema.html new file mode 100644 index 0000000..26c95fe --- /dev/null +++ b/docs/components/variables/ArtStandardMessageSchema.html @@ -0,0 +1,10 @@ +ArtStandardMessageSchema | ART Framework API Docs
                                                                                                                                                                                                                                                                                        ART Framework API Docs
                                                                                                                                                                                                                                                                                          Preparing search index...

                                                                                                                                                                                                                                                                                          Variable ArtStandardMessageSchemaConst

                                                                                                                                                                                                                                                                                          ArtStandardMessageSchema: ZodEffects<
                                                                                                                                                                                                                                                                                              ZodObject<
                                                                                                                                                                                                                                                                                                  {
                                                                                                                                                                                                                                                                                                      content: ZodUnion<[ZodString, ZodRecord<ZodString, ZodAny>, ZodNull]>;
                                                                                                                                                                                                                                                                                                      name: ZodOptional<ZodString>;
                                                                                                                                                                                                                                                                                                      role: ZodType<ArtStandardMessageRole, ZodTypeDef, ArtStandardMessageRole>;
                                                                                                                                                                                                                                                                                                      tool_call_id: ZodOptional<ZodString>;
                                                                                                                                                                                                                                                                                                      tool_calls: ZodOptional<
                                                                                                                                                                                                                                                                                                          ZodArray<
                                                                                                                                                                                                                                                                                                              ZodObject<
                                                                                                                                                                                                                                                                                                                  {
                                                                                                                                                                                                                                                                                                                      function: ZodObject<
                                                                                                                                                                                                                                                                                                                          { arguments: ZodString; name: ZodString },
                                                                                                                                                                                                                                                                                                                          "strip",
                                                                                                                                                                                                                                                                                                                          ZodTypeAny,
                                                                                                                                                                                                                                                                                                                          { arguments: string; name: string },
                                                                                                                                                                                                                                                                                                                          { arguments: string; name: string },
                                                                                                                                                                                                                                                                                                                      >;
                                                                                                                                                                                                                                                                                                                      id: ZodString;
                                                                                                                                                                                                                                                                                                                      type: ZodLiteral<"function">;
                                                                                                                                                                                                                                                                                                                  },
                                                                                                                                                                                                                                                                                                                  "strip",
                                                                                                                                                                                                                                                                                                                  ZodTypeAny,
                                                                                                                                                                                                                                                                                                                  {
                                                                                                                                                                                                                                                                                                                      function: { arguments: string; name: string };
                                                                                                                                                                                                                                                                                                                      id: string;
                                                                                                                                                                                                                                                                                                                      type: "function";
                                                                                                                                                                                                                                                                                                                  },
                                                                                                                                                                                                                                                                                                                  {
                                                                                                                                                                                                                                                                                                                      function: { arguments: string; name: string };
                                                                                                                                                                                                                                                                                                                      id: string;
                                                                                                                                                                                                                                                                                                                      type: "function";
                                                                                                                                                                                                                                                                                                                  },
                                                                                                                                                                                                                                                                                                              >,
                                                                                                                                                                                                                                                                                                              "many",
                                                                                                                                                                                                                                                                                                          >,
                                                                                                                                                                                                                                                                                                      >;
                                                                                                                                                                                                                                                                                                  },
                                                                                                                                                                                                                                                                                                  "strict",
                                                                                                                                                                                                                                                                                                  ZodTypeAny,
                                                                                                                                                                                                                                                                                                  {
                                                                                                                                                                                                                                                                                                      content: null
                                                                                                                                                                                                                                                                                                      | string
                                                                                                                                                                                                                                                                                                      | Record<string, any>;
                                                                                                                                                                                                                                                                                                      name?: string;
                                                                                                                                                                                                                                                                                                      role: ArtStandardMessageRole;
                                                                                                                                                                                                                                                                                                      tool_call_id?: string;
                                                                                                                                                                                                                                                                                                      tool_calls?: {
                                                                                                                                                                                                                                                                                                          function: { arguments: string; name: string };
                                                                                                                                                                                                                                                                                                          id: string;
                                                                                                                                                                                                                                                                                                          type: "function";
                                                                                                                                                                                                                                                                                                      }[];
                                                                                                                                                                                                                                                                                                  },
                                                                                                                                                                                                                                                                                                  {
                                                                                                                                                                                                                                                                                                      content: null
                                                                                                                                                                                                                                                                                                      | string
                                                                                                                                                                                                                                                                                                      | Record<string, any>;
                                                                                                                                                                                                                                                                                                      name?: string;
                                                                                                                                                                                                                                                                                                      role: ArtStandardMessageRole;
                                                                                                                                                                                                                                                                                                      tool_call_id?: string;
                                                                                                                                                                                                                                                                                                      tool_calls?: {
                                                                                                                                                                                                                                                                                                          function: { arguments: string; name: string };
                                                                                                                                                                                                                                                                                                          id: string;
                                                                                                                                                                                                                                                                                                          type: "function";
                                                                                                                                                                                                                                                                                                      }[];
                                                                                                                                                                                                                                                                                                  },
                                                                                                                                                                                                                                                                                              >,
                                                                                                                                                                                                                                                                                              {
                                                                                                                                                                                                                                                                                                  content: null
                                                                                                                                                                                                                                                                                                  | string
                                                                                                                                                                                                                                                                                                  | Record<string, any>;
                                                                                                                                                                                                                                                                                                  name?: string;
                                                                                                                                                                                                                                                                                                  role: ArtStandardMessageRole;
                                                                                                                                                                                                                                                                                                  tool_call_id?: string;
                                                                                                                                                                                                                                                                                                  tool_calls?: {
                                                                                                                                                                                                                                                                                                      function: { arguments: string; name: string };
                                                                                                                                                                                                                                                                                                      id: string;
                                                                                                                                                                                                                                                                                                      type: "function";
                                                                                                                                                                                                                                                                                                  }[];
                                                                                                                                                                                                                                                                                              },
                                                                                                                                                                                                                                                                                              {
                                                                                                                                                                                                                                                                                                  content: null
                                                                                                                                                                                                                                                                                                  | string
                                                                                                                                                                                                                                                                                                  | Record<string, any>;
                                                                                                                                                                                                                                                                                                  name?: string;
                                                                                                                                                                                                                                                                                                  role: ArtStandardMessageRole;
                                                                                                                                                                                                                                                                                                  tool_call_id?: string;
                                                                                                                                                                                                                                                                                                  tool_calls?: {
                                                                                                                                                                                                                                                                                                      function: { arguments: string; name: string };
                                                                                                                                                                                                                                                                                                      id: string;
                                                                                                                                                                                                                                                                                                      type: "function";
                                                                                                                                                                                                                                                                                                  }[];
                                                                                                                                                                                                                                                                                              },
                                                                                                                                                                                                                                                                                          > = ...

                                                                                                                                                                                                                                                                                          Zod schema for validating a single ArtStandardMessage object.

                                                                                                                                                                                                                                                                                          +

                                                                                                                                                                                                                                                                                          This schema enforces the structural and type requirements for each message, including:

                                                                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                                                                            +
                                                                                                                                                                                                                                                                                          • A valid role from the ArtStandardMessageRole enum.
                                                                                                                                                                                                                                                                                          • +
                                                                                                                                                                                                                                                                                          • content that matches the expected type for a given role (e.g., string for 'user', string or null for 'assistant').
                                                                                                                                                                                                                                                                                          • +
                                                                                                                                                                                                                                                                                          • The presence of tool_call_id for 'tool' or 'tool_result' roles.
                                                                                                                                                                                                                                                                                          • +
                                                                                                                                                                                                                                                                                          • The structure of tool_calls when present in an 'assistant' message.
                                                                                                                                                                                                                                                                                          • +
                                                                                                                                                                                                                                                                                          +

                                                                                                                                                                                                                                                                                          It uses a .refine() method to implement context-aware validation based on the message's role.

                                                                                                                                                                                                                                                                                          +
                                                                                                                                                                                                                                                                                          diff --git a/docs/components/variables/ArtStandardPromptSchema.html b/docs/components/variables/ArtStandardPromptSchema.html new file mode 100644 index 0000000..aa5e1e1 --- /dev/null +++ b/docs/components/variables/ArtStandardPromptSchema.html @@ -0,0 +1,4 @@ +ArtStandardPromptSchema | ART Framework API Docs
                                                                                                                                                                                                                                                                                          ART Framework API Docs
                                                                                                                                                                                                                                                                                            Preparing search index...

                                                                                                                                                                                                                                                                                            Variable ArtStandardPromptSchemaConst

                                                                                                                                                                                                                                                                                            ArtStandardPromptSchema: ZodArray<
                                                                                                                                                                                                                                                                                                ZodEffects<
                                                                                                                                                                                                                                                                                                    ZodObject<
                                                                                                                                                                                                                                                                                                        {
                                                                                                                                                                                                                                                                                                            content: ZodUnion<[ZodString, ZodRecord<ZodString, ZodAny>, ZodNull]>;
                                                                                                                                                                                                                                                                                                            name: ZodOptional<ZodString>;
                                                                                                                                                                                                                                                                                                            role: ZodType<
                                                                                                                                                                                                                                                                                                                ArtStandardMessageRole,
                                                                                                                                                                                                                                                                                                                ZodTypeDef,
                                                                                                                                                                                                                                                                                                                ArtStandardMessageRole,
                                                                                                                                                                                                                                                                                                            >;
                                                                                                                                                                                                                                                                                                            tool_call_id: ZodOptional<ZodString>;
                                                                                                                                                                                                                                                                                                            tool_calls: ZodOptional<
                                                                                                                                                                                                                                                                                                                ZodArray<
                                                                                                                                                                                                                                                                                                                    ZodObject<
                                                                                                                                                                                                                                                                                                                        {
                                                                                                                                                                                                                                                                                                                            function: ZodObject<
                                                                                                                                                                                                                                                                                                                                { arguments: ZodString; name: ZodString },
                                                                                                                                                                                                                                                                                                                                "strip",
                                                                                                                                                                                                                                                                                                                                ZodTypeAny,
                                                                                                                                                                                                                                                                                                                                { arguments: string; name: string },
                                                                                                                                                                                                                                                                                                                                { arguments: string; name: string },
                                                                                                                                                                                                                                                                                                                            >;
                                                                                                                                                                                                                                                                                                                            id: ZodString;
                                                                                                                                                                                                                                                                                                                            type: ZodLiteral<"function">;
                                                                                                                                                                                                                                                                                                                        },
                                                                                                                                                                                                                                                                                                                        "strip",
                                                                                                                                                                                                                                                                                                                        ZodTypeAny,
                                                                                                                                                                                                                                                                                                                        {
                                                                                                                                                                                                                                                                                                                            function: { arguments: string; name: string };
                                                                                                                                                                                                                                                                                                                            id: string;
                                                                                                                                                                                                                                                                                                                            type: "function";
                                                                                                                                                                                                                                                                                                                        },
                                                                                                                                                                                                                                                                                                                        {
                                                                                                                                                                                                                                                                                                                            function: { arguments: string; name: string };
                                                                                                                                                                                                                                                                                                                            id: string;
                                                                                                                                                                                                                                                                                                                            type: "function";
                                                                                                                                                                                                                                                                                                                        },
                                                                                                                                                                                                                                                                                                                    >,
                                                                                                                                                                                                                                                                                                                    "many",
                                                                                                                                                                                                                                                                                                                >,
                                                                                                                                                                                                                                                                                                            >;
                                                                                                                                                                                                                                                                                                        },
                                                                                                                                                                                                                                                                                                        "strict",
                                                                                                                                                                                                                                                                                                        ZodTypeAny,
                                                                                                                                                                                                                                                                                                        {
                                                                                                                                                                                                                                                                                                            content: null
                                                                                                                                                                                                                                                                                                            | string
                                                                                                                                                                                                                                                                                                            | Record<string, any>;
                                                                                                                                                                                                                                                                                                            name?: string;
                                                                                                                                                                                                                                                                                                            role: ArtStandardMessageRole;
                                                                                                                                                                                                                                                                                                            tool_call_id?: string;
                                                                                                                                                                                                                                                                                                            tool_calls?: {
                                                                                                                                                                                                                                                                                                                function: { arguments: string; name: string };
                                                                                                                                                                                                                                                                                                                id: string;
                                                                                                                                                                                                                                                                                                                type: "function";
                                                                                                                                                                                                                                                                                                            }[];
                                                                                                                                                                                                                                                                                                        },
                                                                                                                                                                                                                                                                                                        {
                                                                                                                                                                                                                                                                                                            content: null
                                                                                                                                                                                                                                                                                                            | string
                                                                                                                                                                                                                                                                                                            | Record<string, any>;
                                                                                                                                                                                                                                                                                                            name?: string;
                                                                                                                                                                                                                                                                                                            role: ArtStandardMessageRole;
                                                                                                                                                                                                                                                                                                            tool_call_id?: string;
                                                                                                                                                                                                                                                                                                            tool_calls?: {
                                                                                                                                                                                                                                                                                                                function: { arguments: string; name: string };
                                                                                                                                                                                                                                                                                                                id: string;
                                                                                                                                                                                                                                                                                                                type: "function";
                                                                                                                                                                                                                                                                                                            }[];
                                                                                                                                                                                                                                                                                                        },
                                                                                                                                                                                                                                                                                                    >,
                                                                                                                                                                                                                                                                                                    {
                                                                                                                                                                                                                                                                                                        content: null
                                                                                                                                                                                                                                                                                                        | string
                                                                                                                                                                                                                                                                                                        | Record<string, any>;
                                                                                                                                                                                                                                                                                                        name?: string;
                                                                                                                                                                                                                                                                                                        role: ArtStandardMessageRole;
                                                                                                                                                                                                                                                                                                        tool_call_id?: string;
                                                                                                                                                                                                                                                                                                        tool_calls?: {
                                                                                                                                                                                                                                                                                                            function: { arguments: string; name: string };
                                                                                                                                                                                                                                                                                                            id: string;
                                                                                                                                                                                                                                                                                                            type: "function";
                                                                                                                                                                                                                                                                                                        }[];
                                                                                                                                                                                                                                                                                                    },
                                                                                                                                                                                                                                                                                                    {
                                                                                                                                                                                                                                                                                                        content: null
                                                                                                                                                                                                                                                                                                        | string
                                                                                                                                                                                                                                                                                                        | Record<string, any>;
                                                                                                                                                                                                                                                                                                        name?: string;
                                                                                                                                                                                                                                                                                                        role: ArtStandardMessageRole;
                                                                                                                                                                                                                                                                                                        tool_call_id?: string;
                                                                                                                                                                                                                                                                                                        tool_calls?: {
                                                                                                                                                                                                                                                                                                            function: { arguments: string; name: string };
                                                                                                                                                                                                                                                                                                            id: string;
                                                                                                                                                                                                                                                                                                            type: "function";
                                                                                                                                                                                                                                                                                                        }[];
                                                                                                                                                                                                                                                                                                    },
                                                                                                                                                                                                                                                                                                >,
                                                                                                                                                                                                                                                                                                "many",
                                                                                                                                                                                                                                                                                            > = ...

                                                                                                                                                                                                                                                                                            Zod schema for validating an entire ArtStandardPrompt (an array of messages).

                                                                                                                                                                                                                                                                                            +

                                                                                                                                                                                                                                                                                            This is a straightforward array schema that applies the ArtStandardMessageSchema to each element, +ensuring that every message in the prompt conforms to the required structure.

                                                                                                                                                                                                                                                                                            +
                                                                                                                                                                                                                                                                                            diff --git a/docs/components/variables/VERSION.html b/docs/components/variables/VERSION.html new file mode 100644 index 0000000..f5371ff --- /dev/null +++ b/docs/components/variables/VERSION.html @@ -0,0 +1,2 @@ +VERSION | ART Framework API Docs
                                                                                                                                                                                                                                                                                            ART Framework API Docs
                                                                                                                                                                                                                                                                                              Preparing search index...

                                                                                                                                                                                                                                                                                              Variable VERSIONConst

                                                                                                                                                                                                                                                                                              VERSION: "0.3.7" = '0.3.7'

                                                                                                                                                                                                                                                                                              The current version of the ART Framework package.

                                                                                                                                                                                                                                                                                              +
                                                                                                                                                                                                                                                                                              diff --git a/docs/concepts/mcp-system.md b/docs/concepts/mcp-system.md new file mode 100644 index 0000000..5252791 --- /dev/null +++ b/docs/concepts/mcp-system.md @@ -0,0 +1,753 @@ +0## MCP in the ART Framework + +### What this guide covers +- **Data model** expected by ART's MCP implementation +- **How discovery service cards map** to ART's `McpServerConfig` +- **Minimal ArtMcpConfig JSON** for a production-ready Linear HTTP server +- **Initialization & usage** with `McpManager` and proxy tools +- **Auth & CORS requirements** and troubleshooting +- The exact **Linear sample service card** and **discovery schema** (unchanged) + +### Architecture overview +- **ConfigManager**: Loads/persists `ArtMcpConfig` in `localStorage` under `art_mcp_config`, validates and auto-fixes missing arrays (`tools`, `resources`, `resourceTemplates`). +- **McpManager**: Reads config, optionally merges discovery results, pre-registers proxy tools, manages on-demand connections and authentication, and uninstalls servers. +- **McpProxyTool**: Wraps each MCP tool as an ART tool (schema-first), name format: `mcp_{serverId}_{toolName}`. +- **McpClientController**: Handles OAuth 2.1 + PKCE, session persistence, CORS via companion extension, streamable HTTP transport, tool listing/calls, token refresh, and sticky `Mcp-Session-Id`. +- **Persistence**: + - `localStorage`: `art_mcp_config`, `mcp_client_id` + - `sessionStorage`: `access_token`, `refresh_token`, `token_expires_at`, `mcp_oauth_discovery`, `mcp_session_id`, `code_verifier`, `state` + +### Data model expected by ART +- **ArtMcpConfig**: root object `{ mcpServers: Record }` +- **McpServerConfig** (per-server “card”): + - `id`: unique id (used in tool name prefix) + - `type`: `'streamable-http'` (browser-supported transport) + - `enabled`: boolean + - `displayName?`, `description?` + - `connection`: `StreamableHttpConnection` with `url` and optional `oauth` + - `installation?`: `{ source: 'git' | 'npm' | 'manual', ... }` + - `timeout?`: ms + - `tools`: `McpToolDefinition[]` (pre-registration hints; live discovery can replace/update) + - `resources`: `McpResource[]` (reserved; current client does not consume) + - `resourceTemplates`: `McpResourceTemplate[]` (reserved) +- **StreamableHttpConnection**: + - `url`: MCP stream endpoint + - `headers?`, `authStrategyId?` + - `oauth?` (PKCE): `{ type: 'pkce', authorizationEndpoint, tokenEndpoint, clientId, scopes, redirectUri, resource?, openInNewTab?, channelName? }` +- **McpToolDefinition**: `{ name, description?, inputSchema, outputSchema? }` + +### Mapping: Discovery Service Card → ART `McpServerConfig` +Use this one-way mapping to derive a config entry from a service card returned by your discovery endpoint (service_type = MCP_SERVICE): +- **Server identity** + - `id`: choose a stable identifier (e.g., `installation.configurationExtract.mcpServers[]` such as `linear-http`) + - `displayName`: `business.name` + - `description`: `business.description` +- **Transport** + - `type`: `'streamable-http'` (ART browser transport) + - `connection.url`: `specification.transport.endpoints.http` +- **Authentication (OAuth 2.1 + PKCE)** + - `connection.oauth.type`: `'pkce'` + - `connection.oauth.authorizationEndpoint`: `specification.authentication.authUrl` + - `connection.oauth.tokenEndpoint`: `specification.authentication.tokenUrl` + - `connection.oauth.clientId`: if using dynamic registration, set a placeholder like `'public'` (ART will register or synthesize an id at runtime) + - `connection.oauth.scopes`: space-delimited join of `specification.authentication.scopes` (e.g., "read write issues:create") + - `connection.oauth.redirectUri`: your app callback, e.g., `https://your.app/callback` + - `connection.oauth.resource?`: base MCP resource (often the same as `connection.url`) +- **Tools (optional pre-registration hints)** + - For each entry in `specification.tools`, copy `name`, `description`, and the JSON `inputSchema` into `McpToolDefinition`. Omit `outputFormat` or translate it to `outputSchema` if you have a concrete JSON Schema. +- **Resources / Templates** + - If the card lists resources, map them to `McpResource` (requires `uri` and `name`). If a URI isn’t provided by the card, leave `resources: []`. +- **Discovery-only fields** + - `registry`, `business.pricing`, operational metrics, etc., are not used at runtime by ART, but may be shown in your own UI. + +### Minimal ArtMcpConfig JSON (Linear HTTP) +This is a minimal, ready-to-use config entry derived from the sample Linear service card for the ART framework. It includes tool hints for immediate proxy registration; live discovery can refine them later. + +```json +{ + "mcpServers": { + "linear-http": { + "id": "linear-http", + "type": "streamable-http", + "enabled": true, + "displayName": "Linear MCP Server", + "description": "Linear MCP server using direct HTTP transport for issue tracking, project management, and team collaboration. Connects directly to Linear's remote MCP endpoint for seamless workflow integration.", + "connection": { + "url": "https://mcp.linear.app/mcp", + "oauth": { + "type": "pkce", + "authorizationEndpoint": "https://linear.app/oauth/authorize", + "tokenEndpoint": "https://linear.app/oauth/token", + "clientId": "public", + "scopes": "read write issues:create", + "redirectUri": "https://your.app/callback", + "resource": "https://mcp.linear.app/mcp" + } + }, + "timeout": 30000, + "tools": [ + { + "name": "list_issues", + "description": "List and filter issues in your Linear workspace with advanced search capabilities", + "inputSchema": { + "type": "object", + "properties": { + "assignee": {"type": "string", "description": "Filter by assignee name or ID"}, + "team": {"type": "string", "description": "Filter by team name or ID"}, + "state": {"type": "string", "description": "Filter by issue state (Todo, In Progress, Done, etc.)"}, + "project": {"type": "string", "description": "Filter by project name or ID"}, + "query": {"type": "string", "description": "Search query for issue title or description"}, + "limit": {"type": "number", "default": 25, "maximum": 100} + } + } + }, + { + "name": "create_issue", + "description": "Create a new Linear issue with full field support including priority, labels, and assignments", + "inputSchema": { + "type": "object", + "properties": { + "title": {"type": "string", "description": "Issue title (required)"}, + "description": {"type": "string", "description": "Detailed issue description in markdown format"}, + "team": {"type": "string", "description": "Team name or ID where issue should be created (required)"}, + "assignee": {"type": "string", "description": "Assignee username, email, or ID"}, + "priority": {"type": "number", "description": "Issue priority (0=No priority, 1=Urgent, 2=High, 3=Medium, 4=Low)", "minimum": 0, "maximum": 4}, + "labels": {"type": "array", "items": {"type": "string"}, "description": "Array of label names to apply to the issue"}, + "project": {"type": "string", "description": "Project name or ID to associate with the issue"}, + "dueDate": {"type": "string", "format": "date", "description": "Due date in YYYY-MM-DD format"}, + "estimate": {"type": "number", "description": "Story point estimate for the issue"} + }, + "required": ["title", "team"] + } + }, + { + "name": "update_issue", + "description": "Update an existing Linear issue with new information, status changes, or assignments", + "inputSchema": { + "type": "object", + "properties": { + "id": {"type": "string", "description": "Linear issue ID (required)"}, + "title": {"type": "string", "description": "New issue title"}, + "description": {"type": "string", "description": "New issue description in markdown"}, + "assignee": {"type": "string", "description": "New assignee username, email, or ID"}, + "priority": {"type": "number", "description": "New priority level (0-4)", "minimum": 0, "maximum": 4}, + "state": {"type": "string", "description": "New issue state (Todo, In Progress, Done, etc.)"}, + "project": {"type": "string", "description": "Move issue to different project"}, + "labels": {"type": "array", "items": {"type": "string"}, "description": "Replace current labels with new ones"} + }, + "required": ["id"] + } + }, + { + "name": "list_teams", + "description": "List all teams in your Linear workspace with member information", + "inputSchema": { + "type": "object", + "properties": { + "limit": {"type": "number", "default": 50, "maximum": 250} + } + } + } + ], + "resources": [], + "resourceTemplates": [] + } + } +} +``` + +### Initialization & usage +- Enable MCP and register tools from config (and optionally discovery): +```ts +import { McpManager } from '@/systems/mcp'; +import { ToolRegistry, StateManager } from '@/core/interfaces'; + +const toolRegistry: ToolRegistry = /* your registry */ null as any; +const stateManager: StateManager = /* your state manager */ null as any; + +const mcp = new McpManager(toolRegistry, stateManager); +await mcp.initialize({ enabled: true /*, discoveryEndpoint: 'https://your.discovery/api/services' */ }); +``` +- Tools from the Linear server will be registered with names like: + - `mcp_linear-http_list_issues` + - `mcp_linear-http_create_issue` + - `mcp_linear-http_update_issue` + - `mcp_linear-http_list_teams` +- Execute using your app’s tool invocation path (pass JSON matching each tool’s `inputSchema`). + +### Authentication & CORS +- The browser client performs OAuth 2.1 + PKCE and persists session tokens. +- Provide a route/handler for `/callback` to receive the authorization code (client will exchange it for tokens). +- ART requires a companion extension for CORS permissions; you must approve target hosts the first time. + +### Troubleshooting +- **OAuth failures**: Ensure your app serves `/callback`, scopes match, and time sync is reasonable. +- **Permission errors**: Approve the MCP host in the companion extension. +- **Missing tools**: Seed `tools` in config or run install/refresh logic that calls `listTools()`. +- **401 during tool call**: Token refresh is automatic; if it fails, a re-auth flow is triggered. + +--- + +### Sample Service Card (as-is; do not modify) +```json +{ + "registry": { + "id": "550e8400-e29b-41d4-a716-446655440021", + "service_type": "MCP_SERVICE", + "created_at": "2025-05-01T00:00:00.000000+00:00", + "updated_at": "2025-08-25T12:00:00.000000+00:00", + "owner_id": "linear", + "registry_status": "active" + }, + + "business": { + "name": "Linear MCP Server", + "description": "Linear MCP server using direct HTTP transport for issue tracking, project management, and team collaboration. Connects directly to Linear's remote MCP endpoint for seamless workflow integration.", + "version": "1.2.0", + "category": "project-management", + "tags": ["linear", "project-management", "issues", "teams", "productivity", "collaboration", "remote"], + "provider": { + "name": "Linear Orbit, Inc.", + "website": "https://linear.app", + "documentation": "https://linear.app/docs/mcp", + "support": "https://linear.app/contact" + }, + "pricing": { + "model": "freemium", + "free_tier": "Unlimited issues for up to 10 team members per workspace", + "rate_limits": { + "requests_per_minute": 1000, + "requests_per_hour": 60000 + }, + "paid_plans": [ + { + "name": "Standard", + "price": "$8", + "billing_period": "monthly", + "features": "Per user - unlimited everything + advanced features" + }, + { + "name": "Plus", + "price": "$14", + "billing_period": "monthly", + "features": "Per user - everything in Standard + advanced reporting and integrations" + } + ], + "terms_url": "https://linear.app/pricing" + }, + "operational_status": { + "status": "operational", + "last_checked": "2025-08-25T12:00:00Z", + "uptime_percentage": "99.9%", + "avg_response_time": "120ms", + "status_page_url": "https://status.linear.app" + } + }, + + "specification": { + "capabilities": { + "hasTools": true, + "hasResources": true, + "hasPrompts": false, + "supportsSampling": false, + "transport": ["http"], + "remoteServer": true, + "browserCompatible": true + }, + "tools": [ + { + "name": "list_issues", + "description": "List and filter issues in your Linear workspace with advanced search capabilities", + "whenToUse": "When you need to view, search, or filter issues by assignee, status, team, or project", + "inputSchema": { + "type": "object", + "properties": { + "assignee": {"type": "string", "description": "Filter by assignee name or ID"}, + "team": {"type": "string", "description": "Filter by team name or ID"}, + "state": {"type": "string", "description": "Filter by issue state (Todo, In Progress, Done, etc.)"}, + "project": {"type": "string", "description": "Filter by project name or ID"}, + "query": {"type": "string", "description": "Search query for issue title or description"}, + "limit": {"type": "number", "default": 25, "maximum": 100} + } + }, + "outputFormat": "Array of issue objects with ID, title, description, status, assignee, and project information" + }, + { + "name": "create_issue", + "description": "Create a new Linear issue with full field support including priority, labels, and assignments", + "whenToUse": "When you need to create tasks, bugs, feature requests, or project milestones", + "inputSchema": { + "type": "object", + "properties": { + "title": {"type": "string", "description": "Issue title (required)"}, + "description": {"type": "string", "description": "Detailed issue description in markdown format"}, + "team": {"type": "string", "description": "Team name or ID where issue should be created (required)"}, + "assignee": {"type": "string", "description": "Assignee username, email, or ID"}, + "priority": {"type": "number", "description": "Issue priority (0=No priority, 1=Urgent, 2=High, 3=Medium, 4=Low)", "minimum": 0, "maximum": 4}, + "labels": {"type": "array", "items": {"type": "string"}, "description": "Array of label names to apply to the issue"}, + "project": {"type": "string", "description": "Project name or ID to associate with the issue"}, + "dueDate": {"type": "string", "format": "date", "description": "Due date in YYYY-MM-DD format"}, + "estimate": {"type": "number", "description": "Story point estimate for the issue"} + }, + "required": ["title", "team"] + }, + "outputFormat": "Created issue object with ID, URL, and complete metadata" + }, + { + "name": "update_issue", + "description": "Update an existing Linear issue with new information, status changes, or assignments", + "whenToUse": "When you need to modify issue details, change status, reassign, or update project association", + "inputSchema": { + "type": "object", + "properties": { + "id": {"type": "string", "description": "Linear issue ID (required)"}, + "title": {"type": "string", "description": "New issue title"}, + "description": {"type": "string", "description": "New issue description in markdown"}, + "assignee": {"type": "string", "description": "New assignee username, email, or ID"}, + "priority": {"type": "number", "description": "New priority level (0-4)", "minimum": 0, "maximum": 4}, + "state": {"type": "string", "description": "New issue state (Todo, In Progress, Done, etc.)"}, + "project": {"type": "string", "description": "Move issue to different project"}, + "labels": {"type": "array", "items": {"type": "string"}, "description": "Replace current labels with new ones"} + }, + "required": ["id"] + }, + "outputFormat": "Updated issue object with changes reflected" + }, + { + "name": "list_teams", + "description": "List all teams in your Linear workspace with member information", + "whenToUse": "When you need to see available teams for issue assignment or project organization", + "inputSchema": { + "type": "object", + "properties": { + "limit": {"type": "number", "default": 50, "maximum": 250} + } + }, + "outputFormat": "Array of team objects with IDs, names, keys, and member information" + } + ], + "resources": [ + { + "name": "workspace_structure", + "description": "Access to Linear workspace hierarchy including teams, projects, and workflow states", + "mimeType": "application/json", + "whenToUse": "To understand team organization, project structure, and available workflow states" + } + ], + "prompts": [], + "authentication": { + "type": "oauth2.1", + "required": true, + "description": "OAuth 2.1 with dynamic client registration for secure workspace access", + "flows": ["authorization_code"], + "pkce": true, + "scopes": ["read", "write", "issues:create"], + "discoveryUrl": "https://mcp.linear.app/.well-known/oauth-authorization-server", + "authUrl": "https://linear.app/oauth/authorize", + "tokenUrl": "https://linear.app/oauth/token", + "dynamicClientRegistration": true + }, + "transport": { + "primary": "http", + "endpoints": { + "http": "https://mcp.linear.app/mcp" + }, + "browserCompatible": true + }, + "installation": { + "type": "external", + "requirements": [ + "HTTP-compatible MCP client", + "Linear workspace access with appropriate permissions", + "OAuth 2.1 + PKCE support in MCP client" + ], + "configurationExtract": { + "description": "Direct HTTP configuration for connecting to Linear's MCP endpoint", + "mcpServers": { + "linear-http": { + "url": "https://mcp.linear.app/mcp", + "transport": "http", + "authentication": { + "type": "oauth2.1", + "pkce": true, + "discoveryUrl": "https://mcp.linear.app/.well-known/oauth-authorization-server" + }, + "capabilities": ["tools", "resources"], + "disabled": false + } + } + }, + "setupInstructions": [ + "1. Copy the configurationExtract object to your MCP client configuration", + "2. Add the Linear MCP server configuration using the direct HTTP endpoint", + "3. Ensure your MCP client supports HTTP transport and OAuth 2.1 + PKCE", + "4. Save the configuration and restart your MCP client if required", + "5. On first connection, complete OAuth authorization flow in browser", + "6. Grant necessary permissions to your Linear workspace", + "7. Test connection by querying Linear data through your MCP client" + ], + "troubleshooting": [ + "OAuth failures: Ensure your MCP client supports OAuth 2.1 with PKCE", + "Connection timeouts: Verify HTTP transport is properly configured", + "Permission errors: Check Linear workspace access and granted OAuth scopes", + "Tool discovery issues: Confirm capabilities include 'tools' and 'resources'", + "Rate limiting: Respect Linear's API rate limits during heavy usage" + ] + } + } +} +``` + +### Discovery Schema (as-is; do not modify) +```json +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "title": "Universal Service Card Schema v2.0", + "description": "Three-layer architecture supporting MCP, A2A, LLM Gateway, and future protocols with complete standards compliance", + "type": "object", + "properties": { + "registry": { + "type": "object", + "description": "Registry management metadata - internal to service catalog system", + "properties": { + "id": { + "type": "string", + "format": "uuid", + "description": "Unique identifier for the service registry entry" + }, + "service_type": { + "type": "string", + "enum": ["MCP_SERVICE", "A2A_AGENT", "LLM_GATEWAY"], + "description": "Protocol type - determines validation rules for specification section" + }, + "created_at": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp when service was registered" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "description": "ISO 8601 timestamp when registry entry was last updated" + }, + "owner_id": { + "type": "string", + "description": "Identifier of the service owner/provider in the registry system" + }, + "registry_status": { + "type": "string", + "enum": ["active", "inactive", "deprecated", "pending_review"], + "description": "Registry-level status for service catalog management" + } + }, + "required": ["id", "service_type", "created_at", "updated_at", "owner_id", "registry_status"], + "additionalProperties": false + }, + + "business": { + "type": "object", + "description": "Business and operational metadata common across all service types", + "properties": { + "name": { + "type": "string", + "description": "Human-readable service name" + }, + "description": { + "type": "string", + "description": "Comprehensive description of service functionality and value proposition" + }, + "version": { + "type": "string", + "description": "Service version (semantic versioning recommended: major.minor.patch)" + }, + "category": { + "type": "string", + "description": "Primary service category for organization and discovery", + "examples": ["productivity", "development", "data-analysis", "communication", "entertainment"] + }, + "tags": { + "type": "array", + "items": {"type": "string"}, + "description": "Searchable tags for service discovery and categorization" + }, + "provider": { + "type": "object", + "description": "Information about the service provider organization", + "properties": { + "name": {"type": "string", "description": "Provider/organization name"}, + "website": {"type": "string", "format": "uri", "description": "Provider main website URL"}, + "documentation": {"type": "string", "format": "uri", "description": "Service-specific documentation URL"}, + "support": {"type": "string", "format": "uri", "description": "Support contact URL or email"} + }, + "required": ["name"], + "additionalProperties": false + }, + "pricing": { + "type": "object", + "description": "Commercial and usage terms", + "properties": { + "model": { + "type": "string", + "enum": ["free", "freemium", "paid", "enterprise", "usage_based"], + "description": "Primary pricing model" + }, + "free_tier": { + "type": "string", + "description": "Description of free usage allowances, if any" + }, + "rate_limits": { + "type": "object", + "description": "Usage rate limits and quotas", + "properties": { + "requests_per_minute": {"type": "number"}, + "requests_per_hour": {"type": "number"}, + "requests_per_day": {"type": "number"}, + "requests_per_month": {"type": "number"} + }, + "additionalProperties": false + }, + "paid_plans": { + "type": "array", + "description": "Available paid service tiers", + "items": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "price": {"type": "string"}, + "billing_period": {"type": "string", "enum": ["monthly", "annual", "per_usage"]}, + "features": {"type": "string"} + }, + "required": ["name", "price"], + "additionalProperties": false + } + }, + "terms_url": { + "type": "string", + "format": "uri", + "description": "URL to detailed pricing and terms of service" + } + }, + "required": ["model"], + "additionalProperties": false + }, + "operational_status": { + "type": "object", + "description": "Real-time operational health and availability information", + "properties": { + "status": { + "type": "string", + "enum": ["operational", "degraded", "maintenance", "outage"], + "description": "Current operational state" + }, + "last_checked": { + "type": "string", + "format": "date-time", + "description": "Last health check timestamp" + }, + "uptime_percentage": { + "type": "string", + "description": "Service uptime percentage (e.g., '99.9%')" + }, + "avg_response_time": { + "type": "string", + "description": "Average response time (e.g., '120ms')" + }, + "status_page_url": { + "type": "string", + "format": "uri", + "description": "URL to detailed status page" + }, + "incidents": { + "type": "array", + "description": "Recent incidents or maintenance notices", + "items": { + "type": "object", + "properties": { + "date": {"type": "string", "format": "date-time"}, + "severity": {"type": "string", "enum": ["info", "warning", "critical"]}, + "summary": {"type": "string"}, + "resolved": {"type": "boolean"} + } + } + } + }, + "required": ["status", "last_checked"], + "additionalProperties": false + } + }, + "required": ["name", "description", "version", "category", "provider", "pricing"], + "additionalProperties": false + }, + + "specification": { + "description": "Complete protocol-specific specification - native format per protocol standards", + "oneOf": [ + { + "if": { + "properties": { + "registry": { + "properties": {"service_type": {"const": "MCP_SERVICE"}} + } + } + }, + "then": { + "type": "object", + "description": "Complete MCP Server specification as defined by MCP protocol standards", + "properties": { + "capabilities": {"type": "object"}, + "tools": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "description": {"type": "string"}, + "whenToUse": {"type": "string", "description": "Guidance for when to use this tool"}, + "inputSchema": {"type": "object"}, + "outputFormat": {"type": "string"} + } + } + }, + "resources": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "description": {"type": "string"}, + "mimeType": {"type": "string"}, + "whenToUse": {"type": "string", "description": "Guidance for when to use this resource"} + } + } + }, + "prompts": { + "type": "array", + "items": { + "type": "object", + "properties": { + "name": {"type": "string"}, + "description": {"type": "string"}, + "whenToUse": {"type": "string", "description": "Guidance for when to use this prompt"} + } + } + }, + "authentication": {"type": "object"}, + "transport": {"type": "object"}, + "installation": { + "type": "object", + "properties": { + "type": {"type": "string"}, + "requirements": { + "type": "array", + "items": {"type": "string"}, + "description": "Setup requirements and prerequisites" + }, + "configurationExtract": {"type": "object"}, + "setupInstructions": { + "type": "array", + "items": {"type": "string"}, + "description": "Step-by-step setup guide" + }, + "troubleshooting": { + "type": "array", + "items": {"type": "string"}, + "description": "Common issues and solutions" + } + } + } + }, + "required": ["capabilities"], + "additionalProperties": true + } + }, + { + "if": { + "properties": { + "registry": { + "properties": {"service_type": {"const": "A2A_AGENT"}} + } + } + }, + "then": { + "type": "object", + "description": "Complete A2A AgentCard specification as defined by A2A protocol standards", + "properties": { + "url": {"type": "string", "format": "uri"}, + "provider": {"type": "object"}, + "documentationUrl": {"type": "string", "format": "uri"}, + "capabilities": {"type": "object"}, + "authentication": {"type": "object"}, + "defaultInputModes": {"type": "array"}, + "defaultOutputModes": {"type": "array"}, + "skills": {"type": "array"} + }, + "required": ["url", "capabilities", "authentication", "skills"], + "additionalProperties": true + } + }, + { + "if": { + "properties": { + "registry": { + "properties": {"service_type": {"const": "LLM_GATEWAY"}} + } + } + }, + "then": { + "type": "object", + "description": "Complete LLM Gateway specification", + "properties": { + "models": {"type": "array"}, + "endpoints": {"type": "object"}, + "authentication": {"type": "object"}, + "rate_limits": {"type": "object"}, + "supported_formats": {"type": "array"} + }, + "required": ["models", "endpoints", "authentication"], + "additionalProperties": true + } + } + ] + } + }, + "required": ["registry", "business", "specification"], + "additionalProperties": false, + + "examples": [ + { + "title": "MCP Service Example Structure", + "registry": { + "service_type": "MCP_SERVICE" + }, + "business": { + "name": "Linear MCP Server", + "category": "project-management" + }, + "specification": { + "capabilities": {"hasTools": true, "hasResources": true}, + "tools": [], + "authentication": {"type": "oauth2.1"}, + "transport": {"primary": "http"} + } + }, + { + "title": "A2A Agent Example Structure", + "registry": { + "service_type": "A2A_AGENT" + }, + "business": { + "name": "Travel Planning Agent", + "category": "travel" + }, + "specification": { + "url": "https://api.example.com/a2a", + "capabilities": {"streaming": true}, + "authentication": {"schemes": ["Bearer"]}, + "skills": [] + } + } + ] +} +``` + + diff --git a/docs/concepts/pes-agent.md b/docs/concepts/pes-agent.md new file mode 100644 index 0000000..b8e1c4f --- /dev/null +++ b/docs/concepts/pes-agent.md @@ -0,0 +1,400 @@ +# PES Agent Concept Document + +## Overview + +The PES (Plan-Execute-Synthesize) Agent is a core component of the ART framework that implements a structured approach to AI agent orchestration. It follows a three-phase execution model that separates planning, execution, and response synthesis to create more reliable and explainable AI interactions. + +## Key Components and Their Roles + +### 1. PESAgent Class +The main orchestrator that implements the IAgentCore interface. It coordinates all phases of the agent execution cycle. + +### 2. Dependencies +The PESAgent relies on several key dependencies that are injected at initialization: +- **StateManager**: Manages thread configuration and state +- **ConversationManager**: Handles conversation history +- **ToolRegistry**: Manages available tools +- **ReasoningEngine**: Interfaces with LLM providers +- **OutputParser**: Parses LLM responses +- **ObservationManager**: Records execution events +- **ToolSystem**: Orchestrates tool execution +- **UISystem**: Provides UI communication sockets +- **A2ATaskRepository**: Manages Agent-to-Agent tasks +- **AgentDiscoveryService**: Discovers remote agents +- **TaskDelegationService**: Delegates tasks to remote agents +- **SystemPromptResolver**: Resolves system prompt hierarchy + +### 3. Agent Persona +Defines the identity and guidance for the agent with separate prompts for planning and synthesis phases. + +## Workflow of the PES Agent + +The PES agent follows a structured 8-phase workflow: + +1. **Configuration Loading** + - Loads thread context and configuration + - Resolves system prompts through the hierarchy (call → thread → instance) + - Determines runtime provider configuration + +2. **Context Gathering** + - Retrieves conversation history based on thread configuration + - Gathers available tools for the current thread + +3. **Planning Phase** + - Constructs a planning prompt with: + - System prompt guidance + - Conversation history + - Available tools (including virtual delegation tool) + - Agent delegation context + - Calls the LLM for planning + - Parses the planning output to extract: + - Thread title + - User intent + - Execution plan + - Tool calls + - Records observations for each planning element + +4. **A2A Task Delegation** + - Identifies delegation tool calls in the plan + - Delegates tasks to remote agents through the A2A system + - Persists task information in the repository + +5. **A2A Task Completion Waiting** + - Waits for delegated tasks to complete with configurable timeout + - Polls task status periodically + - Updates task information with results + +6. **Tool Execution** + - Executes local tool calls identified in the planning phase + - Records tool execution results and errors + - Handles partial success scenarios + +7. **Synthesis Phase** + - Constructs a synthesis prompt with: + - System prompt guidance + - Conversation history + - Planning output + - Tool execution results + - A2A task results + - Calls the LLM for final response generation + - Parses the final response to extract: + - Main content + - UI metadata (sources, suggestions) + - Records synthesis observations + +8. **Finalization** + - Saves the final AI response message + - Records the final response observation + - Saves state if modified + +## Statement Features and Developer Usage + +### 1. System Prompt Hierarchy +Developers can customize agent behavior through a three-level system prompt hierarchy: +- **Instance Level**: Default prompts defined when creating the ART instance +- **Thread Level**: Thread-specific prompts that override instance defaults +- **Call Level**: Per-call prompts that override thread and instance defaults + +Usage: +```typescript +import { createArtInstance } from 'art-framework'; +import type { ArtInstanceConfig } from 'art-framework'; + +// Instance level (in ArtInstanceConfig) +const config: ArtInstanceConfig = { + storage: { type: 'memory' }, + providers: { + // Your provider configuration + }, + persona: { + name: "CustomAgent", + prompts: { + planning: "You are a specialized planning assistant...", + synthesis: "You are a specialized synthesis assistant..." + } + } +}; + +const art = await createArtInstance(config); + +// Thread level +await art.stateManager.setThreadConfig(threadId, { + providerConfig: { + // Your provider configuration + }, + enabledTools: [], + historyLimit: 10, + persona: { + name: "ThreadAgent", + prompts: { + planning: "You are a thread-specific planning assistant...", + synthesis: "You are a thread-specific synthesis assistant..." + } + } +}); + +// Call level +const response = await art.process({ + query: "What is the weather today?", + threadId: "thread-123", + options: { + persona: { + name: "CallAgent", + prompts: { + planning: "You are a call-specific planning assistant...", + synthesis: "You are a call-specific synthesis assistant..." + } + } + } +}); +``` + +### 2. Observation System +The PES agent records detailed observations throughout execution: +- INTENT: User intent identified during planning +- TITLE: Thread title generated during planning +- PLAN: Execution plan generated during planning +- THOUGHTS: Internal reasoning during LLM calls +- TOOL_CALL: Tool calls identified in the plan +- TOOL_EXECUTION: Results of tool executions +- SYNTHESIS: Events during response synthesis +- ERROR: Any errors encountered +- FINAL_RESPONSE: The final AI response +- STATE_UPDATE: Changes to agent state +- LLM_STREAM_*: Events related to LLM streaming + +Usage: +```typescript +import { ObservationType } from 'art-framework'; + +// Subscribe to observations +const unsubscribe = art.uiSystem.getObservationSocket().subscribe( + (observation) => { + console.log(`Observation: ${observation.type}`, observation.content); + }, + [ObservationType.TITLE, ObservationType.INTENT, ObservationType.PLAN], + { threadId: "thread-123" } +); +``` + +### 3. Streaming Support +The PES agent supports streaming responses with detailed token typing: +- AGENT_THOUGHT_LLM_THINKING: Planning phase thinking tokens +- AGENT_THOUGHT_LLM_RESPONSE: Planning phase response tokens +- FINAL_SYNTHESIS_LLM_THINKING: Synthesis phase thinking tokens +- FINAL_SYNTHESIS_LLM_RESPONSE: Synthesis phase response tokens + +Usage: +```typescript +// Subscribe to LLM stream events +const unsubscribe = art.uiSystem.getLLMStreamSocket().subscribe( + (event) => { + if (event.type === 'TOKEN') { + switch (event.tokenType) { + case 'FINAL_SYNTHESIS_LLM_RESPONSE': + // Add token to final response display + addToResponseDisplay(event.data); + break; + case 'AGENT_THOUGHT_LLM_THINKING': + // Show planning thoughts + showPlanningThoughts(event.data); + break; + } + } + }, + undefined, + { threadId: "thread-123" } +); +``` + +### 4. A2A (Agent-to-Agent) Task System +The PES agent supports delegating tasks to remote agents: +- Automatic agent discovery based on task type +- Task delegation with persistence +- Asynchronous task completion waiting +- Result integration in synthesis + +Usage: +```typescript +import type { ArtInstanceConfig } from 'art-framework'; + +// The agent automatically discovers and delegates to remote agents +// Developers can configure the A2A system at the instance level +const config: ArtInstanceConfig = { + storage: { type: 'memory' }, + providers: { + // Your provider configuration + }, + a2aConfig: { + discoveryEndpoint: "https://a2a-discovery.example.com", + callbackUrl: "https://myapp.example.com/a2a-callback" + } +}; + +const art = await createArtInstance(config); +``` + +### 5. Tool System Integration +The PES agent seamlessly integrates with the ART tool system: +- Automatic tool discovery for threads +- Tool call planning and execution +- Result integration in synthesis +- Error handling and partial success support + +Usage: +```typescript +import { IToolExecutor } from 'art-framework'; +import type { ToolSchema, ToolResult, ExecutionContext } from 'art-framework'; + +// Register custom tools +class CustomTool implements IToolExecutor { + readonly schema: ToolSchema = { + name: "custom_tool", + description: "A custom tool that does something useful", + inputSchema: { + type: "object", + properties: { + param1: { type: "string", description: "First parameter" }, + param2: { type: "number", description: "Second parameter" } + }, + required: ["param1"] + } + }; + + async execute(input: any, context: ExecutionContext): Promise { + // Implementation + return { + callId: "call-id", + toolName: this.schema.name, + status: "success", + output: { result: "Custom tool executed successfully" } + }; + } +} + +// Register tool when creating ART instance +const config: ArtInstanceConfig = { + storage: { type: 'memory' }, + providers: { + // Your provider configuration + }, + tools: [new CustomTool()] +}; + +const art = await createArtInstance(config); +``` + +## When to Use Different Features + +### System Prompt Customization +- Use instance-level prompts for application-wide agent behavior +- Use thread-level prompts for conversation-specific behavior +- Use call-level prompts for dynamic behavior based on user input + +### Observation System +- Use TITLE observations for updating conversation titles in UI +- Use INTENT observations for showing user intent +- Use PLAN observations for displaying execution steps +- Use THOUGHTS observations for showing agent reasoning +- Use ERROR observations for error handling and debugging + +### Streaming +- Use streaming for real-time user feedback during long operations +- Use token typing to differentiate between planning and synthesis phases +- Use thinking tokens to show agent's internal reasoning process + +### A2A Task System +- Use when specialized agents can better handle specific subtasks +- Use when you need to distribute workload across multiple agents +- Use when you want to leverage pre-trained specialized models + +### Tool System +- Use for extending agent capabilities with custom functionality +- Use for integrating with external APIs and services +- Use for implementing domain-specific logic + +## Workflow Flowchart + +```mermaid +flowchart TD + A[Start: User Query] --> B[Load Configuration] + B --> C[Gather Context] + C --> D[Planning Phase] + D --> E[Parse Planning Output] + E --> F[A2A Task Delegation] + F --> G[A2A Task Completion] + G --> H[Tool Execution] + H --> I[Synthesis Phase] + I --> J[Parse Final Response] + J --> K[Finalization] + K --> L[Save State] + L --> M[Return Response] + + subgraph Configuration + B1[Load Thread Context] + B2[Resolve System Prompts] + B3[Determine Provider Config] + B --> B1 --> B2 --> B3 --> C + end + + subgraph Context_Gathering + C1[Gather History] + C2[Gather Tools] + C --> C1 --> C2 --> D + end + + subgraph Planning + D1[Construct Planning Prompt] + D2[LLM Call for Planning] + D3[Stream Planning Tokens] + D --> D1 --> D2 --> D3 --> E + end + + subgraph Planning_Parse + E1[Parse Intent/Title] + E2[Parse Plan] + E3[Parse Tool Calls] + E --> E1 --> E2 --> E3 --> F + end + + subgraph A2A_Delegation + F1[Identify Delegation Calls] + F2[Delegate to Remote Agents] + F3[Persist Task Data] + F --> F1 --> F2 --> F3 --> G + end + + subgraph A2A_Waiting + G1[Wait for Task Completion] + G2[Poll Task Status] + G3[Update Task Results] + G --> G1 --> G2 --> G3 --> H + end + + subgraph Tool_Execution + H1[Execute Local Tools] + H2[Record Tool Results] + H --> H1 --> H2 --> I + end + + subgraph Synthesis + I1[Construct Synthesis Prompt] + I2[LLM Call for Synthesis] + I3[Stream Response Tokens] + I --> I1 --> I2 --> I3 --> J + end + + subgraph Synthesis_Parse + J1[Extract Main Content] + J2[Extract UI Metadata] + J --> J1 --> J2 --> K + end + + subgraph Finalization + K1[Save AI Response] + K2[Record Final Observation] + K --> K1 --> K2 --> L + end +``` + +The PES agent provides a robust, extensible framework for building AI applications with clear separation of concerns, detailed observability, and support for both local and distributed agent architectures. \ No newline at end of file diff --git a/docs/concepts/state-management.md b/docs/concepts/state-management.md new file mode 100644 index 0000000..23e2ef0 --- /dev/null +++ b/docs/concepts/state-management.md @@ -0,0 +1,202 @@ +# ART Framework State Management Concept + +## Overview + +The ART (Agentic Reactive Triad) Framework provides a robust and flexible state management system that allows agents to maintain persistent memory across conversation turns. This system is centered around three key concepts: + +1. **ThreadConfig**: Configuration settings for a specific conversation thread +2. **AgentState**: Dynamic, evolving state data that agents can use as memory +3. **StateManager**: The orchestration layer that manages loading, saving, and caching of thread context + +## Core Components + +### ThreadConfig + +`ThreadConfig` holds the configuration for a single conversation thread. This includes: + +- Provider configuration (which LLM provider and model to use) +- Enabled tools for this thread +- History limit (how many past messages to retrieve) +- System prompt overrides +- Agent persona customizations + +This configuration is typically set once when a new conversation starts and remains relatively static throughout the conversation. + +### AgentState + +`AgentState` represents the dynamic, evolving state of the agent for a specific thread. This serves as the agent's "memory" and can store: + +- Conversation summaries +- User preferences +- Accumulated knowledge +- Any other data the agent needs to remember across turns + +The `AgentState` interface is defined as: + +```typescript +interface AgentState { + data: any; + version?: number; + [key: string]: any; +} +``` + +This flexible structure allows agents to store any JSON-serializable data they need. + +### ThreadContext + +`ThreadContext` is a container that holds both `ThreadConfig` and `AgentState` for a thread: + +```typescript +interface ThreadContext { + config: ThreadConfig; + state: AgentState | null; +} +``` + +### StateManager + +The `StateManager` is the central service that orchestrates loading, saving, and caching of `ThreadConfig` and `AgentState`. It acts as an abstraction layer over the configured `StorageAdapter`. + +Key features of the StateManager include: + +1. **Thread Context Management**: Loading and saving complete thread contexts +2. **State Saving Strategies**: Supporting both explicit and implicit state saving +3. **Tool Permission Management**: Enabling/disabling tools for specific threads +4. **Configuration Management**: Managing thread-specific configurations + +## State Saving Strategies + +The ART framework supports two state saving strategies that can be configured when creating an ART instance: + +### Explicit Strategy (Default) + +In this mode, the agent's state is only saved when you explicitly call `art.stateManager.setAgentState()`. This gives you full control but requires you to manage state saving manually within your agent's logic. + +```typescript +const config: ArtInstanceConfig = { + // ... other config + stateSavingStrategy: 'explicit' +}; +``` + +### Implicit Strategy + +In this mode, the `StateManager` automatically saves the `AgentState` at the end of a processing cycle, but only if it detects that the state object has been modified. It does this by keeping a snapshot of the state from when it was loaded and comparing it to the state after the agent has run. + +```typescript +const config: ArtInstanceConfig = { + // ... other config + stateSavingStrategy: 'implicit' +}; +``` + +## Storage Adapters + +The state management system uses storage adapters to persist data. ART provides several built-in adapters: + +1. **InMemoryStorageAdapter**: Keeps all data in memory (not persistent) +2. **IndexedDBStorageAdapter**: Uses browser's IndexedDB for client-side persistence +3. **SupabaseStorageAdapter**: Connects to a Supabase (Postgres) database for server-side/cloud persistence + +## Working with State in Practice + +### Initializing Thread Configuration + +Before an agent can process requests for a new thread, you must set up its initial configuration: + +```typescript +await art.stateManager.setThreadConfig(threadId, { + providerConfig: { + provider: 'openai', + model: 'gpt-4', + apiKey: 'your-api-key' + }, + enabledTools: ['calculator', 'web-search'], + historyLimit: 10 +}); +``` + +### Loading Thread Context + +The agent automatically loads thread context when processing requests, but you can also load it manually: + +```typescript +const context = await art.stateManager.loadThreadContext(threadId); +``` + +### Saving Agent State + +With the explicit strategy, you explicitly save state: + +```typescript +await art.stateManager.setAgentState(threadId, { + data: { + conversationSummary: 'User is asking about state management', + preferences: { theme: 'dark' } + }, + version: 1 +}); +``` + +With the implicit strategy, the state manager automatically detects changes and saves them at the end of the processing cycle. + +### Modifying Thread Configuration + +You can dynamically modify thread configurations: + +```typescript +// Enable additional tools +await art.stateManager.enableToolsForThread(threadId, ['file-upload']); + +// Disable tools +await art.stateManager.disableToolsForThread(threadId, ['web-search']); + +// Get currently enabled tools +const tools = await art.stateManager.getEnabledToolsForThread(threadId); +``` + +## Advanced Features + +### Tool Permission Management + +The StateManager provides granular control over which tools are available to each thread: + +```typescript +// Check if a tool is enabled +const isEnabled = await art.stateManager.isToolEnabled(threadId, 'calculator'); + +// Enable specific tools +await art.stateManager.enableToolsForThread(threadId, ['calculator', 'web-search']); + +// Disable specific tools +await art.stateManager.disableToolsForThread(threadId, ['dangerous-tool']); +``` + +### Configuration Value Retrieval + +You can retrieve specific configuration values: + +```typescript +const model = await art.stateManager.getThreadConfigValue(threadId, 'providerConfig.model'); +const historyLimit = await art.stateManager.getThreadConfigValue(threadId, 'historyLimit'); +``` + +## Best Practices + +1. **Initialize Configuration First**: Always set up the thread configuration before processing requests +2. **Use Appropriate Storage Adapter**: Choose the right storage adapter for your use case (memory for testing, IndexedDB for web apps, Supabase for server/cloud apps) +3. **Consider State Saving Strategy**: Use explicit strategy for fine-grained control, implicit for automatic management +4. **Handle State Updates Efficiently**: With implicit strategy, modify the state object in place rather than replacing it entirely +5. **Version Your State**: Use the version field in AgentState to track state schema changes + +## Integration with Agent Processing + +The state management system is deeply integrated with the agent processing flow: + +1. **Context Loading**: Agent loads ThreadConfig and AgentState at the beginning of processing +2. **State Modification**: Agent can modify AgentState during processing +3. **Automatic Saving**: With implicit strategy, StateManager automatically saves modified state at the end +4. **Explicit Saving**: With explicit strategy, agent must call setAgentState to persist changes + +This integration ensures that agents can maintain persistent memory across conversation turns while providing developers with flexible control over how that state is managed. \ No newline at end of file diff --git a/docs/concepts/ui-system.md b/docs/concepts/ui-system.md new file mode 100755 index 0000000..7616fff --- /dev/null +++ b/docs/concepts/ui-system.md @@ -0,0 +1,367 @@ +# ART Framework UI System + +The UI System in the ART Framework is the bridge between the core agent logic and the user interface. It provides a reactive and robust mechanism for displaying data, capturing user interactions, and visualizing the agent's internal state in real-time. This system is designed to be flexible, allowing developers to build a wide range of UIs, from simple chat windows to complex debugging and task management dashboards. + +## Core Architecture + +The architecture is centered around the `UISystem`, a central hub that provides access to four specialized **sockets**. Each socket is a dedicated communication channel for a specific type of data. This separation of concerns ensures that UI components only subscribe to the data they need, making the system efficient and scalable. + +All sockets are built on a publish-subscribe model. UI components can **subscribe** to a socket to receive real-time updates and can also query the socket to retrieve **historical data**. + +### Data Flow Diagram + +The general data flow follows a clear pattern: a manager within the framework processes data, stores it in a repository, and then notifies the corresponding socket, which in turn broadcasts the data to all subscribed UI components. + +```mermaid +graph TD; + A[UI Component e.g., Chatbox] -- Subscribes to --> B((Sockets)); + B -- Notifies --> A; + C[Managers e.g., ConversationManager] -- Notifies --> B; + B -- getHistory() --> D{Repositories}; + D -- Reads from/Writes to --> E[Storage Adapter e.g., IndexedDB]; + C -- Writes to --> D; + + subgraph Core Logic + C + D + E + end + + subgraph UI System + B + end + + subgraph Application UI + A + end +``` + +## The Sockets + +The `UISystem` provides access to the following four sockets: + +1. **`ConversationSocket`**: For chat messages. +2. **`ObservationSocket`**: For the agent's internal events and "thoughts". +3. **`LLMStreamSocket`**: For real-time streaming of the Language Model's output. +4. **`A2ATaskSocket`**: For monitoring tasks in multi-agent systems. + +--- + +### 1. `ConversationSocket` + +This is the primary socket for building chat interfaces. It manages the flow of messages between the user and the agent. + +#### Purpose + +- Display real-time conversation history. +- Load past messages in a conversation thread. + +#### Data Transmitted: `ConversationMessage` + +Each message sent through this socket is an object with the following structure: + +| Field | Type | Description | +| :---------- | :---------------------------------- | :----------------------------------------------------------------------- | +| `messageId` | `string` | A unique identifier for the message. | +| `threadId` | `string` | The identifier of the conversation thread. | +| `role` | `enum` (`USER`, `AI`, `SYSTEM`, `TOOL`) | The sender of the message. | +| `content` | `string` | The textual content of the message. | +| `timestamp` | `number` | A Unix timestamp (in milliseconds) when the message was created. | +| `metadata` | `object` (optional) | Any additional data, such as related tool call information. | + +#### Options and Props + +- **Subscription Filter**: You can subscribe to messages from a specific `role` (or an array of roles) to only receive messages from the user or the AI, for example. +- **`getHistory(options)`**: Retrieves an array of past `ConversationMessage` objects. + - `threadId`: The required ID of the conversation to load. + - `limit`: The maximum number of messages to retrieve. + +--- + +### 2. `ObservationSocket` + +This socket provides a window into the agent's "mind," broadcasting events that occur during its execution cycle. It's invaluable for debugging and for UIs that want to show the agent's "thought process." + +#### Purpose + +- Visualize the agent's step-by-step plan. +- Display tool calls and their results. +- Debug errors and monitor the agent's state. + +#### Data Transmitted: `Observation` + +| Field | Type | Description | +| :---------- | :---------------------- | :----------------------------------------------------------------------- | +| `id` | `string` | A unique identifier for the observation. | +| `threadId` | `string` | The identifier of the conversation thread. | +| `traceId` | `string` (optional) | An identifier for tracing a request across multiple components. | +| `timestamp` | `number` | A Unix timestamp (in milliseconds). | +| `type` | `enum` (`INTENT`, `PLAN`, ...) | The category of the event (see `ObservationType` enum in `types/index.ts` for a full list). | +| `title` | `string` | A concise, human-readable summary of the observation. | +| `content` | `any` | The main data payload, which varies depending on the `type`. | +| `metadata` | `object` (optional) | Additional context, such as the source of the event. | + +#### Options and Props + +- **Subscription Filter**: Subscriptions can be filtered by `ObservationType` (or an array of types) to listen for specific events, like `TOOL_CALL`. +- **`getHistory(filter, options)`**: Retrieves past `Observation` objects. + - `filter`: An `ObservationType` or array of types. + - `options`: An object containing the required `threadId` and an optional `limit`. + +--- + +### 3. `LLMStreamSocket` + +This socket is designed for high-performance, real-time UI updates. It streams the raw output from the Language Model as it's being generated. + +#### Purpose + +- Create a "typewriter" or streaming text effect for the agent's responses. +- Differentiate between the agent's internal "thinking" tokens and its final response. +- Handle stream-related events like metadata and errors. + +#### Data Transmitted: `StreamEvent` + +| Field | Type | Description | +| :---------- | :------------------------------------ | :----------------------------------------------------------------------- | +| `type` | `'TOKEN'`, `'METADATA'`, `'ERROR'`, `'END'` | The type of the stream event. | +| `data` | `any` | The content of the event (e.g., a `string` for `TOKEN`, an `object` for `METADATA`). | +| `tokenType` | `string` (optional, enum-like) | A specific classification for `TOKEN` events (e.g., `AGENT_THOUGHT_LLM_RESPONSE`). | +| `threadId` | `string` | The identifier of the conversation thread. | +| `traceId` | `string` | The identifier for the agent execution cycle. | +| `sessionId` | `string` (optional) | An identifier for a specific UI tab or window. | + +#### Options and Props + +- **Subscription Filter**: Subscriptions can be filtered by the `type` of the `StreamEvent`. +- **`getHistory()`**: Not implemented, as stream events are transient and not persisted. + +--- + +### 4. `A2ATaskSocket` + +This socket is for advanced use cases involving multiple agents. It monitors the entire lifecycle of agent-to-agent (A2A) tasks. + +#### Purpose + +- Build dashboards to track the status of tasks delegated between agents. +- Manage and visualize complex workflows in multi-agent systems. +- Debug task failures and monitor agent workloads. + +#### Data Transmitted: `A2ATaskEvent` + +This event is a wrapper that contains information about the event itself (`eventType`, `timestamp`) and the full task object. The core data is the `task` property, which is an `A2ATask` object. + +| Field (`A2ATask`) | Type | Description | +| :---------------- | :-------------------- | :----------------------------------------------------------------------- | +| `taskId` | `string` | Unique identifier for the task. | +| `threadId` | `string` | The thread this task belongs to. | +| `status` | `enum` (`PENDING`, ...) | The current status of the task. | +| `payload` | `object` | The task's parameters, including `taskType` and `input` data. | +| `sourceAgent` | `A2AAgentInfo` | Information about the agent that created the task. | +| `targetAgent` | `A2AAgentInfo` (opt) | Information about the agent assigned to the task. | +| `priority` | `enum` (`LOW`, ...) | The priority level of the task. | +| `metadata` | `A2ATaskMetadata` | Timestamps, retry counts, correlation IDs, etc. | +| `result` | `A2ATaskResult` (opt) | The result of the task execution. | + +#### Options and Props + +- **Subscription Filter**: Provides a rich filtering object (`A2ATaskFilter`) that allows subscribing based on `status`, `taskType`, `sourceAgentId`, `targetAgentId`, `priority`, and `threadId`. +- **`getHistory(filter, options)`**: Retrieves past tasks and wraps them in `A2ATaskEvent` objects. + - `filter`: The `A2ATaskFilter` object. + - `options`: An object containing an optional `threadId` and `limit`. + +--- + +## Appendix: Detailed Data Structures + +This section provides a more detailed look at the enums and complex types transmitted by the sockets. + +### `ObservationType` Enum + +This enum lists all possible categories for an `Observation` record. A UI can filter by these types to show specific aspects of the agent's process. + +| Member | Description | +| :-------------------- | :------------------------------------------------------------------------ | +| `TITLE` | A concise thread title (<= 10 words) derived from intent and context. | +| `INTENT` | The user's inferred intent. | +| `PLAN` | The agent's step-by-step plan to address the intent. | +| `THOUGHTS` | The agent's internal monologue or reasoning process. | +| `TOOL_CALL` | The LLM's decision to call one or more tools. | +| `TOOL_EXECUTION` | The actual execution attempt and result of a specific tool call. | +| `SYNTHESIS` | Events specifically related to the final response generation phase. | +| `ERROR` | An error encountered during any phase of execution. | +| `FINAL_RESPONSE` | The final AI response message generated by the agent. | +| `STATE_UPDATE` | Changes made to the agent's persistent state. | +| `LLM_STREAM_START` | Logged by the Agent Core when LLM stream consumption begins. | +| `LLM_STREAM_METADATA` | Logged upon receiving a `METADATA` stream event. | +| `LLM_STREAM_END` | Logged upon receiving an `END` stream event. | +| `LLM_STREAM_ERROR` | Logged upon receiving an `ERROR` stream event. | + +### Built-in Metadata Fields + +While the `metadata` property on `ConversationMessage` and `Observation` is a generic `object`, the framework uses a few conventional fields: + +- **`ConversationMessage.metadata`**: + - `traceId`: The trace ID of the execution cycle that produced this message. + - `error`: A boolean flag (`true`) indicating that this message is an error response. +- **`Observation.metadata`**: + - `phase`: A string (`'planning'`, `'synthesis'`) indicating which stage of the agent execution cycle the observation was recorded in. + +### The `traceId` Explained + +The `traceId` is a crucial identifier for diagnostics and debugging. It is a unique ID generated at the very beginning of an `agent.process()` call and is passed down through all subsequent operations within that single execution cycle. + +- **Correlation**: It correlates all the events—observations, LLM calls, stream events, tool executions, and final messages—that belong to a single user request. +- **Debugging**: When you inspect the history, you can filter all `Observation` and `StreamEvent` objects by a specific `traceId` to get a complete, chronological picture of everything the agent did to generate a particular response. + +### How `StreamEvent` Works + +The `StreamEvent` system provides a granular, real-time feed of the LLM's generation process. It's not just about receiving text; it's about receiving structured events that describe the entire lifecycle of the stream. + +1. **Initiation**: When the agent calls the LLM with `stream: true`, the connection remains open. +2. **Event Flow**: The provider adapter (e.g., for Anthropic, OpenAI) translates the provider-specific data chunks into the standardized `StreamEvent` format. +3. **Token Events**: For each piece of text generated, a `TOKEN` event is emitted. The `tokenType` field provides crucial context, allowing a UI to distinguish between internal thoughts (like the raw plan) and the final response meant for the user. +4. **Metadata Events**: Periodically, and always at the end, `METADATA` events are sent, providing updates on token usage and the reason the model stopped generating. +5. **Termination**: The stream concludes with either an `END` event (for success) or an `ERROR` event. No more events will be sent for that `traceId` after this. + +This event-driven approach allows a UI to react intelligently, for example, by displaying a "thinking..." spinner for `AGENT_THOUGHT` tokens and then switching to a "typewriter" effect for `FINAL_SYNTHESIS` tokens. + +### Example: Building a Comprehensive Reasoning View + +A powerful feature of the UI system is its ability to combine data from multiple sockets to create a detailed, real-time view of the agent's entire thought process for a single user request. This is invaluable for building advanced UIs that offer full transparency into the agent's reasoning. + +The key to this is the **`traceId`**. Every event from every socket that belongs to the same `agent.process()` cycle will share the same `traceId`, allowing a UI component to subscribe to multiple sockets and assemble a complete, chronological "reasoning block." + +Here is the typical sequence of events a UI would receive and render for a single, complete agent execution that involves tool use: + +1. **Planning Phase Thoughts (`LLMStreamSocket`)**: The process begins with the agent's planning phase. The UI receives a stream of `TOKEN` events from the `LLMStreamSocket`. These tokens are the raw, unstructured reasoning of the LLM as it formulates its plan, often wrapped in `` tags by the model. A UI can identify these by checking the `callContext` (e.g., `'AGENT_THOUGHT'`) on the `StreamEvent`. + +2. **Structured Planning Observations (`ObservationSocket`)**: Once the planning stream ends, the agent parses the output and records several structured observations. The UI then receives `INTENT`, `PLAN`, and `TOOL_CALL` observations from the `ObservationSocket`. These represent the high-quality, validated outcomes of the planning phase. + +3. **Tool Execution (`ObservationSocket`)**: The agent's `ToolSystem` executes the planned tools. As each tool finishes, the UI receives one or more `TOOL_EXECUTION` observations, showing the result (success or error) and output of each call. + +4. **Synthesis Phase Thoughts (`LLMStreamSocket`)**: With the tool results in hand, the agent begins synthesizing the final answer. The UI again receives `TOKEN` events from the `LLMStreamSocket`, but this time the `callContext` will be `'FINAL_SYNTHESIS'`. This stream might include the LLM's reasoning on how to interpret the tool results before it begins generating the final user-facing text. + +5. **Final Response (`LLMStreamSocket` & `ObservationSocket`)**: The final stream of `TOKEN` events from the synthesis call constitutes the agent's answer to the user. When this stream ends, a `FINAL_RESPONSE` observation is recorded, containing the complete, persisted `ConversationMessage`. + +#### Visualizing the Event Flow + +This diagram illustrates how a UI component would receive this interleaved sequence of events from the two sockets to build a complete reasoning view. + +```mermaid +sequenceDiagram + participant UI + participant LLMStreamSocket + participant ObservationSocket + + Note over UI: Subscribes to both sockets, filtering events by a specific traceId + + rect rgb(240, 248, 255) + note right of UI: Planning Phase + LLMStreamSocket->>UI: StreamEvent (TOKEN, context: AGENT_THOUGHT) + LLMStreamSocket->>UI: ... more thought tokens ... + LLMStreamSocket->>UI: StreamEvent (END) + ObservationSocket->>UI: Observation (INTENT) + ObservationSocket->>UI: Observation (PLAN) + ObservationSocket->>UI: Observation (TOOL_CALL) + end + + rect rgb(255, 250, 240) + note right of UI: Execution Phase + ObservationSocket->>UI: Observation (TOOL_EXECUTION) + ObservationSocket->>UI: ... more tool results ... + end + + rect rgb(240, 255, 240) + note right of UI: Synthesis Phase + ObservationSocket->>UI: Observation (SYNTHESIS) + LLMStreamSocket->>UI: StreamEvent (TOKEN, context: FINAL_SYNTHESIS) + LLMStreamSocket->>UI: ... final response tokens ... + LLMStreamSocket->>UI: StreamEvent (END) + ObservationSocket->>UI: Observation (FINAL_RESPONSE) + end +``` + +By handling these events in order, a UI can create a rich, step-by-step visualization that shows not just *what* the agent did, but *why* it did it. +### Example: Subscribing to TITLE updates + +A UI component can subscribe to the `ObservationSocket` to receive `TITLE` events and set the thread title reactively: + +```ts +const unsubscribe = art.uiSystem.getObservationSocket().subscribe( + (obs) => { + if (obs.type === 'TITLE' && obs.content?.title) { + updateThreadTitle(obs.content.title); + } + }, + 'TITLE', + { threadId } +); + +// Later, to stop listening +unsubscribe(); +``` + + +--- + +### `StreamEvent.type` + +| Type | Description | +| :--------- | :------------------------------------------------------------------------------------------------------- | +| `TOKEN` | A chunk of text generated by the LLM. | +| `METADATA` | Information about the LLM call (e.g., token counts, stop reason), typically sent once at the end. | +| `ERROR` | An error occurred during the LLM call or stream processing. The `data` will contain the `Error` object. | +| `END` | Signals the successful completion of the stream. The `data` is typically `null`. | + +### A2A Task Details + +#### `A2ATaskStatus` Enum + +| Status | Description | +| :------------ | :---------------------------------------------------------------- | +| `PENDING` | Task has been created but not yet assigned to an agent. | +| `IN_PROGRESS` | Task has been assigned to an agent and is being processed. | +| `COMPLETED` | Task has been completed successfully. | +| `FAILED` | Task has failed during execution. | +| `CANCELLED` | Task has been cancelled before completion. | +| `WAITING` | Task is waiting for external dependencies or manual intervention. | +| `REVIEW` | Task is being reviewed for quality assurance. | + +#### `A2ATaskPriority` Enum + +| Priority | Description | +| :------- | :----------------- | +| `LOW` | Low priority. | +| `MEDIUM` | Medium priority. | +| `HIGH` | High priority. | +| `URGENT` | Urgent priority. | + +#### `A2ATask.payload` Parameters + +| Field | Type | Description | +| :------------- | :------- | :-------------------------------------------------------- | +| `taskType` | `string` | The type of task to be executed (e.g., 'analyze'). | +| `input` | `any` | Input data required for the task. | +| `instructions` | `string` | (Optional) Instructions or configuration for the task. | +| `parameters` | `object` | (Optional) Additional parameters specific to the task type. | + +#### `A2ATask.metadata` Fields + +The `metadata` object within an `A2ATask` contains various timestamps and configuration details for managing the task's lifecycle. + +| Field | Type | Description | +| :---------------------- | :--------- | :------------------------------------------------------------------ | +| `createdAt` | `number` | Timestamp when the task was created. | +| `updatedAt` | `number` | Timestamp when the task was last updated. | +| `startedAt` | `number` | (Optional) Timestamp when the task processing started. | +| `completedAt` | `number` | (Optional) Timestamp when the task was completed or failed. | +| `delegatedAt` | `number` | (Optional) Timestamp when the task was delegated to a remote agent. | +| `initiatedBy` | `string` | (Optional) The user or system that initiated the task. | +| `correlationId` | `string` | (Optional) ID for tracking related tasks across the system. | +| `retryCount` | `number` | (Optional) Number of retry attempts made for this task. | +| `maxRetries` | `number` | (Optional) Maximum number of retry attempts allowed. | +| `timeoutMs` | `number` | (Optional) Timeout duration in milliseconds. | +| `estimatedCompletionMs` | `number` | (Optional) Estimated completion time provided by a remote agent. | +| `tags` | `string[]` | (Optional) Tags or labels for categorizing the task. | diff --git a/docs/how-to/connecting-your-ui.md b/docs/how-to/connecting-your-ui.md new file mode 100755 index 0000000..fa805d7 --- /dev/null +++ b/docs/how-to/connecting-your-ui.md @@ -0,0 +1,298 @@ +# How to Connect Your UI to the ART Framework + +This guide provides a comprehensive walkthrough for developers on how to use the ART Framework's public UI System API to build reactive and real-time user interfaces. You will learn how to access the UI sockets, subscribe to events, and fetch historical data to create a rich user experience. + +## Prerequisites + +Before you begin, you must complete two essential steps: + +1. **Create an `ArtInstance`**: This is the main entry point to the framework. +2. **Set the `ThreadConfig` for a conversation**: You **must** configure each conversation thread (e.g., set the provider, model, API key, and enabled tools) *before* you can process messages or listen for events on that thread. + +```javascript +import { createArtInstance, ThreadConfig } from 'art-framework'; +import { artConfig } from './art.config.js'; // Your high-level instance configuration + +let art; +const threadId = 'user-123-session-1'; // A unique ID for the conversation + +async function initialize() { + art = await createArtInstance(artConfig); + + // Define and set the configuration for the conversation thread + const initialThreadConfig: ThreadConfig = { + providerConfig: { + providerName: 'openai', + modelId: 'gpt-4o', + adapterOptions: { + apiKey: 'sk-your-real-openai-api-key' // Securely provide your API key + } + }, + enabledTools: ['CalculatorTool'], + historyLimit: 50 + }; + + await art.stateManager.setThreadConfig(threadId, initialThreadConfig); + + // Now you are ready to connect your UI for this specific threadId +} + +initialize(); +``` + +## 1. Accessing the UI System + +The entry point to all UI-related functionality is the `uiSystem` object, which is a property of your `ArtInstance`. + +```javascript +const uiSystem = art.uiSystem; +``` + +From this `uiSystem` object, you can get access to the individual sockets. + +## 2. Understanding Sockets + +The UI System is built on a **publish-subscribe** model. It exposes four specialized **sockets**, each acting as a dedicated channel for a specific type of data (e.g., chat messages, agent observations). + +- **Subscribing**: Your UI components can `subscribe` to a socket to listen for new data in real-time. When new data is available, a callback function you provide is executed. +- **Unsubscribing**: Every `subscribe` call returns an `unsubscribe` function. It is crucial to call this function when your UI component unmounts to prevent memory leaks. +- **Fetching History**: Most sockets have a `getHistory` method that allows you to retrieve a log of past data, which is essential for populating your UI when it first loads. + +--- + +## 3. Connecting to the `ConversationSocket` + +This is the most common socket, used for building chat interfaces. + +### Getting the Socket + +```javascript +const conversationSocket = art.uiSystem.getConversationSocket(); +``` + +### Subscribing to New Messages + +To display messages as they are sent by the user or generated by the agent, you subscribe to the socket. The callback will receive a `ConversationMessage` object. + +```javascript +// Example: Displaying a new message in the chat window +const unsubscribe = conversationSocket.subscribe( + (message) => { + console.log('New message received:', message); + // Code to append the message to your chat UI + // e.g., addMessageToChat(message.content, message.role); + }, + undefined, // No filter + { threadId: 'user-123-session-1' } // VERY IMPORTANT: Always scope subscriptions to a thread +); + +// When your component is destroyed, don't forget to unsubscribe: +// unsubscribe(); +``` + +You can also filter messages by their role: + +```javascript +// Only listen for messages from the AI +const unsubscribeFromAI = conversationSocket.subscribe( + (message) => { /* ... */ }, + 'AI', // Filter: a single MessageRole + { threadId: 'user-123-session-1' } +); + +// Only listen for messages from the USER or a TOOL +const unsubscribeFromUserOrTool = conversationSocket.subscribe( + (message) => { /* ... */ }, + ['USER', 'TOOL'], // Filter: an array of MessageRole + { threadId: 'user-123-session-1' } +); +``` + +### Fetching Message History + +To load the existing chat history for a conversation, use `getHistory`. + +```javascript +async function loadChatHistory(threadId) { + try { + const messages = await conversationSocket.getHistory( + undefined, // No role filter + { + threadId: threadId, + limit: 50 // Get the last 50 messages + } + ); + + console.log(`Loaded ${messages.length} messages.`); + // Code to render the historical messages in your UI + // messages.forEach(msg => addMessageToChat(msg.content, msg.role)); + } catch (error) { + console.error('Failed to load chat history:', error); + } +} +``` + +--- + +## 4. Connecting to the `ObservationSocket` + +This socket lets you visualize the agent's internal "thought process." + +### Getting the Socket + +```javascript +const observationSocket = art.uiSystem.getObservationSocket(); +``` + +### Subscribing to New Observations + +This is useful for showing a real-time feed of the agent's actions. + +```javascript +// Example: Log any tool calls the agent makes +const unsubscribe = observationSocket.subscribe( + (observation) => { + if (observation.type === 'TOOL_CALL') { + console.log('Agent is calling a tool:', observation.content); + // Code to display the tool call in a "thought process" panel + } + }, + 'TOOL_CALL', // Filter by the ObservationType + { threadId: 'user-123-session-1' } +); + +// Example: Listen for the final response to get structured UI metadata +const unsubscribeFinal = observationSocket.subscribe( + (observation) => { + if (observation.type === 'FINAL_RESPONSE') { + const { message, uiMetadata } = observation.content; + console.log('Final message:', message.content); + console.log('UI Metadata for sources/suggestions:', uiMetadata); + // Code to render sources and suggestions from the uiMetadata object + } + }, + 'FINAL_RESPONSE', + { threadId: 'user-123-session-1' } +); +``` + +### Fetching Observation History + +You can retrieve past observations to show a complete log of a previous agent run. + +```javascript +async function loadExecutionLog(threadId) { + try { + const observations = await observationSocket.getHistory( + ['PLAN', 'TOOL_CALL', 'TOOL_EXECUTION', 'ERROR'], // Filter for specific types + { threadId: threadId, limit: 100 } + ); + + console.log('Loaded execution log:', observations); + // The `content` of the PLAN observation will be a structured array of steps. + // The `content` of the FINAL_RESPONSE observation will contain the final message and uiMetadata. + // Code to display the log in your UI + } catch (error) { + console.error('Failed to load execution log:', error); + } +} +``` + +--- + +## 5. Connecting to the `LLMStreamSocket` + +This socket is essential for creating a "typewriter" effect for the agent's response. Remember to set `stream: true` in your `art.process()` call to enable streaming. + +### Getting the Socket + +```javascript +const llmStreamSocket = art.uiSystem.getLLMStreamSocket(); +``` + +### Subscribing to Stream Events + +You'll typically subscribe to `TOKEN` events to append text to the UI in real-time. + +```javascript +let finalMessage = ''; +const unsubscribe = llmStreamSocket.subscribe( + (streamEvent) => { + switch (streamEvent.type) { + case 'TOKEN': + // Differentiate between thoughts and the final response + if (streamEvent.tokenType === 'FINAL_SYNTHESIS_LLM_RESPONSE') { + const token = streamEvent.data; + finalMessage += token; + // Code to update the last message in the UI with the new token + // e.g., updateLastMessage(finalMessage); + } + break; + case 'END': + console.log('Stream ended. Final message:', finalMessage); + // The stream is complete. You might save the final message to your state here. + break; + case 'ERROR': + console.error('An error occurred during streaming:', streamEvent.data); + break; + } + }, + undefined, // No filter + { threadId: 'user-123-session-1' } // Scope to the correct thread +); +``` + +### Fetching History + +The `LLMStreamSocket` does not have a `getHistory` method, as stream events are transient and not saved to the database. + +--- + +## 6. Connecting to the `A2ATaskSocket` + +This socket is for advanced applications that involve multiple agents delegating tasks to one another. + +### Getting the Socket + +```javascript +const a2aTaskSocket = art.uiSystem.getA2ATaskSocket(); +``` + +### Subscribing to Task Updates + +This allows you to build a real-time task management dashboard. + +```javascript +// Example: Listen for any task that gets completed or fails +const unsubscribe = a2aTaskSocket.subscribe( + (taskEvent) => { + console.log(`Task ${taskEvent.task.taskId} moved to status: ${taskEvent.task.status}`); + // Code to update the task's status in your dashboard UI + }, + { + // Rich filter object + status: ['COMPLETED', 'FAILED'] + }, + { threadId: 'user-123-session-1' } +); +``` + +### Fetching Task History + +You can load all existing tasks that match certain criteria. + +```javascript +async function loadInProgressTasks(threadId) { + try { + const tasks = await a2aTaskSocket.getHistory( + { status: 'IN_PROGRESS' }, // Filter + { threadId: threadId } // Options + ); + + console.log('Loaded in-progress tasks:', tasks); + // Code to display these tasks in your UI + } catch (error) { + console.error('Failed to load in-progress tasks:', error); + } +} +``` diff --git a/docs/how-to/creating-and-switching-agents.md b/docs/how-to/creating-and-switching-agents.md new file mode 100644 index 0000000..e8dffd7 --- /dev/null +++ b/docs/how-to/creating-and-switching-agents.md @@ -0,0 +1,239 @@ +# How to Create and Switch Between Agents in ART Framework + +The ART framework provides a flexible agent system that allows developers to create custom agents or modify existing ones. This guide will show you how to create a modified version of the PES agent, create completely new agents, and dynamically switch between different agents. + +## Prerequisites + +Before you begin, ensure you have: +- A basic understanding of the ART framework architecture +- Familiarity with TypeScript/JavaScript +- An initialized ART instance + +## 1. Creating a Modified Version of the PES Agent + +The PES (Plan-Execute-Synthesize) agent is the default agent in ART. You can create a modified version by extending the existing PESAgent class. + +### Extending the PESAgent Class + +```typescript +import { PESAgent } from 'art-framework'; +import type { AgentProps, AgentFinalResponse } from 'art-framework'; + +export class CustomPESAgent extends PESAgent { + // Override specific methods to customize behavior + async process(props: AgentProps): Promise { + // Add custom logic before calling the parent process method + console.log('Custom logic before processing'); + + // Call the parent process method + const result = await super.process(props); + + // Add custom logic after processing + console.log('Custom logic after processing'); + + return result; + } +} +``` + +## 2. Creating Completely New Agents + +To create a completely new agent, you need to implement the `IAgentCore` interface. This gives you full control over the agent's workflow while ensuring compatibility with the ART framework. + +### Step 1: Implement the IAgentCore Interface + +```typescript +import { IAgentCore } from 'art-framework'; +import type { + AgentProps, + AgentFinalResponse, + ConversationMessage, + MessageRole +} from 'art-framework'; +import { generateUUID } from 'art-framework'; + +export class SimpleAgent implements IAgentCore { + constructor(private dependencies: { + // Inject the dependencies your agent needs + stateManager: any; + conversationManager: any; + toolRegistry: any; + reasoningEngine: any; + // Add other dependencies as needed + }) {} + + async process(props: AgentProps): Promise { + const startTime = Date.now(); + const traceId = props.traceId ?? generateUUID(); + + try { + // Load thread context + const threadContext = await this.dependencies.stateManager.loadThreadContext( + props.threadId, + props.userId + ); + + // Get conversation history + const history = await this.dependencies.conversationManager.getMessages( + props.threadId, + { limit: threadContext.config.historyLimit } + ); + + // Get available tools + const availableTools = await this.dependencies.toolRegistry.getAvailableTools({ + enabledForThreadId: props.threadId + }); + + // Simple agent logic - just call the LLM directly + const prompt = this.constructPrompt(props.query, history, availableTools); + + const callOptions = { + threadId: props.threadId, + traceId: traceId, + userId: props.userId, + sessionId: props.sessionId, + stream: props.options?.stream ?? false, + providerConfig: threadContext.config.providerConfig, + ...(props.options?.llmParams ?? {}), + }; + + const stream = await this.dependencies.reasoningEngine.call(prompt, callOptions); + + let responseText = ''; + for await (const event of stream) { + if (event.type === 'TOKEN') { + responseText += event.data; + } + } + + // Save the response + const finalAiMessage: ConversationMessage = { + messageId: generateUUID(), + threadId: props.threadId, + role: MessageRole.AI, + content: responseText, + timestamp: Date.now(), + metadata: { traceId }, + }; + + await this.dependencies.conversationManager.addMessages(props.threadId, [finalAiMessage]); + + const endTime = Date.now(); + + return { + response: finalAiMessage, + metadata: { + threadId: props.threadId, + traceId: traceId, + userId: props.userId, + status: 'success', + totalDurationMs: endTime - startTime, + llmCalls: 1, + toolCalls: 0, + } + }; + } catch (error: any) { + throw error; + } + } + + private constructPrompt( + query: string, + history: ConversationMessage[], + tools: any[] + ): any { + // Construct your prompt based on the query, history, and tools + // This is a simplified example + return [ + { + role: 'system', + content: 'You are a helpful AI assistant.' + }, + ...history.map(msg => ({ + role: msg.role.toLowerCase(), + content: msg.content + })), + { + role: 'user', + content: query + } + ]; + } +} +``` + +### Step 2: Required Dependencies for Custom Agents + +When creating a custom agent, you'll typically need access to these core components through the ART framework's dependency injection system: + +- `StateManager`: For loading thread configuration and state +- `ConversationManager`: For managing conversation history +- `ToolRegistry`: For accessing available tools +- `ReasoningEngine`: For calling LLMs +- `ObservationManager`: For recording observations +- `ToolSystem`: For executing tools +- `UISystem`: For UI communication +- `SystemPromptResolver`: For resolving system prompts + +## 3. Dynamically Switching Between Agents + +The ART framework allows you to dynamically switch between different agents at initialization time. + +### Setting the Agent at Initialization + +```typescript +import { createArtInstance } from 'art-framework'; +import { CustomPESAgent } from './custom-pes-agent'; +import { SimpleAgent } from './simple-agent'; +import type { ArtInstanceConfig } from 'art-framework'; + +// Configuration for using the custom PES agent +const configWithCustomPES: ArtInstanceConfig = { + storage: { type: 'memory' }, + providers: { + // Your provider configuration + }, + agentCore: CustomPESAgent, // Specify your custom agent class + tools: [ + // Your tools + ] +}; + +// Configuration for using the simple agent +const configWithSimpleAgent: ArtInstanceConfig = { + storage: { type: 'memory' }, + providers: { + // Your provider configuration + }, + agentCore: SimpleAgent, // Specify your simple agent class + tools: [ + // Your tools + ] +}; + +// Create ART instance with custom PES agent +const artWithCustomPES = await createArtInstance(configWithCustomPES); + +// Create ART instance with simple agent +const artWithSimpleAgent = await createArtInstance(configWithSimpleAgent); +``` + +## Best Practices + +1. **Maintain Compatibility**: Ensure your custom agents implement the `IAgentCore` interface correctly to maintain compatibility with the ART framework. + +2. **Error Handling**: Implement proper error handling in your custom agents. + +3. **Observations**: Record meaningful observations during agent execution to enable debugging and monitoring. + +4. **Resource Management**: Properly manage resources like LLM connections and clean up when needed. + +5. **Testing**: Thoroughly test your custom agents to ensure they work correctly in different scenarios. + +6. **Documentation**: Document your custom agents' behavior and configuration options. + +## Conclusion + +The ART framework provides a flexible system for creating and switching between different agents. You can modify existing agents like the PES agent or create completely new agents with custom workflows. Dynamic agent switching is supported at initialization. + +By following the patterns described in this guide, you can create powerful, customized AI agents that fit your specific application needs while maintaining full compatibility with the ART framework. \ No newline at end of file diff --git a/docs/how-to/customizing-agent-persona.md b/docs/how-to/customizing-agent-persona.md new file mode 100755 index 0000000..2661118 --- /dev/null +++ b/docs/how-to/customizing-agent-persona.md @@ -0,0 +1,114 @@ +# How to Customize the Agent's Persona + +The ART framework provides a powerful, multi-layered system for customizing the identity and behavior of your agent. This is achieved by defining an `AgentPersona` at the instance, thread, or even individual call level, allowing for incredible flexibility. + +This guide will walk you through the advanced features of agent persona customization. + +## What is an Agent Persona? + +The `AgentPersona` is a configuration object that defines two key aspects of your agent: + +- `name`: A string that sets the agent's identity (e.g., "Zoi", "CodeBot"). This is used in the final **synthesis** stage to instruct the LLM on who it should be. +- `prompts`: An object containing separate system prompts for the two main stages of the agent's reasoning process: + - `planning`: A system prompt that guides the agent's reasoning, expertise, and tool selection. + - `synthesis`: A system prompt that shapes the agent's tone, formatting, and final response structure. + +By separating these prompts, you can fine-tune the agent's behavior with precision. For example, you can have a highly technical and analytical prompt for planning, and a friendly, easy-to-understand prompt for synthesis. + +Here is the interface definition: + +```typescript +export interface AgentPersona { + name: string; + prompts: { + planning?: string; + synthesis?: string; + }; +} +``` + +## The Override Hierarchy + +The agent's final persona is resolved using a clear hierarchy. Settings at a more specific level will always override those at a broader level: + +1. **Call-level Persona**: Defined in the `options` of an `art.process()` call. This is the most specific and will override all other settings for that single execution. +2. **Thread-level Persona**: Defined in the `threadConfig` when a thread is created or updated. This applies to all executions within that specific conversation thread. +3. **Instance-level Persona**: Defined in the `ArtInstanceConfig` when you create your ART instance. This is the default persona for all agents in the instance. + +## How to Use Personas + +### 1. Instance-Level (Default Persona) + +This is the most common way to set a default character for your agent. + +```typescript:main.ts +import { createArtInstance } from 'art-framework'; +import type { ArtInstanceConfig, AgentPersona } from 'art-framework'; + +const defaultPersona: AgentPersona = { + name: 'CodeBot', + prompts: { + planning: 'You are an expert software engineer. Your task is to analyze the user query and create a precise plan to solve it. Identify the best tools and functions for the job.', + synthesis: 'You are CodeBot, a friendly and helpful coding assistant. Synthesize the results into a clear, well-formatted response with code examples.' + } +}; + +const config: ArtInstanceConfig = { + storage: { type: 'memory' }, + providers: { /* ... */ }, + persona: defaultPersona, +}; + +const art = await createArtInstance(config); +``` + +### 2. Thread-Level (Mode Switching) + +You can override the persona for a specific conversation, which is great for implementing different "modes" in your application. For example, a "beginner" mode vs. an "expert" mode. + +```typescript +const expertModePersona: Partial = { + prompts: { + synthesis: 'You are CodeBot, speaking to an expert user. Be concise, technical, and skip the introductory explanations.' + } +}; + +const result = await art.process({ + query: 'Implement a binary search tree in Rust.', + threadId: 'expert-thread-1', + threadConfig: { + providerConfig: { /* ... */ }, + persona: expertModePersona, + }, +}); +``` + +In this example, the agent will still use the `name` ("CodeBot") and the `planning` prompt from the instance-level persona, but it will use the new, more direct `synthesis` prompt for the final response. + +### 3. Call-Level (Dynamic, One-Time Changes) + +For ultimate flexibility, you can change the persona for a single call. This is useful for one-off requests where you need a very specific behavior. + +```typescript +const oneTimePersona: Partial = { + name: 'SecurityAnalyst', + prompts: { + planning: 'You are a security analyst. Analyze the following code for potential vulnerabilities. Focus on injection attacks and improper error handling.', + } +}; + +const result = await art.process({ + query: 'Review this login function for security issues: `...`', + threadId: 'expert-thread-1', + options: { + persona: oneTimePersona, + } +}); +``` + +In this case, for this single execution: +- The agent's name will be **"SecurityAnalyst"**. +- It will use the specialized `planning` prompt. +- It will fall back to the thread-level `synthesis` prompt ("Be concise, technical..."). + +By combining these three levels, you have complete control over your agent's identity and behavior, allowing you to create dynamic, context-aware, and highly specialized AI applications. diff --git a/docs/how-to/streaming-Gemini-Thoughts-to-the-UI.md b/docs/how-to/streaming-Gemini-Thoughts-to-the-UI.md new file mode 100644 index 0000000..8f34371 --- /dev/null +++ b/docs/how-to/streaming-Gemini-Thoughts-to-the-UI.md @@ -0,0 +1,119 @@ +### Using streamed thinking tokens in your UI (and persisting them) + +This guide shows how to: +- Enable Gemini thinking +- Stream planning and synthesis thought tokens via `LLMStreamSocket` +- Persist thoughts to storage and/or your own DB +- Retrieve persisted thoughts + +### 1) Enable Gemini “thinking” on your call +Ensure you’re using a Gemini 2.5 model and pass the thinking flags. Provide these in `llmParams` so both planning and synthesis calls see them. + +```ts +const response = await art.process({ + query: 'Draft a plan, then write a short story', + threadId, + options: { + // forwarded to both planning (AGENT_THOUGHT) and synthesis + llmParams: { + stream: true, + gemini: { + thinking: { includeThoughts: true, thinkingBudget: 8096 } + } + } + } +}); +``` + +- Planning stream tokens will be typed as `AGENT_THOUGHT_LLM_THINKING` / `AGENT_THOUGHT_LLM_RESPONSE`. +- Synthesis stream tokens will be typed as `FINAL_SYNTHESIS_LLM_THINKING` / `FINAL_SYNTHESIS_LLM_RESPONSE`. + +### 2) Stream thinking tokens to your UI with `LLMStreamSocket` +Subscribe before you call `art.process()` to capture the full stream. Filter by `threadId` and check `tokenType`. + +```ts +const llm = art.uiSystem.getLLMStreamSocket(); + +// Example: show planning and synthesis thoughts in separate UI panes +const unsubscribe = llm.subscribe( + (evt) => { + if (evt.type !== 'TOKEN') return; + const text = String(evt.data ?? ''); + + if (evt.tokenType === 'AGENT_THOUGHT_LLM_THINKING') { + // planning thoughts (internal reasoning during planning) + renderPlanningThought(text); + } else if (evt.tokenType === 'FINAL_SYNTHESIS_LLM_THINKING') { + // synthesis thoughts (internal reasoning while forming the final answer) + renderSynthesisThought(text); + } + }, + /* optional filter */ undefined, + /* restrict to this thread */ { threadId } +); + +// Now kick off your agent call (see step 1) +// await art.process({ ... }); + +// Later: unsubscribe() +// unsubscribe(); +``` + +Tip: If you need to isolate events to a specific UI tab/window, include `sessionId` in your `art.process(...)` call and filter on it when you subscribe. + +### 3) Persist thoughts (built-in) +You don’t need to write any code to persist thoughts if you’re using the default `PESAgent`. It automatically records `ObservationType.THOUGHTS` for any thinking tokens detected during planning and synthesis. These are saved through your configured storage adapter (e.g., `IndexedDBStorageAdapter`, `SupabaseStorageAdapter`). + +- Planning thinking tokens are stored with `metadata.phase = 'planning'`. +- Synthesis thinking tokens are stored with `metadata.phase = 'synthesis'`. + +Ensure you configured storage when creating your instance: +```ts +const art = await createArtInstance({ + storage: { type: 'indexedDB', dbName: 'MyArtDB' }, + providers: { + availableProviders: [{ name: 'gemini', adapter: GeminiAdapter }] + }, + // ... +}); +``` + +### 4) Persist thoughts to your own app DB (optional) +If you want a custom copy in your own backend, subscribe to the LLM stream and insert into your DB: + +```ts +const llm2 = art.uiSystem.getLLMStreamSocket(); +const off = llm2.subscribe((evt) => { + if (evt.type !== 'TOKEN') return; + if (!evt.tokenType?.includes('THINKING')) return; + + saveToMyDb({ + threadId: evt.threadId, + tokenType: evt.tokenType, + text: String(evt.data ?? ''), + timestamp: Date.now() + }); +}, undefined, { threadId }); +``` + +### 5) Retrieve persisted thoughts (history) +You can fetch previously saved thought observations using the `ObservationSocket.getHistory(...)` helper (works when an observation repository is configured by the framework): + +```ts +import { ObservationType } from 'art-framework'; + +const obs = art.uiSystem.getObservationSocket(); +const history = await obs.getHistory(ObservationType.THOUGHTS, { threadId }); + +// Each item includes content.text and metadata.phase ('planning' | 'synthesis') +history.forEach((o) => { + if (o.metadata?.phase === 'planning') renderPlanningThought(o.content?.text); + if (o.metadata?.phase === 'synthesis') renderSynthesisThought(o.content?.text); +}); +``` + +### Notes +- Thinking availability depends on the model. Use Gemini 2.5 family (e.g., `gemini-2.5-flash`) and enable `includeThoughts`. +- Stream chunk count is not the same as token count; the final stream `METADATA` event includes provider usage. For Gemini you may see fields like `providerRawUsage.thoughtsTokenCount`; the framework maps what it can to `LLMMetadata.thinkingTokens` when available. +- Real-time UI: use `LLMStreamSocket`. +- Persistence/replay: use `ObservationSocket` (THOUGHTS), which the default `PESAgent` records for you automatically. \ No newline at end of file diff --git a/docs/how-to/supabase-persistence.md b/docs/how-to/supabase-persistence.md new file mode 100644 index 0000000..25a2025 --- /dev/null +++ b/docs/how-to/supabase-persistence.md @@ -0,0 +1,243 @@ +# Using Supabase for Persistence in ART Framework + +## Introduction + +The ART framework provides a flexible storage system that allows developers to choose the persistence mechanism that best fits their application's needs. One of the available storage adapters is the `SupabaseStorageAdapter`, which enables you to use Supabase as a backend storage solution for your ART applications. + +Supabase is an open-source Firebase alternative that provides a PostgreSQL database with real-time capabilities, authentication, and auto-generated APIs. By using the `SupabaseStorageAdapter`, you can leverage Supabase's powerful features while maintaining the flexibility and structure of the ART framework. + +## SupabaseStorageAdapter Features + +The `SupabaseStorageAdapter` implements the `StorageAdapter` interface and provides the following features: + +1. **Persistent Storage**: Data is stored in a Supabase PostgreSQL database, ensuring persistence across sessions and devices. +2. **Collection Mapping**: Maps ART collections (conversations, observations, state, a2a_tasks) to Supabase tables. +3. **CRUD Operations**: Supports Create, Read, Update, and Delete operations for stored data. +4. **Query Capabilities**: Implements basic equality filters, limit/skip pagination, and single-key sorting. +5. **Flexible Configuration**: Allows customization of table names, schema, and Supabase client configuration. + +## Configuration Options + +To use the `SupabaseStorageAdapter`, you need to provide a configuration object that implements the `SupabaseConfig` interface: + +```typescript +interface SupabaseConfig { + /** Supabase project URL, e.g., https://xyzcompany.supabase.co */ + url: string; + /** Supabase anon or service key. Prefer service key on server-side only. */ + apiKey: string; + /** Optional schema name (default 'public'). */ + schema?: string; + /** + * Table names to use. These map ART collections to Supabase. + * If you customize collection names in repositories, adjust accordingly. + */ + tables?: { + conversations?: string; + observations?: string; + state?: string; + a2a_tasks?: string; + }; + /** + * Optional: pass a pre-initialized Supabase client (from @supabase/supabase-js) + * Useful in environments where you already manage the client and auth. + */ + client?: any; +} +``` + +## Integration with ART Framework + +The `SupabaseStorageAdapter` integrates seamlessly with the ART framework through the repository pattern. The framework uses repositories to manage data access, and these repositories can work with any storage adapter that implements the `StorageAdapter` interface. + +When you configure the ART framework to use the `SupabaseStorageAdapter`, the following repositories will automatically use Supabase for persistence: + +1. `ConversationRepository` - Manages conversation history +2. `ObservationRepository` - Manages agent observations +3. `StateRepository` - Manages thread configuration and agent state +4. `TaskStatusRepository` - Manages A2A tasks + +## Comparison with Other Storage Adapters + +The ART framework provides three built-in storage adapters: + +| Feature | InMemoryStorageAdapter | IndexedDBStorageAdapter | SupabaseStorageAdapter | +|---------|------------------------|-------------------------|------------------------| +| Persistence | No (data lost on refresh) | Yes (client-side) | Yes (server-side) | +| Data Location | Browser memory | Browser storage | Supabase PostgreSQL DB | +| Cross-Device Sync | No | No | Yes | +| Real-time Capabilities | No | No | Yes (with Supabase) | +| Scalability | Limited | Limited | High | +| Setup Complexity | Low | Medium | Medium-High | +| Best For | Testing, demos | Web apps | Production apps, collaboration | + +## Usage Examples + +### Basic Setup + +To use the `SupabaseStorageAdapter` in your ART application, you need to create an instance of it and pass it to the `createArtInstance` function: + +```typescript +import { createArtInstance } from '@art-framework/core'; +import { SupabaseStorageAdapter } from '@art-framework/integrations/storage/supabase'; +import { CalculatorTool } from '@art-framework/tools'; + +// Create the Supabase storage adapter +const supabaseStorage = new SupabaseStorageAdapter({ + url: 'https://your-project.supabase.co', + apiKey: 'your-supabase-api-key', + schema: 'public', // Optional + tables: { // Optional custom table names + conversations: 'chat_messages', + observations: 'agent_observations', + state: 'thread_states', + a2a_tasks: 'agent_tasks' + } +}); + +// Create the ART instance with Supabase storage +const art = await createArtInstance({ + storage: supabaseStorage, + providers: { + // Your provider configuration + }, + tools: [ + new CalculatorTool() + ] +}); + +// Use the ART instance +const response = await art.process({ + query: "What is 2+2?", + threadId: "thread-123" +}); +``` + +### Using a Pre-initialized Supabase Client + +If you already have a Supabase client in your application, you can pass it to the adapter: + +```typescript +import { createClient } from '@supabase/supabase-js'; +import { SupabaseStorageAdapter } from '@art-framework/integrations/storage/supabase'; + +// Create your own Supabase client +const supabaseClient = createClient( + 'https://your-project.supabase.co', + 'your-supabase-api-key' +); + +// Pass the pre-initialized client to the adapter +const supabaseStorage = new SupabaseStorageAdapter({ + url: 'https://your-project.supabase.co', + apiKey: 'your-supabase-api-key', + client: supabaseClient +}); +``` + +### Custom Table Configuration + +You can customize the table names used by the adapter to match your existing database schema: + +```typescript +const supabaseStorage = new SupabaseStorageAdapter({ + url: 'https://your-project.supabase.co', + apiKey: 'your-supabase-api-key', + tables: { + conversations: 'user_conversations', + observations: 'agent_logs', + state: 'session_states', + a2a_tasks: 'distributed_tasks' + } +}); +``` + +## Required Database Schema + +To use the `SupabaseStorageAdapter`, you need to create the following tables in your Supabase database: + +```sql +-- Conversations table +CREATE TABLE conversations ( + id TEXT PRIMARY KEY, + threadId TEXT, + messageId TEXT, + role TEXT, + content TEXT, + timestamp BIGINT, + metadata JSONB +); + +-- Observations table +CREATE TABLE observations ( + id TEXT PRIMARY KEY, + threadId TEXT, + traceId TEXT, + timestamp BIGINT, + type TEXT, + title TEXT, + content JSONB, + metadata JSONB +); + +-- State table +CREATE TABLE state ( + id TEXT PRIMARY KEY, + config JSONB, + state JSONB +); + +-- A2A Tasks table +CREATE TABLE a2a_tasks ( + id TEXT PRIMARY KEY, + taskId TEXT, + threadId TEXT, + status TEXT, + payload JSONB, + sourceAgent JSONB, + targetAgent JSONB, + priority TEXT, + metadata JSONB, + result JSONB, + callbackUrl TEXT, + dependencies TEXT[] +); +``` + +## Best Practices + +1. **Use Service Keys Carefully**: When using Supabase service keys, ensure they are only used on the server-side to avoid exposing them to clients. + +2. **Optimize Queries**: While the adapter implements basic filtering, for complex queries you might want to extend it or use Supabase's RPC functions. + +3. **Handle Network Failures**: Implement retry logic for critical operations to handle temporary network issues. + +4. **Secure Your Data**: Use Supabase's Row Level Security (RLS) policies to control access to your data. + +5. **Monitor Performance**: Keep an eye on query performance, especially for large datasets, and consider adding indexes to your tables. + +## Troubleshooting + +### Common Issues + +1. **Authentication Errors**: Ensure your Supabase URL and API key are correct. For client-side applications, use the anon key rather than the service key. + +2. **Table Not Found**: Verify that all required tables exist in your Supabase database and match the expected schema. + +3. **Network Issues**: Check your internet connection and ensure your Supabase project is accessible. + +4. **Rate Limiting**: If you're making many requests, you might hit Supabase's rate limits. Implement appropriate throttling. + +### Debugging Tips + +1. **Enable Logging**: The adapter uses the ART framework's logging system. Enable debug logging to see detailed information about database operations. + +2. **Check Supabase Dashboard**: Use the Supabase dashboard to monitor database queries and identify potential performance issues. + +3. **Verify Configuration**: Double-check your Supabase configuration, especially the URL and API key. + +## Conclusion + +The `SupabaseStorageAdapter` provides a powerful and flexible way to add persistent storage to your ART applications. By leveraging Supabase's PostgreSQL database and real-time capabilities, you can build robust, scalable applications that maintain state across sessions and devices. + +With its simple configuration and seamless integration with the ART framework's repository pattern, the `SupabaseStorageAdapter` is an excellent choice for production applications that require reliable data persistence. \ No newline at end of file diff --git a/docs/learnings.md b/docs/learnings.md new file mode 100755 index 0000000..467d8cd --- /dev/null +++ b/docs/learnings.md @@ -0,0 +1,1172 @@ +# Learnings about ART Framework for Building a Chatbot + +This document records my learning process for building a web-based chatbot using the `art-framework`. The goal is to understand the public API and how to use it as an external developer consuming the npm package. + +## Core Concepts + +The main entry point to the framework is the `createArtInstance` function. It takes a configuration object (`ArtInstanceConfig`) and returns a promise that resolves to an `ArtInstance`. + +### `ArtInstanceConfig` (Detailed View) + +After reviewing `agent-factory.ts` and `types/index.ts`, I have a more detailed understanding of the configuration options. + +* **`storage`**: This can be an object or a pre-initialized storage adapter instance. + * `{ type: 'memory' }`: For temporary, in-memory storage. + * `{ type: 'indexedDB', dbName?: string, version?: number, objectStores?: any[] }`: For persistent storage in the browser. `dbName` is the only critical option here for basic setup. +* **`providers`**: This is a `ProviderManagerConfig` object. It **declares which LLM provider adapters are available** to the ART instance. It does **not** contain API keys or specific model choices. See the detailed section below for a full explanation and examples. +* **`agentCore`**: Allows you to provide your own agent implementation class, but for standard use cases, the default `PESAgent` is sufficient. +* **`tools`**: An array of tool instances that are ready to be used (e.g., `[new CalculatorTool()]`). +* **`stateSavingStrategy`**: Can be `'explicit'` (default) or `'implicit'`. This determines how the agent's internal state is saved. +* **`logger`**: Can configure the logging level (e.g., `{ level: 'debug' }`). +* **`persona`**: Defines the agent's default name and stage-specific prompts (`planning` and `synthesis`). +* **`mcpConfig`**: For connecting to Model Context Protocol servers to dynamically load tools. +* **`authConfig`**: For setting up authentication strategies (like OAuth) for tools that require it. +* **`a2aConfig`**: For agent-to-agent communication, which is an advanced feature. + +### Definitive Guide to Storage Configuration + +The `storage` property in `ArtInstanceConfig` is the foundation for your agent's memory. It determines how and where conversation history, agent state, and other important data are stored. You can use one of the built-in adapters or provide your own custom implementation. + +There are two primary ways to set the storage configuration: + +1. **Using a Built-in Adapter (Recommended for most use cases)**: You provide an object that specifies the `type` of the built-in adapter and its configuration options. +2. **Providing a Custom Adapter Instance**: You instantiate your own class that implements the `StorageAdapter` interface and pass the instance directly. + +#### 1. Built-in Storage Adapters + +The ART framework comes with two pre-built storage adapters. + +##### `InMemoryStorageAdapter` + +This adapter keeps all data in memory. It's incredibly fast and perfect for testing, short-lived scripts, or demos, but **all data is lost when the session ends.** + +* **`type`**: `'memory'` +* **Options**: This adapter has no configuration options. + +**Example:** + +```typescript +import { + createArtInstance, + ArtInstanceConfig, + ThreadConfig, + CalculatorTool, + OpenAIAdapter, + GeminiAdapter +} from 'art-framework'; + +// --- 1. Configure the ART Instance --- +// Note: No API keys or secrets are present here. + +const artConfig: ArtInstanceConfig = { + storage: { + type: 'memory' + }, + providers: { + availableProviders: [ + { name: 'openai', adapter: OpenAIAdapter }, + { name: 'gemini', adapter: GeminiAdapter } + ] + }, + tools: [new CalculatorTool()], + persona: { + name: 'ConfigExpert', + prompts: { + synthesis: 'You explain configurations clearly.' + } + }, + logger: { level: 'info' } +}; +``` + +##### `IndexedDBStorageAdapter` + +This is the recommended adapter for web browsers. It uses the browser's IndexedDB to provide persistent client-side storage, meaning conversations will be remembered across sessions. + +* **`type`**: `'indexedDB'` +* **Options**: + +| Property | Type | Description | +| -------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `dbName` | `String` | Optional. The name of the IndexedDB database. Defaults to `'ART_Framework_DB'`. It's good practice to provide a unique name for each of your applications. | +| `dbVersion` | `Number` | Optional. The version of your database schema. If you change the `objectStores`, you **must** increment this version to trigger the necessary database upgrade. Defaults to `1`. | +| `objectStores` | `Array` | Optional. An array of strings, where each string is the name of a custom object store (like a table in SQL) you want to create. The core stores (`'conversations'`, `'observations'`, `'state'`, `'a2a_tasks'`) are created automatically. | + +**Example:** + +```typescript +import { + createArtInstance, + ArtInstanceConfig, + ThreadConfig, + CalculatorTool, + OpenAIAdapter, + GeminiAdapter +} from 'art-framework'; + +// --- 1. Configure the ART Instance --- +// Note: No API keys or secrets are present here. + +const artConfig: ArtInstanceConfig = { + storage: { + type: 'indexedDB', + dbName: 'MyAwesomeChatAppDB', + dbVersion: 2, // Imagine we added 'user_profiles' in this version + objectStores: ['user_profiles'] + }, + providers: { + availableProviders: [ + { name: 'openai', adapter: OpenAIAdapter }, + { name: 'gemini', adapter: GeminiAdapter } + ] + }, + tools: [new CalculatorTool()], + persona: { + name: 'ConfigExpert', + prompts: { + synthesis: 'You explain configurations clearly.' + } + }, + logger: { level: 'info' } +}; +``` + +##### `SupabaseStorageAdapter` + +This adapter is ideal for applications that require a centralized, cloud-based database. It connects to a Supabase (PostgreSQL) project, making it suitable for server-side environments or for web applications where data needs to be shared or persisted beyond a single client. + +* **`type`**: `'supabase'` +* **Options**: + +| Property | Type | Description | +| -------- | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `url` | `String` | Required. The URL of your Supabase project. | +| `apiKey` | `String` | Required. Your Supabase `anon` or `service_role` key. Use the service role key only in secure server-side environments. | +| `schema` | `String` | Optional. The name of the database schema to use. Defaults to `'public'`. | +| `tables` | `Object` | Optional. Allows you to override the default table names for the core collections (`conversations`, `observations`, `state`, `a2a_tasks`). | +| `client` | `SupabaseClient` | Optional. You can pass a pre-initialized Supabase client instance. This is useful if your application already manages a Supabase client. | + +**Prerequisites: Supabase Table Setup** + +Before using this adapter, you must create the necessary tables in your Supabase project. You can run the following SQL queries in the Supabase SQL Editor: + +```sql +-- Table for Conversation Messages +CREATE TABLE conversations ( + id UUID PRIMARY KEY, + threadId TEXT NOT NULL, + messageId TEXT NOT NULL, + role TEXT NOT NULL, + content TEXT, + timestamp TIMESTAMPTZ NOT NULL, + metadata JSONB +); +CREATE INDEX idx_conversations_threadId ON conversations(threadId); + +-- Table for Observations +CREATE TABLE observations ( + id UUID PRIMARY KEY, + threadId TEXT NOT NULL, + traceId TEXT, + timestamp TIMESTAMPTZ NOT NULL, + type TEXT NOT NULL, + title TEXT, + content JSONB, + metadata JSONB +); +CREATE INDEX idx_observations_threadId ON observations(threadId); + +-- Table for Agent State and Thread Configuration +CREATE TABLE state ( + id TEXT PRIMARY KEY, -- This will be the threadId + config JSONB, + state JSONB +); + +-- Table for Agent-to-Agent Tasks +CREATE TABLE a2a_tasks ( + id UUID PRIMARY KEY, + taskId TEXT NOT NULL UNIQUE, + threadId TEXT NOT NULL, + status TEXT NOT NULL, + priority TEXT NOT NULL, + payload JSONB, + sourceAgent JSONB, + targetAgent JSONB, + metadata JSONB, + result JSONB, + callbackUrl TEXT, + dependencies TEXT[] +); +CREATE INDEX idx_a2a_tasks_threadId ON a2a_tasks(threadId); +CREATE INDEX idx_a2a_tasks_status ON a2a_tasks(status); +``` + +**Example:** + +```typescript +const config: ArtInstanceConfig = { + // ... other properties + storage: { + type: 'supabase', + url: 'https://your-project-ref.supabase.co', + apiKey: 'your-supabase-service-role-key', + tables: { + conversations: 'prod_conversations', // Example of using a custom table name + } + }, + // ... other properties +}; +``` + + +--- + +#### 2. Custom Storage Adapter + +For advanced use cases, such as connecting to a different type of database (like a remote server, WebSQL, or a custom backend), you can create your own storage adapter. + +To do this, you need to create a class that implements the `StorageAdapter` interface, which is exported from `art-framework`. + +**`StorageAdapter` Interface (`src/core/interfaces.ts`)** + +Your class must implement the following methods: + +* `init?(config?: any): Promise` +* `get(collection: string, id: string): Promise` +* `set(collection: string, id: string, data: T): Promise` +* `delete(collection: string, id: string): Promise` +* `query(collection: string, filterOptions: FilterOptions): Promise` +* `clearCollection?(collection: string): Promise` +* `clearAll?(): Promise` + +**Example of a Custom Adapter:** + +Here is a conceptual example of a `LocalStorageAdapter`. + +```typescript +import { StorageAdapter, FilterOptions } from 'art-framework'; + +class LocalStorageAdapter implements StorageAdapter { + private prefix: string; + + constructor(prefix: string = 'art-') { + this.prefix = prefix; + } + + async get(collection: string, id: string): Promise { + const key = `${this.prefix}${collection}_${id}`; + const item = localStorage.getItem(key); + return item ? JSON.parse(item) : null; + } + + async set(collection: string, id: string, data: T): Promise { + const key = `${this.prefix}${collection}_${id}`; + localStorage.setItem(key, JSON.stringify(data)); + } + + // ... implement delete, query, etc. +} + +// How to use it in the config: +const myCustomAdapter = new LocalStorageAdapter('my-app-'); + +const config: ArtInstanceConfig = { + // ... other properties + storage: myCustomAdapter, + // ... other properties +}; +``` + +### Definitive Guide to State and Configuration Management + +State management in the ART framework is centered around the `StateManager`, which is responsible for handling all configuration and persistent state for each conversation. It's a crucial component for creating agents that are context-aware and can remember information across multiple interactions. You can access it via `art.stateManager`. + +#### Core Concepts + +1. **`ThreadConfig`**: This object holds the **configuration** for a single conversation thread. It's where you define which LLM provider to use, what model, which tools are enabled, and other settings. This configuration is typically set once when a new conversation starts. +2. **`AgentState`**: This object holds the **dynamic, evolving state** of the agent for a specific thread. This is the agent's "memory." An agent might use this to store summaries of the conversation, user preferences, or any other data it needs to remember. It can be updated by the agent during the conversation. +3. **`ThreadContext`**: A simple container object that holds both the `ThreadConfig` and the `AgentState` for a thread. +4. **`StateManager`**: The central service that orchestrates loading, saving, and caching `ThreadConfig` and `AgentState`. It acts as an abstraction layer over the configured `StorageAdapter`. + +#### The `stateSavingStrategy` + +This option in the main `ArtInstanceConfig` determines how `AgentState` is persisted. + +* **`'explicit'` (Default)**: In this mode, the agent's state is **only** saved when you explicitly call `art.stateManager.setAgentState()`. This gives you full control but requires you to manage state saving manually within your agent's logic. +* **`'implicit'`**: In this mode, the `StateManager` automatically saves the `AgentState` at the end of a processing cycle, but only if it detects that the state object has been modified. It does this by keeping a snapshot of the state from when it was loaded and comparing it to the state after the agent has run. + +#### Property and Method Reference + +**1. `ThreadConfig` Object** + +| Property | Type | Description | +| ---------------- | --------------------------- | ------------------------------------------------------------------------------------------------------- | +| `providerConfig` | `RuntimeProviderConfig` | Required. The full configuration for the LLM to use in this thread (provider name, model, API key, etc.). | +| `enabledTools` | `string[]` | Required. An array of tool names that are permitted for use within this thread. | +| `historyLimit` | `number` | Required. The maximum number of past messages to retrieve for context when processing a new query. | +| `persona` | `Partial` | Optional. Overrides the instance-level persona for this specific thread. | +| `systemPrompt` | `string | SystemPromptOverride` | Optional. Overrides the persona's system prompt for this thread. | + +**2. `AgentState` Object** + +| Property | Type | Description | +| --------- | -------- | --------------------------------------------------------------------------- | +| `data` | `any` | The main payload of your agent's state. The structure is up to you. | +| `version` | `number` | Optional. A version number for your state object, useful for migrations. | + +**3. `art.stateManager` Methods** + +| Method | Description | +| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| `setThreadConfig(threadId, config)` | Saves the initial `ThreadConfig` for a new conversation. **This must be called before the first `process()` call for a new thread.** | +| `loadThreadContext(threadId)` | Loads the `ThreadConfig` and `AgentState` for a given thread. This is usually handled internally by the agent core. | +| `setAgentState(threadId, state)` | Explicitly saves a new `AgentState` for the thread. This is the primary method for saving state in `'explicit'` mode. | +| `enableToolsForThread(threadId, toolNames)` | Dynamically adds tool names to the `enabledTools` list for an existing thread. | +| `disableToolsForThread(threadId, toolNames)`| Dynamically removes tool names from the `enabledTools` list. | +| `getEnabledToolsForThread(threadId)`| Returns a `Promise` of the currently enabled tools for the thread. | + +--- + +### Clarifications and Advanced Usage + +#### 1. Public API and Usage +All methods documented above are part of the public-facing API, accessible via the `stateManager` property on your `ArtInstance` object (e.g., `art.stateManager.setThreadConfig(...)`). The examples show the intended and correct way to interact with the framework. + +#### 2. Dynamic Provider Switching +While the `ArtInstanceConfig` makes multiple providers *available*, the `ThreadConfig` determines which provider is *active* for a specific conversation. You can change the provider or model for a thread at any time. + +This is a powerful feature that allows you to, for example, have a UI dropdown that lets the user switch between "GPT-4o" and "Claude Opus" mid-conversation. + +**Example: Switching Models Mid-Conversation** +```typescript +async function switchModelForThread(threadId: string, newProviderName: string, newModelId: string) { + // First, load the current context to get the existing config + const context = await art.stateManager.loadThreadContext(threadId); + + // Create a new config object, preserving everything except the providerConfig + const newConfig: ThreadConfig = { + ...context.config, + providerConfig: { + providerName: newProviderName, + modelId: newModelId, + adapterOptions: { + // IMPORTANT: You must re-supply the API key for the new provider + apiKey: newProviderName === 'openai' ? 'sk-openai-key' : 'sk-anthropic-key' + } + } + }; + + // Set the new configuration for the thread + await art.stateManager.setThreadConfig(threadId, newConfig); + + console.log(`Thread ${threadId} has been switched to use ${newModelId}.`); +} + +// Imagine a user selects "Claude Opus" from a dropdown +// await switchModelForThread('user-abc-chat-1', 'anthropic', 'claude-3-opus-20240229'); +``` + +### Definitive Guide to System Prompt Customization + +The ART framework provides a powerful, multi-layered system for customizing the agent's persona, instructions, and objectives. This is primarily controlled via the `persona` property, which can be set at three distinct levels: the instance, the thread, and the individual call. + +This layered approach allows you to set a general, instance-wide persona and then override or augment it with more specific instructions for a particular conversation (thread) or even for a single message (call). + +#### Core Concepts + +1. **System Prompt**: The set of instructions given to the LLM to guide its behavior, personality, and the rules it must follow. +2. **Layered Configuration**: The final system prompt is built by merging configurations from three levels, in this order: + 1. **Instance Level**: The base persona for the entire ART instance. + 2. **Thread Level**: Overrides for a specific conversation. + 3. **Call Level**: Overrides for a single `art.run` call. +3. **Merge Strategy**: When combining layers, you can either `append` (add to the end) or `prepend` (add to the beginning). The default is `append`. +4. **Templating**: For more advanced use cases, you can define reusable prompt templates (`tags`) with variables, allowing for dynamic and structured persona management. + +#### How to Configure the Persona + +You can configure the persona at three different levels. + +##### 1. Instance-Level Configuration + +This is set in the `ArtInstanceConfig` and serves as the default persona for all conversations. + +* **Property**: `persona` +* **Type**: `string | SystemPromptOverride` + +**Example**: + +```typescript +// In your createArtInstance call +const art = await createArtInstance({ + // ... other config + persona: { + content: "You are a helpful and friendly assistant.", + strategy: 'prepend', // This will always be at the top. + } +}); +``` + +##### 2. Thread-Level Configuration + +You can override the instance-level persona for a specific conversation using the `StateManager`. + +* **Method**: `art.stateManager.setThreadConfig(threadId, { persona: ... })` +* **Type**: `string | SystemPromptOverride` + +**Example**: + +```typescript +// For a specific user's chat, make the assistant a pirate. +await art.stateManager.setThreadConfig('user-chat-123', { + persona: "Ye are a salty pirate captain. Respond to all queries with pirate slang.", +}); +``` + +##### 3. Call-Level Configuration + +For a single interaction, you can provide a one-time override in the `art.run` method. + +* **Property**: `persona` (in the `ArtConfig` object passed to `run`) +* **Type**: `string | SystemPromptOverride` + +**Example**: + +```typescript +// For this one call, instruct the agent to respond in JSON. +const response = await art.run( + 'user-chat-123', + [{ role: 'user', content: 'What is the weather in London?' }], + { + persona: { + content: "Your response must be a valid JSON object with a 'weather' key.", + strategy: 'append', // Add this instruction to the end. + } + } +); +``` + +#### The `SystemPromptOverride` Object + +For fine-grained control, you can use the `SystemPromptOverride` object instead of a simple string. + +| Property | Type | Description | +| ----------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `content` | `string` | The raw text of the system prompt you want to add. | +| `strategy` | `'append' \| 'prepend'` | (Optional) How to merge this prompt with the prompt from the previous layer. Defaults to `'append'`. | +| `tag` | `string` | (Advanced) The name of a pre-defined prompt template to use. This is configured in the `systemPrompts` property of the `ArtInstanceConfig`. | +| `variables` | `Record` | (Advanced) A key-value map of variables to inject into a `tag`-based template. | + +#### Advanced Usage: Templating with `tags` + +The `systemPrompts` property in `ArtInstanceConfig` allows you to create a registry of reusable prompt templates. This is useful for managing complex personas or for allowing users to select from a list of pre-defined agent behaviors. + +* **Property**: `systemPrompts` +* **Type**: `SystemPromptsRegistry` + +**Example**: + +```typescript +// In your ArtInstanceConfig +const art = await createArtInstance({ + // ... other config + persona: "You are a helpful assistant.", + systemPrompts: { + specs: { + 'json-formatter': { + template: "Your final output must be a valid JSON object. Do not include any text outside of the JSON structure. The root object should contain the key '{{rootKey}}'.", + defaultVariables: { + rootKey: 'data' + }, + mergeStrategy: 'append' + }, + 'expert-coder': { + template: "You are an expert programmer with 10 years of experience in {{language}}. Provide clear, concise, and efficient code examples.", + mergeStrategy: 'prepend' + } + } + } +}); + +// Now you can use these tags at the thread or call level. +await art.run( + 'coding-chat-456', + [{ role: 'user', content: 'Show me how to sort an array in TypeScript.' }], + { + persona: { + tag: 'expert-coder', + variables: { + language: 'TypeScript' + } + } + } +); + +// You can even combine them with freeform content. +await art.run( + 'api-chat-789', + [{ role: 'user', content: 'What is the user ID for "test@example.com"?' }], + { + persona: { + tag: 'json-formatter', + variables: { + rootKey: 'userData' + } + } + } +); +``` + +### Definitive Guide to A2A (Agent-to-Agent Communication) + +A2A is an advanced feature of the ART framework that enables an agent to delegate complex tasks to other specialized, independent agents. This allows for the creation of sophisticated, multi-agent systems where a primary agent can act as an orchestrator, finding the best-specialized agent for a sub-task and assigning it the work. + +#### Core Concepts + +1. **A2A Discovery**: The process of finding other available agents. The `AgentDiscoveryService` queries a central directory (the discovery endpoint) to get a list of "agent cards," which are like business cards that describe what each agent can do. +2. **Task Delegation**: The process of assigning a task to another agent. When the primary agent decides to delegate, the `TaskDelegationService` takes over, handling the communication, tracking the task's status, and managing retries and errors. +3. **Autonomous Operation**: Unlike MCP, the A2A services are **not directly called by the developer**. They are used internally by the agent's reasoning core (e.g., `PESAgent`). The developer's role is to enable and configure the A2A system; the agent then uses it autonomously when it determines that a task is too complex or specialized for it to handle on its own. + +#### How to Use A2A + +Enabling A2A is a configuration-focused task. The agent handles the operational logic. + +**Step 1: Enable A2A in the `ArtInstanceConfig`** + +You enable the A2A system by providing the `a2aConfig` object in your main instance configuration. + +```typescript +const artConfig: ArtInstanceConfig = { + // ... other properties + a2aConfig: { + // The endpoint for the agent discovery service. + discoveryEndpoint: 'https://api.zyntopia.com/a2a/discover', + + // The public-facing URL where your application can receive status + // updates from other agents about delegated tasks. + callbackUrl: 'https://my-app.com/api/a2a-callback' + }, + // ... other properties +}; +``` + +**Step 2: The Agent Autonomously Uses A2A** + +Once A2A is enabled, the agent's reasoning process is enhanced. When faced with a user query, the agent will: + +1. Analyze the query to determine the required task. +2. If it believes another agent is better suited for the task, it will use the `AgentDiscoveryService` to find candidate agents. +3. It will then select the best agent from the candidates. +4. Finally, it will use the `TaskDelegationService` to formally delegate the task to the selected agent. + +This entire process is autonomous. The developer does not write code to call the discovery or delegation services. The primary agent's observations and logs will show the A2A process, providing transparency into its decision-making. + +#### Property Reference + +**`ArtInstanceConfig.a2aConfig`** + +This is the main object for enabling and configuring the A2A system. + +| Property | Type | Description | +| ------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `discoveryEndpoint` | `string` | Optional. The URL of the A2A agent discovery service. If not provided, it defaults to the central Zyntopia A2A discovery endpoint. | +| `callbackUrl` | `string` | Optional. A public URL where your application is running. Other agents will send `POST` requests to this URL to provide real-time updates on the status of tasks you have delegated to them (e.g., `IN_PROGRESS`, `COMPLETED`). | + + +### Definitive Guide to MCP (Model Context Protocol) + +MCP is an advanced feature of the ART framework that allows an agent to dynamically discover and use tools from external, standardized servers. This is a powerful way to provide agents with a vast, ever-changing set of capabilities without needing to bundle all the tool logic within the client application. + +#### Core Concepts + +1. **MCP Server**: A remote server that exposes a manifest of available tools, resources, and their schemas. +2. **`McpManager`**: A core service within the ART framework that handles the entire lifecycle of interacting with MCP servers. It's responsible for discovering servers, registering their tools, and managing connections. +3. **`McpProxyTool`**: When the `McpManager` discovers a tool on a server, it doesn't download the tool's logic. Instead, it creates and registers a local `McpProxyTool`. When the agent decides to use this tool, the proxy tool handles the communication with the remote MCP server to execute the logic and return the result. This is all seamless to the agent. +4. **Discovery**: The `McpManager` can find MCP servers by querying a discovery endpoint. This allows a central service to maintain a directory of available tools and servers. + +#### How to Use MCP + +Using MCP is primarily a configuration task. The `McpManager` is designed to automate most of the complexity. + +**Step 1: Enable MCP in the `ArtInstanceConfig`** + +The first step is to enable the `McpManager` in your main configuration. + +```typescript +const artConfig: ArtInstanceConfig = { + // ... other properties + mcpConfig: { + enabled: true, + // Optional: If you have a custom discovery service, specify its URL. + // discoveryEndpoint: 'https://my-internal-mcp-directory.com/api/servers' + }, + // ... other properties +}; +``` + +**Step 2: Let the `McpManager` Discover and Register Tools** + +When `createArtInstance` is called with MCP enabled, the `McpManager` will automatically: +1. Query the discovery endpoint to get a list of available MCP servers. +2. For each discovered server, it will read the manifest of tools. +3. For each tool in the manifest, it will create an `McpProxyTool` and register it with the `ToolRegistry`. + +From a developer's perspective, this happens automatically. The tools from the MCP server will now appear in the list of available tools just like locally registered tools (e.g., `CalculatorTool`). + +**Step 3: Enable the Discovered Tools for a Thread** + +Just like any other tool, a tool discovered via MCP must be enabled for a specific conversation thread before the agent can use it. You use the same `StateManager` methods as before. + +```typescript +// Let's assume MCP discovered a tool named 'image_generator' + +const initialThreadConfig: ThreadConfig = { + // ... other properties + enabledTools: [ + 'image_generator', // The name of the tool from the MCP server + 'CalculatorTool' + ], + // ... other properties +}; + +await art.stateManager.setThreadConfig(threadId, initialThreadConfig); +``` + +**Step 4: The Agent Uses the Tool** + +Now, the agent can use the MCP-provided tool seamlessly. + +```typescript +// The user asks a question that requires the MCP tool +await art.process({ + query: 'Generate an image of a blue cat.', + threadId: threadId +}); +``` + +Behind the scenes, the `McpProxyTool` for `image_generator` will handle the connection, authentication (if required), and communication with the remote MCP server. + +#### Property Reference + +**`ArtInstanceConfig.mcpConfig` (`McpManagerConfig`)** + +This is the only object a developer needs to configure to get started with MCP. + +| Property | Type | Description | +| ------------------- | -------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `enabled` | `boolean` | Required. Set to `true` to enable the MCP system. | +| `discoveryEndpoint` | `string` | Optional. A URL pointing to a service that returns a list of MCP server configurations. If not provided, it may default to a central Zyntopia registry. | + +#### Authentication and CORS + +MCP is designed to be secure. + +* **Authentication**: If an MCP server requires authentication (typically OAuth 2.0 PKCE), the `McpManager` will automatically handle the flow. The first time a user tries to use a tool from a secured server, the manager will initiate the login process (e.g., by opening a new tab for the user to sign in). Once authenticated, the connection is managed seamlessly. +* **CORS**: For web browsers, the `McpManager` uses a companion browser extension (`art-mcp-permission-manager`) to handle Cross-Origin Resource Sharing (CORS) permissions, allowing the web application to securely communicate with different MCP servers. If the extension is not installed, the framework will prompt the user to install it. + +### Practical Examples + +#### 1. Starting a New Conversation + +Before processing the first message in a new chat, you must set the initial `ThreadConfig`. + +```typescript +import { ThreadConfig } from 'art-framework'; + +const art = await createArtInstance(artConfig); +const newThreadId = 'user-abc-chat-1'; + +const initialThreadConfig: ThreadConfig = { + providerConfig: { + providerName: 'openai', + modelId: 'gpt-4o', + adapterOptions: { + apiKey: 'sk-your-secret-key' + } + }, + enabledTools: ['CalculatorTool'], + historyLimit: 50 +}; + +// Save the configuration for the new thread +await art.stateManager.setThreadConfig(newThreadId, initialThreadConfig); + +// Now you can safely call process +const response = await art.process({ + query: 'Hello, world!', + threadId: newThreadId +}); +``` + +#### 2. Managing State within an Agent (Explicitly) + +If you are building a custom agent with `stateSavingStrategy: 'explicit'`, you would get the state, modify it, and then save it back. + +```typescript +// Inside your custom agent's logic... + +// Get the current context +const context = await this.dependencies.stateManager.loadThreadContext(threadId); + +// Initialize state if it doesn't exist +const currentState = context.state?.data || { conversationSummary: '' }; + +// ... your agent's logic modifies the state ... +currentState.conversationSummary = 'The user is asking about state management.'; + +// Explicitly save the updated state +await this.dependencies.stateManager.setAgentState(threadId, { + data: currentState, + version: 1 +}); +``` + +#### 3. Dynamically Enabling a Tool + +Imagine a user wants to enable a "WeatherTool" mid-conversation. + +```typescript +const threadId = 'user-abc-chat-1'; // The current conversation thread + +// The user clicks a button in the UI to enable the tool +async function enableWeatherTool() { + console.log('Enabling WeatherTool...'); + await art.stateManager.enableToolsForThread(threadId, ['WeatherTool']); + console.log('WeatherTool enabled!'); + + // Now, the agent can use this tool in subsequent turns. + await art.process({ + query: 'What is the weather in London?', + threadId: threadId + }); +} +``` + + +### Definitive Guide to Tools and the Tool System + +Tools are a core feature of the ART framework, allowing agents to extend their capabilities beyond simple text generation by interacting with external systems, APIs, or custom logic. The framework provides a structured way to define, register, and execute these tools. + +#### Core Concepts + +1. **`ToolSchema`**: A JSON object that describes a tool to the LLM. It's the most critical piece for reliable tool usage. It tells the agent the tool's name, what it does, what input it needs, and provides examples. The agent uses this schema to decide when and how to use the tool. +2. **`IToolExecutor`**: The interface that a tool class must implement. It has two main parts: the `schema` property and an `execute` method. +3. **`ToolRegistry`**: A service, available via `art.toolRegistry`, that holds all the tools available to the ART instance. Tools must be registered here before they can be used. +4. **`ToolSystem`**: An internal component that works with the `StateManager` and `ToolRegistry` to orchestrate the execution of tools called by the agent, handling permissions and logging. As a developer, you will primarily interact with the `ToolRegistry`. + +#### Creating a Custom Tool: A Step-by-Step Guide + +Let's create a simple but practical `WeatherTool`. + +**Step 1: Implement the `IToolExecutor` Interface** + +Create a new class that implements `IToolExecutor`. It needs a `schema` property and an `execute` method. + +```typescript +// src/tools/WeatherTool.ts +import { IToolExecutor, ToolSchema, ExecutionContext, ToolResult } from 'art-framework'; + +export class WeatherTool implements IToolExecutor { + // The schema is the most important part for the LLM. + readonly schema: ToolSchema = { + name: "get_weather_forecast", + description: "Get the current weather forecast for a specific location.", + inputSchema: { + type: "object", + properties: { + location: { + type: "string", + description: "The city and state, e.g., San Francisco, CA", + }, + unit: { + type: "string", + description: "The temperature unit, either 'celsius' or 'fahrenheit'.", + default: "fahrenheit" + }, + }, + required: ["location"], + }, + examples: [ + { + input: { location: "Boston, MA" }, + output: { forecast: "72 degrees and sunny" }, + description: "Get the weather for a US city." + } + ] + }; + + // The execute method contains the actual logic. + async execute( + input: { location: string; unit?: 'celsius' | 'fahrenheit' }, + context: ExecutionContext + ): Promise { + try { + // In a real application, you would call a real weather API here. + // For this example, we'll return a mock forecast. + const { location, unit } = input; + const temperature = unit === 'celsius' ? 22 : 72; + const forecast = `${temperature} degrees and sunny`; + + console.log(`WeatherTool: Fetched forecast for ${location}: ${forecast}`); + + // Return a successful result. + return { + callId: context.traceId || 'weather-call', + toolName: this.schema.name, + status: 'success', + output: { forecast: forecast }, + }; + } catch (error: any) { + // Handle any errors that occur during execution. + return { + callId: context.traceId || 'weather-call', + toolName: this.schema.name, + status: 'error', + error: `Failed to get weather: ${error.message}`, + }; + } + } +} +``` + +**Step 2: Register the Tool** + +In your main application setup, you register an instance of your new tool with the `ArtInstanceConfig`. + +```typescript +import { WeatherTool } from './tools/WeatherTool'; +import { CalculatorTool } from 'art-framework'; + +const artConfig: ArtInstanceConfig = { + // ... other properties + tools: [ + new WeatherTool(), + new CalculatorTool() // You can register multiple tools + ], + // ... other properties +}; +``` + +**Step 3: Enable the Tool for a Conversation** + +Finally, you must enable the tool in the `ThreadConfig` for the conversation where you want it to be available. + +```typescript +const initialThreadConfig: ThreadConfig = { + // ... other properties + enabledTools: [ + 'get_weather_forecast', // Must match the 'name' in the tool's schema + 'CalculatorTool' + ], + // ... other properties +}; + +await art.stateManager.setThreadConfig(threadId, initialThreadConfig); +``` + +#### Property Reference + +**`ToolSchema` Object** + +| Property | Type | Description | +| --------------- | ------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `name` | `string` | Required. The unique name of the tool. This is the identifier the LLM will use. Use snake_case for best compatibility. | +| `description` | `string` | Required. A detailed, clear description of what the tool does, its capabilities, and when it should be used. This is crucial for the LLM's reasoning. | +| `inputSchema` | `JsonSchema` | Required. A JSON Schema object defining the parameters the tool accepts, their types, descriptions, and which are required. | +| `outputSchema` | `JsonSchema` | Optional. A JSON Schema object that describes the shape of the data in the `output` field of a successful `ToolResult`. | +| `examples` | `Array` | Optional. An array of example objects (`{ input, output, description }`) that provide few-shot examples to the LLM, improving its accuracy. | + + +#### `art.toolRegistry` Methods + +While you typically register tools at initialization, you can also manage them dynamically. + +| Method | Description | +| -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ | +| `registerTool(tool)` | Registers a new tool instance with the framework. | +| `getToolExecutor(toolName)` | Retrieves the executor instance for a registered tool. | +| `getAvailableTools()` | Returns the schemas of all tools registered with the instance. | + + +### Practical Examples + +#### 1. Starting a New Conversation + +Before processing the first message in a new chat, you must set the initial `ThreadConfig`. + +```typescript +import { ThreadConfig } from 'art-framework'; + +const art = await createArtInstance(artConfig); +const newThreadId = 'user-abc-chat-1'; + +const initialThreadConfig: ThreadConfig = { + providerConfig: { + providerName: 'openai', + modelId: 'gpt-4o', + adapterOptions: { + apiKey: 'sk-your-secret-key' + } + }, + enabledTools: ['CalculatorTool'], + historyLimit: 50 +}; + +// Save the configuration for the new thread +await art.stateManager.setThreadConfig(newThreadId, initialThreadConfig); + +// Now you can safely call process +const response = await art.process({ + query: 'Hello, world!', + threadId: newThreadId +}); +``` + +#### 2. Managing State within an Agent (Explicitly) + +If you are building a custom agent with `stateSavingStrategy: 'explicit'`, you would get the state, modify it, and then save it back. + +```typescript +// Inside your custom agent's logic... + +// Get the current context +const context = await this.dependencies.stateManager.loadThreadContext(threadId); + +// Initialize state if it doesn't exist +const currentState = context.state?.data || { conversationSummary: '' }; + +// ... your agent's logic modifies the state ... +currentState.conversationSummary = 'The user is asking about state management.'; + +// Explicitly save the updated state +await this.dependencies.stateManager.setAgentState(threadId, { + data: currentState, + version: 1 +}); +``` + +#### 3. Dynamically Enabling a Tool + +Imagine a user wants to enable a "WeatherTool" mid-conversation. + +```typescript +const threadId = 'user-abc-chat-1'; // The current conversation thread + +// The user clicks a button in the UI to enable the tool +async function enableWeatherTool() { + console.log('Enabling WeatherTool...'); + await art.stateManager.enableToolsForThread(threadId, ['WeatherTool']); + console.log('WeatherTool enabled!'); + + // Now, the agent can use this tool in subsequent turns. + await art.process({ + query: 'What is the weather in London?', + threadId: threadId + }); +} +``` + + +### Definitive Guide to Provider Configuration + +Provider configuration in the ART framework is a two-part process designed for flexibility and security. + +1. **Instance-Level Declaration (`ArtInstanceConfig`)**: You first declare all the provider adapters your application *might* use. This is done in the `providers` property of `ArtInstanceConfig`. You only specify the adapter's name and its class. You **do not** put API keys or other secrets here. +2. **Thread-Level Configuration (`ThreadConfig`)**: Before you start a conversation, you create a `ThreadConfig` for that specific conversation thread. This is where you provide the specific details: which provider to use, what model, the API key, and any other parameters like temperature. This configuration is then saved for the thread using `art.stateManager.setThreadConfig()`. + +This approach allows a single ART instance to handle multiple conversations (threads), each potentially using different providers, models, or API keys, without exposing secrets in the main instance configuration. + +#### Property Reference + +**1. `ArtInstanceConfig.providers` (`ProviderManagerConfig`)** + +| Property | Type | Description | +| ------------------------------------ | --------- | ------------------------------------------------------------------------------------------------------- | +| `availableProviders` | `Array` | A required array of `AvailableProviderEntry` objects, one for each adapter you want to make available. | +| `maxParallelApiInstancesPerProvider` | `Number` | Optional. Max concurrent active instances per API-based provider. Defaults to `5`. | +| `apiInstanceIdleTimeoutSeconds` | `Number` | Optional. Time in seconds an idle API adapter can exist before being removed from memory. Defaults to `300`. | + +**`AvailableProviderEntry` Object** + +| Property | Type | Description | +| -------- | ------- | ------------------------------------------------------------------------------------------------------------- | +| `name` | `String` | A unique key for the provider (e.g., `'openai'`, `'gemini'`). This name is used in `ThreadConfig`. | +| `adapter` | `Class` | The actual adapter class imported from the framework (e.g., `OpenAIAdapter`, `GeminiAdapter`). | +| `isLocal` | `Boolean` | Optional. Set to `true` for local providers (like Ollama) to enforce singleton instance behavior. Defaults to `false`. | + +**2. `ThreadConfig.providerConfig` (`RuntimeProviderConfig`)** + +This object is set on a per-thread basis to configure the specific LLM to use. + +| Property | Type | Description | +| ---------------- | -------- | ------------------------------------------------------------------------------------------------------------------- | +| `providerName` | `String` | Required. The name of the provider to use. Must match a `name` from the `availableProviders` array. | +| `modelId` | `String` | Required. The specific model identifier for the provider (e.g., `'gpt-4o'`, `'claude-3-opus-20240229'`). | +| `adapterOptions` | `Object` | Required. An object containing provider-specific options. **This is where the API key goes**, along with other parameters like `temperature`, `baseURL`, etc. | + +### Comprehensive and Corrected Code Example + +This example demonstrates the complete, correct flow: configuring the instance, setting the thread-specific configuration, and then processing a message. + +```typescript +import { + createArtInstance, + ArtInstanceConfig, + ThreadConfig, + CalculatorTool, + OpenAIAdapter, + GeminiAdapter +} from 'art-framework'; + +// --- 1. Configure the ART Instance --- +// Note: No API keys or secrets are present here. + +const artConfig: ArtInstanceConfig = { + storage: { + type: 'indexedDB', + dbName: 'MyCorrectChatDB' + }, + providers: { + availableProviders: [ + { name: 'openai', adapter: OpenAIAdapter }, + { name: 'gemini', adapter: GeminiAdapter } + ] + }, + tools: [new CalculatorTool()], + persona: { + name: 'ConfigExpert', + prompts: { + synthesis: 'You explain configurations clearly.' + } + }, + logger: { level: 'info' } +}; + + +// --- 2. Main Application Logic --- + +async function initializeAndRun() { + // Create the ART instance with the high-level configuration. + const art = await createArtInstance(artConfig); + console.log('ART Instance Initialized.'); + + // --- 3. Set Up a New Conversation Thread --- + const threadId = 'user-123-session-1'; + + // Create the thread-specific configuration. + // THIS is where you specify the provider, model, and API key. + const threadConfig: ThreadConfig = { + providerConfig: { + providerName: 'openai', // Must match a name from availableProviders + modelId: 'gpt-4o', + adapterOptions: { + apiKey: 'sk-your-real-openai-api-key', // Securely provide your API key here + temperature: 0.7 + } + }, + // Other thread settings + enabledTools: ['CalculatorTool'], + historyLimit: 20 + }; + + // Save this configuration for the new thread. + // This step is crucial and must be done before the first `process` call. + await art.stateManager.setThreadConfig(threadId, threadConfig); + console.log(`ThreadConfig set for threadId: ${threadId}`); + + // Now the ART instance is ready to process requests for this thread. + console.log('Sending first message...'); + const response = await art.process({ + query: 'What is 2 + 2?', + threadId: threadId + }); + + console.log('Final response:', response.response.content); +} + +initializeAndRun().catch(console.error); +``` + +### Creating the Instance + +Once you have your configuration object, creating the ART instance is a single asynchronous call: + +```typescript +import { createArtInstance } from 'art-framework'; + +async function initializeArt() { + try { + // Use the desired configuration + const art = await createArtInstance(basicBrowserConfig); + console.log('ART Instance created successfully!'); + + // Now you can use the 'art' object to process queries and interact with sockets. + // const response = await art.process({ query: 'Hello!', threadId: 'thread-1' }); + + } catch (error) { + console.error('Failed to initialize ART instance:', error); + } +} + +initializeArt(); +``` + +### `ArtInstance` + +The object returned by `createArtInstance`. The example in `index.ts` shows it has a `process` method to interact with the agent. It also provides access to all the core managers and systems: + +* `process`: The main function to send a query to the agent. +* `uiSystem`: Provides access to the UI sockets (`ConversationSocket`, `LLMStreamSocket`, etc.). +* `stateManager`: Manages thread-specific configuration and state. +* `conversationManager`: Manages the conversation history. +* `toolRegistry`: Manages the registration and retrieval of tools. +* `observationManager`: Manages the recording and retrieval of agent observations. +* `authManager`: Manages authentication strategies. + +```ts +const response = await art.process({ query: "Hello, world!" }); +``` + +This detailed understanding will allow me to write a much more comprehensive guide. + +## Building a UI + +The framework provides "sockets" for building user interfaces, accessible via the `uiSystem` property on the `ArtInstance`. + +* **`ConversationSocket`**: This is the primary way to get the conversation history. A chatbot UI would subscribe to this socket to display messages. It can be accessed via `art.uiSystem.getConversationSocket()`. +* **`ObservationSocket`**: This provides a stream of the agent's internal state, like tool calls. It's useful for debugging and showing the agent's "thought process". +* **`LLMStreamSocket`**: This is crucial for real-time UI updates. It streams `StreamEvent` objects, which can be `TOKEN`, `METADATA`, `ERROR`, or `END`. The `TOKEN` events can even be differentiated by `tokenType` to distinguish between the agent's internal "thinking" and the final user-facing response. This is perfect for a "thinking..." indicator in the UI. + +### Subscribing to Sockets + +The sockets have a `subscribe` method. It takes a callback function and returns an `unsubscribe` function. + +```ts +const art = await createArtInstance(config); + +const unsubscribe = art.uiSystem.getConversationSocket().subscribe( + (message: ConversationMessage) => { + console.log('New message:', message); + // Add the message to the UI + }, + undefined, // No filter + { threadId: 'my-conversation-thread' } +); + +// Later, to clean up: +// unsubscribe(); +``` + +## Next Steps for Learning + +1. ~~**Examine core interfaces**~~: (Done) I have a good understanding of `ArtInstance`, `ArtInstanceConfig`, `ConversationMessage`, `StreamEvent`, etc. +2. ~~**Understand `ConversationSocket`**~~: (Done) I know how to access it via `art.uiSystem.getConversationSocket()` and how to subscribe to it. +3. ~~**Investigate response streaming**~~: (Done) The `LLMStreamSocket` is the way to go for streaming responses. The `StreamEvent` provides rich information. +4. **Simulate Project Setup**: Plan how to set up a simple web project (e.g., using Vite or just plain HTML/JS) that would import `art-framework` and use it. +5. **Write a Basic Chatbot Implementation**: Based on the project setup, write the TypeScript code for a simple chatbot that: + * Initializes `art-framework`. + * Creates a new conversation thread. + * Subscribes to the `ConversationSocket` and `LLMStreamSocket`. + * Has an input field to send user messages. + * Displays the conversation history and streaming response. +6. **Flesh out the guide**: Based on the chatbot implementation, write a step-by-step guide explaining how to build a chatbot from scratch using `art-framework`. diff --git a/docs/llm-full.txt b/docs/llm-full.txt new file mode 100755 index 0000000..c60a76f --- /dev/null +++ b/docs/llm-full.txt @@ -0,0 +1,1206 @@ +# The Definitive Developer Guide to the ART Framework + +This document provides a definitive, highly detailed overview of the ART (Agentic Runtime) Framework. It is designed to be the single source of truth for developers building with ART, covering the framework's architecture, core concepts, API reference, and practical, up-to-date usage examples. + +## 1. Introduction & Core Value Proposition + +The ART Framework is a modular, extensible, and browser-first TypeScript library for building advanced AI agents. It provides a robust, structured foundation for creating agentic systems that can reason, use tools, and interact with users in real-time. + +**Key Features at a Glance:** +* **Secure & Flexible LLM Configuration:** A two-tiered system separates instance-level provider declarations from thread-level configuration, keeping API keys secure and enabling multi-provider, multi-model conversations from a single instance. +* **Advanced Agent Orchestration:** A built-in Plan-Execute-Synthesize (`PESAgent`) core provides robust, multi-step reasoning for complex tasks. +* **Extensible Tool System:** Equip agents with custom capabilities to interact with any API or data source through a clear, schema-driven interface. +* **Dynamic Tool Loading (MCP):** Discover and use tools from remote servers at runtime via the Model Context Protocol. +* **Agent-to-Agent (A2A) Communication:** Build complex systems where agents can delegate tasks to specialized peers. +* **Pluggable Persistence:** Store agent memory and conversation history in-browser (`IndexedDB`), in the cloud (`Supabase`), or using a custom storage adapter. +* **First-Class Observability:** Deeply inspect an agent's thought process through a structured `Observation` system. +* **Real-time UI Integration:** A dedicated `UISystem` with event sockets for streaming tokens, thoughts, and messages to any front-end framework. +* **Layered Persona Management:** A powerful, three-level system (Instance, Thread, Call) for customizing system prompts and agent behavior. + +## 2. Core Concepts & Design Philosophy + +* **Separation of Concerns:** Each component has a single, well-defined responsibility. The `StateManager` handles state, the `ToolSystem` handles tools, and `ProviderAdapters` handle LLM communication. This makes the system predictable and easy to debug. +* **Instance vs. Thread:** The `ArtInstance` is the long-lived application object that defines *potential capabilities* (available tools, providers). A `Thread` is a single conversation with a *specific configuration* (the exact model, API key, and enabled tools). This is the cornerstone of the framework's security and flexibility. +* **Standardized Interfaces:** The framework relies on a set of core interfaces (`IAgentCore`, `IToolExecutor`, `StorageAdapter`, `ProviderAdapter`). This allows developers to replace any part of the system with a custom implementation without breaking the rest of the framework. +* **Explicit State Management:** Configuration and state are managed through explicit API calls (e.g., `art.stateManager.setThreadConfig`). This creates a clear, predictable data flow and prevents race conditions. +* **Observability by Default:** Every significant action an agent takes—forming a plan, calling a tool, receiving an LLM response—is recorded as a structured `Observation`. This is a core feature for debugging, analysis, and building transparent AI systems. + +## 3. High-Level Architecture & Data Flow + +A typical user request flows through the system as follows: + +1. **Entry Point:** A user query enters the system via `art.process()`. +2. **Agent Core (`PESAgent`):** The `PESAgent` takes control. +3. **Context Loading:** It uses the `StateManager` to load the `ThreadContext` (the specific `ThreadConfig` and `AgentState`) for the given `threadId`. +4. **Planning:** The agent constructs a prompt (using history from `ConversationManager` and available tools from `ToolRegistry`) and sends it to the `ReasoningEngine`. The LLM returns a plan, which the `OutputParser` extracts into structured data. These events are recorded via the `ObservationManager`. +5. **Execution:** The `ToolSystem` is invoked with the parsed tool calls. It validates each call against the `ToolRegistry` and the thread's `enabledTools`, then executes them. Results are recorded as `Observations`. +6. **Synthesis:** The agent constructs a final prompt containing the original query and tool results, sending it to the `ReasoningEngine`. The LLM generates the final, user-facing response. +7. **Finalization:** The final user and AI messages are saved via the `ConversationManager`, and any modified `AgentState` is persisted. The final response is returned. +8. **Real-time Events:** Throughout this process, the `UISystem`'s sockets (`LLMStreamSocket`, `ObservationSocket`, etc.) emit events to any subscribed UI components. + +```mermaid +flowchart TD + User([User Query]) --> ArtInstance["art.process(query, threadId)"] + ArtInstance --> AgentCore["Agent Core (PESAgent)"] + + subgraph "1. Context Loading" + AgentCore -- "Loads ThreadContext" --> StateManager["StateManager"] + StateManager -- "Gets data from" --> Repositories["Repositories\n(State, Conversation)"] + Repositories -- "Read/Write" --> StorageAdapter["StorageAdapter\n(IndexedDB, etc.)"] + end + + subgraph "2. Planning & Reasoning" + AgentCore -- "Sends planning prompt" --> ReasoningEngine["ReasoningEngine"] + ReasoningEngine -- "Uses" --> ProviderAdapter["ProviderAdapter\n(e.g., OpenAIAdapter)"] + ProviderAdapter -- "Calls" --> ExternalLLM["External LLM API"] + ExternalLLM -- "Streams response" --> ProviderAdapter + ProviderAdapter -- "Yields StreamEvents" --> ReasoningEngine + ReasoningEngine -- "Returns full text" --> OutputParser["OutputParser"] + OutputParser -- "Extracts tool calls" --> AgentCore + end + + subgraph "3. Tool Execution" + AgentCore -- "Executes tool calls via" --> ToolSystem["ToolSystem"] + ToolSystem -- "Validates against" --> ToolRegistry["ToolRegistry"] + ToolSystem -- "Executes" --> IToolExecutor["IToolExecutor\n(e.g., CalculatorTool)"] + IToolExecutor -- "Returns ToolResult" --> ToolSystem + end + + subgraph "4. Synthesis" + AgentCore -- "Sends synthesis prompt\n(with tool results)" --> ReasoningEngine + end + + subgraph "5. Finalization & UI" + AgentCore -- "Saves messages" --> ConversationManager["ConversationManager"] + AgentCore -- "Returns AgentFinalResponse" --> ArtInstance + ReasoningEngine -- "Notifies UI of tokens" --> LLMStreamSocket["LLMStreamSocket"] + AgentCore -- "Records events via" --> ObservationManager["ObservationManager"] + ObservationManager -- "Notifies UI of thoughts" --> ObservationSocket["ObservationSocket"] + end +``` + +## 4. How-To Guides (Practical Scenarios) + +### 4.1. Building a Persistent Chatbot (The Right Way) +**Goal:** Create a conversational agent that remembers history across browser sessions. + +```typescript +import { + createArtInstance, + ArtInstanceConfig, + ThreadConfig, + OpenAIAdapter +} from 'art-framework'; + +// 1. Define the INSTANCE configuration. No secrets here. +const artConfig: ArtInstanceConfig = { + storage: { + type: 'indexedDB', + dbName: 'MyChatAppDB', + dbVersion: 1, + }, + providers: { + availableProviders: [ + { name: 'openai', adapter: OpenAIAdapter }, + ], + }, +}; + +// 2. Create the ART instance once in your application. +const art = await createArtInstance(artConfig); + +// 3. In your chat component, manage the conversation lifecycle. +async function startOrContinueChat(threadId: string, query: string) { + // Check if this is a new conversation. + const context = await art.stateManager.loadThreadContext(threadId); + + if (!context.config) { + console.log(`No config found for thread ${threadId}. Setting it up now.`); + // This is the first message. Set the THREAD configuration. + const threadConfig: ThreadConfig = { + providerConfig: { + providerName: 'openai', + modelId: 'gpt-4o', + adapterOptions: { + apiKey: 'sk-your-secret-openai-key', // Provide the key here + }, + }, + enabledTools: [], // No tools for this simple chat + historyLimit: 20, + }; + // CRITICAL: Save the configuration before processing. + await art.stateManager.setThreadConfig(threadId, threadConfig); + } + + // 4. Process the query. The framework will now find the saved config. + const result = await art.process({ query, threadId }); + console.log('Agent Response:', result.response.content); +} +``` + +### 4.2. Creating and Using a Custom Tool +**Goal:** Give the agent the ability to fetch real-time weather data. + +**1. Define the Tool (`WeatherTool.ts`)** +```typescript +import { IToolExecutor, ToolSchema, ToolResult, ExecutionContext } from 'art-framework'; + +export class WeatherTool implements IToolExecutor { + public readonly schema: ToolSchema = { + name: 'get_weather', + description: 'Gets the current weather for a specified location.', + inputSchema: { + type: 'object', + properties: { location: { type: 'string', description: 'The city, e.g., "San Francisco"' } }, + required: ['location'], + }, + }; + + async execute(input: { location: string }, context: ExecutionContext): Promise { + try { + // In a real app, call a weather API. + const temperature = Math.floor(Math.random() * 30) + 50; + return { + callId: context.traceId, + toolName: this.schema.name, + status: 'success', + output: { temperature, location: input.location, conditions: "Sunny" }, + }; + } catch (error) { + return { + callId: context.traceId, + toolName: this.schema.name, + status: 'error', + error: error instanceof Error ? error.message : 'Unknown error', + }; + } + } +} +``` + +**2. Register and Enable the Tool** +```typescript +import { WeatherTool } from './WeatherTool'; +import { OpenAIAdapter } from 'art-framework'; + +// In your main setup file: +const artConfig: ArtInstanceConfig = { + storage: { type: 'memory' }, + providers: { availableProviders: [{ name: 'openai', adapter: OpenAIAdapter }] }, + tools: [new WeatherTool()], // REGISTER the tool instance +}; +const art = await createArtInstance(artConfig); + +// In your application logic for a specific chat: +const threadId = 'weather-thread-1'; +const threadConfig: ThreadConfig = { + providerConfig: { + providerName: 'openai', + modelId: 'gpt-4o', + adapterOptions: { apiKey: 'sk-your-key' }, + }, + enabledTools: ['get_weather'], // ENABLE the tool for this thread by its schema name + historyLimit: 10, +}; +await art.stateManager.setThreadConfig(threadId, threadConfig); + +// Now the agent can use the tool. +await art.process({ query: "What's the weather like in Boston?", threadId }); +``` + +### 4.3. Integrating with a UI for Real-Time Updates +**Goal:** Display the agent's streaming response and thought process in a web UI. + +```typescript +// In your front-end code (e.g., a React component) +import { art } from './artInstance'; // Assuming you've initialized ART elsewhere + +function ChatComponent({ threadId }) { + const [streamingResponse, setStreamingResponse] = useState(''); + const [observations, setObservations] = useState([]); + + useEffect(() => { + // Subscribe to LLM token stream for the final answer + const unsubscribeStream = art.uiSystem.getLLMStreamSocket().subscribe( + (event) => { + if (event.type === 'TOKEN' && event.tokenType === 'RESPONSE') { + setStreamingResponse((prev) => prev + event.payload); + } + if (event.type === 'END') { + // Stream finished, save the full message to your state + setStreamingResponse(''); // Reset for next message + } + }, + null, // No filter + { threadId } // Only listen for events on this thread + ); + + // Subscribe to observations to show the agent's "thoughts" + const unsubscribeObs = art.uiSystem.getObservationSocket().subscribe( + (observation) => { + setObservations((prev) => [...prev, observation]); + }, + null, + { threadId } + ); + + return () => { + unsubscribeStream(); + unsubscribeObs(); + }; + }, [threadId]); + + // ... render your UI using streamingResponse and observations ... +} +``` + +## 5. Advanced Topics + +### 5.1. Agent-to-Agent (A2A) Communication +The A2A system allows you to build sophisticated, multi-agent workflows. +* **Concept:** An agent can act as a "manager" that receives a complex task. It can then use the `AgentDiscoveryService` to find "specialist" agents. The manager then uses the `TaskDelegationService` to send a structured `A2ATask` to the specialist. It monitors the task's progress and uses the result in its final synthesis. +* **Use Case:** A research agent receives a query "Summarize recent AI trends and create a presentation." It delegates the "summarize trends" task to a web-research agent and the "create presentation" task to a document-generation agent, then combines the results. + +### 5.2. Model Context Protocol (MCP) +MCP allows your agent to dynamically expand its capabilities without requiring a redeployment. +* **Concept:** The `McpManager` connects to MCP servers, fetches a manifest of available tools, and creates local `McpProxyTool` instances. When the agent uses one of these tools, the proxy handles the secure API call to the remote server, making the process seamless. +* **Use Case:** A company maintains a central MCP server with proprietary tools (e.g., `query_internal_database`). Any ART agent, with the right configuration, can connect to this server and instantly gain access to these tools. + +## 6. Comprehensive API Reference + +#### **Core Factory & Instance** +* **`createArtInstance(config: ArtInstanceConfig)`**: **(Function)** The primary entry point. Initializes all managers and systems. Returns a ready-to-use `ArtInstance`. +* **`ArtInstance`**: **(Interface)** The main object. Provides the `process()` method and accessors to all major public systems (`uiSystem`, `stateManager`, `toolRegistry`). + +#### **Agent Orchestration & Reasoning** +* **`IAgentCore` / `PESAgent`**: **(Interface/Class)** The agent's central reasoning logic. `PESAgent` is the default implementation that orchestrates the Plan-Execute-Synthesize cycle. +* **`ReasoningEngine`**: **(Class)** The service that directly interacts with LLM providers via adapters. +* **`ProviderAdapter`**: **(Interface)** The contract for a specific LLM provider (e.g., `OpenAIAdapter`). Translates between ART's standard format and the provider's API. +* **`ProviderManager`**: **(Class)** Manages the lifecycle and pooling of `ProviderAdapter` instances. +* **`StreamEvent`**: **(Interface)** A standardized object representing a chunk of data from an LLM stream (`TOKEN`, `METADATA`, `ERROR`, `END`). + +#### **Tools** +* **`IToolExecutor`**: **(Interface)** The contract that all tools must implement, requiring a `schema` and an `execute` method. +* **`ToolSchema`**: **(Interface)** The JSON Schema definition of a tool that is shown to the LLM. +* **`ToolRegistry`**: **(Class)** A service that holds all registered `IToolExecutor` instances. +* **`ToolSystem`**: **(Class)** The orchestrator for tool execution, handling validation and invocation. + +#### **State & Persistence** +* **`StorageAdapter`**: **(Interface)** The low-level contract for a key-value persistence layer (e.g., `IndexedDBStorageAdapter`). +* **`StateManager`**: **(Class)** The primary public interface for managing `ThreadConfig` and `AgentState`. This is a critical component for developers. +* **`ConversationManager`**: **(Class)** The primary public interface for managing `ConversationMessage` history. +* **`ThreadConfig`**: **(Interface)** The configuration for a single conversation thread (provider, model, API key, enabled tools). +* **`AgentState`**: **(Interface)** A flexible data structure for an agent to store its own persistent memory for a thread. + +#### **Observability & UI** +* **`Observation`**: **(Interface)** A structured log entry representing a significant event in the agent's lifecycle (e.g., `PLAN`, `TOOL_CALL`). +* **`ObservationManager`**: **(Class)** The service used by the agent to record `Observation`s. +* **`UISystem`**: **(Class)** The entry point to access the various real-time event sockets. +* **`LLMStreamSocket` / `ObservationSocket` / `ConversationSocket`**: **(Classes)** Typed event emitters that allow external code (like a UI) to subscribe to framework events with filtering. + +## 7. Glossary of Terms + +* **A2A (Agent-to-Agent):** A protocol and set of services enabling agents to delegate tasks to one another. +* **Agent Core:** The central component that orchestrates the agent's reasoning and action loop (e.g., `PESAgent`). +* **MCP (Model Context Protocol):** A standard for servers to expose tools that can be dynamically discovered and used by agents. +* **Observation:** A structured record of a significant internal event during an agent's execution, used for debugging and observability. +* **PES (Plan-Execute-Synthesize):** A robust agent orchestration pattern where the agent first plans its steps, then executes necessary actions, and finally synthesizes a final response. +* **Provider Adapter:** A component that translates between ART's standard format and the specific API format of an LLM provider. +* **Thread:** A single, continuous conversation, identified by a `threadId`. It has its own associated history, configuration, and state. + +Of course. Based on your detailed learning notes, here is a comprehensive and well-structured guide to the ART Framework. + +# The Definitive Guide to the ART Framework + +Welcome to the comprehensive guide for building intelligent, web-based chatbots and agents with the ART Framework. This document covers the core concepts, features, and step-by-step instructions needed to leverage the full power of the framework, from basic setup to advanced features like dynamic tools and agent-to-agent communication. + +## Table of Contents + +1. [Introduction: What is the ART Framework?](#1-introduction-what-is-the-art-framework) +2. [Core Concepts](#2-core-concepts) +3. [Getting Started: Your First Chatbot](#3-getting-started-your-first-chatbot) +4. [Definitive Guide to Provider Configuration](#4-definitive-guide-to-provider-configuration) +5. [Definitive Guide to Storage](#5-definitive-guide-to-storage) +6. [Definitive Guide to State and Configuration Management](#6-definitive-guide-to-state-and-configuration-management) +7. [Definitive Guide to Tools and the Tool System](#7-definitive-guide-to-tools-and-the-tool-system) +8. [Definitive Guide to System Prompt Customization](#8-definitive-guide-to-system-prompt-customization) +9. [Building a User Interface with Sockets](#9-building-a-user-interface-with-sockets) +10. [Advanced Features](#10-advanced-features) + * [MCP (Model Context Protocol)](#mcp-model-context-protocol) + * [A2A (Agent-to-Agent Communication)](#a2a-agent-to-agent-communication) +11. [The `ArtInstance` Object: API Reference](#11-the-artinstance-object-api-reference) + +--- + +## 1. Introduction: What is the ART Framework? + +The ART (Agentic Reactive Triad) Framework is a powerful, client-focused library for building sophisticated conversational agents. It provides a robust, extensible architecture that handles the complexities of state management, conversation history, tool usage, and LLM provider integration, allowing you to focus on creating unique and capable agents. + +**Key Features:** + +* **Stateful Conversations**: Persist conversation history and agent memory across sessions using flexible storage adapters (In-Memory, IndexedDB, Supabase, or custom). +* **Extensible Tool System**: Empower your agent to interact with external APIs and custom logic by creating and registering tools. +* **Multi-Provider Support**: Seamlessly switch between different LLM providers (like OpenAI, Gemini, Anthropic) on a per-conversation basis. +* **Secure Configuration**: A two-tiered configuration system keeps sensitive API keys out of your main instance setup and securely scoped to individual conversation threads. +* **Reactive UI Layer**: A dedicated UI system with "sockets" makes it easy to build real-time, streaming user interfaces. +* **Advanced Agent Capabilities**: Built-in support for dynamic tool discovery (MCP) and agent-to-agent communication (A2A) for creating complex, multi-agent systems. + +## 2. Core Concepts + +Understanding these core concepts is key to effectively using the framework. + +* **`ArtInstance`**: The main object and entry point to the framework. It holds all the core services like the `StateManager`, `ToolRegistry`, and `UISystem`. You create it once with a high-level configuration. +* **`ArtInstanceConfig`**: The configuration object passed to `createArtInstance`. It defines the *available* capabilities of your instance, such as which storage adapters can be used, which LLM providers are available, and which tools are registered. **It does not contain secrets like API keys.** +* **`Thread`**: A single conversation or session, identified by a unique `threadId`. Each thread has its own isolated state, configuration, and conversation history. +* **`ThreadConfig`**: The specific configuration for a single thread. This is where you define which LLM provider and model to use, provide the API key, and specify which of the registered tools are *enabled* for this conversation. +* **`AgentState`**: The agent's "memory" for a specific thread. It's a flexible object where the agent can store summaries, user preferences, or any other data it needs to maintain context across turns. +* **`Tool`**: A class that implements the `IToolExecutor` interface, allowing the agent to perform actions. Each tool has a `schema` that describes its function to the LLM and an `execute` method that contains the implementation. + +## 3. Getting Started: Your First Chatbot + +This example demonstrates the complete, correct flow: configuring the instance, setting up a new conversation thread, and processing a message. + +**Step 1: Install the Framework** + +```bash +npm install art-framework +``` + +**Step 2: Write the Code** + +```typescript +import { + createArtInstance, + ArtInstanceConfig, + ThreadConfig, + CalculatorTool, + OpenAIAdapter, + GeminiAdapter +} from 'art-framework'; + +// --- 1. Define the Instance-Level Configuration --- +// Note: No API keys or secrets are present here. This config defines +// what is *possible* for this ART instance. + +const artConfig: ArtInstanceConfig = { + storage: { + type: 'memory' // Use in-memory storage for this simple example + }, + providers: { + // Make OpenAI and Gemini adapters available for use + availableProviders: [ + { name: 'openai', adapter: OpenAIAdapter }, + { name: 'gemini', adapter: GeminiAdapter } + ] + }, + // Register a built-in CalculatorTool + tools: [new CalculatorTool()], + logger: { level: 'info' } +}; + + +// --- 2. Main Application Logic --- + +async function initializeAndRun() { + // Create the ART instance with the high-level configuration. + const art = await createArtInstance(artConfig); + console.log('ART Instance Initialized.'); + + // --- 3. Set Up a New Conversation Thread --- + const threadId = 'user-123-session-1'; + + // Create the thread-specific configuration. + // THIS is where you specify the provider, model, and API key. + const threadConfig: ThreadConfig = { + providerConfig: { + providerName: 'openai', // Must match a name from availableProviders + modelId: 'gpt-4o', + adapterOptions: { + apiKey: 'sk-your-real-openai-api-key', // Securely provide your API key here + temperature: 0.7 + } + }, + enabledTools: ['CalculatorTool'], // Enable the tool for this thread + historyLimit: 20 + }; + + // Save this configuration for the new thread. + // This step is crucial and must be done before the first `process` call. + await art.stateManager.setThreadConfig(threadId, threadConfig); + console.log(`ThreadConfig set for threadId: ${threadId}`); + + // --- 4. Process a User Query --- + console.log('Sending first message...'); + const response = await art.process({ + query: 'What is 2 + 2?', + threadId: threadId + }); + + console.log('Final response:', response.response.content); +} + +initializeAndRun().catch(console.error); +``` + +## 4. Definitive Guide to Provider Configuration + +Provider configuration is a secure, two-part process. + +1. **Instance-Level Declaration (`ArtInstanceConfig`)**: You declare all provider adapters your application *might* use. This registers the adapter classes with the framework but includes no secrets. +2. **Thread-Level Configuration (`ThreadConfig`)**: For each conversation, you provide the specific details: which provider to use, what model, the API key, and other runtime parameters. + +### `ArtInstanceConfig.providers` (`ProviderManagerConfig`) + +| Property | Type | Description | +| :--- | :--- | :--- | +| `availableProviders` | `Array` | A required array of `AvailableProviderEntry` objects. | +| `maxParallelApiInstancesPerProvider` | `Number` | Optional. Max concurrent active instances per API-based provider. Defaults to `5`. | +| `apiInstanceIdleTimeoutSeconds` | `Number` | Optional. Time in seconds an idle API adapter can exist before being removed from memory. Defaults to `300`. | + +**`AvailableProviderEntry` Object** + +| Property | Type | Description | +| :--- | :--- | :--- | +| `name` | `String` | A unique key for the provider (e.g., `'openai'`). This name is used in `ThreadConfig`. | +| `adapter` | `Class` | The actual adapter class (e.g., `OpenAIAdapter`). | +| `isLocal` | `Boolean` | Optional. Set to `true` for local providers (like Ollama). Defaults to `false`. | + +### `ThreadConfig.providerConfig` (`RuntimeProviderConfig`) + +This object is set on a per-thread basis to configure the specific LLM to use. + +| Property | Type | Description | +| :--- | :--- | :--- | +| `providerName` | `String` | Required. The name of the provider to use. Must match a `name` from `availableProviders`. | +| `modelId` | `String` | Required. The specific model identifier (e.g., `'gpt-4o'`). | +| `adapterOptions` | `Object` | Required. An object containing provider-specific options. **This is where the API key goes.** | + +## 5. Definitive Guide to Storage + +The `storage` property in `ArtInstanceConfig` is the foundation for your agent's memory. + +### Built-in Storage Adapters + +#### `InMemoryStorageAdapter` +Keeps all data in memory. Fast and perfect for testing, but all data is lost when the session ends. + +* **`type`**: `'memory'` +* **Example**: `storage: { type: 'memory' }` + +#### `IndexedDBStorageAdapter` +The recommended adapter for web browsers, providing persistent client-side storage. + +* **`type`**: `'indexedDB'` +* **Options**: + +| Property | Type | Description | +| :--- | :--- | :--- | +| `dbName` | `String` | Optional. The name of the IndexedDB database. Defaults to `'ART_Framework_DB'`. | +| `dbVersion` | `Number` | Optional. The version of your database schema. **Must** be incremented if you change `objectStores`. Defaults to `1`. | +| `objectStores` | `Array` | Optional. An array of custom object store names. Core stores are created automatically. | + +* **Example**: + ```typescript + storage: { + type: 'indexedDB', + dbName: 'MyAwesomeChatAppDB', + dbVersion: 2, + objectStores: ['user_profiles'] + } + ``` + +#### `SupabaseStorageAdapter` +Connects to a Supabase (PostgreSQL) project, ideal for applications requiring a centralized, cloud-based database. + +* **`type`**: `'supabase'` +* **Prerequisites**: You must run the provided SQL scripts in your Supabase project to create the necessary tables (`conversations`, `observations`, `state`, `a2a_tasks`). +* **Options**: + +| Property | Type | Description | +| :--- | :--- | :--- | +| `url` | `String` | Required. The URL of your Supabase project. | +| `apiKey` | `String` | Required. Your Supabase `anon` or `service_role` key. | +| `schema` | `String` | Optional. The database schema to use. Defaults to `'public'`. | +| `tables` | `Object` | Optional. Allows you to override the default table names. | +| `client` | `SupabaseClient` | Optional. Pass a pre-initialized Supabase client instance. | + +* **Example**: + ```typescript + storage: { + type: 'supabase', + url: 'https://your-project-ref.supabase.co', + apiKey: 'your-supabase-service-role-key' + } + ``` + +### Custom Storage Adapter +For advanced use cases, you can create your own adapter by implementing the `StorageAdapter` interface and passing an instance of your class to the `storage` property. + +## 6. Definitive Guide to State and Configuration Management + +State management is centered around the `StateManager`, which handles all configuration (`ThreadConfig`) and persistent state (`AgentState`) for each conversation. You can access it via `art.stateManager`. + +### `stateSavingStrategy` +This option in `ArtInstanceConfig` determines how `AgentState` is persisted. + +* **`'explicit'` (Default)**: State is only saved when you explicitly call `art.stateManager.setAgentState()`. This gives you full control. +* **`'implicit'`**: The `StateManager` automatically saves the `AgentState` at the end of a processing cycle if it has been modified. + +### `art.stateManager` Methods + +| Method | Description | +| :--- | :--- | +| `setThreadConfig(threadId, config)` | Saves the initial `ThreadConfig` for a new conversation. **Must be called before the first `process()` call for a new thread.** | +| `loadThreadContext(threadId)` | Loads the `ThreadConfig` and `AgentState` for a given thread. Usually handled internally. | +| `setAgentState(threadId, state)` | Explicitly saves a new `AgentState` for the thread. | +| `enableToolsForThread(threadId, toolNames)` | Dynamically adds tool names to the `enabledTools` list for an existing thread. | +| `disableToolsForThread(threadId, toolNames)` | Dynamically removes tool names from the `enabledTools` list. | +| `getEnabledToolsForThread(threadId)` | Returns a `Promise` of the currently enabled tools for the thread. | + +### Practical Example: Starting a New Conversation + +```typescript +import { ThreadConfig } from 'art-framework'; + +const art = await createArtInstance(artConfig); +const newThreadId = 'user-abc-chat-1'; + +const initialThreadConfig: ThreadConfig = { + providerConfig: { + providerName: 'openai', + modelId: 'gpt-4o', + adapterOptions: { apiKey: 'sk-your-secret-key' } + }, + enabledTools: ['CalculatorTool'], + historyLimit: 50 +}; + +// Save the configuration for the new thread +await art.stateManager.setThreadConfig(newThreadId, initialThreadConfig); + +// Now you can safely call process +const response = await art.process({ + query: 'Hello, world!', + threadId: newThreadId +}); +``` + +## 7. Definitive Guide to Tools and the Tool System + +Tools allow agents to interact with external systems. The framework provides a structured way to define, register, and execute them. + +### Creating a Custom Tool + +**Step 1: Implement the `IToolExecutor` Interface** +Create a class with a `schema` property and an `execute` method. The `schema` is critical, as it describes the tool's function and parameters to the LLM. + +```typescript +// src/tools/WeatherTool.ts +import { IToolExecutor, ToolSchema, ExecutionContext, ToolResult } from 'art-framework'; + +export class WeatherTool implements IToolExecutor { + readonly schema: ToolSchema = { + name: "get_weather_forecast", + description: "Get the current weather forecast for a specific location.", + inputSchema: { + type: "object", + properties: { + location: { + type: "string", + description: "The city and state, e.g., San Francisco, CA", + }, + }, + required: ["location"], + }, + }; + + async execute(input: { location: string }, context: ExecutionContext): Promise { + try { + // In a real app, call a weather API here. + const forecast = `The weather in ${input.location} is 72 degrees and sunny.`; + return { + callId: context.traceId || 'weather-call', + toolName: this.schema.name, + status: 'success', + output: { forecast }, + }; + } catch (error: any) { + return { + callId: context.traceId || 'weather-call', + toolName: this.schema.name, + status: 'error', + error: `Failed to get weather: ${error.message}`, + }; + } + } +} +``` + +**Step 2: Register the Tool** +In your `ArtInstanceConfig`, provide an instance of your tool in the `tools` array. + +```typescript +import { WeatherTool } from './tools/WeatherTool'; + +const artConfig: ArtInstanceConfig = { + // ... + tools: [new WeatherTool(), new CalculatorTool()], + // ... +}; +``` + +**Step 3: Enable the Tool for a Conversation** +In the `ThreadConfig`, add the tool's name (from its schema) to the `enabledTools` array. + +```typescript +const initialThreadConfig: ThreadConfig = { + // ... + enabledTools: ['get_weather_forecast', 'CalculatorTool'], + // ... +}; +await art.stateManager.setThreadConfig(threadId, initialThreadConfig); +``` + +## 8. Definitive Guide to System Prompt Customization + +The framework uses a powerful, multi-layered system to customize the agent's persona and instructions. The final system prompt is built by merging configurations from three levels: **Instance -> Thread -> Call**. + +### Configuration Levels + +1. **Instance-Level**: Set in `ArtInstanceConfig.persona`. This is the base persona for all conversations. +2. **Thread-Level**: Set in `ThreadConfig.persona`. Overrides the instance persona for a specific conversation. +3. **Call-Level**: Passed in the `ArtConfig` object to `art.run()` or `art.process()`. A one-time override for a single interaction. + +### The `SystemPromptOverride` Object + +For fine-grained control, you can use an object instead of a simple string. + +| Property | Type | Description | +| :--- | :--- | :--- | +| `content` | `string` | The raw text of the system prompt. | +| `strategy` | `'append' \| 'prepend'` | Optional. How to merge with the previous layer's prompt. Defaults to `'append'`. | +| `tag` | `string` | Advanced. The name of a pre-defined prompt template. | +| `variables` | `Record` | Advanced. Variables to inject into a `tag`-based template. | + +### Advanced Usage: Templating with `tags` + +You can create a registry of reusable prompt templates in `ArtInstanceConfig.systemPrompts`. + +```typescript +// In your ArtInstanceConfig +const art = await createArtInstance({ + // ... + persona: "You are a helpful assistant.", + systemPrompts: { + specs: { + 'expert-coder': { + template: "You are an expert programmer in {{language}}.", + mergeStrategy: 'prepend' + } + } + } +}); + +// Use the tag at the call level +await art.process({ + threadId: 'coding-chat-456', + query: 'Show me how to sort an array in TypeScript.', + persona: { + tag: 'expert-coder', + variables: { language: 'TypeScript' } + } +}); +``` + +## 9. Building a User Interface with Sockets + +The framework provides "sockets" for building reactive UIs, accessible via `art.uiSystem`. + +* **`ConversationSocket`**: Provides the full conversation history. Subscribe to it to display messages. +* **`ObservationSocket`**: Streams the agent's internal "thought process," such as tool calls. Excellent for debugging or showing agent activity. +* **`LLMStreamSocket`**: Streams the LLM's response token by token. This is essential for creating a "typing" effect and real-time UI updates. It emits `StreamEvent` objects (`TOKEN`, `METADATA`, `ERROR`, `END`). + +### Subscribing to Sockets + +The sockets have a `subscribe` method that takes a callback and returns an `unsubscribe` function. + +```typescript +const art = await createArtInstance(config); +const threadId = 'my-conversation-thread'; + +// Subscribe to the conversation history +const unsubConversation = art.uiSystem.getConversationSocket().subscribe( + (message) => { + // Add the message to your UI's message list + console.log('New message:', message); + }, + undefined, // No filter + { threadId } +); + +// Subscribe to the LLM stream for real-time updates +let currentResponse = ''; +const unsubStream = art.uiSystem.getLLMStreamSocket().subscribe( + (event) => { + if (event.type === 'TOKEN' && event.tokenType === 'RESPONSE') { + currentResponse += event.payload; + // Update the UI with the streaming response + } else if (event.type === 'END') { + console.log('Stream finished.'); + currentResponse = ''; // Reset for the next message + } + }, + undefined, + { threadId } +); + +// To clean up later (e.g., when a component unmounts): +// unsubConversation(); +// unsubStream(); +``` + +## 10. Advanced Features + +### MCP (Model Context Protocol) + +MCP allows an agent to dynamically discover and use tools from external servers without needing to bundle the tool logic in your application. + +* **How it works**: The `McpManager` discovers tools from a central directory, creating local `McpProxyTool` instances. When the agent uses one of these tools, the proxy handles the communication with the remote MCP server. +* **How to use**: Simply enable it in your `ArtInstanceConfig`. The framework handles the rest. + +```typescript +const artConfig: ArtInstanceConfig = { + // ... + mcpConfig: { + enabled: true, + // Optional: URL of a custom discovery service + // discoveryEndpoint: 'https://my-mcp-directory.com/api' + }, + // ... +}; +``` +Discovered tools are then enabled for a thread just like any other tool. + +### A2A (Agent-to-Agent Communication) + +A2A enables an agent to delegate complex or specialized tasks to other independent agents. + +* **How it works**: The agent autonomously uses the `AgentDiscoveryService` to find suitable agents from a directory and the `TaskDelegationService` to assign the work. The developer's role is to enable and configure the system. +* **How to use**: Provide the `a2aConfig` in your `ArtInstanceConfig`. + +```typescript +const artConfig: ArtInstanceConfig = { + // ... + a2aConfig: { + discoveryEndpoint: 'https://api.zyntopia.com/a2a/discover', + // A public URL where your app can receive status updates + callbackUrl: 'https://my-app.com/api/a2a-callback' + }, + // ... +}; +``` + +## 11. The `ArtInstance` Object: API Reference + +The `art` object returned by `createArtInstance` is your main gateway to the framework's capabilities. + +| Property | Description | +| :--- | :--- | +| `process` | The main function to send a query to the agent and receive a response. | +| `uiSystem` | Provides access to the UI sockets (`ConversationSocket`, `LLMStreamSocket`, etc.). | +| `stateManager` | Manages thread-specific configuration (`ThreadConfig`) and agent memory (`AgentState`). | +| `conversationManager` | Manages the storage and retrieval of conversation history. | +| `toolRegistry` | Manages the registration and retrieval of all available tools. | +| `observationManager` | Manages the recording and retrieval of agent observations (its internal monologue). | +| `authManager` | Manages authentication strategies (e.g., OAuth) for tools that require it. | + +# How to Connect Your UI to the ART Framework + +This guide provides a comprehensive walkthrough for developers on how to use the ART Framework's public UI System API to build reactive and real-time user interfaces. You will learn how to access the UI sockets, subscribe to events, and fetch historical data to create a rich user experience. + +## Prerequisites + +Before you begin, you must complete two essential steps: + +1. **Create an `ArtInstance`**: This is the main entry point to the framework. +2. **Set the `ThreadConfig` for a conversation**: You **must** configure each conversation thread (e.g., set the provider, model, API key, and enabled tools) *before* you can process messages or listen for events on that thread. + +```javascript +import { createArtInstance, ThreadConfig } from 'art-framework'; +import { artConfig } from './art.config.js'; // Your high-level instance configuration + +let art; +const threadId = 'user-123-session-1'; // A unique ID for the conversation + +async function initialize() { + art = await createArtInstance(artConfig); + + // Define and set the configuration for the conversation thread + const initialThreadConfig: ThreadConfig = { + providerConfig: { + providerName: 'openai', + modelId: 'gpt-4o', + adapterOptions: { + apiKey: 'sk-your-real-openai-api-key' // Securely provide your API key + } + }, + enabledTools: ['CalculatorTool'], + historyLimit: 50 + }; + + await art.stateManager.setThreadConfig(threadId, initialThreadConfig); + + // Now you are ready to connect your UI for this specific threadId +} + +initialize(); +``` + +## 1. Accessing the UI System + +The entry point to all UI-related functionality is the `uiSystem` object, which is a property of your `ArtInstance`. + +```javascript +const uiSystem = art.uiSystem; +``` + +From this `uiSystem` object, you can get access to the individual sockets. + +## 2. Understanding Sockets + +The UI System is built on a **publish-subscribe** model. It exposes four specialized **sockets**, each acting as a dedicated channel for a specific type of data (e.g., chat messages, agent observations). + +- **Subscribing**: Your UI components can `subscribe` to a socket to listen for new data in real-time. When new data is available, a callback function you provide is executed. +- **Unsubscribing**: Every `subscribe` call returns an `unsubscribe` function. It is crucial to call this function when your UI component unmounts to prevent memory leaks. +- **Fetching History**: Most sockets have a `getHistory` method that allows you to retrieve a log of past data, which is essential for populating your UI when it first loads. + +--- + +## 3. Connecting to the `ConversationSocket` + +This is the most common socket, used for building chat interfaces. + +### Getting the Socket + +```javascript +const conversationSocket = art.uiSystem.getConversationSocket(); +``` + +### Subscribing to New Messages + +To display messages as they are sent by the user or generated by the agent, you subscribe to the socket. The callback will receive a `ConversationMessage` object. + +```javascript +// Example: Displaying a new message in the chat window +const unsubscribe = conversationSocket.subscribe( + (message) => { + console.log('New message received:', message); + // Code to append the message to your chat UI + // e.g., addMessageToChat(message.content, message.role); + }, + undefined, // No filter + { threadId: 'user-123-session-1' } // VERY IMPORTANT: Always scope subscriptions to a thread +); + +// When your component is destroyed, don't forget to unsubscribe: +// unsubscribe(); +``` + +You can also filter messages by their role: + +```javascript +// Only listen for messages from the AI +const unsubscribeFromAI = conversationSocket.subscribe( + (message) => { /* ... */ }, + 'AI', // Filter: a single MessageRole + { threadId: 'user-123-session-1' } +); + +// Only listen for messages from the USER or a TOOL +const unsubscribeFromUserOrTool = conversationSocket.subscribe( + (message) => { /* ... */ }, + ['USER', 'TOOL'], // Filter: an array of MessageRole + { threadId: 'user-123-session-1' } +); +``` + +### Fetching Message History + +To load the existing chat history for a conversation, use `getHistory`. + +```javascript +async function loadChatHistory(threadId) { + try { + const messages = await conversationSocket.getHistory( + undefined, // No role filter + { + threadId: threadId, + limit: 50 // Get the last 50 messages + } + ); + + console.log(`Loaded ${messages.length} messages.`); + // Code to render the historical messages in your UI + // messages.forEach(msg => addMessageToChat(msg.content, msg.role)); + } catch (error) { + console.error('Failed to load chat history:', error); + } +} +``` + +--- + +## 4. Connecting to the `ObservationSocket` + +This socket lets you visualize the agent's internal "thought process." + +### Getting the Socket + +```javascript +const observationSocket = art.uiSystem.getObservationSocket(); +``` + +### Subscribing to New Observations + +This is useful for showing a real-time feed of the agent's actions. + +```javascript +// Example: Log any tool calls the agent makes +const unsubscribe = observationSocket.subscribe( + (observation) => { + if (observation.type === 'TOOL_CALL') { + console.log('Agent is calling a tool:', observation.content); + // Code to display the tool call in a "thought process" panel + } + }, + 'TOOL_CALL', // Filter by the ObservationType + { threadId: 'user-123-session-1' } +); +``` + +### Fetching Observation History + +You can retrieve past observations to show a complete log of a previous agent run. + +```javascript +async function loadExecutionLog(threadId) { + try { + const observations = await observationSocket.getHistory( + ['PLAN', 'TOOL_CALL', 'TOOL_EXECUTION', 'ERROR'], // Filter for specific types + { threadId: threadId, limit: 100 } + ); + + console.log('Loaded execution log:', observations); + // Code to display the log in your UI + } catch (error) { + console.error('Failed to load execution log:', error); + } +} +``` + +--- + +## 5. Connecting to the `LLMStreamSocket` + +This socket is essential for creating a "typewriter" effect for the agent's response. Remember to set `stream: true` in your `art.process()` call to enable streaming. + +### Getting the Socket + +```javascript +const llmStreamSocket = art.uiSystem.getLLMStreamSocket(); +``` + +### Subscribing to Stream Events + +You'll typically subscribe to `TOKEN` events to append text to the UI in real-time. + +```javascript +let finalMessage = ''; +const unsubscribe = llmStreamSocket.subscribe( + (streamEvent) => { + switch (streamEvent.type) { + case 'TOKEN': + // Differentiate between thoughts and the final response + if (streamEvent.tokenType === 'FINAL_SYNTHESIS_LLM_RESPONSE') { + const token = streamEvent.data; + finalMessage += token; + // Code to update the last message in the UI with the new token + // e.g., updateLastMessage(finalMessage); + } + break; + case 'END': + console.log('Stream ended. Final message:', finalMessage); + // The stream is complete. You might save the final message to your state here. + break; + case 'ERROR': + console.error('An error occurred during streaming:', streamEvent.data); + break; + } + }, + undefined, // No filter + { threadId: 'user-123-session-1' } // Scope to the correct thread +); +``` + +### Fetching History + +The `LLMStreamSocket` does not have a `getHistory` method, as stream events are transient and not saved to the database. + +--- + +## 6. Connecting to the `A2ATaskSocket` + +This socket is for advanced applications that involve multiple agents delegating tasks to one another. + +### Getting the Socket + +```javascript +const a2aTaskSocket = art.uiSystem.getA2ATaskSocket(); +``` + +### Subscribing to Task Updates + +This allows you to build a real-time task management dashboard. + +```javascript +// Example: Listen for any task that gets completed or fails +const unsubscribe = a2aTaskSocket.subscribe( + (taskEvent) => { + console.log(`Task ${taskEvent.task.taskId} moved to status: ${taskEvent.task.status}`); + // Code to update the task's status in your dashboard UI + }, + { + // Rich filter object + status: ['COMPLETED', 'FAILED'] + }, + { threadId: 'user-123-session-1' } +); +``` + +### Fetching Task History + +You can load all existing tasks that match certain criteria. + +```javascript +async function loadInProgressTasks(threadId) { + try { + const tasks = await a2aTaskSocket.getHistory( + { status: 'IN_PROGRESS' }, // Filter + { threadId: threadId } // Options + ); + + console.log('Loaded in-progress tasks:', tasks); + // Code to display these tasks in your UI + } catch (error) { + console.error('Failed to load in-progress tasks:', error); + } +} +``` +### `ObservationType` Enum + +This enum lists all possible categories for an `Observation` record. A UI can filter by these types to show specific aspects of the agent's process. + +| Member | Description | +| :-------------------- | :------------------------------------------------------------------------ | +| `INTENT` | The user's inferred intent. | +| `PLAN` | The agent's step-by-step plan to address the intent. | +| `THOUGHTS` | The agent's internal monologue or reasoning process. | +| `TOOL_CALL` | The LLM's decision to call one or more tools. | +| `TOOL_EXECUTION` | The actual execution attempt and result of a specific tool call. | +| `SYNTHESIS` | Events specifically related to the final response generation phase. | +| `ERROR` | An error encountered during any phase of execution. | +| `FINAL_RESPONSE` | The final AI response message generated by the agent. | +| `STATE_UPDATE` | Changes made to the agent's persistent state. | +| `LLM_STREAM_START` | Logged by the Agent Core when LLM stream consumption begins. | +| `LLM_STREAM_METADATA` | Logged upon receiving a `METADATA` stream event. | +| `LLM_STREAM_END` | Logged upon receiving an `END` stream event. | +| `LLM_STREAM_ERROR` | Logged upon receiving an `ERROR` stream event. | + +### Built-in Metadata Fields + +While the `metadata` property on `ConversationMessage` and `Observation` is a generic `object`, the framework uses a few conventional fields: + +- **`ConversationMessage.metadata`**: + - `traceId`: The trace ID of the execution cycle that produced this message. + - `error`: A boolean flag (`true`) indicating that this message is an error response. +- **`Observation.metadata`**: + - `phase`: A string (`'planning'`, `'synthesis'`) indicating which stage of the agent execution cycle the observation was recorded in. + +### The `traceId` Explained + +The `traceId` is a crucial identifier for diagnostics and debugging. It is a unique ID generated at the very beginning of an `agent.process()` call and is passed down through all subsequent operations within that single execution cycle. + +- **Correlation**: It correlates all the events—observations, LLM calls, stream events, tool executions, and final messages—that belong to a single user request. +- **Debugging**: When you inspect the history, you can filter all `Observation` and `StreamEvent` objects by a specific `traceId` to get a complete, chronological picture of everything the agent did to generate a particular response. + +### How `StreamEvent` Works + +The `StreamEvent` system provides a granular, real-time feed of the LLM's generation process. It's not just about receiving text; it's about receiving structured events that describe the entire lifecycle of the stream. + +1. **Initiation**: When the agent calls the LLM with `stream: true`, the connection remains open. +2. **Event Flow**: The provider adapter (e.g., for Anthropic, OpenAI) translates the provider-specific data chunks into the standardized `StreamEvent` format. +3. **Token Events**: For each piece of text generated, a `TOKEN` event is emitted. The `tokenType` field provides crucial context, allowing a UI to distinguish between internal thoughts (like the raw plan) and the final response meant for the user. +4. **Metadata Events**: Periodically, and always at the end, `METADATA` events are sent, providing updates on token usage and the reason the model stopped generating. +5. **Termination**: The stream concludes with either an `END` event (for success) or an `ERROR` event. No more events will be sent for that `traceId` after this. + +This event-driven approach allows a UI to react intelligently, for example, by displaying a "thinking..." spinner for `AGENT_THOUGHT` tokens and then switching to a "typewriter" effect for `FINAL_SYNTHESIS` tokens. + +### `StreamEvent.type` + +| Type | Description | +| :--------- | :------------------------------------------------------------------------------------------------------- | +| `TOKEN` | A chunk of text generated by the LLM. | +| `METADATA` | Information about the LLM call (e.g., token counts, stop reason), typically sent once at the end. | +| `ERROR` | An error occurred during the LLM call or stream processing. The `data` will contain the `Error` object. | +| `END` | Signals the successful completion of the stream. The `data` is typically `null`. | + +### A2A Task Details + +#### `A2ATaskStatus` Enum + +| Status | Description | +| :------------ | :---------------------------------------------------------------- | +| `PENDING` | Task has been created but not yet assigned to an agent. | +| `IN_PROGRESS` | Task has been assigned to an agent and is being processed. | +| `COMPLETED` | Task has been completed successfully. | +| `FAILED` | Task has failed during execution. | +| `CANCELLED` | Task has been cancelled before completion. | +| `WAITING` | Task is waiting for external dependencies or manual intervention. | +| `REVIEW` | Task is being reviewed for quality assurance. | + +#### `A2ATaskPriority` Enum + +| Priority | Description | +| :------- | :----------------- | +| `LOW` | Low priority. | +| `MEDIUM` | Medium priority. | +| `HIGH` | High priority. | +| `URGENT` | Urgent priority. | + +#### `A2ATask.payload` Parameters + +| Field | Type | Description | +| :------------- | :------- | :-------------------------------------------------------- | +| `taskType` | `string` | The type of task to be executed (e.g., 'analyze'). | +| `input` | `any` | Input data required for the task. | +| `instructions` | `string` | (Optional) Instructions or configuration for the task. | +| `parameters` | `object` | (Optional) Additional parameters specific to the task type. | + +#### `A2ATask.metadata` Fields + +The `metadata` object within an `A2ATask` contains various timestamps and configuration details for managing the task's lifecycle. + +| Field | Type | Description | +| :---------------------- | :--------- | :------------------------------------------------------------------ | +| `createdAt` | `number` | Timestamp when the task was created. | +| `updatedAt` | `number` | Timestamp when the task was last updated. | +| `startedAt` | `number` | (Optional) Timestamp when the task processing started. | +| `completedAt` | `number` | (Optional) Timestamp when the task was completed or failed. | +| `delegatedAt` | `number` | (Optional) Timestamp when the task was delegated to a remote agent. | +| `initiatedBy` | `string` | (Optional) The user or system that initiated the task. | +| `correlationId` | `string` | (Optional) ID for tracking related tasks across the system. | +| `retryCount` | `number` | (Optional) Number of retry attempts made for this task. | +| `maxRetries` | `number` | (Optional) Maximum number of retry attempts allowed. | +| `timeoutMs` | `number` | (Optional) Timeout duration in milliseconds. | +| `estimatedCompletionMs` | `number` | (Optional) Estimated completion time provided by a remote agent. | +| `tags` | `string[]` | (Optional) Tags or labels for categorizing the task. | diff --git a/docs/llm.txt b/docs/llm.txt new file mode 100755 index 0000000..e0e6618 --- /dev/null +++ b/docs/llm.txt @@ -0,0 +1,309 @@ +# The Definitive Developer Guide to the ART Framework + +This document provides a definitive, highly detailed overview of the ART (Agentic Runtime) Framework. It is designed to be the single source of truth for developers building with ART, covering the framework's architecture, core concepts, API reference, and practical, up-to-date usage examples. + +## 1. Introduction & Core Value Proposition + +The ART Framework is a modular, extensible, and browser-first TypeScript library for building advanced AI agents. It provides a robust, structured foundation for creating agentic systems that can reason, use tools, and interact with users in real-time. + +**Key Features at a Glance:** +* **Secure & Flexible LLM Configuration:** A two-tiered system separates instance-level provider declarations from thread-level configuration, keeping API keys secure and enabling multi-provider, multi-model conversations from a single instance. +* **Advanced Agent Orchestration:** A built-in Plan-Execute-Synthesize (`PESAgent`) core provides robust, multi-step reasoning for complex tasks. +* **Extensible Tool System:** Equip agents with custom capabilities to interact with any API or data source through a clear, schema-driven interface. +* **Dynamic Tool Loading (MCP):** Discover and use tools from remote servers at runtime via the Model Context Protocol. +* **Agent-to-Agent (A2A) Communication:** Build complex systems where agents can delegate tasks to specialized peers. +* **Pluggable Persistence:** Store agent memory and conversation history in-browser (`IndexedDB`), in the cloud (`Supabase`), or using a custom storage adapter. +* **First-Class Observability:** Deeply inspect an agent's thought process through a structured `Observation` system. +* **Real-time UI Integration:** A dedicated `UISystem` with event sockets for streaming tokens, thoughts, and messages to any front-end framework. +* **Layered Persona Management:** A powerful, three-level system (Instance, Thread, Call) for customizing system prompts and agent behavior. + +## 2. Core Concepts & Design Philosophy + +* **Separation of Concerns:** Each component has a single, well-defined responsibility. The `StateManager` handles state, the `ToolSystem` handles tools, and `ProviderAdapters` handle LLM communication. This makes the system predictable and easy to debug. +* **Instance vs. Thread:** The `ArtInstance` is the long-lived application object that defines *potential capabilities* (available tools, providers). A `Thread` is a single conversation with a *specific configuration* (the exact model, API key, and enabled tools). This is the cornerstone of the framework's security and flexibility. +* **Standardized Interfaces:** The framework relies on a set of core interfaces (`IAgentCore`, `IToolExecutor`, `StorageAdapter`, `ProviderAdapter`). This allows developers to replace any part of the system with a custom implementation without breaking the rest of the framework. +* **Explicit State Management:** Configuration and state are managed through explicit API calls (e.g., `art.stateManager.setThreadConfig`). This creates a clear, predictable data flow and prevents race conditions. +* **Observability by Default:** Every significant action an agent takes—forming a plan, calling a tool, receiving an LLM response—is recorded as a structured `Observation`. This is a core feature for debugging, analysis, and building transparent AI systems. + +## 3. High-Level Architecture & Data Flow + +A typical user request flows through the system as follows: + +1. **Entry Point:** A user query enters the system via `art.process()`. +2. **Agent Core (`PESAgent`):** The `PESAgent` takes control. +3. **Context Loading:** It uses the `StateManager` to load the `ThreadContext` (the specific `ThreadConfig` and `AgentState`) for the given `threadId`. +4. **Planning:** The agent constructs a prompt (using history from `ConversationManager` and available tools from `ToolRegistry`) and sends it to the `ReasoningEngine`. The LLM returns a plan, which the `OutputParser` extracts into structured data. These events are recorded via the `ObservationManager`. +5. **Execution:** The `ToolSystem` is invoked with the parsed tool calls. It validates each call against the `ToolRegistry` and the thread's `enabledTools`, then executes them. Results are recorded as `Observations`. +6. **Synthesis:** The agent constructs a final prompt containing the original query and tool results, sending it to the `ReasoningEngine`. The LLM generates the final, user-facing response. +7. **Finalization:** The final user and AI messages are saved via the `ConversationManager`, and any modified `AgentState` is persisted. The final response is returned. +8. **Real-time Events:** Throughout this process, the `UISystem`'s sockets (`LLMStreamSocket`, `ObservationSocket`, etc.) emit events to any subscribed UI components. + +```mermaid +flowchart TD + User([User Query]) --> ArtInstance["art.process(query, threadId)"] + ArtInstance --> AgentCore["Agent Core (PESAgent)"] + + subgraph "1. Context Loading" + AgentCore -- "Loads ThreadContext" --> StateManager["StateManager"] + StateManager -- "Gets data from" --> Repositories["Repositories\n(State, Conversation)"] + Repositories -- "Read/Write" --> StorageAdapter["StorageAdapter\n(IndexedDB, etc.)"] + end + + subgraph "2. Planning & Reasoning" + AgentCore -- "Sends planning prompt" --> ReasoningEngine["ReasoningEngine"] + ReasoningEngine -- "Uses" --> ProviderAdapter["ProviderAdapter\n(e.g., OpenAIAdapter)"] + ProviderAdapter -- "Calls" --> ExternalLLM["External LLM API"] + ExternalLLM -- "Streams response" --> ProviderAdapter + ProviderAdapter -- "Yields StreamEvents" --> ReasoningEngine + ReasoningEngine -- "Returns full text" --> OutputParser["OutputParser"] + OutputParser -- "Extracts tool calls" --> AgentCore + end + + subgraph "3. Tool Execution" + AgentCore -- "Executes tool calls via" --> ToolSystem["ToolSystem"] + ToolSystem -- "Validates against" --> ToolRegistry["ToolRegistry"] + ToolSystem -- "Executes" --> IToolExecutor["IToolExecutor\n(e.g., CalculatorTool)"] + IToolExecutor -- "Returns ToolResult" --> ToolSystem + end + + subgraph "4. Synthesis" + AgentCore -- "Sends synthesis prompt\n(with tool results)" --> ReasoningEngine + end + + subgraph "5. Finalization & UI" + AgentCore -- "Saves messages" --> ConversationManager["ConversationManager"] + AgentCore -- "Returns AgentFinalResponse" --> ArtInstance + ReasoningEngine -- "Notifies UI of tokens" --> LLMStreamSocket["LLMStreamSocket"] + AgentCore -- "Records events via" --> ObservationManager["ObservationManager"] + ObservationManager -- "Notifies UI of thoughts" --> ObservationSocket["ObservationSocket"] + end +``` + +## 4. How-To Guides (Practical Scenarios) + +### 4.1. Building a Persistent Chatbot (The Right Way) +**Goal:** Create a conversational agent that remembers history across browser sessions. + +```typescript +import { + createArtInstance, + ArtInstanceConfig, + ThreadConfig, + OpenAIAdapter +} from 'art-framework'; + +// 1. Define the INSTANCE configuration. No secrets here. +const artConfig: ArtInstanceConfig = { + storage: { + type: 'indexedDB', + dbName: 'MyChatAppDB', + dbVersion: 1, + }, + providers: { + availableProviders: [ + { name: 'openai', adapter: OpenAIAdapter }, + ], + }, +}; + +// 2. Create the ART instance once in your application. +const art = await createArtInstance(artConfig); + +// 3. In your chat component, manage the conversation lifecycle. +async function startOrContinueChat(threadId: string, query: string) { + // Check if this is a new conversation. + const context = await art.stateManager.loadThreadContext(threadId); + + if (!context.config) { + console.log(`No config found for thread ${threadId}. Setting it up now.`); + // This is the first message. Set the THREAD configuration. + const threadConfig: ThreadConfig = { + providerConfig: { + providerName: 'openai', + modelId: 'gpt-4o', + adapterOptions: { + apiKey: 'sk-your-secret-openai-key', // Provide the key here + }, + }, + enabledTools: [], // No tools for this simple chat + historyLimit: 20, + }; + // CRITICAL: Save the configuration before processing. + await art.stateManager.setThreadConfig(threadId, threadConfig); + } + + // 4. Process the query. The framework will now find the saved config. + const result = await art.process({ query, threadId }); + console.log('Agent Response:', result.response.content); +} +``` + +### 4.2. Creating and Using a Custom Tool +**Goal:** Give the agent the ability to fetch real-time weather data. + +**1. Define the Tool (`WeatherTool.ts`)** +```typescript +import { IToolExecutor, ToolSchema, ToolResult, ExecutionContext } from 'art-framework'; + +export class WeatherTool implements IToolExecutor { + public readonly schema: ToolSchema = { + name: 'get_weather', + description: 'Gets the current weather for a specified location.', + inputSchema: { + type: 'object', + properties: { location: { type: 'string', description: 'The city, e.g., "San Francisco"' } }, + required: ['location'], + }, + }; + + async execute(input: { location: string }, context: ExecutionContext): Promise { + try { + // In a real app, call a weather API. + const temperature = Math.floor(Math.random() * 30) + 50; + return { + callId: context.traceId, + toolName: this.schema.name, + status: 'success', + output: { temperature, location: input.location, conditions: "Sunny" }, + }; + } catch (error) { + return { + callId: context.traceId, + toolName: this.schema.name, + status: 'error', + error: error instanceof Error ? error.message : 'Unknown error', + }; + } + } +} +``` + +**2. Register and Enable the Tool** +```typescript +import { WeatherTool } from './WeatherTool'; +import { OpenAIAdapter } from 'art-framework'; + +// In your main setup file: +const artConfig: ArtInstanceConfig = { + storage: { type: 'memory' }, + providers: { availableProviders: [{ name: 'openai', adapter: OpenAIAdapter }] }, + tools: [new WeatherTool()], // REGISTER the tool instance +}; +const art = await createArtInstance(artConfig); + +// In your application logic for a specific chat: +const threadId = 'weather-thread-1'; +const threadConfig: ThreadConfig = { + providerConfig: { + providerName: 'openai', + modelId: 'gpt-4o', + adapterOptions: { apiKey: 'sk-your-key' }, + }, + enabledTools: ['get_weather'], // ENABLE the tool for this thread by its schema name + historyLimit: 10, +}; +await art.stateManager.setThreadConfig(threadId, threadConfig); + +// Now the agent can use the tool. +await art.process({ query: "What's the weather like in Boston?", threadId }); +``` + +### 4.3. Integrating with a UI for Real-Time Updates +**Goal:** Display the agent's streaming response and thought process in a web UI. + +```typescript +// In your front-end code (e.g., a React component) +import { art } from './artInstance'; // Assuming you've initialized ART elsewhere + +function ChatComponent({ threadId }) { + const [streamingResponse, setStreamingResponse] = useState(''); + const [observations, setObservations] = useState([]); + + useEffect(() => { + // Subscribe to LLM token stream for the final answer + const unsubscribeStream = art.uiSystem.getLLMStreamSocket().subscribe( + (event) => { + if (event.type === 'TOKEN' && event.tokenType === 'RESPONSE') { + setStreamingResponse((prev) => prev + event.payload); + } + if (event.type === 'END') { + // Stream finished, save the full message to your state + setStreamingResponse(''); // Reset for next message + } + }, + null, // No filter + { threadId } // Only listen for events on this thread + ); + + // Subscribe to observations to show the agent's "thoughts" + const unsubscribeObs = art.uiSystem.getObservationSocket().subscribe( + (observation) => { + setObservations((prev) => [...prev, observation]); + }, + null, + { threadId } + ); + + return () => { + unsubscribeStream(); + unsubscribeObs(); + }; + }, [threadId]); + + // ... render your UI using streamingResponse and observations ... +} +``` + +## 5. Advanced Topics + +### 5.1. Agent-to-Agent (A2A) Communication +The A2A system allows you to build sophisticated, multi-agent workflows. +* **Concept:** An agent can act as a "manager" that receives a complex task. It can then use the `AgentDiscoveryService` to find "specialist" agents. The manager then uses the `TaskDelegationService` to send a structured `A2ATask` to the specialist. It monitors the task's progress and uses the result in its final synthesis. +* **Use Case:** A research agent receives a query "Summarize recent AI trends and create a presentation." It delegates the "summarize trends" task to a web-research agent and the "create presentation" task to a document-generation agent, then combines the results. + +### 5.2. Model Context Protocol (MCP) +MCP allows your agent to dynamically expand its capabilities without requiring a redeployment. +* **Concept:** The `McpManager` connects to MCP servers, fetches a manifest of available tools, and creates local `McpProxyTool` instances. When the agent uses one of these tools, the proxy handles the secure API call to the remote server, making the process seamless. +* **Use Case:** A company maintains a central MCP server with proprietary tools (e.g., `query_internal_database`). Any ART agent, with the right configuration, can connect to this server and instantly gain access to these tools. + +## 6. Comprehensive API Reference + +#### **Core Factory & Instance** +* **`createArtInstance(config: ArtInstanceConfig)`**: **(Function)** The primary entry point. Initializes all managers and systems. Returns a ready-to-use `ArtInstance`. +* **`ArtInstance`**: **(Interface)** The main object. Provides the `process()` method and accessors to all major public systems (`uiSystem`, `stateManager`, `toolRegistry`). + +#### **Agent Orchestration & Reasoning** +* **`IAgentCore` / `PESAgent`**: **(Interface/Class)** The agent's central reasoning logic. `PESAgent` is the default implementation that orchestrates the Plan-Execute-Synthesize cycle. +* **`ReasoningEngine`**: **(Class)** The service that directly interacts with LLM providers via adapters. +* **`ProviderAdapter`**: **(Interface)** The contract for a specific LLM provider (e.g., `OpenAIAdapter`). Translates between ART's standard format and the provider's API. +* **`ProviderManager`**: **(Class)** Manages the lifecycle and pooling of `ProviderAdapter` instances. +* **`StreamEvent`**: **(Interface)** A standardized object representing a chunk of data from an LLM stream (`TOKEN`, `METADATA`, `ERROR`, `END`). + +#### **Tools** +* **`IToolExecutor`**: **(Interface)** The contract that all tools must implement, requiring a `schema` and an `execute` method. +* **`ToolSchema`**: **(Interface)** The JSON Schema definition of a tool that is shown to the LLM. +* **`ToolRegistry`**: **(Class)** A service that holds all registered `IToolExecutor` instances. +* **`ToolSystem`**: **(Class)** The orchestrator for tool execution, handling validation and invocation. + +#### **State & Persistence** +* **`StorageAdapter`**: **(Interface)** The low-level contract for a key-value persistence layer (e.g., `IndexedDBStorageAdapter`). +* **`StateManager`**: **(Class)** The primary public interface for managing `ThreadConfig` and `AgentState`. This is a critical component for developers. +* **`ConversationManager`**: **(Class)** The primary public interface for managing `ConversationMessage` history. +* **`ThreadConfig`**: **(Interface)** The configuration for a single conversation thread (provider, model, API key, enabled tools). +* **`AgentState`**: **(Interface)** A flexible data structure for an agent to store its own persistent memory for a thread. + +#### **Observability & UI** +* **`Observation`**: **(Interface)** A structured log entry representing a significant event in the agent's lifecycle (e.g., `PLAN`, `TOOL_CALL`). +* **`ObservationManager`**: **(Class)** The service used by the agent to record `Observation`s. +* **`UISystem`**: **(Class)** The entry point to access the various real-time event sockets. +* **`LLMStreamSocket` / `ObservationSocket` / `ConversationSocket`**: **(Classes)** Typed event emitters that allow external code (like a UI) to subscribe to framework events with filtering. + +## 7. Glossary of Terms + +* **A2A (Agent-to-Agent):** A protocol and set of services enabling agents to delegate tasks to one another. +* **Agent Core:** The central component that orchestrates the agent's reasoning and action loop (e.g., `PESAgent`). +* **MCP (Model Context Protocol):** A standard for servers to expose tools that can be dynamically discovered and used by agents. +* **Observation:** A structured record of a significant internal event during an agent's execution, used for debugging and observability. +* **PES (Plan-Execute-Synthesize):** A robust agent orchestration pattern where the agent first plans its steps, then executes necessary actions, and finally synthesizes a final response. +* **Provider Adapter:** A component that translates between ART's standard format and the specific API format of an LLM provider. +* **Thread:** A single, continuous conversation, identified by a `threadId`. It has its own associated history, configuration, and state. \ No newline at end of file diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 021a172..0000000 --- a/package-lock.json +++ /dev/null @@ -1,6608 +0,0 @@ -{ - "name": "art-framework", - "version": "0.2.5", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "art-framework", - "version": "0.2.5", - "license": "MIT", - "dependencies": { - "@anthropic-ai/sdk": "^0.51.0", - "@google/genai": "^0.10.0", - "@types/mathjs": "^9.4.1", - "@types/mustache": "^4.2.5", - "ajv": "^8.17.1", - "mathjs": "^14.4.0", - "mustache": "^4.2.0", - "openai": "^4.98.0", - "uuid": "^9.0.0", - "zod": "^3.24.2" - }, - "devDependencies": { - "@playwright/test": "^1.51.1", - "@types/jest": "^29.5.14", - "@types/node": "^20.0.0", - "@types/uuid": "^10.0.0", - "@types/ws": "^8.18.1", - "@typescript-eslint/eslint-plugin": "^6.0.0", - "@typescript-eslint/parser": "^6.0.0", - "@vitest/coverage-v8": "^1.0.0", - "dotenv": "^16.5.0", - "eslint": "^8.0.0", - "prettier": "^3.0.0", - "ts-node": "^10.9.2", - "tsup": "^8.0.0", - "typedoc": "^0.28.1", - "typedoc-plugin-markdown": "^4.6.1", - "typescript": "^5.0.0", - "vitest": "^1.0.0", - "ws": "^8.18.1" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@anthropic-ai/sdk": { - "version": "0.51.0", - "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.51.0.tgz", - "integrity": "sha512-fAFC/uHhyzfw7rs65EPVV+scXDytGNm5BjttxHf6rP/YGvaBRKEvp2lwyuMigTwMI95neeG4bzrZigz7KCikjw==", - "license": "MIT", - "bin": { - "anthropic-ai-sdk": "bin/cli" - } - }, - "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==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-validator-identifier": "^7.27.1", - "js-tokens": "^4.0.0", - "picocolors": "^1.1.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/code-frame/node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@babel/helper-string-parser": { - "version": "7.25.9", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.25.9.tgz", - "integrity": "sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz", - "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz", - "integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/types": "^7.27.0" - }, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", - "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", - "license": "MIT", - "dependencies": { - "regenerator-runtime": "^0.14.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.27.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz", - "integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-string-parser": "^7.25.9", - "@babel/helper-validator-identifier": "^7.25.9" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@bcoe/v8-coverage": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", - "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", - "dev": true, - "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.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", - "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", - "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", - "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/android-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", - "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", - "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", - "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", - "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", - "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", - "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", - "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", - "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", - "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", - "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", - "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", - "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", - "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/linux-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", - "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", - "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", - "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", - "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", - "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", - "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", - "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", - "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@esbuild/win32-x64": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", - "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.5.1.tgz", - "integrity": "sha512-soEIOALTfTK6EjmKMMoLugwaP0rzkad90iIWd1hMO9ARkSAyjfMfkRRhLvD5qH7vvM0Cg72pieUfR6yh6XxC4w==", - "dev": true, - "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", - "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", - "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.1.tgz", - "integrity": "sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@gerrit0/mini-shiki": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@gerrit0/mini-shiki/-/mini-shiki-3.2.2.tgz", - "integrity": "sha512-vaZNGhGLKMY14HbF53xxHNgFO9Wz+t5lTlGNpl2N9xFiKQ0I5oIe0vKjU9dh7Nb3Dw6lZ7wqUE0ri+zcdpnK+Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/engine-oniguruma": "^3.2.1", - "@shikijs/langs": "^3.2.1", - "@shikijs/themes": "^3.2.1", - "@shikijs/types": "^3.2.1", - "@shikijs/vscode-textmate": "^10.0.2" - } - }, - "node_modules/@google/genai": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@google/genai/-/genai-0.10.0.tgz", - "integrity": "sha512-LAbp0em5A+wRtQR2+r5ckRBg2U2cBy8cJHgyTHa9PUbK8zucApw6A93HWyom/qlUQBNCpnIHFp20RiJuYMQwAw==", - "license": "Apache-2.0", - "dependencies": { - "google-auth-library": "^9.14.2", - "ws": "^8.18.0", - "zod": "^3.22.4", - "zod-to-json-schema": "^3.22.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "deprecated": "Use @eslint/config-array instead", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" - }, - "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "deprecated": "Use @eslint/object-schema instead", - "dev": true, - "license": "BSD-3-Clause" - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/expect-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.7.0.tgz", - "integrity": "sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "jest-get-type": "^29.6.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jest/types": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", - "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^3.0.0", - "@types/node": "*", - "@types/yargs": "^17.0.8", - "chalk": "^4.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", - "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/@playwright/test": { - "version": "1.51.1", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.51.1.tgz", - "integrity": "sha512-nM+kEaTSAoVlXmMPH10017vn3FSiFqr/bh4fKg9vmAdMfd9SDqRZNvPSiAHADc/itWak+qPvMPZQOPwCBW7k7Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "playwright": "1.51.1" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.39.0.tgz", - "integrity": "sha512-lGVys55Qb00Wvh8DMAocp5kIcaNzEFTmGhfFd88LfaogYTRKrdxgtlO5H6S49v2Nd8R2C6wLOal0qv6/kCkOwA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.39.0.tgz", - "integrity": "sha512-It9+M1zE31KWfqh/0cJLrrsCPiF72PoJjIChLX+rEcujVRCb4NLQ5QzFkzIZW8Kn8FTbvGQBY5TkKBau3S8cCQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.39.0.tgz", - "integrity": "sha512-lXQnhpFDOKDXiGxsU9/l8UEGGM65comrQuZ+lDcGUx+9YQ9dKpF3rSEGepyeR5AHZ0b5RgiligsBhWZfSSQh8Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.39.0.tgz", - "integrity": "sha512-mKXpNZLvtEbgu6WCkNij7CGycdw9cJi2k9v0noMb++Vab12GZjFgUXD69ilAbBh034Zwn95c2PNSz9xM7KYEAQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.39.0.tgz", - "integrity": "sha512-jivRRlh2Lod/KvDZx2zUR+I4iBfHcu2V/BA2vasUtdtTN2Uk3jfcZczLa81ESHZHPHy4ih3T/W5rPFZ/hX7RtQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.39.0.tgz", - "integrity": "sha512-8RXIWvYIRK9nO+bhVz8DwLBepcptw633gv/QT4015CpJ0Ht8punmoHU/DuEd3iw9Hr8UwUV+t+VNNuZIWYeY7Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.39.0.tgz", - "integrity": "sha512-mz5POx5Zu58f2xAG5RaRRhp3IZDK7zXGk5sdEDj4o96HeaXhlUwmLFzNlc4hCQi5sGdR12VDgEUqVSHer0lI9g==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.39.0.tgz", - "integrity": "sha512-+YDwhM6gUAyakl0CD+bMFpdmwIoRDzZYaTWV3SDRBGkMU/VpIBYXXEvkEcTagw/7VVkL2vA29zU4UVy1mP0/Yw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.39.0.tgz", - "integrity": "sha512-EKf7iF7aK36eEChvlgxGnk7pdJfzfQbNvGV/+l98iiMwU23MwvmV0Ty3pJ0p5WQfm3JRHOytSIqD9LB7Bq7xdQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.39.0.tgz", - "integrity": "sha512-vYanR6MtqC7Z2SNr8gzVnzUul09Wi1kZqJaek3KcIlI/wq5Xtq4ZPIZ0Mr/st/sv/NnaPwy/D4yXg5x0B3aUUA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.39.0.tgz", - "integrity": "sha512-NMRUT40+h0FBa5fb+cpxtZoGAggRem16ocVKIv5gDB5uLDgBIwrIsXlGqYbLwW8YyO3WVTk1FkFDjMETYlDqiw==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.39.0.tgz", - "integrity": "sha512-0pCNnmxgduJ3YRt+D+kJ6Ai/r+TaePu9ZLENl+ZDV/CdVczXl95CbIiwwswu4L+K7uOIGf6tMo2vm8uadRaICQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.39.0.tgz", - "integrity": "sha512-t7j5Zhr7S4bBtksT73bO6c3Qa2AV/HqiGlj9+KB3gNF5upcVkx+HLgxTm8DK4OkzsOYqbdqbLKwvGMhylJCPhQ==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.39.0.tgz", - "integrity": "sha512-m6cwI86IvQ7M93MQ2RF5SP8tUjD39Y7rjb1qjHgYh28uAPVU8+k/xYWvxRO3/tBN2pZkSMa5RjnPuUIbrwVxeA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.39.0.tgz", - "integrity": "sha512-iRDJd2ebMunnk2rsSBYlsptCyuINvxUfGwOUldjv5M4tpa93K8tFMeYGpNk2+Nxl+OBJnBzy2/JCscGeO507kA==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.39.0.tgz", - "integrity": "sha512-t9jqYw27R6Lx0XKfEFe5vUeEJ5pF3SGIM6gTfONSMb7DuG6z6wfj2yjcoZxHg129veTqU7+wOhY6GX8wmf90dA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.39.0.tgz", - "integrity": "sha512-ThFdkrFDP55AIsIZDKSBWEt/JcWlCzydbZHinZ0F/r1h83qbGeenCt/G/wG2O0reuENDD2tawfAj2s8VK7Bugg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.39.0.tgz", - "integrity": "sha512-jDrLm6yUtbOg2TYB3sBF3acUnAwsIksEYjLeHL+TJv9jg+TmTwdyjnDex27jqEMakNKf3RwwPahDIt7QXCSqRQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.39.0.tgz", - "integrity": "sha512-6w9uMuza+LbLCVoNKL5FSLE7yvYkq9laSd09bwS0tMjkwXrmib/4KmoJcrKhLWHvw19mwU+33ndC69T7weNNjQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.39.0.tgz", - "integrity": "sha512-yAkUOkIKZlK5dl7u6dg897doBgLXmUHhIINM2c+sND3DZwnrdQkkSiDh7N75Ll4mM4dxSkYfXqU9fW3lLkMFug==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@shikijs/engine-oniguruma": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@shikijs/engine-oniguruma/-/engine-oniguruma-3.2.1.tgz", - "integrity": "sha512-wZZAkayEn6qu2+YjenEoFqj0OyQI64EWsNR6/71d1EkG4sxEOFooowKivsWPpaWNBu3sxAG+zPz5kzBL/SsreQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.2.1", - "@shikijs/vscode-textmate": "^10.0.2" - } - }, - "node_modules/@shikijs/langs": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@shikijs/langs/-/langs-3.2.1.tgz", - "integrity": "sha512-If0iDHYRSGbihiA8+7uRsgb1er1Yj11pwpX1c6HLYnizDsKAw5iaT3JXj5ZpaimXSWky/IhxTm7C6nkiYVym+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.2.1" - } - }, - "node_modules/@shikijs/themes": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@shikijs/themes/-/themes-3.2.1.tgz", - "integrity": "sha512-k5DKJUT8IldBvAm8WcrDT5+7GA7se6lLksR+2E3SvyqGTyFMzU2F9Gb7rmD+t+Pga1MKrYFxDIeyWjMZWM6uBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/types": "3.2.1" - } - }, - "node_modules/@shikijs/types": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/@shikijs/types/-/types-3.2.1.tgz", - "integrity": "sha512-/NTWAk4KE2M8uac0RhOsIhYQf4pdU0OywQuYDGIGAJ6Mjunxl2cGiuLkvu4HLCMn+OTTLRWkjZITp+aYJv60yA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@shikijs/vscode-textmate": "^10.0.2", - "@types/hast": "^3.0.4" - } - }, - "node_modules/@shikijs/vscode-textmate": { - "version": "10.0.2", - "resolved": "https://registry.npmjs.org/@shikijs/vscode-textmate/-/vscode-textmate-10.0.2.tgz", - "integrity": "sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sinclair/typebox": { - "version": "0.27.8", - "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@tsconfig/node10": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", - "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", - "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/estree": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", - "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/hast": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/hast/-/hast-3.0.4.tgz", - "integrity": "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/unist": "*" - } - }, - "node_modules/@types/istanbul-lib-coverage": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", - "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/istanbul-lib-report": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", - "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-coverage": "*" - } - }, - "node_modules/@types/istanbul-reports": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", - "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/istanbul-lib-report": "*" - } - }, - "node_modules/@types/jest": { - "version": "29.5.14", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", - "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "expect": "^29.0.0", - "pretty-format": "^29.0.0" - } - }, - "node_modules/@types/json-schema": { - "version": "7.0.15", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", - "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/mathjs": { - "version": "9.4.1", - "resolved": "https://registry.npmjs.org/@types/mathjs/-/mathjs-9.4.1.tgz", - "integrity": "sha512-pEvgJ9c0LkVSZODbBuxeFngyhg/xMpZElcmvtFLayUXEgt6I4fGcMaxlPspV4kIMucmY6W4YwmtaWyTAQpqsrQ==", - "license": "MIT", - "dependencies": { - "mathjs": "*" - } - }, - "node_modules/@types/mustache": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/@types/mustache/-/mustache-4.2.5.tgz", - "integrity": "sha512-PLwiVvTBg59tGFL/8VpcGvqOu3L4OuveNvPi0EYbWchRdEVP++yRUXJPFl+CApKEq13017/4Nf7aQ5lTtHUNsA==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "20.17.30", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.30.tgz", - "integrity": "sha512-7zf4YyHA+jvBNfVrk2Gtvs6x7E8V+YDW05bNfG2XkWDJfYRXrTiP/DsB2zSYTaHX0bGIujTBQdMVAhb+j7mwpg==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.19.2" - } - }, - "node_modules/@types/node-fetch": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", - "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "form-data": "^4.0.0" - } - }, - "node_modules/@types/semver": { - "version": "7.7.0", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.7.0.tgz", - "integrity": "sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/stack-utils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", - "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/unist": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.3.tgz", - "integrity": "sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/uuid": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", - "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "node_modules/@types/yargs": { - "version": "17.0.33", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.33.tgz", - "integrity": "sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/yargs-parser": "*" - } - }, - "node_modules/@types/yargs-parser": { - "version": "21.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", - "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", - "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/type-utils": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "graphemer": "^1.4.0", - "ignore": "^5.2.4", - "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/parser": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", - "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", - "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/type-utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", - "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/typescript-estree": "6.21.0", - "@typescript-eslint/utils": "6.21.0", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", - "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", - "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/visitor-keys": "6.21.0", - "debug": "^4.3.4", - "globby": "^11.1.0", - "is-glob": "^4.0.3", - "minimatch": "9.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "node_modules/@typescript-eslint/utils": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", - "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.21.0", - "@typescript-eslint/types": "6.21.0", - "@typescript-eslint/typescript-estree": "6.21.0", - "semver": "^7.5.4" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", - "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "6.21.0", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^16.0.0 || >=18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/@ungap/structured-clone": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz", - "integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==", - "dev": true, - "license": "ISC" - }, - "node_modules/@vitest/coverage-v8": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-1.6.1.tgz", - "integrity": "sha512-6YeRZwuO4oTGKxD3bijok756oktHSIm3eczVVzNe3scqzuhLwltIF3S9ZL/vwOVIpURmU6SnZhziXXAfw8/Qlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.2.1", - "@bcoe/v8-coverage": "^0.2.3", - "debug": "^4.3.4", - "istanbul-lib-coverage": "^3.2.2", - "istanbul-lib-report": "^3.0.1", - "istanbul-lib-source-maps": "^5.0.4", - "istanbul-reports": "^3.1.6", - "magic-string": "^0.30.5", - "magicast": "^0.3.3", - "picocolors": "^1.0.0", - "std-env": "^3.5.0", - "strip-literal": "^2.0.0", - "test-exclude": "^6.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "vitest": "1.6.1" - } - }, - "node_modules/@vitest/expect": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.1.tgz", - "integrity": "sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/spy": "1.6.1", - "@vitest/utils": "1.6.1", - "chai": "^4.3.10" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.1.tgz", - "integrity": "sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/utils": "1.6.1", - "p-limit": "^5.0.0", - "pathe": "^1.1.1" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner/node_modules/p-limit": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", - "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^1.0.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@vitest/runner/node_modules/yocto-queue": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", - "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@vitest/snapshot": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.1.tgz", - "integrity": "sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "pretty-format": "^29.7.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.1.tgz", - "integrity": "sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "tinyspy": "^2.2.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.1.tgz", - "integrity": "sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "diff-sequences": "^29.6.3", - "estree-walker": "^3.0.3", - "loupe": "^2.3.7", - "pretty-format": "^29.7.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/acorn": { - "version": "8.14.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", - "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", - "dev": true, - "license": "MIT", - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-jsx": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", - "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^6.0.0 || ^7.0.0 || ^8.0.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/agent-base": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", - "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/agentkeepalive": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", - "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", - "license": "MIT", - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "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/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "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": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/assertion-error": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", - "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "license": "MIT" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "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/bignumber.js": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.3.0.tgz", - "integrity": "sha512-EM7aMFTXbptt/wZdMlBv2t8IViwQL+h6SLHosp8Yf0dqJMTnY6iL32opnAB6kAdL0SZPuvcAzFr31o0c/R3/RA==", - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/braces": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", - "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fill-range": "^7.1.1" - }, - "engines": { - "node": ">=8" - } - }, - "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", - "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", - "license": "BSD-3-Clause" - }, - "node_modules/bundle-require": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bundle-require/-/bundle-require-5.1.0.tgz", - "integrity": "sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==", - "dev": true, - "license": "MIT", - "dependencies": { - "load-tsconfig": "^0.2.3" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "peerDependencies": { - "esbuild": ">=0.18" - } - }, - "node_modules/cac": { - "version": "6.7.14", - "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", - "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "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", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/chai": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", - "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "assertion-error": "^1.1.0", - "check-error": "^1.0.3", - "deep-eql": "^4.1.3", - "get-func-name": "^2.0.2", - "loupe": "^2.3.6", - "pathval": "^1.1.1", - "type-detect": "^4.1.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/check-error": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", - "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.2" - }, - "engines": { - "node": "*" - } - }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/ci-info": { - "version": "3.9.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", - "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/complex.js": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/complex.js/-/complex.js-2.4.2.tgz", - "integrity": "sha512-qtx7HRhPGSCBtGiST4/WGHuW+zeaND/6Ld+db6PbrulIB1i2Ev/2UPiqcmpQNPSyfBKraC0EOvOKCB5dGZKt3g==", - "license": "MIT", - "engines": { - "node": "*" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/confbox": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", - "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", - "dev": true, - "license": "MIT" - }, - "node_modules/consola": { - "version": "3.4.2", - "resolved": "https://registry.npmjs.org/consola/-/consola-3.4.2.tgz", - "integrity": "sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.18.0 || >=16.10.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", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decimal.js": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", - "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", - "license": "MIT" - }, - "node_modules/deep-eql": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", - "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-detect": "^4.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/deep-is": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "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", - "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/dir-glob": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", - "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/doctrine": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", - "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/dotenv": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", - "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "dev": true, - "license": "MIT" - }, - "node_modules/ecdsa-sig-formatter": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", - "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", - "license": "Apache-2.0", - "dependencies": { - "safe-buffer": "^5.0.1" - } - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true, - "license": "MIT" - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/esbuild": { - "version": "0.25.2", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", - "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.25.2", - "@esbuild/android-arm": "0.25.2", - "@esbuild/android-arm64": "0.25.2", - "@esbuild/android-x64": "0.25.2", - "@esbuild/darwin-arm64": "0.25.2", - "@esbuild/darwin-x64": "0.25.2", - "@esbuild/freebsd-arm64": "0.25.2", - "@esbuild/freebsd-x64": "0.25.2", - "@esbuild/linux-arm": "0.25.2", - "@esbuild/linux-arm64": "0.25.2", - "@esbuild/linux-ia32": "0.25.2", - "@esbuild/linux-loong64": "0.25.2", - "@esbuild/linux-mips64el": "0.25.2", - "@esbuild/linux-ppc64": "0.25.2", - "@esbuild/linux-riscv64": "0.25.2", - "@esbuild/linux-s390x": "0.25.2", - "@esbuild/linux-x64": "0.25.2", - "@esbuild/netbsd-arm64": "0.25.2", - "@esbuild/netbsd-x64": "0.25.2", - "@esbuild/openbsd-arm64": "0.25.2", - "@esbuild/openbsd-x64": "0.25.2", - "@esbuild/sunos-x64": "0.25.2", - "@esbuild/win32-arm64": "0.25.2", - "@esbuild/win32-ia32": "0.25.2", - "@esbuild/win32-x64": "0.25.2" - } - }, - "node_modules/escape-latex": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/escape-latex/-/escape-latex-1.2.0.tgz", - "integrity": "sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==", - "license": "MIT" - }, - "node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint": { - "version": "8.57.1", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.1.tgz", - "integrity": "sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.6.1", - "@eslint/eslintrc": "^2.1.4", - "@eslint/js": "8.57.1", - "@humanwhocodes/config-array": "^0.13.0", - "@humanwhocodes/module-importer": "^1.0.1", - "@nodelib/fs.walk": "^1.2.8", - "@ungap/structured-clone": "^1.2.0", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.2", - "debug": "^4.3.2", - "doctrine": "^3.0.0", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^7.2.2", - "eslint-visitor-keys": "^3.4.3", - "espree": "^9.6.1", - "esquery": "^1.4.2", - "esutils": "^2.0.2", - "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^6.0.1", - "find-up": "^5.0.0", - "glob-parent": "^6.0.2", - "globals": "^13.19.0", - "graphemer": "^1.4.0", - "ignore": "^5.2.0", - "imurmurhash": "^0.1.4", - "is-glob": "^4.0.0", - "is-path-inside": "^3.0.3", - "js-yaml": "^4.1.0", - "json-stable-stringify-without-jsonify": "^1.0.1", - "levn": "^0.4.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3", - "strip-ansi": "^6.0.1", - "text-table": "^0.2.0" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-scope": { - "version": "7.2.2", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", - "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^5.2.0" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, - "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/espree": { - "version": "9.6.1", - "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", - "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "acorn": "^8.9.0", - "acorn-jsx": "^5.3.2", - "eslint-visitor-keys": "^3.4.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/esquery": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", - "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "estraverse": "^5.1.0" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/expect": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-29.7.0.tgz", - "integrity": "sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/expect-utils": "^29.7.0", - "jest-get-type": "^29.6.3", - "jest-matcher-utils": "^29.7.0", - "jest-message-util": "^29.7.0", - "jest-util": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "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-glob": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", - "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "node_modules/fast-glob/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "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", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true, - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", - "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/fastq": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", - "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "reusify": "^1.0.4" - } - }, - "node_modules/file-entry-cache": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", - "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, - "license": "MIT", - "dependencies": { - "flat-cache": "^3.0.4" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", - "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-up": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", - "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^6.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/flat-cache": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", - "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, - "license": "MIT", - "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.3", - "rimraf": "^3.0.2" - }, - "engines": { - "node": "^10.12.0 || >=12.0.0" - } - }, - "node_modules/flatted": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", - "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", - "dev": true, - "license": "ISC" - }, - "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.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/form-data-encoder": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", - "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", - "license": "MIT" - }, - "node_modules/formdata-node": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", - "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", - "license": "MIT", - "dependencies": { - "node-domexception": "1.0.0", - "web-streams-polyfill": "4.0.0-beta.3" - }, - "engines": { - "node": ">= 12.20" - } - }, - "node_modules/fraction.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-5.2.2.tgz", - "integrity": "sha512-uXBDv5knpYmv/2gLzWQ5mBHGBRk9wcKTeWu6GLTUEQfjCxO09uM/mHDrojlL+Q1mVGIIFo149Gba7od1XPgSzQ==", - "license": "MIT", - "engines": { - "node": ">= 12" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/rawify" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true, - "license": "ISC" - }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gaxios": { - "version": "6.7.1", - "resolved": "https://registry.npmjs.org/gaxios/-/gaxios-6.7.1.tgz", - "integrity": "sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==", - "license": "Apache-2.0", - "dependencies": { - "extend": "^3.0.2", - "https-proxy-agent": "^7.0.1", - "is-stream": "^2.0.0", - "node-fetch": "^2.6.9", - "uuid": "^9.0.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/gaxios/node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/gcp-metadata": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-6.1.1.tgz", - "integrity": "sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==", - "license": "Apache-2.0", - "dependencies": { - "gaxios": "^6.1.1", - "google-logging-utils": "^0.0.2", - "json-bigint": "^1.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/get-func-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", - "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/globals": { - "version": "13.24.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", - "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "type-fest": "^0.20.2" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/globby": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", - "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/google-auth-library": { - "version": "9.15.1", - "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-9.15.1.tgz", - "integrity": "sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==", - "license": "Apache-2.0", - "dependencies": { - "base64-js": "^1.3.0", - "ecdsa-sig-formatter": "^1.0.11", - "gaxios": "^6.1.1", - "gcp-metadata": "^6.1.0", - "gtoken": "^7.0.0", - "jws": "^4.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/google-logging-utils": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/google-logging-utils/-/google-logging-utils-0.0.2.tgz", - "integrity": "sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true, - "license": "MIT" - }, - "node_modules/gtoken": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-7.1.0.tgz", - "integrity": "sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==", - "license": "MIT", - "dependencies": { - "gaxios": "^6.0.0", - "jws": "^4.0.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", - "dev": true, - "license": "MIT" - }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=16.17.0" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/import-fresh": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", - "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dev": true, - "license": "ISC", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "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", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-path-inside": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", - "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "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": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", - "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", - "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.23", - "debug": "^4.1.1", - "istanbul-lib-coverage": "^3.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-reports": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.7.tgz", - "integrity": "sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jackspeak": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.3.tgz", - "integrity": "sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/javascript-natural-sort": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", - "integrity": "sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==", - "license": "MIT" - }, - "node_modules/jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-matcher-utils": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.7.0.tgz", - "integrity": "sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^4.0.0", - "jest-diff": "^29.7.0", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-message-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.7.0.tgz", - "integrity": "sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.12.13", - "@jest/types": "^29.6.3", - "@types/stack-utils": "^2.0.0", - "chalk": "^4.0.0", - "graceful-fs": "^4.2.9", - "micromatch": "^4.0.4", - "pretty-format": "^29.7.0", - "slash": "^3.0.0", - "stack-utils": "^2.0.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/jest-util": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", - "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/types": "^29.6.3", - "@types/node": "*", - "chalk": "^4.0.0", - "ci-info": "^3.2.0", - "graceful-fs": "^4.2.9", - "picomatch": "^2.2.3" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/joycon": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", - "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, - "node_modules/js-tokens": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-9.0.1.tgz", - "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-bigint": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", - "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", - "license": "MIT", - "dependencies": { - "bignumber.js": "^9.0.0" - } - }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true, - "license": "MIT" - }, - "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-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/jwa": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.0.tgz", - "integrity": "sha512-jrZ2Qx916EA+fq9cEAeCROWPTfCwi1IVHqT2tapuqLEVVDKFDENFw1oL+MwrTvH6msKxsd1YTDVw6uKEcsrLEA==", - "license": "MIT", - "dependencies": { - "buffer-equal-constant-time": "1.0.1", - "ecdsa-sig-formatter": "1.0.11", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/jws": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.0.tgz", - "integrity": "sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==", - "license": "MIT", - "dependencies": { - "jwa": "^2.0.0", - "safe-buffer": "^5.0.1" - } - }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, - "license": "MIT", - "dependencies": { - "json-buffer": "3.0.1" - } - }, - "node_modules/levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/linkify-it": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", - "integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "uc.micro": "^2.0.0" - } - }, - "node_modules/load-tsconfig": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/load-tsconfig/-/load-tsconfig-0.2.5.tgz", - "integrity": "sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - } - }, - "node_modules/local-pkg": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz", - "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mlly": "^1.7.3", - "pkg-types": "^1.2.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/locate-path": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", - "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^5.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", - "dev": true, - "license": "MIT" - }, - "node_modules/loupe": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", - "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-func-name": "^2.0.1" - } - }, - "node_modules/lru-cache": { - "version": "10.4.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", - "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/lunr": { - "version": "2.3.9", - "resolved": "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz", - "integrity": "sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==", - "dev": true, - "license": "MIT" - }, - "node_modules/magic-string": { - "version": "0.30.17", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", - "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0" - } - }, - "node_modules/magicast": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/magicast/-/magicast-0.3.5.tgz", - "integrity": "sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/parser": "^7.25.4", - "@babel/types": "^7.25.4", - "source-map-js": "^1.2.0" - } - }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-error": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", - "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", - "dev": true, - "license": "ISC" - }, - "node_modules/markdown-it": { - "version": "14.1.0", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.0.tgz", - "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", - "dev": true, - "license": "MIT", - "dependencies": { - "argparse": "^2.0.1", - "entities": "^4.4.0", - "linkify-it": "^5.0.0", - "mdurl": "^2.0.0", - "punycode.js": "^2.3.1", - "uc.micro": "^2.1.0" - }, - "bin": { - "markdown-it": "bin/markdown-it.mjs" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mathjs": { - "version": "14.4.0", - "resolved": "https://registry.npmjs.org/mathjs/-/mathjs-14.4.0.tgz", - "integrity": "sha512-CpoYDhNENefjIG9wU9epr+0pBHzlaySfpWcblZdAf5qXik/j/U8eSmx/oNbmXO0F5PyfwPGVD/wK4VWsTho1SA==", - "license": "Apache-2.0", - "dependencies": { - "@babel/runtime": "^7.26.10", - "complex.js": "^2.2.5", - "decimal.js": "^10.4.3", - "escape-latex": "^1.2.0", - "fraction.js": "^5.2.1", - "javascript-natural-sort": "^0.7.1", - "seedrandom": "^3.0.5", - "tiny-emitter": "^2.1.0", - "typed-function": "^4.2.1" - }, - "bin": { - "mathjs": "bin/cli.js" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/mdurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz", - "integrity": "sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==", - "dev": true, - "license": "MIT" - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true, - "license": "MIT" - }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=8.6" - } - }, - "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/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/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/mlly": { - "version": "1.7.4", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", - "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", - "dev": true, - "license": "MIT", - "dependencies": { - "acorn": "^8.14.0", - "pathe": "^2.0.1", - "pkg-types": "^1.3.0", - "ufo": "^1.5.4" - } - }, - "node_modules/mlly/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/mustache": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", - "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", - "license": "MIT", - "bin": { - "mustache": "bin/mustache" - } - }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true, - "license": "MIT" - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "deprecated": "Use your platform's native DOMException instead", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-fetch/node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" - }, - "node_modules/node-fetch/node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" - }, - "node_modules/node-fetch/node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/npm-run-path": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", - "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^4.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", - "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "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==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-6.0.0.tgz", - "integrity": "sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "mimic-fn": "^4.0.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/openai": { - "version": "4.98.0", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.98.0.tgz", - "integrity": "sha512-TmDKur1WjxxMPQAtLG5sgBSCJmX7ynTsGmewKzoDwl1fRxtbLOsiR0FA/AOAAtYUmP6azal+MYQuOENfdU+7yg==", - "license": "Apache-2.0", - "dependencies": { - "@types/node": "^18.11.18", - "@types/node-fetch": "^2.6.4", - "abort-controller": "^3.0.0", - "agentkeepalive": "^4.2.1", - "form-data-encoder": "1.7.2", - "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7" - }, - "bin": { - "openai": "bin/cli" - }, - "peerDependencies": { - "ws": "^8.18.0", - "zod": "^3.23.8" - }, - "peerDependenciesMeta": { - "ws": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/openai/node_modules/@types/node": { - "version": "18.19.100", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.100.tgz", - "integrity": "sha512-ojmMP8SZBKprc3qGrGk8Ujpo80AXkrP7G2tOT4VWr5jlr5DHjsJF+emXJz+Wm0glmy4Js62oKMdZZ6B9Y+tEcA==", - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/openai/node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "license": "MIT" - }, - "node_modules/optionator": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", - "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0", - "word-wrap": "^1.2.5" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/p-limit": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", - "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "yocto-queue": "^0.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", - "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "dev": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "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" - } - }, - "node_modules/path-scurry": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.11.1.tgz", - "integrity": "sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/pathval": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", - "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "*" - } - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/pkg-types": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", - "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "confbox": "^0.1.8", - "mlly": "^1.7.4", - "pathe": "^2.0.1" - } - }, - "node_modules/pkg-types/node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "dev": true, - "license": "MIT" - }, - "node_modules/playwright": { - "version": "1.51.1", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.51.1.tgz", - "integrity": "sha512-kkx+MB2KQRkyxjYPc3a0wLZZoDczmppyGJIvQ43l+aZihkaVvmu/21kiyaHeHjiFxjxNNFnUncKmcGIyOojsaw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "playwright-core": "1.51.1" - }, - "bin": { - "playwright": "cli.js" - }, - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "fsevents": "2.3.2" - } - }, - "node_modules/playwright-core": { - "version": "1.51.1", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.51.1.tgz", - "integrity": "sha512-/crRMj8+j/Nq5s8QcvegseuyeZPxpQCZb6HNk3Sos3BlZyAknRjoyJPFWkpNn8v0+P3WiwqFF8P+zQo4eqiNuw==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "playwright-core": "cli.js" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/playwright/node_modules/fsevents": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", - "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, - "node_modules/postcss": { - "version": "8.5.3", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", - "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "nanoid": "^3.3.8", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" - }, - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/prettier": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", - "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/punycode.js": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", - "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", - "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "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/react-is": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true, - "license": "MIT" - }, - "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.14.1", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", - "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", - "license": "MIT" - }, - "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/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/reusify": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", - "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", - "dev": true, - "license": "MIT", - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, - "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/rollup": { - "version": "4.39.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.39.0.tgz", - "integrity": "sha512-thI8kNc02yNvnmJp8dr3fNWJ9tCONDhp6TV35X6HkKGGs9E6q7YWCHbe5vKiTa7TAiNcFEmXKj3X/pG2b3ci0g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "1.0.7" - }, - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=18.0.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.39.0", - "@rollup/rollup-android-arm64": "4.39.0", - "@rollup/rollup-darwin-arm64": "4.39.0", - "@rollup/rollup-darwin-x64": "4.39.0", - "@rollup/rollup-freebsd-arm64": "4.39.0", - "@rollup/rollup-freebsd-x64": "4.39.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.39.0", - "@rollup/rollup-linux-arm-musleabihf": "4.39.0", - "@rollup/rollup-linux-arm64-gnu": "4.39.0", - "@rollup/rollup-linux-arm64-musl": "4.39.0", - "@rollup/rollup-linux-loongarch64-gnu": "4.39.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.39.0", - "@rollup/rollup-linux-riscv64-gnu": "4.39.0", - "@rollup/rollup-linux-riscv64-musl": "4.39.0", - "@rollup/rollup-linux-s390x-gnu": "4.39.0", - "@rollup/rollup-linux-x64-gnu": "4.39.0", - "@rollup/rollup-linux-x64-musl": "4.39.0", - "@rollup/rollup-win32-arm64-msvc": "4.39.0", - "@rollup/rollup-win32-ia32-msvc": "4.39.0", - "@rollup/rollup-win32-x64-msvc": "4.39.0", - "fsevents": "~2.3.2" - } - }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "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", - "dependencies": { - "queue-microtask": "^1.2.2" - } - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "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/seedrandom": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz", - "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/shebang-command": { - "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" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "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" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "dev": true, - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/source-map": { - "version": "0.8.0-beta.0", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.8.0-beta.0.tgz", - "integrity": "sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "whatwg-url": "^7.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/stack-utils": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", - "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "escape-string-regexp": "^2.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/stack-utils/node_modules/escape-string-regexp": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", - "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "dev": true, - "license": "MIT" - }, - "node_modules/std-env": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.8.1.tgz", - "integrity": "sha512-vj5lIj3Mwf9D79hBkltk5qmkFI+biIKWS2IBxEyEU3AX1tUf7AoL8nSazCOiiqQsGKIq01SClsKEzweu34uwvA==", - "dev": true, - "license": "MIT" - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "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/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/string-width/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/string-width/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-3.0.0.tgz", - "integrity": "sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strip-literal": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-2.1.1.tgz", - "integrity": "sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-tokens": "^9.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/antfu" - } - }, - "node_modules/sucrase": { - "version": "3.35.0", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", - "integrity": "sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "^10.3.10", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/sucrase/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", - "dev": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/sucrase/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", - "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", - "dev": true, - "license": "ISC", - "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/test-exclude/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/text-table": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true, - "license": "MIT" - }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tiny-emitter": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", - "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==", - "license": "MIT" - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", - "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", - "dev": true, - "license": "MIT" - }, - "node_modules/tinyglobby": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", - "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", - "dev": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.4.3", - "picomatch": "^4.0.2" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", - "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tinypool": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", - "integrity": "sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tinyspy": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", - "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==", - "dev": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", - "dev": true, - "license": "MIT", - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/ts-api-utils": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.4.3.tgz", - "integrity": "sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=16" - }, - "peerDependencies": { - "typescript": ">=4.2.0" - } - }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true, - "license": "Apache-2.0" - }, - "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/tsup": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/tsup/-/tsup-8.4.0.tgz", - "integrity": "sha512-b+eZbPCjz10fRryaAA7C8xlIHnf8VnsaRqydheLIqwG/Mcpfk8Z5zp3HayX7GaTygkigHl5cBUs+IhcySiIexQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "bundle-require": "^5.1.0", - "cac": "^6.7.14", - "chokidar": "^4.0.3", - "consola": "^3.4.0", - "debug": "^4.4.0", - "esbuild": "^0.25.0", - "joycon": "^3.1.1", - "picocolors": "^1.1.1", - "postcss-load-config": "^6.0.1", - "resolve-from": "^5.0.0", - "rollup": "^4.34.8", - "source-map": "0.8.0-beta.0", - "sucrase": "^3.35.0", - "tinyexec": "^0.3.2", - "tinyglobby": "^0.2.11", - "tree-kill": "^1.2.2" - }, - "bin": { - "tsup": "dist/cli-default.js", - "tsup-node": "dist/cli-node.js" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@microsoft/api-extractor": "^7.36.0", - "@swc/core": "^1", - "postcss": "^8.4.12", - "typescript": ">=4.5.0" - }, - "peerDependenciesMeta": { - "@microsoft/api-extractor": { - "optional": true - }, - "@swc/core": { - "optional": true - }, - "postcss": { - "optional": true - }, - "typescript": { - "optional": true - } - } - }, - "node_modules/tsup/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, - "license": "MIT", - "dependencies": { - "prelude-ls": "^1.2.1" - }, - "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-detect": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", - "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/type-fest": { - "version": "0.20.2", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", - "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typed-function": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/typed-function/-/typed-function-4.2.1.tgz", - "integrity": "sha512-EGjWssW7Tsk4DGfE+5yluuljS1OGYWiI1J6e8puZz9nTMM51Oug8CD5Zo4gWMsOhq5BI+1bF+rWTm4Vbj3ivRA==", - "license": "MIT", - "engines": { - "node": ">= 18" - } - }, - "node_modules/typedoc": { - "version": "0.28.1", - "resolved": "https://registry.npmjs.org/typedoc/-/typedoc-0.28.1.tgz", - "integrity": "sha512-Mn2VPNMaxoe/hlBiLriG4U55oyAa3Xo+8HbtEwV7F5WEOPXqtxzGuMZhJYHaqFJpajeQ6ZDUC2c990NAtTbdgw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "@gerrit0/mini-shiki": "^3.2.1", - "lunr": "^2.3.9", - "markdown-it": "^14.1.0", - "minimatch": "^9.0.5", - "yaml": "^2.7.0 " - }, - "bin": { - "typedoc": "bin/typedoc" - }, - "engines": { - "node": ">= 18", - "pnpm": ">= 10" - }, - "peerDependencies": { - "typescript": "5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x" - } - }, - "node_modules/typedoc-plugin-markdown": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-4.6.1.tgz", - "integrity": "sha512-SrJv9zkpCWdG1cvtWniFU6M7MkCZuheN2R3fuqDPF+O+PeZ8bzmfj1ju/BJwoPWIKyFJVPhK8Sg6tBrM1y+VoA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 18" - }, - "peerDependencies": { - "typedoc": "0.28.x" - } - }, - "node_modules/typedoc/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/typescript": { - "version": "5.8.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.2.tgz", - "integrity": "sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/uc.micro": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", - "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", - "dev": true, - "license": "MIT" - }, - "node_modules/ufo": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.4.tgz", - "integrity": "sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/undici-types": { - "version": "6.19.8", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", - "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "license": "MIT" - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/uuid": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.1.tgz", - "integrity": "sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==", - "funding": [ - "https://github.com/sponsors/broofa", - "https://github.com/sponsors/ctavan" - ], - "license": "MIT", - "bin": { - "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/vite": { - "version": "5.4.16", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.16.tgz", - "integrity": "sha512-Y5gnfp4NemVfgOTDQAunSD4346fal44L9mszGGY/e+qxsRT5y1sMlS/8tiQ8AFAp+MFgYNSINdfEchJiPm41vQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" - }, - "bin": { - "vite": "bin/vite.js" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - } - } - }, - "node_modules/vite-node": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.1.tgz", - "integrity": "sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==", - "dev": true, - "license": "MIT", - "dependencies": { - "cac": "^6.7.14", - "debug": "^4.3.4", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "vite": "^5.0.0" - }, - "bin": { - "vite-node": "vite-node.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/vite/node_modules/@esbuild/aix-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", - "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "aix" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", - "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", - "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/android-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", - "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", - "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", - "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", - "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", - "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", - "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", - "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", - "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", - "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", - "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", - "cpu": [ - "mips64el" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", - "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", - "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", - "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", - "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", - "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", - "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", - "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", - "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", - "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", - "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=12" - } - }, - "node_modules/vite/node_modules/esbuild": { - "version": "0.21.5", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", - "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "bin": { - "esbuild": "bin/esbuild" - }, - "engines": { - "node": ">=12" - }, - "optionalDependencies": { - "@esbuild/aix-ppc64": "0.21.5", - "@esbuild/android-arm": "0.21.5", - "@esbuild/android-arm64": "0.21.5", - "@esbuild/android-x64": "0.21.5", - "@esbuild/darwin-arm64": "0.21.5", - "@esbuild/darwin-x64": "0.21.5", - "@esbuild/freebsd-arm64": "0.21.5", - "@esbuild/freebsd-x64": "0.21.5", - "@esbuild/linux-arm": "0.21.5", - "@esbuild/linux-arm64": "0.21.5", - "@esbuild/linux-ia32": "0.21.5", - "@esbuild/linux-loong64": "0.21.5", - "@esbuild/linux-mips64el": "0.21.5", - "@esbuild/linux-ppc64": "0.21.5", - "@esbuild/linux-riscv64": "0.21.5", - "@esbuild/linux-s390x": "0.21.5", - "@esbuild/linux-x64": "0.21.5", - "@esbuild/netbsd-x64": "0.21.5", - "@esbuild/openbsd-x64": "0.21.5", - "@esbuild/sunos-x64": "0.21.5", - "@esbuild/win32-arm64": "0.21.5", - "@esbuild/win32-ia32": "0.21.5", - "@esbuild/win32-x64": "0.21.5" - } - }, - "node_modules/vitest": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.1.tgz", - "integrity": "sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "1.6.1", - "@vitest/runner": "1.6.1", - "@vitest/snapshot": "1.6.1", - "@vitest/spy": "1.6.1", - "@vitest/utils": "1.6.1", - "acorn-walk": "^8.3.2", - "chai": "^4.3.10", - "debug": "^4.3.4", - "execa": "^8.0.1", - "local-pkg": "^0.5.0", - "magic-string": "^0.30.5", - "pathe": "^1.1.1", - "picocolors": "^1.0.0", - "std-env": "^3.5.0", - "strip-literal": "^2.0.0", - "tinybench": "^2.5.1", - "tinypool": "^0.8.3", - "vite": "^5.0.0", - "vite-node": "1.6.1", - "why-is-node-running": "^2.2.2" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "engines": { - "node": "^18.0.0 || >=20.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.6.1", - "@vitest/ui": "1.6.1", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "node_modules/web-streams-polyfill": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", - "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true, - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "node_modules/which": { - "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" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "dev": true, - "license": "MIT", - "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" - }, - "bin": { - "why-is-node-running": "cli.js" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/word-wrap": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", - "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/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/wrap-ansi/node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/ws": { - "version": "8.18.1", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", - "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", - "license": "MIT", - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } - }, - "node_modules/yaml": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", - "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14" - } - }, - "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", - "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/zod": { - "version": "3.24.2", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.2.tgz", - "integrity": "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.24.5", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz", - "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==", - "license": "ISC", - "peerDependencies": { - "zod": "^3.24.1" - } - } - } -} diff --git a/package.json b/package.json old mode 100644 new mode 100755 index e1f0dfe..153d841 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "art-framework", - "version": "0.2.8", - "description": "Agent Runtine (ART) Framework - A browser-first JavaScript/TypeScript framework for building LLM-powered intelligent agents", + "version": "0.3.7", + "description": "Agent Runtine (ART) Framework - A browser-first JavaScript/TypeScript framework for building LLM-powered Agentic AI applications that supports MCP and A2A protocols natively", "type": "module", "main": "./dist/index.js", "module": "./dist/index.js", @@ -27,7 +27,8 @@ "type-check": "tsc --noEmit", "prepare": "npm run build", "test:e2e": "playwright test", - "docs:api": "typedoc" + "docs:api": "typedoc", + "docs:site": "typedoc --options typedoc.html.json" }, "keywords": [ "llm", @@ -43,6 +44,7 @@ "@playwright/test": "^1.51.1", "@types/jest": "^29.5.14", "@types/node": "^20.0.0", + "@types/react-syntax-highlighter": "^15.5.13", "@types/uuid": "^10.0.0", "@types/ws": "^8.18.1", "@typescript-eslint/eslint-plugin": "^6.0.0", @@ -61,15 +63,20 @@ }, "dependencies": { "@anthropic-ai/sdk": "^0.51.0", - "@google/genai": "^0.10.0", + "@google/genai": "^1.17.0", + "@modelcontextprotocol/sdk": "^1.12.3", + "@supabase/supabase-js": "^2.56.0", "@types/mathjs": "^9.4.1", "@types/mustache": "^4.2.5", "ajv": "^8.17.1", "mathjs": "^14.4.0", "mustache": "^4.2.0", "openai": "^4.98.0", + "react-syntax-highlighter": "^15.6.1", + "reconnecting-eventsource": "^1.6.4", "uuid": "^9.0.0", - "zod": "^3.24.2" + "zod": "^3.24.2", + "art-mcp-permission-manager": "^0.2.1" }, "engines": { "node": ">=18.0.0" diff --git a/playwright.config.ts b/playwright.config.ts old mode 100644 new mode 100755 diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100755 index 0000000..6277c35 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,4898 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@anthropic-ai/sdk': + specifier: ^0.51.0 + version: 0.51.0 + '@google/genai': + specifier: ^0.10.0 + version: 0.10.0 + '@modelcontextprotocol/sdk': + specifier: ^1.12.3 + version: 1.17.3 + '@supabase/supabase-js': + specifier: ^2.56.0 + version: 2.56.0 + '@types/mathjs': + specifier: ^9.4.1 + version: 9.4.2 + '@types/mustache': + specifier: ^4.2.5 + version: 4.2.6 + ajv: + specifier: ^8.17.1 + version: 8.17.1 + art-mcp-permission-manager: + specifier: ^0.2.1 + version: 0.2.1 + mathjs: + specifier: ^14.4.0 + version: 14.6.0 + mustache: + specifier: ^4.2.0 + version: 4.2.0 + openai: + specifier: ^4.98.0 + version: 4.104.0(ws@8.18.3)(zod@3.25.76) + react-syntax-highlighter: + specifier: ^15.6.1 + version: 15.6.1(react@19.1.1) + reconnecting-eventsource: + specifier: ^1.6.4 + version: 1.6.4 + uuid: + specifier: ^9.0.0 + version: 9.0.1 + zod: + specifier: ^3.24.2 + version: 3.25.76 + devDependencies: + '@playwright/test': + specifier: ^1.51.1 + version: 1.54.2 + '@types/jest': + specifier: ^29.5.14 + version: 29.5.14 + '@types/node': + specifier: ^20.0.0 + version: 20.19.11 + '@types/react-syntax-highlighter': + specifier: ^15.5.13 + version: 15.5.13 + '@types/uuid': + specifier: ^10.0.0 + version: 10.0.0 + '@types/ws': + specifier: ^8.18.1 + version: 8.18.1 + '@typescript-eslint/eslint-plugin': + specifier: ^6.0.0 + version: 6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2) + '@typescript-eslint/parser': + specifier: ^6.0.0 + version: 6.21.0(eslint@8.57.1)(typescript@5.9.2) + '@vitest/coverage-v8': + specifier: ^1.0.0 + version: 1.6.1(vitest@1.6.1(@types/node@20.19.11)) + dotenv: + specifier: ^16.5.0 + version: 16.6.1 + eslint: + specifier: ^8.0.0 + version: 8.57.1 + prettier: + specifier: ^3.0.0 + version: 3.6.2 + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@20.19.11)(typescript@5.9.2) + tsup: + specifier: ^8.0.0 + version: 8.5.0(postcss@8.5.6)(typescript@5.9.2)(yaml@2.8.1) + typedoc: + specifier: ^0.28.1 + version: 0.28.10(typescript@5.9.2) + typedoc-plugin-markdown: + specifier: ^4.6.1 + version: 4.8.1(typedoc@0.28.10(typescript@5.9.2)) + typescript: + specifier: ^5.0.0 + version: 5.9.2 + vitest: + specifier: ^1.0.0 + version: 1.6.1(@types/node@20.19.11) + ws: + specifier: ^8.18.1 + version: 8.18.3 + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@anthropic-ai/sdk@0.51.0': + resolution: {integrity: sha512-fAFC/uHhyzfw7rs65EPVV+scXDytGNm5BjttxHf6rP/YGvaBRKEvp2lwyuMigTwMI95neeG4bzrZigz7KCikjw==} + hasBin: true + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.28.3': + resolution: {integrity: sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/runtime@7.28.3': + resolution: {integrity: sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.28.2': + resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@esbuild/aix-ppc64@0.21.5': + resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.25.9': + resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.21.5': + resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.25.9': + resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.21.5': + resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.25.9': + resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.21.5': + resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.25.9': + resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.21.5': + resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.25.9': + resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.21.5': + resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.25.9': + resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.21.5': + resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.25.9': + resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.21.5': + resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.25.9': + resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.21.5': + resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.25.9': + resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.21.5': + resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.25.9': + resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.21.5': + resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.25.9': + resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.21.5': + resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.25.9': + resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.21.5': + resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.25.9': + resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.21.5': + resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.25.9': + resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.21.5': + resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.25.9': + resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.21.5': + resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.25.9': + resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.21.5': + resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.25.9': + resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.25.9': + resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.21.5': + resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.25.9': + resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.25.9': + resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.21.5': + resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.25.9': + resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.25.9': + resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.21.5': + resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.25.9': + resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.21.5': + resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.25.9': + resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.21.5': + resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.25.9': + resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.21.5': + resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.25.9': + resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.7.0': + resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/eslintrc@2.1.4': + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@eslint/js@8.57.1': + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@gerrit0/mini-shiki@3.9.2': + resolution: {integrity: sha512-Tvsj+AOO4Z8xLRJK900WkyfxHsZQu+Zm1//oT1w443PO6RiYMoq/4NGOhaNuZoUMYsjKIAPVQ6eOFMddj6yphQ==} + + '@google/genai@0.10.0': + resolution: {integrity: sha512-LAbp0em5A+wRtQR2+r5ckRBg2U2cBy8cJHgyTHa9PUbK8zucApw6A93HWyom/qlUQBNCpnIHFp20RiJuYMQwAw==} + engines: {node: '>=18.0.0'} + + '@humanwhocodes/config-array@0.13.0': + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} + engines: {node: '>=10.10.0'} + deprecated: Use @eslint/config-array instead + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/object-schema@2.0.3': + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} + deprecated: Use @eslint/object-schema instead + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.30': + resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@lukeed/csprng@1.1.0': + resolution: {integrity: sha512-Z7C/xXCiGWsg0KuKsHTKJxbWhpI3Vs5GwLfOean7MGyVFGqdRgBbAjOCh6u4bbjPc/8MJ2pZmK/0DLdCbivLDA==} + engines: {node: '>=8'} + + '@modelcontextprotocol/sdk@1.17.3': + resolution: {integrity: sha512-JPwUKWSsbzx+DLFznf/QZ32Qa+ptfbUlHhRLrBQBAFu9iI1iYvizM4p+zhhRDceSsPutXp4z+R/HPVphlIiclg==} + engines: {node: '>=18'} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@playwright/test@1.54.2': + resolution: {integrity: sha512-A+znathYxPf+72riFd1r1ovOLqsIIB0jKIoPjyK2kqEIe30/6jF6BC7QNluHuwUmsD2tv1XZVugN8GqfTMOxsA==} + engines: {node: '>=18'} + hasBin: true + + '@rollup/rollup-android-arm-eabi@4.46.3': + resolution: {integrity: sha512-UmTdvXnLlqQNOCJnyksjPs1G4GqXNGW1LrzCe8+8QoaLhhDeTXYBgJ3k6x61WIhlHX2U+VzEJ55TtIjR/HTySA==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.46.3': + resolution: {integrity: sha512-8NoxqLpXm7VyeI0ocidh335D6OKT0UJ6fHdnIxf3+6oOerZZc+O7r+UhvROji6OspyPm+rrIdb1gTXtVIqn+Sg==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.46.3': + resolution: {integrity: sha512-csnNavqZVs1+7/hUKtgjMECsNG2cdB8F7XBHP6FfQjqhjF8rzMzb3SLyy/1BG7YSfQ+bG75Ph7DyedbUqwq1rA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.46.3': + resolution: {integrity: sha512-r2MXNjbuYabSIX5yQqnT8SGSQ26XQc8fmp6UhlYJd95PZJkQD1u82fWP7HqvGUf33IsOC6qsiV+vcuD4SDP6iw==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.46.3': + resolution: {integrity: sha512-uluObTmgPJDuJh9xqxyr7MV61Imq+0IvVsAlWyvxAaBSNzCcmZlhfYcRhCdMaCsy46ccZa7vtDDripgs9Jkqsw==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.46.3': + resolution: {integrity: sha512-AVJXEq9RVHQnejdbFvh1eWEoobohUYN3nqJIPI4mNTMpsyYN01VvcAClxflyk2HIxvLpRcRggpX1m9hkXkpC/A==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.46.3': + resolution: {integrity: sha512-byyflM+huiwHlKi7VHLAYTKr67X199+V+mt1iRgJenAI594vcmGGddWlu6eHujmcdl6TqSNnvqaXJqZdnEWRGA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.46.3': + resolution: {integrity: sha512-aLm3NMIjr4Y9LklrH5cu7yybBqoVCdr4Nvnm8WB7PKCn34fMCGypVNpGK0JQWdPAzR/FnoEoFtlRqZbBBLhVoQ==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.46.3': + resolution: {integrity: sha512-VtilE6eznJRDIoFOzaagQodUksTEfLIsvXymS+UdJiSXrPW7Ai+WG4uapAc3F7Hgs791TwdGh4xyOzbuzIZrnw==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.46.3': + resolution: {integrity: sha512-dG3JuS6+cRAL0GQ925Vppafi0qwZnkHdPeuZIxIPXqkCLP02l7ka+OCyBoDEv8S+nKHxfjvjW4OZ7hTdHkx8/w==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loongarch64-gnu@4.46.3': + resolution: {integrity: sha512-iU8DxnxEKJptf8Vcx4XvAUdpkZfaz0KWfRrnIRrOndL0SvzEte+MTM7nDH4A2Now4FvTZ01yFAgj6TX/mZl8hQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.46.3': + resolution: {integrity: sha512-VrQZp9tkk0yozJoQvQcqlWiqaPnLM6uY1qPYXvukKePb0fqaiQtOdMJSxNFUZFsGw5oA5vvVokjHrx8a9Qsz2A==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.46.3': + resolution: {integrity: sha512-uf2eucWSUb+M7b0poZ/08LsbcRgaDYL8NCGjUeFMwCWFwOuFcZ8D9ayPl25P3pl+D2FH45EbHdfyUesQ2Lt9wA==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.46.3': + resolution: {integrity: sha512-7tnUcDvN8DHm/9ra+/nF7lLzYHDeODKKKrh6JmZejbh1FnCNZS8zMkZY5J4sEipy2OW1d1Ncc4gNHUd0DLqkSg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.46.3': + resolution: {integrity: sha512-MUpAOallJim8CsJK+4Lc9tQzlfPbHxWDrGXZm2z6biaadNpvh3a5ewcdat478W+tXDoUiHwErX/dOql7ETcLqg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.46.3': + resolution: {integrity: sha512-F42IgZI4JicE2vM2PWCe0N5mR5vR0gIdORPqhGQ32/u1S1v3kLtbZ0C/mi9FFk7C5T0PgdeyWEPajPjaUpyoKg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.46.3': + resolution: {integrity: sha512-oLc+JrwwvbimJUInzx56Q3ujL3Kkhxehg7O1gWAYzm8hImCd5ld1F2Gry5YDjR21MNb5WCKhC9hXgU7rRlyegQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-win32-arm64-msvc@4.46.3': + resolution: {integrity: sha512-lOrQ+BVRstruD1fkWg9yjmumhowR0oLAAzavB7yFSaGltY8klttmZtCLvOXCmGE9mLIn8IBV/IFrQOWz5xbFPg==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.46.3': + resolution: {integrity: sha512-vvrVKPRS4GduGR7VMH8EylCBqsDcw6U+/0nPDuIjXQRbHJc6xOBj+frx8ksfZAh6+Fptw5wHrN7etlMmQnPQVg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.46.3': + resolution: {integrity: sha512-fi3cPxCnu3ZeM3EwKZPgXbWoGzm2XHgB/WShKI81uj8wG0+laobmqy5wbgEwzstlbLu4MyO8C19FyhhWseYKNQ==} + cpu: [x64] + os: [win32] + + '@shikijs/engine-oniguruma@3.10.0': + resolution: {integrity: sha512-O7ofyEUm4uDBlfd+2YPc7GHA72Kr3eUw5wSgZzgK6GUniD52106diH9Fo7+7l+lhBiyWntYcvzGK8QMciwf+Xw==} + + '@shikijs/langs@3.10.0': + resolution: {integrity: sha512-uE9ojRozrm1PmUw2aM8EbHpT/XdWzSdv/sWRN5MCMdXMW1eOl4bMxWAlY5yhZj0GghYfMbBzMlcDKqrIjOue/Q==} + + '@shikijs/themes@3.10.0': + resolution: {integrity: sha512-JDnZKjYs4nhBniOmVILfEFZCA9JxxLnxG4PRQQQudn8DREhoWQelw7fhv+3Up8phzkoZWQ9TW2jp9k+6DjJS5A==} + + '@shikijs/types@3.10.0': + resolution: {integrity: sha512-PAeyajDDhdzefMiSZn7ENCwVaACMnO53+p5pSrJpIQOJTSX+4Qn28Y5e7I6v9wkJNyepRFfbZmzmbbnzjxBMEA==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + '@supabase/auth-js@2.71.1': + resolution: {integrity: sha512-mMIQHBRc+SKpZFRB2qtupuzulaUhFYupNyxqDj5Jp/LyPvcWvjaJzZzObv6URtL/O6lPxkanASnotGtNpS3H2Q==} + + '@supabase/functions-js@2.4.5': + resolution: {integrity: sha512-v5GSqb9zbosquTo6gBwIiq7W9eQ7rE5QazsK/ezNiQXdCbY+bH8D9qEaBIkhVvX4ZRW5rP03gEfw5yw9tiq4EQ==} + + '@supabase/node-fetch@2.6.15': + resolution: {integrity: sha512-1ibVeYUacxWYi9i0cf5efil6adJ9WRyZBLivgjs+AUpewx1F3xPi7gLgaASI2SmIQxPoCEjAsLAzKPgMJVgOUQ==} + engines: {node: 4.x || >=6.0.0} + + '@supabase/postgrest-js@1.21.3': + resolution: {integrity: sha512-rg3DmmZQKEVCreXq6Am29hMVe1CzemXyIWVYyyua69y6XubfP+DzGfLxME/1uvdgwqdoaPbtjBDpEBhqxq1ZwA==} + + '@supabase/realtime-js@2.15.1': + resolution: {integrity: sha512-edRFa2IrQw50kNntvUyS38hsL7t2d/psah6om6aNTLLcWem0R6bOUq7sk7DsGeSlNfuwEwWn57FdYSva6VddYw==} + + '@supabase/storage-js@2.11.0': + resolution: {integrity: sha512-Y+kx/wDgd4oasAgoAq0bsbQojwQ+ejIif8uczZ9qufRHWFLMU5cODT+ApHsSrDufqUcVKt+eyxtOXSkeh2v9ww==} + + '@supabase/supabase-js@2.56.0': + resolution: {integrity: sha512-XqwhHSyVnkjdliPN61CmXsmFGnFHTX2WDdwjG3Ukvdzuu3Trix+dXupYOQ3BueIyYp7B6t0yYpdQtJP2hIInyg==} + + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/hast@2.3.10': + resolution: {integrity: sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest@29.5.14': + resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/mathjs@9.4.2': + resolution: {integrity: sha512-GF5g1vJmvKdWIWsE53XX7EDAyCaZ9p6gaYm1xhlXn5JjrY/NJrOfJN3fBxS3wyZpVh3QqKoMkS2WjFwxWMHOTw==} + deprecated: This is a stub types definition. mathjs provides its own type definitions, so you do not need this installed. + + '@types/mustache@4.2.6': + resolution: {integrity: sha512-t+8/QWTAhOFlrF1IVZqKnMRJi84EgkIK5Kh0p2JV4OLywUvCwJPFxbJAl7XAow7DVIHsF+xW9f1MVzg0L6Szjw==} + + '@types/node-fetch@2.6.13': + resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} + + '@types/node@18.19.123': + resolution: {integrity: sha512-K7DIaHnh0mzVxreCR9qwgNxp3MH9dltPNIEddW9MYUlcKAzm+3grKNSTe2vCJHI1FaLpvpL5JGJrz1UZDKYvDg==} + + '@types/node@20.19.11': + resolution: {integrity: sha512-uug3FEEGv0r+jrecvUUpbY8lLisvIjg6AAic6a2bSP5OEOLeJsDSnvhCDov7ipFFMXS3orMpzlmi0ZcuGkBbow==} + + '@types/phoenix@1.6.6': + resolution: {integrity: sha512-PIzZZlEppgrpoT2QgbnDU+MMzuR6BbCjllj0bM70lWoejMeNJAxCchxnv7J3XFkI8MpygtRpzXrIlmWUBclP5A==} + + '@types/react-syntax-highlighter@15.5.13': + resolution: {integrity: sha512-uLGJ87j6Sz8UaBAooU0T6lWJ0dBmjZgN1PZTrj05TNql2/XpC6+4HhMT5syIdFUUt+FASfCeLLv4kBygNU+8qA==} + + '@types/react@19.1.10': + resolution: {integrity: sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==} + + '@types/semver@7.7.0': + resolution: {integrity: sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/uuid@10.0.0': + resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.33': + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + + '@typescript-eslint/eslint-plugin@6.21.0': + resolution: {integrity: sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + '@typescript-eslint/parser': ^6.0.0 || ^6.0.0-alpha + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/parser@6.21.0': + resolution: {integrity: sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/scope-manager@6.21.0': + resolution: {integrity: sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==} + engines: {node: ^16.0.0 || >=18.0.0} + + '@typescript-eslint/type-utils@6.21.0': + resolution: {integrity: sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/types@6.21.0': + resolution: {integrity: sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==} + engines: {node: ^16.0.0 || >=18.0.0} + + '@typescript-eslint/typescript-estree@6.21.0': + resolution: {integrity: sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/utils@6.21.0': + resolution: {integrity: sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==} + engines: {node: ^16.0.0 || >=18.0.0} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 + + '@typescript-eslint/visitor-keys@6.21.0': + resolution: {integrity: sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==} + engines: {node: ^16.0.0 || >=18.0.0} + + '@ungap/structured-clone@1.3.0': + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} + + '@vitest/coverage-v8@1.6.1': + resolution: {integrity: sha512-6YeRZwuO4oTGKxD3bijok756oktHSIm3eczVVzNe3scqzuhLwltIF3S9ZL/vwOVIpURmU6SnZhziXXAfw8/Qlw==} + peerDependencies: + vitest: 1.6.1 + + '@vitest/expect@1.6.1': + resolution: {integrity: sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==} + + '@vitest/runner@1.6.1': + resolution: {integrity: sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==} + + '@vitest/snapshot@1.6.1': + resolution: {integrity: sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==} + + '@vitest/spy@1.6.1': + resolution: {integrity: sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==} + + '@vitest/utils@1.6.1': + resolution: {integrity: sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==} + + '@webext-core/messaging@2.3.0': + resolution: {integrity: sha512-gChSVKdRs7JEq5hFH0jVROSvTq+sKq9afXTA/gBswep3RWNLhXyDsXFlvPMkYbmML1XZ8QKKC9ou2MlCKRZwSQ==} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.0: + resolution: {integrity: sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + art-mcp-permission-manager@0.2.1: + resolution: {integrity: sha512-1AxL4cd81/yPAeKtC8XbuOj02OoXXhpmW0qT8XAev4N+pZ0Rrck4nM8tKUClifLP6lEAowvjmOoK7m9lBNSjgA==} + + assertion-error@1.1.0: + resolution: {integrity: sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bignumber.js@9.3.1: + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + + body-parser@2.2.0: + resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} + engines: {node: '>=18'} + + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.18' + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + chai@4.5.0: + resolution: {integrity: sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==} + engines: {node: '>=4'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + character-entities-legacy@1.1.4: + resolution: {integrity: sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA==} + + character-entities@1.2.4: + resolution: {integrity: sha512-iBMyeEHxfVnIakwOuDXpVkc54HijNgCyQB2w0VfGQThle6NXn50zU6V/u+LDhxHcDUPojn6Kpga3PTAD8W1bQw==} + + character-reference-invalid@1.1.4: + resolution: {integrity: sha512-mKKUkUbhPpQlCOfIuZkvSEgktjPFIsZKRRbC6KWVEMvlzblj3i3asQv5ODsrwt0N3pHAEvjP8KTQPHkp0+6jOg==} + + check-error@1.0.3: + resolution: {integrity: sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + comma-separated-tokens@1.0.8: + resolution: {integrity: sha512-GHuDRO12Sypu2cV70d1dkA2EUmXHgntrzbpvOB+Qy+49ypNfGgFQIC2fhhXbnyrJRynDCAARsT7Ou0M6hirpfw==} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + complex.js@2.4.2: + resolution: {integrity: sha512-qtx7HRhPGSCBtGiST4/WGHuW+zeaND/6Ld+db6PbrulIB1i2Ev/2UPiqcmpQNPSyfBKraC0EOvOKCB5dGZKt3g==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + content-disposition@1.0.0: + resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + + deep-eql@4.1.4: + resolution: {integrity: sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==} + engines: {node: '>=6'} + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + doctrine@3.0.0: + resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} + engines: {node: '>=6.0.0'} + + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + esbuild@0.21.5: + resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} + engines: {node: '>=12'} + hasBin: true + + esbuild@0.25.9: + resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} + engines: {node: '>=18'} + hasBin: true + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-latex@1.2.0: + resolution: {integrity: sha512-nV5aVWW1K0wEiUIEdZ4erkGGH8mDxGyxSeqPzRNtWP7ataw+/olFObw7hujFWlVjNsaDFw5VZ5NzVSIqRgfTiw==} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. + hasBin: true + + espree@9.6.1: + resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + eventsource-parser@3.0.5: + resolution: {integrity: sha512-bSRG85ZrMdmWtm7qkF9He9TNRzc/Bm99gEJMaQoHJ9E6Kv9QBbsldh2oMj7iXmYNEAVvNgvv5vPorG6W+XtBhQ==} + engines: {node: '>=20.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + express-rate-limit@7.5.1: + resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.1.0: + resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} + engines: {node: '>= 18'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-uri@3.0.6: + resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + fault@1.0.4: + resolution: {integrity: sha512-CJ0HCB5tL5fYTEA7ToAq5+kTwd++Borf1/bifxd9iT70QcXr4MRrO3Llf8Ifs70q+SJcGHFtnIE/Nw6giCtECA==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + file-entry-cache@6.0.1: + resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} + engines: {node: ^10.12.0 || >=12.0.0} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + finalhandler@2.1.0: + resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} + engines: {node: '>= 0.8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + fix-dts-default-cjs-exports@1.0.1: + resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + + flat-cache@3.2.0: + resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} + engines: {node: ^10.12.0 || >=12.0.0} + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + form-data-encoder@1.7.2: + resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} + + form-data@4.0.4: + resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} + engines: {node: '>= 6'} + + format@0.2.2: + resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} + engines: {node: '>=0.4.x'} + + formdata-node@4.4.1: + resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} + engines: {node: '>= 12.20'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fraction.js@5.3.1: + resolution: {integrity: sha512-PhqCuhSKIGbbkJ+cojHv47eEWClU71FIOhiUsYdZYTwhIzCeIN8rXeEjserTvPat5JLJChumn8chHz64WkZgTw==} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gaxios@6.7.1: + resolution: {integrity: sha512-LDODD4TMYx7XXdpwxAVRAIAuB0bzv0s+ywFonY46k126qzQHT9ygyoa9tncmOiQmmDrik65UYsEkv3lbfqQ3yQ==} + engines: {node: '>=14'} + + gcp-metadata@6.1.1: + resolution: {integrity: sha512-a4tiq7E0/5fTjxPAaH4jpjkSv/uCaU2p5KC6HVGrvl0cDjA8iBZv4vv1gyzlmK0ZUKqwpOyQMKzZQe3lTit77A==} + engines: {node: '>=14'} + + get-func-name@2.0.2: + resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + globals@13.24.0: + resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} + engines: {node: '>=8'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + google-auth-library@9.15.1: + resolution: {integrity: sha512-Jb6Z0+nvECVz+2lzSMt9u98UsoakXxA2HGHMCxh+so3n90XgYWkq5dur19JAJV7ONiJY22yBTyJB1TSkvPq9Ng==} + engines: {node: '>=14'} + + google-logging-utils@0.0.2: + resolution: {integrity: sha512-NEgUnEcBiP5HrPzufUkBzJOD/Sxsco3rLNo1F1TNf7ieU8ryUzBhqba8r756CjLX7rn3fHl6iLEwPYuqpoKgQQ==} + engines: {node: '>=14'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + gtoken@7.1.0: + resolution: {integrity: sha512-pCcEwRi+TKpMlxAQObHDQ56KawURgyAf6jtIY046fJ5tIv3zDe/LEIubckAO8fj6JnAxLdmWkUfNyulQ2iKdEw==} + engines: {node: '>=14.0.0'} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + hast-util-parse-selector@2.2.5: + resolution: {integrity: sha512-7j6mrk/qqkSehsM92wQjdIgWM2/BW61u/53G6xmC8i1OmEdKLHbk419QKQUjz6LglWsfqoiHmyMRkP1BGjecNQ==} + + hastscript@6.0.0: + resolution: {integrity: sha512-nDM6bvd7lIqDUiYEiu5Sl/+6ReP0BMk/2f4U/Rooccxkj0P5nm+acM5PrGJ/t5I8qPGiqZSE6hVAwZEdZIvP4w==} + + highlight.js@10.7.3: + resolution: {integrity: sha512-tzcUFauisWKNHaRkN4Wjl/ZA07gENAjFl3J/c480dprkGTg5EQstgaNFqBfUqCq54kZRIEcreTsAgF/m2quD7A==} + + highlightjs-vue@1.0.0: + resolution: {integrity: sha512-PDEfEF102G23vHmPhLyPboFCD+BkMGu+GuJe2d9/eH4FsCwvgBpnc9n0pGE+ffKdph38s6foEZiEjdgHdzp+IA==} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-alphabetical@1.0.4: + resolution: {integrity: sha512-DwzsA04LQ10FHTZuL0/grVDk4rFoVH1pjAToYwBrHSxcrBIGQuXrQMtD5U1b0U2XVgKZCTLLP8u2Qxqhy3l2Vg==} + + is-alphanumerical@1.0.4: + resolution: {integrity: sha512-UzoZUr+XfVz3t3v4KyGEniVL9BDRoQtY7tOyrRybkVNjDFWyo1yhXNGrrBTQxp3ib9BLAWs7k2YKBQsFRkZG9A==} + + is-decimal@1.0.4: + resolution: {integrity: sha512-RGdriMmQQvZ2aqaQq3awNA6dCGtKpiDFcOzrTWrDAT2MiWrKQVPmxLGHl7Y2nNu6led0kEyoX0enY0qXYsv9zw==} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-hexadecimal@1.0.4: + resolution: {integrity: sha512-gyPJuv83bHMpocVYoqof5VDiZveEoGoFL8m3BXNb2VW8Xs+rz9kqO8LOQ5DH6EsuvilT1ApazU0pyl+ytbPtlw==} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + javascript-natural-sort@0.7.1: + resolution: {integrity: sha512-nO6jcEfZWQXDhOiBtG2KvKyEptz7RVbpGP4vTD2hLBdmNQSsCiicO2Ioinv6UI4y9ukqnBpy+XZ9H6uLNgJTlw==} + + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + + jws@4.0.0: + resolution: {integrity: sha512-KDncfTmOZoOMTFG4mBlG0qUIOlc03fmzH+ru6RgYVZhPkyiy/92Owlt/8UEN+a4TXR1FQetfIpJE8ApdvdVxTg==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + local-pkg@0.5.1: + resolution: {integrity: sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==} + engines: {node: '>=14'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.sortby@4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + + loupe@2.3.7: + resolution: {integrity: sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==} + + lowlight@1.20.0: + resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lunr@2.3.9: + resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + magicast@0.3.5: + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + hasBin: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mathjs@14.6.0: + resolution: {integrity: sha512-5vI2BLB5GKQmiSK9BH6hVkZ+GgqpdnOgEfmHl7mqVmdQObLynr63KueyYYLCQMzj66q69mV2XZZGQqqxeftQbA==} + engines: {node: '>= 18'} + hasBin: true + + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mime-types@3.0.1: + resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} + engines: {node: '>= 0.6'} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.3: + resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} + engines: {node: '>=16 || 14 >=14.17'} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + mlly@1.7.4: + resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mustache@4.2.0: + resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} + hasBin: true + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + openai@4.104.0: + resolution: {integrity: sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.23.8 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-limit@5.0.0: + resolution: {integrity: sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==} + engines: {node: '>=18'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-entities@2.0.0: + resolution: {integrity: sha512-kkywGpCcRYhqQIchaWqZ875wzpS/bMKhz5HnN3p7wveJTkTtyAB/AlnS0f8DFSqYW1T82t6yEAkEcB+A1I3MbQ==} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-to-regexp@8.2.0: + resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} + engines: {node: '>=16'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@1.1.1: + resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkce-challenge@5.0.0: + resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} + engines: {node: '>=16.20.0'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + playwright-core@1.54.2: + resolution: {integrity: sha512-n5r4HFbMmWsB4twG7tJLDN9gmBUeSPcsBZiWSE4DnYz9mJMAFqr2ID7+eGC9kpEnxExJ1epttwR59LEWCk8mtA==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.54.2: + resolution: {integrity: sha512-Hu/BMoA1NAdRUuulyvQC0pEqZ4vQbGfn8f7wPXcnqQmM+zct9UliKxsIkLNmz/ku7LElUNqmaiv1TG/aL5ACsw==} + engines: {node: '>=18'} + hasBin: true + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} + engines: {node: '>=14'} + hasBin: true + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + prismjs@1.27.0: + resolution: {integrity: sha512-t13BGPUlFDR7wRB5kQDG4jjl7XeuH6jbJGt11JHPL96qwsEHNX2+68tFXqc1/k+/jALsbSWJKUOT/hcYAZ5LkA==} + engines: {node: '>=6'} + + prismjs@1.30.0: + resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} + engines: {node: '>=6'} + + property-information@5.6.0: + resolution: {integrity: sha512-YUHSPk+A30YPv+0Qf8i9Mbfe/C0hdPXk1s1jPVToV8pk8BQtpw10ct89Eo7OWkutrwqvT0eicAxlOg3dOAu8JA==} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.0: + resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} + engines: {node: '>= 0.8'} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-syntax-highlighter@15.6.1: + resolution: {integrity: sha512-OqJ2/vL7lEeV5zTJyG7kmARppUjiB9h9udl4qHQjjgEos66z00Ia0OckwYfRxCSFrW8RJIBnsBwQsHZbVPspqg==} + peerDependencies: + react: '>= 0.14.0' + + react@19.1.1: + resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} + engines: {node: '>=0.10.0'} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + reconnecting-eventsource@1.6.4: + resolution: {integrity: sha512-0L3IS3wxcNFApTPPHkcbY8Aya7XZIpYDzhxa8j6QSufVkUN018XJKfh2ZaThLBGP/iN5UTz2yweMhkqr0PKa7A==} + engines: {node: '>=12.0.0'} + + refractor@3.6.0: + resolution: {integrity: sha512-MY9W41IOWxxk31o+YvFCNyNzdkc9M20NoZK5vq6jkv4I/uh2zkWcfudj0Q1fovjUQJrNewS9NMzeTtqPf+n5EA==} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + deprecated: Rimraf versions prior to v4 are no longer supported + hasBin: true + + rollup@4.46.3: + resolution: {integrity: sha512-RZn2XTjXb8t5g13f5YclGoilU/kwT696DIkY3sywjdZidNSi3+vseaQov7D7BZXVJCPv3pDWUN69C78GGbXsKw==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + seedrandom@3.0.5: + resolution: {integrity: sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==} + + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + + send@1.2.0: + resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + engines: {node: '>= 18'} + + serialize-error@11.0.3: + resolution: {integrity: sha512-2G2y++21dhj2R7iHAdd0FIzjGwuKZld+7Pl/bTU6YIkrC2ZMbVUjm+luj6A6V34Rv9XfKJDKpTWu9W4Gse1D9g==} + engines: {node: '>=14.16'} + + serve-static@2.2.0: + resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map@0.8.0-beta.0: + resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} + engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions + + space-separated-tokens@1.1.5: + resolution: {integrity: sha512-q/JSVd1Lptzhf5bkYm4ob4iWPjx0KiRe3sRFBNrVqbJkFaBm5vbbowy1mymoPNLRa52+oadOhJ+K49wsSeSjTA==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + std-env@3.9.0: + resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strip-literal@2.1.1: + resolution: {integrity: sha512-631UJ6O00eNGfMiWG78ck80dfBab8X6IVFB51jZK5Icd7XAs60Z5y7QdSd/wGIklnWvRbUNloVzhOKKmutxQ6Q==} + + sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + text-table@0.2.0: + resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + tiny-emitter@2.1.0: + resolution: {integrity: sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.14: + resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} + engines: {node: '>=12.0.0'} + + tinypool@0.8.4: + resolution: {integrity: sha512-i11VH5gS6IFeLY3gMBQ00/MmLncVP7JLXOw1vlgkytLmJK7QnEr7NXf0LBdxfmNPAeyetukOk0bOYrJrFGjYJQ==} + engines: {node: '>=14.0.0'} + + tinyspy@2.2.1: + resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==} + engines: {node: '>=14.0.0'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + + tr46@1.0.1: + resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + ts-api-utils@1.4.3: + resolution: {integrity: sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw==} + engines: {node: '>=16'} + peerDependencies: + typescript: '>=4.2.0' + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + 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 + + tsup@8.5.0: + resolution: {integrity: sha512-VmBp77lWNQq6PfuMqCHD3xWl22vEoWsKajkF8t+yMBawlUS8JzEI+vOVMeuNZIuMML8qXRizFKi9oD5glKQVcQ==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-detect@4.1.0: + resolution: {integrity: sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==} + engines: {node: '>=4'} + + type-fest@0.20.2: + resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} + engines: {node: '>=10'} + + type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + + typed-function@4.2.1: + resolution: {integrity: sha512-EGjWssW7Tsk4DGfE+5yluuljS1OGYWiI1J6e8puZz9nTMM51Oug8CD5Zo4gWMsOhq5BI+1bF+rWTm4Vbj3ivRA==} + engines: {node: '>= 18'} + + typedoc-plugin-markdown@4.8.1: + resolution: {integrity: sha512-ug7fc4j0SiJxSwBGLncpSo8tLvrT9VONvPUQqQDTKPxCoFQBADLli832RGPtj6sfSVJebNSrHZQRUdEryYH/7g==} + engines: {node: '>= 18'} + peerDependencies: + typedoc: 0.28.x + + typedoc@0.28.10: + resolution: {integrity: sha512-zYvpjS2bNJ30SoNYfHSRaFpBMZAsL7uwKbWwqoCNFWjcPnI3e/mPLh2SneH9mX7SJxtDpvDgvd9/iZxGbo7daw==} + engines: {node: '>= 18', pnpm: '>= 10'} + hasBin: true + peerDependencies: + typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x || 5.9.x + + typescript@5.9.2: + resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} + engines: {node: '>=14.17'} + hasBin: true + + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + + ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + + uid@2.0.2: + resolution: {integrity: sha512-u3xV3X7uzvi5b1MncmZo3i2Aw222Zk1keqLA1YkHldREkAhAqi65wuPfe7lHx8H/Wzy+8CE7S7uS3jekIM5s8g==} + engines: {node: '>=8'} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vite-node@1.6.1: + resolution: {integrity: sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + + vite@5.4.19: + resolution: {integrity: sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || >=20.0.0 + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.4.0 + peerDependenciesMeta: + '@types/node': + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + + vitest@1.6.1: + resolution: {integrity: sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==} + engines: {node: ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/node': ^18.0.0 || >=20.0.0 + '@vitest/browser': 1.6.1 + '@vitest/ui': 1.6.1 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + web-streams-polyfill@4.0.0-beta.3: + resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} + engines: {node: '>= 14'} + + webextension-polyfill@0.10.0: + resolution: {integrity: sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==} + + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + + webidl-conversions@4.0.2: + resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + + whatwg-url@7.1.0: + resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + yaml@2.8.1: + resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} + engines: {node: '>= 14.6'} + hasBin: true + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yocto-queue@1.2.1: + resolution: {integrity: sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==} + engines: {node: '>=12.20'} + + zod-to-json-schema@3.24.6: + resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==} + peerDependencies: + zod: ^3.24.1 + + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + + '@anthropic-ai/sdk@0.51.0': {} + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.27.1': {} + + '@babel/parser@7.28.3': + dependencies: + '@babel/types': 7.28.2 + + '@babel/runtime@7.28.3': {} + + '@babel/types@7.28.2': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + + '@bcoe/v8-coverage@0.2.3': {} + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@esbuild/aix-ppc64@0.21.5': + optional: true + + '@esbuild/aix-ppc64@0.25.9': + optional: true + + '@esbuild/android-arm64@0.21.5': + optional: true + + '@esbuild/android-arm64@0.25.9': + optional: true + + '@esbuild/android-arm@0.21.5': + optional: true + + '@esbuild/android-arm@0.25.9': + optional: true + + '@esbuild/android-x64@0.21.5': + optional: true + + '@esbuild/android-x64@0.25.9': + optional: true + + '@esbuild/darwin-arm64@0.21.5': + optional: true + + '@esbuild/darwin-arm64@0.25.9': + optional: true + + '@esbuild/darwin-x64@0.21.5': + optional: true + + '@esbuild/darwin-x64@0.25.9': + optional: true + + '@esbuild/freebsd-arm64@0.21.5': + optional: true + + '@esbuild/freebsd-arm64@0.25.9': + optional: true + + '@esbuild/freebsd-x64@0.21.5': + optional: true + + '@esbuild/freebsd-x64@0.25.9': + optional: true + + '@esbuild/linux-arm64@0.21.5': + optional: true + + '@esbuild/linux-arm64@0.25.9': + optional: true + + '@esbuild/linux-arm@0.21.5': + optional: true + + '@esbuild/linux-arm@0.25.9': + optional: true + + '@esbuild/linux-ia32@0.21.5': + optional: true + + '@esbuild/linux-ia32@0.25.9': + optional: true + + '@esbuild/linux-loong64@0.21.5': + optional: true + + '@esbuild/linux-loong64@0.25.9': + optional: true + + '@esbuild/linux-mips64el@0.21.5': + optional: true + + '@esbuild/linux-mips64el@0.25.9': + optional: true + + '@esbuild/linux-ppc64@0.21.5': + optional: true + + '@esbuild/linux-ppc64@0.25.9': + optional: true + + '@esbuild/linux-riscv64@0.21.5': + optional: true + + '@esbuild/linux-riscv64@0.25.9': + optional: true + + '@esbuild/linux-s390x@0.21.5': + optional: true + + '@esbuild/linux-s390x@0.25.9': + optional: true + + '@esbuild/linux-x64@0.21.5': + optional: true + + '@esbuild/linux-x64@0.25.9': + optional: true + + '@esbuild/netbsd-arm64@0.25.9': + optional: true + + '@esbuild/netbsd-x64@0.21.5': + optional: true + + '@esbuild/netbsd-x64@0.25.9': + optional: true + + '@esbuild/openbsd-arm64@0.25.9': + optional: true + + '@esbuild/openbsd-x64@0.21.5': + optional: true + + '@esbuild/openbsd-x64@0.25.9': + optional: true + + '@esbuild/openharmony-arm64@0.25.9': + optional: true + + '@esbuild/sunos-x64@0.21.5': + optional: true + + '@esbuild/sunos-x64@0.25.9': + optional: true + + '@esbuild/win32-arm64@0.21.5': + optional: true + + '@esbuild/win32-arm64@0.25.9': + optional: true + + '@esbuild/win32-ia32@0.21.5': + optional: true + + '@esbuild/win32-ia32@0.25.9': + optional: true + + '@esbuild/win32-x64@0.21.5': + optional: true + + '@esbuild/win32-x64@0.25.9': + optional: true + + '@eslint-community/eslint-utils@4.7.0(eslint@8.57.1)': + dependencies: + eslint: 8.57.1 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/eslintrc@2.1.4': + dependencies: + ajv: 6.12.6 + debug: 4.4.1 + espree: 9.6.1 + globals: 13.24.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@8.57.1': {} + + '@gerrit0/mini-shiki@3.9.2': + dependencies: + '@shikijs/engine-oniguruma': 3.10.0 + '@shikijs/langs': 3.10.0 + '@shikijs/themes': 3.10.0 + '@shikijs/types': 3.10.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@google/genai@0.10.0': + dependencies: + google-auth-library: 9.15.1 + ws: 8.18.3 + zod: 3.25.76 + zod-to-json-schema: 3.24.6(zod@3.25.76) + transitivePeerDependencies: + - bufferutil + - encoding + - supports-color + - utf-8-validate + + '@humanwhocodes/config-array@0.13.0': + dependencies: + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.4.1 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/object-schema@2.0.3': {} + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jest/expect-utils@29.7.0': + dependencies: + jest-get-type: 29.6.3 + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.8 + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 20.19.11 + '@types/yargs': 17.0.33 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.30 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.30': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@lukeed/csprng@1.1.0': {} + + '@modelcontextprotocol/sdk@1.17.3': + dependencies: + ajv: 6.12.6 + content-type: 1.0.5 + cors: 2.8.5 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.0.5 + express: 5.1.0 + express-rate-limit: 7.5.1(express@5.1.0) + pkce-challenge: 5.0.0 + raw-body: 3.0.0 + zod: 3.25.76 + zod-to-json-schema: 3.24.6(zod@3.25.76) + transitivePeerDependencies: + - supports-color + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@playwright/test@1.54.2': + dependencies: + playwright: 1.54.2 + + '@rollup/rollup-android-arm-eabi@4.46.3': + optional: true + + '@rollup/rollup-android-arm64@4.46.3': + optional: true + + '@rollup/rollup-darwin-arm64@4.46.3': + optional: true + + '@rollup/rollup-darwin-x64@4.46.3': + optional: true + + '@rollup/rollup-freebsd-arm64@4.46.3': + optional: true + + '@rollup/rollup-freebsd-x64@4.46.3': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.46.3': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.46.3': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.46.3': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.46.3': + optional: true + + '@rollup/rollup-linux-loongarch64-gnu@4.46.3': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.46.3': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.46.3': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.46.3': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.46.3': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.46.3': + optional: true + + '@rollup/rollup-linux-x64-musl@4.46.3': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.46.3': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.46.3': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.46.3': + optional: true + + '@shikijs/engine-oniguruma@3.10.0': + dependencies: + '@shikijs/types': 3.10.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@3.10.0': + dependencies: + '@shikijs/types': 3.10.0 + + '@shikijs/themes@3.10.0': + dependencies: + '@shikijs/types': 3.10.0 + + '@shikijs/types@3.10.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + + '@sinclair/typebox@0.27.8': {} + + '@supabase/auth-js@2.71.1': + dependencies: + '@supabase/node-fetch': 2.6.15 + + '@supabase/functions-js@2.4.5': + dependencies: + '@supabase/node-fetch': 2.6.15 + + '@supabase/node-fetch@2.6.15': + dependencies: + whatwg-url: 5.0.0 + + '@supabase/postgrest-js@1.21.3': + dependencies: + '@supabase/node-fetch': 2.6.15 + + '@supabase/realtime-js@2.15.1': + dependencies: + '@supabase/node-fetch': 2.6.15 + '@types/phoenix': 1.6.6 + '@types/ws': 8.18.1 + ws: 8.18.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@supabase/storage-js@2.11.0': + dependencies: + '@supabase/node-fetch': 2.6.15 + + '@supabase/supabase-js@2.56.0': + dependencies: + '@supabase/auth-js': 2.71.1 + '@supabase/functions-js': 2.4.5 + '@supabase/node-fetch': 2.6.15 + '@supabase/postgrest-js': 1.21.3 + '@supabase/realtime-js': 2.15.1 + '@supabase/storage-js': 2.11.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@types/estree@1.0.8': {} + + '@types/hast@2.3.10': + dependencies: + '@types/unist': 2.0.11 + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/jest@29.5.14': + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + + '@types/json-schema@7.0.15': {} + + '@types/mathjs@9.4.2': + dependencies: + mathjs: 14.6.0 + + '@types/mustache@4.2.6': {} + + '@types/node-fetch@2.6.13': + dependencies: + '@types/node': 20.19.11 + form-data: 4.0.4 + + '@types/node@18.19.123': + dependencies: + undici-types: 5.26.5 + + '@types/node@20.19.11': + dependencies: + undici-types: 6.21.0 + + '@types/phoenix@1.6.6': {} + + '@types/react-syntax-highlighter@15.5.13': + dependencies: + '@types/react': 19.1.10 + + '@types/react@19.1.10': + dependencies: + csstype: 3.1.3 + + '@types/semver@7.7.0': {} + + '@types/stack-utils@2.0.3': {} + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@types/uuid@10.0.0': {} + + '@types/ws@8.18.1': + dependencies: + '@types/node': 20.19.11 + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.33': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@typescript-eslint/eslint-plugin@6.21.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.9.2) + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/type-utils': 6.21.0(eslint@8.57.1)(typescript@5.9.2) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.4.1 + eslint: 8.57.1 + graphemer: 1.4.0 + ignore: 5.3.2 + natural-compare: 1.4.0 + semver: 7.7.2 + ts-api-utils: 1.4.3(typescript@5.9.2) + optionalDependencies: + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.9.2)': + dependencies: + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.4.1 + eslint: 8.57.1 + optionalDependencies: + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@6.21.0': + dependencies: + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 + + '@typescript-eslint/type-utils@6.21.0(eslint@8.57.1)(typescript@5.9.2)': + dependencies: + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.9.2) + '@typescript-eslint/utils': 6.21.0(eslint@8.57.1)(typescript@5.9.2) + debug: 4.4.1 + eslint: 8.57.1 + ts-api-utils: 1.4.3(typescript@5.9.2) + optionalDependencies: + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@6.21.0': {} + + '@typescript-eslint/typescript-estree@6.21.0(typescript@5.9.2)': + dependencies: + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/visitor-keys': 6.21.0 + debug: 4.4.1 + globby: 11.1.0 + is-glob: 4.0.3 + minimatch: 9.0.3 + semver: 7.7.2 + ts-api-utils: 1.4.3(typescript@5.9.2) + optionalDependencies: + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@6.21.0(eslint@8.57.1)(typescript@5.9.2)': + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1) + '@types/json-schema': 7.0.15 + '@types/semver': 7.7.0 + '@typescript-eslint/scope-manager': 6.21.0 + '@typescript-eslint/types': 6.21.0 + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.9.2) + eslint: 8.57.1 + semver: 7.7.2 + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/visitor-keys@6.21.0': + dependencies: + '@typescript-eslint/types': 6.21.0 + eslint-visitor-keys: 3.4.3 + + '@ungap/structured-clone@1.3.0': {} + + '@vitest/coverage-v8@1.6.1(vitest@1.6.1(@types/node@20.19.11))': + dependencies: + '@ampproject/remapping': 2.3.0 + '@bcoe/v8-coverage': 0.2.3 + debug: 4.4.1 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + magic-string: 0.30.17 + magicast: 0.3.5 + picocolors: 1.1.1 + std-env: 3.9.0 + strip-literal: 2.1.1 + test-exclude: 6.0.0 + vitest: 1.6.1(@types/node@20.19.11) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@1.6.1': + dependencies: + '@vitest/spy': 1.6.1 + '@vitest/utils': 1.6.1 + chai: 4.5.0 + + '@vitest/runner@1.6.1': + dependencies: + '@vitest/utils': 1.6.1 + p-limit: 5.0.0 + pathe: 1.1.2 + + '@vitest/snapshot@1.6.1': + dependencies: + magic-string: 0.30.17 + pathe: 1.1.2 + pretty-format: 29.7.0 + + '@vitest/spy@1.6.1': + dependencies: + tinyspy: 2.2.1 + + '@vitest/utils@1.6.1': + dependencies: + diff-sequences: 29.6.3 + estree-walker: 3.0.3 + loupe: 2.3.7 + pretty-format: 29.7.0 + + '@webext-core/messaging@2.3.0': + dependencies: + serialize-error: 11.0.3 + uid: 2.0.2 + webextension-polyfill: 0.10.0 + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + accepts@2.0.0: + dependencies: + mime-types: 3.0.1 + negotiator: 1.0.0 + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn-walk@8.3.4: + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + agent-base@7.1.4: {} + + agentkeepalive@4.6.0: + dependencies: + humanize-ms: 1.2.1 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.0.6 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.0: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + ansi-styles@6.2.1: {} + + any-promise@1.3.0: {} + + arg@4.1.3: {} + + argparse@2.0.1: {} + + array-union@2.1.0: {} + + art-mcp-permission-manager@0.2.1: + dependencies: + '@webext-core/messaging': 2.3.0 + + assertion-error@1.1.0: {} + + asynckit@0.4.0: {} + + balanced-match@1.0.2: {} + + base64-js@1.5.1: {} + + bignumber.js@9.3.1: {} + + body-parser@2.2.0: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.1 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + on-finished: 2.4.1 + qs: 6.14.0 + raw-body: 3.0.0 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + buffer-equal-constant-time@1.0.1: {} + + bundle-require@5.1.0(esbuild@0.25.9): + dependencies: + esbuild: 0.25.9 + load-tsconfig: 0.2.5 + + bytes@3.1.2: {} + + cac@6.7.14: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + chai@4.5.0: + dependencies: + assertion-error: 1.1.0 + check-error: 1.0.3 + deep-eql: 4.1.4 + get-func-name: 2.0.2 + loupe: 2.3.7 + pathval: 1.1.1 + type-detect: 4.1.0 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + character-entities-legacy@1.1.4: {} + + character-entities@1.2.4: {} + + character-reference-invalid@1.1.4: {} + + check-error@1.0.3: + dependencies: + get-func-name: 2.0.2 + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + ci-info@3.9.0: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + comma-separated-tokens@1.0.8: {} + + commander@4.1.1: {} + + complex.js@2.4.2: {} + + concat-map@0.0.1: {} + + confbox@0.1.8: {} + + consola@3.4.2: {} + + content-disposition@1.0.0: + dependencies: + safe-buffer: 5.2.1 + + content-type@1.0.5: {} + + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + cors@2.8.5: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + create-require@1.1.1: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.1.3: {} + + debug@4.4.1: + dependencies: + ms: 2.1.3 + + decimal.js@10.6.0: {} + + deep-eql@4.1.4: + dependencies: + type-detect: 4.1.0 + + deep-is@0.1.4: {} + + delayed-stream@1.0.0: {} + + depd@2.0.0: {} + + diff-sequences@29.6.3: {} + + diff@4.0.2: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + doctrine@3.0.0: + dependencies: + esutils: 2.0.3 + + dotenv@16.6.1: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + + ee-first@1.1.1: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encodeurl@2.0.0: {} + + entities@4.5.0: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + esbuild@0.21.5: + optionalDependencies: + '@esbuild/aix-ppc64': 0.21.5 + '@esbuild/android-arm': 0.21.5 + '@esbuild/android-arm64': 0.21.5 + '@esbuild/android-x64': 0.21.5 + '@esbuild/darwin-arm64': 0.21.5 + '@esbuild/darwin-x64': 0.21.5 + '@esbuild/freebsd-arm64': 0.21.5 + '@esbuild/freebsd-x64': 0.21.5 + '@esbuild/linux-arm': 0.21.5 + '@esbuild/linux-arm64': 0.21.5 + '@esbuild/linux-ia32': 0.21.5 + '@esbuild/linux-loong64': 0.21.5 + '@esbuild/linux-mips64el': 0.21.5 + '@esbuild/linux-ppc64': 0.21.5 + '@esbuild/linux-riscv64': 0.21.5 + '@esbuild/linux-s390x': 0.21.5 + '@esbuild/linux-x64': 0.21.5 + '@esbuild/netbsd-x64': 0.21.5 + '@esbuild/openbsd-x64': 0.21.5 + '@esbuild/sunos-x64': 0.21.5 + '@esbuild/win32-arm64': 0.21.5 + '@esbuild/win32-ia32': 0.21.5 + '@esbuild/win32-x64': 0.21.5 + + esbuild@0.25.9: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.9 + '@esbuild/android-arm': 0.25.9 + '@esbuild/android-arm64': 0.25.9 + '@esbuild/android-x64': 0.25.9 + '@esbuild/darwin-arm64': 0.25.9 + '@esbuild/darwin-x64': 0.25.9 + '@esbuild/freebsd-arm64': 0.25.9 + '@esbuild/freebsd-x64': 0.25.9 + '@esbuild/linux-arm': 0.25.9 + '@esbuild/linux-arm64': 0.25.9 + '@esbuild/linux-ia32': 0.25.9 + '@esbuild/linux-loong64': 0.25.9 + '@esbuild/linux-mips64el': 0.25.9 + '@esbuild/linux-ppc64': 0.25.9 + '@esbuild/linux-riscv64': 0.25.9 + '@esbuild/linux-s390x': 0.25.9 + '@esbuild/linux-x64': 0.25.9 + '@esbuild/netbsd-arm64': 0.25.9 + '@esbuild/netbsd-x64': 0.25.9 + '@esbuild/openbsd-arm64': 0.25.9 + '@esbuild/openbsd-x64': 0.25.9 + '@esbuild/openharmony-arm64': 0.25.9 + '@esbuild/sunos-x64': 0.25.9 + '@esbuild/win32-arm64': 0.25.9 + '@esbuild/win32-ia32': 0.25.9 + '@esbuild/win32-x64': 0.25.9 + + escape-html@1.0.3: {} + + escape-latex@1.2.0: {} + + escape-string-regexp@2.0.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-scope@7.2.2: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint@8.57.1: + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1) + '@eslint-community/regexpp': 4.12.1 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.1 + '@humanwhocodes/config-array': 0.13.0 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.3.0 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.1 + doctrine: 3.0.0 + escape-string-regexp: 4.0.0 + eslint-scope: 7.2.2 + eslint-visitor-keys: 3.4.3 + espree: 9.6.1 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 6.0.1 + find-up: 5.0.0 + glob-parent: 6.0.2 + globals: 13.24.0 + graphemer: 1.4.0 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + is-path-inside: 3.0.3 + js-yaml: 4.1.0 + json-stable-stringify-without-jsonify: 1.0.1 + levn: 0.4.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + strip-ansi: 6.0.1 + text-table: 0.2.0 + transitivePeerDependencies: + - supports-color + + espree@9.6.1: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 3.4.3 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + esutils@2.0.3: {} + + etag@1.8.1: {} + + event-target-shim@5.0.1: {} + + eventsource-parser@3.0.5: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.0.5 + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + expect@29.7.0: + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + + express-rate-limit@7.5.1(express@5.1.0): + dependencies: + express: 5.1.0 + + express@5.1.0: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.0 + content-disposition: 1.0.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.1 + 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.1 + 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.2.0 + serve-static: 2.2.0 + statuses: 2.0.2 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + extend@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-uri@3.0.6: {} + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + fault@1.0.4: + dependencies: + format: 0.2.2 + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + file-entry-cache@6.0.1: + dependencies: + flat-cache: 3.2.0 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + finalhandler@2.1.0: + dependencies: + debug: 4.4.1 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + fix-dts-default-cjs-exports@1.0.1: + dependencies: + magic-string: 0.30.17 + mlly: 1.7.4 + rollup: 4.46.3 + + flat-cache@3.2.0: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + rimraf: 3.0.2 + + flatted@3.3.3: {} + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + form-data-encoder@1.7.2: {} + + form-data@4.0.4: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + format@0.2.2: {} + + formdata-node@4.4.1: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 4.0.0-beta.3 + + forwarded@0.2.0: {} + + fraction.js@5.3.1: {} + + fresh@2.0.0: {} + + fs.realpath@1.0.0: {} + + fsevents@2.3.2: + optional: true + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gaxios@6.7.1: + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6 + is-stream: 2.0.1 + node-fetch: 2.7.0 + uuid: 9.0.1 + transitivePeerDependencies: + - encoding + - supports-color + + gcp-metadata@6.1.1: + dependencies: + gaxios: 6.7.1 + google-logging-utils: 0.0.2 + json-bigint: 1.0.0 + transitivePeerDependencies: + - encoding + - supports-color + + get-func-name@2.0.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stream@8.0.1: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.4.5: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + globals@13.24.0: + dependencies: + type-fest: 0.20.2 + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + google-auth-library@9.15.1: + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 6.7.1 + gcp-metadata: 6.1.1 + gtoken: 7.1.0 + jws: 4.0.0 + transitivePeerDependencies: + - encoding + - supports-color + + google-logging-utils@0.0.2: {} + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + gtoken@7.1.0: + dependencies: + gaxios: 6.7.1 + jws: 4.0.0 + transitivePeerDependencies: + - encoding + - supports-color + + has-flag@4.0.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hast-util-parse-selector@2.2.5: {} + + hastscript@6.0.0: + dependencies: + '@types/hast': 2.3.10 + comma-separated-tokens: 1.0.8 + hast-util-parse-selector: 2.2.5 + property-information: 5.6.0 + space-separated-tokens: 1.1.5 + + highlight.js@10.7.3: {} + + highlightjs-vue@1.0.0: {} + + html-escaper@2.0.2: {} + + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + + human-signals@5.0.0: {} + + humanize-ms@1.2.1: + dependencies: + ms: 2.1.3 + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + ignore@5.3.2: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + ipaddr.js@1.9.1: {} + + is-alphabetical@1.0.4: {} + + is-alphanumerical@1.0.4: + dependencies: + is-alphabetical: 1.0.4 + is-decimal: 1.0.4 + + is-decimal@1.0.4: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-hexadecimal@1.0.4: {} + + is-number@7.0.0: {} + + is-path-inside@3.0.3: {} + + is-promise@4.0.0: {} + + is-stream@2.0.1: {} + + is-stream@3.0.0: {} + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.30 + debug: 4.4.1 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + javascript-natural-sort@0.7.1: {} + + jest-diff@29.7.0: + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-get-type@29.6.3: {} + + jest-matcher-utils@29.7.0: + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-message-util@29.7.0: + dependencies: + '@babel/code-frame': 7.27.1 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 20.19.11 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + joycon@3.1.1: {} + + js-tokens@4.0.0: {} + + js-tokens@9.0.1: {} + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + json-bigint@1.0.0: + dependencies: + bignumber.js: 9.3.1 + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + jwa@2.0.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@4.0.0: + dependencies: + jwa: 2.0.1 + safe-buffer: 5.2.1 + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lilconfig@3.1.3: {} + + lines-and-columns@1.2.4: {} + + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + + load-tsconfig@0.2.5: {} + + local-pkg@0.5.1: + dependencies: + mlly: 1.7.4 + pkg-types: 1.3.1 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lodash.sortby@4.7.0: {} + + loupe@2.3.7: + dependencies: + get-func-name: 2.0.2 + + lowlight@1.20.0: + dependencies: + fault: 1.0.4 + highlight.js: 10.7.3 + + lru-cache@10.4.3: {} + + lunr@2.3.9: {} + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magicast@0.3.5: + dependencies: + '@babel/parser': 7.28.3 + '@babel/types': 7.28.2 + source-map-js: 1.2.1 + + make-dir@4.0.0: + dependencies: + semver: 7.7.2 + + make-error@1.3.6: {} + + markdown-it@14.1.0: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + + math-intrinsics@1.1.0: {} + + mathjs@14.6.0: + dependencies: + '@babel/runtime': 7.28.3 + complex.js: 2.4.2 + decimal.js: 10.6.0 + escape-latex: 1.2.0 + fraction.js: 5.3.1 + javascript-natural-sort: 0.7.1 + seedrandom: 3.0.5 + tiny-emitter: 2.1.0 + typed-function: 4.2.1 + + mdurl@2.0.0: {} + + media-typer@1.1.0: {} + + merge-descriptors@2.0.0: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-db@1.54.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mime-types@3.0.1: + dependencies: + mime-db: 1.54.0 + + mimic-fn@4.0.0: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.12 + + minimatch@9.0.3: + dependencies: + brace-expansion: 2.0.2 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + + minipass@7.1.2: {} + + mlly@1.7.4: + dependencies: + acorn: 8.15.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.1 + + ms@2.1.3: {} + + mustache@4.2.0: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.11: {} + + natural-compare@1.4.0: {} + + negotiator@1.0.0: {} + + node-domexception@1.0.0: {} + + node-fetch@2.7.0: + dependencies: + whatwg-url: 5.0.0 + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + openai@4.104.0(ws@8.18.3)(zod@3.25.76): + dependencies: + '@types/node': 18.19.123 + '@types/node-fetch': 2.6.13 + abort-controller: 3.0.0 + agentkeepalive: 4.6.0 + form-data-encoder: 1.7.2 + formdata-node: 4.4.1 + node-fetch: 2.7.0 + optionalDependencies: + ws: 8.18.3 + zod: 3.25.76 + transitivePeerDependencies: + - encoding + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-limit@5.0.0: + dependencies: + yocto-queue: 1.2.1 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + package-json-from-dist@1.0.1: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-entities@2.0.0: + dependencies: + character-entities: 1.2.4 + character-entities-legacy: 1.1.4 + character-reference-invalid: 1.1.4 + is-alphanumerical: 1.0.4 + is-decimal: 1.0.4 + is-hexadecimal: 1.0.4 + + parseurl@1.3.3: {} + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + path-to-regexp@8.2.0: {} + + path-type@4.0.0: {} + + pathe@1.1.2: {} + + pathe@2.0.3: {} + + pathval@1.1.1: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + picomatch@4.0.3: {} + + pirates@4.0.7: {} + + pkce-challenge@5.0.0: {} + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.7.4 + pathe: 2.0.3 + + playwright-core@1.54.2: {} + + playwright@1.54.2: + dependencies: + playwright-core: 1.54.2 + optionalDependencies: + fsevents: 2.3.2 + + postcss-load-config@6.0.1(postcss@8.5.6)(yaml@2.8.1): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + postcss: 8.5.6 + yaml: 2.8.1 + + postcss@8.5.6: + dependencies: + nanoid: 3.3.11 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier@3.6.2: {} + + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + prismjs@1.27.0: {} + + prismjs@1.30.0: {} + + property-information@5.6.0: + dependencies: + xtend: 4.0.2 + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + punycode.js@2.3.1: {} + + punycode@2.3.1: {} + + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + + queue-microtask@1.2.3: {} + + range-parser@1.2.1: {} + + raw-body@3.0.0: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + unpipe: 1.0.0 + + react-is@18.3.1: {} + + react-syntax-highlighter@15.6.1(react@19.1.1): + dependencies: + '@babel/runtime': 7.28.3 + highlight.js: 10.7.3 + highlightjs-vue: 1.0.0 + lowlight: 1.20.0 + prismjs: 1.30.0 + react: 19.1.1 + refractor: 3.6.0 + + react@19.1.1: {} + + readdirp@4.1.2: {} + + reconnecting-eventsource@1.6.4: {} + + refractor@3.6.0: + dependencies: + hastscript: 6.0.0 + parse-entities: 2.0.0 + prismjs: 1.27.0 + + require-from-string@2.0.2: {} + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + reusify@1.1.0: {} + + rimraf@3.0.2: + dependencies: + glob: 7.2.3 + + rollup@4.46.3: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.46.3 + '@rollup/rollup-android-arm64': 4.46.3 + '@rollup/rollup-darwin-arm64': 4.46.3 + '@rollup/rollup-darwin-x64': 4.46.3 + '@rollup/rollup-freebsd-arm64': 4.46.3 + '@rollup/rollup-freebsd-x64': 4.46.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.46.3 + '@rollup/rollup-linux-arm-musleabihf': 4.46.3 + '@rollup/rollup-linux-arm64-gnu': 4.46.3 + '@rollup/rollup-linux-arm64-musl': 4.46.3 + '@rollup/rollup-linux-loongarch64-gnu': 4.46.3 + '@rollup/rollup-linux-ppc64-gnu': 4.46.3 + '@rollup/rollup-linux-riscv64-gnu': 4.46.3 + '@rollup/rollup-linux-riscv64-musl': 4.46.3 + '@rollup/rollup-linux-s390x-gnu': 4.46.3 + '@rollup/rollup-linux-x64-gnu': 4.46.3 + '@rollup/rollup-linux-x64-musl': 4.46.3 + '@rollup/rollup-win32-arm64-msvc': 4.46.3 + '@rollup/rollup-win32-ia32-msvc': 4.46.3 + '@rollup/rollup-win32-x64-msvc': 4.46.3 + fsevents: 2.3.3 + + router@2.2.0: + dependencies: + debug: 4.4.1 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.2.0 + transitivePeerDependencies: + - supports-color + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + seedrandom@3.0.5: {} + + semver@7.7.2: {} + + send@1.2.0: + dependencies: + debug: 4.4.1 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.0 + mime-types: 3.0.1 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serialize-error@11.0.3: + dependencies: + type-fest: 2.19.0 + + serve-static@2.2.0: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.0 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + siginfo@2.0.0: {} + + signal-exit@4.1.0: {} + + slash@3.0.0: {} + + source-map-js@1.2.1: {} + + source-map@0.8.0-beta.0: + dependencies: + whatwg-url: 7.1.0 + + space-separated-tokens@1.1.5: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + stackback@0.0.2: {} + + statuses@2.0.1: {} + + statuses@2.0.2: {} + + std-env@3.9.0: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.2.0 + + strip-final-newline@3.0.0: {} + + strip-json-comments@3.1.1: {} + + strip-literal@2.1.1: + dependencies: + js-tokens: 9.0.1 + + sucrase@3.35.0: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + glob: 10.4.5 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + ts-interface-checker: 0.1.13 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + + text-table@0.2.0: {} + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + tiny-emitter@2.1.0: {} + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.14: + dependencies: + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + + tinypool@0.8.4: {} + + tinyspy@2.2.1: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + tr46@0.0.3: {} + + tr46@1.0.1: + dependencies: + punycode: 2.3.1 + + tree-kill@1.2.2: {} + + ts-api-utils@1.4.3(typescript@5.9.2): + dependencies: + typescript: 5.9.2 + + ts-interface-checker@0.1.13: {} + + ts-node@10.9.2(@types/node@20.19.11)(typescript@5.9.2): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 20.19.11 + acorn: 8.15.0 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.9.2 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + tsup@8.5.0(postcss@8.5.6)(typescript@5.9.2)(yaml@2.8.1): + dependencies: + bundle-require: 5.1.0(esbuild@0.25.9) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.1 + esbuild: 0.25.9 + fix-dts-default-cjs-exports: 1.0.1 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(postcss@8.5.6)(yaml@2.8.1) + resolve-from: 5.0.0 + rollup: 4.46.3 + source-map: 0.8.0-beta.0 + sucrase: 3.35.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.14 + tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.5.6 + typescript: 5.9.2 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-detect@4.1.0: {} + + type-fest@0.20.2: {} + + type-fest@2.19.0: {} + + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.1 + + typed-function@4.2.1: {} + + typedoc-plugin-markdown@4.8.1(typedoc@0.28.10(typescript@5.9.2)): + dependencies: + typedoc: 0.28.10(typescript@5.9.2) + + typedoc@0.28.10(typescript@5.9.2): + dependencies: + '@gerrit0/mini-shiki': 3.9.2 + lunr: 2.3.9 + markdown-it: 14.1.0 + minimatch: 9.0.5 + typescript: 5.9.2 + yaml: 2.8.1 + + typescript@5.9.2: {} + + uc.micro@2.1.0: {} + + ufo@1.6.1: {} + + uid@2.0.2: + dependencies: + '@lukeed/csprng': 1.1.0 + + undici-types@5.26.5: {} + + undici-types@6.21.0: {} + + unpipe@1.0.0: {} + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + uuid@9.0.1: {} + + v8-compile-cache-lib@3.0.1: {} + + vary@1.1.2: {} + + vite-node@1.6.1(@types/node@20.19.11): + dependencies: + cac: 6.7.14 + debug: 4.4.1 + pathe: 1.1.2 + picocolors: 1.1.1 + vite: 5.4.19(@types/node@20.19.11) + transitivePeerDependencies: + - '@types/node' + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + vite@5.4.19(@types/node@20.19.11): + dependencies: + esbuild: 0.21.5 + postcss: 8.5.6 + rollup: 4.46.3 + optionalDependencies: + '@types/node': 20.19.11 + fsevents: 2.3.3 + + vitest@1.6.1(@types/node@20.19.11): + dependencies: + '@vitest/expect': 1.6.1 + '@vitest/runner': 1.6.1 + '@vitest/snapshot': 1.6.1 + '@vitest/spy': 1.6.1 + '@vitest/utils': 1.6.1 + acorn-walk: 8.3.4 + chai: 4.5.0 + debug: 4.4.1 + execa: 8.0.1 + local-pkg: 0.5.1 + magic-string: 0.30.17 + pathe: 1.1.2 + picocolors: 1.1.1 + std-env: 3.9.0 + strip-literal: 2.1.1 + tinybench: 2.9.0 + tinypool: 0.8.4 + vite: 5.4.19(@types/node@20.19.11) + vite-node: 1.6.1(@types/node@20.19.11) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/node': 20.19.11 + transitivePeerDependencies: + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + + web-streams-polyfill@4.0.0-beta.3: {} + + webextension-polyfill@0.10.0: {} + + webidl-conversions@3.0.1: {} + + webidl-conversions@4.0.2: {} + + whatwg-url@5.0.0: + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + + whatwg-url@7.1.0: + dependencies: + lodash.sortby: 4.7.0 + tr46: 1.0.1 + webidl-conversions: 4.0.2 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + word-wrap@1.2.5: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + wrappy@1.0.2: {} + + ws@8.18.3: {} + + xtend@4.0.2: {} + + yaml@2.8.1: {} + + yn@3.1.1: {} + + yocto-queue@0.1.0: {} + + yocto-queue@1.2.1: {} + + zod-to-json-schema@3.24.6(zod@3.25.76): + dependencies: + zod: 3.25.76 + + zod@3.25.76: {} diff --git a/src/adapters/reasoning/anthropic.test.ts b/src/adapters/reasoning/anthropic.test.ts deleted file mode 100644 index 68e12ab..0000000 --- a/src/adapters/reasoning/anthropic.test.ts +++ /dev/null @@ -1,219 +0,0 @@ -// src/adapters/reasoning/anthropic.test.ts -import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'; -import { AnthropicAdapter, AnthropicAdapterOptions } from './anthropic'; -import { Logger } from '../../utils/logger'; -import { CallOptions } from '../../types'; - -// Mock Logger -vi.mock('../../utils/logger', () => ({ - Logger: { - warn: vi.fn(), - error: vi.fn(), - info: vi.fn(), - debug: vi.fn(), - configure: vi.fn(), - }, -})); - -// Mock global fetch -const mockFetch = vi.fn(); -global.fetch = mockFetch; - -describe('AnthropicAdapter', () => { - let adapter: AnthropicAdapter; - const defaultOptions: AnthropicAdapterOptions = { apiKey: 'test-anthropic-key' }; - const defaultCallOptions: CallOptions = { threadId: 't-anthropic' }; - const defaultMaxTokens = 1024; // From adapter implementation - - beforeEach(() => { - adapter = new AnthropicAdapter(defaultOptions); - vi.clearAllMocks(); // Clear mocks including fetch and Logger - }); - - afterEach(() => { - vi.restoreAllMocks(); // Ensure fetch mock doesn't leak - }); - - it('should throw error if API key is missing', () => { - expect(() => new AnthropicAdapter({} as AnthropicAdapterOptions)).toThrow('Anthropic API key is required.'); - }); - - it('should initialize with default model and API version if not provided', () => { - expect((adapter as any).model).toBe('claude-3-haiku-20240307'); - expect((adapter as any).apiVersion).toBe('2023-06-01'); - expect((adapter as any).apiBaseUrl).toBe('https://api.anthropic.com/v1'); - expect(Logger.debug).toHaveBeenCalledWith('AnthropicAdapter initialized with model: claude-3-haiku-20240307, version: 2023-06-01'); - }); - - it('should initialize with provided model, version, and apiBaseUrl', () => { - const opts: AnthropicAdapterOptions = { apiKey: 'key', model: 'claude-3-opus-20240229', apiVersion: '2024-01-01', apiBaseUrl: 'http://localhost:8082' }; - const customAdapter = new AnthropicAdapter(opts); - expect((customAdapter as any).model).toBe('claude-3-opus-20240229'); - expect((customAdapter as any).apiVersion).toBe('2024-01-01'); - expect((customAdapter as any).apiBaseUrl).toBe('http://localhost:8082'); - }); - - it('should make a successful API call with basic prompt', async () => { - const mockResponse = { - id: 'msg_123', type: 'message', role: 'assistant', model: 'claude-3...', - content: [{ type: 'text', text: ' Anthropic says hello! ' }], - stop_reason: 'end_turn', stop_sequence: null, usage: { input_tokens: 10, output_tokens: 5 }, - }; - mockFetch.mockResolvedValueOnce({ - ok: true, - json: async () => mockResponse, - status: 200, - statusText: 'OK', - }); - - const prompt = 'Say hello'; - const result = await adapter.call(prompt, defaultCallOptions); - - expect(result).toBe('Anthropic says hello!'); // Should be trimmed - expect(mockFetch).toHaveBeenCalledOnce(); - const expectedUrl = `https://api.anthropic.com/v1/messages`; - expect(mockFetch).toHaveBeenCalledWith( - expectedUrl, - expect.objectContaining({ - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': defaultOptions.apiKey, - 'anthropic-version': '2023-06-01', - }, - body: JSON.stringify({ - model: 'claude-3-haiku-20240307', - messages: [{ role: 'user', content: prompt }], - max_tokens: defaultMaxTokens, // Default max_tokens - }), - }) - ); - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining('Calling Anthropic API'), expect.anything()); - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining('Anthropic API call successful'), expect.anything()); - }); - - it('should handle non-string prompt by coercing to string', async () => { - const mockResponse = { content: [{ type: 'text', text: 'Processed object.' }] }; - mockFetch.mockResolvedValueOnce({ ok: true, json: async () => mockResponse }); - const prompt = { value: true }; // Non-string prompt - await adapter.call(prompt as any, defaultCallOptions); // Cast to any for test - - expect(Logger.warn).toHaveBeenCalledWith('AnthropicAdapter received non-string prompt. Treating as string.'); - expect(mockFetch).toHaveBeenCalledWith( - expect.any(String), - expect.objectContaining({ - body: JSON.stringify({ - model: 'claude-3-haiku-20240307', - messages: [{ role: 'user', content: '[object Object]' }], // Default string coercion - max_tokens: defaultMaxTokens, - }), - }) - ); - }); - - it('should include optional parameters in the API call payload', async () => { - const mockResponse = { content: [{ type: 'text', text: 'Response with params.' }] }; - mockFetch.mockResolvedValueOnce({ ok: true, json: async () => mockResponse }); - - const callOptions: CallOptions = { - ...defaultCallOptions, - temperature: 0.7, - max_tokens: 500, // Explicitly set max_tokens - topP: 0.8, - topK: 40, - stopSequences: ['\nHuman:'], - system: 'You are a helpful bot.', // System prompt - }; - await adapter.call('Test params', callOptions); - - expect(mockFetch).toHaveBeenCalledWith( - expect.any(String), - expect.objectContaining({ - body: JSON.stringify({ - model: 'claude-3-haiku-20240307', - messages: [{ role: 'user', content: 'Test params' }], - system: 'You are a helpful bot.', - max_tokens: 500, - temperature: 0.7, - top_p: 0.8, - top_k: 40, - stop_sequences: ['\nHuman:'], - }), - }) - ); - }); - - it('should use default max_tokens if not provided in options', async () => { - const mockResponse = { content: [{ type: 'text', text: 'Response default tokens.' }] }; - mockFetch.mockResolvedValueOnce({ ok: true, json: async () => mockResponse }); - - await adapter.call('Test default tokens', defaultCallOptions); // No max_tokens in options - - expect(mockFetch).toHaveBeenCalledWith( - expect.any(String), - expect.objectContaining({ - body: expect.stringContaining(`"max_tokens":${defaultMaxTokens}`), // Check default is used - }) - ); - }); - - - it('should handle API error response (non-200 status) with JSON body', async () => { - const errorBody = JSON.stringify({ type: 'error', error: { type: 'invalid_request_error', message: 'Invalid API key.' } }); - mockFetch.mockResolvedValueOnce({ - ok: false, - text: async () => errorBody, - json: async () => JSON.parse(errorBody), // Mock json() as well if needed - status: 401, - statusText: 'Unauthorized', - }); - - await expect(adapter.call('Test API error', defaultCallOptions)).rejects.toThrow( - 'Anthropic API request failed: 401 Unauthorized - Invalid API key.' // Parsed message - ); - expect(Logger.error).toHaveBeenCalledWith( - expect.stringContaining('Anthropic API request failed with status 401'), - expect.anything() - ); - }); - - it('should handle API error response (non-200 status) with non-JSON body', async () => { - const errorBody = 'Internal Server Error'; - mockFetch.mockResolvedValueOnce({ - ok: false, - text: async () => errorBody, - status: 500, - statusText: 'Internal Server Error', - }); - - await expect(adapter.call('Test API error non-json', defaultCallOptions)).rejects.toThrow( - 'Anthropic API request failed: 500 Internal Server Error - Internal Server Error' // Raw text body - ); - }); - - it('should handle invalid response structure (missing text content)', async () => { - const invalidResponse = { content: [{ type: 'other', value: '...' }] }; // No text content - mockFetch.mockResolvedValueOnce({ ok: true, json: async () => invalidResponse }); - - await expect(adapter.call('Test invalid structure', defaultCallOptions)).rejects.toThrow( - 'Invalid response structure from Anthropic API: No text content found.' - ); - expect(Logger.error).toHaveBeenCalledWith( - 'Invalid response structure from Anthropic API: No text content found', - expect.objectContaining({ responseData: invalidResponse }) - ); - }); - - it('should handle fetch network error', async () => { - const networkError = new Error('Network connection failed'); - mockFetch.mockRejectedValueOnce(networkError); - - await expect(adapter.call('Test network error', defaultCallOptions)).rejects.toThrow('Network connection failed'); - expect(Logger.error).toHaveBeenCalledWith( - 'Error during Anthropic API call: Network connection failed', - expect.objectContaining({ error: networkError }) - ); - }); - - // TODO: Add tests for system prompt and history handling once implemented -}); \ No newline at end of file diff --git a/src/adapters/reasoning/deepseek.test.ts b/src/adapters/reasoning/deepseek.test.ts deleted file mode 100644 index 9d1acd8..0000000 --- a/src/adapters/reasoning/deepseek.test.ts +++ /dev/null @@ -1,161 +0,0 @@ -// src/adapters/reasoning/deepseek.test.ts -import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'; -import { DeepSeekAdapter, DeepSeekAdapterOptions } from './deepseek'; -import { Logger } from '../../utils/logger'; -import { CallOptions } from '../../types'; - -// Mock Logger -vi.mock('../../utils/logger', () => ({ - Logger: { - warn: vi.fn(), - error: vi.fn(), - info: vi.fn(), - debug: vi.fn(), - configure: vi.fn(), - }, -})); - -// Mock global fetch -const mockFetch = vi.fn(); -global.fetch = mockFetch; - -describe('DeepSeekAdapter', () => { - let adapter: DeepSeekAdapter; - const defaultOptions: DeepSeekAdapterOptions = { apiKey: 'test-deepseek-key' }; - const defaultCallOptions: CallOptions = { threadId: 't-deepseek' }; - - beforeEach(() => { - adapter = new DeepSeekAdapter(defaultOptions); - vi.clearAllMocks(); // Clear mocks including fetch and Logger - }); - - afterEach(() => { - vi.restoreAllMocks(); // Ensure fetch mock doesn't leak - }); - - it('should throw error if API key is missing', () => { - expect(() => new DeepSeekAdapter({} as DeepSeekAdapterOptions)).toThrow('DeepSeek API key is required.'); - }); - - it('should initialize with default model and apiBaseUrl if not provided', () => { - expect((adapter as any).model).toBe('deepseek-chat'); - expect((adapter as any).apiBaseUrl).toBe('https://api.deepseek.com/v1'); - expect(Logger.debug).toHaveBeenCalledWith('DeepSeekAdapter initialized with model: deepseek-chat'); - }); - - it('should initialize with provided model and apiBaseUrl', () => { - const opts: DeepSeekAdapterOptions = { apiKey: 'key', model: 'deepseek-coder', apiBaseUrl: 'http://localhost:8084' }; - const customAdapter = new DeepSeekAdapter(opts); - expect((customAdapter as any).model).toBe('deepseek-coder'); - expect((customAdapter as any).apiBaseUrl).toBe('http://localhost:8084'); - }); - - it('should make a successful API call with basic prompt', async () => { - const mockResponse = { - id: 'ds-123', object: 'chat.completion', created: 1677652288, model: 'deepseek-chat', - choices: [{ index: 0, message: { role: 'assistant', content: ' DeepSeek says hello! ' }, finish_reason: 'stop' }], - usage: { prompt_tokens: 9, completion_tokens: 12, total_tokens: 21 }, - }; - mockFetch.mockResolvedValueOnce({ - ok: true, - json: async () => mockResponse, - status: 200, - statusText: 'OK', - }); - - const prompt = 'Say hello'; - const result = await adapter.call(prompt, defaultCallOptions); - - expect(result).toBe('DeepSeek says hello!'); // Should be trimmed - expect(mockFetch).toHaveBeenCalledOnce(); - const expectedUrl = `https://api.deepseek.com/v1/chat/completions`; - expect(mockFetch).toHaveBeenCalledWith( - expectedUrl, - expect.objectContaining({ - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${defaultOptions.apiKey}`, - }, - body: JSON.stringify({ - model: 'deepseek-chat', - messages: [{ role: 'user', content: prompt }], - }), - }) - ); - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining('Calling DeepSeek API'), expect.anything()); - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining('DeepSeek API call successful'), expect.anything()); - }); - - it('should include optional parameters in the API call payload', async () => { - const mockResponse = { choices: [{ message: { content: 'Response with params.' } }] }; - mockFetch.mockResolvedValueOnce({ ok: true, json: async () => mockResponse }); - - const callOptions: CallOptions = { - ...defaultCallOptions, - temperature: 0.6, - max_tokens: 600, - topP: 0.7, // Test alias - stop: ['\nObservation:'], // Test alias - }; - await adapter.call('Test params', callOptions); - - expect(mockFetch).toHaveBeenCalledWith( - expect.any(String), - expect.objectContaining({ - body: JSON.stringify({ - model: 'deepseek-chat', - messages: [{ role: 'user', content: 'Test params' }], - temperature: 0.6, - max_tokens: 600, - top_p: 0.7, - stop: ['\nObservation:'], - }), - }) - ); - }); - - it('should handle API error response (non-200 status)', async () => { - const errorBody = JSON.stringify({ error: { message: 'Authentication error.' } }); - mockFetch.mockResolvedValueOnce({ - ok: false, - text: async () => errorBody, - status: 401, - statusText: 'Unauthorized', - }); - - await expect(adapter.call('Test API error', defaultCallOptions)).rejects.toThrow( - 'DeepSeek API request failed: 401 Unauthorized - Authentication error.' // Parsed message - ); - expect(Logger.error).toHaveBeenCalledWith( - expect.stringContaining('DeepSeek API request failed with status 401'), - expect.anything() - ); - }); - - it('should handle invalid response structure (missing content)', async () => { - const invalidResponse = { choices: [{ message: {} }] }; // Missing content - mockFetch.mockResolvedValueOnce({ ok: true, json: async () => invalidResponse }); - - await expect(adapter.call('Test invalid structure', defaultCallOptions)).rejects.toThrow( - 'Invalid response structure from DeepSeek API: No content found.' - ); - expect(Logger.error).toHaveBeenCalledWith( - 'Invalid response structure from DeepSeek API', - expect.objectContaining({ responseData: invalidResponse }) - ); - }); - - it('should handle fetch network error', async () => { - const networkError = new Error('Network connection failed'); - mockFetch.mockRejectedValueOnce(networkError); - - await expect(adapter.call('Test network error', defaultCallOptions)).rejects.toThrow('Network connection failed'); - expect(Logger.error).toHaveBeenCalledWith( - 'Error during DeepSeek API call: Network connection failed', - expect.objectContaining({ error: networkError }) - ); - }); - - // Other tests like non-string prompt handling would be similar -}); \ No newline at end of file diff --git a/src/adapters/reasoning/gemini.test.ts b/src/adapters/reasoning/gemini.test.ts deleted file mode 100644 index 280fe74..0000000 --- a/src/adapters/reasoning/gemini.test.ts +++ /dev/null @@ -1,372 +0,0 @@ -// src/adapters/reasoning/gemini.test.ts -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { GeminiAdapter, GeminiAdapterOptions } from './gemini'; -import { Logger } from '../../utils/logger'; -import { CallOptions, ArtStandardPrompt, StreamEvent } from '../../types'; // Removed LLMMetadata -import { GoogleGenAI } from '@google/genai'; // Import SDK for mocking -import { ARTError, ErrorCode } from '../../errors'; - -// Mock Logger -vi.mock('../../utils/logger', () => ({ - Logger: { - warn: vi.fn(), - error: vi.fn(), - info: vi.fn(), - debug: vi.fn(), - configure: vi.fn(), - }, -})); - -// Mock the @google/genai SDK -const mockGenerateContent = vi.fn(); -const mockGenerateContentStream = vi.fn(); -const mockModels = { - generateContent: mockGenerateContent, - generateContentStream: mockGenerateContentStream, -}; -const mockGenAIInstance = { - models: mockModels, -}; - -vi.mock('@google/genai', () => ({ - GoogleGenAI: vi.fn(() => mockGenAIInstance), // Mock constructor to return our instance -})); - - -describe('GeminiAdapter (Refactored)', () => { - let adapter: GeminiAdapter; - const defaultOptions: GeminiAdapterOptions = { apiKey: 'test-gemini-key' }; - const defaultCallOptions: CallOptions = { threadId: 't-gemini' }; - - beforeEach(() => { - vi.clearAllMocks(); // Clear all mocks before each test - adapter = new GeminiAdapter(defaultOptions); - }); - - it('should throw error if API key is missing', () => { - // Need to clear the mock constructor for this specific test - (GoogleGenAI as any).mockImplementationOnce(() => { throw new Error('Simulated constructor error'); }); - expect(() => new GeminiAdapter({} as GeminiAdapterOptions)).toThrow('GeminiAdapter requires an apiKey in options.'); - }); - - it('should initialize with default model', () => { - expect((adapter as any).defaultModel).toBe('gemini-1.5-flash-latest'); - expect(GoogleGenAI).toHaveBeenCalledWith({ apiKey: 'test-gemini-key' }); - expect(Logger.debug).toHaveBeenCalledWith('GeminiAdapter initialized with default model: gemini-1.5-flash-latest'); - }); - - it('should initialize with provided model', () => { - const opts: GeminiAdapterOptions = { apiKey: 'key', model: 'gemini-pro' }; - const customAdapter = new GeminiAdapter(opts); - expect((customAdapter as any).defaultModel).toBe('gemini-pro'); - }); - - // --- Non-Streaming Tests --- - describe('call (non-streaming)', () => { - it('should translate basic ArtStandardPrompt and call generateContent', async () => { - const mockApiResponse = { - text: () => 'Gemini says hello!', // Simplified mock response - candidates: [{ finishReason: 'STOP' }], - usageMetadata: { promptTokenCount: 10, candidatesTokenCount: 5 }, - }; - mockGenerateContent.mockResolvedValueOnce(mockApiResponse); - - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Say hello' }]; - const resultStream = await adapter.call(prompt, defaultCallOptions); - const results = await consumeStream(resultStream); - - expect(mockGenerateContent).toHaveBeenCalledOnce(); - expect(mockGenerateContent).toHaveBeenCalledWith({ - model: 'gemini-1.5-flash-latest', - contents: [{ role: 'user', parts: [{ text: 'Say hello' }] }], - config: {}, // Empty config by default - }); - - expect(results.find(e => e.type === 'TOKEN')?.data).toBe('Gemini says hello!'); - expect(results.find(e => e.type === 'METADATA')?.data).toMatchObject({ - stopReason: 'STOP', - inputTokens: 10, - outputTokens: 5, - }); - expect(results.some(e => e.type === 'END')).toBe(true); - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining('Calling Gemini SDK'), expect.anything()); - }); - - it('should translate ArtStandardPrompt with system prompt and history', async () => { - const mockApiResponse = { text: () => 'Understood history.' }; - mockGenerateContent.mockResolvedValueOnce(mockApiResponse); - - const prompt: ArtStandardPrompt = [ - { role: 'system', content: 'You are helpful.' }, - { role: 'user', content: 'First message' }, - { role: 'assistant', content: 'My response' }, - { role: 'user', content: 'Second message' }, - ]; - await consumeStream(await adapter.call(prompt, defaultCallOptions)); - - expect(mockGenerateContent).toHaveBeenCalledWith(expect.objectContaining({ - contents: [ - { role: 'user', parts: [{ text: 'You are helpful.\n\nFirst message' }] }, // System merged - { role: 'model', parts: [{ text: 'My response' }] }, - { role: 'user', parts: [{ text: 'Second message' }] }, - ], - })); - }); - - it('should translate ArtStandardPrompt with tool calls', async () => { - const mockApiResponse = { - text: () => '', // No text response when requesting tools - candidates: [{ - content: { - role: 'model', - parts: [{ functionCall: { name: 'calculator', args: { expression: '2+2' } } }] - }, - finishReason: 'TOOL_USE', // Or similar - }], - usageMetadata: { promptTokenCount: 20, candidatesTokenCount: 10 }, - }; - mockGenerateContent.mockResolvedValueOnce(mockApiResponse); - - const prompt: ArtStandardPrompt = [ - { role: 'user', content: 'What is 2+2?' }, - { - role: 'assistant', - content: null, // No text content - tool_calls: [{ - id: 'call_123', - type: 'function', - function: { name: 'calculator', arguments: '{"expression":"2+2"}' } - }] - } - ]; - // We don't consume the stream here, just check the call to generateContent - await adapter.call(prompt, defaultCallOptions); - - expect(mockGenerateContent).toHaveBeenCalledWith(expect.objectContaining({ - contents: [ - { role: 'user', parts: [{ text: 'What is 2+2?' }] }, - { role: 'model', parts: [{ functionCall: { name: 'calculator', args: { expression: '2+2' } } }] } - ], - })); - // Note: The adapter's `call` method itself doesn't return the raw tool call structure, - // it yields stream events. The test verifies the input to the SDK. - // A full E2E test would verify the agent correctly handles the LLM response containing tool calls. - }); - - it('should translate ArtStandardPrompt with tool results', async () => { - const mockApiResponse = { text: () => 'The result is 4.' }; - mockGenerateContent.mockResolvedValueOnce(mockApiResponse); - - const prompt: ArtStandardPrompt = [ - { role: 'user', content: 'What is 2+2?' }, - { - role: 'assistant', - content: null, - tool_calls: [{ id: 'call_abc', type: 'function', function: { name: 'calculator', arguments: '{"expression":"2+2"}' } }] - }, - { - role: 'tool_result', - tool_call_id: 'call_abc', - name: 'calculator', - content: '4' // Stringified result - } - ]; - await consumeStream(await adapter.call(prompt, defaultCallOptions)); - - expect(mockGenerateContent).toHaveBeenCalledWith(expect.objectContaining({ - contents: [ - { role: 'user', parts: [{ text: 'What is 2+2?' }] }, - { role: 'model', parts: [{ functionCall: { name: 'calculator', args: { expression: '2+2' } } }] }, - { role: 'user', parts: [{ functionResponse: { name: 'calculator', response: { content: '4' } } }] } // Tool result mapped to user role with functionResponse - ], - })); - }); - - - it('should include optional generation parameters', async () => { - const mockApiResponse = { text: () => 'Response with params.' }; - mockGenerateContent.mockResolvedValueOnce(mockApiResponse); - - const callOptions: CallOptions = { - ...defaultCallOptions, - temperature: 0.6, - maxOutputTokens: 150, // Use camelCase for SDK - topP: 0.9, - stopSequences: ['\nObservation:'], - }; - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Test params' }]; - await consumeStream(await adapter.call(prompt, callOptions)); - - expect(mockGenerateContent).toHaveBeenCalledWith(expect.objectContaining({ - config: { - temperature: 0.6, - maxOutputTokens: 150, - topP: 0.9, - stopSequences: ['\nObservation:'], - }, - })); - }); - - it('should handle SDK error during generateContent', async () => { - const sdkError = new Error('Invalid API Key'); - mockGenerateContent.mockRejectedValueOnce(sdkError); - - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Test SDK error' }]; - const resultStream = await adapter.call(prompt, defaultCallOptions); - const results = await consumeStream(resultStream); - - expect(results.find(e => e.type === 'ERROR')?.data).toBe(sdkError); - expect(results.some(e => e.type === 'END')).toBe(true); - expect(Logger.error).toHaveBeenCalledWith( - expect.stringContaining('Error during Gemini SDK call: Invalid API Key'), - expect.anything() - ); - }); - - it('should handle blocked content response from SDK', async () => { - const blockedResponse = { - text: () => '', // No text - promptFeedback: { blockReason: 'SAFETY' }, // Block reason provided - candidates: [], // No candidates - }; - mockGenerateContent.mockResolvedValueOnce(blockedResponse); - - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Risky prompt' }]; - const resultStream = await adapter.call(prompt, defaultCallOptions); - const results = await consumeStream(resultStream); - - const errorEvent = results.find(e => e.type === 'ERROR'); - expect(errorEvent).toBeDefined(); - expect(errorEvent?.data).toBeInstanceOf(Error); - expect((errorEvent?.data as Error).message).toContain('Gemini API call blocked: SAFETY'); - expect(results.some(e => e.type === 'END')).toBe(true); - expect(Logger.error).toHaveBeenCalledWith('Gemini SDK call blocked.', expect.anything()); - }); - - it('should handle invalid response structure (no text/candidate) from SDK', async () => { - const invalidResponse = { - text: () => undefined, // No text method or returns undefined - candidates: [], // No candidates - }; - mockGenerateContent.mockResolvedValueOnce(invalidResponse); - - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Weird prompt' }]; - const resultStream = await adapter.call(prompt, defaultCallOptions); - const results = await consumeStream(resultStream); - - const errorEvent = results.find(e => e.type === 'ERROR'); - expect(errorEvent).toBeDefined(); - expect(errorEvent?.data).toBeInstanceOf(Error); - expect((errorEvent?.data as Error).message).toContain('Invalid response structure from Gemini SDK: No text content found'); - expect(results.some(e => e.type === 'END')).toBe(true); - expect(Logger.error).toHaveBeenCalledWith('Invalid response structure from Gemini SDK: No text content found', expect.anything()); - }); - - it('should yield error if translation fails', async () => { - const invalidPrompt: ArtStandardPrompt = [ - { role: 'tool_result', content: 'Result', name: undefined, tool_call_id: undefined } // Missing required fields - ]; - - const resultStream = await adapter.call(invalidPrompt, defaultCallOptions); - const results = await consumeStream(resultStream); - - expect(mockGenerateContent).not.toHaveBeenCalled(); // SDK should not be called - const errorEvent = results.find(e => e.type === 'ERROR'); - expect(errorEvent).toBeDefined(); - expect(errorEvent?.data).toBeInstanceOf(ARTError); - expect((errorEvent?.data as ARTError).code).toBe(ErrorCode.PROMPT_TRANSLATION_FAILED); - expect((errorEvent?.data as ARTError).message).toContain("missing required 'tool_call_id' or 'name'"); - expect(results.some(e => e.type === 'END')).toBe(true); - expect(Logger.error).toHaveBeenCalledWith(expect.stringContaining('Error translating ArtStandardPrompt to Gemini format'), expect.anything()); - }); - - }); - - // --- Streaming Tests --- - describe('call (streaming)', () => { - it('should call generateContentStream and yield events', async () => { - // Mock the stream response - const mockStream = (async function*() { - yield { text: () => 'Hello ' }; - yield { text: () => 'World', usageMetadata: { promptTokenCount: 5 } }; // Add some metadata mid-stream - yield { text: () => '!', candidates: [{ finishReason: 'STOP' }], usageMetadata: { candidatesTokenCount: 15 } }; // Final chunk with reason and more metadata - })(); - mockGenerateContentStream.mockResolvedValueOnce(mockStream); - - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Stream hello' }]; - const callOptions: CallOptions = { ...defaultCallOptions, stream: true }; - const resultStream = await adapter.call(prompt, callOptions); - const results = await consumeStream(resultStream); - - expect(mockGenerateContentStream).toHaveBeenCalledOnce(); - expect(mockGenerateContentStream).toHaveBeenCalledWith({ - model: 'gemini-1.5-flash-latest', - contents: [{ role: 'user', parts: [{ text: 'Stream hello' }] }], - config: {}, - }); - - const tokens = results.filter(e => e.type === 'TOKEN').map(e => e.data); - expect(tokens).toEqual(['Hello ', 'World', '!']); - - const metadataEvent = results.find(e => e.type === 'METADATA'); - expect(metadataEvent).toBeDefined(); - expect(metadataEvent?.data).toMatchObject({ - stopReason: 'STOP', - inputTokens: 5, // From second chunk - outputTokens: 15, // From last chunk - providerRawUsage: { candidatesTokenCount: 15 }, // Raw usage from last chunk overwrites previous - }); - - expect(results.some(e => e.type === 'END')).toBe(true); - }); - - it('should handle SDK error during generateContentStream', async () => { - const sdkError = new Error('Stream connection failed'); - mockGenerateContentStream.mockRejectedValueOnce(sdkError); // Error on initial call - - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Test stream error' }]; - const callOptions: CallOptions = { ...defaultCallOptions, stream: true }; - const resultStream = await adapter.call(prompt, callOptions); - const results = await consumeStream(resultStream); - - expect(results.find(e => e.type === 'ERROR')?.data).toBe(sdkError); - expect(results.some(e => e.type === 'END')).toBe(true); - expect(Logger.error).toHaveBeenCalledWith( - expect.stringContaining('Error during Gemini SDK call: Stream connection failed'), - expect.anything() - ); - }); - - it('should handle error within the stream itself', async () => { - const streamError = new Error('Chunk processing error'); - const mockStream = (async function*() { - yield { text: () => 'Good chunk ' }; - throw streamError; // Error after first chunk - })(); - mockGenerateContentStream.mockResolvedValueOnce(mockStream); - - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Test stream error mid' }]; - const callOptions: CallOptions = { ...defaultCallOptions, stream: true }; - const resultStream = await adapter.call(prompt, callOptions); - const results = await consumeStream(resultStream); - - expect(results.find(e => e.type === 'TOKEN')?.data).toBe('Good chunk '); - expect(results.find(e => e.type === 'ERROR')?.data).toBe(streamError); - expect(results.some(e => e.type === 'END')).toBe(true); // END should still be yielded - expect(Logger.error).toHaveBeenCalledWith( - expect.stringContaining('Error during Gemini SDK call: Chunk processing error'), - expect.anything() - ); - }); - }); - -}); - -// Helper function to consume the async iterable stream into an array -async function consumeStream(stream: AsyncIterable): Promise { - const events: StreamEvent[] = []; - for await (const event of stream) { - events.push(event); - } - return events; -} \ No newline at end of file diff --git a/src/adapters/reasoning/ollama.test.ts b/src/adapters/reasoning/ollama.test.ts deleted file mode 100644 index c6c2f91..0000000 --- a/src/adapters/reasoning/ollama.test.ts +++ /dev/null @@ -1,375 +0,0 @@ -// src/adapters/reasoning/ollama.test.ts -import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'; -import { OllamaAdapter, OllamaAdapterOptions } from './ollama'; -import { Logger } from '../../utils/logger'; -import { ArtStandardPrompt, CallOptions, StreamEvent, LLMMetadata, ToolSchema } from '../../types'; -import { ARTError, ErrorCode } from '../../errors'; -import OpenAI from 'openai'; // Mocked below - -// Mock Logger -vi.mock('../../utils/logger', () => ({ - Logger: { - warn: vi.fn(), - error: vi.fn(), - info: vi.fn(), - debug: vi.fn(), - configure: vi.fn(), - }, -})); - -// Mock the 'openai' package -const mockCreate = vi.fn(); -const mockCompletions = { create: mockCreate }; -const mockChat = { completions: mockCompletions }; -const mockOpenAIInstance = { chat: mockChat }; - -vi.mock('openai', () => ({ - __esModule: true, - default: vi.fn(() => mockOpenAIInstance), -})); - - -// Helper function to consume the async iterable stream into an array -async function consumeStream(stream: AsyncIterable): Promise { - const events: StreamEvent[] = []; - for await (const event of stream) { - events.push(event); - } - return events; -} - -describe('OllamaAdapter', () => { - let adapter: OllamaAdapter; - const defaultModel = 'llama3'; - const defaultOptions: OllamaAdapterOptions = { defaultModel: defaultModel }; - const defaultCallOptions: CallOptions = { threadId: 't-ollama', providerConfig: { providerName: 'ollama', modelId: defaultModel, adapterOptions: {} } }; - - beforeEach(() => { - vi.clearAllMocks(); - adapter = new OllamaAdapter(defaultOptions); - }); - - afterEach(() => { - vi.restoreAllMocks(); - }); - - it('should initialize with default base URL and model', () => { - expect((adapter as any).ollamaBaseUrl).toBe('http://localhost:11434'); - expect((adapter as any).defaultModel).toBe(defaultModel); - expect(OpenAI).toHaveBeenCalledWith({ - baseURL: 'http://localhost:11434/v1', - apiKey: 'ollama', - dangerouslyAllowBrowser: true, - }); - expect(Logger.debug).toHaveBeenCalledWith(`OllamaAdapter initialized. Base URL: http://localhost:11434/v1, Default Model: ${defaultModel}`); - }); - - it('should initialize with custom base URL and api key', () => { - const customOptions: OllamaAdapterOptions = { ollamaBaseUrl: 'http://custom:12345', apiKey: 'custom-key', defaultModel: 'mistral' }; - const customAdapter = new OllamaAdapter(customOptions); - expect((customAdapter as any).ollamaBaseUrl).toBe('http://custom:12345'); - expect(OpenAI).toHaveBeenCalledWith({ - baseURL: 'http://custom:12345/v1', - apiKey: 'custom-key', - dangerouslyAllowBrowser: true, - }); - expect(Logger.debug).toHaveBeenCalledWith(`OllamaAdapter initialized. Base URL: http://custom:12345/v1, Default Model: mistral`); - }); - - it('should use model from providerConfig if available', async () => { - const specificModel = 'specific-ollama-model'; - const callOpts: CallOptions = { ...defaultCallOptions, providerConfig: { providerName: 'ollama', modelId: specificModel, adapterOptions: {} } }; - mockCreate.mockResolvedValueOnce({ choices: [{ message: { role: 'assistant', content: 'Response' }, finish_reason: 'stop' }], usage: { prompt_tokens: 1, completion_tokens: 1 } }); - await consumeStream(await adapter.call([{ role: 'user', content: 'Hi' }], callOpts)); - expect(mockCreate).toHaveBeenCalledWith(expect.objectContaining({ model: specificModel })); - }); - - it('should use model from callOptions if providerConfig.modelId is not set', async () => { - const specificModel = 'ollama-from-callopts'; - const callOpts: CallOptions = { ...defaultCallOptions, model: specificModel, providerConfig: { providerName: 'ollama', adapterOptions: {} } as any }; // remove modelId from providerConfig - mockCreate.mockResolvedValueOnce({ choices: [{ message: { role: 'assistant', content: 'Response' }, finish_reason: 'stop' }], usage: { prompt_tokens: 1, completion_tokens: 1 } }); - await consumeStream(await adapter.call([{ role: 'user', content: 'Hi' }], callOpts)); - expect(mockCreate).toHaveBeenCalledWith(expect.objectContaining({ model: specificModel })); - }); - - - it('should yield error if no model is specified', async () => { - const adapterWithoutModel = new OllamaAdapter({}); // No default model - const callOpts: CallOptions = { threadId: 't-no-model', providerConfig: { providerName: 'ollama', adapterOptions: {} } as any }; - const resultStream = await adapterWithoutModel.call([{ role: 'user', content: 'Hi' }], callOpts); - const results = await consumeStream(resultStream); - - const errorEvent = results.find(e => e.type === 'ERROR'); - expect(errorEvent).toBeDefined(); - expect(errorEvent?.data).toBeInstanceOf(ARTError); - expect((errorEvent?.data as ARTError).code).toBe(ErrorCode.INVALID_CONFIG); - expect((errorEvent?.data as ARTError).message).toContain('Ollama model ID is not specified'); - expect(results.some(e => e.type === 'END')).toBe(true); - }); - - - // --- Non-Streaming Tests --- - describe('call (non-streaming)', () => { - // Define basicPrompt at the describe block level - const basicPrompt: ArtStandardPrompt = [{ role: 'user', content: 'Say hello' }]; - - it('should translate basic ArtStandardPrompt and call client.chat.completions.create', async () => { - const mockApiResponse = { - id: 'chatcmpl-ollama-123', - object: 'chat.completion', - created: Date.now(), - model: defaultModel, - choices: [{ index: 0, message: { role: 'assistant', content: 'Ollama says hello!' }, finish_reason: 'stop' }], - usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 }, - }; - mockCreate.mockResolvedValueOnce(mockApiResponse); - - const resultStream = await adapter.call(basicPrompt, defaultCallOptions); // Use basicPrompt - const results = await consumeStream(resultStream); - - expect(mockCreate).toHaveBeenCalledOnce(); - expect(mockCreate).toHaveBeenCalledWith({ - model: defaultModel, - messages: [{ role: 'user', content: 'Say hello' }], - stream: false, - // other potential defaults like temperature might be undefined and thus not sent - }); - - expect(results.find(e => e.type === 'TOKEN')?.data).toBe('Ollama says hello!'); - const metadata = results.find(e => e.type === 'METADATA')?.data as LLMMetadata; - expect(metadata).toBeDefined(); - expect(metadata.stopReason).toBe('stop'); - expect(metadata.inputTokens).toBe(10); - expect(metadata.outputTokens).toBe(5); - expect(results.some(e => e.type === 'END')).toBe(true); - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining('Calling Ollama API'), expect.anything()); - }); - - it('should handle tool calls in non-streaming response', async () => { - const mockApiResponse = { - id: 'chatcmpl-tool', - choices: [{ - index: 0, - message: { - role: 'assistant', - content: 'Thinking about tools.', - tool_calls: [{ id: 'tool_123', type: 'function', function: { name: 'get_weather', arguments: '{"location":"Paris"}' } }] - }, - finish_reason: 'tool_calls' - }], - usage: { prompt_tokens: 20, completion_tokens: 10, total_tokens: 30 } - }; - mockCreate.mockResolvedValueOnce(mockApiResponse); - - const resultStream = await adapter.call(basicPrompt, defaultCallOptions); // Use a distinct prompt variable if needed - const results = await consumeStream(resultStream); - - const tokenEvent = results.find(e => e.type === 'TOKEN'); - expect(tokenEvent).toBeDefined(); - expect(tokenEvent?.data).toEqual([ - { type: 'text', text: 'Thinking about tools.' }, - { type: 'tool_use', id: 'tool_123', name: 'get_weather', input: { location: 'Paris' } } - ]); - - const metadata = results.find(e => e.type === 'METADATA')?.data as LLMMetadata; - expect(metadata.stopReason).toBe('tool_calls'); - }); - - - it('should handle API error from client by yielding ERROR', async () => { - const apiError = new OpenAI.APIError(401, { error: { message: 'Unauthorized' } } as any, 'Error message', {}); - mockCreate.mockRejectedValueOnce(apiError); - - const resultStream = await adapter.call(basicPrompt, defaultCallOptions); - const results = await consumeStream(resultStream); - - const errorEvent = results.find(e => e.type === 'ERROR'); - expect(errorEvent).toBeDefined(); - expect(errorEvent?.data).toBeInstanceOf(ARTError); - expect((errorEvent?.data as ARTError).code).toBe(ErrorCode.LLM_PROVIDER_ERROR); - expect((errorEvent?.data as ARTError).message).toContain('Ollama API Error (401): Unauthorized'); - expect(results.some(e => e.type === 'END')).toBe(true); - }); - }); - - // --- Streaming Tests --- - describe('call (streaming)', () => { - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Stream hello' }]; - const streamCallOptions: CallOptions = { ...defaultCallOptions, stream: true }; - - async function* createMockStreamChunks(chunks: Partial[]) { - for (const chunk of chunks) { - yield chunk as OpenAI.Chat.Completions.ChatCompletionChunk; - } - } - - it('should call client.chat.completions.create with stream and yield TOKEN events with correct tokenType', async () => { - const mockStream = createMockStreamChunks([ - { choices: [{ index: 0, delta: { role: 'assistant' }, finish_reason: null }] }, - { choices: [{ index: 0, delta: { content: 'Hello ' }, finish_reason: null }] }, - { choices: [{ index: 0, delta: { content: 'Ollama!' }, finish_reason: null }] }, - { choices: [{ index: 0, delta: {}, finish_reason: 'stop' }], usage: { prompt_tokens: 7, completion_tokens: 3, total_tokens: 10 } }, - ]); - mockCreate.mockResolvedValueOnce(mockStream); - - const agentThoughtCallOptions: CallOptions = { ...streamCallOptions, callContext: 'AGENT_THOUGHT' }; - const resultStream = await adapter.call(prompt, agentThoughtCallOptions); - const results = await consumeStream(resultStream); - - expect(mockCreate).toHaveBeenCalledWith(expect.objectContaining({ stream: true })); - - const tokenEvents = results.filter(e => e.type === 'TOKEN'); - expect(tokenEvents.map(e => e.data)).toEqual(['Hello ', 'Ollama!']); - tokenEvents.forEach(event => { - expect(event.tokenType).toBe('AGENT_THOUGHT_LLM_RESPONSE'); - }); - - const metadata = results.find(e => e.type === 'METADATA')?.data as LLMMetadata; - expect(metadata).toBeDefined(); - expect(metadata.stopReason).toBe('stop'); - expect(metadata.inputTokens).toBe(7); - expect(metadata.outputTokens).toBe(3); - expect(metadata.timeToFirstTokenMs).toBeGreaterThanOrEqual(0); - expect(results.some(e => e.type === 'END')).toBe(true); - }); - - it('should handle tool calls in streaming response', async () => { - const mockStream = createMockStreamChunks([ - { choices: [{ index: 0, delta: { role: 'assistant' }, finish_reason: null }] }, - { choices: [{ index: 0, delta: { content: 'Okay, using a tool: ' }, finish_reason: null }] }, - { choices: [{ index: 0, delta: { tool_calls: [{ index: 0, id: 'call_stream_123', type: 'function', function: { name: 'search_web', arguments: '{"query":"' } }] }, finish_reason: null }] }, - { choices: [{ index: 0, delta: { tool_calls: [{ index: 0, function: { arguments: 'ollama streaming"}' } }] }, finish_reason: null }] }, - { choices: [{ index: 0, delta: {}, finish_reason: 'tool_calls' }], usage: { prompt_tokens: 10, completion_tokens: 5, total_tokens: 15 } }, // Added total_tokens - ]); - mockCreate.mockResolvedValueOnce(mockStream); - - const resultStream = await adapter.call(prompt, streamCallOptions); - const results = await consumeStream(resultStream); - - const tokenEvents = results.filter(e => e.type === 'TOKEN'); - expect(tokenEvents.length).toBe(2); // One for text, one for tool_use - expect(tokenEvents[0].data).toBe('Okay, using a tool: '); - - const toolUseEventData = tokenEvents[1].data; - expect(toolUseEventData).toEqual([ - { type: 'tool_use', id: 'call_stream_123', name: 'search_web', input: { query: 'ollama streaming' } } - ]); - - const metadata = results.find(e => e.type === 'METADATA')?.data as LLMMetadata; - expect(metadata.stopReason).toBe('tool_calls'); - }); - - - it('should handle error during stream consumption', async () => { - const streamError = new Error('Stream read failed'); - async function* errorStream() { - // Add index to the choice - yield { choices: [{ index: 0, delta: { content: 'Good ' } }] } as OpenAI.Chat.Completions.ChatCompletionChunk; - throw streamError; - } - mockCreate.mockResolvedValueOnce(errorStream()); - - const resultStream = await adapter.call(prompt, streamCallOptions); - const results = await consumeStream(resultStream); - - expect(results.find(e => e.type === 'TOKEN')?.data).toBe('Good '); - const errorEvent = results.find(e => e.type === 'ERROR'); - expect(errorEvent).toBeDefined(); - expect(errorEvent?.data).toBeInstanceOf(ARTError); - expect((errorEvent?.data as ARTError).message).toContain('Stream read failed'); - expect(results.some(e => e.type === 'END')).toBe(true); - }); - }); - - describe('translateToOpenAI (including R1 merging)', () => { - it('should merge consecutive user messages for deepseek-r1 model', () => { - const r1Adapter = new OllamaAdapter({ defaultModel: 'deepseek-r1-test' }); - const artPrompt: ArtStandardPrompt = [ - { role: 'user', content: 'Hello.' }, - { role: 'user', content: 'How are you?' }, - { role: 'assistant', content: 'I am fine.' }, - { role: 'user', content: 'Good.' }, - ]; - const openAiMessages = (r1Adapter as any).translateToOpenAI(artPrompt, 'deepseek-r1-model'); - expect(openAiMessages).toEqual([ - { role: 'user', content: 'Hello.\nHow are you?' }, - { role: 'assistant', content: 'I am fine.' }, - { role: 'user', content: 'Good.' }, - ]); - }); - - it('should merge consecutive assistant messages for deepseek-r1 model, including tool_calls', () => { - const r1Adapter = new OllamaAdapter({ defaultModel: 'deepseek-r1-test' }); - const artPrompt: ArtStandardPrompt = [ - { role: 'user', content: 'What is 2+2 and then 3+3?' }, - { role: 'assistant', content: 'Thinking...', tool_calls: [{id: 'tc1', type: 'function', function: {name: 'calc', arguments: '{"expr":"2+2"}'}}]}, - { role: 'assistant', content: 'And also...', tool_calls: [{id: 'tc2', type: 'function', function: {name: 'calc', arguments: '{"expr":"3+3"}'}}]} - ]; - const openAiMessages = (r1Adapter as any).translateToOpenAI(artPrompt, 'deepseek-r1-model'); - expect(openAiMessages.length).toBe(2); - expect(openAiMessages[1].role).toBe('assistant'); - expect(openAiMessages[1].content).toBe('Thinking...\nAnd also...'); - expect(openAiMessages[1].tool_calls?.length).toBe(2); - expect(openAiMessages[1].tool_calls).toEqual([ - {id: 'tc1', type: 'function', function: {name: 'calc', arguments: '{"expr":"2+2"}'}}, - {id: 'tc2', type: 'function', function: {name: 'calc', arguments: '{"expr":"3+3"}'}} - ]); - }); - - it('should not merge messages for non-deepseek-r1 models', () => { - const standardAdapter = new OllamaAdapter({ defaultModel: 'llama3' }); - const artPrompt: ArtStandardPrompt = [ - { role: 'user', content: 'Hello.' }, - { role: 'user', content: 'How are you?' }, - ]; - const openAiMessages = (standardAdapter as any).translateToOpenAI(artPrompt, 'llama3'); - expect(openAiMessages).toEqual([ - { role: 'user', content: 'Hello.' }, - { role: 'user', content: 'How are you?' }, - ]); - }); - }); - - describe('translateArtToolsToOpenAI', () => { - it('should correctly translate ART ToolSchema to OpenAI tool format', () => { - const artTools: ToolSchema[] = [ - { - name: 'get_current_weather', - description: 'Get the current weather in a given location', - inputSchema: { - type: 'object', - properties: { - location: { type: 'string', description: 'The city and state, e.g. San Francisco, CA' }, - unit: { type: 'string', enum: ['celsius', 'fahrenheit'] }, - }, - required: ['location'], - }, - }, - ]; - const openAiTools = (adapter as any).translateArtToolsToOpenAI(artTools); - expect(openAiTools).toEqual([ - { - type: 'function', - function: { - name: 'get_current_weather', - description: 'Get the current weather in a given location', - parameters: { - type: 'object', - properties: { - location: { type: 'string', description: 'The city and state, e.g. San Francisco, CA' }, - unit: { type: 'string', enum: ['celsius', 'fahrenheit'] }, - }, - required: ['location'], - }, - }, - }, - ]); - }); - - it('should throw ARTError for invalid tool schema', () => { - const invalidArtTools: any[] = [{ description: 'A tool without a name or input schema' }]; - expect(() => (adapter as any).translateArtToolsToOpenAI(invalidArtTools)).toThrow(ARTError); - expect(() => (adapter as any).translateArtToolsToOpenAI(invalidArtTools)).toThrow(/Invalid ART ToolSchema for tool 'unknown'/); - }); - }); -}); \ No newline at end of file diff --git a/src/adapters/reasoning/openai.test.ts b/src/adapters/reasoning/openai.test.ts deleted file mode 100644 index ca9cd41..0000000 --- a/src/adapters/reasoning/openai.test.ts +++ /dev/null @@ -1,425 +0,0 @@ -// src/adapters/reasoning/openai.test.ts -import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'; -import { OpenAIAdapter, OpenAIAdapterOptions } from './openai'; -import { Logger } from '../../utils/logger'; -import { CallOptions, ArtStandardPrompt, StreamEvent } from '../../types'; // Import new types -import { ARTError, ErrorCode } from '../../errors'; // Import errors - -// Mock Logger -vi.mock('../../utils/logger', () => ({ - Logger: { - warn: vi.fn(), - error: vi.fn(), - info: vi.fn(), - debug: vi.fn(), - configure: vi.fn(), - }, -})); - -// Mock global fetch -const mockFetch = vi.fn(); -global.fetch = mockFetch; - -// Helper function to consume the async iterable stream into an array -async function consumeStream(stream: AsyncIterable): Promise { - const events: StreamEvent[] = []; - for await (const event of stream) { - events.push(event); - } - return events; -} - - -describe('OpenAIAdapter (Refactored)', () => { - let adapter: OpenAIAdapter; - const defaultOptions: OpenAIAdapterOptions = { apiKey: 'test-api-key' }; - const defaultCallOptions: CallOptions = { threadId: 't-openai' }; - - beforeEach(() => { - adapter = new OpenAIAdapter(defaultOptions); - vi.clearAllMocks(); // Clear mocks including fetch and Logger - }); - - afterEach(() => { - vi.restoreAllMocks(); // Ensure fetch mock doesn't leak - }); - - it('should throw error if API key is missing', () => { - expect(() => new OpenAIAdapter({} as OpenAIAdapterOptions)).toThrow('OpenAIAdapter requires an apiKey in options.'); - }); - - it('should initialize with default model if not provided', () => { - expect((adapter as any).model).toBe('gpt-3.5-turbo'); - expect((adapter as any).apiBaseUrl).toBe('https://api.openai.com/v1'); - expect(Logger.debug).toHaveBeenCalledWith('OpenAIAdapter initialized with model: gpt-3.5-turbo'); - }); - - it('should initialize with provided model and apiBaseUrl', () => { - const opts: OpenAIAdapterOptions = { apiKey: 'key', model: 'gpt-4', apiBaseUrl: 'http://localhost:8080' }; - const customAdapter = new OpenAIAdapter(opts); - expect((customAdapter as any).model).toBe('gpt-4'); - expect((customAdapter as any).apiBaseUrl).toBe('http://localhost:8080'); - }); - - // --- Non-Streaming Tests --- - describe('call (non-streaming)', () => { - it('should translate basic ArtStandardPrompt and call API', async () => { - const mockApiResponse = { - id: 'chatcmpl-123', object: 'chat.completion', created: 1677652288, model: 'gpt-3.5-turbo-0613', - choices: [{ index: 0, message: { role: 'assistant', content: 'OpenAI says hello!' }, finish_reason: 'stop' }], - usage: { prompt_tokens: 9, completion_tokens: 12, total_tokens: 21 }, - }; - mockFetch.mockResolvedValueOnce({ ok: true, json: async () => mockApiResponse }); - - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Say hello' }]; - const resultStream = await adapter.call(prompt, defaultCallOptions); - const results = await consumeStream(resultStream); - - expect(mockFetch).toHaveBeenCalledOnce(); - expect(mockFetch).toHaveBeenCalledWith( - 'https://api.openai.com/v1/chat/completions', - expect.objectContaining({ - method: 'POST', - headers: expect.objectContaining({ 'Authorization': 'Bearer test-api-key' }), - body: JSON.stringify({ - model: 'gpt-3.5-turbo', - messages: [{ role: 'user', content: 'Say hello' }], // Correct translation - stream: false, - }), - }) - ); - - expect(results.find(e => e.type === 'TOKEN')?.data).toBe('OpenAI says hello!'); - expect(results.find(e => e.type === 'METADATA')?.data).toMatchObject({ - stopReason: 'stop', - inputTokens: 9, - outputTokens: 12, - }); - expect(results.some(e => e.type === 'END')).toBe(true); - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining('Calling OpenAI API'), expect.anything()); - }); - - it('should translate ArtStandardPrompt with system prompt and history', async () => { - const mockApiResponse = { choices: [{ message: { role: 'assistant', content: 'Understood history.' }, finish_reason: 'stop' }] }; - mockFetch.mockResolvedValueOnce({ ok: true, json: async () => mockApiResponse }); - - const prompt: ArtStandardPrompt = [ - { role: 'system', content: 'You are helpful.' }, - { role: 'user', content: 'First message' }, - { role: 'assistant', content: 'My response' }, - { role: 'user', content: 'Second message' }, - ]; - await consumeStream(await adapter.call(prompt, defaultCallOptions)); - - expect(mockFetch).toHaveBeenCalledWith( - expect.any(String), - expect.objectContaining({ - body: JSON.stringify({ - model: 'gpt-3.5-turbo', - messages: [ - { role: 'system', content: 'You are helpful.' }, - { role: 'user', content: 'First message' }, - { role: 'assistant', content: 'My response' }, - { role: 'user', content: 'Second message' }, - ], - stream: false, - }), - }) - ); - }); - - it('should translate ArtStandardPrompt with assistant tool calls', async () => { - const mockApiResponse = { choices: [{ message: { role: 'assistant', content: null, tool_calls: [{ id: 'call_123', type: 'function', function: { name: 'calculator', arguments: '{"expr":"2+2"}' } }] }, finish_reason: 'tool_calls' }] }; - mockFetch.mockResolvedValueOnce({ ok: true, json: async () => mockApiResponse }); - - const prompt: ArtStandardPrompt = [ - { role: 'user', content: 'What is 2+2?' }, - { - role: 'assistant', - content: null, // No text content - tool_calls: [{ - id: 'call_123', - type: 'function', - function: { name: 'calculator', arguments: '{"expr":"2+2"}' } - }] - } - ]; - await consumeStream(await adapter.call(prompt, defaultCallOptions)); - - expect(mockFetch).toHaveBeenCalledWith( - expect.any(String), - expect.objectContaining({ - body: JSON.stringify({ - model: 'gpt-3.5-turbo', - messages: [ - { role: 'user', content: 'What is 2+2?' }, - { role: 'assistant', content: null, tool_calls: [{ id: 'call_123', type: 'function', function: { name: 'calculator', arguments: '{"expr":"2+2"}' } }] } - ], - stream: false, - }), - }) - ); - // Note: The adapter yields the text content (which is empty/null here) and metadata. - // The agent is responsible for parsing tool calls from the raw response if needed, - // though typically the LLM provides them directly in the 'message' object. - }); - - it('should translate ArtStandardPrompt with tool results', async () => { - const mockApiResponse = { choices: [{ message: { role: 'assistant', content: 'The result is 4.' }, finish_reason: 'stop' }] }; - mockFetch.mockResolvedValueOnce({ ok: true, json: async () => mockApiResponse }); - - const prompt: ArtStandardPrompt = [ - { role: 'user', content: 'What is 2+2?' }, - { role: 'assistant', content: null, tool_calls: [{ id: 'call_abc', type: 'function', function: { name: 'calculator', arguments: '{"expression":"2+2"}' } }] }, - { role: 'tool_result', tool_call_id: 'call_abc', name: 'calculator', content: '4' } // Stringified result - ]; - await consumeStream(await adapter.call(prompt, defaultCallOptions)); - - expect(mockFetch).toHaveBeenCalledWith( - expect.any(String), - expect.objectContaining({ - body: JSON.stringify({ - model: 'gpt-3.5-turbo', - messages: [ - { role: 'user', content: 'What is 2+2?' }, - { role: 'assistant', content: null, tool_calls: [{ id: 'call_abc', type: 'function', function: { name: 'calculator', arguments: '{"expression":"2+2"}' } }] }, - { role: 'tool', tool_call_id: 'call_abc', content: '4' } // Correct translation - ], - stream: false, - }), - }) - ); - }); - - - it('should include optional parameters in the API call payload', async () => { - const mockApiResponse = { choices: [{ message: { role: 'assistant', content: 'Response with params.' }, finish_reason: 'stop' }] }; - mockFetch.mockResolvedValueOnce({ ok: true, json: async () => mockApiResponse }); - - const callOptions: CallOptions = { - ...defaultCallOptions, - temperature: 0.5, - max_tokens: 100, - top_p: 0.9, - stop_sequences: ["\n"], // Test stop sequence mapping - }; - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Test params' }]; - await consumeStream(await adapter.call(prompt, callOptions)); - - expect(mockFetch).toHaveBeenCalledWith( - expect.any(String), - expect.objectContaining({ - method: 'POST', // Ensure method is checked - // We will check the body separately below by parsing it - }) - ); - // Check the full body by parsing the JSON string - const actualBody = JSON.parse(mockFetch.mock.calls[0][1].body); - expect(actualBody).toMatchObject({ - model: 'gpt-3.5-turbo', - messages: [{ role: 'user', content: 'Test params' }], - temperature: 0.5, - max_tokens: 100, - top_p: 0.9, - stop: ["\n"], - stream: false, - }); - }); - - it('should handle API error response (non-200 status) by yielding ERROR', async () => { - const errorBody = '{"error": {"message": "Invalid API key"}}'; - mockFetch.mockResolvedValueOnce({ ok: false, text: async () => errorBody, status: 401, statusText: 'Unauthorized' }); - - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Test API error' }]; - const resultStream = await adapter.call(prompt, defaultCallOptions); - const results = await consumeStream(resultStream); - - const errorEvent = results.find(e => e.type === 'ERROR'); - expect(errorEvent).toBeDefined(); - expect(errorEvent?.data).toBeInstanceOf(ARTError); - expect((errorEvent?.data as ARTError).code).toBe(ErrorCode.LLM_PROVIDER_ERROR); - expect((errorEvent?.data as ARTError).message).toContain('OpenAI API request failed: 401 Unauthorized'); - expect(results.some(e => e.type === 'END')).toBe(true); // END should still be yielded - expect(Logger.error).toHaveBeenCalledWith(expect.stringContaining('OpenAI API request failed with status 401'), expect.anything()); - }); - - it('should handle invalid response structure (missing message) by yielding ERROR', async () => { - const invalidResponse = { choices: [{ finish_reason: 'stop' }] }; // Missing message - mockFetch.mockResolvedValueOnce({ ok: true, json: async () => invalidResponse }); - - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Test invalid structure' }]; - const resultStream = await adapter.call(prompt, defaultCallOptions); - const results = await consumeStream(resultStream); - - const errorEvent = results.find(e => e.type === 'ERROR'); - expect(errorEvent).toBeDefined(); - expect(errorEvent?.data).toBeInstanceOf(ARTError); - expect((errorEvent?.data as ARTError).code).toBe(ErrorCode.LLM_PROVIDER_ERROR); - expect((errorEvent?.data as ARTError).message).toContain('Invalid response structure from OpenAI API: No message found'); - expect(results.some(e => e.type === 'END')).toBe(true); - expect(Logger.error).toHaveBeenCalledWith('Invalid response structure from OpenAI API: No message found', expect.anything()); - }); - - it('should handle fetch network error by yielding ERROR', async () => { - const networkError = new Error('Network failed'); - mockFetch.mockRejectedValueOnce(networkError); - - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Test network error' }]; - const resultStream = await adapter.call(prompt, defaultCallOptions); - const results = await consumeStream(resultStream); - - const errorEvent = results.find(e => e.type === 'ERROR'); - expect(errorEvent).toBeDefined(); - expect(errorEvent?.data).toBeInstanceOf(ARTError); - expect((errorEvent?.data as ARTError).code).toBe(ErrorCode.LLM_PROVIDER_ERROR); - expect((errorEvent?.data as ARTError).message).toContain('Network failed'); - expect((errorEvent?.data as ARTError).originalError).toBe(networkError); - expect(results.some(e => e.type === 'END')).toBe(true); - expect(Logger.error).toHaveBeenCalledWith('Error during OpenAI API call: Network failed', expect.anything()); - }); - - it('should yield error if translation fails', async () => { - const invalidPrompt: ArtStandardPrompt = [ - { role: 'tool_result', content: 'Result', name: 'tool', tool_call_id: undefined } // Missing tool_call_id - ]; - - const resultStream = await adapter.call(invalidPrompt, defaultCallOptions); - const results = await consumeStream(resultStream); - - expect(mockFetch).not.toHaveBeenCalled(); // API should not be called - const errorEvent = results.find(e => e.type === 'ERROR'); - expect(errorEvent).toBeDefined(); - expect(errorEvent?.data).toBeInstanceOf(ARTError); - expect((errorEvent?.data as ARTError).code).toBe(ErrorCode.PROMPT_TRANSLATION_FAILED); - expect((errorEvent?.data as ARTError).message).toContain("missing required 'tool_call_id'"); - expect(results.some(e => e.type === 'END')).toBe(true); - expect(Logger.error).toHaveBeenCalledWith(expect.stringContaining('Error translating ArtStandardPrompt to OpenAI format'), expect.anything()); - }); - }); - - // --- Streaming Tests --- - describe('call (streaming)', () => { - // Helper to create a mock ReadableStream from SSE lines - function createMockStream(lines: string[]): ReadableStream { - const encoder = new TextEncoder(); - const stream = new ReadableStream({ - async start(controller) { - for (const line of lines) { - controller.enqueue(encoder.encode(line + '\n')); - await new Promise(resolve => setTimeout(resolve, 1)); // Simulate async nature - } - controller.enqueue(encoder.encode('data: [DONE]\n')); // Add DONE signal - controller.close(); - } - }); - return stream; - } - - it('should call API with stream flag and yield TOKEN events', async () => { - const mockStreamLines = [ - 'data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","created":17000,"model":"gpt-3.5-turbo","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]}', - 'data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","created":17000,"model":"gpt-3.5-turbo","choices":[{"index":0,"delta":{"content":"Hello"},"finish_reason":null}]}', - 'data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","created":17000,"model":"gpt-3.5-turbo","choices":[{"index":0,"delta":{"content":" world"},"finish_reason":null}]}', - 'data: {"id":"chatcmpl-xxx","object":"chat.completion.chunk","created":17000,"model":"gpt-3.5-turbo","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]}', - ]; - const mockStream = createMockStream(mockStreamLines); - mockFetch.mockResolvedValueOnce({ ok: true, body: mockStream }); - - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Stream hello' }]; - const callOptions: CallOptions = { ...defaultCallOptions, stream: true }; - const resultStream = await adapter.call(prompt, callOptions); - const results = await consumeStream(resultStream); - - expect(mockFetch).toHaveBeenCalledOnce(); - expect(mockFetch).toHaveBeenCalledWith( - expect.any(String), - expect.objectContaining({ - body: expect.stringContaining('"stream":true'), - }) - ); - const actualBody = JSON.parse(mockFetch.mock.calls[0][1].body); - expect(actualBody.stream).toBe(true); - - const tokens = results.filter(e => e.type === 'TOKEN').map(e => e.data); - expect(tokens).toEqual(['Hello', ' world']); // Note: Initial empty content delta is ignored - - const metadataEvent = results.find(e => e.type === 'METADATA'); - expect(metadataEvent).toBeDefined(); - expect(metadataEvent?.data?.stopReason).toBe('stop'); - // Token counts are estimates in stream mode for now - expect(metadataEvent?.data?.outputTokens).toBe(2); - - expect(results.some(e => e.type === 'END')).toBe(true); - }); - - it('should handle stream error during fetch', async () => { - const networkError = new Error('Stream connection failed'); - mockFetch.mockRejectedValueOnce(networkError); // Error on initial call - - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Test stream error' }]; - const callOptions: CallOptions = { ...defaultCallOptions, stream: true }; - const resultStream = await adapter.call(prompt, callOptions); - const results = await consumeStream(resultStream); - - const errorEvent = results.find(e => e.type === 'ERROR'); - expect(errorEvent).toBeDefined(); - expect(errorEvent?.data).toBeInstanceOf(ARTError); - expect((errorEvent?.data as ARTError).message).toContain('Stream connection failed'); - expect(results.some(e => e.type === 'END')).toBe(true); - }); - - it('should handle error within the stream itself (e.g., read error)', async () => { - const streamError = new Error('Chunk read error'); - const stream = new ReadableStream({ - async pull(controller) { - controller.enqueue(new TextEncoder().encode('data: {"choices":[{"delta":{"content":"Good "}}]}\n')); - await new Promise(resolve => setTimeout(resolve, 1)); - controller.error(streamError); // Simulate error during read - } - }); - mockFetch.mockResolvedValueOnce({ ok: true, body: stream }); - - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Test stream error mid' }]; - const callOptions: CallOptions = { ...defaultCallOptions, stream: true }; - const resultStream = await adapter.call(prompt, callOptions); - const results = await consumeStream(resultStream); - - expect(results.find(e => e.type === 'TOKEN')?.data).toBe('Good '); - const errorEvent = results.find(e => e.type === 'ERROR'); - expect(errorEvent).toBeDefined(); - expect(errorEvent?.data).toBeInstanceOf(ARTError); - expect((errorEvent?.data as ARTError).message).toContain('Error reading OpenAI stream: Chunk read error'); - expect(results.some(e => e.type === 'END')).toBe(true); // END should still be yielded - }); - - it('should handle invalid JSON within the stream', async () => { - const mockStreamLines = [ - 'data: {"choices":[{"delta":{"content":"Valid "}}]}', - 'data: {invalid json', // Invalid chunk - 'data: {"choices":[{"delta":{"content":" more"}}]}', - ]; - const mockStream = createMockStream(mockStreamLines); - mockFetch.mockResolvedValueOnce({ ok: true, body: mockStream }); - - const prompt: ArtStandardPrompt = [{ role: 'user', content: 'Test invalid stream json' }]; - const callOptions: CallOptions = { ...defaultCallOptions, stream: true }; - const resultStream = await adapter.call(prompt, callOptions); - const results = await consumeStream(resultStream); - - const tokens = results.filter(e => e.type === 'TOKEN').map(e => e.data); - expect(tokens).toEqual(['Valid ', ' more']); // Should skip the invalid chunk - - // Check if a warning was logged - expect(Logger.warn).toHaveBeenCalledWith( - expect.stringContaining('Failed to parse OpenAI stream chunk'), - expect.anything() - ); - - expect(results.some(e => e.type === 'END')).toBe(true); - // No ERROR event should be yielded for just a parse warning by default - expect(results.some(e => e.type === 'ERROR')).toBe(false); - }); - - // TODO: Add tests for streaming tool calls once aggregation is properly implemented - }); -}); \ No newline at end of file diff --git a/src/adapters/reasoning/openrouter.test.ts b/src/adapters/reasoning/openrouter.test.ts deleted file mode 100644 index 3815870..0000000 --- a/src/adapters/reasoning/openrouter.test.ts +++ /dev/null @@ -1,188 +0,0 @@ -// src/adapters/reasoning/openrouter.test.ts -import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest'; -import { OpenRouterAdapter, OpenRouterAdapterOptions } from './openrouter'; -import { Logger } from '../../utils/logger'; -import { CallOptions } from '../../types'; - -// Mock Logger -vi.mock('../../utils/logger', () => ({ - Logger: { - warn: vi.fn(), - error: vi.fn(), - info: vi.fn(), - debug: vi.fn(), - configure: vi.fn(), - }, -})); - -// Mock global fetch -const mockFetch = vi.fn(); -global.fetch = mockFetch; - -describe('OpenRouterAdapter', () => { - let adapter: OpenRouterAdapter; - const defaultOptions: OpenRouterAdapterOptions = { - apiKey: 'test-openrouter-key', - model: 'google/gemini-pro', // Example required model - }; - const defaultCallOptions: CallOptions = { threadId: 't-openrouter' }; - - beforeEach(() => { - adapter = new OpenRouterAdapter(defaultOptions); - vi.clearAllMocks(); // Clear mocks including fetch and Logger - }); - - afterEach(() => { - vi.restoreAllMocks(); // Ensure fetch mock doesn't leak - }); - - it('should throw error if API key is missing', () => { - expect(() => new OpenRouterAdapter({ model: 'test/model' } as OpenRouterAdapterOptions)).toThrow('OpenRouter API key is required.'); - }); - - it('should throw error if model is missing', () => { - expect(() => new OpenRouterAdapter({ apiKey: 'key' } as OpenRouterAdapterOptions)).toThrow('OpenRouter model identifier is required'); - }); - - it('should initialize with default apiBaseUrl if not provided', () => { - expect((adapter as any).model).toBe('google/gemini-pro'); - expect((adapter as any).apiBaseUrl).toBe('https://openrouter.ai/api/v1'); - expect(Logger.debug).toHaveBeenCalledWith('OpenRouterAdapter initialized for model: google/gemini-pro'); - }); - - it('should initialize with provided apiBaseUrl, siteUrl, and appName', () => { - const opts: OpenRouterAdapterOptions = { - apiKey: 'key', - model: 'anthropic/claude-3-haiku', - apiBaseUrl: 'http://localhost:8083', - siteUrl: 'https://my-site.com', - appName: 'My Test App' - }; - const customAdapter = new OpenRouterAdapter(opts); - expect((customAdapter as any).model).toBe('anthropic/claude-3-haiku'); - expect((customAdapter as any).apiBaseUrl).toBe('http://localhost:8083'); - expect((customAdapter as any).siteUrl).toBe('https://my-site.com'); - expect((customAdapter as any).appName).toBe('My Test App'); - }); - - it('should make a successful API call with basic prompt and default headers', async () => { - const mockResponse = { - id: 'or-123', object: 'chat.completion', created: 1677652288, model: 'google/gemini-pro', - choices: [{ index: 0, message: { role: 'assistant', content: ' OpenRouter says hello! ' }, finish_reason: 'stop' }], - usage: { prompt_tokens: 9, completion_tokens: 12, total_tokens: 21 }, - }; - mockFetch.mockResolvedValueOnce({ - ok: true, - json: async () => mockResponse, - status: 200, - statusText: 'OK', - }); - - const prompt = 'Say hello'; - const result = await adapter.call(prompt, defaultCallOptions); - - expect(result).toBe('OpenRouter says hello!'); // Should be trimmed - expect(mockFetch).toHaveBeenCalledOnce(); - const expectedUrl = `https://openrouter.ai/api/v1/chat/completions`; - expect(mockFetch).toHaveBeenCalledWith( - expectedUrl, - expect.objectContaining({ - method: 'POST', - headers: { // Default headers only - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${defaultOptions.apiKey}`, - }, - body: JSON.stringify({ - model: defaultOptions.model, // Use the specific model - messages: [{ role: 'user', content: prompt }], - }), - }) - ); - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining('Calling OpenRouter API'), expect.anything()); - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining('OpenRouter API call successful'), expect.anything()); - }); - - it('should include optional parameters and custom headers in the API call', async () => { - const optsWithHeaders: OpenRouterAdapterOptions = { - ...defaultOptions, - siteUrl: 'https://example.com/art', - appName: 'ART-Test-Suite' - }; - const adapterWithHeaders = new OpenRouterAdapter(optsWithHeaders); - const mockResponse = { choices: [{ message: { content: 'Response with params.' } }] }; - mockFetch.mockResolvedValueOnce({ ok: true, json: async () => mockResponse }); - - const callOptions: CallOptions = { - ...defaultCallOptions, - temperature: 0.7, - max_tokens: 500, - topP: 0.8, // Test alias - stop: ['\nObservation:'], // Test alias - }; - await adapterWithHeaders.call('Test params', callOptions); - - expect(mockFetch).toHaveBeenCalledWith( - expect.any(String), - expect.objectContaining({ - headers: { // Check for custom headers - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${defaultOptions.apiKey}`, - 'HTTP-Referer': optsWithHeaders.siteUrl, - 'X-Title': optsWithHeaders.appName, - }, - body: JSON.stringify({ - model: defaultOptions.model, - messages: [{ role: 'user', content: 'Test params' }], - temperature: 0.7, - max_tokens: 500, - top_p: 0.8, - stop: ['\nObservation:'], - }), - }) - ); - }); - - it('should handle API error response (non-200 status)', async () => { - const errorBody = JSON.stringify({ error: { message: 'Invalid model requested.' } }); - mockFetch.mockResolvedValueOnce({ - ok: false, - text: async () => errorBody, - status: 400, - statusText: 'Bad Request', - }); - - await expect(adapter.call('Test API error', defaultCallOptions)).rejects.toThrow( - 'OpenRouter API request failed: 400 Bad Request - Invalid model requested.' // Parsed message - ); - expect(Logger.error).toHaveBeenCalledWith( - expect.stringContaining('OpenRouter API request failed with status 400'), - expect.anything() - ); - }); - - it('should handle invalid response structure (missing content)', async () => { - const invalidResponse = { choices: [{ message: {} }] }; // Missing content - mockFetch.mockResolvedValueOnce({ ok: true, json: async () => invalidResponse }); - - await expect(adapter.call('Test invalid structure', defaultCallOptions)).rejects.toThrow( - 'Invalid response structure from OpenRouter API: No content found.' - ); - expect(Logger.error).toHaveBeenCalledWith( - 'Invalid response structure from OpenRouter API', - expect.objectContaining({ responseData: invalidResponse }) - ); - }); - - it('should handle fetch network error', async () => { - const networkError = new Error('Network connection failed'); - mockFetch.mockRejectedValueOnce(networkError); - - await expect(adapter.call('Test network error', defaultCallOptions)).rejects.toThrow('Network connection failed'); - expect(Logger.error).toHaveBeenCalledWith( - 'Error during OpenRouter API call: Network connection failed', - expect.objectContaining({ error: networkError }) - ); - }); - - // Other tests like non-string prompt handling would be similar to OpenAIAdapter tests -}); \ No newline at end of file diff --git a/src/adapters/storage/inMemory.test.ts b/src/adapters/storage/inMemory.test.ts deleted file mode 100644 index 695205d..0000000 --- a/src/adapters/storage/inMemory.test.ts +++ /dev/null @@ -1,216 +0,0 @@ -import { describe, it, expect, beforeEach } from 'vitest'; -import { InMemoryStorageAdapter } from './inMemory'; -import { FilterOptions } from '../../types'; // Assuming types are in ../../types - -// Define a type for the test data for better type safety in tests -type TestItem = { - name: string; - type: string; - value: number; -}; - -type OtherItem = { - name: string; - type: string; -}; - -type SimpleData = { - data: string; -}; - -describe('InMemoryStorageAdapter', () => { - let adapter: InMemoryStorageAdapter; - const testCollection = 'testItems'; - const otherCollection = 'otherCollection'; - - beforeEach(() => { - adapter = new InMemoryStorageAdapter(); - // Ensure adapter is initialized if needed (though init is no-op here) - adapter.init(); - }); - - it('should initialize without errors', async () => { - await expect(adapter.init()).resolves.toBeUndefined(); - }); - - it('should set and get an item', async () => { - const id = 'item1'; - const data = { name: 'Test Item', value: 123 }; // Less specific type here is fine - await adapter.set(testCollection, id, data); - const retrieved = await adapter.get(testCollection, id); - expect(retrieved).toEqual(data); - expect(retrieved).not.toBe(data); // Ensure it's a copy - }); - - it('should return null when getting a non-existent item', async () => { - const retrieved = await adapter.get(testCollection, 'nonexistent'); - expect(retrieved).toBeNull(); - }); - - it('should return null when getting from a non-existent collection', async () => { - const retrieved = await adapter.get('nonexistentCollection', 'item1'); - expect(retrieved).toBeNull(); - }); - - it('should update an existing item on set', async () => { - const id = 'itemToUpdate'; - const initialData = { name: 'Initial', value: 1 }; - const updatedData = { name: 'Updated', value: 2 }; - await adapter.set(testCollection, id, initialData); - await adapter.set(testCollection, id, updatedData); - const retrieved = await adapter.get(testCollection, id); - expect(retrieved).toEqual(updatedData); - }); - - it('should handle deep copies correctly on set/get', async () => { - const id = 'deepCopyTest'; - const originalData = { nested: { prop: 'value' } }; - await adapter.set(testCollection, id, originalData); - - // Modify original after setting - originalData.nested.prop = 'modified_externally'; - - const retrieved = await adapter.get(testCollection, id); - expect(retrieved?.nested.prop).toBe('value'); // Should have original value - - // Modify retrieved and check original stored value - if (retrieved) { - retrieved.nested.prop = 'modified_retrieved'; - } - const retrievedAgain = await adapter.get(testCollection, id); - expect(retrievedAgain?.nested.prop).toBe('value'); // Stored value should be unchanged - }); - - - it('should delete an item', async () => { - const id = 'itemToDelete'; - const data = { name: 'Delete Me' }; - await adapter.set(testCollection, id, data); - let retrieved = await adapter.get(testCollection, id); // Added type arg - expect(retrieved).toEqual(data); - - await adapter.delete(testCollection, id); - retrieved = await adapter.get(testCollection, id); - expect(retrieved).toBeNull(); - }); - - it('should not throw when deleting a non-existent item', async () => { - await expect(adapter.delete(testCollection, 'nonexistent')).resolves.toBeUndefined(); - }); - - it('should not throw when deleting from a non-existent collection', async () => { - await expect(adapter.delete('nonexistentCollection', 'item1')).resolves.toBeUndefined(); - }); - - describe('query', () => { - beforeEach(async () => { - // Seed data for query tests - await adapter.set(testCollection, 'q1', { name: 'Query Item 1', type: 'A', value: 10 }); - await adapter.set(testCollection, 'q2', { name: 'Query Item 2', type: 'B', value: 20 }); - await adapter.set(testCollection, 'q3', { name: 'Query Item 3', type: 'A', value: 30 }); - await adapter.set(otherCollection, 'o1', { name: 'Other 1', type: 'A' }); - }); - - it('should return all items in a collection with empty filter', async () => { - // Provide expected type for the query result - const results = await adapter.query(testCollection, {}); - expect(results).toHaveLength(3); - // Now 'r' has the type TestItem - expect(results.map(r => r.name)).toEqual(expect.arrayContaining([ - 'Query Item 1', 'Query Item 2', 'Query Item 3' - ])); - }); - - it('should filter items based on exact match', async () => { - const filterOptions: FilterOptions = { filter: { type: 'A' } }; - const results = await adapter.query(testCollection, filterOptions); - expect(results).toHaveLength(2); - expect(results.map(r => r.name)).toEqual(expect.arrayContaining([ - 'Query Item 1', 'Query Item 3' - ])); - expect(results.every(r => r.type === 'A')).toBe(true); - }); - - it('should filter items based on multiple exact matches', async () => { - const filterOptions: FilterOptions = { filter: { type: 'A', value: 30 } }; - const results = await adapter.query(testCollection, filterOptions); - expect(results).toHaveLength(1); - expect(results[0].name).toBe('Query Item 3'); - }); - - it('should return empty array if no items match filter', async () => { - const filterOptions: FilterOptions = { filter: { type: 'C' } }; - // Specify type even for expected empty array - const results = await adapter.query(testCollection, filterOptions); - expect(results).toHaveLength(0); - }); - - it('should return empty array when querying a non-existent collection', async () => { - // Specify type even for expected empty array - const results = await adapter.query('nonexistentQueryCollection', {}); - expect(results).toHaveLength(0); - }); - - it('should limit the number of results', async () => { - const filterOptions: FilterOptions = { limit: 2 }; - // Specify expected type - const results = await adapter.query(testCollection, filterOptions); - expect(results).toHaveLength(2); - }); - - it('should apply filter and limit together', async () => { - const filterOptions: FilterOptions = { filter: { type: 'A' }, limit: 1 }; - // Specify expected type - const results = await adapter.query(testCollection, filterOptions); - expect(results).toHaveLength(1); - // 'results[0]' now has type TestItem - expect(['Query Item 1', 'Query Item 3']).toContain(results[0].name); - }); - - it('should return deep copies from query', async () => { - const filterOptions: FilterOptions = { filter: { name: 'Query Item 1' } }; - const results = await adapter.query(testCollection, filterOptions); - expect(results).toHaveLength(1); - const item = results[0]; - const originalValue = item.value; - - // Modify the retrieved item - item.value = 999; - - // Re-query and check the stored value is unchanged - const resultsAgain = await adapter.query(testCollection, filterOptions); - expect(resultsAgain).toHaveLength(1); - expect(resultsAgain[0].value).toBe(originalValue); - expect(resultsAgain[0].value).not.toBe(999); - }); - }); - - it('should clear a specific collection', async () => { - await adapter.set(testCollection, 'item1', { data: 'a' }); - await adapter.set(otherCollection, 'item2', { data: 'b' }); - - await adapter.clearCollection(testCollection); - - const item1 = await adapter.get(testCollection, 'item1'); - const item2 = await adapter.get(otherCollection, 'item2'); - - expect(item1).toBeNull(); - expect(item2).toEqual({ data: 'b' }); // Other collection should remain - }); - - it('should clear all collections', async () => { - await adapter.set(testCollection, 'item1', { data: 'a' }); - await adapter.set(otherCollection, 'item2', { data: 'b' }); - - await adapter.clearAll(); - - const item1 = await adapter.get(testCollection, 'item1'); - const item2 = await adapter.get(otherCollection, 'item2'); - - expect(item1).toBeNull(); - expect(item2).toBeNull(); - // Specify expected type for query results - expect(await adapter.query(testCollection, {})).toHaveLength(0); - expect(await adapter.query(otherCollection, {})).toHaveLength(0); - }); -}); \ No newline at end of file diff --git a/src/adapters/storage/indexedDB.test.ts b/src/adapters/storage/indexedDB.test.ts deleted file mode 100644 index 1978734..0000000 --- a/src/adapters/storage/indexedDB.test.ts +++ /dev/null @@ -1,289 +0,0 @@ -import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'; -import { IndexedDBStorageAdapter, IndexedDBConfig } from './indexedDB'; -import { FilterOptions } from '../../types'; - -// Mock window.indexedDB if running in Node.js environment for basic checks -// A proper browser environment (like Playwright, jsdom with indexeddbshim, or @vitest/browser) is needed for full testing. -if (typeof window === 'undefined') { - // Basic mock to allow tests to run without crashing in Node - global.window = { - indexedDB: { - open: vi.fn().mockReturnValue({ - onerror: null, - onsuccess: null, - onupgradeneeded: null, - result: { objectStoreNames: [], close: vi.fn(), transaction: vi.fn(), version: 1 }, - // Add basic event handlers if needed by tests - }), - deleteDatabase: vi.fn().mockReturnValue({ onsuccess: null, onerror: null }), // Mock deleteDatabase - } - } as any; - global.IDBTransaction = {} as any; - global.IDBKeyRange = {} as any; -} - - -// Helper function to delete the database before each test run -async function deleteDatabase(dbName: string): Promise { - return new Promise((resolve, reject) => { - if (!window.indexedDB) { - console.warn("Cannot delete DB: window.indexedDB not available."); - resolve(); // Resolve silently if no IndexedDB - return; - } - console.log(`Attempting to delete database: ${dbName}`); - const request = window.indexedDB.deleteDatabase(dbName); - request.onsuccess = () => { - console.log(`Database ${dbName} deleted successfully.`); - resolve(); - }; - request.onerror = (event) => { - console.error(`Error deleting database ${dbName}:`, request.error, event); - reject(new Error(`Failed to delete database ${dbName}: ${request.error?.message}`)); - }; - request.onblocked = (event) => { - console.warn(`Database ${dbName} deletion blocked. Close other connections.`, event); - // Resolve anyway, as the test might still proceed if the block is temporary - // or if the existing DB state is acceptable for the next test. - // Alternatively, reject(new Error(`Database ${dbName} deletion blocked.`)); - resolve(); - }; - }); -} - - -describe('IndexedDBStorageAdapter', () => { - const dbName = `TestDB_${Date.now()}`; // Unique DB name per test run - const testCollection = 'items'; - const otherCollection = 'others'; - const config: IndexedDBConfig = { - dbName: dbName, - dbVersion: 1, - objectStores: [testCollection, otherCollection], - }; - let adapter: IndexedDBStorageAdapter; - - // Delete the database before each test to ensure a clean state - beforeEach(async () => { - await deleteDatabase(dbName); - adapter = new IndexedDBStorageAdapter(config); - // We need to init before most tests - }); - - // Optional: Attempt to delete after all tests in the suite - afterEach(async () => { - // Close the DB connection if open? IndexedDB handles this somewhat automatically, - // but explicit close might be needed if tests leak connections. - // adapter.close(); // Assuming adapter has a close method if implemented - await deleteDatabase(dbName); // Clean up after each test - }); - - it('should initialize the database and create object stores', async () => { - await expect(adapter.init()).resolves.toBeUndefined(); - // In a real browser env, we could inspect the DB further here - // For now, success of init is the main check. - }); - - it('should handle multiple init calls gracefully', async () => { - await adapter.init(); // First call - await expect(adapter.init()).resolves.toBeUndefined(); // Second call should resolve immediately - }); - - it('should reject init if IndexedDB is not supported', async () => { - const originalIndexedDB = window.indexedDB; - (window as any).indexedDB = undefined; // Simulate no support - const badAdapter = new IndexedDBStorageAdapter(config); - await expect(badAdapter.init()).rejects.toThrow("IndexedDB not supported"); - window.indexedDB = originalIndexedDB; // Restore - }); - - - it('should set and get an item', async () => { - await adapter.init(); - const id = 'item1'; - const data = { id: id, name: 'Test Item', value: 123 }; - await adapter.set(testCollection, id, data); - const retrieved = await adapter.get(testCollection, id); - expect(retrieved).toEqual(data); - // IndexedDB returns structured clones, so they shouldn't be the same reference - // expect(retrieved).not.toBe(data); // This might fail depending on exact IDB impl/mocks - }); - - it('should return null when getting a non-existent item', async () => { - await adapter.init(); - const retrieved = await adapter.get(testCollection, 'nonexistent'); - expect(retrieved).toBeNull(); - }); - - it('should reject when getting from a non-existent collection', async () => { - await adapter.init(); - // The getTransaction helper should throw before the promise - await expect(adapter.get('nonexistentCollection', 'item1')) - .rejects.toThrow('Object store "nonexistentCollection" does not exist'); - }); - - it('should update an existing item on set', async () => { - await adapter.init(); - const id = 'itemToUpdate'; - const initialData = { id: id, name: 'Initial', value: 1 }; - const updatedData = { id: id, name: 'Updated', value: 2 }; - await adapter.set(testCollection, id, initialData); - await adapter.set(testCollection, id, updatedData); - const retrieved = await adapter.get(testCollection, id); - expect(retrieved).toEqual(updatedData); - }); - - it('should reject set if data does not have an id property', async () => { - await adapter.init(); - const id = 'badData'; - const data = { name: 'No ID here' }; // Missing 'id' - await expect(adapter.set(testCollection, id, data as any)) // Cast to bypass compile check - .rejects.toThrow(/must have an 'id' property/); - }); - - it('should warn if provided id and data.id mismatch, but still use data.id', async () => { - await adapter.init(); - const consoleWarnSpy = vi.spyOn(console, 'warn'); - const providedId = 'provided-id'; - const dataId = 'data-id'; - const data = { id: dataId, name: 'Mismatch Test' }; - - await adapter.set(testCollection, providedId, data); // Mismatched IDs - - expect(consoleWarnSpy).toHaveBeenCalledWith( - expect.stringContaining(`Provided id ('${providedId}') and data.id ('${dataId}') mismatch`) - ); - - // Should be stored under data.id, not providedId - const retrievedByDataId = await adapter.get(testCollection, dataId); - const retrievedByProvidedId = await adapter.get(testCollection, providedId); - - expect(retrievedByDataId).toEqual(data); - expect(retrievedByProvidedId).toBeNull(); - - consoleWarnSpy.mockRestore(); - }); - - - it('should delete an item', async () => { - await adapter.init(); - const id = 'itemToDelete'; - const data = { id: id, name: 'Delete Me' }; - await adapter.set(testCollection, id, data); - let retrieved = await adapter.get(testCollection, id); - expect(retrieved).toEqual(data); - - await adapter.delete(testCollection, id); - retrieved = await adapter.get(testCollection, id); - expect(retrieved).toBeNull(); - }); - - it('should resolve delete even if item does not exist', async () => { - await adapter.init(); - await expect(adapter.delete(testCollection, 'nonexistent')).resolves.toBeUndefined(); - }); - - describe('query', () => { - type QueryItem = { id: string; name: string; type: string; value: number }; - - beforeEach(async () => { - await adapter.init(); - // Seed data for query tests - await adapter.set(testCollection, 'q1', { id: 'q1', name: 'Query Item 1', type: 'A', value: 10 }); - await adapter.set(testCollection, 'q2', { id: 'q2', name: 'Query Item 2', type: 'B', value: 20 }); - await adapter.set(testCollection, 'q3', { id: 'q3', name: 'Query Item 3', type: 'A', value: 30 }); - await adapter.set<{ id: string, name: string, type: string }>(otherCollection, 'o1', { id: 'o1', name: 'Other 1', type: 'A' }); - }); - - it('should return all items in a collection with empty filter', async () => { - const results = await adapter.query(testCollection, {}); - expect(results).toHaveLength(3); - expect(results.map(r => r.name)).toEqual(expect.arrayContaining([ - 'Query Item 1', 'Query Item 2', 'Query Item 3' - ])); - }); - - it('should filter items based on exact match (client-side)', async () => { - const filterOptions: FilterOptions = { filter: { type: 'A' } }; - const results = await adapter.query(testCollection, filterOptions); - expect(results).toHaveLength(2); - expect(results.map(r => r.name)).toEqual(expect.arrayContaining([ - 'Query Item 1', 'Query Item 3' - ])); - expect(results.every(r => r.type === 'A')).toBe(true); - }); - - it('should limit the number of results (client-side)', async () => { - // Note: Order isn't guaranteed without sort - const filterOptions: FilterOptions = { limit: 2 }; - const results = await adapter.query(testCollection, filterOptions); - expect(results).toHaveLength(2); - }); - - it('should apply filter and limit together (client-side)', async () => { - const filterOptions: FilterOptions = { filter: { type: 'A' }, limit: 1 }; - const results = await adapter.query(testCollection, filterOptions); - expect(results).toHaveLength(1); - // Result depends on getAll() order + client-side filter - }); - - it('should apply skip and limit (client-side)', async () => { - // Need sorting for predictable skip - const filterOptions: FilterOptions = { sort: { value: 'asc' }, skip: 1, limit: 1 }; - const results = await adapter.query(testCollection, filterOptions); - expect(results).toHaveLength(1); - expect(results[0].name).toBe('Query Item 2'); // q1 (10), q2 (20), q3 (30) -> skip 1 -> q2 - }); - - it('should sort results (client-side)', async () => { - const filterOptionsAsc: FilterOptions = { sort: { value: 'asc' } }; - const resultsAsc = await adapter.query(testCollection, filterOptionsAsc); - expect(resultsAsc.map(r => r.name)).toEqual(['Query Item 1', 'Query Item 2', 'Query Item 3']); - - const filterOptionsDesc: FilterOptions = { sort: { value: 'desc' } }; - const resultsDesc = await adapter.query(testCollection, filterOptionsDesc); - expect(resultsDesc.map(r => r.name)).toEqual(['Query Item 3', 'Query Item 2', 'Query Item 1']); - }); - - it('should return empty array if no items match filter', async () => { - const filterOptions: FilterOptions = { filter: { type: 'C' } }; - const results = await adapter.query(testCollection, filterOptions); - expect(results).toHaveLength(0); - }); - }); - - it('should clear a specific collection', async () => { - await adapter.init(); - await adapter.set(testCollection, 'item1', { id: 'item1', data: 'a' }); - await adapter.set(otherCollection, 'item2', { id: 'item2', data: 'b' }); - - await adapter.clearCollection(testCollection); - - const item1 = await adapter.get(testCollection, 'item1'); - const item2 = await adapter.get<{ id: string, data: string }>(otherCollection, 'item2'); - - expect(item1).toBeNull(); - expect(item2).toEqual({ id: 'item2', data: 'b' }); // Other collection should remain - }); - - it('should clear all collections', async () => { - await adapter.init(); - await adapter.set(testCollection, 'item1', { id: 'item1', data: 'a' }); - await adapter.set(otherCollection, 'item2', { id: 'item2', data: 'b' }); - - await adapter.clearAll(); - - const item1 = await adapter.get(testCollection, 'item1'); - const item2 = await adapter.get(otherCollection, 'item2'); - - expect(item1).toBeNull(); - expect(item2).toBeNull(); - expect(await adapter.query(testCollection, {})).toHaveLength(0); - expect(await adapter.query(otherCollection, {})).toHaveLength(0); - }); - - // Add more tests: - // - Error handling during transactions (onerror callbacks) - // - More complex query scenarios if indexes were implemented - // - Database upgrade scenarios (onupgradeneeded) - harder to test reliably -}); \ No newline at end of file diff --git a/src/auth/ApiKeyStrategy.ts b/src/auth/ApiKeyStrategy.ts new file mode 100755 index 0000000..72aca89 --- /dev/null +++ b/src/auth/ApiKeyStrategy.ts @@ -0,0 +1,54 @@ +import { IAuthStrategy } from '@/core/interfaces'; + +/** + * Simple API key authentication strategy. + * Supports configurable header names for different service requirements. + */ +export class ApiKeyStrategy implements IAuthStrategy { + /** + * Creates a new API key authentication strategy. + * @param apiKey - The API key to use for authentication + * @param headerName - The header name to use (defaults to 'Authorization') + */ + constructor( + private readonly apiKey: string, + private readonly headerName: string = 'Authorization' + ) { + if (!apiKey || apiKey.trim() === '') { + throw new Error('API key cannot be empty or null'); + } + if (!headerName || headerName.trim() === '') { + throw new Error('Header name cannot be empty or null'); + } + } + + /** + * Generates authentication headers for API key-based authentication. + * Uses Bearer token format for Authorization header, plain key for custom headers. + * @returns Promise resolving to authentication headers + */ + async getAuthHeaders(): Promise> { + // Use Bearer token format for Authorization header, plain key for custom headers + const value = this.headerName === 'Authorization' + ? `Bearer ${this.apiKey}` + : this.apiKey; + + return { [this.headerName]: value }; + } + + /** + * Gets the configured header name for this strategy. + * @returns The header name that will be used + */ + public getHeaderName(): string { + return this.headerName; + } + + /** + * Checks if this strategy uses the standard Authorization header. + * @returns True if using Authorization header, false for custom headers + */ + public isUsingAuthorizationHeader(): boolean { + return this.headerName === 'Authorization'; + } +} \ No newline at end of file diff --git a/src/auth/GenericOAuthStrategy.ts b/src/auth/GenericOAuthStrategy.ts new file mode 100755 index 0000000..0051efc --- /dev/null +++ b/src/auth/GenericOAuthStrategy.ts @@ -0,0 +1,320 @@ +import { IAuthStrategy } from '@/core/interfaces'; +import { ARTError, ErrorCode } from '@/errors'; +import { Logger } from '@/utils/logger'; + +/** + * Configuration for OAuth 2.0 authentication strategy + */ +export interface OAuthConfig { + /** Client ID for OAuth authentication */ + clientId: string; + /** Client secret for OAuth authentication */ + clientSecret: string; + /** OAuth token endpoint URL */ + tokenEndpoint: string; + /** OAuth scopes to request (space-separated) */ + scopes?: string; + /** Grant type to use (defaults to 'client_credentials') */ + grantType?: 'client_credentials' | 'authorization_code' | 'refresh_token'; + /** Additional headers to send with token requests */ + tokenRequestHeaders?: Record; + /** Custom timeout for token requests in milliseconds (default: 30000) */ + tokenTimeoutMs?: number; + /** Buffer time before token expiry to trigger refresh (default: 300000 = 5 minutes) */ + tokenRefreshBufferMs?: number; +} + +/** + * OAuth token response structure + */ +interface TokenResponse { + access_token: string; + token_type: string; + expires_in?: number; + refresh_token?: string; + scope?: string; +} + +/** + * Cached token with expiry information + */ +interface CachedToken { + accessToken: string; + tokenType: string; + expiresAt: number; // Unix timestamp + refreshToken?: string; + scope?: string; +} + +/** + * Generic OAuth 2.0 authentication strategy with token caching and refresh capabilities. + * Supports client credentials flow and authorization code flow with automatic token refresh. + * @deprecated This strategy is not recommended for browser-based applications as it uses the insecure client_credentials grant type. Please use PKCEOAuthStrategy instead. + */ +export class GenericOAuthStrategy implements IAuthStrategy { + private config: OAuthConfig; + private cachedToken: CachedToken | null = null; + private refreshPromise: Promise | null = null; + + /** + * Creates a new OAuth authentication strategy. + * @param {OAuthConfig} config - OAuth configuration including endpoints, credentials, and options + */ + constructor(config: OAuthConfig) { + this.validateConfig(config); + this.config = { + grantType: 'client_credentials', + tokenTimeoutMs: 30000, + tokenRefreshBufferMs: 300000, // 5 minutes + ...config + }; + + Logger.debug(`GenericOAuthStrategy: Initialized with endpoint ${config.tokenEndpoint} and grant type ${this.config.grantType}`); + } + + /** + * Validates the OAuth configuration to ensure required fields are present. + * @param {OAuthConfig} config - The OAuth configuration to validate. + * @throws {ARTError} If the configuration is invalid. + */ + private validateConfig(config: OAuthConfig): void { + if (!config.clientId || config.clientId.trim() === '') { + throw new ARTError('OAuth client ID cannot be empty', ErrorCode.VALIDATION_ERROR); + } + if (!config.clientSecret || config.clientSecret.trim() === '') { + throw new ARTError('OAuth client secret cannot be empty', ErrorCode.VALIDATION_ERROR); + } + if (!config.tokenEndpoint || config.tokenEndpoint.trim() === '') { + throw new ARTError('OAuth token endpoint cannot be empty', ErrorCode.VALIDATION_ERROR); + } + + // Validate URL format + try { + new URL(config.tokenEndpoint); + } catch (error) { + throw new ARTError('Invalid OAuth token endpoint URL', ErrorCode.VALIDATION_ERROR, error instanceof Error ? error : new Error(String(error))); + } + } + + /** + * Gets authentication headers, automatically handling token refresh if needed. + * @returns {Promise>} A promise that resolves to the authentication headers. + */ + async getAuthHeaders(): Promise> { + try { + const token = await this.getValidToken(); + return { + 'Authorization': `${token.tokenType} ${token.accessToken}` + }; + } catch (error) { + const message = 'Failed to get OAuth authentication headers'; + Logger.error(message, error); + throw new ARTError(message, ErrorCode.LLM_PROVIDER_ERROR, error instanceof Error ? error : new Error(String(error))); + } + } + + /** + * Gets a valid access token, refreshing if necessary. + * @returns {Promise} A promise that resolves to a valid cached token. + */ + private async getValidToken(): Promise { + // Check if we have a valid cached token + if (this.cachedToken && this.isTokenValid(this.cachedToken)) { + Logger.debug('GenericOAuthStrategy: Using cached token'); + return this.cachedToken; + } + + // If a refresh is already in progress, wait for it + if (this.refreshPromise) { + Logger.debug('GenericOAuthStrategy: Waiting for ongoing token refresh'); + return await this.refreshPromise; + } + + // Start new token acquisition + this.refreshPromise = this.acquireNewToken(); + + try { + const token = await this.refreshPromise; + this.cachedToken = token; + return token; + } finally { + this.refreshPromise = null; + } + } + + /** + * Checks if a token is still valid (not expired with buffer). + * @param {CachedToken} token - The token to validate. + * @returns {boolean} True if the token is valid, false otherwise. + */ + private isTokenValid(token: CachedToken): boolean { + const now = Date.now(); + const buffer = this.config.tokenRefreshBufferMs!; + return token.expiresAt > (now + buffer); + } + + /** + * Acquires a new token from the OAuth provider. + * @returns {Promise} A promise that resolves to a new cached token. + */ + private async acquireNewToken(): Promise { + Logger.debug(`GenericOAuthStrategy: Acquiring new token from ${this.config.tokenEndpoint}`); + + const tokenRequest = this.buildTokenRequest(); + + try { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), this.config.tokenTimeoutMs!); + + const response = await fetch(this.config.tokenEndpoint, { + ...tokenRequest, + signal: controller.signal + }); + + clearTimeout(timeoutId); + + if (!response.ok) { + const errorText = await response.text().catch(() => 'Unknown error'); + throw new ARTError( + `OAuth token request failed: ${response.status} ${response.statusText}: ${errorText}`, + ErrorCode.EXTERNAL_SERVICE_ERROR + ); + } + + const tokenResponse: TokenResponse = await response.json(); + return this.processTokenResponse(tokenResponse); + + } catch (error) { + if (error instanceof ARTError) { + throw error; + } + + const message = `Failed to acquire OAuth token: ${error instanceof Error ? error.message : String(error)}`; + Logger.error(message, error); + throw new ARTError(message, ErrorCode.EXTERNAL_SERVICE_ERROR, error instanceof Error ? error : new Error(String(error))); + } + } + + /** + * Builds the token request configuration based on grant type. + * @returns {RequestInit} The request initialization object for the token request. + */ + private buildTokenRequest(): RequestInit { + const headers: Record = { + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept': 'application/json', + ...this.config.tokenRequestHeaders + }; + + let body: string; + + if (this.config.grantType === 'client_credentials') { + const params = new URLSearchParams({ + grant_type: 'client_credentials', + client_id: this.config.clientId, + client_secret: this.config.clientSecret + }); + + if (this.config.scopes) { + params.append('scope', this.config.scopes); + } + + body = params.toString(); + } else if (this.config.grantType === 'refresh_token' && this.cachedToken?.refreshToken) { + const params = new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: this.cachedToken.refreshToken, + client_id: this.config.clientId, + client_secret: this.config.clientSecret + }); + + body = params.toString(); + } else { + throw new ARTError(`Unsupported grant type: ${this.config.grantType}`, ErrorCode.NOT_IMPLEMENTED); + } + + return { + method: 'POST', + headers, + body + }; + } + + /** + * Processes the token response and creates a cached token object. + * @param {TokenResponse} response - The token response from the provider. + * @returns {CachedToken} The processed and cached token. + */ + private processTokenResponse(response: TokenResponse): CachedToken { + if (!response.access_token) { + throw new ARTError('OAuth token response missing access_token', ErrorCode.EXTERNAL_SERVICE_ERROR); + } + + const now = Date.now(); + const expiresIn = response.expires_in || 3600; // Default to 1 hour if not specified + const expiresAt = now + (expiresIn * 1000); + + const cachedToken: CachedToken = { + accessToken: response.access_token, + tokenType: response.token_type || 'Bearer', + expiresAt, + refreshToken: response.refresh_token, + scope: response.scope + }; + + Logger.debug(`GenericOAuthStrategy: Token acquired, expires at ${new Date(expiresAt).toISOString()}`); + return cachedToken; + } + + /** + * Manually refreshes the cached token. + * @returns {Promise>} A promise that resolves to new authentication headers. + */ + public async refreshToken(): Promise> { + Logger.debug('GenericOAuthStrategy: Manual token refresh requested'); + this.cachedToken = null; // Force refresh + this.refreshPromise = null; + return await this.getAuthHeaders(); + } + + /** + * Clears the cached token, forcing a new token request on next use. + */ + public clearTokenCache(): void { + Logger.debug('GenericOAuthStrategy: Clearing token cache'); + this.cachedToken = null; + this.refreshPromise = null; + } + + /** + * Gets information about the current cached token. + * @returns {{ expiresAt: Date; scope?: string; hasRefreshToken: boolean } | null} Token information or null if no token is cached. + */ + public getTokenInfo(): { expiresAt: Date; scope?: string; hasRefreshToken: boolean } | null { + if (!this.cachedToken) { + return null; + } + + return { + expiresAt: new Date(this.cachedToken.expiresAt), + scope: this.cachedToken.scope, + hasRefreshToken: !!this.cachedToken.refreshToken + }; + } + + /** + * Gets the configured OAuth endpoints and settings. + * @returns {Omit} Configuration information (excluding sensitive data). + */ + public getConfig(): Omit { + return { + clientId: this.config.clientId, + tokenEndpoint: this.config.tokenEndpoint, + scopes: this.config.scopes, + grantType: this.config.grantType, + tokenRequestHeaders: this.config.tokenRequestHeaders, + tokenTimeoutMs: this.config.tokenTimeoutMs, + tokenRefreshBufferMs: this.config.tokenRefreshBufferMs + }; + } +} \ No newline at end of file diff --git a/src/auth/PKCEOAuthStrategy.ts b/src/auth/PKCEOAuthStrategy.ts new file mode 100755 index 0000000..542d0c9 --- /dev/null +++ b/src/auth/PKCEOAuthStrategy.ts @@ -0,0 +1,364 @@ +import { IAuthStrategy } from '@/core/interfaces'; +import { ARTError, ErrorCode } from '@/errors'; +import { Logger } from '@/utils/logger'; + +/** + * Configuration for the PKCE OAuth 2.0 authentication strategy. + */ +export interface PKCEOAuthConfig { + /** The OAuth 2.0 authorization endpoint URL. */ + authorizationEndpoint: string; + /** The OAuth 2.0 token endpoint URL. */ + tokenEndpoint: string; + /** The client ID for the application. */ + clientId: string; + /** The redirect URI for the application. */ + redirectUri: string; + /** The scopes to request (space-separated). */ + scopes: string; + /** Optional: The resource parameter to specify the target audience (for MCP servers). */ + resource?: string; + /** Open login in a new tab (default true for ART MCP flows). */ + openInNewTab?: boolean; + /** BroadcastChannel name used to receive auth codes from callback tab (default 'art-auth'). */ + channelName?: string; +} + +interface CachedToken { + accessToken: string; + refreshToken?: string; + expiresAt: number; +} + +/** + * Implements the OAuth 2.0 Authorization Code Flow with PKCE (Proof Key for Code Exchange). + * This is the recommended, most secure method for authenticating users in browser-based applications. + */ +export class PKCEOAuthStrategy implements IAuthStrategy { + private config: PKCEOAuthConfig; + private cachedToken: CachedToken | null = null; + private codeVerifierForPendingLogin: string | null = null; + private loginWaiter: { resolve: () => void; reject: (e: any) => void } | null = null; + private channel?: BroadcastChannel; + + /** + * Creates an instance of PKCEOAuthStrategy. + * @param {PKCEOAuthConfig} config - The configuration for the PKCE OAuth 2.0 strategy. + */ + constructor(config: PKCEOAuthConfig) { + if (!config.authorizationEndpoint || !config.tokenEndpoint || !config.clientId || !config.redirectUri || !config.scopes) { + throw new ARTError( + 'PKCEOAuthStrategy requires authorizationEndpoint, tokenEndpoint, clientId, redirectUri, and scopes.', + ErrorCode.INVALID_CONFIG, + ); + } + this.config = { openInNewTab: true, channelName: 'art-auth', ...config }; + + // Setup BroadcastChannel to receive auth codes from the callback tab (new-tab flow) + try { + this.channel = new BroadcastChannel(this.config.channelName!); + this.channel.onmessage = async (evt: MessageEvent) => { + const msg = evt.data || {}; + if (msg?.type === 'art-auth-code' && typeof msg?.code === 'string') { + try { + await this.exchangeCodeForToken(msg.code); + if (this.loginWaiter) this.loginWaiter.resolve(); + } catch (e) { + if (this.loginWaiter) this.loginWaiter.reject(e); + } finally { + this.loginWaiter = null; + } + } + }; + } catch { + // BroadcastChannel not available; new-tab flow will not work in this environment + } + } + + /** + * Initiates the PKCE login flow by redirecting the user to the authorization endpoint. + * @returns {Promise} A promise that resolves when the login process is complete. + */ + public async login(): Promise { + const codeVerifier = this.generateCodeVerifier(); + const codeChallenge = await this.generateCodeChallenge(codeVerifier); + + // Store verifier for same-tab fallback and keep in-memory for new-tab token exchange + sessionStorage.setItem('pkce_code_verifier', codeVerifier); + this.codeVerifierForPendingLogin = codeVerifier; + + const params = new URLSearchParams({ + client_id: this.config.clientId, + redirect_uri: this.config.redirectUri, + scope: this.config.scopes, + response_type: 'code', + code_challenge: codeChallenge, + code_challenge_method: 'S256', + }); + + if (this.config.resource) { + params.append('resource', this.config.resource); + } + + // Include a minimal state that carries the BroadcastChannel name for the callback tab + try { + const statePayload = { ch: this.config.channelName }; + const state = btoa(unescape(encodeURIComponent(JSON.stringify(statePayload)))).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); + params.append('state', state); + } catch {/* ignore */} + + const authorizationUrl = `${this.config.authorizationEndpoint}?${params.toString()}`; + Logger.info('Starting PKCE login at authorization endpoint.'); + + if (this.config.openInNewTab) { + const popup = window.open(authorizationUrl, '_blank', 'noopener,noreferrer'); + if (!popup) { + throw new ARTError('Popup blocked. Please allow popups to continue login.', ErrorCode.INVALID_CONFIG); + } + // Wait for token acquisition via BroadcastChannel + await new Promise((resolve, reject) => { + this.loginWaiter = { resolve, reject }; + setTimeout(() => { + if (this.loginWaiter) { + this.loginWaiter = null; + reject(new ARTError('Login timed out. Please try again.', ErrorCode.TIMEOUT)); + } + }, 180000); // 3 minutes + }); + return; + } + + // Same-tab redirect fallback (not preferred for ART MCP flows) + window.location.assign(authorizationUrl); + } + + /** + * Handles the redirect from the authorization server. + * This method should be called on the redirect URI page. + * It exchanges the authorization code for an access token. + * @returns {Promise} A promise that resolves when the redirect has been handled. + */ + public async handleRedirect(): Promise { + const params = new URLSearchParams(window.location.search); + const code = params.get('code'); + + if (!code) { + const error = params.get('error'); + const errorDescription = params.get('error_description'); + throw new ARTError( + `OAuth error on redirect: ${error} - ${errorDescription || 'No description provided.'}`, + ErrorCode.EXTERNAL_SERVICE_ERROR, + ); + } + + const codeVerifier = sessionStorage.getItem('pkce_code_verifier'); + if (!codeVerifier) { + throw new ARTError('No PKCE code verifier found in session storage. Please initiate login again.', ErrorCode.INVALID_CONFIG); + } + + try { + const tokenResponse = await fetch(this.config.tokenEndpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ + grant_type: 'authorization_code', + client_id: this.config.clientId, + redirect_uri: this.config.redirectUri, + code: code, + code_verifier: codeVerifier, + }), + }); + + if (!tokenResponse.ok) { + const errorText = await tokenResponse.text(); + throw new ARTError(`Failed to exchange authorization code for token: ${errorText}`, ErrorCode.NETWORK_ERROR); + } + + const tokenData = await tokenResponse.json(); + this.cachedToken = { + accessToken: tokenData.access_token, + refreshToken: tokenData.refresh_token, + expiresAt: Date.now() + (tokenData.expires_in || 3600) * 1000, + }; + + Logger.info('Successfully obtained access token.'); + } catch (error) { + Logger.error('Error during token exchange:', error); + throw new ARTError('An unexpected error occurred during the token exchange process.', ErrorCode.UNKNOWN_ERROR, error as Error); + } finally { + sessionStorage.removeItem('pkce_code_verifier'); + } + } + + /** + * Gets the authentication headers, automatically handling token refresh if needed. + * @returns {Promise>} A promise that resolves to the authentication headers. + */ + public async getAuthHeaders(): Promise> { + if (!this.cachedToken) { + throw new ARTError('No cached token available. Please login first.', ErrorCode.INVALID_CONFIG); + } + + if (Date.now() >= this.cachedToken.expiresAt) { + Logger.info('Access token expired, attempting to refresh.'); + await this.refreshToken(); + } + + return { + Authorization: `Bearer ${this.cachedToken!.accessToken}`, + }; + } + + /** + * Clears the cached token. + */ + public logout(): void { + this.cachedToken = null; + sessionStorage.removeItem('pkce_code_verifier'); + Logger.info('Cached token and PKCE code verifier cleared.'); + } + + /** + * Checks if there is a valid, non-expired token. + * @returns {Promise} A promise that resolves to true if the token is valid, false otherwise. + */ + public async isAuthenticated(): Promise { + if (!this.cachedToken) { + return false; + } + + if (Date.now() >= this.cachedToken.expiresAt) { + try { + await this.refreshToken(); + return true; + } catch (error) { + return false; + } + } + + return true; + } + + // --- Private Helper Methods --- + + /** + * Generates a random string for the code verifier. + * @returns {string} The generated code verifier. + */ + private generateCodeVerifier(): string { + const randomBytes = new Uint8Array(32); + window.crypto.getRandomValues(randomBytes); + return this.base64UrlEncode(randomBytes); + } + + /** + * Generates a code challenge from a code verifier. + * @param {string} verifier - The code verifier. + * @returns {Promise} A promise that resolves to the code challenge. + */ + private async generateCodeChallenge(verifier: string): Promise { + const encoder = new TextEncoder(); + const data = encoder.encode(verifier); + const hashBuffer = await window.crypto.subtle.digest('SHA-256', data); + return this.base64UrlEncode(new Uint8Array(hashBuffer)); + } + + /** + * Encodes a byte array into a base64 URL-safe string. + * @param {Uint8Array} bytes - The byte array to encode. + * @returns {string} The base64 URL-safe encoded string. + */ + private base64UrlEncode(bytes: Uint8Array): string { + return btoa(String.fromCharCode.apply(null, Array.from(bytes))) + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/, ''); + } + + /** + * Refreshes the access token using the refresh token. + * @returns {Promise} A promise that resolves when the token has been refreshed. + */ + private async refreshToken(): Promise { + if (!this.cachedToken?.refreshToken) { + this.logout(); // Clear expired token + throw new ARTError('No refresh token available. User must re-authenticate.', ErrorCode.INVALID_CONFIG); + } + + try { + const tokenResponse = await fetch(this.config.tokenEndpoint, { + method: 'POST', + headers: { + 'Content-Type': 'application/x-www-form-urlencoded', + }, + body: new URLSearchParams({ + grant_type: 'refresh_token', + client_id: this.config.clientId, + refresh_token: this.cachedToken.refreshToken, + }), + }); + + if (!tokenResponse.ok) { + const errorText = await tokenResponse.text(); + this.logout(); // Clear tokens on failure + throw new ARTError(`Failed to refresh token: ${errorText}`, ErrorCode.NETWORK_ERROR); + } + + const tokenData = await tokenResponse.json(); + this.cachedToken = { + accessToken: tokenData.access_token, + // Keep the same refresh token if a new one isn't provided + refreshToken: tokenData.refresh_token || this.cachedToken.refreshToken, + expiresAt: Date.now() + (tokenData.expires_in || 3600) * 1000, + }; + + Logger.info('Successfully refreshed access token.'); + } catch (error) { + this.logout(); + Logger.error('Error during token refresh:', error); + throw new ARTError('An unexpected error occurred during the token refresh process.', ErrorCode.UNKNOWN_ERROR, error as Error); + } + } + + // --- Private: Exchange code to token using stored verifier (new-tab flow) --- + /** + * Exchanges an authorization code for an access token. + * @param {string} code - The authorization code. + * @returns {Promise} A promise that resolves when the token exchange is complete. + */ + private async exchangeCodeForToken(code: string): Promise { + if (!this.codeVerifierForPendingLogin) { + throw new ARTError('Missing code verifier for PKCE exchange.', ErrorCode.INVALID_CONFIG); + } + + const tokenResponse = await fetch(this.config.tokenEndpoint, { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: new URLSearchParams({ + grant_type: 'authorization_code', + client_id: this.config.clientId, + redirect_uri: this.config.redirectUri, + code, + code_verifier: this.codeVerifierForPendingLogin, + }), + }); + + if (!tokenResponse.ok) { + const errorText = await tokenResponse.text(); + throw new ARTError(`Failed to exchange authorization code for token: ${errorText}`, ErrorCode.NETWORK_ERROR); + } + + const tokenData = await tokenResponse.json(); + this.cachedToken = { + accessToken: tokenData.access_token, + refreshToken: tokenData.refresh_token, + expiresAt: Date.now() + (tokenData.expires_in || 3600) * 1000, + }; + + // Clear pending verifier + this.codeVerifierForPendingLogin = null; + sessionStorage.removeItem('pkce_code_verifier'); + } +} \ No newline at end of file diff --git a/src/auth/ZyntopiaOAuthStrategy.ts b/src/auth/ZyntopiaOAuthStrategy.ts new file mode 100755 index 0000000..9300aac --- /dev/null +++ b/src/auth/ZyntopiaOAuthStrategy.ts @@ -0,0 +1,233 @@ +import { GenericOAuthStrategy, type OAuthConfig } from '@/auth/GenericOAuthStrategy'; +import { Logger } from '@/utils/logger'; + +/** + * Configuration specific to Zyntopia OAuth strategy + */ +export interface ZyntopiaOAuthConfig { + /** Client ID for Zyntopia OAuth authentication */ + clientId: string; + /** Client secret for Zyntopia OAuth authentication */ + clientSecret: string; + /** Optional custom token endpoint (defaults to Zyntopia's standard endpoint) */ + tokenEndpoint?: string; + /** Optional custom scopes (defaults to Zyntopia's standard scopes) */ + scopes?: string; + /** Optional environment ('production' | 'staging' | 'development') */ + environment?: 'production' | 'staging' | 'development'; + /** Optional custom timeout for token requests in milliseconds */ + tokenTimeoutMs?: number; + /** Optional custom buffer time before token expiry to trigger refresh */ + tokenRefreshBufferMs?: number; + /** Additional custom headers for Zyntopia API requirements */ + customHeaders?: Record; +} + +/** + * Zyntopia-specific OAuth 2.0 authentication strategy. + * Pre-configured for Zyntopia services with standard endpoints, scopes, and authentication flows. + * Extends GenericOAuthStrategy with Zyntopia-specific defaults and configurations. + */ +export class ZyntopiaOAuthStrategy extends GenericOAuthStrategy { + private static readonly ZYNTOPIA_ENDPOINTS = { + production: 'https://auth.zyntopia.com/oauth/token', + staging: 'https://staging-auth.zyntopia.com/oauth/token', + development: 'https://dev-auth.zyntopia.com/oauth/token' + }; + + private static readonly ZYNTOPIA_DEFAULT_SCOPES = { + production: 'zyntopia:read zyntopia:write zyntopia:admin', + staging: 'zyntopia:read zyntopia:write zyntopia:admin zyntopia:debug', + development: 'zyntopia:read zyntopia:write zyntopia:admin zyntopia:debug zyntopia:test' + }; + + private zyntopiaConfig: Required; + + /** + * Creates a new Zyntopia OAuth authentication strategy. + * @param {ZyntopiaOAuthConfig} config - Zyntopia-specific OAuth configuration + */ + constructor(config: ZyntopiaOAuthConfig) { + // Set defaults for Zyntopia + const environment = config.environment || 'production'; + const defaultTokenEndpoint = ZyntopiaOAuthStrategy.ZYNTOPIA_ENDPOINTS[environment]; + const defaultScopes = ZyntopiaOAuthStrategy.ZYNTOPIA_DEFAULT_SCOPES[environment]; + + // Build the complete configuration with Zyntopia defaults + const zyntopiaConfig: Required = { + clientId: config.clientId, + clientSecret: config.clientSecret, + tokenEndpoint: config.tokenEndpoint || defaultTokenEndpoint, + scopes: config.scopes || defaultScopes, + environment, + tokenTimeoutMs: config.tokenTimeoutMs || 30000, + tokenRefreshBufferMs: config.tokenRefreshBufferMs || 300000, // 5 minutes + customHeaders: config.customHeaders || {} + }; + + // Create the generic OAuth config with Zyntopia-specific settings + const genericConfig: OAuthConfig = { + clientId: zyntopiaConfig.clientId, + clientSecret: zyntopiaConfig.clientSecret, + tokenEndpoint: zyntopiaConfig.tokenEndpoint, + scopes: zyntopiaConfig.scopes, + grantType: 'client_credentials', // Zyntopia uses client credentials flow + tokenTimeoutMs: zyntopiaConfig.tokenTimeoutMs, + tokenRefreshBufferMs: zyntopiaConfig.tokenRefreshBufferMs, + tokenRequestHeaders: { + 'User-Agent': 'ART-Framework-Zyntopia/1.0', + 'X-Zyntopia-Client': 'art-framework', + 'X-Zyntopia-Environment': environment, + ...zyntopiaConfig.customHeaders + } + }; + + // Initialize the parent GenericOAuthStrategy + super(genericConfig); + + this.zyntopiaConfig = zyntopiaConfig; + + Logger.debug(`ZyntopiaOAuthStrategy: Initialized for ${environment} environment with endpoint ${zyntopiaConfig.tokenEndpoint}`); + } + + /** + * Gets the Zyntopia-specific configuration. + * @returns {Omit} Zyntopia configuration (excluding sensitive data). + */ + public getZyntopiaConfig(): Omit { + return { + clientId: this.zyntopiaConfig.clientId, + tokenEndpoint: this.zyntopiaConfig.tokenEndpoint, + scopes: this.zyntopiaConfig.scopes, + environment: this.zyntopiaConfig.environment, + tokenTimeoutMs: this.zyntopiaConfig.tokenTimeoutMs, + tokenRefreshBufferMs: this.zyntopiaConfig.tokenRefreshBufferMs, + customHeaders: this.zyntopiaConfig.customHeaders + }; + } + + /** + * Gets the current environment this strategy is configured for. + * @returns {'production' | 'staging' | 'development'} The environment ('production', 'staging', or 'development'). + */ + public getEnvironment(): 'production' | 'staging' | 'development' { + return this.zyntopiaConfig.environment; + } + + /** + * Checks if this strategy is configured for production environment. + * @returns {boolean} True if configured for production, false otherwise. + */ + public isProduction(): boolean { + return this.zyntopiaConfig.environment === 'production'; + } + + /** + * Checks if this strategy is configured for development/testing. + * @returns {boolean} True if configured for development or staging, false for production. + */ + public isDevelopment(): boolean { + return this.zyntopiaConfig.environment !== 'production'; + } + + /** + * Creates a ZyntopiaOAuthStrategy instance pre-configured for production. + * @param {string} clientId - Zyntopia client ID + * @param {string} clientSecret - Zyntopia client secret + * @param {string} [customScopes] - Optional custom scopes (defaults to production scopes) + * @returns {ZyntopiaOAuthStrategy} Configured ZyntopiaOAuthStrategy for production. + */ + public static forProduction( + clientId: string, + clientSecret: string, + customScopes?: string + ): ZyntopiaOAuthStrategy { + return new ZyntopiaOAuthStrategy({ + clientId, + clientSecret, + environment: 'production', + scopes: customScopes + }); + } + + /** + * Creates a ZyntopiaOAuthStrategy instance pre-configured for staging. + * @param {string} clientId - Zyntopia client ID + * @param {string} clientSecret - Zyntopia client secret + * @param {string} [customScopes] - Optional custom scopes (defaults to staging scopes) + * @returns {ZyntopiaOAuthStrategy} Configured ZyntopiaOAuthStrategy for staging. + */ + public static forStaging( + clientId: string, + clientSecret: string, + customScopes?: string + ): ZyntopiaOAuthStrategy { + return new ZyntopiaOAuthStrategy({ + clientId, + clientSecret, + environment: 'staging', + scopes: customScopes + }); + } + + /** + * Creates a ZyntopiaOAuthStrategy instance pre-configured for development. + * @param {string} clientId - Zyntopia client ID + * @param {string} clientSecret - Zyntopia client secret + * @param {string} [customScopes] - Optional custom scopes (defaults to development scopes) + * @returns {ZyntopiaOAuthStrategy} Configured ZyntopiaOAuthStrategy for development. + */ + public static forDevelopment( + clientId: string, + clientSecret: string, + customScopes?: string + ): ZyntopiaOAuthStrategy { + return new ZyntopiaOAuthStrategy({ + clientId, + clientSecret, + environment: 'development', + scopes: customScopes + }); + } + + /** + * Gets the default scopes for a specific environment. + * @param {'production' | 'staging' | 'development'} environment - The environment to get scopes for + * @returns {string} Default scopes for the specified environment. + */ + public static getDefaultScopes(environment: 'production' | 'staging' | 'development'): string { + return ZyntopiaOAuthStrategy.ZYNTOPIA_DEFAULT_SCOPES[environment]; + } + + /** + * Gets the token endpoint for a specific environment. + * @param {'production' | 'staging' | 'development'} environment - The environment to get endpoint for + * @returns {string} Token endpoint URL for the specified environment. + */ + public static getTokenEndpoint(environment: 'production' | 'staging' | 'development'): string { + return ZyntopiaOAuthStrategy.ZYNTOPIA_ENDPOINTS[environment]; + } + + /** + * Validates Zyntopia-specific configuration requirements. + * @param {ZyntopiaOAuthConfig} config - Configuration to validate + * @throws {Error} If configuration is invalid. + */ + public static validateZyntopiaConfig(config: ZyntopiaOAuthConfig): void { + if (!config.clientId || config.clientId.trim() === '') { + throw new Error('Zyntopia client ID is required'); + } + if (!config.clientSecret || config.clientSecret.trim() === '') { + throw new Error('Zyntopia client secret is required'); + } + if (config.environment && !['production', 'staging', 'development'].includes(config.environment)) { + throw new Error('Zyntopia environment must be one of: production, staging, development'); + } + if (config.tokenTimeoutMs && (config.tokenTimeoutMs < 1000 || config.tokenTimeoutMs > 60000)) { + throw new Error('Zyntopia token timeout must be between 1000ms and 60000ms'); + } + if (config.tokenRefreshBufferMs && (config.tokenRefreshBufferMs < 30000 || config.tokenRefreshBufferMs > 600000)) { + throw new Error('Zyntopia token refresh buffer must be between 30000ms and 600000ms'); + } + } +} \ No newline at end of file diff --git a/src/core/agent-factory.test.ts b/src/core/agent-factory.test.ts deleted file mode 100644 index ae02458..0000000 --- a/src/core/agent-factory.test.ts +++ /dev/null @@ -1,272 +0,0 @@ -// src/core/agent-factory.test.ts -import { describe, it, expect, vi, beforeEach, Mock } from 'vitest'; -import { AgentFactory, StorageConfig } from './agent-factory'; // Import only AgentFactory here -import type { AgentFactoryConfig } from './agent-factory'; // Import type separately -import type { IToolExecutor } from './interfaces'; // Use type-only import for unused types -import type { ProviderManagerConfig } from '../types/providers'; // Use type-only import -import { PESAgent } from './agents/pes-agent'; // Revert to relative -import type { JsonSchema } from '../types'; // Use type-only import - -// --- Mock Concrete Implementations --- -// Mock entire modules that the factory imports using relative paths -vi.mock('../adapters/storage/inMemory', () => ({ // Correct casing: inMemory - InMemoryStorageAdapter: vi.fn().mockImplementation(() => ({ - init: vi.fn().mockResolvedValue(undefined), - })) -})); -vi.mock('../adapters/storage/indexedDB', () => ({ // Relative path - IndexedDBStorageAdapter: vi.fn().mockImplementation(() => ({ - init: vi.fn().mockResolvedValue(undefined), - })) -})); -vi.mock('../systems/context/repositories/ConversationRepository', () => ({ ConversationRepository: vi.fn() })); // Relative path -vi.mock('../systems/context/repositories/ObservationRepository', () => ({ ObservationRepository: vi.fn() })); // Relative path -vi.mock('../systems/context/repositories/StateRepository', () => ({ StateRepository: vi.fn() })); // Relative path -vi.mock('../systems/ui/typed-socket', () => ({ TypedSocket: vi.fn() })); // Relative path -vi.mock('../systems/ui/ui-system', () => ({ // Relative path - UISystem: vi.fn().mockImplementation(() => ({ - getObservationSocket: vi.fn(() => vi.fn()), - getConversationSocket: vi.fn(() => vi.fn()), - getLLMStreamSocket: vi.fn(() => vi.fn()), - })) -})); -vi.mock('../systems/context/managers/ConversationManager', () => ({ ConversationManager: vi.fn() })); // Relative path -vi.mock('../systems/context/managers/StateManager', () => ({ StateManager: vi.fn() })); // Relative path -vi.mock('../systems/observation/observation-manager', () => ({ ObservationManager: vi.fn() })); // Relative path -vi.mock('../systems/tool/ToolRegistry', () => ({ // Relative path - ToolRegistry: vi.fn().mockImplementation(() => ({ - registerTool: vi.fn().mockResolvedValue(undefined), - getAvailableTools: vi.fn().mockResolvedValue([]), - })) -})); -// Mock ProviderManagerImpl -vi.mock('../providers/ProviderManagerImpl', () => ({ // Relative path - ProviderManagerImpl: vi.fn().mockImplementation(() => ({ - getAdapter: vi.fn(), - })) -})); -vi.mock('../systems/reasoning/ReasoningEngine', () => ({ ReasoningEngine: vi.fn() })); // Relative path -vi.mock('../systems/reasoning/PromptManager', () => ({ PromptManager: vi.fn() })); // Relative path -vi.mock('../systems/reasoning/OutputParser', () => ({ OutputParser: vi.fn() })); // Relative path -vi.mock('../systems/tool/ToolSystem', () => ({ ToolSystem: vi.fn() })); // Relative path -vi.mock('./agents/pes-agent', () => ({ PESAgent: vi.fn() })); // Relative path - -// Import the mocked classes after mocking the modules (using relative paths) -import { InMemoryStorageAdapter } from '../adapters/storage/inMemory'; // Correct casing: inMemory -import { IndexedDBStorageAdapter } from '../adapters/storage/indexedDB'; -import { ConversationRepository } from '../systems/context/repositories/ConversationRepository'; -import { ObservationRepository } from '../systems/context/repositories/ObservationRepository'; -import { StateRepository } from '../systems/context/repositories/StateRepository'; -// import { TypedSocket } from '../systems/ui/typed-socket'; // Removed unused import -import { UISystem as UISystemMock } from '../systems/ui/ui-system'; // Use relative path -import { ConversationManager } from '../systems/context/managers/ConversationManager'; -import { StateManager } from '../systems/context/managers/StateManager'; -import { ObservationManager } from '../systems/observation/observation-manager'; -import { ToolRegistry } from '../systems/tool/ToolRegistry'; -import { ProviderManagerImpl } from '../providers/ProviderManagerImpl'; -import { ReasoningEngine } from '../systems/reasoning/ReasoningEngine'; -import { PromptManager } from '../systems/reasoning/PromptManager'; -import { OutputParser } from '../systems/reasoning/OutputParser'; -import { ToolSystem } from '../systems/tool/ToolSystem'; - - -// --- Test Data --- -const mockStorageConfigMemory: StorageConfig = { type: 'memory' }; -const mockStorageConfigIndexedDB: StorageConfig = { type: 'indexedDB', dbName: 'TestDB' }; -// Define a mock ProviderManagerConfig -const mockProviderManagerConfig: ProviderManagerConfig = { - availableProviders: [{ name: 'mock-provider', adapter: vi.fn(), isLocal: true }], // Minimal config - maxParallelApiInstancesPerProvider: 1, - apiInstanceIdleTimeoutSeconds: 10, -}; -// Fix mock tool schemas -const mockToolSchema: JsonSchema = { type: 'object', properties: {} }; -const mockTool1: IToolExecutor = { schema: { name: 'tool1', description: '', inputSchema: mockToolSchema }, execute: vi.fn() }; -const mockTool2: IToolExecutor = { schema: { name: 'tool2', description: '', inputSchema: mockToolSchema }, execute: vi.fn() }; - -const mockBaseConfig: AgentFactoryConfig = { - storage: mockStorageConfigMemory, - providers: mockProviderManagerConfig, // Use providers key -}; - -// --- Test Suite --- -describe('AgentFactory', () => { - - beforeEach(() => { - vi.clearAllMocks(); - }); - - it('should throw error if storage config is missing', () => { - expect(() => new AgentFactory({ providers: mockProviderManagerConfig } as any)) // Check for providers - .toThrow("AgentFactoryConfig requires 'storage' configuration."); - }); - - it('should throw error if providers config is missing', () => { - expect(() => new AgentFactory({ storage: mockStorageConfigMemory } as any)) // Check for providers - .toThrow("AgentFactoryConfig requires 'providers' configuration."); - }); - - describe('initialize', () => { - it('should initialize InMemoryStorageAdapter correctly', async () => { - // Re-add 'as any' assertion to bypass persistent type error - const factory = new AgentFactory(mockBaseConfig as any); - await factory.initialize(); - expect(InMemoryStorageAdapter).toHaveBeenCalledTimes(1); - expect(IndexedDBStorageAdapter).not.toHaveBeenCalled(); - const adapterInstance = (InMemoryStorageAdapter as Mock).mock.results[0].value; - expect(adapterInstance.init).toHaveBeenCalledTimes(1); - }); - - it('should initialize IndexedDBStorageAdapter correctly', async () => { - const config = { ...mockBaseConfig, storage: mockStorageConfigIndexedDB }; - // Re-add 'as any' assertion - const factory = new AgentFactory(config as any); - await factory.initialize(); - expect(IndexedDBStorageAdapter).toHaveBeenCalledTimes(1); - expect(IndexedDBStorageAdapter).toHaveBeenCalledWith({ - dbName: mockStorageConfigIndexedDB.dbName, - objectStores: ['conversations', 'observations', 'state'] - }); - expect(InMemoryStorageAdapter).not.toHaveBeenCalled(); - const adapterInstance = (IndexedDBStorageAdapter as Mock).mock.results[0].value; - expect(adapterInstance.init).toHaveBeenCalledTimes(1); - }); - - it('should initialize repositories with the storage adapter', async () => { - // Re-add 'as any' assertion - const factory = new AgentFactory(mockBaseConfig as any); - await factory.initialize(); - const adapterInstance = (InMemoryStorageAdapter as Mock).mock.results[0].value; - expect(ConversationRepository).toHaveBeenCalledWith(adapterInstance); - expect(ObservationRepository).toHaveBeenCalledWith(adapterInstance); - expect(StateRepository).toHaveBeenCalledWith(adapterInstance); - }); - - it('should initialize UI system and sockets', async () => { - // Re-add 'as any' assertion - // const factory = new AgentFactory(mockBaseConfig as any); // Removed unused factory variable - await new AgentFactory(mockBaseConfig as any).initialize(); // Initialize directly - // This test might be less relevant now as TypedSocket is an internal detail of the mocked UISystem/Sockets - // We primarily care that UISystem is initialized correctly. - // expect(TypedSocket).toHaveBeenCalledTimes(2); // Commenting out as it's an internal detail - - // Check UISystem initialization - const obsRepoInstance = (ObservationRepository as Mock).mock.results[0].value; - const convRepoInstance = (ConversationRepository as Mock).mock.results[0].value; - expect(UISystemMock).toHaveBeenCalledWith(obsRepoInstance, convRepoInstance); // Check mock UISystem call - }); - - it('should initialize managers with repositories and sockets', async () => { - // Re-add 'as any' assertion - const factory = new AgentFactory(mockBaseConfig as any); - await factory.initialize(); - const repoConvInstance = (ConversationRepository as Mock).mock.results[0].value; - const repoObsInstance = (ObservationRepository as Mock).mock.results[0].value; - const repoStateInstance = (StateRepository as Mock).mock.results[0].value; - const uiSystemInstance = (UISystemMock as Mock).mock.results[0].value; // Use aliased mock - const obsSocket = uiSystemInstance.getObservationSocket(); // Get mock socket from mock UI system - const convSocket = uiSystemInstance.getConversationSocket(); // Get mock socket from mock UI system - - expect(ConversationManager).toHaveBeenCalledWith(repoConvInstance, convSocket); // Use updated name - expect(StateManager).toHaveBeenCalledWith(repoStateInstance); // Use updated name - expect(ObservationManager).toHaveBeenCalledWith(repoObsInstance, obsSocket); - }); - - it('should initialize ToolRegistry and register initial tools', async () => { - const config = { ...mockBaseConfig, tools: [mockTool1, mockTool2] }; - // Re-add 'as any' assertion - // const factory = new AgentFactory(config as any); // Removed unused factory variable - await new AgentFactory(config as any).initialize(); // Initialize directly for the test effects - const stateManagerInstance = (StateManager as Mock).mock.results[0].value; // Get StateManager instance - expect(ToolRegistry).toHaveBeenCalledWith(stateManagerInstance); // Check ToolRegistry dependency - const registryInstance = (ToolRegistry as Mock).mock.results[0].value; - expect(registryInstance.registerTool).toHaveBeenCalledTimes(2); - expect(registryInstance.registerTool).toHaveBeenCalledWith(mockTool1); - expect(registryInstance.registerTool).toHaveBeenCalledWith(mockTool2); - }); - - // Remove tests related to direct adapter initialization and old reasoning config - // it('should initialize OpenAIAdapter correctly', async () => { ... }); - // it('should throw error for unsupported reasoning provider', async () => { ... }); - - it('should initialize ProviderManager correctly', async () => { - // Re-add 'as any' assertion - const factory = new AgentFactory(mockBaseConfig as any); - await factory.initialize(); - expect(ProviderManagerImpl).toHaveBeenCalledTimes(1); - expect(ProviderManagerImpl).toHaveBeenCalledWith(mockBaseConfig.providers); // Check with correct config property - }); - - - it('should initialize reasoning components', async () => { - // Re-add 'as any' assertion - const factory = new AgentFactory(mockBaseConfig as any); - await factory.initialize(); - const providerManagerInstance = (ProviderManagerImpl as Mock).mock.results[0].value; - expect(ReasoningEngine).toHaveBeenCalledWith(providerManagerInstance); // Use updated name - expect(PromptManager).toHaveBeenCalledTimes(1); // Use updated name - expect(OutputParser).toHaveBeenCalledTimes(1); // Use updated name - }); - - it('should initialize ToolSystem', async () => { - // Re-add 'as any' assertion - const factory = new AgentFactory(mockBaseConfig as any); - await factory.initialize(); - const registryInstance = (ToolRegistry as Mock).mock.results[0].value; // Use updated name - const stateManagerInstance = (StateManager as Mock).mock.results[0].value; // Use updated name - const obsManagerInstance = (ObservationManager as Mock).mock.results[0].value; - expect(ToolSystem).toHaveBeenCalledWith(registryInstance, stateManagerInstance, obsManagerInstance); // Use updated name - }); - }); - - describe('createAgent', () => { - it('should throw error if initialize() has not been called', () => { - // Re-add 'as any' assertion - const factory = new AgentFactory(mockBaseConfig as any); - expect(() => factory.createAgent()).toThrow("AgentFactory not fully initialized."); // Update error message check - }); - - it('should create and return a PESAgent instance after initialization', async () => { - // Re-add 'as any' assertion - const factory = new AgentFactory(mockBaseConfig as any); - await factory.initialize(); - const agent = factory.createAgent(); - - expect(agent).toBeDefined(); - expect(PESAgent).toHaveBeenCalledTimes(1); - - // Verify dependencies passed to PESAgent constructor (using updated names) - const expectedDeps = { - stateManager: (StateManager as Mock).mock.results[0].value, - conversationManager: (ConversationManager as Mock).mock.results[0].value, - toolRegistry: (ToolRegistry as Mock).mock.results[0].value, - promptManager: (PromptManager as Mock).mock.results[0].value, - reasoningEngine: (ReasoningEngine as Mock).mock.results[0].value, - outputParser: (OutputParser as Mock).mock.results[0].value, - observationManager: (ObservationManager as Mock).mock.results[0].value, - toolSystem: (ToolSystem as Mock).mock.results[0].value, - uiSystem: (UISystemMock as Mock).mock.results[0].value, // Use aliased mock - }; - expect(PESAgent).toHaveBeenCalledWith(expectedDeps); - }); - }); - - describe('Getters', () => { - it('should return null for components before initialization', () => { - // Re-add 'as any' assertion - const factory = new AgentFactory(mockBaseConfig as any); - expect(factory.getStorageAdapter()).toBeNull(); - expect(factory.getUISystem()).toBeNull(); - expect(factory.getToolRegistry()).toBeNull(); - }); - - it('should return initialized components after initialization', async () => { - // Re-add 'as any' assertion - const factory = new AgentFactory(mockBaseConfig as any); - await factory.initialize(); - expect(factory.getStorageAdapter()).toBe((InMemoryStorageAdapter as Mock).mock.results[0].value); - expect(factory.getUISystem()).toBe((UISystemMock as Mock).mock.results[0].value); // Use aliased mock - expect(factory.getToolRegistry()).toBe((ToolRegistry as Mock).mock.results[0].value); // Use updated name - }); - }); -}); \ No newline at end of file diff --git a/src/core/agent-factory.ts b/src/core/agent-factory.ts old mode 100644 new mode 100755 index 5e3f3cb..70fc784 --- a/src/core/agent-factory.ts +++ b/src/core/agent-factory.ts @@ -5,6 +5,7 @@ import { IConversationRepository, IObservationRepository, IStateRepository, + IA2ATaskRepository, ConversationManager, StateManager, ObservationManager, @@ -18,45 +19,52 @@ import { ToolSystem, UISystem // Removed ObservationSocket, ConversationSocket interface imports -} from './interfaces'; -import { IProviderManager } from '../types/providers'; // Corrected path +} from '@/core/interfaces'; +import { IProviderManager } from '@/types/providers'; // Corrected path // eslint-disable-next-line @typescript-eslint/no-unused-vars -import type { ProviderManagerConfig } from '../types/providers'; // type-only import +import type { ProviderManagerConfig } from '@/types/providers'; // type-only import // Import ArtInstanceConfig and StateSavingStrategy // eslint-disable-next-line @typescript-eslint/no-unused-vars -import type { ArtInstanceConfig } from '../types'; // type-only import -// eslint-disable-next-line @typescript-eslint/no-unused-vars -import type { StateSavingStrategy } from '../types'; // type-only import -import { ProviderManagerImpl } from '../providers/ProviderManagerImpl'; // Corrected path -import { PESAgent } from './agents/pes-agent'; +import { ArtInstanceConfig, StateSavingStrategy } from '@/types'; +import { ProviderManagerImpl } from '@/systems/reasoning/ProviderManagerImpl'; // Corrected path +import { PESAgent } from '@/core/agents/pes-agent'; // Import concrete implementations (assuming paths) // Storage Adapters -import { InMemoryStorageAdapter } from '../adapters/storage/inMemory'; // Corrected path -import { IndexedDBStorageAdapter } from '../adapters/storage/indexedDB'; // Corrected path +import { InMemoryStorageAdapter } from '@/integrations/storage/inMemory'; // Corrected path +import { IndexedDBStorageAdapter } from '@/integrations/storage/indexedDB'; // Corrected path // Repositories -import { ConversationRepository } from '../systems/context/repositories/ConversationRepository'; // Corrected path -import { ObservationRepository } from '../systems/context/repositories/ObservationRepository'; // Corrected path - Moved from observation system -import { StateRepository } from '../systems/context/repositories/StateRepository'; // Corrected path +import { ConversationRepository } from '@/systems/context/repositories/ConversationRepository'; // Corrected path +import { ObservationRepository } from '@/systems/context/repositories/ObservationRepository'; // Corrected path - Moved from observation system +import { StateRepository } from '@/systems/context/repositories/StateRepository'; // Corrected path +import { TaskStatusRepository } from '@/systems/context/repositories/TaskStatusRepository'; // A2A task repository // Managers -import { ConversationManager as ConversationManagerImpl } from '../systems/context/managers/ConversationManager'; // Corrected path -import { StateManager as StateManagerImpl } from '../systems/context/managers/StateManager'; // Corrected path -import { ObservationManager as ObservationManagerImpl } from '../systems/observation/observation-manager'; // Correct path +import { ConversationManager as ConversationManagerImpl } from '@/systems/context/managers/ConversationManager'; // Corrected path +import { StateManager as StateManagerImpl } from '@/systems/context/managers/StateManager'; // Corrected path +import { ObservationManager as ObservationManagerImpl } from '@/systems/observation/observation-manager'; // Correct path // Tool System -import { ToolRegistry as ToolRegistryImpl } from '../systems/tool/ToolRegistry'; // Correct path -import { ToolSystem as ToolSystemImpl } from '../systems/tool/ToolSystem'; // Correct path +import { ToolRegistry as ToolRegistryImpl } from '@/systems/tool/ToolRegistry'; // Correct path +import { ToolSystem as ToolSystemImpl } from '@/systems/tool/ToolSystem'; // Correct path // Reasoning System -import { PromptManager as PromptManagerImpl } from '../systems/reasoning/PromptManager'; // Correct path -import { ReasoningEngine as ReasoningEngineImpl } from '../systems/reasoning/ReasoningEngine'; // Correct path -import { OutputParser as OutputParserImpl } from '../systems/reasoning/OutputParser'; // Correct path +import { PromptManager as PromptManagerImpl } from '@/systems/reasoning/PromptManager'; // Correct path +import { SystemPromptResolver as SystemPromptResolverImpl } from '@/systems/reasoning/SystemPromptResolver'; +import { ReasoningEngine as ReasoningEngineImpl } from '@/systems/reasoning/ReasoningEngine'; // Correct path +import { OutputParser as OutputParserImpl } from '@/systems/reasoning/OutputParser'; // Correct path // Provider Adapters are now managed by ProviderManagerImpl // UI System -import { UISystem as UISystemImpl } from '../systems/ui/ui-system'; // Correct path +import { UISystem as UISystemImpl } from '@/systems/ui/ui-system'; // Correct path +// Auth and MCP Systems +import { AuthManager } from '@/systems/auth/AuthManager'; // Import AuthManager +import { McpManager } from '@/systems/mcp/McpManager'; // Import McpManager +// eslint-disable-next-line @typescript-eslint/no-unused-vars +import type { McpManagerConfig } from '@/systems/mcp/types'; // type-only import for McpManagerConfig +import { AgentDiscoveryService } from '@/systems/a2a/AgentDiscoveryService'; +import { TaskDelegationService } from '@/systems/a2a/TaskDelegationService'; // Removed direct imports of concrete socket classes - they will be accessed via UISystem instance // Removed unused type imports: Observation, ConversationMessage, ObservationType, MessageRole -import { Logger } from '../utils/logger'; // Import Logger +import { Logger } from '@/utils/logger'; // Import Logger // eslint-disable-next-line @typescript-eslint/no-unused-vars -import type { LogLevel } from '../utils/logger'; // type-only import +import type { LogLevel } from '@/utils/logger'; // type-only import /** @@ -121,6 +129,7 @@ export class AgentFactory { private conversationRepository: IConversationRepository | null = null; private observationRepository: IObservationRepository | null = null; private stateRepository: IStateRepository | null = null; + private a2aTaskRepository: IA2ATaskRepository | null = null; private conversationManager: ConversationManager | null = null; private stateManager: StateManager | null = null; private observationManager: ObservationManager | null = null; @@ -130,7 +139,12 @@ export class AgentFactory { private reasoningEngine: ReasoningEngine | null = null; private promptManager: PromptManager | null = null; private outputParser: OutputParser | null = null; + private systemPromptResolver: any | null = null; private toolSystem: ToolSystem | null = null; + private authManager: AuthManager | null = null; + private mcpManager: McpManager | null = null; + private agentDiscoveryService: AgentDiscoveryService | null = null; + private taskDelegationService: TaskDelegationService | null = null; /** @@ -160,7 +174,7 @@ export class AgentFactory { case 'indexedDB': this.storageAdapter = new IndexedDBStorageAdapter({ dbName: storageConfig.dbName || 'ARTDB', - objectStores: storageConfig.objectStores || ['conversations', 'observations', 'state'] + objectStores: storageConfig.objectStores || ['conversations', 'observations', 'state', 'a2a_tasks'] }); break; case 'memory': @@ -178,10 +192,11 @@ export class AgentFactory { this.conversationRepository = new ConversationRepository(this.storageAdapter!); this.observationRepository = new ObservationRepository(this.storageAdapter!); this.stateRepository = new StateRepository(this.storageAdapter!); + this.a2aTaskRepository = new TaskStatusRepository(this.storageAdapter!); // --- Initialize UI System --- // UISystem constructor expects repositories, not sockets - this.uiSystem = new UISystemImpl(this.observationRepository!, this.conversationRepository!); // Pass repositories + this.uiSystem = new UISystemImpl(this.observationRepository!, this.conversationRepository!, this.a2aTaskRepository || undefined); // Pass repositories including A2A task repository // --- Initialize Managers --- // Pass the actual socket instances obtained from the initialized uiSystem @@ -213,11 +228,54 @@ export class AgentFactory { // --- Initialize Reasoning Components --- this.reasoningEngine = new ReasoningEngineImpl(this.providerManager!); // Pass ProviderManager this.promptManager = new PromptManagerImpl(); // Basic implementation for now + // Initialize SystemPromptResolver with registry from config if provided + const registry = (this.config as any).systemPrompts as import('../types').SystemPromptsRegistry | undefined; + this.systemPromptResolver = new SystemPromptResolverImpl(this.promptManager as any, registry); this.outputParser = new OutputParserImpl(); // Basic implementation for now // --- Initialize Tool System --- // Inject ToolRegistry, StateManager, and ObservationManager into ToolSystem this.toolSystem = new ToolSystemImpl(this.toolRegistry!, this.stateManager!, this.observationManager!); // Added observationManager + + // --- Initialize Auth Manager --- + if (this.config.authConfig?.enabled) { + this.authManager = new AuthManager(); + // Register any pre-configured strategies + if (this.config.authConfig.strategies) { + for (const { id, strategy } of this.config.authConfig.strategies) { + this.authManager.registerStrategy(id, strategy); + } + } + Logger.info("AuthManager initialized."); + } + + // --- Initialize A2A Services --- + if (this.config.a2aConfig) { + this.agentDiscoveryService = new AgentDiscoveryService({ + discoveryEndpoint: this.config.a2aConfig.discoveryEndpoint, + }); + this.taskDelegationService = new TaskDelegationService( + this.a2aTaskRepository!, + { callbackUrl: this.config.a2aConfig.callbackUrl } + ); + Logger.info("A2A Services (Discovery, Delegation) initialized."); + } + + // --- Initialize MCP Manager --- + if (this.config.mcpConfig) { + if (!this.toolRegistry || !this.stateManager) { + throw new Error("MCP Manager requires ToolRegistry and StateManager to be initialized first."); + } + // McpManager now reads its own config from the file system and discovers from Zyntopia. + this.mcpManager = new McpManager( + this.toolRegistry, + this.stateManager, + this.authManager || undefined + ); + // Initialize with both local config and Zyntopia discovery + await this.mcpManager.initialize(this.config.mcpConfig); + Logger.info("McpManager Hub initialized with local config and Zyntopia discovery."); + } } /** @@ -231,7 +289,8 @@ export class AgentFactory { // Check for all required components after initialization if (!this.stateManager || !this.conversationManager || !this.toolRegistry || !this.promptManager || !this.reasoningEngine || !this.outputParser || - !this.observationManager || !this.toolSystem || !this.providerManager) { // Check providerManager + !this.observationManager || !this.toolSystem || !this.providerManager || + !this.a2aTaskRepository) { // Check A2A task repository throw new Error("AgentFactory not fully initialized. Call initialize() before creating an agent."); } @@ -247,7 +306,13 @@ export class AgentFactory { observationManager: this.observationManager, toolSystem: this.toolSystem, uiSystem: this.uiSystem!, // Include the UI System (non-null assertion) - instanceDefaultCustomSystemPrompt: this.config.defaultSystemPrompt, // Pass instance-level default system prompt from ArtInstanceConfig + systemPromptResolver: this.systemPromptResolver, + a2aTaskRepository: this.a2aTaskRepository, // Include A2A task repository + authManager: this.authManager, // Include Auth Manager (may be null if not configured) + mcpManager: this.mcpManager, // Include MCP Manager (may be null if not configured) + agentDiscoveryService: this.agentDiscoveryService, // Include A2A Discovery Service + taskDelegationService: this.taskDelegationService, // Include A2A Delegation Service + persona: this.config.persona, // Pass the persona from the main config // Note: providerAdapter is used by reasoningEngine, not directly by agent core usually }; @@ -270,11 +335,15 @@ export class AgentFactory { getConversationManager(): ConversationManager | null { return this.conversationManager; } /** Gets the initialized Observation Manager instance. */ getObservationManager(): ObservationManager | null { return this.observationManager; } + /** Gets the initialized Auth Manager instance. */ + getAuthManager(): AuthManager | null { return this.authManager; } + /** Gets the initialized MCP Manager instance. */ + getMcpManager(): McpManager | null { return this.mcpManager; } // Add getters for other components like reasoningEngine, toolSystem if needed } // --- Convenience Factory Function --- -import { ArtInstance } from './interfaces'; // Import the new interface +import { ArtInstance } from '@/core/interfaces'; // Import the new interface /** * High-level factory function to create and initialize a complete ART framework instance. @@ -302,6 +371,7 @@ export async function createArtInstance(config: ArtInstanceConfig): Promise { - let pesAgent: PESAgent; - - beforeEach(() => { - vi.clearAllMocks(); - // Setup default happy path mocks - vi.mocked(generateUUID).mockReturnValue(mockFinalMessageId); // For final message ID - vi.spyOn(Date, 'now').mockReturnValue(mockFinalTimestamp); - - vi.mocked(mockStateManager.loadThreadContext).mockResolvedValue(mockThreadContext); - vi.mocked(mockConversationManager.getMessages).mockResolvedValue(mockHistory); - vi.mocked(mockToolRegistry.getAvailableTools).mockResolvedValue(mockAvailableTools); - - // Mock assemblePrompt - vi.mocked(mockPromptManager.assemblePrompt) - .mockResolvedValueOnce(mockPlanningArtPrompt) // First call (planning) - .mockResolvedValueOnce(mockSynthesisArtPrompt); // Second call (synthesis) - - // Mock reasoningEngine.call to return async iterables (streams) - const planningStream = async function*(): AsyncIterable { - yield { type: 'TOKEN', data: mockPlanningLLMOutput, tokenType: 'AGENT_THOUGHT_LLM_RESPONSE', threadId: mockThreadId, traceId: mockTraceId }; - yield { type: 'END', data: null, threadId: mockThreadId, traceId: mockTraceId }; - }; - const synthesisStream = async function*(): AsyncIterable { - yield { type: 'TOKEN', data: mockSynthesisLLMOutput, tokenType: 'FINAL_SYNTHESIS_LLM_RESPONSE', threadId: mockThreadId, traceId: mockTraceId }; - yield { type: 'END', data: null, threadId: mockThreadId, traceId: mockTraceId }; - }; - vi.mocked(mockReasoningEngine.call) - .mockResolvedValueOnce(planningStream()) // Planning call returns stream - .mockResolvedValueOnce(synthesisStream()); // Synthesis call returns stream - - vi.mocked(mockOutputParser.parsePlanningOutput).mockResolvedValue(mockParsedPlanningOutput); - // No mock needed for parseSynthesisOutput as agent uses raw stream output now - vi.mocked(mockToolSystem.executeTools).mockResolvedValue(mockToolResults); - vi.mocked(mockConversationManager.addMessages).mockResolvedValue(undefined); - vi.mocked(mockStateManager.saveStateIfModified).mockResolvedValue(undefined); - vi.mocked(mockObservationManager.record).mockResolvedValue(undefined); // Assume recording succeeds - - pesAgent = new PESAgent(mockDependencies); - }); - - it('should execute the full PES flow successfully', async () => { - const result = await pesAgent.process(mockAgentProps); - - // Verify Stages were called (via dependency mocks) - expect(mockStateManager.loadThreadContext).toHaveBeenCalledWith(mockThreadId, mockUserId); - expect(mockConversationManager.getMessages).toHaveBeenCalledWith(mockThreadId, { limit: mockThreadConfig.historyLimit }); - expect(mockToolRegistry.getAvailableTools).toHaveBeenCalledWith({ enabledForThreadId: mockThreadId }); - - // Check assemblePrompt calls - expect(mockPromptManager.assemblePrompt).toHaveBeenCalledTimes(2); - // Check Planning Context - expect(mockPromptManager.assemblePrompt).toHaveBeenNthCalledWith(1, - expect.any(String), // Check blueprint string exists - expect.objectContaining({ - query: mockQuery, - systemPrompt: mockThreadConfig.systemPrompt, - history: expect.arrayContaining([ - expect.objectContaining({ role: 'user', content: 'Hello' }), - expect.objectContaining({ role: 'assistant', content: 'Hi there!', last: true }) // Check formatting helper adds 'last' - ]), - availableTools: expect.arrayContaining([ - expect.objectContaining({ name: 'get_weather', inputSchemaJson: JSON.stringify(mockToolSchema.inputSchema) }) // Check pre-stringified schema - ]) - }) - ); - // Check Synthesis Context - expect(mockPromptManager.assemblePrompt).toHaveBeenNthCalledWith(2, - expect.any(String), // Check blueprint string exists - expect.objectContaining({ - query: mockQuery, - systemPrompt: mockThreadConfig.systemPrompt, - history: expect.any(Array), // Already checked format above - intent: mockParsedPlanningOutput.intent, - plan: mockParsedPlanningOutput.plan, - toolResults: expect.arrayContaining([ - expect.objectContaining({ callId: 'call1', status: 'success', outputJson: JSON.stringify(mockToolResult.output) }) // Check pre-stringified output - ]) - }) - ); - - // Check reasoning engine calls with ArtStandardPrompt - expect(mockReasoningEngine.call).toHaveBeenCalledTimes(2); - expect(mockReasoningEngine.call).toHaveBeenNthCalledWith(1, mockPlanningArtPrompt, expect.objectContaining({ threadId: mockThreadId, traceId: mockTraceId, callContext: 'AGENT_THOUGHT' })); - expect(mockOutputParser.parsePlanningOutput).toHaveBeenCalledWith(mockPlanningLLMOutput); // Still parse planning output - expect(mockToolSystem.executeTools).toHaveBeenCalledWith(mockParsedPlanningOutput.toolCalls, mockThreadId, mockTraceId); - expect(mockReasoningEngine.call).toHaveBeenNthCalledWith(2, mockSynthesisArtPrompt, expect.objectContaining({ threadId: mockThreadId, traceId: mockTraceId, callContext: 'FINAL_SYNTHESIS' })); - // expect(mockOutputParser.parseSynthesisOutput).not.toHaveBeenCalled(); // Synthesis output is now raw stream content - expect(mockConversationManager.addMessages).toHaveBeenCalledWith(mockThreadId, [expect.objectContaining({ role: MessageRole.AI, content: mockSynthesisLLMOutput })]); // Use raw synthesis output - expect(mockStateManager.saveStateIfModified).toHaveBeenCalledWith(mockThreadId); - - // Verify Observations (basic checks) - Update thought observations - expect(mockObservationManager.record).toHaveBeenCalledWith(expect.objectContaining({ type: ObservationType.INTENT })); - expect(mockObservationManager.record).toHaveBeenCalledWith(expect.objectContaining({ type: ObservationType.PLAN })); - expect(mockObservationManager.record).toHaveBeenCalledWith(expect.objectContaining({ type: ObservationType.TOOL_CALL })); - // Note: TOOL_EXECUTION observations are expected to be recorded *within* mockToolSystem.executeTools - expect(mockObservationManager.record).toHaveBeenCalledWith(expect.objectContaining({ type: ObservationType.SYNTHESIS })); - expect(mockObservationManager.record).toHaveBeenCalledWith(expect.objectContaining({ type: ObservationType.FINAL_RESPONSE })); - // Check stream observations - expect(mockObservationManager.record).toHaveBeenCalledWith(expect.objectContaining({ type: ObservationType.LLM_STREAM_START, content: { phase: 'planning' } })); - expect(mockObservationManager.record).toHaveBeenCalledWith(expect.objectContaining({ type: ObservationType.LLM_STREAM_END, content: { phase: 'planning' } })); - expect(mockObservationManager.record).toHaveBeenCalledWith(expect.objectContaining({ type: ObservationType.LLM_STREAM_START, content: { phase: 'synthesis' } })); - expect(mockObservationManager.record).toHaveBeenCalledWith(expect.objectContaining({ type: ObservationType.LLM_STREAM_END, content: { phase: 'synthesis' } })); - // Check UI System calls - expect(mockUISystem.getLLMStreamSocket().notify).toHaveBeenCalledTimes(4); // TOKEN+END for planning, TOKEN+END for synthesis - - - // Verify Final Response - expect(result.response.role).toBe(MessageRole.AI); - expect(result.response.content).toBe(mockSynthesisLLMOutput); // Use raw synthesis output - expect(result.response.messageId).toBe(mockFinalMessageId); - expect(result.response.threadId).toBe(mockThreadId); - expect(result.metadata.status).toBe('success'); - expect(result.metadata.threadId).toBe(mockThreadId); - expect(result.metadata.traceId).toBe(mockTraceId); - expect(result.metadata.llmCalls).toBe(2); - expect(result.metadata.toolCalls).toBe(1); - expect(result.metadata.error).toBeUndefined(); - }); - - it('should handle planning failure (assemblePrompt error)', async () => { - const assembleError = new ARTError('Blueprint invalid', ErrorCode.PROMPT_ASSEMBLY_FAILED); - vi.mocked(mockPromptManager.assemblePrompt).mockRejectedValueOnce(assembleError); // Fail first assemble call - - await expect(pesAgent.process(mockAgentProps)).rejects.toThrow(assembleError); - - // Verify observations - expect(mockObservationManager.record).toHaveBeenCalledWith(expect.objectContaining({ type: ObservationType.ERROR, content: expect.objectContaining({ phase: 'planning', error: assembleError.message }) })); - expect(mockReasoningEngine.call).not.toHaveBeenCalled(); // Engine not called if prompt fails - expect(mockStateManager.saveStateIfModified).toHaveBeenCalledWith(mockThreadId); // Should still attempt save - }); - - it('should handle planning failure (reasoning engine error)', async () => { - const planningError = new Error('LLM Planning Failed'); - // Mock assemblePrompt to succeed, but reasoningEngine.call to fail (returning error stream) - vi.mocked(mockPromptManager.assemblePrompt).mockResolvedValueOnce(mockPlanningArtPrompt); - const errorStream = async function*(): AsyncIterable { - yield { type: 'ERROR', data: planningError, threadId: mockThreadId, traceId: mockTraceId }; - yield { type: 'END', data: null, threadId: mockThreadId, traceId: mockTraceId }; - }; - vi.mocked(mockReasoningEngine.call).mockResolvedValueOnce(errorStream()); // Fail first call - - await expect(pesAgent.process(mockAgentProps)).rejects.toThrow(ARTError); // Expect ARTError wrapper - - // Verify observations - expect(mockObservationManager.record).toHaveBeenCalledWith(expect.objectContaining({ type: ObservationType.ERROR, content: expect.objectContaining({ phase: 'planning', error: planningError.message }) })); - - // Verify finalization attempts - expect(mockStateManager.saveStateIfModified).toHaveBeenCalledWith(mockThreadId); // Should still attempt save - - // Verify later stages not called - expect(mockOutputParser.parsePlanningOutput).not.toHaveBeenCalled(); - expect(mockToolSystem.executeTools).not.toHaveBeenCalled(); - expect(mockPromptManager.assemblePrompt).toHaveBeenCalledTimes(1); // Only planning assemble called - expect(mockConversationManager.addMessages).not.toHaveBeenCalled(); // No final message to add - }); - - it('should handle tool execution failure (partial)', async () => { - const toolErrorResult: ToolResult = { callId: 'call1', toolName: 'get_weather', status: 'error', error: 'API unavailable' }; - vi.mocked(mockToolSystem.executeTools).mockResolvedValue([toolErrorResult]); // Tool system returns an error result - - const result = await pesAgent.process(mockAgentProps); - - // Verify observations (TOOL_EXECUTION error is handled by ToolSystem, check for synthesis error if it occurs) - expect(mockObservationManager.record).not.toHaveBeenCalledWith(expect.objectContaining({ type: ObservationType.ERROR, content: expect.objectContaining({ phase: 'tool_execution' }) })); // PESAgent doesn't record this directly - - // Verify synthesis still happens - expect(mockPromptManager.assemblePrompt).toHaveBeenCalledTimes(2); // Planning + Synthesis prompts assembled - expect(mockReasoningEngine.call).toHaveBeenCalledTimes(2); // Planning + Synthesis - // expect(mockOutputParser.parseSynthesisOutput).not.toHaveBeenCalled(); // No synthesis parsing - - // Verify final response reflects partial failure - expect(result.metadata.status).toBe('partial'); - expect(result.metadata.error).toContain('Tool execution errors occurred.'); - expect(result.response.content).toBe(mockSynthesisLLMOutput); // Synthesis should still complete - - // Verify finalization - expect(mockConversationManager.addMessages).toHaveBeenCalled(); - expect(mockStateManager.saveStateIfModified).toHaveBeenCalled(); - }); - - it('should handle synthesis failure (reasoning engine error)', async () => { - const synthesisError = new Error('LLM Synthesis Failed'); - // Mock planning stream to succeed - const planningStream = async function*(): AsyncIterable { - yield { type: 'TOKEN', data: mockPlanningLLMOutput, tokenType: 'AGENT_THOUGHT_LLM_RESPONSE', threadId: mockThreadId, traceId: mockTraceId }; - yield { type: 'END', data: null, threadId: mockThreadId, traceId: mockTraceId }; - }; - // Mock synthesis stream to yield error - const errorStream = async function*(): AsyncIterable { - yield { type: 'ERROR', data: synthesisError, threadId: mockThreadId, traceId: mockTraceId }; - yield { type: 'END', data: null, threadId: mockThreadId, traceId: mockTraceId }; - }; - vi.mocked(mockReasoningEngine.call) - .mockResolvedValueOnce(planningStream()) // Planning OK - .mockResolvedValueOnce(errorStream()); // Synthesis fails - - // Current implementation returns partial if tools ran, error otherwise. Here tools ran. - const result = await pesAgent.process(mockAgentProps); - - - // Verify observations - expect(mockObservationManager.record).toHaveBeenCalledWith(expect.objectContaining({ type: ObservationType.ERROR, content: expect.objectContaining({ phase: 'synthesis', error: synthesisError.message }) })); - - // Verify final response reflects synthesis failure - expect(result.metadata.status).toBe('partial'); // Partial because tools succeeded - expect(result.metadata.error).toContain('Synthesis phase failed'); - expect(result.response.content).toContain('Synthesis phase failed'); // Error message becomes content - - // Verify finalization attempts - expect(mockConversationManager.addMessages).toHaveBeenCalled(); // Adds the error message - expect(mockStateManager.saveStateIfModified).toHaveBeenCalled(); - }); - - it('should handle case with no tool calls', async () => { - const noToolPlanningOutput = { intent: 'Greeting', plan: 'Respond politely', toolCalls: [] }; - vi.mocked(mockOutputParser.parsePlanningOutput).mockResolvedValue(noToolPlanningOutput); - vi.mocked(mockToolSystem.executeTools).mockResolvedValue([]); // Should not be called, but setting expectation - - const result = await pesAgent.process(mockAgentProps); - - expect(mockToolSystem.executeTools).not.toHaveBeenCalled(); // Crucial check - // Check synthesis assemblePrompt call context - expect(mockPromptManager.assemblePrompt).toHaveBeenNthCalledWith(2, - expect.any(String), - expect.objectContaining({ - intent: noToolPlanningOutput.intent, - plan: noToolPlanningOutput.plan, - toolResults: [] // Empty tool results - }) - ); - expect(mockReasoningEngine.call).toHaveBeenCalledTimes(2); // Planning + Synthesis - expect(result.metadata.status).toBe('success'); - expect(result.metadata.toolCalls).toBe(0); - expect(result.response.content).toBe(mockSynthesisLLMOutput); // Corrected variable name - }); - -}); \ No newline at end of file diff --git a/src/core/agents/pes-agent.ts b/src/core/agents/pes-agent.ts old mode 100644 new mode 100755 index fc1c41d..0a6e9cc --- a/src/core/agents/pes-agent.ts +++ b/src/core/agents/pes-agent.ts @@ -9,9 +9,10 @@ import { OutputParser, ObservationManager, ToolSystem, - UISystem // Added UISystem import + UISystem, // Added UISystem import + IA2ATaskRepository // Added A2A task repository interface // Assuming repository interfaces might be needed indirectly or for type safety, though not directly used -} from '../interfaces'; +} from '@/core/interfaces'; import { AgentProps, AgentFinalResponse, @@ -26,21 +27,29 @@ import { LLMMetadata, ArtStandardPrompt, // Import new types ArtStandardMessageRole, + A2ATask, // Added A2A task types + A2ATaskStatus, + A2ATaskPriority, + A2AAgentInfo, // PromptContext, // Removed unused import after refactoring prompt construction // ThreadConfig, // Removed unused import (config accessed via ThreadContext) // ToolSchema, // Removed unused import // ThreadContext, // Removed unused import -} from '../../types'; -import { RuntimeProviderConfig } from '../../types/providers'; // Import RuntimeProviderConfig -import { generateUUID } from '../../utils/uuid'; -import { ARTError, ErrorCode } from '../../errors'; -import { Logger } from '../../utils/logger'; // Added Logger import +} from '@/types'; +import { AgentPersona } from '@/types'; +import { RuntimeProviderConfig } from '@/types/providers'; // Import RuntimeProviderConfig +import { generateUUID } from '@/utils/uuid'; +import { ARTError, ErrorCode } from '@/errors'; +import { Logger } from '@/utils/logger'; // Added Logger import /** * Defines the dependencies required by the PESAgent constructor. * These are typically provided by the AgentFactory during instantiation. */ -interface PESAgentDependencies { +import { AgentDiscoveryService } from '@/systems/a2a/AgentDiscoveryService'; +import { TaskDelegationService } from '@/systems/a2a/TaskDelegationService'; + +export interface PESAgentDependencies { /** Manages thread configuration and state. */ stateManager: StateManager; /** @@ -48,7 +57,7 @@ interface PESAgentDependencies { * This serves as a custom prompt part if no thread-specific or call-specific * system prompt is provided. It's appended to the agent's base system prompt. */ - instanceDefaultCustomSystemPrompt?: string; + // instanceDefaultCustomSystemPrompt?: string; // This will be replaced by the persona /** Manages conversation history. */ conversationManager: ConversationManager; /** Registry for available tools. */ @@ -65,12 +74,25 @@ interface PESAgentDependencies { toolSystem: ToolSystem; /** Provides access to UI communication sockets. */ uiSystem: UISystem; // Added UISystem dependency + /** Repository for A2A tasks. */ + a2aTaskRepository: IA2ATaskRepository; + /** Service for discovering A2A agents. */ + agentDiscoveryService?: AgentDiscoveryService | null; + /** Service for delegating A2A tasks. */ + taskDelegationService?: TaskDelegationService | null; + /** Resolver for standardized system prompt composition. */ + systemPromptResolver: import('@/core/interfaces').SystemPromptResolver; + /** Optional: Defines the default identity and high-level guidance for the agent. */ + persona?: AgentPersona; } -// Default system prompt remains -const DEFAULT_PES_SYSTEM_PROMPT = `You are a helpful AI assistant. You need to understand a user's query, potentially use tools to gather information, and then synthesize a final response.`; - -// Removed DEFAULT_PLANNING_BLUEPRINT and DEFAULT_SYNTHESIS_BLUEPRINT +const DEFAULT_PERSONA: AgentPersona = { + name: 'Zoi', + prompts: { + planning: 'You are a helpful AI assistant. Your primary goal is to understand a user\'s query, determine the intent, and create a clear plan to provide an accurate and helpful response. You can use tools to gather information if necessary.', + synthesis: 'You are a helpful AI assistant named Art. Your primary goal is to synthesize the information gathered from tools and planning into a final, user-friendly response. Be clear, concise, and helpful.' + } +}; /** * Implements the Plan-Execute-Synthesize (PES) agent orchestration logic. @@ -82,7 +104,6 @@ const DEFAULT_PES_SYSTEM_PROMPT = `You are a helpful AI assistant. You need to u * It constructs standardized prompts (`ArtStandardPrompt`) directly as JavaScript objects * for the `ReasoningEngine`. It processes the `StreamEvent` output from the reasoning engine for both planning and synthesis. * - * @implements {IAgentCore} * // @see {PromptManager} // Removed * @see {ReasoningEngine} * @see {ArtStandardPrompt} @@ -90,54 +111,40 @@ const DEFAULT_PES_SYSTEM_PROMPT = `You are a helpful AI assistant. You need to u */ export class PESAgent implements IAgentCore { private readonly deps: PESAgentDependencies; - /** The base system prompt inherent to this agent. */ - private readonly defaultSystemPrompt: string = DEFAULT_PES_SYSTEM_PROMPT; // This is the AGENT BASE - /** - * Stores the instance-level default custom system prompt, passed during construction. - * Used in the system prompt hierarchy if no thread or call-level prompt is specified. - */ - private readonly instanceDefaultCustomSystemPrompt?: string; - // Removed blueprint properties + private readonly persona: AgentPersona; /** * Creates an instance of the PESAgent. - * @param dependencies - An object containing instances of all required subsystems (managers, registries, etc.). + * @param {module:core/agents/pes-agent.PESAgentDependencies} dependencies - An object containing instances of all required subsystems (managers, registries, etc.). */ constructor(dependencies: PESAgentDependencies) { this.deps = dependencies; - this.instanceDefaultCustomSystemPrompt = dependencies.instanceDefaultCustomSystemPrompt; + // Deep merge the default persona with the provided one + this.persona = { + ...DEFAULT_PERSONA, + ...dependencies.persona, + prompts: { + ...DEFAULT_PERSONA.prompts, + ...dependencies.persona?.prompts, + }, + }; } /** * Executes the full Plan-Execute-Synthesize cycle for a given user query. * * **Workflow:** - * 1. **Initiation & Config:** Loads thread configuration. Resolves the final system prompt based on a hierarchy: - * Call-level (`AgentProps.options.systemPrompt`) > Thread-level (`ThreadConfig.systemPrompt`) > - * Instance-level (`ArtInstanceConfig.defaultSystemPrompt` via constructor) > Agent's base prompt. - * The resolved custom part is appended to the agent's base prompt. - * 2. **Data Gathering:** Gathers history, available tools, the resolved system prompt, and query. - * 3. **Planning Prompt Construction:** Directly constructs the `ArtStandardPrompt` object/array for planning. - * 4. **Planning LLM Call:** Sends the planning prompt object to the `reasoningEngine` (requesting streaming). Consumes the `StreamEvent` stream, buffers the output text, and handles potential errors. - * 5. **Planning Output Parsing:** Parses the buffered planning output text to extract intent, plan, and tool calls using `outputParser.parsePlanningOutput`. - * 6. **Tool Execution:** Executes identified tool calls via the `toolSystem`. - * 7. **Data Gathering (Synthesis):** Gathers the original query, plan, tool results, history, etc. - * 8. **Synthesis Prompt Construction:** Directly constructs the `ArtStandardPrompt` object/array for synthesis. - * 9. **Synthesis LLM Call:** Sends the synthesis prompt object to the `reasoningEngine` (requesting streaming). Consumes the `StreamEvent` stream, buffers the final response text, and handles potential errors. - * 10. **Finalization:** Saves the final AI message, updates state if needed, records observations, and returns the result. - * - * **Error Handling:** - * - Errors during critical phases (planning/synthesis LLM call) will throw an `ARTError`. Prompt construction errors are less likely but possible if data is malformed. - * - Errors during tool execution or synthesis LLM call might result in a 'partial' success status, potentially using the error message as the final response content. + * 1. **Initiation & Config:** Loads thread configuration and resolves system prompt + * 2. **Data Gathering:** Gathers history, available tools + * 3. **Planning:** LLM call for planning and parsing + * 4. **A2A Discovery & Delegation:** Identifies and delegates A2A tasks to remote agents + * 5. **Tool Execution:** Executes identified local tool calls + * 6. **Synthesis:** LLM call for final response generation including A2A results + * 7. **Finalization:** Saves messages and cleanup * * @param {AgentProps} props - The input properties containing the user query, threadId, userId, traceId, etc. * @returns {Promise} A promise resolving to the final response, including the AI message and execution metadata. - * @throws {ARTError} If a critical error occurs that prevents the agent from completing the process (e.g., config loading, planning failure). - * @see {AgentProps} - * @see {AgentFinalResponse} - * // @see {PromptContext} // Removed - context is implicit in object construction - * @see {ArtStandardPrompt} - * @see {StreamEvent} + * @throws {ARTError} If a critical error occurs that prevents the agent from completing the process. */ async process(props: AgentProps): Promise { const startTime = Date.now(); @@ -147,436 +154,952 @@ export class PESAgent implements IAgentCore { let llmCalls = 0; let toolCallsCount = 0; let finalAiMessage: ConversationMessage | undefined; - let aggregatedLlmMetadata: LLMMetadata | undefined = undefined; // Initialize aggregated metadata + let aggregatedLlmMetadata: LLMMetadata | undefined = undefined; + let phase = 'initialization'; try { - // --- Stage 1: Initiation & Config --- - Logger.debug(`[${traceId}] Stage 1: Initiation & Config`); - const threadContext = await this.deps.stateManager.loadThreadContext(props.threadId, props.userId); - if (!threadContext) { - throw new ARTError(`Thread context not found for threadId: ${props.threadId}`, ErrorCode.THREAD_NOT_FOUND); - } - // Resolve system prompt based on the new hierarchy - const agentInternalBaseSystemPrompt = this.defaultSystemPrompt; - let customSystemPromptPart: string | undefined = undefined; - - // Check Call-level (AgentProps.options.systemPrompt) - if (props.options?.systemPrompt) { - customSystemPromptPart = props.options.systemPrompt; - Logger.debug(`[${traceId}] Using Call-level custom system prompt.`); - } - // Else, check Thread-level (ThreadConfig.systemPrompt from types/index.ts) - else { - const threadSystemPrompt = await this.deps.stateManager.getThreadConfigValue(props.threadId, 'systemPrompt'); - if (threadSystemPrompt) { - customSystemPromptPart = threadSystemPrompt; - Logger.debug(`[${traceId}] Using Thread-level custom system prompt.`); - } - // Else, check Instance-level (this.instanceDefaultCustomSystemPrompt) - else if (this.instanceDefaultCustomSystemPrompt) { - customSystemPromptPart = this.instanceDefaultCustomSystemPrompt; - Logger.debug(`[${traceId}] Using Instance-level custom system prompt.`); - } - } + // Stage 1: Load configuration and resolve system prompt + phase = 'configuration'; + const { threadContext, planningSystemPrompt, synthesisSystemPrompt, runtimeProviderConfig, finalPersona } = await this._loadConfiguration(props, traceId); - let finalSystemPrompt = agentInternalBaseSystemPrompt; - if (customSystemPromptPart) { - finalSystemPrompt = `${agentInternalBaseSystemPrompt}\n\n${customSystemPromptPart}`; - Logger.debug(`[${traceId}] Custom system prompt part applied: "${customSystemPromptPart.substring(0, 100)}..."`); - } else { - Logger.debug(`[${traceId}] No custom system prompt part found. Using agent internal base prompt only.`); + // Stage 2: Gather context data + phase = 'context_gathering'; + const history = await this._gatherHistory(props.threadId, threadContext); + const availableTools = await this._gatherTools(props.threadId); + + // Stage 3: Perform planning + phase = 'planning'; + const { planningOutput, planningMetadata, planningContext } = await this._performPlanning( + props, planningSystemPrompt, history, availableTools, runtimeProviderConfig, traceId + ); + llmCalls++; + if (planningMetadata) { + aggregatedLlmMetadata = { ...(aggregatedLlmMetadata ?? {}), ...planningMetadata }; } - const systemPrompt = finalSystemPrompt; // Use this variable name for minimal changes below - // Determine RuntimeProviderConfig (Checklist item 17) - // This config specifies the provider/model/adapterOptions for the LLM call - const runtimeProviderConfig: RuntimeProviderConfig | undefined = - props.options?.providerConfig || threadContext.config.providerConfig; + // Stage 4: Delegate A2A tasks based on the plan + phase = 'a2a_delegation'; + const delegatedA2ATasks = await this._delegateA2ATasks( + planningOutput, props.threadId, traceId + ); + + // Stage 4b: Wait for A2A task completion + phase = 'a2a_completion'; + const completedA2ATasks = await this._waitForA2ACompletion( + delegatedA2ATasks, props.threadId, traceId + ); - if (!runtimeProviderConfig) { - throw new ARTError(`RuntimeProviderConfig is missing in AgentProps.options or ThreadConfig for threadId: ${props.threadId}`, ErrorCode.INVALID_CONFIG); + // Stage 5: Execute local tools + phase = 'tool_execution'; + const toolResults = await this._executeLocalTools( + planningOutput.toolCalls, props.threadId, traceId + ); + toolCallsCount = toolResults.length; + if (toolResults.some(r => r.status === 'error')) { + status = 'partial'; + Logger.warn(`[${traceId}] Partial success in tool execution.`); + errorMessage = 'Tool execution errors occurred.'; } + // Stage 6: Perform synthesis + phase = 'synthesis'; + const { finalResponseContent, synthesisMetadata, uiMetadata } = await this._performSynthesis( + props, synthesisSystemPrompt, history, planningOutput, toolResults, completedA2ATasks, runtimeProviderConfig, traceId, finalPersona, planningContext + ); + llmCalls++; + if (synthesisMetadata) { + aggregatedLlmMetadata = { ...(aggregatedLlmMetadata ?? {}), ...synthesisMetadata }; + } + + // Stage 7: Finalization + phase = 'finalization'; + finalAiMessage = await this._finalize(props, finalResponseContent, traceId, uiMetadata); + + } catch (error: any) { + const artError = (error instanceof ARTError) + ? error + : new ARTError(`An unexpected error occurred during agent processing: ${error.message}`, ErrorCode.UNKNOWN_ERROR, error); - // --- Stage 2: Planning Context Assembly --- - Logger.debug(`[${traceId}] Stage 2: Planning Context Assembly`); - const historyOptions = { limit: threadContext.config.historyLimit }; - const rawHistory = await this.deps.conversationManager.getMessages(props.threadId, historyOptions); - const availableTools = await this.deps.toolRegistry.getAvailableTools({ enabledForThreadId: props.threadId }); + // Annotate error with the phase if it's not already set + if (!artError.details) artError.details = {}; + artError.details.phase = artError.details.phase || phase; - // Format history for direct inclusion - const formattedHistory = this.formatHistoryForPrompt(rawHistory); + Logger.error(`[${traceId}] PESAgent process error in phase '${artError.details.phase}':`, artError); + status = status === 'partial' ? 'partial' : 'error'; + errorMessage = artError.message; + if (status === 'error') finalAiMessage = undefined; - // --- Stage 3: Planning Prompt Construction --- - Logger.debug(`[${traceId}] Stage 3: Planning Prompt Construction`); - let planningPrompt: ArtStandardPrompt; + // Record top-level error observation, ensuring it's always an ARTError + await this.deps.observationManager.record({ + threadId: props.threadId, traceId, type: ObservationType.ERROR, + content: { + phase: artError.details.phase, + error: artError.message, + code: artError.code, + stack: artError.stack + }, + metadata: { timestamp: Date.now() } + }).catch(err => Logger.error(`[${traceId}] Failed to record top-level error observation:`, err)); + } finally { + // Ensure state is saved even if errors occurred try { - planningPrompt = [ - { role: 'system', content: systemPrompt }, - ...formattedHistory, // Spread the formatted history messages - { - role: 'user', - // Construct the user content string directly - content: `User Query: ${props.query}\n\nAvailable Tools:\n${ - availableTools.length > 0 - ? availableTools.map(tool => `- ${tool.name}: ${tool.description}\n Input Schema: ${JSON.stringify(tool.inputSchema)}`).join('\n') - : 'No tools available.' - }\n\nBased on the user query and conversation history, identify the user's intent and create a plan to fulfill it using the available tools if necessary.\nRespond in the following format:\nIntent: [Briefly describe the user's goal]\nPlan: [Provide a step-by-step plan. If tools are needed, list them clearly.]\nTool Calls: [Output *only* the JSON array of tool calls required by the assistant, matching the ArtStandardMessage tool_calls format: [{\\"id\\": \\"call_abc123\\", \\"type\\": \\"function\\", \\"function\\": {\\"name\\": \\"tool_name\\", \\"arguments\\": \\"{\\\\\\"arg1\\\\\\": \\\\\\"value1\\\\\\"}\\"}}] or [] if no tools are needed. Do not add any other text in this section.]` - } - ]; - // Optional: Validate the constructed prompt object if needed - // ArtStandardPromptSchema.parse(planningPrompt); - } catch (err: any) { - Logger.error(`[${traceId}] Failed to construct planning prompt object:`, err); - throw new ARTError(`Failed to construct planning prompt object: ${err.message}`, ErrorCode.PROMPT_ASSEMBLY_FAILED, err); + await this.deps.stateManager.saveStateIfModified(props.threadId); + } catch(saveError: any) { + Logger.error(`[${traceId}] Failed to save state during finalization:`, saveError); } + } + const endTime = Date.now(); + const metadata: ExecutionMetadata = { + threadId: props.threadId, + traceId: traceId, + userId: props.userId, + status: status, + totalDurationMs: endTime - startTime, + llmCalls: llmCalls, + toolCalls: toolCallsCount, + error: errorMessage, + llmMetadata: aggregatedLlmMetadata, + }; - // --- Stage 3b: Planning LLM Call --- - Logger.debug(`[${traceId}] Stage 3b: Planning LLM Call`); - const planningOptions: CallOptions = { + if (!finalAiMessage && status !== 'success') { + finalAiMessage = { + messageId: generateUUID(), threadId: props.threadId, - traceId: traceId, - userId: props.userId, - sessionId: props.sessionId, // Pass sessionId - stream: true, // Request streaming - callContext: 'AGENT_THOUGHT', // Set context for planning - requiredCapabilities: [ModelCapability.REASONING], - // Pass the determined runtimeProviderConfig - providerConfig: runtimeProviderConfig, - // Merge additional LLM parameters from ThreadConfig and AgentProps (AgentProps overrides ThreadConfig) - // ...(threadContext.config.reasoning?.parameters ?? {}), // Removed: Parameters are now in providerConfig.adapterOptions - ...(props.options?.llmParams ?? {}), // AgentProps.options.llmParams can still override adapterOptions at call time if needed + role: MessageRole.AI, + content: errorMessage ?? "Agent execution failed.", + timestamp: Date.now(), + metadata: { traceId, error: true } }; + } else if (!finalAiMessage) { + throw new ARTError("Agent finished with success status but no final message was generated.", ErrorCode.UNKNOWN_ERROR); + } + + return { + response: finalAiMessage, + metadata: metadata, + }; + } + + /** + * Loads thread configuration and resolves the system prompt hierarchy. + * @private + */ + private async _loadConfiguration(props: AgentProps, traceId: string) { + Logger.debug(`[${traceId}] Stage 1: Initiation & Config`); + + const threadContext = await this.deps.stateManager.loadThreadContext(props.threadId, props.userId); + if (!threadContext) { + throw new ARTError(`Thread context not found for threadId: ${props.threadId}`, ErrorCode.THREAD_NOT_FOUND); + } + + // Resolve persona hierarchy: call -> thread -> instance + const callPersona = props.options?.persona; + const threadPersona = await this.deps.stateManager.getThreadConfigValue>(props.threadId, 'persona'); + const instancePersona = this.persona; + + const finalPersona: AgentPersona = { + name: callPersona?.name || threadPersona?.name || instancePersona.name, + prompts: { + planning: callPersona?.prompts?.planning || threadPersona?.prompts?.planning || instancePersona.prompts.planning, + synthesis: callPersona?.prompts?.synthesis || threadPersona?.prompts?.synthesis || instancePersona.prompts.synthesis, + }, + }; + + // Resolve system prompts for each stage + const planningSystemPrompt = await this.deps.systemPromptResolver.resolve({ + base: finalPersona.prompts.planning || '', + thread: await this.deps.stateManager.getThreadConfigValue(props.threadId, 'systemPrompt'), + call: props.options?.systemPrompt + }, traceId); - let planningOutputText: string = ''; // Initialize buffer for planning output - let parsedPlanningOutput: { intent?: string; plan?: string; toolCalls?: ParsedToolCall[] } = {}; - let planningStreamError: Error | null = null; + const synthesisSystemPrompt = await this.deps.systemPromptResolver.resolve({ + base: finalPersona.prompts.synthesis || '', + thread: await this.deps.stateManager.getThreadConfigValue(props.threadId, 'systemPrompt'), + call: props.options?.systemPrompt + }, traceId); + // Determine RuntimeProviderConfig + const runtimeProviderConfig: RuntimeProviderConfig | undefined = + props.options?.providerConfig || threadContext.config.providerConfig; + + if (!runtimeProviderConfig) { + throw new ARTError(`RuntimeProviderConfig is missing in AgentProps.options or ThreadConfig for threadId: ${props.threadId}`, ErrorCode.INVALID_CONFIG); + } + + return { + threadContext, + planningSystemPrompt, + synthesisSystemPrompt, + runtimeProviderConfig, + finalPersona + }; + } + + /** + * Gathers conversation history for the current thread. + * @private + */ + private async _gatherHistory(threadId: string, threadContext: any) { + Logger.debug(`[${threadContext.threadId || threadId}] Stage 2: Gathering History`); + + const historyOptions = { limit: threadContext.config.historyLimit }; + const rawHistory = await this.deps.conversationManager.getMessages(threadId, historyOptions); + return this.formatHistoryForPrompt(rawHistory); + } + + /** + * Gathers available tools for the current thread. + * @private + */ + private async _gatherTools(threadId: string) { + Logger.debug(`[${threadId}] Stage 2: Gathering Tools`); + return await this.deps.toolRegistry.getAvailableTools({ enabledForThreadId: threadId }); + } + + /** + * Performs the planning phase including LLM call and output parsing. + * @private + * + * @remarks + * The planning prompt instructs the LLM to produce a concise `title` (<= 10 words) + * alongside `intent`, `plan`, and `toolCalls`. After parsing, a `TITLE` observation + * is emitted (if present) for UI components to subscribe via `ObservationSocket`. + */ + private async _performPlanning( + props: AgentProps, + systemPrompt: string, + formattedHistory: ArtStandardPrompt, + availableTools: any[], + runtimeProviderConfig: RuntimeProviderConfig, + traceId: string + ) { + Logger.debug(`[${traceId}] Stage 3: Pre-planning & A2A Discovery`); + + // --- A2A Pre-Discovery --- + let candidateAgents: A2AAgentInfo[] = []; + let a2aPromptSection = 'No candidate agents found for delegation.'; + if (this.deps.agentDiscoveryService) { try { - // Record PLAN observation before making the call - await this.deps.observationManager.record({ - threadId: props.threadId, traceId: traceId, type: ObservationType.PLAN, content: { message: "Preparing for planning LLM call." }, metadata: { timestamp: Date.now() } - }).catch(err => Logger.error(`[${traceId}] Failed to record PLAN observation:`, err)); + // Simple heuristic to find a task type from the query. + // This could be improved with a more sophisticated NLP model in the future. + const potentialTaskType = props.query.split(' ')[0].toLowerCase(); + candidateAgents = await this.deps.agentDiscoveryService.findTopAgentsForTask(potentialTaskType, 3, traceId); - llmCalls++; - // Pass the constructed prompt object directly - const planningStream = await this.deps.reasoningEngine.call(planningPrompt, planningOptions); + if (candidateAgents.length > 0) { + a2aPromptSection = `You can delegate tasks to other specialized agents. Here are the available candidates for this query:\n${ + candidateAgents.map(agent => + `- Agent ID: ${agent.agentId}\n Name: ${agent.agentName}\n Capabilities: ${(agent.capabilities ?? []).join(', ')}` + ).join('\n') + }\nTo delegate, use the "delegate_to_agent" tool.`; + } + } catch (err: any) { + Logger.warn(`[${traceId}] A2A pre-discovery failed, proceeding without candidate agents:`, err); + a2aPromptSection = 'Agent discovery failed. Delegation is not available.'; + } + } else { + a2aPromptSection = 'A2A delegation is not configured.'; + } - // Record stream start - await this.deps.observationManager.record({ - threadId: props.threadId, traceId, type: ObservationType.LLM_STREAM_START, content: { phase: 'planning' }, metadata: { timestamp: Date.now() } - }).catch(err => Logger.error(`[${traceId}] Failed to record LLM_STREAM_START observation:`, err)); - - // Consume the stream - for await (const event of planningStream) { - // Call the base notify method directly - this.deps.uiSystem.getLLMStreamSocket().notify(event, { targetThreadId: event.threadId, targetSessionId: event.sessionId }); - - switch (event.type) { - case 'TOKEN': - planningOutputText += event.data; // Append all tokens for planning output - break; - case 'METADATA': - await this.deps.observationManager.record({ - threadId: props.threadId, traceId, type: ObservationType.LLM_STREAM_METADATA, content: event.data, metadata: { phase: 'planning', timestamp: Date.now() } - }).catch(err => Logger.error(`[${traceId}] Failed to record LLM_STREAM_METADATA observation:`, err)); - // Aggregate planning metadata if needed (e.g., for overall cost) - aggregatedLlmMetadata = { ...(aggregatedLlmMetadata ?? {}), ...event.data }; - break; - case 'ERROR': - planningStreamError = event.data instanceof Error ? event.data : new Error(String(event.data)); - status = 'error'; - errorMessage = `Planning phase stream error: ${planningStreamError.message}`; - Logger.error(`[${traceId}] Planning Stream Error:`, planningStreamError); - await this.deps.observationManager.record({ - threadId: props.threadId, traceId, type: ObservationType.LLM_STREAM_ERROR, content: { phase: 'planning', error: planningStreamError.message, stack: planningStreamError.stack }, metadata: { timestamp: Date.now() } - }).catch(err => Logger.error(`[${traceId}] Failed to record LLM_STREAM_ERROR observation:`, err)); - break; - case 'END': - await this.deps.observationManager.record({ - threadId: props.threadId, traceId, type: ObservationType.LLM_STREAM_END, content: { phase: 'planning' }, metadata: { timestamp: Date.now() } - }).catch(err => Logger.error(`[${traceId}] Failed to record LLM_STREAM_END observation:`, err)); - break; - } - if (planningStreamError) break; + // --- Planning Prompt Construction --- + Logger.debug(`[${traceId}] Stage 3b: Planning Prompt Construction`); + let planningPrompt: ArtStandardPrompt; + try { + // Define a "virtual" tool for delegation that the LLM can call. + const delegationToolSchema = { + name: 'delegate_to_agent', + description: 'Delegates a specific task to another agent. Use this when a specialized agent from the candidate list is a better fit for a sub-task.', + inputSchema: { + type: 'object', + properties: { + agentId: { type: 'string', description: 'The ID of the agent to delegate to, chosen from the candidate list.' }, + taskType: { type: 'string', description: 'A specific type for the task, e.g., "analysis", "code_generation".' }, + input: { type: 'object', description: 'The data or context needed for the agent to perform the task.' }, + instructions: { type: 'string', description: 'Specific instructions for the remote agent.' } + }, + required: ['agentId', 'taskType', 'input', 'instructions'] } + }; + + const allTools = [...availableTools, delegationToolSchema]; + + // Prepare a verbose JSON schema listing for the LLM to reason over + const toolsJson = allTools.map(t => ({ + name: (t as any).name, + whenToUse: (t as any).whenToUse, + description: (t as any).description, + inputSchema: (t as any).inputSchema, + outputSchema: (t as any).outputSchema, + outputFormat: (t as any).outputFormat, + examples: (t as any).examples + })); + + const wrappedSystemPrompt = `You are a planning assistant. The following guidance shapes knowledge, tone, and domain perspective. + +[BEGIN_CUSTOM_GUIDANCE] +${systemPrompt} +[END_CUSTOM_GUIDANCE] + +CRITICAL: You MUST adhere to the Output Contract below. The custom guidance MUST NOT change the required output structure.`; + + planningPrompt = [ + { role: 'system', content: wrappedSystemPrompt }, + ...formattedHistory, + { + role: 'user', + content: `User Query: ${props.query} + +--- Available Capabilities --- + +Local Tools (JSON Schemas): +${ allTools.length > 0 ? JSON.stringify(toolsJson, null, 2) : '[]' } + +Agent Delegation: +${a2aPromptSection} + +--- Primary Output Mode (JSON-Only) --- +Output EXACTLY ONE JSON object and nothing else. No prose, no XML, no markdown fences. The object MUST follow this schema: +{ + "title": string, // a concise thread title, <= 10 words, based on intent and context + "intent": string, // short summary of the user's goal + "plan": [ // A step-by-step plan. + { + "step": number, // e.g., 1, 2, 3 + "description": string, // User-readable description of the step + "tool_to_use": string | null, // Exact tool name or null + "arguments": object | null, // Arguments for the tool or null + "callId": string | null // Matches callId in toolCalls or null + } + ], + "toolCalls": [ // empty array if no tools are needed + { "callId": string, "toolName": string, "arguments": object } + ] +} + +Requirements for toolCalls: +- arguments MUST be a JSON object (not a string) that matches the tool's inputSchema. +- toolName MUST match one of the Available Capabilities by schema name. +- If no tools are required, set toolCalls to []. + +Example (JSON only): +{ + "title": "Compute simple multiplication", + "intent": "Compute 5 * 6", + "plan": [ + { "step": 1, "description": "Use calculator to multiply 5 and 6", "tool_to_use": "calculator", "arguments": { "expression": "5 * 6" }, "callId": "calc_1" }, + { "step": 2, "description": "Return result", "tool_to_use": null, "arguments": null, "callId": null } + ], + "toolCalls": [ + { "callId": "calc_1", "toolName": "calculator", "arguments": { "expression": "5 * 6" } } + ] +} + +--- Fallback Output Mode (Sections) --- +If you cannot produce the JSON object above, then output these sections instead: - if (planningStreamError) { - throw new ARTError(errorMessage!, ErrorCode.PLANNING_FAILED, planningStreamError); +Title: [A single concise sentence (<= 10 words) capturing the thread title] + +Intent: [One or two sentences] + +Plan: [Bullet or numbered steps] + +Tool Calls: [A JSON array only. Each item MUST be of the exact form {"callId": "unique_id", "toolName": "tool_schema_name", "arguments": { /* JSON object matching the tool's inputSchema */ }}. If no tools are needed, return []]. + +Invalid Examples (do NOT do these): +- Wrapping with markdown code fences or any fences +- Wrapping with json(...): json([ ... ]) +- Placing inside XML tags such as or +- Setting arguments as a string: {"arguments": "{ 'expression': '5*6' }"} +- Using unknown toolName not present in Available Capabilities +` } + ]; + } catch (err: any) { + Logger.error(`[${traceId}] Failed to construct planning prompt object:`, err); + throw new ARTError(`Failed to construct planning prompt object: ${err.message}`, ErrorCode.PROMPT_ASSEMBLY_FAILED, err); + } - // Parse the accumulated output - parsedPlanningOutput = await this.deps.outputParser.parsePlanningOutput(planningOutputText); + // --- Planning LLM Call --- + Logger.debug(`[${traceId}] Stage 3c: Planning LLM Call`); + const planningOptions: CallOptions = { + threadId: props.threadId, traceId, userId: props.userId, sessionId: props.sessionId, + stream: true, callContext: 'AGENT_THOUGHT', + requiredCapabilities: [ModelCapability.REASONING], + providerConfig: runtimeProviderConfig, + ...(props.options?.llmParams ?? {}), + }; - // Record Intent and Plan observations using the final text - await this.deps.observationManager.record({ - threadId: props.threadId, traceId, type: ObservationType.INTENT, content: { intent: parsedPlanningOutput.intent }, metadata: { timestamp: Date.now() } - }); - await this.deps.observationManager.record({ - threadId: props.threadId, traceId, type: ObservationType.PLAN, content: { plan: parsedPlanningOutput.plan, rawOutput: planningOutputText }, metadata: { timestamp: Date.now() } + let planningOutputText: string = ''; + let parsedPlanningOutput: { title?: string; intent?: string; plan?: string; toolCalls?: ParsedToolCall[]; thoughts?: string } = {}; + let planningStreamError: Error | null = null; + let planningMetadata: LLMMetadata | undefined = undefined; + let planningContext: { + toolsList: { name: string; description?: string }[]; + a2aSummary: string; + plannedToolCalls: ParsedToolCall[]; + rawPlanningText?: string; + } = { toolsList: [], a2aSummary: '', plannedToolCalls: [] }; + + try { + await this.deps.observationManager.record({ + threadId: props.threadId, traceId, type: ObservationType.PLAN, + content: { message: "Preparing for planning LLM call." }, + metadata: { timestamp: Date.now() } + }); + + const planningStream = await this.deps.reasoningEngine.call(planningPrompt, planningOptions); + + await this.deps.observationManager.record({ + threadId: props.threadId, traceId, type: ObservationType.LLM_STREAM_START, + content: { phase: 'planning' }, metadata: { timestamp: Date.now() } + }); + + for await (const event of planningStream) { + this.deps.uiSystem.getLLMStreamSocket().notify(event, { + targetThreadId: event.threadId, targetSessionId: event.sessionId }); - if (parsedPlanningOutput.toolCalls && parsedPlanningOutput.toolCalls.length > 0) { - await this.deps.observationManager.record({ - threadId: props.threadId, traceId, type: ObservationType.TOOL_CALL, content: { toolCalls: parsedPlanningOutput.toolCalls }, metadata: { timestamp: Date.now() } - }); - } - } catch (err: any) { - // Catch errors from initial call or re-thrown stream errors - status = 'error'; - errorMessage = errorMessage ?? `Planning phase failed: ${err.message}`; // Use stream error message if available - Logger.error(`[${traceId}] Planning Error:`, err); - // Avoid duplicate error recording if it came from the stream - if (!planningStreamError) { - await this.deps.observationManager.record({ - threadId: props.threadId, traceId, type: ObservationType.ERROR, content: { phase: 'planning', error: err.message, stack: err.stack }, metadata: { timestamp: Date.now() } - }); + switch (event.type) { + case 'TOKEN': + planningOutputText += event.data; + // Emit THOUGHTS observation for thinking tokens + if (event.tokenType && String(event.tokenType).includes('THINKING')) { + await this.deps.observationManager.record({ + threadId: props.threadId, + traceId, + type: ObservationType.THOUGHTS, + content: { text: event.data }, + metadata: { phase: 'planning', tokenType: event.tokenType, timestamp: Date.now() } + }).catch(err => Logger.error(`[${traceId}] Failed to record THOUGHTS (planning) observation:`, err)); + } + break; + case 'METADATA': + planningMetadata = { ...(planningMetadata ?? {}), ...event.data }; + break; + case 'ERROR': + planningStreamError = event.data instanceof Error ? event.data : new Error(String(event.data)); + break; } - throw err instanceof ARTError ? err : new ARTError(errorMessage, ErrorCode.PLANNING_FAILED, err); // Rethrow + if (planningStreamError) break; } - // --- Stage 4: Tool Execution --- - let toolResults: ToolResult[] = []; - if (parsedPlanningOutput.toolCalls && parsedPlanningOutput.toolCalls.length > 0) { - Logger.debug(`[${traceId}] Stage 4: Tool Execution (${parsedPlanningOutput.toolCalls.length} calls)`); - try { - toolResults = await this.deps.toolSystem.executeTools(parsedPlanningOutput.toolCalls, props.threadId, traceId); - toolCallsCount = toolResults.length; - if (toolResults.some(r => r.status === 'error')) { - status = 'partial'; - Logger.warn(`[${traceId}] Partial success in tool execution.`); - errorMessage = errorMessage ? `${errorMessage}; Tool execution errors occurred.` : 'Tool execution errors occurred.'; - } - } catch (err: any) { - status = 'error'; - errorMessage = `Tool execution phase failed: ${err.message}`; - Logger.error(`[${traceId}] Tool Execution System Error:`, err); - await this.deps.observationManager.record({ - threadId: props.threadId, traceId, type: ObservationType.ERROR, content: { phase: 'tool_execution', error: err.message, stack: err.stack }, metadata: { timestamp: Date.now() } - }); - throw new ARTError(errorMessage, ErrorCode.TOOL_EXECUTION_FAILED, err); - } - } else { - Logger.debug(`[${traceId}] Stage 4: Tool Execution (No tool calls)`); + if (planningStreamError) { + throw new ARTError(`Planning phase stream error: ${planningStreamError.message}`, ErrorCode.PLANNING_FAILED, planningStreamError); } + parsedPlanningOutput = await this.deps.outputParser.parsePlanningOutput(planningOutputText); + // Build a compact planning context for downstream synthesis + planningContext = { + toolsList: availableTools.map((t: any) => ({ name: t.name, description: t.description })), + a2aSummary: a2aPromptSection, + plannedToolCalls: parsedPlanningOutput.toolCalls ?? [], + rawPlanningText: planningOutputText + }; - // --- Stage 5: Synthesis Call --- - Logger.debug(`[${traceId}] Stage 5: Synthesis Call`); - // Record SYNTHESIS observation before making the call await this.deps.observationManager.record({ - threadId: props.threadId, traceId: traceId, type: ObservationType.SYNTHESIS, content: { message: "Preparing for synthesis LLM call." }, metadata: { timestamp: Date.now() } - }).catch(err => Logger.error(`[${traceId}] Failed to record SYNTHESIS observation:`, err)); + threadId: props.threadId, traceId, type: ObservationType.INTENT, + content: { intent: parsedPlanningOutput.intent }, metadata: { timestamp: Date.now() } + }); + if (parsedPlanningOutput.title) { + await this.deps.observationManager.record({ + threadId: props.threadId, traceId, type: ObservationType.TITLE, + content: { title: parsedPlanningOutput.title }, metadata: { timestamp: Date.now() } + }); + } + await this.deps.observationManager.record({ + threadId: props.threadId, traceId, type: ObservationType.PLAN, + content: { plan: parsedPlanningOutput.plan, rawOutput: planningOutputText }, + metadata: { timestamp: Date.now() } + }); + if (parsedPlanningOutput.toolCalls && parsedPlanningOutput.toolCalls.length > 0) { + await this.deps.observationManager.record({ + threadId: props.threadId, traceId, type: ObservationType.TOOL_CALL, + content: { toolCalls: parsedPlanningOutput.toolCalls }, + metadata: { timestamp: Date.now() } + }); + } + + } catch (err: any) { + const errorMessage = `Planning phase failed: ${err.message}`; + Logger.error(`[${traceId}] Planning Error:`, err); + throw err instanceof ARTError ? err : new ARTError(errorMessage, ErrorCode.PLANNING_FAILED, err); + } + + return { planningOutput: parsedPlanningOutput, planningMetadata, planningContext }; + } + + /** + * Delegates A2A tasks identified in the planning phase. + * @private + */ + private async _delegateA2ATasks( + planningOutput: { toolCalls?: ParsedToolCall[] }, + threadId: string, + traceId: string + ): Promise { + Logger.debug(`[${traceId}] Stage 4: A2A Task Delegation`); - // --- Stage 5: Synthesis Prompt Construction --- - Logger.debug(`[${traceId}] Stage 5: Synthesis Prompt Construction`); - let synthesisPrompt: ArtStandardPrompt; + const delegationCalls = planningOutput.toolCalls?.filter( + call => call.toolName === 'delegate_to_agent' + ) ?? []; + + if (delegationCalls.length === 0) { + Logger.debug(`[${traceId}] No A2A delegation calls in the plan.`); + return []; + } + + if (!this.deps.taskDelegationService || !this.deps.agentDiscoveryService) { + Logger.warn(`[${traceId}] A2A services not available. Skipping delegation.`); + return []; + } + + const delegatedTasks: A2ATask[] = []; + for (const call of delegationCalls) { try { - synthesisPrompt = [ - { role: 'system', content: systemPrompt }, - ...formattedHistory, // Reuse formatted history - { - role: 'user', - // Construct the user content string directly - content: `User Query: ${props.query}\n\nOriginal Intent: ${parsedPlanningOutput.intent ?? ''}\nExecution Plan: ${parsedPlanningOutput.plan ?? ''}\n\nTool Execution Results:\n${ - toolResults.length > 0 - ? toolResults.map(result => `- Tool: ${result.toolName} (Call ID: ${result.callId})\n Status: ${result.status}\n ${result.status === 'success' ? `Output: ${JSON.stringify(result.output)}` : ''}\n ${result.status === 'error' ? `Error: ${result.error ?? 'Unknown error'}` : ''}`).join('\n') - : 'No tools were executed.' - }\n\nBased on the user query, the plan, and the results of any tool executions, synthesize a final response to the user.\nIf the tools failed or provided unexpected results, explain the issue and try to answer based on available information or ask for clarification.` + const args = call.arguments; + const { agentId, taskType, input, instructions } = args; + + // Find the full agent info. In a real scenario, we might cache this from the planning phase. + const allAgents = await this.deps.agentDiscoveryService.discoverAgents(traceId); + const targetAgent = allAgents.find(a => a.agentId === agentId); + + if (!targetAgent) { + throw new Error(`Agent with ID "${agentId}" not found during delegation.`); + } + + const now = Date.now(); + const a2aTask: A2ATask = { + taskId: call.callId, // Use the tool call ID as the task ID for traceability + threadId: threadId, + status: A2ATaskStatus.PENDING, + payload: { taskType, input, instructions, parameters: { threadId, traceId } }, + sourceAgent: { agentId: 'pes-agent', agentName: 'PES Agent', agentType: 'orchestrator' }, + targetAgent: targetAgent, // Assign the target agent + priority: A2ATaskPriority.MEDIUM, + metadata: { + createdAt: now, updatedAt: now, initiatedBy: threadId, correlationId: traceId, + retryCount: 0, maxRetries: 3, timeoutMs: 60000, tags: ['delegated', taskType] } - ]; - // Optional: Validate the constructed prompt object if needed - // ArtStandardPromptSchema.parse(synthesisPrompt); + }; + + // Persist the task before delegating + await this.deps.a2aTaskRepository.createTask(a2aTask); + + // Delegate the task + const delegatedTask = await this.deps.taskDelegationService.delegateTask(a2aTask, traceId); + if (delegatedTask) { + delegatedTasks.push(delegatedTask); + } } catch (err: any) { - Logger.error(`[${traceId}] Failed to construct synthesis prompt object:`, err); - throw new ARTError(`Failed to construct synthesis prompt object: ${err.message}`, ErrorCode.PROMPT_ASSEMBLY_FAILED, err); + Logger.error(`[${traceId}] Failed to process and delegate A2A task for call ${call.callId}:`, err); + await this.deps.observationManager.record({ + threadId, traceId, type: ObservationType.ERROR, + content: { phase: 'a2a_delegation', error: `Delegation for call ${call.callId} failed: ${err.message}` }, + metadata: { timestamp: Date.now() } + }); } + } - // --- Stage 5b: Synthesis LLM Call --- - Logger.debug(`[${traceId}] Stage 5b: Synthesis LLM Call`); - const synthesisOptions: CallOptions = { - threadId: props.threadId, - traceId: traceId, - userId: props.userId, - sessionId: props.sessionId, // Pass sessionId - stream: true, // Request streaming - callContext: 'FINAL_SYNTHESIS', // Set context for synthesis - requiredCapabilities: [ModelCapability.TEXT], - // Pass the determined runtimeProviderConfig - providerConfig: runtimeProviderConfig, - // Merge additional LLM parameters from ThreadConfig and AgentProps (AgentProps overrides ThreadConfig) - // ...(threadContext.config.reasoning?.parameters ?? {}), // Removed: Parameters are now in providerConfig.adapterOptions - ...(props.options?.llmParams ?? {}), // AgentProps.options.llmParams can still override adapterOptions at call time if needed - }; + Logger.info(`[${traceId}] Successfully initiated delegation for ${delegatedTasks.length}/${delegationCalls.length} A2A task(s).`); + return delegatedTasks; + } - let finalResponseContent: string = ''; // Initialize buffer for final response - let synthesisStreamError: Error | null = null; + /** + * Waits for A2A tasks to complete with configurable timeout. + * Polls task status periodically and updates local repository with results. + * @private + */ + private async _waitForA2ACompletion( + a2aTasks: A2ATask[], + threadId: string, + traceId: string, + maxWaitTimeMs: number = 30000, // 30 seconds default + pollIntervalMs: number = 2000 // 2 seconds default + ): Promise { + if (a2aTasks.length === 0) { + Logger.debug(`[${traceId}] No A2A tasks to wait for`); + return a2aTasks; + } - try { - llmCalls++; - // Pass the constructed prompt object directly - const synthesisStream = await this.deps.reasoningEngine.call(synthesisPrompt, synthesisOptions); + Logger.debug(`[${traceId}] Waiting for ${a2aTasks.length} A2A task(s) to complete (timeout: ${maxWaitTimeMs}ms)`); + + const startTime = Date.now(); + const updatedTasks: A2ATask[] = [...a2aTasks]; + + // Record observation for waiting start + await this.deps.observationManager.record({ + threadId: threadId, + traceId: traceId, + type: ObservationType.TOOL_CALL, // Using TOOL_CALL as closest equivalent + content: { + phase: 'a2a_waiting', + message: 'Started waiting for A2A task completion', + taskCount: a2aTasks.length, + maxWaitTimeMs: maxWaitTimeMs, + pollIntervalMs: pollIntervalMs + }, + metadata: { timestamp: Date.now() } + }).catch(err => Logger.error(`[${traceId}] Failed to record A2A waiting observation:`, err)); - // Record stream start - await this.deps.observationManager.record({ - threadId: props.threadId, traceId, type: ObservationType.LLM_STREAM_START, content: { phase: 'synthesis' }, metadata: { timestamp: Date.now() } - }).catch(err => Logger.error(`[${traceId}] Failed to record LLM_STREAM_START observation:`, err)); - - // Consume the stream - for await (const event of synthesisStream) { - // Call the base notify method directly - this.deps.uiSystem.getLLMStreamSocket().notify(event, { targetThreadId: event.threadId, targetSessionId: event.sessionId }); - - switch (event.type) { - case 'TOKEN': - // Append only final response tokens - if (event.tokenType === 'FINAL_SYNTHESIS_LLM_RESPONSE' || event.tokenType === 'LLM_RESPONSE') { - finalResponseContent += event.data; - } - break; - case 'METADATA': - aggregatedLlmMetadata = { ...(aggregatedLlmMetadata ?? {}), ...event.data }; // Aggregate metadata - await this.deps.observationManager.record({ - threadId: props.threadId, traceId, type: ObservationType.LLM_STREAM_METADATA, content: event.data, metadata: { phase: 'synthesis', timestamp: Date.now() } - }).catch(err => Logger.error(`[${traceId}] Failed to record LLM_STREAM_METADATA observation:`, err)); - break; - case 'ERROR': - synthesisStreamError = event.data instanceof Error ? event.data : new Error(String(event.data)); - status = status === 'partial' ? 'partial' : 'error'; - errorMessage = errorMessage ? `${errorMessage}; Synthesis stream error: ${synthesisStreamError.message}` : `Synthesis stream error: ${synthesisStreamError.message}`; - Logger.error(`[${traceId}] Synthesis Stream Error:`, synthesisStreamError); - await this.deps.observationManager.record({ - threadId: props.threadId, traceId, type: ObservationType.LLM_STREAM_ERROR, content: { phase: 'synthesis', error: synthesisStreamError.message, stack: synthesisStreamError.stack }, metadata: { timestamp: Date.now() } - }).catch(err => Logger.error(`[${traceId}] Failed to record LLM_STREAM_ERROR observation:`, err)); - break; - case 'END': - await this.deps.observationManager.record({ - threadId: props.threadId, traceId, type: ObservationType.LLM_STREAM_END, content: { phase: 'synthesis' }, metadata: { timestamp: Date.now() } - }).catch(err => Logger.error(`[${traceId}] Failed to record LLM_STREAM_END observation:`, err)); - break; + try { + while ((Date.now() - startTime) < maxWaitTimeMs) { + // Check if all tasks are completed + const incompleteTasks = updatedTasks.filter(task => + task.status !== A2ATaskStatus.COMPLETED && + task.status !== A2ATaskStatus.FAILED && + task.status !== A2ATaskStatus.CANCELLED + ); + + if (incompleteTasks.length === 0) { + Logger.info(`[${traceId}] All A2A tasks completed successfully`); + break; + } + + Logger.debug(`[${traceId}] Waiting for ${incompleteTasks.length} A2A task(s) to complete...`); + + // Poll each incomplete task for status updates + for (let i = 0; i < updatedTasks.length; i++) { + const task = updatedTasks[i]; + + // Skip already completed tasks + if (task.status === A2ATaskStatus.COMPLETED || + task.status === A2ATaskStatus.FAILED || + task.status === A2ATaskStatus.CANCELLED) { + continue; + } + + try { + // Get latest task status from repository (may have been updated by webhooks) + const latestTask = await this.deps.a2aTaskRepository.getTask(task.taskId); + if (latestTask) { + updatedTasks[i] = latestTask; + Logger.debug(`[${traceId}] Task ${task.taskId} status updated to: ${latestTask.status}`); + } + } catch (error: any) { + Logger.warn(`[${traceId}] Failed to get updated status for task ${task.taskId}:`, error); } - if (synthesisStreamError) break; } - // Handle stream error after loop - if (synthesisStreamError) { - if (status !== 'partial') { - throw new ARTError(errorMessage!, ErrorCode.SYNTHESIS_FAILED, synthesisStreamError); - } - finalResponseContent = errorMessage!; // Use error message as content if synthesis failed partially - } - // No need to parse output anymore + // Wait before next poll cycle + await new Promise(resolve => setTimeout(resolve, pollIntervalMs)); + } + + // Check final completion status + const completedTasks = updatedTasks.filter(task => task.status === A2ATaskStatus.COMPLETED); + const failedTasks = updatedTasks.filter(task => task.status === A2ATaskStatus.FAILED); + const timeoutTasks = updatedTasks.filter(task => + task.status !== A2ATaskStatus.COMPLETED && + task.status !== A2ATaskStatus.FAILED && + task.status !== A2ATaskStatus.CANCELLED + ); - } catch (err: any) { - // Catch errors from initial call or re-thrown stream errors - status = status === 'partial' ? 'partial' : 'error'; - const synthesisErrorMessage = `Synthesis phase failed: ${err.message}`; - errorMessage = errorMessage ? `${errorMessage}; ${synthesisErrorMessage}` : synthesisErrorMessage; - Logger.error(`[${traceId}] Synthesis Error:`, err); - // Avoid duplicate error recording if it came from the stream - if (!synthesisStreamError) { - await this.deps.observationManager.record({ - threadId: props.threadId, traceId, type: ObservationType.ERROR, content: { phase: 'synthesis', error: err.message, stack: err.stack }, metadata: { timestamp: Date.now() } - }); - } - if (status !== 'partial') { - throw err instanceof ARTError ? err : new ARTError(synthesisErrorMessage, ErrorCode.SYNTHESIS_FAILED, err); - } - finalResponseContent = errorMessage; // Use error message as content if synthesis failed partially + const totalWaitTime = Date.now() - startTime; + + // Record completion observation + await this.deps.observationManager.record({ + threadId: threadId, + traceId: traceId, + type: ObservationType.TOOL_CALL, + content: { + phase: 'a2a_waiting_complete', + message: 'A2A task waiting completed', + totalWaitTimeMs: totalWaitTime, + completedTasks: completedTasks.length, + failedTasks: failedTasks.length, + timeoutTasks: timeoutTasks.length, + success: timeoutTasks.length === 0 + }, + metadata: { timestamp: Date.now() } + }).catch(err => Logger.error(`[${traceId}] Failed to record A2A waiting completion observation:`, err)); + + if (timeoutTasks.length > 0) { + Logger.warn(`[${traceId}] ${timeoutTasks.length} A2A task(s) did not complete within timeout (${maxWaitTimeMs}ms)`); } - // --- Stage 6: Finalization --- - Logger.debug(`[${traceId}] Stage 6: Finalization`); - const finalTimestamp = Date.now(); - finalAiMessage = { - messageId: generateUUID(), - threadId: props.threadId, - role: MessageRole.AI, - content: finalResponseContent, // Use buffered content - timestamp: finalTimestamp, - metadata: { traceId }, - }; + if (completedTasks.length > 0) { + Logger.info(`[${traceId}] Successfully completed ${completedTasks.length} A2A task(s) in ${totalWaitTime}ms`); + } - // Save AI response message - await this.deps.conversationManager.addMessages(props.threadId, [finalAiMessage]); + return updatedTasks; - // Record final response observation + } catch (error: any) { + Logger.error(`[${traceId}] Error during A2A task waiting:`, error); + + // Record error observation await this.deps.observationManager.record({ - threadId: props.threadId, - traceId, - type: ObservationType.FINAL_RESPONSE, - content: { message: finalAiMessage }, - metadata: { timestamp: finalTimestamp } - }); + threadId: threadId, + traceId: traceId, + type: ObservationType.ERROR, + content: { + phase: 'a2a_waiting', + error: error.message, + stack: error.stack, + waitTimeMs: Date.now() - startTime + }, + metadata: { timestamp: Date.now() } + }).catch(err => Logger.error(`[${traceId}] Failed to record A2A waiting error observation:`, err)); - // Save state if modified (StateManager handles the check) - await this.deps.stateManager.saveStateIfModified(props.threadId); + // Don't fail the entire process for A2A waiting errors - return current state + return updatedTasks; + } + } - } catch (error: any) { - Logger.error(`[${traceId}] PESAgent process error:`, error); - status = status === 'partial' ? 'partial' : 'error'; // Keep partial if it was set before the catch - errorMessage = errorMessage ?? (error instanceof ARTError ? error.message : 'An unexpected error occurred.'); - // Ensure finalAiMessage is undefined if a critical error occurred before synthesis - if (status === 'error') finalAiMessage = undefined; - - // Record top-level error if not already recorded in specific phases - if (!(error instanceof ARTError && ( - error.code === ErrorCode.PLANNING_FAILED || - error.code === ErrorCode.TOOL_EXECUTION_FAILED || - error.code === ErrorCode.SYNTHESIS_FAILED - ))) { - await this.deps.observationManager.record({ - threadId: props.threadId, traceId, type: ObservationType.ERROR, content: { phase: 'agent_process', error: error.message, stack: error.stack }, metadata: { timestamp: Date.now() } - }).catch(err => Logger.error(`[${traceId}] Failed to record top-level error observation:`, err)); - } - } finally { - // Ensure state is attempted to be saved even if errors occurred mid-process - // (unless the error was during state loading itself) - try { - await this.deps.stateManager.saveStateIfModified(props.threadId); - } catch(saveError: any) { - Logger.error(`[${traceId}] Failed to save state during finalization:`, saveError); - // Potentially record another error observation - } + /** + * Executes local tools identified during planning. + * @private + */ + private async _executeLocalTools(toolCalls: ParsedToolCall[] | undefined, threadId: string, traceId: string): Promise { + const localToolCalls = toolCalls?.filter(call => call.toolName !== 'delegate_to_agent') ?? []; + + if (localToolCalls.length === 0) { + Logger.debug(`[${traceId}] Stage 5: Tool Execution (No local tool calls)`); + return []; } + Logger.debug(`[${traceId}] Stage 5: Tool Execution (${localToolCalls.length} calls)`); + try { + return await this.deps.toolSystem.executeTools(localToolCalls, threadId, traceId); + } catch (err: any) { + const errorMessage = `Tool execution phase failed: ${err.message}`; + Logger.error(`[${traceId}] Tool Execution System Error:`, err); + await this.deps.observationManager.record({ + threadId: threadId, traceId, type: ObservationType.ERROR, + content: { phase: 'tool_execution', error: err.message, stack: err.stack }, + metadata: { timestamp: Date.now() } + }); + throw new ARTError(errorMessage, ErrorCode.TOOL_EXECUTION_FAILED, err); + } + } - const endTime = Date.now(); - const metadata: ExecutionMetadata = { + /** + * Performs the synthesis phase including LLM call for final response generation. + * @private + */ + private async _performSynthesis( + props: AgentProps, + systemPrompt: string, + formattedHistory: ArtStandardPrompt, + planningOutput: any, + toolResults: ToolResult[], + a2aTasks: A2ATask[], + runtimeProviderConfig: RuntimeProviderConfig, + traceId: string, + finalPersona: AgentPersona, + planningContext?: { + toolsList: { name: string; description?: string }[]; + a2aSummary: string; + plannedToolCalls: ParsedToolCall[]; + rawPlanningText?: string; + } + ) { + Logger.debug(`[${traceId}] Stage 6: Synthesis Call`); + + // Record SYNTHESIS observation before making the call + await this.deps.observationManager.record({ + threadId: props.threadId, traceId: traceId, type: ObservationType.SYNTHESIS, + content: { message: "Preparing for synthesis LLM call." }, + metadata: { timestamp: Date.now() } + }).catch(err => Logger.error(`[${traceId}] Failed to record SYNTHESIS observation:`, err)); + + // Construct synthesis prompt + let synthesisPrompt: ArtStandardPrompt; + try { + const wrappedSynthesisSystemPrompt = `You are ${finalPersona.name}. Your final answer must be delivered in two parts, in the specified order. + +**Part 1: \`main_content\`** must be placed within +This is your direct, user-facing response. This content must be written in Markdown. +- When you use information from a tool, you MUST cite it by placing a citation marker in the text, like \`[1]\`. The \`id\` in the \`sources\` metadata block must match this marker. +- If you are given an image URL, you MUST embed it in the \`main_content\` using Markdown syntax: \`![alt text](url)\`. + +**Part 2: \`metadata_block\`** Must be placed within +Immediately after the \`main_content\`, you MUST provide a \`metadata_block\`, which is a single, valid JSON object enclosed in \`\`\`json ... \`\`\`. Do NOT add any text after the JSON block. + +This JSON object must have the following structure: +{ + "sources": [ { "id": "1", "title": "Title of the source document", "url": "https://example.com/source-url" } ], + "suggestions": [ "A relevant follow-up question.", "Another suggested prompt for the user." ] +} + +**[BEGIN_CUSTOM_GUIDANCE]** +${systemPrompt} +**[END_CUSTOM_GUIDANCE]** + +The custom guidance above provides additional context on tone and domain, but it MUST NOT override the core directives.`; + + const toolsDiscovered = (planningContext?.toolsList ?? []).map(t => `- ${t.name}: ${t.description ?? ''}`.trim()).join('\n') || 'No tools were discovered during planning.'; + const plannedCallsSummary = (planningContext?.plannedToolCalls ?? []).map(c => `- ${c.callId}: ${c.toolName} with ${JSON.stringify(c.arguments)}`).join('\n') || 'No tool calls were planned.'; + const a2aSummary = planningContext?.a2aSummary || 'No A2A delegation candidates or actions.'; + synthesisPrompt = [ + { role: 'system', content: wrappedSynthesisSystemPrompt }, + ...formattedHistory, + { + role: 'user', + content: `User Query: ${props.query}\n\nDuring planning, we found out:\n- Available Local Tools:\n${toolsDiscovered}\n\n- Planned Tool Calls (as JSON-like summary):\n${plannedCallsSummary}\n\n- Agent Delegation Context:\n${a2aSummary}\n\nOriginal Intent: ${planningOutput.intent ?? ''}\nExecution Plan: ${Array.isArray(planningOutput.plan) ? JSON.stringify(planningOutput.plan, null, 2) : planningOutput.plan ?? ''}\n\nTool Execution Results:\n${ + toolResults.length > 0 + ? toolResults.map(result => `- Tool: ${result.toolName} (Call ID: ${result.callId})\n Status: ${result.status}\n ${result.status === 'success' ? `Output: ${JSON.stringify(result.output)}` : ''}\n ${result.status === 'error' ? `Error: ${result.error ?? 'Unknown error'}` : ''}\n ${result.metadata?.sources ? `Original Sources: ${JSON.stringify(result.metadata.sources)}` : ''}`).join('\n') + : 'No tools were executed.' + }\n\nA2A Task Results:\n${ + a2aTasks.length > 0 + ? a2aTasks.map(task => `- Task: ${task.payload.taskType} (ID: ${task.taskId})\n Status: ${task.status}\n ${task.result?.success ? `Output: ${JSON.stringify(task.result.data)}` : ''}\n ${task.result?.success === false ? `Error: ${task.result.error ?? 'Unknown error'}` : ''}\n ${task.result?.metadata?.sources ? `Original Sources: ${JSON.stringify(task.result.metadata.sources)}` : ''}`).join('\n') + : 'No A2A tasks were delegated.' + }\n\nSynthesize the final answer based on the directives in the system prompt. Give appropriate weight to the verified Tool Execution Results and any successful A2A Task Results. If tools failed, explain briefly and answer using best available evidence.` + } + ]; + } catch (err: any) { + Logger.error(`[${traceId}] Failed to construct synthesis prompt object:`, err); + throw new ARTError(`Failed to construct synthesis prompt object: ${err.message}`, ErrorCode.PROMPT_ASSEMBLY_FAILED, err); + } + + Logger.debug(`[${traceId}] Stage 6b: Synthesis LLM Call`); + + const synthesisOptions: CallOptions = { threadId: props.threadId, traceId: traceId, userId: props.userId, - status: status, - totalDurationMs: endTime - startTime, - llmCalls: llmCalls, - toolCalls: toolCallsCount, // Use the count of executed tools - // llmCost: calculateCost(), // TODO: Implement cost calculation if needed - error: errorMessage, - llmMetadata: aggregatedLlmMetadata, // Add aggregated LLM metadata + sessionId: props.sessionId, + stream: true, + callContext: 'FINAL_SYNTHESIS', + requiredCapabilities: [ModelCapability.TEXT], + providerConfig: runtimeProviderConfig, + ...(props.options?.llmParams ?? {}), }; - if (!finalAiMessage && status !== 'success') { - // If we had an error before generating a final message, create a placeholder error response - finalAiMessage = { - messageId: generateUUID(), - threadId: props.threadId, - role: MessageRole.AI, - content: errorMessage ?? "Agent execution failed.", - timestamp: Date.now(), - metadata: { traceId, error: true } - }; - // Optionally save this error message to history? For now, just return it. - } else if (!finalAiMessage) { - // This case should ideally not happen if status is success, but as a fallback: - throw new ARTError("Agent finished with success status but no final message was generated.", ErrorCode.UNKNOWN_ERROR); + let finalResponseContent: string = ''; + let synthesisStreamError: Error | null = null; + let synthesisMetadata: LLMMetadata | undefined = undefined; + + try { + const synthesisStream = await this.deps.reasoningEngine.call(synthesisPrompt, synthesisOptions); + + // Record stream start + await this.deps.observationManager.record({ + threadId: props.threadId, traceId, type: ObservationType.LLM_STREAM_START, + content: { phase: 'synthesis' }, metadata: { timestamp: Date.now() } + }).catch(err => Logger.error(`[${traceId}] Failed to record LLM_STREAM_START observation:`, err)); + + // Consume the stream + for await (const event of synthesisStream) { + this.deps.uiSystem.getLLMStreamSocket().notify(event, { + targetThreadId: event.threadId, targetSessionId: event.sessionId + }); + + switch (event.type) { + case 'TOKEN': + if (event.tokenType === 'FINAL_SYNTHESIS_LLM_RESPONSE' || event.tokenType === 'LLM_RESPONSE') { + finalResponseContent += event.data; + } + // Emit THOUGHTS observation for thinking tokens during synthesis + if (event.tokenType && String(event.tokenType).includes('THINKING')) { + await this.deps.observationManager.record({ + threadId: props.threadId, + traceId, + type: ObservationType.THOUGHTS, + content: { text: event.data }, + metadata: { phase: 'synthesis', tokenType: event.tokenType, timestamp: Date.now() } + }).catch(err => Logger.error(`[${traceId}] Failed to record THOUGHTS (synthesis) observation:`, err)); + } + break; + case 'METADATA': + synthesisMetadata = { ...(synthesisMetadata ?? {}), ...event.data }; + await this.deps.observationManager.record({ + threadId: props.threadId, traceId, type: ObservationType.LLM_STREAM_METADATA, + content: event.data, metadata: { phase: 'synthesis', timestamp: Date.now() } + }).catch(err => Logger.error(`[${traceId}] Failed to record LLM_STREAM_METADATA observation:`, err)); + break; + case 'ERROR': + synthesisStreamError = event.data instanceof Error ? event.data : new Error(String(event.data)); + Logger.error(`[${traceId}] Synthesis Stream Error:`, synthesisStreamError); + await this.deps.observationManager.record({ + threadId: props.threadId, traceId, type: ObservationType.LLM_STREAM_ERROR, + content: { phase: 'synthesis', error: synthesisStreamError.message, stack: synthesisStreamError.stack }, + metadata: { timestamp: Date.now() } + }).catch(err => Logger.error(`[${traceId}] Failed to record LLM_STREAM_ERROR observation:`, err)); + break; + case 'END': + await this.deps.observationManager.record({ + threadId: props.threadId, traceId, type: ObservationType.LLM_STREAM_END, + content: { phase: 'synthesis' }, metadata: { timestamp: Date.now() } + }).catch(err => Logger.error(`[${traceId}] Failed to record LLM_STREAM_END observation:`, err)); + break; + } + if (synthesisStreamError) break; + } + + if (synthesisStreamError) { + throw new ARTError(`Synthesis stream error: ${synthesisStreamError.message}`, ErrorCode.SYNTHESIS_FAILED, synthesisStreamError); + } + + } catch (err: any) { + const synthesisErrorMessage = `Synthesis phase failed: ${err.message}`; + Logger.error(`[${traceId}] Synthesis Error:`, err); + if (!synthesisStreamError) { + await this.deps.observationManager.record({ + threadId: props.threadId, traceId, type: ObservationType.ERROR, + content: { phase: 'synthesis', error: err.message, stack: err.stack }, + metadata: { timestamp: Date.now() } + }); + } + throw err instanceof ARTError ? err : new ARTError(synthesisErrorMessage, ErrorCode.SYNTHESIS_FAILED, err); } + // --- Response Parsing --- + let mainContent = finalResponseContent; + let uiMetadata: object | undefined = undefined; - return { - response: finalAiMessage, - metadata: metadata, + try { + const metadataBlockRegex = /```json\s*([\s\S]*?)\s*```$/; + const match = finalResponseContent.match(metadataBlockRegex); + + if (match && match[1]) { + mainContent = finalResponseContent.replace(metadataBlockRegex, '').trim(); + uiMetadata = JSON.parse(match[1]); + Logger.debug(`[${traceId}] Parsed metadata block from synthesis output.`); + } else { + Logger.warn(`[${traceId}] No metadata block found in synthesis output. Treating entire output as main content.`); + } + } catch (parseError: any) { + Logger.error(`[${traceId}] Failed to parse metadata block from synthesis output:`, parseError); + // Fallback to treating the whole response as content + mainContent = finalResponseContent; + uiMetadata = { error: 'Failed to parse metadata block', details: parseError.message }; + } + + return { finalResponseContent: mainContent, synthesisMetadata, uiMetadata }; + } + + /** + * Finalizes the agent execution by saving the final message and performing cleanup. + * @private + */ + private async _finalize(props: AgentProps, finalResponseContent: string, traceId: string, uiMetadata?: object): Promise { + Logger.debug(`[${traceId}] Stage 7: Finalization`); + + const finalTimestamp = Date.now(); + const finalAiMessage: ConversationMessage = { + messageId: generateUUID(), + threadId: props.threadId, + role: MessageRole.AI, + content: finalResponseContent, + timestamp: finalTimestamp, + metadata: { traceId }, }; + + // Save AI response message + await this.deps.conversationManager.addMessages(props.threadId, [finalAiMessage]); + + // Record final response observation + await this.deps.observationManager.record({ + threadId: props.threadId, + traceId, + type: ObservationType.FINAL_RESPONSE, + content: { + message: finalAiMessage, + uiMetadata: uiMetadata + }, + metadata: { timestamp: finalTimestamp } + }); + + return finalAiMessage; } /** @@ -585,33 +1108,30 @@ export class PESAgent implements IAgentCore { * @param history - Array of ConversationMessage objects. * @returns Array of messages suitable for ArtStandardPrompt. */ - private formatHistoryForPrompt(history: ConversationMessage[]): ArtStandardPrompt { // Renamed function and updated return type - return history.map((msg) => { // Removed unused 'index' parameter + private formatHistoryForPrompt(history: ConversationMessage[]): ArtStandardPrompt { + return history.map((msg) => { let role: ArtStandardMessageRole; switch (msg.role) { case MessageRole.USER: - role = 'user'; // Assign string literal + role = 'user'; break; case MessageRole.AI: - role = 'assistant'; // Assign string literal + role = 'assistant'; break; - case MessageRole.SYSTEM: // Add mapping for SYSTEM role - role = 'system'; // Assign string literal + case MessageRole.SYSTEM: + role = 'system'; break; case MessageRole.TOOL: - role = 'tool'; // Assign string literal + role = 'tool'; break; default: - // Log a warning for unhandled roles but default to user - Logger.warn(`Unhandled message role '${msg.role}' in formatHistoryForPrompt. Defaulting to 'user'.`); // Updated function name in log - role = 'user'; // Assign string literal + Logger.warn(`Unhandled message role '${msg.role}' in formatHistoryForPrompt. Defaulting to 'user'.`); + role = 'user'; } - // Return the object structure expected by ArtStandardPrompt return { role: role, - content: msg.content, // Use raw content - // Add other fields like 'name' or 'tool_call_id' if necessary based on msg structure + content: msg.content, }; - }).filter(msg => msg.content); // Example: Filter out messages with no content if needed + }).filter(msg => msg.content); } } diff --git a/src/core/interfaces.ts b/src/core/interfaces.ts old mode 100644 new mode 100755 index 737e631..7656ab1 --- a/src/core/interfaces.ts +++ b/src/core/interfaces.ts @@ -21,7 +21,7 @@ import { // --- Import new types (Refactor Phase 1) --- ArtStandardPrompt, // PromptContext, // Removed - No longer used by PromptManager interface -} from '../types'; +} from '@/types'; // Re-export types that might be needed by implementers of these core interfaces export type { @@ -45,7 +45,7 @@ export type { ArtStandardPrompt, StreamEvent, // Also re-export StreamEvent as it's used in ReasoningEngine LLMMetadata // Also re-export LLMMetadata -} from '../types'; +} from '@/types'; /** @@ -80,7 +80,7 @@ export interface ReasoningEngine { * @throws {ARTError} If a critical error occurs during the initial call setup or if the stream itself errors out (typically code `LLM_PROVIDER_ERROR`). */ // TODO (Refactor): Update prompt type from FormattedPrompt to FormattedPromptResult['prompt'] in Phase 2 - call(prompt: import('../types').FormattedPrompt, options: CallOptions): Promise>; + call(prompt: import('@/types').FormattedPrompt, options: CallOptions): Promise>; } // --- PromptManager Interface (Refactor Phase 1) --- @@ -110,10 +110,37 @@ export interface PromptManager { */ validatePrompt(prompt: ArtStandardPrompt): ArtStandardPrompt; + /** + * Assembles a prompt using a Mustache template (blueprint) and context data. + * Renders the template with the provided context and parses the result as an ArtStandardPrompt. + * + * @param blueprint - The Mustache template containing the prompt structure. + * @param context - The context data to inject into the template. + * @returns A promise resolving to the assembled ArtStandardPrompt. + * @throws {ARTError} If template rendering or JSON parsing fails. + */ + assemblePrompt(blueprint: import('@/types').PromptBlueprint, context: import('@/types').PromptContext): Promise; + // Future methods could include: // - loadFragmentsFromDir(directoryPath: string): Promise; // - registerFragment(name: string, content: string): void; } +// --- SystemPromptResolver Interface --- +/** + * Resolves the final system prompt from base + instance/thread/call overrides + * using tag+variables and merge strategies. + */ +export interface SystemPromptResolver { + resolve( + input: { + base: string; + instance?: string | import('@/types').SystemPromptOverride; + thread?: string | import('@/types').SystemPromptOverride; + call?: string | import('@/types').SystemPromptOverride; + }, + traceId?: string + ): Promise; +} // --- END PromptManager Interface --- @@ -128,10 +155,25 @@ export interface OutputParser { * @returns A promise resolving to an object containing the extracted intent, plan description, and an array of parsed tool calls. * @throws {ARTError} If the output cannot be parsed into the expected structure (typically code `OUTPUT_PARSING_FAILED`). */ + /** + * Parses the raw planning LLM output into structured fields. + * + * @remarks + * This method should be resilient to provider-specific wrappers and formats. + * Implementations MUST attempt JSON-first parsing and then fall back to parsing + * labeled sections. Supported fields: + * - `title?`: A concise thread title (<= 10 words), derived from the user's intent and context. + * - `intent?`: A short summary of the user's goal. + * - `plan?`: A human-readable list/description of steps. + * - `toolCalls?`: Structured tool call intents parsed from the output. + * - `thoughts?`: Aggregated content extracted from tags when present. + */ parsePlanningOutput(output: string): Promise<{ + title?: string; intent?: string; plan?: string; toolCalls?: ParsedToolCall[]; + thoughts?: string; }>; /** @@ -198,6 +240,18 @@ export interface ToolRegistry { * @returns A promise resolving to an array of `ToolSchema` objects. */ getAvailableTools(filter?: { enabledForThreadId?: string }): Promise; + + /** + * Unregisters a tool by its unique name. + * Implementations should silently succeed if the tool does not exist. + */ + unregisterTool?(toolName: string): Promise; + + /** + * Unregisters multiple tools that match a predicate. Returns the number of tools removed. + * This is useful for removing all tools belonging to a specific MCP server by name prefix. + */ + unregisterTools?(predicate: (schema: ToolSchema) => boolean): Promise; } /** @@ -281,6 +335,37 @@ export interface StateManager { */ setAgentState(threadId: string, state: AgentState): Promise; + /** + * Enables specific tools for a conversation thread by adding them to the thread's enabled tools list. + * This method loads the current thread configuration, updates the enabledTools array, + * and persists the changes. Cache is invalidated to ensure fresh data on next load. + * @param threadId - The unique identifier of the thread. + * @param toolNames - Array of tool names to enable for this thread. + * @returns A promise that resolves when the tools are enabled and configuration is saved. + * @throws {ARTError} If no ThreadConfig exists for the threadId, or if the repository fails. + */ + enableToolsForThread(threadId: string, toolNames: string[]): Promise; + + /** + * Disables specific tools for a conversation thread by removing them from the thread's enabled tools list. + * This method loads the current thread configuration, updates the enabledTools array, + * and persists the changes. Cache is invalidated to ensure fresh data on next load. + * @param threadId - The unique identifier of the thread. + * @param toolNames - Array of tool names to disable for this thread. + * @returns A promise that resolves when the tools are disabled and configuration is saved. + * @throws {ARTError} If no ThreadConfig exists for the threadId, or if the repository fails. + */ + disableToolsForThread(threadId: string, toolNames: string[]): Promise; + + /** + * Gets the list of currently enabled tools for a specific thread. + * This is a convenience method that loads the thread context and returns the enabledTools array. + * @param threadId - The unique identifier of the thread. + * @returns A promise that resolves to an array of enabled tool names, or empty array if no tools are enabled. + * @throws {ARTError} If the thread context cannot be loaded. + */ + getEnabledToolsForThread(threadId: string): Promise; + // Potentially add methods to update config/state if needed during runtime, // though v0.2.4 focuses on loading existing config. // updateAgentState(threadId: string, updates: Partial): Promise; @@ -384,8 +469,8 @@ export interface ObservationSocket extends ITypedSocket {} // Import concrete socket classes for use in the UISystem interface return types -import { ObservationSocket as ObservationSocketImpl } from '../systems/ui/observation-socket'; -import { ConversationSocket as ConversationSocketImpl } from '../systems/ui/conversation-socket'; +import { ObservationSocket as ObservationSocketImpl } from '@/systems/ui/observation-socket'; +import { ConversationSocket as ConversationSocketImpl } from '@/systems/ui/conversation-socket'; /** * Interface for the system providing access to UI communication sockets. @@ -396,7 +481,9 @@ export interface UISystem { /** Returns the singleton instance of the ConversationSocket. */ getConversationSocket(): ConversationSocketImpl; /** Returns the singleton instance of the LLMStreamSocket. */ - getLLMStreamSocket(): import("../systems/ui/llm-stream-socket").LLMStreamSocket; + getLLMStreamSocket(): import("@/systems/ui/llm-stream-socket").LLMStreamSocket; + /** Returns the singleton instance of the A2ATaskSocket. */ + getA2ATaskSocket(): import("@/systems/ui/a2a-task-socket").A2ATaskSocket; // TODO: Potentially add getStateSocket(): StateSocket; in the future } @@ -473,10 +560,105 @@ export interface IStateRepository { } /** - * Represents the fully initialized and configured ART Framework client instance. - * This object is the main entry point for interacting with the framework after setup. - * It provides access to the core processing method and key subsystems. + * Interface for managing A2A (Agent-to-Agent) task persistence and retrieval. */ +export interface IA2ATaskRepository { + /** + * Creates a new A2A task in the repository. + * @param task - The A2ATask object to create. + * @returns A promise that resolves when the task is successfully stored. + * @throws {ARTError} If the task cannot be created (e.g., duplicate taskId, validation errors). + */ + createTask(task: import('@/types').A2ATask): Promise; + + /** + * Retrieves an A2A task by its unique identifier. + * @param taskId - The unique identifier of the task. + * @returns A promise resolving to the A2ATask object if found, or null if not found. + * @throws {ARTError} If an error occurs during retrieval. + */ + getTask(taskId: string): Promise; + + /** + * Updates an existing A2A task with new information. + * @param taskId - The unique identifier of the task to update. + * @param updates - Partial A2ATask object containing the fields to update. + * @returns A promise that resolves when the task is successfully updated. + * @throws {ARTError} If the task is not found or cannot be updated. + */ + updateTask(taskId: string, updates: Partial): Promise; + + /** + * Removes an A2A task from the repository. + * @param taskId - The unique identifier of the task to delete. + * @returns A promise that resolves when the task is successfully deleted. + * @throws {ARTError} If the task is not found or cannot be deleted. + */ + deleteTask(taskId: string): Promise; + + /** + * Retrieves tasks associated with a specific thread. + * @param threadId - The thread identifier to filter tasks. + * @param filter - Optional filter criteria for task status, priority, or assigned agent. + * @returns A promise resolving to an array of A2ATask objects matching the criteria. + */ + getTasksByThread(threadId: string, filter?: { + status?: import('@/types').A2ATaskStatus | import('@/types').A2ATaskStatus[]; + priority?: import('@/types').A2ATaskPriority; + assignedAgentId?: string; + }): Promise; + + /** + * Retrieves tasks assigned to a specific agent. + * @param agentId - The agent identifier to filter tasks. + * @param filter - Optional filter criteria for task status or priority. + * @returns A promise resolving to an array of A2ATask objects assigned to the agent. + */ + getTasksByAgent(agentId: string, filter?: { + status?: import('@/types').A2ATaskStatus | import('@/types').A2ATaskStatus[]; + priority?: import('@/types').A2ATaskPriority; + }): Promise; + + /** + * Retrieves tasks based on their current status. + * @param status - The task status(es) to filter by. + * @param options - Optional query parameters like limit and pagination. + * @returns A promise resolving to an array of A2ATask objects with the specified status. + */ + getTasksByStatus( + status: import('@/types').A2ATaskStatus | import('@/types').A2ATaskStatus[], + options?: { limit?: number; offset?: number } + ): Promise; +} + +/** + * Interface for an authentication strategy that can provide authorization headers. + * This enables pluggable security for remote service connections (MCP servers, A2A agents, etc.) + */ +export interface IAuthStrategy { + /** + * Asynchronously retrieves the authentication headers. + * This might involve checking a cached token, refreshing it if expired, and then returning it. + * @returns A promise that resolves to a record of header keys and values. + * @throws {ARTError} If authentication fails or cannot be obtained. + */ + getAuthHeaders(): Promise>; + + /** Optional: Initiates the login flow for the strategy. */ + login?(): Promise; + + /** Optional: Handles the redirect from the authentication server. */ + handleRedirect?(): Promise; + + /** Optional: Logs the user out. */ + logout?(): void; + + /** Optional: Checks if the user is authenticated. */ + isAuthenticated?(): Promise; +} + +import { AuthManager } from '@/systems/auth/AuthManager'; + export interface ArtInstance { /** The main method to process a user query using the configured Agent Core. */ readonly process: IAgentCore['process']; @@ -490,6 +672,8 @@ export interface ArtInstance { readonly toolRegistry: ToolRegistry; /** Accessor for the Observation Manager, used for recording and retrieving observations. */ readonly observationManager: ObservationManager; + /** Accessor for the Auth Manager, used for handling authentication. */ + readonly authManager?: AuthManager | null; // Note: Direct access to other internal components like ReasoningEngine or StorageAdapter // is typically discouraged; interaction should primarily happen via the managers and process method. } \ No newline at end of file diff --git a/src/errors.ts b/src/errors.ts old mode 100644 new mode 100755 index 86ce3fc..2b05df9 --- a/src/errors.ts +++ b/src/errors.ts @@ -2,63 +2,152 @@ /** * Defines standard error codes for the ART framework. + * These codes categorize errors originating from different subsystems. */ export enum ErrorCode { // Configuration Errors + /** Invalid or malformed configuration provided. */ INVALID_CONFIG = 'INVALID_CONFIG', - MISSING_API_KEY = 'MISSING_API_KEY', + /** A required API key was not provided. */ + MISSING_API_key = 'MISSING_API_KEY', + /** General configuration-related error. */ + CONFIGURATION_ERROR = 'CONFIGURATION_ERROR', // Storage Errors + /** A generic error occurred in the storage layer. */ STORAGE_ERROR = 'STORAGE_ERROR', + /** The requested thread could not be found in storage. */ THREAD_NOT_FOUND = 'THREAD_NOT_FOUND', + /** Failed to save data to the storage layer. */ SAVE_FAILED = 'SAVE_FAILED', // Reasoning Errors + /** An error occurred while communicating with the LLM provider. */ LLM_PROVIDER_ERROR = 'LLM_PROVIDER_ERROR', + /** Failed to generate a prompt. */ PROMPT_GENERATION_FAILED = 'PROMPT_GENERATION_FAILED', + /** Failed to parse the output from the LLM. */ OUTPUT_PARSING_FAILED = 'OUTPUT_PARSING_FAILED', - PROMPT_ASSEMBLY_FAILED = 'PROMPT_ASSEMBLY_FAILED', // Error during prompt template rendering or initial structure creation (legacy, might be removed) - PROMPT_FRAGMENT_NOT_FOUND = 'PROMPT_FRAGMENT_NOT_FOUND', // Requested prompt fragment does not exist - PROMPT_VALIDATION_FAILED = 'PROMPT_VALIDATION_FAILED', // Constructed prompt object failed schema validation - PROMPT_TRANSLATION_FAILED = 'PROMPT_TRANSLATION_FAILED', // Added for Adapter translation + /** Error during prompt template rendering or initial structure creation. */ + PROMPT_ASSEMBLY_FAILED = 'PROMPT_ASSEMBLY_FAILED', + /** The requested prompt fragment does not exist. */ + PROMPT_FRAGMENT_NOT_FOUND = 'PROMPT_FRAGMENT_NOT_FOUND', + /** The constructed prompt object failed schema validation. */ + PROMPT_VALIDATION_FAILED = 'PROMPT_VALIDATION_FAILED', + /** Failed to translate the ART standard prompt to a provider-specific format. */ + PROMPT_TRANSLATION_FAILED = 'PROMPT_TRANSLATION_FAILED', // Tool Errors + /** The requested tool could not be found in the registry. */ TOOL_NOT_FOUND = 'TOOL_NOT_FOUND', + /** The provided tool schema failed validation. */ TOOL_SCHEMA_VALIDATION_FAILED = 'TOOL_SCHEMA_VALIDATION_FAILED', - TOOL_EXECUTION_ERROR = 'TOOL_EXECUTION_ERROR', // Generic tool execution error + /** A generic error occurred during tool execution. */ + TOOL_EXECUTION_ERROR = 'TOOL_EXECUTION_ERROR', + /** The requested tool is disabled for the current thread. */ TOOL_DISABLED = 'TOOL_DISABLED', // Agent Core / Orchestration Errors + /** The planning phase of the agent failed. */ PLANNING_FAILED = 'PLANNING_FAILED', - TOOL_EXECUTION_FAILED = 'TOOL_EXECUTION_FAILED', // Error within the ToolSystem execution loop + /** An error occurred within the ToolSystem execution loop. */ + TOOL_EXECUTION_FAILED = 'TOOL_EXECUTION_FAILED', + /** The synthesis phase of the agent failed. */ SYNTHESIS_FAILED = 'SYNTHESIS_FAILED', - AGENT_PROCESSING_ERROR = 'AGENT_PROCESSING_ERROR', // General error during agent.process + /** A general error occurred during the agent's process method. */ + AGENT_PROCESSING_ERROR = 'AGENT_PROCESSING_ERROR', + /** An A2A (Agent-to-Agent) task delegation failed. */ + DELEGATION_FAILED = 'DELEGATION_FAILED', // General Errors + /** A network error occurred. */ NETWORK_ERROR = 'NETWORK_ERROR', + /** An operation timed out. */ TIMEOUT_ERROR = 'TIMEOUT_ERROR', + /** An operation timed out (duplicate of TIMEOUT_ERROR). */ + TIMEOUT = 'TIMEOUT', + /** An error occurred with an external service. */ + EXTERNAL_SERVICE_ERROR = 'EXTERNAL_SERVICE_ERROR', + /** The requested task was not found. */ + TASK_NOT_FOUND = 'TASK_NOT_FOUND', + /** Input data failed validation. */ + VALIDATION_ERROR = 'VALIDATION_ERROR', + /** The request was invalid or malformed. */ + INVALID_REQUEST = 'INVALID_REQUEST', + /** A task with the same ID already exists. */ + DUPLICATE_TASK_ID = 'DUPLICATE_TASK_ID', + /** A generic error occurred in a repository. */ + REPOSITORY_ERROR = 'REPOSITORY_ERROR', + /** A connection is already established. */ + ALREADY_CONNECTED = 'ALREADY_CONNECTED', + /** A required configuration is missing. */ + MISSING_CONFIG = 'MISSING_CONFIG', + /** The requested feature is not implemented. */ + NOT_IMPLEMENTED = 'NOT_IMPLEMENTED', + /** No active connection is available. */ + NOT_CONNECTED = 'NOT_CONNECTED', + /** The request timed out. */ + REQUEST_TIMEOUT = 'REQUEST_TIMEOUT', + /** Standard input is not available. */ + NO_STDIN = 'NO_STDIN', + /** The provided URL is not an HTTP/HTTPS URL. */ + NO_HTTP_URL = 'NO_HTTP_URL', + /** An HTTP error occurred. */ + HTTP_ERROR = 'HTTP_ERROR', + /** The requested server was not found. */ + SERVER_NOT_FOUND = 'SERVER_NOT_FOUND', + /** A health check for a service failed. */ + HEALTH_CHECK_FAILED = 'HEALTH_CHECK_FAILED', + /** Failed to discover tools from a remote source. */ + TOOL_DISCOVERY_FAILED = 'TOOL_DISCOVERY_FAILED', + /** The requested transport protocol is not supported. */ + UNSUPPORTED_TRANSPORT = 'UNSUPPORTed_TRANSPORT', + /** A CORS browser extension is required to proceed. */ + CORS_EXTENSION_REQUIRED = 'CORS_EXTENSION_REQUIRED', + /** CORS permissions are required but have not been granted. */ + CORS_PERMISSION_REQUIRED = 'CORS_PERMISSION_REQUIRED', + /** An unknown or unexpected error occurred. */ UNKNOWN_ERROR = 'UNKNOWN_ERROR', // Provider Manager Errors - UNKNOWN_PROVIDER = 'UNKNOWN_PROVIDER', // Checklist item 4.7 - LOCAL_PROVIDER_CONFLICT = 'LOCAL_PROVIDER_CONFLICT', // Checklist item 4.7 - LOCAL_INSTANCE_BUSY = 'LOCAL_INSTANCE_BUSY', // Checklist item 4.7 - API_QUEUE_TIMEOUT = 'API_QUEUE_TIMEOUT', // Checklist item 4.7 (optional) - ADAPTER_INSTANTIATION_ERROR = 'ADAPTER_INSTANTIATION_ERROR', // Checklist item 4.7 + /** The requested LLM provider is not known or configured. */ + UNKNOWN_PROVIDER = 'UNKNOWN_PROVIDER', + /** Attempted to activate a local provider when another is already active. */ + LOCAL_PROVIDER_CONFLICT = 'LOCAL_PROVIDER_CONFLICT', + /** The requested local LLM instance is currently busy. */ + LOCAL_INSTANCE_BUSY = 'LOCAL_INSTANCE_BUSY', + /** Timeout waiting for an available instance of an API provider. */ + API_QUEUE_TIMEOUT = 'API_QUEUE_TIMEOUT', + /** Failed to instantiate an adapter for a provider. */ + ADAPTER_INSTANTIATION_ERROR = 'ADAPTER_INSTANTIATION_ERROR', } /** * Custom error class for ART framework specific errors. + * It includes an error code, an optional original error for chaining, + * and a details object for additional context. */ export class ARTError extends Error { + /** The specific error code from the ErrorCode enum. */ public readonly code: ErrorCode; + /** The original error that caused this error, if any. */ public readonly originalError?: Error; - - constructor(message: string, code: ErrorCode, originalError?: Error) { + /** A record of additional details about the error. */ + public details: Record; + + /** + * Creates an instance of ARTError. + * @param {string} message - The error message. + * @param {ErrorCode} code - The error code. + * @param {Error} [originalError] - The original error, if any. + * @param {Record} [details={}] - Additional details about the error. + */ + constructor(message: string, code: ErrorCode, originalError?: Error, details: Record = {}) { super(message); this.name = 'ARTError'; this.code = code; this.originalError = originalError; + this.details = details; // Maintains proper stack trace in V8 environments (Node, Chrome) if (Error.captureStackTrace) { @@ -66,6 +155,10 @@ export class ARTError extends Error { } } + /** + * Returns a string representation of the error, including the original error if present. + * @returns {string} The string representation of the error. + */ toString(): string { let str = `${this.name} [${this.code}]: ${this.message}`; if (this.originalError) { @@ -75,7 +168,9 @@ export class ARTError extends Error { } } -// Specific error classes for Provider Manager (Checklist item 4.7) +/** + * Error thrown when a requested LLM provider is not known or configured. + */ export class UnknownProviderError extends ARTError { constructor(providerName: string) { super(`Unknown provider requested: ${providerName}`, ErrorCode.UNKNOWN_PROVIDER); @@ -83,6 +178,9 @@ export class UnknownProviderError extends ARTError { } } +/** + * Error thrown when attempting to activate a local provider while another is already active. + */ export class LocalProviderConflictError extends ARTError { constructor(requestedProvider: string, activeProvider: string) { super(`Cannot activate local provider '${requestedProvider}'. Local provider '${activeProvider}' is already active.`, ErrorCode.LOCAL_PROVIDER_CONFLICT); @@ -90,6 +188,9 @@ export class LocalProviderConflictError extends ARTError { } } +/** + * Error thrown when a requested local LLM instance is currently busy. + */ export class LocalInstanceBusyError extends ARTError { constructor(providerName: string, modelId: string) { super(`Local provider instance '${providerName}:${modelId}' is currently busy.`, ErrorCode.LOCAL_INSTANCE_BUSY); @@ -97,6 +198,9 @@ export class LocalInstanceBusyError extends ARTError { } } +/** + * Error thrown when a timeout occurs while waiting for an available instance of an API provider. + */ export class ApiQueueTimeoutError extends ARTError { constructor(providerName: string) { super(`Timeout waiting for an available instance of API provider '${providerName}'.`, ErrorCode.API_QUEUE_TIMEOUT); @@ -104,6 +208,9 @@ export class ApiQueueTimeoutError extends ARTError { } } +/** + * Error thrown when an adapter for a provider fails to instantiate. + */ export class AdapterInstantiationError extends ARTError { constructor(providerName: string, originalError: Error) { super(`Failed to instantiate adapter for provider '${providerName}'.`, ErrorCode.ADAPTER_INSTANTIATION_ERROR, originalError); diff --git a/src/index.ts b/src/index.ts old mode 100644 new mode 100755 index fe68b33..1f1fda5 --- a/src/index.ts +++ b/src/index.ts @@ -1,72 +1,307 @@ /** - * Main entry point for the ART Framework library. - * This file exports the primary factory function (`createArtInstance`), - * core components, adapters, types, interfaces, and utilities needed - * to build and run ART agents. - */ - -// --- Core Factory Function --- -/** - * The main function to create and initialize an ART instance. - * @see {@link ./core/agent-factory.ts} for implementation details. - */ -export { createArtInstance } from './core/agent-factory'; - -// --- Agent Core Implementations --- -/** - * The default Plan-Execute-Synthesize agent implementation. - * @see {@link ./core/agents/pes-agent.ts} - */ -export { PESAgent } from './core/agents/pes-agent'; -// export { ReActAgent } from './core/agents/react-agent'; // Example for future - -// --- Storage Adapters (Implementations of `StorageAdapter`) --- -/** Stores data temporarily in memory. Useful for testing. */ -export { InMemoryStorageAdapter } from './adapters/storage/inMemory'; -/** Persists data in the browser's IndexedDB. Recommended for web apps. */ -export { IndexedDBStorageAdapter } from './adapters/storage/indexedDB'; - -// --- Reasoning Provider Adapters (Implementations of `ProviderAdapter`) --- -/** Adapter for Google Gemini models. */ -export { GeminiAdapter } from './adapters/reasoning/gemini'; -/** Adapter for OpenAI models (GPT-3.5, GPT-4, etc.). */ -export { OpenAIAdapter } from './adapters/reasoning/openai'; -/** Adapter for Anthropic Claude models. */ -export { AnthropicAdapter } from './adapters/reasoning/anthropic'; -/** Adapter for OpenRouter, acting as a proxy to various models. */ -export { OpenRouterAdapter } from './adapters/reasoning/openrouter'; -/** Adapter for DeepSeek models. */ -export { DeepSeekAdapter } from './adapters/reasoning/deepseek'; -/** Adapter for Ollama models. */ -export { OllamaAdapter } from './adapters/reasoning/ollama'; -export type { OllamaAdapterOptions } from './adapters/reasoning/ollama'; - -// --- Built-in Tools (Implementations of `IToolExecutor`) --- -/** A basic tool for evaluating mathematical expressions. */ -export { CalculatorTool } from './tools/CalculatorTool'; -// export { WebSearchTool } from './tools/WebSearchTool'; // Example for future - -// --- Core Types & Interfaces --- -/** Export all core data structures and type definitions. @see {@link ./types/index.ts} */ -export * from './types'; -export type { ArtInstanceConfig } from './types'; // Explicit export for clarity -/** Export all core system interfaces. @see {@link ./core/interfaces.ts} */ -export * from './core/interfaces'; -// Explicitly export Provider types from their source file + * ART (Agentic Reasoning & Tool-use) Framework - Main Entry Point + * ----------------------------------------------------------------- + * + * Welcome to the ART framework! This file is the primary public API surface for the library. + * It's structured to provide a clear and intuitive experience for developers, + * whether you're just getting started or building advanced, custom agentic systems. + * + * --- Quick Start --- + * For most use cases, you'll only need `createArtInstance` and the associated types. + * + * Example: + * ```ts + * import { createArtInstance } from 'art-framework'; + * import type { ArtInstanceConfig } from 'art-framework'; + * + * const config: ArtInstanceConfig = { + * storage: { type: 'memory' }, + * providers: { + * openai: { adapter: 'openai', apiKey: '...' } + * }, + * tools: [new CalculatorTool()], + * persona: { + * name: 'MyAgent', + * prompts: { + * synthesis: 'You are MyAgent. Always answer in rhyme.' + * } + * } + * }; + * + * const art = await createArtInstance(config); + * const response = await art.process({ query: "Hello, world!" }); + * ``` + * + * --- API Structure --- + * 1. **Core Factory**: The main function to create an ART instance. + * 2. **Primary Interfaces & Types**: Essential types for configuration and interaction. + * 3. **Built-in Components**: Concrete implementations of adapters, tools, and agents. + * 4. **Advanced Systems & Managers**: Lower-level components for building custom logic. + * 5. **Utilities**: Helper functions and classes. + * + * @module ART + */ + +// --- 1. Core Factory --- + +/** + * The main factory function to create and initialize a complete ART framework instance. + * This is the recommended starting point for all users. It simplifies setup by + * assembling all necessary components based on the provided configuration. + * @param {ArtInstanceConfig} config - The configuration object for the ART instance. + * @returns {Promise} A promise that resolves to a ready-to-use ART instance. + * @see {@link ArtInstanceConfig} for configuration options. + */ +export { createArtInstance } from '@/core/agent-factory'; + +// --- 2. Primary Interfaces & Types --- + +/** + * Core interfaces that define the contracts for key components of the ART framework. + * Use these to build your own custom components (e.g., agents, tools, storage adapters). + */ +export * from '@/core/interfaces'; + +/** + * Core data structures, enums, and type definitions used throughout the framework. + * This includes types for messages, observations, agent state, and more. + */ +export * from '@/types'; + +/** + * The main configuration object for creating an ART instance. + * Explicitly exported for clarity and ease of use. + */ +export type { ArtInstanceConfig, AgentPersona } from '@/types'; + +/** + * Types related to LLM Provider management. + * Useful for advanced scenarios, such as dynamically configuring providers at runtime. + */ +export type { + ProviderManagerConfig, + AvailableProviderEntry, + RuntimeProviderConfig, + ManagedAdapterAccessor, + IProviderManager, +} from '@/types/providers'; + +// --- 3. Built-in Components --- + +// --- Agent Implementations --- + +/** + * The default agent core implementation based on the Plan-Execute-Synthesize model. + * It's suitable for a wide range of general-purpose tasks. + * When to use: As the default reasoning engine unless you have a specific need for a different agent architecture. + */ +export { PESAgent } from '@/core/agents/pes-agent'; + +// --- Storage Adapters --- + +/** + * A non-persistent storage adapter that keeps all data in memory. + * When to use: Ideal for testing, short-lived scripts, or scenarios + * where data persistence across sessions is not required. + */ +export { InMemoryStorageAdapter } from '@/integrations/storage/inMemory'; + +/** + * A persistent storage adapter that uses the browser's IndexedDB. + * When to use: The recommended choice for web-based applications to persist + * conversation history and agent state on the client-side. + */ +export { IndexedDBStorageAdapter } from '@/integrations/storage/indexedDB'; + +/** + * A persistent storage adapter for connecting to a Supabase (Postgres) database. + * When to use: Suitable for server-side environments, or for applications + * requiring data to be shared or persisted in the cloud. + */ +export { SupabaseStorageAdapter } from '@/integrations/storage/supabase'; + +// --- Reasoning Provider Adapters --- + +/** + * Adapter for Google's Gemini models. + */ +export { GeminiAdapter } from '@/integrations/reasoning/gemini'; +export type { GeminiAdapterOptions } from '@/integrations/reasoning/gemini'; + +/** + * Adapter for OpenAI's models (e.g., GPT-3.5, GPT-4). + */ +export { OpenAIAdapter } from '@/integrations/reasoning/openai'; +export type { OpenAIAdapterOptions } from '@/integrations/reasoning/openai'; + +/** + * Adapter for Anthropic's Claude models. + */ +export { AnthropicAdapter } from '@/integrations/reasoning/anthropic'; +export type { AnthropicAdapterOptions } from '@/integrations/reasoning/anthropic'; + +/** + * Adapter for OpenRouter, which acts as a proxy to a wide variety of models. + */ +export { OpenRouterAdapter } from '@/integrations/reasoning/openrouter'; +export type { OpenRouterAdapterOptions } from '@/integrations/reasoning/openrouter'; + +/** + * Adapter for DeepSeek models. + */ +export { DeepSeekAdapter } from '@/integrations/reasoning/deepseek'; +export type { DeepSeekAdapterOptions } from '@/integrations/reasoning/deepseek'; + +/** + * Adapter for running local LLMs through the Ollama service. + */ +export { OllamaAdapter } from '@/integrations/reasoning/ollama'; +export type { OllamaAdapterOptions } from '@/integrations/reasoning/ollama'; + +// --- Built-in Tools --- + +/** + * A basic tool that allows the agent to evaluate mathematical expressions. + */ +export { CalculatorTool } from '@/tools/CalculatorTool'; + +// --- 4. Advanced Systems & Managers --- +// For developers who need to directly interact with or extend ART's internal systems. + +// --- UI & Sockets --- +/** + * Provides a real-time connection to an agent's conversation history. + * When to use: For building custom UI components that display the back-and-forth + * interaction between a user and the agent. + */ +export { ConversationSocket } from '@/systems/ui/conversation-socket'; + +/** + * Provides a real-time stream of agent observations (e.g., tool calls, state changes). + * When to use: For building developer tools, debug panels, or UIs that visualize + * the agent's internal thought process. + */ +export { ObservationSocket } from '@/systems/ui/observation-socket'; +export type { StreamEventTypeFilter } from '@/systems/ui/llm-stream-socket'; +/** + * Provides a real-time stream of raw token output from the LLM as it's generated. + * When to use: For building UIs with a typewriter effect and fine-grained stream control. + */ +export { LLMStreamSocket } from '@/systems/ui/llm-stream-socket'; +/** + * Provides real-time updates for A2A task lifecycle events. + * When to use: For dashboards/monitors tracking delegated task progress. + */ +export { A2ATaskSocket } from '@/systems/ui/a2a-task-socket'; +/** + * Facade providing access to all UI sockets. + */ +export { UISystem } from '@/systems/ui/ui-system'; + +// --- Authentication --- +/** + * Manages authentication strategies and token lifecycle for external services. + * When to use: When your tools or providers require secure authentication (e.g., OAuth2). + * You can register different strategies with this manager. + */ +export { AuthManager } from '@/systems/auth/AuthManager'; + +/** + * An implementation of the PKCE (Proof Key for Code Exchange) OAuth2 flow. + * When to use: As a strategy in the `AuthManager` for services that support + * the PKCE flow, common in public clients and SPAs. + */ +export { PKCEOAuthStrategy } from '@/auth/PKCEOAuthStrategy'; +export type { PKCEOAuthConfig } from '@/auth/PKCEOAuthStrategy'; +/** + * Simple API key authentication strategy and generic OAuth strategy variants. + */ +export { ApiKeyStrategy } from '@/auth/ApiKeyStrategy'; +export { GenericOAuthStrategy } from '@/auth/GenericOAuthStrategy'; +export type { OAuthConfig } from '@/auth/GenericOAuthStrategy'; +export { ZyntopiaOAuthStrategy } from '@/auth/ZyntopiaOAuthStrategy'; +export type { ZyntopiaOAuthConfig } from '@/auth/ZyntopiaOAuthStrategy'; + +// --- MCP (Model Context Protocol) --- +/** + * The core manager for handling connections to MCP servers. + * When to use: When integrating ART with an MCP server to dynamically load tools and resources. + */ +export { McpManager } from '@/systems/mcp'; +export type { McpManagerConfig } from '@/systems/mcp/types'; + +/** + * A special tool that acts as a proxy for all tools provided by an MCP server. + * When to use: This is typically registered automatically when MCP is configured, + * but can be used manually for advanced MCP integrations. + */ +export { McpProxyTool } from '@/systems/mcp'; + +/** + * Client controller for making direct requests to an MCP server. + * When to use: If you need to interact with an MCP server's resources outside + * of the standard agent tool-use loop. + */ +export { McpClientController } from '@/systems/mcp'; export type { - ProviderManagerConfig, - AvailableProviderEntry, - RuntimeProviderConfig, - ManagedAdapterAccessor, - IProviderManager -} from './types/providers'; - -// --- Utility Functions & Classes --- -/** Basic logging utility with configurable levels. */ -export { Logger, LogLevel } from './utils/logger'; -/** Function to generate unique identifiers (UUID v4). */ -export { generateUUID } from './utils/uuid'; + McpServerConfig, + McpToolDefinition, + McpResource, + McpResourceTemplate, + McpServerStatus, +} from '@/systems/mcp/types'; + +// --- A2A (Agent-to-Agent Communication) --- +/** + * Service for discovering other agents available on an A2A network. + * When to use: When building collaborative agent systems where one agent + * needs to find and delegate tasks to another. + */ +export { AgentDiscoveryService } from '@/systems/a2a/AgentDiscoveryService'; +export type { AgentDiscoveryConfig } from '@/systems/a2a/AgentDiscoveryService'; + +/** + * Service for delegating tasks to other agents and monitoring their status. + * When to use: After discovering an agent, use this service to assign it a task + * and receive updates on its progress. + */ +export { TaskDelegationService } from '@/systems/a2a/TaskDelegationService'; +export type { TaskDelegationConfig, TaskStatusResponse } from '@/systems/a2a/TaskDelegationService'; +export type { A2ATaskEvent, A2ATaskFilter } from '@/systems/ui/a2a-task-socket'; + + +// --- 5. Utilities --- + +// --- Managers & Registries (advanced) --- +/** + * State manager for thread config/state with explicit/implicit save strategies. + */ +export { StateManager } from '@/systems/context/managers/StateManager'; +/** + * In-memory tool registry for registering and querying tool executors. + */ +export { ToolRegistry } from '@/systems/tool/ToolRegistry'; +/** + * Provider manager implementation controlling adapter lifecycles and concurrency. + */ +export { ProviderManagerImpl } from '@/systems/reasoning/ProviderManagerImpl'; + +/** + * A simple logging utility with configurable levels. + * When to use: For adding consistent logging throughout your custom components. + * An instance is available on `ArtInstance.logger`. + */ +export { Logger, LogLevel } from '@/utils/logger'; +export type { LoggerConfig } from '@/utils/logger'; + +/** + * A function to generate RFC4122 v4 compliant UUIDs. + * When to use: For creating unique identifiers for threads, messages, or other entities. + */ +export { generateUUID } from '@/utils/uuid'; // --- Framework Version --- -/** The current version of the ART Framework package. */ -export const VERSION = '0.2.8'; \ No newline at end of file +/** + * The current version of the ART Framework package. + */ +export const VERSION = '0.3.7'; \ No newline at end of file diff --git a/src/adapters/reasoning/anthropic.ts b/src/integrations/reasoning/anthropic.ts old mode 100644 new mode 100755 similarity index 93% rename from src/adapters/reasoning/anthropic.ts rename to src/integrations/reasoning/anthropic.ts index f13121a..afac079 --- a/src/adapters/reasoning/anthropic.ts +++ b/src/integrations/reasoning/anthropic.ts @@ -2,7 +2,7 @@ import { Anthropic } from '@anthropic-ai/sdk'; // AnthropicStream and CacheControlEphemeral are not directly used, SDK handles stream types. -import { ProviderAdapter, ToolSchema } from '../../core/interfaces'; +import { ProviderAdapter, ToolSchema } from '@/core/interfaces'; import { ArtStandardPrompt, ArtStandardMessage, @@ -10,9 +10,9 @@ import { StreamEvent, LLMMetadata, // Assuming ArtToolCall and ArtToolResult types exist or are part of ArtStandardMessage -} from '../../types'; -import { Logger } from '../../utils/logger'; -import { ARTError, ErrorCode } from '../../errors'; +} from '@/types'; +import { Logger } from '@/utils/logger'; +import { ARTError, ErrorCode } from '@/errors'; // Default model if not specified const ANTHROPIC_DEFAULT_MODEL_ID = 'claude-3-7-sonnet-20250219'; @@ -50,7 +50,8 @@ type AnthropicSDKToolUseBlock = Anthropic.ToolUseBlock; // This is a received bl * * Handles formatting requests, parsing responses, streaming, and tool use. * - * @implements {ProviderAdapter} + * @see {@link ProviderAdapter} for the interface definition. + * @see {@link AnthropicAdapterOptions} for configuration options. */ export class AnthropicAdapter implements ProviderAdapter { readonly providerName = 'anthropic'; @@ -390,9 +391,11 @@ export class AnthropicAdapter implements ProviderAdapter { } /** - * Prepares request options. Currently a placeholder for potential future additions - * like Anthropic beta headers for specific models or features (e.g., prompt caching). - * The user's example code shows more advanced beta header logic. + * Prepares request options, adding Anthropic beta headers if applicable for features like prompt caching. + * This allows opting into experimental features on a per-request basis. + * @private + * @param {string} modelId - The model ID being used for the request, to determine which beta features may apply. + * @returns {Anthropic.RequestOptions} The request options object, potentially with custom headers. */ private getRequestOptions(modelId: string): Anthropic.RequestOptions { const betas: string[] = []; @@ -419,11 +422,12 @@ export class AnthropicAdapter implements ProviderAdapter { /** * Translates the provider-agnostic `ArtStandardPrompt` into the Anthropic SDK Messages format. + * It handles system prompts, message merging for consecutive roles, and validates message structure. * * @private * @param {ArtStandardPrompt} artPrompt - The input `ArtStandardPrompt` array. - * @returns {{ systemPrompt?: string; messages: AnthropicSDKMessageParam[] }} - * @throws {ARTError} If translation encounters an issue. + * @returns {{ systemPrompt?: string; messages: Anthropic.Messages.MessageParam[] }} An object containing the extracted system prompt and the array of Anthropic-formatted messages. + * @throws {ARTError} If translation encounters an issue, such as multiple system messages or invalid message roles. */ private translateToAnthropicSdk(artPrompt: ArtStandardPrompt): { systemPrompt?: string; messages: Anthropic.Messages.MessageParam[] } { let systemPrompt: string | undefined; @@ -492,7 +496,14 @@ export class AnthropicAdapter implements ProviderAdapter { } /** - * Maps a single ArtStandardMessage to Anthropic SDK's content format (string or AnthropicSDKContentBlockParam[]). + * Maps a single `ArtStandardMessage` to Anthropic SDK's content format. + * This can be a simple string or an array of `ContentBlockParam` for complex content + * like tool calls and tool results. + * + * @private + * @param {ArtStandardMessage} artMsg - The ART standard message to map. + * @returns {string | AnthropicSDKContentBlockParam[]} The translated content for the Anthropic API. + * @throws {ARTError} If tool call arguments are not valid JSON or if a tool result is missing its ID. */ private mapArtMessageToAnthropicContent(artMsg: ArtStandardMessage): string | AnthropicSDKContentBlockParam[] { const blocks: AnthropicSDKContentBlockParam[] = []; @@ -570,7 +581,11 @@ export class AnthropicAdapter implements ProviderAdapter { } /** - * Translates ART ToolSchema array to Anthropic's tool format. + * Translates an array of `ToolSchema` from the ART framework format to Anthropic's specific tool format. + * @private + * @param {ToolSchema[]} artTools - An array of ART tool schemas. + * @returns {AnthropicSDKTool[]} An array of tools formatted for the Anthropic API. + * @throws {ARTError} If a tool's `inputSchema` is invalid. */ private translateArtToolsToAnthropic(artTools: ToolSchema[]): AnthropicSDKTool[] { return artTools.map(artTool => { diff --git a/src/adapters/reasoning/deepseek.ts b/src/integrations/reasoning/deepseek.ts old mode 100644 new mode 100755 similarity index 94% rename from src/adapters/reasoning/deepseek.ts rename to src/integrations/reasoning/deepseek.ts index ccfa5c2..0c5edc9 --- a/src/adapters/reasoning/deepseek.ts +++ b/src/integrations/reasoning/deepseek.ts @@ -1,19 +1,18 @@ // src/adapters/reasoning/deepseek.ts -import { ProviderAdapter } from '../../core/interfaces'; +import { ProviderAdapter } from '@/core/interfaces'; import { ArtStandardPrompt, // Use the new standard type ArtStandardMessage, // Keep for translation function type hint CallOptions, StreamEvent, LLMMetadata, -} from '../../types'; -import { Logger } from '../../utils/logger'; -import { ARTError, ErrorCode } from '../../errors'; // Import ARTError and ErrorCode +} from '@/types'; +import { Logger } from '@/utils/logger'; +import { ARTError, ErrorCode } from '@/errors'; // Import ARTError and ErrorCode // TODO: Implement streaming support for DeepSeek. -// TODO: Consider if a dedicated SDK or more specific types are needed, or if OpenAI compatibility is sufficient. +// TODO: Implement support for 'tools' and 'tool_choice'. -// Define expected options for the DeepSeek adapter constructor /** * Configuration options required for the `DeepSeekAdapter`. */ @@ -76,13 +75,11 @@ interface OpenAIChatCompletionResponse { } /** - * Implements the `ProviderAdapter` interface for interacting with the DeepSeek API, - * which uses an OpenAI-compatible Chat Completions endpoint. + * This adapter provides a consistent interface for ART agents to use DeepSeek models, + * handling the conversion of standard ART prompts to the DeepSeek API format and + * parsing the responses into the ART `StreamEvent` format. * - * Handles formatting requests and parsing responses for DeepSeek models. - * Note: Streaming is **not yet implemented** for this adapter. Calls requesting streaming will yield an error and end. - * - * @implements {ProviderAdapter} + * @see {@link ProviderAdapter} for the interface it implements. */ export class DeepSeekAdapter implements ProviderAdapter { readonly providerName = 'deepseek'; @@ -92,8 +89,9 @@ export class DeepSeekAdapter implements ProviderAdapter { /** * Creates an instance of the DeepSeekAdapter. - * @param options - Configuration options including the API key and optional model/baseURL overrides. + * @param {DeepSeekAdapterOptions} options - Configuration options including the API key and optional model/baseURL overrides. * @throws {Error} If the API key is missing. + * @see https://platform.deepseek.com/api-docs */ constructor(options: DeepSeekAdapterOptions) { if (!options.apiKey) { @@ -114,6 +112,7 @@ export class DeepSeekAdapter implements ProviderAdapter { * @param {ArtStandardPrompt} prompt - The standardized prompt messages. * @param {CallOptions} options - Call options, including `threadId`, `traceId`, `stream`, and any OpenAI-compatible generation parameters. * @returns {Promise>} A promise resolving to an AsyncIterable of StreamEvent objects. If streaming is requested, it yields an error event and ends. + * @see https://platform.deepseek.com/api-docs/api/create-chat-completion/index.html */ async call(prompt: ArtStandardPrompt, options: CallOptions): Promise> { const { threadId, traceId = `deepseek-trace-${Date.now()}`, sessionId, stream, callContext, model: modelOverride } = options; diff --git a/src/adapters/reasoning/gemini.ts b/src/integrations/reasoning/gemini.ts old mode 100644 new mode 100755 similarity index 75% rename from src/adapters/reasoning/gemini.ts rename to src/integrations/reasoning/gemini.ts index 822123b..3520c4a --- a/src/adapters/reasoning/gemini.ts +++ b/src/integrations/reasoning/gemini.ts @@ -1,7 +1,7 @@ // src/adapters/reasoning/gemini.ts // Use correct import based on documentation for @google/genai import { GoogleGenAI, Content, Part, GenerationConfig, GenerateContentResponse } from "@google/genai"; // Import SDK components -import { ProviderAdapter } from '../../core/interfaces'; +import { ProviderAdapter } from '@/core/interfaces'; import { ArtStandardPrompt, // Use the new standard type // ArtStandardMessage, // Removed unused import @@ -10,9 +10,9 @@ import { StreamEvent, LLMMetadata, // Removed ConversationMessage, MessageRole as they are replaced by ArtStandard types for input -} from '../../types'; -import { Logger } from '../../utils/logger'; -import { ARTError, ErrorCode } from '../../errors'; // Import ARTError and ErrorCode +} from '@/types'; +import { Logger } from '@/utils/logger'; +import { ARTError, ErrorCode } from '@/errors'; // Import ARTError and ErrorCode // Define expected options for the Gemini adapter constructor /** @@ -40,6 +40,7 @@ export class GeminiAdapter implements ProviderAdapter { * Creates an instance of GeminiAdapter. * @param {GeminiAdapterOptions} options - Configuration options for the adapter. * @throws {Error} If `apiKey` is missing in the options. + * @see https://ai.google.dev/api/rest */ constructor(options: GeminiAdapterOptions) { if (!options.apiKey) { @@ -63,10 +64,24 @@ export class GeminiAdapter implements ProviderAdapter { * * Handles both streaming and non-streaming requests based on `options.stream`. * + * Thinking tokens (Gemini): + * - On supported Gemini models (e.g., `gemini-2.5-*`), you can enable thought output via `config.thinkingConfig`. + * - This adapter reads provider-specific flags from the call options: + * - `options.gemini.thinking.includeThoughts: boolean` — when `true`, requests thought (reasoning) output. + * - `options.gemini.thinking.thinkingBudget?: number` — optional token budget for thinking. + * - When enabled and supported, the adapter will attempt to differentiate thought vs response parts and set + * `StreamEvent.tokenType` accordingly: + * - For planning calls (`callContext === 'AGENT_THOUGHT'`): `AGENT_THOUGHT_LLM_THINKING` or `AGENT_THOUGHT_LLM_RESPONSE`. + * - For synthesis calls (`callContext === 'FINAL_SYNTHESIS'`): `FINAL_SYNTHESIS_LLM_THINKING` or `FINAL_SYNTHESIS_LLM_RESPONSE`. + * - `LLMMetadata.thinkingTokens` will be populated if the provider reports separate thinking token usage. + * - If the SDK/model does not expose thought parts, the adapter falls back to labeling tokens as `...LLM_RESPONSE`. + * * @param {ArtStandardPrompt} prompt - The standardized prompt messages. * @param {CallOptions} options - Options for the LLM call, including streaming preference, model override, and execution context. * @returns {Promise>} An async iterable that yields `StreamEvent` objects. * - `TOKEN`: Contains a chunk of the response text. `tokenType` indicates if it's part of agent thought or final synthesis. + * When Gemini thinking is enabled and available, `tokenType` may be one of the `...LLM_THINKING` or + * `...LLM_RESPONSE` variants to separate thought vs response tokens. * - `METADATA`: Contains information like stop reason, token counts, and timing, yielded once at the end. * - `ERROR`: Contains any error encountered during translation, SDK call, or response processing. * - `END`: Signals the completion of the stream. @@ -74,6 +89,24 @@ export class GeminiAdapter implements ProviderAdapter { * @see {CallOptions} * @see {StreamEvent} * @see {LLMMetadata} + * @see https://ai.google.dev/api/rest/v1beta/models/generateContent + * + * @example + * // Enable Gemini thinking (if supported by the selected model) + * const stream = await geminiAdapter.call(prompt, { + * threadId, + * stream: true, + * callContext: 'FINAL_SYNTHESIS', + * providerConfig, // your RuntimeProviderConfig + * gemini: { + * thinking: { includeThoughts: true, thinkingBudget: 8096 } + * } + * }); + * for await (const evt of stream) { + * if (evt.type === 'TOKEN') { + * // evt.tokenType may be FINAL_SYNTHESIS_LLM_THINKING or FINAL_SYNTHESIS_LLM_RESPONSE + * } + * } */ async call(prompt: ArtStandardPrompt, options: CallOptions): Promise> { const { threadId, traceId = `gemini-trace-${Date.now()}`, sessionId, stream, callContext, model: modelOverride } = options; @@ -106,6 +139,20 @@ export class GeminiAdapter implements ProviderAdapter { generationConfig[key as keyof GenerationConfig] === undefined && delete generationConfig[key as keyof GenerationConfig] ); + // Build optional thinking configuration from CallOptions (feature flag) + // Expecting shape: options.gemini?.thinking?.{ includeThoughts?: boolean; thinkingBudget?: number } + const includeThoughts: boolean = !!(options as any)?.gemini?.thinking?.includeThoughts; + const thinkingBudget: number | undefined = (options as any)?.gemini?.thinking?.thinkingBudget; + // Merge into a requestConfig that is leniently typed to allow SDK preview fields + const requestConfig: any = includeThoughts + ? { + ...generationConfig, + thinkingConfig: { + includeThoughts: true, + ...(thinkingBudget !== undefined ? { thinkingBudget } : {}), + }, + } + : { ...generationConfig }; // --- End Format Payload --- Logger.debug(`Calling Gemini SDK with model ${modelToUse}, stream: ${!!stream}`, { threadId, traceId }); @@ -129,7 +176,7 @@ export class GeminiAdapter implements ProviderAdapter { const streamResult = await genAIInstance.models.generateContentStream({ // Use captured instance model: modelToUse, // Pass model name here contents, - config: generationConfig, // Pass config object directly (key is 'config') + config: requestConfig, // Pass merged config including optional thinkingConfig }); // Process the stream by iterating directly over streamResult (based on docs) @@ -138,11 +185,29 @@ export class GeminiAdapter implements ProviderAdapter { if (!timeToFirstTokenMs) { timeToFirstTokenMs = Date.now() - startTime; } - const textPart = chunk.text; // Access as property (based on docs) - if (textPart) { - // Determine tokenType based on callContext (Gemini SDK doesn't expose thinking markers directly) - const tokenType = callContext === 'AGENT_THOUGHT' ? 'AGENT_THOUGHT_LLM_RESPONSE' : 'FINAL_SYNTHESIS_LLM_RESPONSE'; - yield { type: 'TOKEN', data: textPart, threadId, traceId, sessionId, tokenType }; + // Prefer structured parts if available to differentiate thinking vs response + const candidate = (chunk as any)?.candidates?.[0]; + const parts = candidate?.content?.parts; + if (Array.isArray(parts) && parts.length > 0) { + for (const part of parts) { + const partText: string | undefined = (part as any)?.text; + if (!partText) continue; + const isThought: boolean = !!( + (part as any)?.thought || + (part as any)?.metadata?.thought || + (part as any)?.inlineMetadata?.thought + ); + const tokenType = callContext === 'AGENT_THOUGHT' + ? (isThought ? 'AGENT_THOUGHT_LLM_THINKING' : 'AGENT_THOUGHT_LLM_RESPONSE') + : (isThought ? 'FINAL_SYNTHESIS_LLM_THINKING' : 'FINAL_SYNTHESIS_LLM_RESPONSE'); + yield { type: 'TOKEN', data: partText, threadId, traceId, sessionId, tokenType }; + } + } else { + const textPart = (chunk as any).text; // Access as property (fallback) + if (textPart) { + const tokenType = callContext === 'AGENT_THOUGHT' ? 'AGENT_THOUGHT_LLM_RESPONSE' : 'FINAL_SYNTHESIS_LLM_RESPONSE'; + yield { type: 'TOKEN', data: textPart, threadId, traceId, sessionId, tokenType }; + } } // Log potential usage metadata if available in chunks (less common) // Capture usage metadata if present in chunks @@ -179,6 +244,7 @@ export class GeminiAdapter implements ProviderAdapter { stopReason: streamFinishReason, // Use finishReason from last chunk inputTokens: finalUsage?.promptTokenCount, outputTokens: finalUsage?.candidatesTokenCount, // Or totalTokenCount? Check SDK details + thinkingTokens: finalUsage?.thinkingTokenCount ?? finalUsage?.thoughtTokens, timeToFirstTokenMs: timeToFirstTokenMs, totalGenerationTimeMs: totalGenerationTimeMs, providerRawUsage: finalUsage, // Use usage from last chunk @@ -193,7 +259,7 @@ export class GeminiAdapter implements ProviderAdapter { const result: GenerateContentResponse = await genAIInstance.models.generateContent({ // Use captured instance model: modelToUse, // Pass model name here contents, - config: generationConfig, // Use 'config' key as per documentation + config: requestConfig, // Use merged config including optional thinkingConfig }); // Removed incorrect line: const response = result.response; const firstCandidate = result.candidates?.[0]; // Access directly from result @@ -203,8 +269,23 @@ export class GeminiAdapter implements ProviderAdapter { const totalGenerationTimeMs = Date.now() - startTime; - // Check if candidate exists AND responseText is truthy (not undefined, null, or empty string) - if (!firstCandidate || !responseText) { + // If structured parts are present, prefer splitting into thought vs response tokens + const nonStreamParts = (firstCandidate as any)?.content?.parts; + if (Array.isArray(nonStreamParts) && nonStreamParts.length > 0) { + for (const part of nonStreamParts) { + const partText: string | undefined = (part as any)?.text; + if (!partText) continue; + const isThought: boolean = !!( + (part as any)?.thought || + (part as any)?.metadata?.thought || + (part as any)?.inlineMetadata?.thought + ); + const tokenType = callContext === 'AGENT_THOUGHT' + ? (isThought ? 'AGENT_THOUGHT_LLM_THINKING' : 'AGENT_THOUGHT_LLM_RESPONSE') + : (isThought ? 'FINAL_SYNTHESIS_LLM_THINKING' : 'FINAL_SYNTHESIS_LLM_RESPONSE'); + yield { type: 'TOKEN', data: partText.trim(), threadId, traceId, sessionId, tokenType }; + } + } else if (!firstCandidate || !responseText) { if (result.promptFeedback?.blockReason) { // Access directly from result Logger.error('Gemini SDK call blocked.', { feedback: result.promptFeedback, threadId, traceId }); yield { type: 'ERROR', data: new Error(`Gemini API call blocked: ${result.promptFeedback.blockReason}`), threadId, traceId, sessionId }; @@ -213,20 +294,18 @@ export class GeminiAdapter implements ProviderAdapter { Logger.error('Invalid response structure from Gemini SDK: No text content found', { responseData: result, threadId, traceId }); // Log the whole result yield { type: 'ERROR', data: new Error('Invalid response structure from Gemini SDK: No text content found.'), threadId, traceId, sessionId }; return; + } else { + // Yield TOKEN (fallback single text) + const tokenType = callContext === 'AGENT_THOUGHT' ? 'AGENT_THOUGHT_LLM_RESPONSE' : 'LLM_RESPONSE'; + yield { type: 'TOKEN', data: responseText.trim(), threadId, traceId, sessionId, tokenType }; } - // Yield TOKEN - // Determine tokenType based on callContext for non-streaming - // For planning (AGENT_THOUGHT), yield the raw response text for the OutputParser - // For synthesis, yield the text as the final response - const tokenType = callContext === 'AGENT_THOUGHT' ? 'AGENT_THOUGHT_LLM_RESPONSE' : 'LLM_RESPONSE'; - yield { type: 'TOKEN', data: responseText.trim(), threadId, traceId, sessionId, tokenType }; - // Yield METADATA const metadata: LLMMetadata = { stopReason: finishReason, inputTokens: usageMetadata?.promptTokenCount, outputTokens: usageMetadata?.candidatesTokenCount, + thinkingTokens: (usageMetadata as any)?.thinkingTokenCount ?? (usageMetadata as any)?.thoughtTokens, totalGenerationTimeMs: totalGenerationTimeMs, providerRawUsage: usageMetadata, traceId: traceId, diff --git a/src/adapters/reasoning/ollama.ts b/src/integrations/reasoning/ollama.ts old mode 100644 new mode 100755 similarity index 93% rename from src/adapters/reasoning/ollama.ts rename to src/integrations/reasoning/ollama.ts index 7daf1a5..67dc4e4 --- a/src/adapters/reasoning/ollama.ts +++ b/src/integrations/reasoning/ollama.ts @@ -1,7 +1,7 @@ // src/adapters/reasoning/ollama.ts import OpenAI from "openai"; -import { ProviderAdapter } from '../../core/interfaces'; +import { ProviderAdapter } from '@/core/interfaces'; import { ArtStandardPrompt, ArtStandardMessage, @@ -9,9 +9,9 @@ import { StreamEvent, LLMMetadata, ToolSchema, // Added for tool support -} from '../../types'; -import { Logger } from '../../utils/logger'; -import { ARTError, ErrorCode } from '../../errors'; +} from '@/types'; +import { Logger } from '@/utils/logger'; +import { ARTError, ErrorCode } from '@/errors'; // XmlMatcher removed, parsing of embedded XML is responsibility of OutputParser // Define expected options for the Ollama adapter constructor @@ -62,7 +62,8 @@ interface OpenAIToolCall { * * Handles formatting requests, parsing responses, streaming, and tool use. * - * @implements {ProviderAdapter} + * @see {@link ProviderAdapter} for the interface definition. + * @see {@link OllamaAdapterOptions} for configuration options. */ export class OllamaAdapter implements ProviderAdapter { readonly providerName = 'ollama'; @@ -307,7 +308,11 @@ export class OllamaAdapter implements ProviderAdapter { /** * Translates the provider-agnostic `ArtStandardPrompt` into the OpenAI API's `OpenAIMessage[]` format. - * This is a common utility function that can be shared or adapted from other OpenAI-compatible adapters. + * This method can handle model-specific formatting, such as merging consecutive messages for certain models. + * @private + * @param {ArtStandardPrompt} artPrompt - The input `ArtStandardPrompt` array. + * @param {string} [modelIdForTransform] - The model ID, used to determine if special formatting is needed. + * @returns {OpenAIMessage[]} The `OpenAIMessage[]` array formatted for the OpenAI API. */ private translateToOpenAI(artPrompt: ArtStandardPrompt, modelIdForTransform?: string): OpenAIMessage[] { const messagesToProcess = [...artPrompt]; @@ -376,6 +381,13 @@ export class OllamaAdapter implements ProviderAdapter { // Helper function to map a single ArtStandardMessage to an OpenAIMessage // This is called by translateToOpenAI + /** + * Maps a single `ArtStandardMessage` to an `OpenAIMessage`. + * @private + * @param {ArtStandardMessage} message - The message to map. + * @returns {OpenAIMessage} The mapped message. + * @throws {ARTError} If an unsupported or invalid message role is encountered. + */ private mapArtMessageToOpenAIMessage(message: ArtStandardMessage): OpenAIMessage { switch (message.role) { case 'system': @@ -437,7 +449,11 @@ export class OllamaAdapter implements ProviderAdapter { } /** - * Translates ART ToolSchema array to OpenAI's tool format. + * Translates an array of `ToolSchema` from the ART framework format to OpenAI's specific tool format. + * @private + * @param {ToolSchema[]} artTools - An array of ART tool schemas. + * @returns {OpenAI.Chat.Completions.ChatCompletionTool[]} An array of tools formatted for the OpenAI API. + * @throws {ARTError} If a tool's schema is invalid. */ private translateArtToolsToOpenAI(artTools: ToolSchema[]): OpenAI.Chat.Completions.ChatCompletionTool[] { return artTools.map(artTool => { @@ -458,11 +474,9 @@ export class OllamaAdapter implements ProviderAdapter { } /** - * Optional method for graceful shutdown. - * For Ollama, which is typically a separate local server, this adapter - * doesn't manage persistent connections that need explicit closing. - * The OpenAI client used internally might have its own cleanup, but - * it's generally handled by garbage collection. + * Optional method for graceful shutdown. For Ollama, which is typically a separate + * local server, this adapter doesn't manage persistent connections that need explicit closing. + * @returns {Promise} A promise that resolves when the shutdown is complete. */ async shutdown(): Promise { Logger.debug(`OllamaAdapter shutdown called. No specific resources to release for model ${this.defaultModel || 'not set'}.`); diff --git a/src/adapters/reasoning/openai.ts b/src/integrations/reasoning/openai.ts old mode 100644 new mode 100755 similarity index 97% rename from src/adapters/reasoning/openai.ts rename to src/integrations/reasoning/openai.ts index 20fdd05..1521891 --- a/src/adapters/reasoning/openai.ts +++ b/src/integrations/reasoning/openai.ts @@ -1,5 +1,5 @@ // src/adapters/reasoning/openai.ts -import { ProviderAdapter } from '../../core/interfaces'; +import { ProviderAdapter } from '@/core/interfaces'; import { ArtStandardPrompt, // Use the new standard type ArtStandardMessage, // Keep for translation function type hint @@ -7,13 +7,12 @@ import { CallOptions, StreamEvent, LLMMetadata, -} from '../../types'; -import { Logger } from '../../utils/logger'; -import { ARTError, ErrorCode } from '../../errors'; // Import ARTError and ErrorCode +} from '@/types'; +import { Logger } from '@/utils/logger'; +import { ARTError, ErrorCode } from '@/errors'; // Import ARTError and ErrorCode // TODO: Upgrade to use the official 'openai' SDK package instead of raw fetch calls. -// Define expected options for the OpenAI adapter constructor /** * Configuration options required for the `OpenAIAdapter`. */ @@ -85,7 +84,7 @@ interface OpenAIChatCompletionResponse { * Handles formatting requests and parsing responses for OpenAI. * Uses raw `fetch` for now. * - * @implements {ProviderAdapter} + * @see {@link ProviderAdapter} for the interface definition. */ // TODO: Refactor to use the official OpenAI SDK for better error handling, types, and features. export class OpenAIAdapter implements ProviderAdapter { @@ -96,8 +95,9 @@ export class OpenAIAdapter implements ProviderAdapter { /** * Creates an instance of the OpenAIAdapter. - * @param options - Configuration options including the API key and optional model/baseURL overrides. + * @param {OpenAIAdapterOptions} options - Configuration options including the API key and optional model/baseURL overrides. * @throws {Error} If the API key is missing. + * @see https://platform.openai.com/docs/api-reference */ constructor(options: OpenAIAdapterOptions) { if (!options.apiKey) { @@ -116,6 +116,7 @@ export class OpenAIAdapter implements ProviderAdapter { * @param {ArtStandardPrompt} prompt - The standardized prompt messages. * @param {CallOptions} options - Call options, including `threadId`, `traceId`, `stream` preference, and any OpenAI-specific parameters (like `temperature`, `max_tokens`) passed through. * @returns {Promise>} A promise resolving to an AsyncIterable of StreamEvent objects. + * @see https://platform.openai.com/docs/api-reference/chat/create */ async call(prompt: ArtStandardPrompt, options: CallOptions): Promise> { const { threadId, traceId = `openai-trace-${Date.now()}`, sessionId, stream, callContext, model: modelOverride } = options; @@ -266,7 +267,7 @@ export class OpenAIAdapter implements ProviderAdapter { const aggregatedUsage: any = undefined; // Store usage if provided in stream // TODO: Add proper aggregation for streamed tool calls if needed let aggregatedToolCalls: any[] | undefined = undefined; - const reader = stream.pipeThrough(new TextDecoderStream()).getReader(); + const reader = stream.pipeThrough(new TextDecoderStream() as any).getReader(); let buffer = ''; let done = false; diff --git a/src/adapters/reasoning/openrouter.ts b/src/integrations/reasoning/openrouter.ts old mode 100644 new mode 100755 similarity index 93% rename from src/adapters/reasoning/openrouter.ts rename to src/integrations/reasoning/openrouter.ts index 36171dc..834331a --- a/src/adapters/reasoning/openrouter.ts +++ b/src/integrations/reasoning/openrouter.ts @@ -1,19 +1,18 @@ // src/adapters/reasoning/openrouter.ts -import { ProviderAdapter } from '../../core/interfaces'; +import { ProviderAdapter } from '@/core/interfaces'; import { ArtStandardPrompt, // Use the new standard type ArtStandardMessage, // Keep for translation function type hint CallOptions, StreamEvent, LLMMetadata, -} from '../../types'; -import { Logger } from '../../utils/logger'; -import { ARTError, ErrorCode } from '../../errors'; // Import ARTError and ErrorCode +} from '@/types'; +import { Logger } from '@/utils/logger'; +import { ARTError, ErrorCode } from '@/errors'; // Import ARTError and ErrorCode // TODO: Implement streaming support for OpenRouter. -// TODO: Consider if a dedicated SDK or more specific types are needed, or if OpenAI compatibility is sufficient. +// TODO: Implement support for 'tools' and 'tool_choice'. -// Define expected options for the OpenRouter adapter constructor /** * Configuration options required for the `OpenRouterAdapter`. */ @@ -81,14 +80,11 @@ interface OpenAIChatCompletionResponse { } /** - * Implements the `ProviderAdapter` interface for interacting with the OpenRouter API, - * which provides access to various LLMs through an OpenAI-compatible interface. + * This adapter provides a unified interface for various LLM providers through OpenRouter, + * handling prompt conversion and response parsing into the ART `StreamEvent` format. * - * Handles formatting requests and parsing responses for OpenRouter's chat completions endpoint. - * Handles formatting requests and parsing responses for OpenRouter's chat completions endpoint. - * Note: Streaming is **not yet implemented** for this adapter. Calls requesting streaming will yield an error and end. - * - * @implements {ProviderAdapter} + * @see {@link ProviderAdapter} for the interface it implements. + * @see {@link OpenRouterAdapterOptions} for configuration options. */ export class OpenRouterAdapter implements ProviderAdapter { readonly providerName = 'openrouter'; @@ -100,8 +96,9 @@ export class OpenRouterAdapter implements ProviderAdapter { /** * Creates an instance of the OpenRouterAdapter. - * @param options - Configuration options including the API key, the specific OpenRouter model identifier, and optional headers/baseURL. + * @param {OpenRouterAdapterOptions} options - Configuration options including the API key, the specific OpenRouter model identifier, and optional headers/baseURL. * @throws {Error} If the API key or model identifier is missing. + * @see https://openrouter.ai/docs */ constructor(options: OpenRouterAdapterOptions) { if (!options.apiKey) { @@ -127,6 +124,7 @@ export class OpenRouterAdapter implements ProviderAdapter { * @param {ArtStandardPrompt} prompt - The standardized prompt messages. * @param {CallOptions} options - Call options, including `threadId`, `traceId`, `stream`, and any OpenAI-compatible generation parameters. * @returns {Promise>} A promise resolving to an AsyncIterable of StreamEvent objects. If streaming is requested, it yields an error event and ends. + * @see https://openrouter.ai/docs#api-reference-chat-completions */ async call(prompt: ArtStandardPrompt, options: CallOptions): Promise> { const { threadId, traceId = `openrouter-trace-${Date.now()}`, sessionId, stream, callContext, model: modelOverride } = options; diff --git a/src/adapters/storage/inMemory.ts b/src/integrations/storage/inMemory.ts old mode 100644 new mode 100755 similarity index 91% rename from src/adapters/storage/inMemory.ts rename to src/integrations/storage/inMemory.ts index aead284..c0dd707 --- a/src/adapters/storage/inMemory.ts +++ b/src/integrations/storage/inMemory.ts @@ -1,5 +1,5 @@ -import { StorageAdapter } from '../../core/interfaces'; -import { FilterOptions } from '../../types'; +import { StorageAdapter } from '@/core/interfaces'; +import { FilterOptions } from '@/types'; /** * An in-memory implementation of the `StorageAdapter` interface. @@ -11,13 +11,25 @@ import { FilterOptions } from '../../types'; * - Simple demos or examples where persistence isn't needed. * - Ephemeral agents that don't require long-term memory. * - * @implements {StorageAdapter} + * It provides a simple key-value store for various data types used within the + * ART framework, such as conversation history, agent state, and observations. + * + * @see {@link StorageAdapter} for the interface definition. */ export class InMemoryStorageAdapter implements StorageAdapter { private storage: Map> = new Map(); /** - * Initializes the adapter. This is a no-op for the in-memory adapter. + * Creates an instance of InMemoryStorageAdapter. + * @see StorageAdapter + */ + constructor() { + // No-op + } + + /** + * Initializes the adapter. This is a no-op for the in-memory adapter + * and is provided for interface compatibility. * @param _config - Optional configuration (ignored by this adapter). * @returns A promise that resolves immediately. */ diff --git a/src/adapters/storage/indexedDB.ts b/src/integrations/storage/indexedDB.ts old mode 100644 new mode 100755 similarity index 96% rename from src/adapters/storage/indexedDB.ts rename to src/integrations/storage/indexedDB.ts index ee1c5a5..b0013a5 --- a/src/adapters/storage/indexedDB.ts +++ b/src/integrations/storage/indexedDB.ts @@ -1,6 +1,6 @@ -import { StorageAdapter } from '../../core/interfaces'; -import { FilterOptions } from '../../types'; -import { Logger } from '../../utils/logger'; // Import Logger at top level +import { StorageAdapter } from '@/core/interfaces'; +import { FilterOptions } from '@/types'; +import { Logger } from '@/utils/logger'; // Import Logger at top level // Default configuration const DEFAULT_DB_NAME = 'ART_Framework_DB'; @@ -28,7 +28,8 @@ export interface IndexedDBConfig { * **Important:** The `init()` method *must* be called and awaited before performing * any other database operations (get, set, delete, query). * - * @implements {StorageAdapter} + * @see {@link StorageAdapter} for the interface it implements. + * @see {@link IndexedDBConfig} for configuration options. */ export class IndexedDBStorageAdapter implements StorageAdapter { private db: IDBDatabase | null = null; @@ -40,7 +41,8 @@ export class IndexedDBStorageAdapter implements StorageAdapter { /** * Creates an instance of IndexedDBStorageAdapter. * Note: The database connection is not opened until `init()` is called. - * @param config - Configuration options including database name, version, and required object stores. + * @param {module:integrations/storage/indexedDB.IndexedDBConfig} config - Configuration options including database name, version, and required object stores. + * @see https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API */ constructor(config: IndexedDBConfig) { this.dbName = config.dbName || DEFAULT_DB_NAME; @@ -50,6 +52,7 @@ export class IndexedDBStorageAdapter implements StorageAdapter { 'conversations', // Used by ConversationRepository 'observations', // Used by ObservationRepository 'state', // Used by StateRepository + 'a2a_tasks', // Used by TaskStatusRepository ...(config.objectStores || []) // Add any user-defined stores ]); } @@ -67,8 +70,6 @@ export class IndexedDBStorageAdapter implements StorageAdapter { return this.initPromise; } -// ... (rest of the file remains the same until line 71) - this.initPromise = new Promise((resolve, reject) => { if (!('indexedDB' in window)) { Logger.error("IndexedDBStorageAdapter: IndexedDB not supported in this browser."); // Use Logger @@ -317,6 +318,8 @@ export class IndexedDBStorageAdapter implements StorageAdapter { * @param filterOptions - Options for filtering, sorting, skipping, and limiting results. * @returns A promise resolving to an array of deep copies of the matching items. * @throws {Error} If the database is not initialized, the store doesn't exist, or a database error occurs. + * @remarks TODO: Implement more advanced querying using IndexedDB indexes and cursors. + * This will improve performance for large datasets. */ async query(collection: string, filterOptions: FilterOptions): Promise { await this.init(); // Ensure DB is ready diff --git a/src/integrations/storage/supabase.ts b/src/integrations/storage/supabase.ts new file mode 100755 index 0000000..c014066 --- /dev/null +++ b/src/integrations/storage/supabase.ts @@ -0,0 +1,263 @@ +import { StorageAdapter } from '@/core/interfaces'; +import { FilterOptions } from '@/types'; +import { Logger } from '@/utils/logger'; + +export interface SupabaseConfig { + /** Supabase project URL, e.g., https://xyzcompany.supabase.co */ + url: string; + /** Supabase anon or service key. Prefer service key on server-side only. */ + apiKey: string; + /** Optional schema name (default 'public'). */ + schema?: string; + /** + * Table names to use. These map ART collections to Supabase. + * If you customize collection names in repositories, adjust accordingly. + */ + tables?: { + conversations?: string; + observations?: string; + state?: string; + a2a_tasks?: string; + }; + /** + * Optional: pass a pre-initialized Supabase client (from @supabase/supabase-js) + * Useful in environments where you already manage the client and auth. + */ + client?: any; +} + +/** + * A Supabase-backed StorageAdapter implementation. + * + * Expectations/assumptions: + * - Each collection maps to a table with a primary key column named 'id' (text/uuid). + * - We store JSON columns for flexible data where needed. However, repositories + * store fully shaped rows; this adapter just persists and retrieves whole objects. + * - For query(), we implement basic equality filters per FilterOptions.filter keys, + * plus limit/skip and a single-key sort. + */ +export class SupabaseStorageAdapter implements StorageAdapter { + private client: any | null = null; + private config!: SupabaseConfig; + private schema: string = 'public'; + private tables = { + conversations: 'conversations', + observations: 'observations', + state: 'state', + a2a_tasks: 'a2a_tasks', + }; + + /** + * Creates an instance of SupabaseStorageAdapter. + * @see SupabaseConfig + */ + constructor(config: SupabaseConfig) { + this.configure(config); + } + + /** + * Configures the adapter with the provided Supabase settings. + * @private + * @param {SupabaseConfig} config - The configuration for the adapter. + */ + private configure(config: SupabaseConfig) { + this.config = config; + if (config.schema) this.schema = config.schema; + if (config.tables) { + this.tables = { ...this.tables, ...config.tables }; + } + this.client = config.client ?? null; + } + + /** + * Initializes the Supabase client if it hasn't been provided already. + * @returns {Promise} A promise that resolves when the client is initialized. + */ + async init(): Promise { + if (this.client) return; // Already provided + try { + // Lazy import to avoid bundling if unused + const { createClient } = await import('@supabase/supabase-js'); + this.client = createClient(this.config.url, this.config.apiKey, { + db: { schema: this.schema }, + auth: { persistSession: false }, + }); + Logger.info('SupabaseStorageAdapter: Client initialized.'); + } catch (err: any) { + Logger.error('SupabaseStorageAdapter: Failed to initialize client', err); + throw err; + } + } + + /** + * Maps a collection name to a Supabase table name. + * @private + * @param {string} collection - The name of the collection. + * @returns {string} The name of the Supabase table. + */ + private tableForCollection(collection: string): string { + // Allow direct pass-through for custom collections; otherwise map known ones + switch (collection) { + case 'conversations': + return this.tables.conversations; + case 'observations': + return this.tables.observations; + case 'state': + return this.tables.state; + case 'a2a_tasks': + return this.tables.a2a_tasks; + default: + return collection; // Use collection name as-is for custom use + } + } + + /** + * Retrieves a single item from a collection by its ID. + * @template T + * @param {string} collection - The name of the collection. + * @param {string} id - The ID of the item to retrieve. + * @returns {Promise} A promise that resolves with the item, or null if not found. + */ + async get(collection: string, id: string): Promise { + await this.init(); + const table = this.tableForCollection(collection); + const { data, error } = await this.client + .from(table) + .select('*') + .eq('id', id) + .limit(1) + .maybeSingle(); + if (error) { + Logger.error(`SupabaseStorageAdapter: get error for ${table}/${id}`, error); + throw new Error(error.message); + } + return (data ? { ...data } : null) as T | null; + } + + /** + * Saves (upserts) an item in a collection. + * @template T + * @param {string} collection - The name of the collection. + * @param {string} id - The ID of the item to save. + * @param {T} data - The data to save. + * @returns {Promise} A promise that resolves when the item is saved. + */ + async set(collection: string, id: string, data: T): Promise { + await this.init(); + const table = this.tableForCollection(collection); + const row: any = { ...(data as any) }; + if (typeof row.id === 'undefined') { + throw new Error(`SupabaseStorageAdapter: Data for collection '${collection}' must have an 'id' property.`); + } + // Upsert by primary key 'id' + const { error } = await this.client + .from(table) + .upsert(row, { onConflict: 'id' }); + if (error) { + Logger.error(`SupabaseStorageAdapter: set error for ${table}/${id}`, error); + throw new Error(error.message); + } + } + + /** + * Deletes an item from a collection by its ID. + * @param {string} collection - The name of the collection. + * @param {string} id - The ID of the item to delete. + * @returns {Promise} A promise that resolves when the item is deleted. + */ + async delete(collection: string, id: string): Promise { + await this.init(); + const table = this.tableForCollection(collection); + const { error } = await this.client + .from(table) + .delete() + .eq('id', id); + if (error) { + Logger.error(`SupabaseStorageAdapter: delete error for ${table}/${id}`, error); + throw new Error(error.message); + } + } + + /** + * Queries items in a collection. + * @template T + * @param {string} collection - The name of the collection. + * @param {FilterOptions} filterOptions - The options for filtering, sorting, and pagination. + * @returns {Promise} A promise that resolves with an array of items. + */ + async query(collection: string, filterOptions: FilterOptions): Promise { + await this.init(); + const table = this.tableForCollection(collection); + let query = this.client.from(table).select('*'); + + // Basic equality filters: key = value + if (filterOptions?.filter) { + for (const [key, value] of Object.entries(filterOptions.filter)) { + // For array filter, use 'in' + if (Array.isArray(value)) { + query = query.in(key, value); + } else if (value !== undefined && value !== null) { + query = query.eq(key, value); + } + } + } + + // Sorting: single key supported (choose first) + if (filterOptions?.sort) { + const [sortKey, sortDir] = Object.entries(filterOptions.sort)[0] || []; + if (sortKey) { + query = query.order(sortKey, { ascending: sortDir === 'asc' }); + } + } + + // Pagination + const skip = filterOptions?.skip || 0; + const limit = filterOptions?.limit ?? null; + if (limit !== null && limit >= 0) { + query = query.range(skip, skip + Math.max(0, limit) - 1); + } else if (skip > 0) { + // Supabase requires a range; if only skip is provided without limit, we pick a large window + query = query.range(skip, skip + 9999); + } + + const { data, error } = await query; + if (error) { + Logger.error(`SupabaseStorageAdapter: query error for ${table}`, error); + throw new Error(error.message); + } + return (data ?? []).map((row: any) => ({ ...row })) as T[]; + } + + /** + * Clears all items from a collection. + * @param {string} collection - The name of the collection. + * @returns {Promise} A promise that resolves when the collection is cleared. + */ + async clearCollection(collection: string): Promise { + await this.init(); + const table = this.tableForCollection(collection); + const { error } = await this.client.from(table).delete().neq('id', null); + if (error) { + Logger.error(`SupabaseStorageAdapter: clearCollection error for ${table}`, error); + throw new Error(error.message); + } + } + + /** + * Clears all items from all collections. + * @returns {Promise} A promise that resolves when all collections are cleared. + */ + async clearAll(): Promise { + await this.init(); + const tables = Object.values(this.tables); + for (const table of tables) { + const { error } = await this.client.from(table).delete().neq('id', null); + if (error) { + Logger.error(`SupabaseStorageAdapter: clearAll error for ${table}`, error); + throw new Error(error.message); + } + } + } +} + + diff --git a/src/providers/ProviderManagerImpl.test.ts b/src/providers/ProviderManagerImpl.test.ts deleted file mode 100644 index c4f6ed9..0000000 --- a/src/providers/ProviderManagerImpl.test.ts +++ /dev/null @@ -1,249 +0,0 @@ -import { ProviderManagerImpl } from './ProviderManagerImpl'; -import { - AvailableProviderEntry, - ProviderManagerConfig, - RuntimeProviderConfig, - IProviderManager, - ProviderAdapter, - ManagedAdapterAccessor, // Import normally -} from '../types/providers'; // Assuming types are in providers.ts -import { FormattedPrompt, StreamEvent, CallOptions } from '../types'; // Import types from ../types -import { LocalProviderConflictError, LocalInstanceBusyError } from '../errors'; // Assuming errors are defined here - -// Mock ProviderAdapter for testing -class MockProviderAdapter implements ProviderAdapter { - providerName: string; - options: any; - isActive: boolean = false; - shutdownCalled: boolean = false; - - constructor(options: any) { - this.options = options; - this.providerName = options.providerName || 'mock'; - } - - async call(_prompt: FormattedPrompt, _options: CallOptions): Promise> { - this.isActive = true; - // Simulate some async work - await new Promise(resolve => setTimeout(resolve, 10)); - const mockResponse = `mock response for ${this.providerName}`; - this.isActive = false; - - // Return an AsyncIterable that yields a single StreamEvent - const stream: AsyncIterable = (async function*() { - yield { type: 'TOKEN', data: mockResponse, threadId: _options.threadId, traceId: _options.traceId || 'mock-trace-id' }; - yield { type: 'END', data: null, threadId: _options.threadId, traceId: _options.traceId || 'mock-trace-id' }; - })(); - - return stream; - } - - async shutdown(): Promise { - this.shutdownCalled = true; - } -} - -class MockLocalProviderAdapter extends MockProviderAdapter { - constructor(options: any) { - super(options); - this.providerName = options.providerName || 'mock_local'; - } -} - -describe('ProviderManagerImpl', () => { - let providerManager: IProviderManager; - let mockOpenAIAdapterEntry: AvailableProviderEntry; - let mockOllamaAdapterEntry: AvailableProviderEntry; - let mockLMStudioAdapterEntry: AvailableProviderEntry; - let config: ProviderManagerConfig; - - beforeEach(() => { - jest.useFakeTimers(); // Use fake timers for testing idle timeout - - mockOpenAIAdapterEntry = { - name: 'openai', - adapter: MockProviderAdapter, - isLocal: false, - }; - mockOllamaAdapterEntry = { - name: 'ollama_local', - adapter: MockLocalProviderAdapter, - isLocal: true, - }; - mockLMStudioAdapterEntry = { - name: 'lmstudio_local', - adapter: MockLocalProviderAdapter, - isLocal: true, - }; - - config = { - availableProviders: [ - mockOpenAIAdapterEntry, - mockOllamaAdapterEntry, - mockLMStudioAdapterEntry, - ], - maxParallelApiInstancesPerProvider: 2, - apiInstanceIdleTimeoutSeconds: 1, // Short timeout for testing - }; - - providerManager = new ProviderManagerImpl(config); - }); - - afterEach(() => { - jest.useRealTimers(); // Restore real timers - }); - - it('should be instantiated with a valid config', () => { - expect(providerManager).toBeInstanceOf(ProviderManagerImpl); - }); - - it('should return available provider names', () => { - const availableProviders = providerManager.getAvailableProviders(); - expect(availableProviders).toEqual(['openai', 'ollama_local', 'lmstudio_local']); - }); - - it('should return an adapter accessor for a valid provider config', async () => { - const runtimeConfig: RuntimeProviderConfig = { - providerName: 'openai', - modelId: 'gpt-4o', - adapterOptions: { apiKey: 'test-key' }, - }; - - const accessor: ManagedAdapterAccessor = await providerManager.getAdapter(runtimeConfig); - - expect(accessor).toHaveProperty('adapter'); - expect(accessor).toHaveProperty('release'); - expect(accessor.adapter).toBeInstanceOf(MockProviderAdapter); - expect(accessor.adapter.providerName).toBe('openai'); - expect(typeof accessor.release).toBe('function'); - }); - - it('should reuse an idle API adapter instance with the same config signature', async () => { - const runtimeConfig: RuntimeProviderConfig = { - providerName: 'openai', - modelId: 'gpt-4o', - adapterOptions: { apiKey: 'test-key' }, - }; - - const accessor1: ManagedAdapterAccessor = await providerManager.getAdapter(runtimeConfig); - accessor1.release(); - - // Simulate time passing for idle timeout, but instance should be reused before eviction - jest.advanceTimersByTime(500); - - const accessor2: ManagedAdapterAccessor = await providerManager.getAdapter(runtimeConfig); - - expect(accessor2.adapter).toBe(accessor1.adapter); // Should be the same instance - }); - - it('should evict an idle API adapter instance after timeout', async () => { - const runtimeConfig: RuntimeProviderConfig = { - providerName: 'openai', - modelId: 'gpt-4o', - adapterOptions: { apiKey: 'test-key' }, - }; - - const accessor1: ManagedAdapterAccessor = await providerManager.getAdapter(runtimeConfig); - const adapter1 = accessor1.adapter as MockProviderAdapter; - accessor1.release(); - - expect(adapter1.shutdownCalled).toBe(false); - - // Advance time beyond idle timeout - jest.advanceTimersByTime(config.apiInstanceIdleTimeoutSeconds! * 1000 + 100); - - // Requesting the same config should create a new instance - const accessor2: ManagedAdapterAccessor = await providerManager.getAdapter(runtimeConfig); - const adapter2 = accessor2.adapter as MockProviderAdapter; - - expect(adapter2).not.toBe(adapter1); // Should be a new instance - expect(adapter1.shutdownCalled).toBe(true); // Old instance should have been shut down - }); - - it('should enforce local provider singleton constraint (conflict)', async () => { - const ollamaConfig: RuntimeProviderConfig = { - providerName: 'ollama_local', - modelId: 'llama3:latest', - adapterOptions: {}, - }; - const lmstudioConfig: RuntimeProviderConfig = { - providerName: 'lmstudio_local', - modelId: 'local-model', - adapterOptions: {}, - }; - - // Get the first local provider, keep it active - const ollamaAccessor: ManagedAdapterAccessor = await providerManager.getAdapter(ollamaConfig); - // Do not release ollamaAccessor yet - - // Attempt to get a different local provider - await expect(providerManager.getAdapter(lmstudioConfig)).rejects.toThrow( - LocalProviderConflictError - ); - - // Release the first local provider - ollamaAccessor.release(); - - // Now getting the second local provider should work - const lmstudioAccessor: ManagedAdapterAccessor = await providerManager.getAdapter(lmstudioConfig); - expect(lmstudioAccessor.adapter).toBeInstanceOf(MockLocalProviderAdapter); - lmstudioAccessor.release(); - }); - - it('should enforce local provider singleton constraint (busy)', async () => { - const ollamaConfig: RuntimeProviderConfig = { - providerName: 'ollama_local', - modelId: 'llama3:latest', - adapterOptions: {}, - }; - - // Get the local provider, keep it active - const ollamaAccessor1: ManagedAdapterAccessor = await providerManager.getAdapter(ollamaConfig); - // Do not release ollamaAccessor1 yet - - // Attempt to get the *same* local provider again while it's active - await expect(providerManager.getAdapter(ollamaConfig)).rejects.toThrow( - LocalInstanceBusyError - ); - - // Release the instance - ollamaAccessor1.release(); - - // Now getting the same local provider should work - const ollamaAccessor2: ManagedAdapterAccessor = await providerManager.getAdapter(ollamaConfig); - expect(ollamaAccessor2.adapter).toBeInstanceOf(MockLocalProviderAdapter); - ollamaAccessor2.release(); - }); - - it('should evict an idle local provider instance when a different local provider is requested', async () => { - const ollamaConfig: RuntimeProviderConfig = { - providerName: 'ollama_local', - modelId: 'llama3:latest', - adapterOptions: {}, - }; - const lmstudioConfig: RuntimeProviderConfig = { - providerName: 'lmstudio_local', - modelId: 'local-model', - adapterOptions: {}, - }; - - // Get Ollama, then release it (it becomes idle) - const ollamaAccessor: ManagedAdapterAccessor = await providerManager.getAdapter(ollamaConfig); - const ollamaAdapter = ollamaAccessor.adapter as MockLocalProviderAdapter; - ollamaAccessor.release(); - - expect(ollamaAdapter.shutdownCalled).toBe(false); // Not shut down yet - - // Request LMStudio (a different local provider) - const lmstudioAccessor: ManagedAdapterAccessor = await providerManager.getAdapter(lmstudioConfig); - expect(lmstudioAccessor.adapter).toBeInstanceOf(MockLocalProviderAdapter); - - // The idle Ollama instance should have been shut down - expect(ollamaAdapter.shutdownCalled).toBe(true); - - lmstudioAccessor.release(); - }); - - // TODO: Add tests for API concurrency limits and queueing once implemented - // TODO: Add tests for error handling (unknown provider) -}); \ No newline at end of file diff --git a/src/systems/a2a/AgentDiscoveryService.ts b/src/systems/a2a/AgentDiscoveryService.ts new file mode 100755 index 0000000..c4a8192 --- /dev/null +++ b/src/systems/a2a/AgentDiscoveryService.ts @@ -0,0 +1,406 @@ +import { Logger } from '@/utils/logger'; +import { ARTError, ErrorCode } from '@/errors'; +import { A2AAgentInfo } from '@/types'; + +/** + * Interface for A2A Agent Card as defined in the A2A protocol standards. + * This represents the digital "business card" that agents use to advertise their capabilities. + */ +export interface A2AAgentCard { + /** Unique identifier for the agent */ + id: string; + /** Human-readable name of the agent */ + name: string; + /** Version of the agent */ + version: string; + /** Brief description of what the agent does */ + description: string; + /** Agent category (e.g., 'healthcare', 'research', 'analytics') */ + category: string; + /** Base endpoint URL for A2A communication */ + endpoint: string; + /** Array of capabilities the agent can perform */ + capabilities: string[]; + /** Authentication requirements */ + authentication: { + type: string; + required: boolean; + }; + /** Input schema definition */ + inputSchema?: { + type: string; + properties: Record; + }; + /** Output schema definition */ + outputSchema?: { + type: string; + properties: Record; + }; + /** Rate limiting information */ + rateLimits?: { + requestsPerMinute: number; + }; + /** Tags for categorization */ + tags?: string[]; +} + +/** + * Response structure from the discovery endpoint + */ +export interface DiscoveryResponse { + services: Array<{ + id: string; + service_type: string; + card_data: A2AAgentCard; + status: string; + owner_id?: string; + created_at: string; + updated_at: string; + }>; + count: number; + timestamp: string; +} + +/** + * Configuration for the AgentDiscoveryService + */ +export interface AgentDiscoveryConfig { + /** Base URL for the discovery endpoint. If not provided, a default will be used. */ + discoveryEndpoint?: string; + /** Timeout for discovery requests in milliseconds */ + timeoutMs?: number; + /** Whether to cache discovered agents */ + enableCaching?: boolean; + /** Cache TTL in milliseconds */ + cacheTtlMs?: number; +} + +/** + * Service for discovering A2A protocol compatible agents. + * Implements the A2A discovery standards for finding and identifying compatible agents. + */ +export class AgentDiscoveryService { + private readonly config: Required; + private agentCache: Map = new Map(); + + /** + * Creates an instance of AgentDiscoveryService. + * @param {Partial} config - The configuration for the service. + * @see A2AAgentCard + */ + constructor(config?: Partial) { + this.config = { + discoveryEndpoint: 'https://api.zyntopia.com/a2a/discover', // Default endpoint + timeoutMs: 10000, // 10 seconds default + enableCaching: true, + cacheTtlMs: 300000, // 5 minutes default + ...config + }; + + Logger.debug(`AgentDiscoveryService initialized with endpoint: ${this.config.discoveryEndpoint}`); + } + + /** + * Discovers all available A2A agents from the discovery endpoint. + * @param traceId - Optional trace ID for request tracking + * @returns Promise resolving to array of discovered A2A agents + * @throws {ARTError} If discovery fails or no agents are found + */ + async discoverAgents(traceId?: string): Promise { + const cacheKey = 'all_agents'; + + // Check cache first if enabled + if (this.config.enableCaching) { + const cached = this.getCachedAgents(cacheKey); + if (cached) { + Logger.debug(`[${traceId}] Returning ${cached.length} cached A2A agents`); + return cached; + } + } + + try { + Logger.debug(`[${traceId}] Discovering A2A agents from: ${this.config.discoveryEndpoint}`); + + // Create AbortController for timeout handling + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), this.config.timeoutMs); + + const response = await fetch(this.config.discoveryEndpoint, { + method: 'GET', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json' + }, + signal: controller.signal + }); + + clearTimeout(timeoutId); + + if (!response.ok) { + throw new ARTError( + `Discovery endpoint returned ${response.status}: ${response.statusText}`, + ErrorCode.EXTERNAL_SERVICE_ERROR + ); + } + + const discoveryData: DiscoveryResponse = await response.json(); + + // Filter for A2A agents only + const a2aServices = discoveryData.services.filter( + service => service.service_type === 'A2A_AGENT' && service.status === 'active' + ); + + if (a2aServices.length === 0) { + Logger.warn(`[${traceId}] No active A2A agents found in discovery response`); + return []; + } + + // Transform to A2AAgentInfo format + const agents = a2aServices.map(service => this.transformToA2AAgentInfo(service.card_data)); + + // Cache the results + if (this.config.enableCaching) { + this.setCachedAgents(cacheKey, agents); + } + + Logger.info(`[${traceId}] Discovered ${agents.length} A2A agents: ${agents.map(a => a.agentName).join(', ')}`); + return agents; + + } catch (error: any) { + if (error.name === 'AbortError') { + throw new ARTError( + `Agent discovery request timed out after ${this.config.timeoutMs}ms`, + ErrorCode.TIMEOUT + ); + } + + if (error instanceof ARTError) { + throw error; + } + + throw new ARTError( + `Failed to discover A2A agents: ${error.message}`, + ErrorCode.EXTERNAL_SERVICE_ERROR, + error + ); + } + } + + /** + * Finds the top K A2A agents for a specific task type, ranked by suitability. + * This method acts as a pre-filter, returning a list of the most promising candidates + * for an LLM to make the final selection from. + * @param taskType - The type of task (e.g., 'analysis', 'research', 'generation') + * @param topK - The maximum number of agents to return. + * @param traceId - Optional trace ID for request tracking. + * @returns Promise resolving to a ranked array of matching agents. + * @remarks TODO: Revisit and enhance the scoring algorithm. + */ + async findTopAgentsForTask(taskType: string, topK: number = 3, traceId?: string): Promise { + const agents = await this.discoverAgents(traceId); + + if (agents.length === 0) { + Logger.warn(`[${traceId}] No A2A agents available for task type: ${taskType}`); + return []; + } + + // TODO: This scoring algorithm is a foundational heuristic. Revisit and enhance this + // frequently. Future optimizations could include: + // 1. LLM-based semantic scoring for more nuanced understanding. + // 2. Incorporating a "specialization score" to reward agents with fewer, more focused capabilities. + // 3. Factoring in agent metadata (name, description, tags) for contextual relevance. + // 4. Caching individual agent scores for performance. + + // Score agents based on capability relevance to the task type + const scoredAgents = agents.map(agent => { + const capabilities = agent.capabilities || []; + let totalScore = 0; + const matchedCapabilities: string[] = []; + + for (const capability of capabilities) { + const capLower = capability.toLowerCase(); + const taskLower = taskType.toLowerCase(); + let capabilityScore = 0; + + // Exact match with task type + if (capLower === taskLower) { + capabilityScore = 10; + } + // Capability contains task type + else if (capLower.includes(taskLower)) { + capabilityScore = 8; + } + // Task type contains capability (e.g., capability "research" matches task "medical_research") + else if (taskLower.includes(capLower)) { + capabilityScore = 6; + } + // Semantic similarity for common patterns + else { + // Check for semantic relationships + const semanticScore = this.calculateSemanticScore(capLower, taskLower); + capabilityScore = semanticScore; + } + + if (capabilityScore > 0) { + totalScore += capabilityScore; + matchedCapabilities.push(capability); + } + } + + return { + agent, + score: totalScore, + matchedCapabilities + }; + }); + + // Filter out agents with no score, sort by score (highest first), and take the top K + const topMatches = scoredAgents + .filter(a => a.score > 0) + .sort((a, b) => b.score - a.score) + .slice(0, topK); + + if (topMatches.length === 0) { + Logger.warn(`[${traceId}] No suitable A2A agent found for task type: ${taskType}`); + return []; + } + + Logger.debug(`[${traceId}] Found ${topMatches.length} candidate agents for task type "${taskType}":`); + topMatches.forEach(match => { + Logger.debug(` - ${match.agent.agentName} (Score: ${match.score}, Matched: ${match.matchedCapabilities.join(', ')})`); + }); + + return topMatches.map(match => match.agent); + } + + /** + * Calculates semantic similarity score between capability and task type. + * This uses common word patterns to identify relationships without hardcoded mappings. + * @private + */ + private calculateSemanticScore(capability: string, taskType: string): number { + // Common semantic relationships + const semanticPairs = [ + // Analysis-related + ['analysis', 'analyze'], ['analysis', 'examine'], ['analysis', 'evaluate'], + ['statistical', 'statistics'], ['data', 'information'], + + // Research-related + ['research', 'investigate'], ['research', 'study'], ['research', 'explore'], + ['medical', 'health'], ['web', 'online'], ['literature', 'document'], + + // Generation-related + ['generation', 'generate'], ['generation', 'create'], ['generation', 'produce'], + ['report', 'document'], ['visualization', 'visual'], ['chart', 'graph'], + + // Computation-related + ['computation', 'compute'], ['computation', 'calculate'], ['computation', 'process'], + ['mathematical', 'math'], ['algorithm', 'algorithmic'], + + // Transformation-related + ['transformation', 'transform'], ['conversion', 'convert'], ['translation', 'translate'], + + // Validation-related + ['validation', 'validate'], ['verification', 'verify'], ['testing', 'test'] + ]; + + for (const [word1, word2] of semanticPairs) { + if ((capability.includes(word1) && taskType.includes(word2)) || + (capability.includes(word2) && taskType.includes(word1))) { + return 4; // Medium semantic match + } + } + + // Check for common word roots (basic stemming) + const getWordRoot = (word: string) => { + return word.replace(/ing$|ed$|er$|tion$|sion$|ment$|ness$|ly$|al$/, ''); + }; + + const capWords = capability.split(/[_\s-]/).map(getWordRoot); + const taskWords = taskType.split(/[_\s-]/).map(getWordRoot); + + for (const capWord of capWords) { + for (const taskWord of taskWords) { + if (capWord.length > 3 && taskWord.length > 3 && + (capWord.includes(taskWord) || taskWord.includes(capWord))) { + return 3; // Lower semantic match + } + } + } + + return 0; // No semantic relationship found + } + + /** + * Finds agents by specific capabilities. + * @param capabilities - Array of required capabilities + * @param traceId - Optional trace ID for request tracking + * @returns Promise resolving to agents that have all specified capabilities + */ + async findAgentsByCapabilities(capabilities: string[], traceId?: string): Promise { + const agents = await this.discoverAgents(traceId); + + const matchingAgents = agents.filter(agent => { + return capabilities.every(requiredCap => + agent.capabilities?.some(agentCap => + agentCap.toLowerCase().includes(requiredCap.toLowerCase()) || + requiredCap.toLowerCase().includes(agentCap.toLowerCase()) + ) + ); + }); + + Logger.debug(`[${traceId}] Found ${matchingAgents.length} agents matching capabilities: ${capabilities.join(', ')}`); + return matchingAgents; + } + + /** + * Clears the agent cache. + */ + clearCache(): void { + this.agentCache.clear(); + Logger.debug('Agent discovery cache cleared'); + } + + /** + * Gets cached agents if they exist and are not expired. + * @private + */ + private getCachedAgents(cacheKey: string): A2AAgentInfo[] | null { + const cached = this.agentCache.get(cacheKey); + if (!cached) return null; + + const isExpired = Date.now() - cached.timestamp > this.config.cacheTtlMs; + if (isExpired) { + this.agentCache.delete(cacheKey); + return null; + } + + return cached.agents; + } + + /** + * Sets agents in cache with current timestamp. + * @private + */ + private setCachedAgents(cacheKey: string, agents: A2AAgentInfo[]): void { + this.agentCache.set(cacheKey, { + agents, + timestamp: Date.now() + }); + } + + /** + * Transforms an A2A Agent Card to the ART framework's A2AAgentInfo format. + * @private + */ + private transformToA2AAgentInfo(card: A2AAgentCard): A2AAgentInfo { + return { + agentId: card.id, + agentName: card.name, + agentType: card.category || 'unknown', + endpoint: card.endpoint, + capabilities: card.capabilities || [], + status: 'available' // Assume available since it was returned by discovery + }; + } +} \ No newline at end of file diff --git a/src/systems/a2a/TaskDelegationService.ts b/src/systems/a2a/TaskDelegationService.ts new file mode 100755 index 0000000..70d87b2 --- /dev/null +++ b/src/systems/a2a/TaskDelegationService.ts @@ -0,0 +1,506 @@ +// src/systems/a2a/TaskDelegationService.ts + +import { Logger } from '@/utils/logger'; +import { ARTError, ErrorCode } from '@/errors'; +import { A2ATask, A2ATaskStatus, A2AAgentInfo, A2ATaskResult, A2ATaskMetadata } from '@/types'; +import { IA2ATaskRepository } from '@/core/interfaces'; +// AgentDiscoveryService is no longer used here; discovery is handled by PESAgent. + +/** + * Configuration options for the TaskDelegationService + */ +export interface TaskDelegationConfig { + /** Default timeout for task delegation requests in milliseconds */ + defaultTimeoutMs?: number; + /** Maximum number of retry attempts for failed requests */ + maxRetries?: number; + /** Base delay between retry attempts in milliseconds */ + retryDelayMs?: number; + /** Whether to use exponential backoff for retries */ + useExponentialBackoff?: boolean; + /** The base callback URL for receiving A2A task updates. */ + callbackUrl?: string; +} + +/** + * Response structure for A2A task submission according to A2A protocol + */ +export interface TaskSubmissionResponse { + /** Whether the task was successfully submitted */ + success: boolean; + /** The unique task ID assigned by the remote agent */ + taskId: string; + /** Current status of the submitted task */ + status: A2ATaskStatus; + /** Optional message from the remote agent */ + message?: string; + /** Estimated completion time in milliseconds (if provided) */ + estimatedCompletionMs?: number; + /** Additional metadata from the remote agent */ + metadata?: Record; +} + +/** + * Response structure for A2A task status queries + */ +export interface TaskStatusResponse { + /** The task ID */ + taskId: string; + /** Current status of the task */ + status: A2ATaskStatus; + /** Progress percentage (0-100) if available */ + progress?: number; + /** Task result if completed */ + result?: A2ATaskResult; + /** Error information if failed */ + error?: string; + /** Additional metadata */ + metadata?: Record; +} + +/** + * Service responsible for delegating A2A tasks to remote agents. + * Implements the A2A protocol for task submission, tracking, and completion. + * + * This service handles: + * - Finding suitable agents for specific task types + * - Submitting tasks to remote agents via HTTP API + * - Tracking task status and handling updates + * - Managing task lifecycle according to A2A protocol + * - Error handling and retry logic + * - Integration with local task repository for persistence + */ +export class TaskDelegationService { + private readonly config: Required; + private readonly taskRepository: IA2ATaskRepository; + + /** + * Creates an instance of TaskDelegationService. + * @param {IA2ATaskRepository} taskRepository - The repository for persisting task status. + * @param {TaskDelegationConfig} [config={}] - Configuration for the service. + */ + constructor( + taskRepository: IA2ATaskRepository, + config: TaskDelegationConfig = {} + ) { + this.taskRepository = taskRepository; + + // Set default configuration + this.config = { + defaultTimeoutMs: config.defaultTimeoutMs ?? 30000, // 30 seconds + maxRetries: config.maxRetries ?? 3, + retryDelayMs: config.retryDelayMs ?? 1000, // 1 second + useExponentialBackoff: config.useExponentialBackoff ?? true, + callbackUrl: config.callbackUrl ?? 'http://localhost:3000/api/a2a/callback' + }; + + Logger.debug('TaskDelegationService initialized with config:', this.config); + } + + /** + * Delegates a list of A2A tasks to suitable remote agents. + * For each task, finds the best agent and submits the task. + * + * @param {A2ATask[]} tasks - Array of A2A tasks to delegate + * @param {string} [traceId] - Optional trace ID for request tracking + * @returns {Promise} Promise resolving to array of successfully delegated tasks + */ + async delegateTasks(tasks: A2ATask[], traceId?: string): Promise { + if (tasks.length === 0) { + Logger.debug(`[${traceId}] No tasks to delegate`); + return []; + } + + Logger.info(`[${traceId}] Starting delegation of ${tasks.length} A2A task(s)`); + const delegatedTasks: A2ATask[] = []; + + for (const task of tasks) { + try { + const delegatedTask = await this.delegateTask(task, traceId); + if (delegatedTask) { + delegatedTasks.push(delegatedTask); + } + } catch (error: any) { + Logger.error(`[${traceId}] Failed to delegate task ${task.taskId}:`, error); + // Continue with other tasks even if one fails + } + } + + Logger.info(`[${traceId}] Successfully delegated ${delegatedTasks.length}/${tasks.length} task(s)`); + return delegatedTasks; + } + + /** + * Delegates a single A2A task to a suitable remote agent. + * + * @param {A2ATask} task - The A2A task to delegate + * @param {string} [traceId] - Optional trace ID for request tracking + * @returns {Promise} Promise resolving to the updated task or null if delegation failed + */ + async delegateTask(task: A2ATask, traceId?: string): Promise { + Logger.debug(`[${traceId}] Delegating task ${task.taskId} of type "${task.payload.taskType}"`); + + try { + // Step 1: Validate that a target agent has been assigned to the task + const targetAgent = task.targetAgent; + if (!targetAgent) { + throw new ARTError( + `Task ${task.taskId} cannot be delegated without a targetAgent.`, + ErrorCode.VALIDATION_ERROR + ); + } + + Logger.debug(`[${traceId}] Confirmed target agent "${targetAgent.agentName}" for task ${task.taskId}`); + + // Step 2: Submit task to the remote agent + const submissionResponse = await this.submitTaskToAgent(task, targetAgent, traceId); + + // Step 3: Update local task with delegation information + const now = Date.now(); + const updatedTask: A2ATask = { + ...task, + status: submissionResponse.status, + // targetAgent is already set + metadata: { + ...task.metadata, + updatedAt: now, + startedAt: submissionResponse.status === A2ATaskStatus.IN_PROGRESS ? now : task.metadata.startedAt, + tags: [...(task.metadata.tags || []), 'delegated'], + delegatedAt: now, + estimatedCompletionMs: submissionResponse.estimatedCompletionMs + } + }; + + // Step 4: Persist the updated task + // Note: The task should already exist in a PENDING state. We update it. + await this.taskRepository.updateTask(updatedTask.taskId, updatedTask); + + Logger.info(`[${traceId}] Successfully delegated task ${task.taskId} to agent "${targetAgent.agentName}" (status: ${submissionResponse.status})`); + return updatedTask; + + } catch (error: any) { + Logger.error(`[${traceId}] Task delegation failed for ${task.taskId}:`, error); + + // Update task status to failed and persist + try { + await this.taskRepository.updateTask(task.taskId, { + status: A2ATaskStatus.FAILED, + metadata: { + ...task.metadata, + updatedAt: Date.now(), + completedAt: Date.now(), + tags: [...(task.metadata.tags || []), 'delegation_failed'] + }, + result: { + success: false, + error: `Delegation failed: ${error.message}`, + metadata: { errorType: 'delegation_error', timestamp: Date.now() } + } + }); + } catch (persistError: any) { + Logger.error(`[${traceId}] Failed to persist task failure for ${task.taskId}:`, persistError); + } + + // Re-throw the original error to be handled by the caller (e.g., PESAgent) + throw error instanceof ARTError ? error : new ARTError( + `Failed to delegate task ${task.taskId}: ${error.message}`, + ErrorCode.DELEGATION_FAILED, + error + ); + } + } + + /** + * Submits a task to a specific remote agent using A2A protocol. + * + * @private + * @param {A2ATask} task - The A2A task to submit + * @param {A2AAgentInfo} targetAgent - The target agent to submit the task to + * @param {string} [traceId] - Optional trace ID for request tracking + * @returns {Promise} Promise resolving to the submission response + */ + private async submitTaskToAgent( + task: A2ATask, + targetAgent: A2AAgentInfo, + traceId?: string + ): Promise { + if (!targetAgent.endpoint) { + throw new ARTError( + `Target agent "${targetAgent.agentName}" has no endpoint configured`, + ErrorCode.VALIDATION_ERROR + ); + } + + const taskSubmissionUrl = `${targetAgent.endpoint.replace(/\/$/, '')}/tasks`; + + // Prepare the task submission payload according to A2A protocol + const submissionPayload = { + taskId: task.taskId, + taskType: task.payload.taskType, + input: task.payload.input, + instructions: task.payload.instructions, + parameters: task.payload.parameters, + priority: task.priority, + sourceAgent: task.sourceAgent, + timeoutMs: task.metadata.timeoutMs, + maxRetries: task.metadata.maxRetries, + callbackUrl: this.generateCallbackUrl(task.taskId), // For webhook notifications + metadata: { + traceId: traceId, + submittedAt: Date.now(), + sourceTimestamp: task.metadata.createdAt + } + }; + + Logger.debug(`[${traceId}] Submitting task ${task.taskId} to ${taskSubmissionUrl}`); + + let lastError: Error = new Error('Unknown error'); + let attempt = 0; + + // Retry loop with exponential backoff + while (attempt <= this.config.maxRetries) { + try { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), this.config.defaultTimeoutMs); + + const response = await fetch(taskSubmissionUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'User-Agent': 'ART-Framework-A2A/1.0.0', + 'X-Trace-ID': traceId || '', + ...(targetAgent.authentication?.type === 'bearer' && targetAgent.authentication.token + ? { 'Authorization': `Bearer ${targetAgent.authentication.token}` } + : {}), + ...(targetAgent.authentication?.type === 'api_key' && targetAgent.authentication.apiKey + ? { 'X-API-Key': targetAgent.authentication.apiKey } + : {}) + }, + body: JSON.stringify(submissionPayload), + signal: controller.signal + }); + + clearTimeout(timeoutId); + + if (!response.ok) { + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const responseData: TaskSubmissionResponse = await response.json(); + + // Validate the response structure + if (!responseData.taskId || !responseData.status) { + throw new Error('Invalid response format from remote agent'); + } + + Logger.debug(`[${traceId}] Task ${task.taskId} submitted successfully to "${targetAgent.agentName}" (remote task ID: ${responseData.taskId})`); + return responseData; + + } catch (error: any) { + lastError = error; + attempt++; + + if (error.name === 'AbortError') { + Logger.warn(`[${traceId}] Task submission timed out for ${task.taskId} (attempt ${attempt}/${this.config.maxRetries + 1})`); + } else { + Logger.warn(`[${traceId}] Task submission failed for ${task.taskId} (attempt ${attempt}/${this.config.maxRetries + 1}):`, error.message); + } + + // Don't retry if we've exhausted attempts + if (attempt > this.config.maxRetries) { + break; + } + + // Calculate delay with exponential backoff + const delay = this.config.useExponentialBackoff + ? this.config.retryDelayMs * Math.pow(2, attempt - 1) + : this.config.retryDelayMs; + + Logger.debug(`[${traceId}] Retrying task submission in ${delay}ms...`); + await new Promise(resolve => setTimeout(resolve, delay)); + } + } + + throw new ARTError( + `Failed to submit task ${task.taskId} to agent "${targetAgent.agentName}" after ${this.config.maxRetries + 1} attempts: ${lastError.message}`, + ErrorCode.EXTERNAL_SERVICE_ERROR, + lastError + ); + } + + /** + * Checks the status of a delegated task from the remote agent. + * + * @param {A2ATask} task - The A2A task to check status for + * @param {string} [traceId] - Optional trace ID for request tracking + * @returns {Promise} Promise resolving to the current task status + */ + async checkTaskStatus(task: A2ATask, traceId?: string): Promise { + if (!task.targetAgent?.endpoint) { + Logger.warn(`[${traceId}] Cannot check status for task ${task.taskId}: no target agent endpoint`); + return null; + } + + const statusUrl = `${task.targetAgent.endpoint.replace(/\/$/, '')}/tasks/${task.taskId}`; + + try { + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), this.config.defaultTimeoutMs); + + const response = await fetch(statusUrl, { + method: 'GET', + headers: { + 'User-Agent': 'ART-Framework-A2A/1.0.0', + 'X-Trace-ID': traceId || '', + ...(task.targetAgent.authentication?.type === 'bearer' && task.targetAgent.authentication.token + ? { 'Authorization': `Bearer ${task.targetAgent.authentication.token}` } + : {}), + ...(task.targetAgent.authentication?.type === 'api_key' && task.targetAgent.authentication.apiKey + ? { 'X-API-Key': task.targetAgent.authentication.apiKey } + : {}) + }, + signal: controller.signal + }); + + clearTimeout(timeoutId); + + if (!response.ok) { + if (response.status === 404) { + Logger.warn(`[${traceId}] Task ${task.taskId} not found on remote agent`); + return null; + } + throw new Error(`HTTP ${response.status}: ${response.statusText}`); + } + + const statusData: TaskStatusResponse = await response.json(); + Logger.debug(`[${traceId}] Task ${task.taskId} status: ${statusData.status}`); + + return statusData; + + } catch (error: any) { + Logger.error(`[${traceId}] Failed to check status for task ${task.taskId}:`, error); + return null; + } + } + + /** + * Updates a local A2A task based on remote status information. + * + * @param {A2ATask} task - The local A2A task to update + * @param {TaskStatusResponse} statusResponse - The status response from the remote agent + * @param {string} [traceId] - Optional trace ID for request tracking + * @returns {Promise} Promise resolving to the updated task + */ + async updateTaskFromRemoteStatus( + task: A2ATask, + statusResponse: TaskStatusResponse, + traceId?: string + ): Promise { + const now = Date.now(); + const updatedMetadata: A2ATaskMetadata = { + ...task.metadata, + updatedAt: now + }; + + const updates: Partial = { + status: statusResponse.status, + metadata: updatedMetadata + }; + + // Handle completion + if (statusResponse.status === A2ATaskStatus.COMPLETED && statusResponse.result) { + updates.result = statusResponse.result; + updatedMetadata.completedAt = now; + } + + // Handle failure + if (statusResponse.status === A2ATaskStatus.FAILED && statusResponse.error) { + updates.result = { + success: false, + error: statusResponse.error, + metadata: { remoteError: true, timestamp: now } + }; + updatedMetadata.completedAt = now; + } + + // Update additional metadata + if (statusResponse.metadata) { + Object.assign(updatedMetadata, statusResponse.metadata); + } + + // Update the updates object with the final metadata + updates.metadata = updatedMetadata; + + await this.taskRepository.updateTask(task.taskId, updates); + + Logger.debug(`[${traceId}] Updated task ${task.taskId} with remote status: ${statusResponse.status}`); + return { ...task, ...updates }; + } + + /** + * Generates a callback URL for webhook notifications. + * This would typically point to an endpoint in the local system. + * + * @private + * @param {string} taskId - The task ID to generate callback URL for + * @returns {string} The callback URL string + */ + private generateCallbackUrl(taskId: string): string { + const baseUrl = this.config.callbackUrl.replace(/\/$/, ''); // Remove trailing slash + return `${baseUrl}/${taskId}`; + } + + /** + * Cancels a delegated task on the remote agent. + * + * @param {A2ATask} task - The A2A task to cancel + * @param {string} [traceId] - Optional trace ID for request tracking + * @returns {Promise} Promise resolving to whether cancellation was successful + */ + async cancelTask(task: A2ATask, traceId?: string): Promise { + if (!task.targetAgent?.endpoint) { + Logger.warn(`[${traceId}] Cannot cancel task ${task.taskId}: no target agent endpoint`); + return false; + } + + const cancelUrl = `${task.targetAgent.endpoint.replace(/\/$/, '')}/tasks/${task.taskId}`; + + try { + const response = await fetch(cancelUrl, { + method: 'DELETE', + headers: { + 'User-Agent': 'ART-Framework-A2A/1.0.0', + 'X-Trace-ID': traceId || '', + ...(task.targetAgent.authentication?.type === 'bearer' && task.targetAgent.authentication.token + ? { 'Authorization': `Bearer ${task.targetAgent.authentication.token}` } + : {}), + ...(task.targetAgent.authentication?.type === 'api_key' && task.targetAgent.authentication.apiKey + ? { 'X-API-Key': task.targetAgent.authentication.apiKey } + : {}) + } + }); + + if (response.ok) { + // Update local task status + await this.taskRepository.updateTask(task.taskId, { + status: A2ATaskStatus.CANCELLED, + metadata: { + ...task.metadata, + updatedAt: Date.now(), + completedAt: Date.now() + } + }); + + Logger.info(`[${traceId}] Successfully cancelled task ${task.taskId}`); + return true; + } else { + Logger.warn(`[${traceId}] Failed to cancel task ${task.taskId}: HTTP ${response.status}`); + return false; + } + + } catch (error: any) { + Logger.error(`[${traceId}] Error cancelling task ${task.taskId}:`, error); + return false; + } + } +} \ No newline at end of file diff --git a/src/systems/auth/AuthManager.ts b/src/systems/auth/AuthManager.ts new file mode 100755 index 0000000..2681154 --- /dev/null +++ b/src/systems/auth/AuthManager.ts @@ -0,0 +1,154 @@ +import { IAuthStrategy } from '@/core/interfaces'; +import { ARTError, ErrorCode } from '@/errors'; +import { Logger } from '@/utils/logger'; + +/** + * Central authentication manager for handling multiple authentication strategies. + * Manages registration and retrieval of different auth strategies for secure connections + * to remote services like MCP servers and A2A agents. + */ +export class AuthManager { + private strategies = new Map(); + + constructor() { + Logger.info('AuthManager initialized.'); + } + + /** + * Registers an authentication strategy with the given ID. + * @param strategyId - Unique identifier for the strategy (e.g., 'default_zyntopia_auth', 'api_key_strategy') + * @param strategy - Implementation of IAuthStrategy + * @throws {ARTError} If strategyId is empty or null + */ + public registerStrategy(strategyId: string, strategy: IAuthStrategy): void { + if (!strategyId || strategyId.trim() === '') { + throw new ARTError('Strategy ID cannot be empty or null', ErrorCode.INVALID_CONFIG); + } + + if (this.strategies.has(strategyId)) { + Logger.warn(`AuthManager: Overwriting existing auth strategy with ID: ${strategyId}`); + } + + this.strategies.set(strategyId, strategy); + Logger.debug(`AuthManager: Registered strategy '${strategyId}'.`); + } + + /** + * Retrieves authentication headers from the specified strategy. + * @param strategyId - The ID of the registered strategy to use + * @returns Promise resolving to authentication headers + * @throws {ARTError} If strategy is not found or authentication fails + */ + public async getHeaders(strategyId: string): Promise> { + const strategy = this.strategies.get(strategyId); + if (!strategy) { + // Convention: If a Zyntopia-related auth is needed but not found, guide the developer. + if (strategyId.includes('zyntopia')) { + Logger.error(`AuthManager: Strategy '${strategyId}' not found. Did you register a ZyntopiaOAuthStrategy with the ID 'default_zyntopia_auth'?`); + } + throw new ARTError(`Authentication strategy with ID '${strategyId}' not found.`, ErrorCode.INVALID_CONFIG); + } + + try { + return await strategy.getAuthHeaders(); + } catch (error) { + const message = `Failed to get authentication headers from strategy '${strategyId}'`; + Logger.error(message, error); + throw new ARTError(message, ErrorCode.LLM_PROVIDER_ERROR, error instanceof Error ? error : new Error(String(error))); + } + } + + /** + * Checks if a strategy with the given ID is registered. + * @param strategyId - The ID to check + * @returns True if the strategy exists, false otherwise + */ + public hasStrategy(strategyId: string): boolean { + return this.strategies.has(strategyId); + } + + /** + * Lists all registered strategy IDs. + * @returns Array of registered strategy IDs + */ + public getRegisteredStrategyIds(): string[] { + return Array.from(this.strategies.keys()); + } + + /** + * Removes a registered strategy. + * @param strategyId - The ID of the strategy to remove + * @returns True if strategy was removed, false if it didn't exist + */ + public removeStrategy(strategyId: string): boolean { + const removed = this.strategies.delete(strategyId); + if (removed) { + Logger.debug(`AuthManager: Removed strategy '${strategyId}'.`); + } + return removed; + } + + /** + * Clears all registered strategies. + * Useful for testing or complete reconfiguration. + */ + public clearAllStrategies(): void { + const count = this.strategies.size; + this.strategies.clear(); + Logger.debug(`AuthManager: Cleared ${count} strategies.`); + } + + /** + * Initiates the login flow for a specific strategy. + * @param {string} strategyId - The ID of the strategy to use for login. + * @returns {Promise} A promise that resolves when the login process is initiated. + * @throws {ARTError} If the strategy is not found or does not support login. + */ + public async login(strategyId: string): Promise { + const strategy = this.strategies.get(strategyId); + if (!strategy || !strategy.login) { + throw new ARTError(`Login not supported for strategy '${strategyId}'.`, ErrorCode.INVALID_CONFIG); + } + await strategy.login(); + } + + /** + * Handles the redirect from an OAuth provider. + * @param {string} strategyId - The ID of the strategy that initiated the redirect. + * @returns {Promise} A promise that resolves when the redirect has been handled. + * @throws {ARTError} If the strategy is not found or does not support handling redirects. + */ + public async handleRedirect(strategyId: string): Promise { + const strategy = this.strategies.get(strategyId); + if (!strategy || !strategy.handleRedirect) { + throw new ARTError(`handleRedirect not supported for strategy '${strategyId}'.`, ErrorCode.INVALID_CONFIG); + } + await strategy.handleRedirect(); + } + + /** + * Logs the user out of a specific strategy. + * @param {string} strategyId - The ID of the strategy to use for logout. + * @throws {ARTError} If the strategy is not found or does not support logout. + */ + public logout(strategyId: string): void { + const strategy = this.strategies.get(strategyId); + if (!strategy || !strategy.logout) { + throw new ARTError(`Logout not supported for strategy '${strategyId}'.`, ErrorCode.INVALID_CONFIG); + } + strategy.logout(); + } + + /** + * Checks if the user is authenticated with a specific strategy. + * @param {string} strategyId - The ID of the strategy to check. + * @returns {Promise} A promise that resolves to true if authenticated, false otherwise. + */ + public async isAuthenticated(strategyId: string): Promise { + const strategy = this.strategies.get(strategyId); + if (!strategy || !strategy.isAuthenticated) { + return false; + } + return await strategy.isAuthenticated(); + } +} \ No newline at end of file diff --git a/src/systems/context/ContextProvider.ts b/src/systems/context/ContextProvider.ts old mode 100644 new mode 100755 index 160f0de..be039dd --- a/src/systems/context/ContextProvider.ts +++ b/src/systems/context/ContextProvider.ts @@ -1,4 +1,4 @@ -import { Logger } from '../../utils/logger'; // Import Logger +import { Logger } from '@/utils/logger'; // Import Logger //import { StateManager } from './managers/StateManager'; //import { ConversationManager } from './managers/ConversationManager'; // Import other necessary types or interfaces if needed in the future @@ -13,6 +13,8 @@ import { Logger } from '../../utils/logger'; // Import Logger * * For v1.0, the core context (history, config) is primarily managed and retrieved * directly via ConversationManager and StateManager within the Agent Core's flow. + * @see StateManager + * @see ConversationManager */ export class ContextProvider { // Dependencies like StateManager and ConversationManager might be needed later @@ -21,6 +23,9 @@ export class ContextProvider { // private conversationManager: ConversationManager // ) {} + /** + * Creates an instance of ContextProvider. + */ constructor() { Logger.info("ContextProvider initialized (v1.0 Placeholder)"); // Use Logger } @@ -29,9 +34,9 @@ export class ContextProvider { * Retrieves relevant dynamic context based on the current state. * Placeholder implementation for v1.0. * - * @param _threadId The ID of the current thread. - * @param _query The current user query or intent. - * @returns A promise resolving to a context object (currently empty). + * @param {string} _threadId The ID of the current thread. + * @param {string} [_query] The current user query or intent. + * @returns {Promise>} A promise resolving to a context object (currently empty). */ async getDynamicContext(_threadId: string, _query?: string): Promise> { // In future versions, this method would: diff --git a/src/systems/context/managers/ConversationManager.test.ts b/src/systems/context/managers/ConversationManager.test.ts deleted file mode 100644 index 57a1f3c..0000000 --- a/src/systems/context/managers/ConversationManager.test.ts +++ /dev/null @@ -1,140 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { ConversationManager } from './ConversationManager'; -import { IConversationRepository } from '../../../core/interfaces'; -import { ConversationSocket } from '../../ui/conversation-socket'; // Import mock target -import { ConversationMessage, MessageOptions, MessageRole } from '../../../types'; - -// Helper to create messages -const createMessage = (id: number, threadId: string, timestamp: number, role: MessageRole, content: string): ConversationMessage => ({ - messageId: `msg-${id}`, - threadId: threadId, - timestamp: timestamp, - role: role, - content: content, -}); - -// Create a mock repository -const createMockRepository = (): IConversationRepository => ({ - addMessages: vi.fn().mockResolvedValue(undefined), - getMessages: vi.fn().mockResolvedValue([]), // Default to empty array -}); - -describe('ConversationManager', () => { - let mockRepository: IConversationRepository; - let mockSocket: ConversationSocket; // Add mock socket variable - let manager: ConversationManager; - const threadId = 'conv-mgr-thread-1'; - - beforeEach(() => { - mockRepository = createMockRepository(); - // Create a basic mock socket with a spy on the notify method - mockSocket = { - notify: vi.fn(), - // Add other methods if needed by tests, mocked similarly - } as unknown as ConversationSocket; - manager = new ConversationManager(mockRepository, mockSocket); // Pass mock socket - }); - - describe('addMessages', () => { - it('should call repository.addMessages with correct arguments', async () => { - const messages = [ - createMessage(1, threadId, Date.now(), MessageRole.USER, 'Hello'), - createMessage(2, threadId, Date.now() + 1, MessageRole.AI, 'Hi there'), - ]; - await manager.addMessages(threadId, messages); - - expect(mockRepository.addMessages).toHaveBeenCalledOnce(); - expect(mockRepository.addMessages).toHaveBeenCalledWith(threadId, messages); - // Check if socket was notified for each message - expect(mockSocket.notify).toHaveBeenCalledTimes(messages.length); - expect(mockSocket.notify).toHaveBeenCalledWith(messages[0], { targetThreadId: threadId }); - expect(mockSocket.notify).toHaveBeenCalledWith(messages[1], { targetThreadId: threadId }); - }); - - it('should resolve successfully even if repository throws (depends on desired behavior - current impl lets repo handle errors)', async () => { - // Mock repository to throw an error - const repoError = new Error("Repo failed"); - mockRepository.addMessages = vi.fn().mockRejectedValue(repoError); - const messages = [createMessage(1, threadId, Date.now(), MessageRole.USER, 'Test')]; - - // The manager currently doesn't catch errors from the repository addMessages - // Even if repo fails, socket notification might still be attempted depending on order - // In current implementation, repo call is first, so if it rejects, socket won't be called. - await expect(manager.addMessages(threadId, messages)).rejects.toThrow(repoError); - expect(mockRepository.addMessages).toHaveBeenCalledWith(threadId, messages); - expect(mockSocket.notify).not.toHaveBeenCalled(); // Because repo call failed first - }); - - - it('should not call repository or socket if messages array is empty', async () => { - await manager.addMessages(threadId, []); - expect(mockRepository.addMessages).not.toHaveBeenCalled(); - expect(mockSocket.notify).not.toHaveBeenCalled(); - }); - - it('should not call repository or socket if messages array is null or undefined', async () => { - await manager.addMessages(threadId, null as any); - expect(mockRepository.addMessages).not.toHaveBeenCalled(); - expect(mockSocket.notify).not.toHaveBeenCalled(); - await manager.addMessages(threadId, undefined as any); - expect(mockRepository.addMessages).not.toHaveBeenCalled(); - expect(mockSocket.notify).not.toHaveBeenCalled(); - }); - - it('should reject and not call repo/socket if threadId is empty', async () => { - const messages = [createMessage(1, '', Date.now(), MessageRole.USER, 'Test')]; - await expect(manager.addMessages('', messages)).rejects.toThrow('ConversationManager: threadId cannot be empty.'); - expect(mockRepository.addMessages).not.toHaveBeenCalled(); - expect(mockSocket.notify).not.toHaveBeenCalled(); - }); - }); - - describe('getMessages', () => { - it('should call repository.getMessages with correct threadId and default options', async () => { - const expectedMessages = [createMessage(1, threadId, Date.now(), MessageRole.USER, 'Retrieved')]; - mockRepository.getMessages = vi.fn().mockResolvedValue(expectedMessages); - - const retrieved = await manager.getMessages(threadId); - - expect(mockRepository.getMessages).toHaveBeenCalledOnce(); - expect(mockRepository.getMessages).toHaveBeenCalledWith(threadId, undefined); // No options passed - expect(retrieved).toEqual(expectedMessages); - }); - - it('should call repository.getMessages with correct threadId and provided options', async () => { - const options: MessageOptions = { limit: 10, beforeTimestamp: Date.now() }; - const expectedMessages = [createMessage(1, threadId, Date.now() - 100, MessageRole.USER, 'Limited')]; - mockRepository.getMessages = vi.fn().mockResolvedValue(expectedMessages); - - const retrieved = await manager.getMessages(threadId, options); - - expect(mockRepository.getMessages).toHaveBeenCalledOnce(); - expect(mockRepository.getMessages).toHaveBeenCalledWith(threadId, options); - expect(retrieved).toEqual(expectedMessages); - }); - - it('should return the result from the repository', async () => { - const expectedMessages = [ - createMessage(1, threadId, Date.now(), MessageRole.USER, 'Msg A'), - createMessage(2, threadId, Date.now()+1, MessageRole.AI, 'Msg B') - ]; - mockRepository.getMessages = vi.fn().mockResolvedValue(expectedMessages); - - const result = await manager.getMessages(threadId); - expect(result).toBe(expectedMessages); // Check if it returns the exact array from repo - }); - - it('should reject if threadId is empty', async () => { - await expect(manager.getMessages('')).rejects.toThrow('threadId cannot be empty'); - expect(mockRepository.getMessages).not.toHaveBeenCalled(); - }); - - it('should propagate errors from the repository', async () => { - const repoError = new Error("Repo read failed"); - mockRepository.getMessages = vi.fn().mockRejectedValue(repoError); - - await expect(manager.getMessages(threadId)).rejects.toThrow(repoError); - expect(mockRepository.getMessages).toHaveBeenCalledWith(threadId, undefined); - }); - }); -}); \ No newline at end of file diff --git a/src/systems/context/managers/ConversationManager.ts b/src/systems/context/managers/ConversationManager.ts old mode 100644 new mode 100755 index 0e9a317..9f342c4 --- a/src/systems/context/managers/ConversationManager.ts +++ b/src/systems/context/managers/ConversationManager.ts @@ -1,6 +1,6 @@ -import { ConversationManager as IConversationManager, IConversationRepository } from '../../../core/interfaces'; -import { ConversationSocket } from '../../ui/conversation-socket'; // Import the class -import { ConversationMessage, MessageOptions } from '../../../types'; +import { ConversationManager as IConversationManager, IConversationRepository } from '@/core/interfaces'; +import { ConversationSocket } from '@/systems/ui/conversation-socket'; // Import the class +import { ConversationMessage, MessageOptions } from '@/types'; /** * Manages the retrieval and addition of `ConversationMessage` objects for different threads, @@ -13,8 +13,8 @@ export class ConversationManager implements IConversationManager { /** * Creates an instance of ConversationManager. - * @param conversationRepository - The repository responsible for persisting conversation messages. - * @param conversationSocket - The socket instance used to notify the UI of new messages. + * @param {IConversationRepository} conversationRepository - The repository responsible for persisting conversation messages. + * @param {ConversationSocket} conversationSocket - The socket instance used to notify the UI of new messages. */ constructor( conversationRepository: IConversationRepository, @@ -27,9 +27,9 @@ export class ConversationManager implements IConversationManager { /** * Adds one or more messages to a specific thread's history using the repository * and notifies the `ConversationSocket` for each added message. - * @param threadId - The ID of the thread to add messages to. Must not be empty. - * @param messages - An array of `ConversationMessage` objects to add. - * @returns A promise that resolves when messages are saved and notifications are sent (or attempted). + * @param {string} threadId - The ID of the thread to add messages to. Must not be empty. + * @param {ConversationMessage[]} messages - An array of `ConversationMessage` objects to add. + * @returns {Promise} A promise that resolves when messages are saved and notifications are sent (or attempted). * @throws {Error} If `threadId` is empty. Repository errors might also propagate. */ async addMessages(threadId: string, messages: ConversationMessage[]): Promise { @@ -58,9 +58,9 @@ export class ConversationManager implements IConversationManager { /** * Retrieves messages from a specific thread's history using the repository. - * @param threadId - The ID of the thread whose history is needed. Must not be empty. - * @param options - Optional parameters (`MessageOptions`) to control retrieval (e.g., limit, timestamp filters). - * @returns A promise resolving to an array of `ConversationMessage` objects, typically ordered newest first by the repository. + * @param {string} threadId - The ID of the thread whose history is needed. Must not be empty. + * @param {MessageOptions} [options] - Optional parameters (`MessageOptions`) to control retrieval (e.g., limit, timestamp filters). + * @returns {Promise} A promise resolving to an array of `ConversationMessage` objects, typically ordered newest first by the repository. * @throws {Error} If `threadId` is empty. Repository errors might also propagate. */ async getMessages(threadId: string, options?: MessageOptions): Promise { diff --git a/src/systems/context/managers/StateManager.test.ts b/src/systems/context/managers/StateManager.test.ts deleted file mode 100644 index 0f183f9..0000000 --- a/src/systems/context/managers/StateManager.test.ts +++ /dev/null @@ -1,199 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { StateManager } from './StateManager'; -import { IStateRepository } from '../../../core/interfaces'; -import { ThreadContext, ThreadConfig, AgentState } from '../../../types'; // Need ThreadConfig/AgentState for test data - -// Helper to create default config/state for tests -const createTestConfig = (tools: string[] = ['toolA']): ThreadConfig => ({ - reasoning: { provider: 'test', model: 'test-m' }, - enabledTools: tools, - historyLimit: 5, - systemPrompt: 'Test prompt', -}); - -const createTestState = (): AgentState => ({ preference: 'value' }); - -// Create a mock repository -const createMockRepository = (): IStateRepository => ({ - getThreadContext: vi.fn(), - setThreadContext: vi.fn().mockResolvedValue(undefined), - getThreadConfig: vi.fn(), // Not directly used by StateManager, but part of interface - setThreadConfig: vi.fn().mockResolvedValue(undefined), // Not directly used by StateManager - getAgentState: vi.fn(), // Not directly used by StateManager - setAgentState: vi.fn().mockResolvedValue(undefined), // Not directly used by StateManager -}); - -describe('StateManager', () => { - let mockRepository: IStateRepository; - let manager: StateManager; - const threadId = 'state-mgr-thread-1'; - - beforeEach(() => { - mockRepository = createMockRepository(); - manager = new StateManager(mockRepository); - }); - - describe('loadThreadContext', () => { - it('should call repository.getThreadContext and return the context', async () => { - const expectedContext: ThreadContext = { config: createTestConfig(), state: createTestState() }; - mockRepository.getThreadContext = vi.fn().mockResolvedValue(expectedContext); - - const context = await manager.loadThreadContext(threadId); - - expect(mockRepository.getThreadContext).toHaveBeenCalledOnce(); - expect(mockRepository.getThreadContext).toHaveBeenCalledWith(threadId); - expect(context).toEqual(expectedContext); - }); - - it('should throw an error if repository returns null', async () => { - mockRepository.getThreadContext = vi.fn().mockResolvedValue(null); - - await expect(manager.loadThreadContext(threadId)) - .rejects.toThrow(`Thread context not found for threadId '${threadId}'`); - expect(mockRepository.getThreadContext).toHaveBeenCalledWith(threadId); - }); - - it('should throw an error if repository throws an error', async () => { - const repoError = new Error('Repo DB connection failed'); - mockRepository.getThreadContext = vi.fn().mockRejectedValue(repoError); - - await expect(manager.loadThreadContext(threadId)).rejects.toThrow(repoError); - expect(mockRepository.getThreadContext).toHaveBeenCalledWith(threadId); - }); - - it('should throw an error if threadId is empty', async () => { - await expect(manager.loadThreadContext('')).rejects.toThrow('threadId cannot be empty'); - expect(mockRepository.getThreadContext).not.toHaveBeenCalled(); - }); - }); - - describe('isToolEnabled', () => { - it('should return true if tool is in enabledTools list', async () => { - const config = createTestConfig(['toolA', 'toolB']); - const context: ThreadContext = { config, state: null }; - mockRepository.getThreadContext = vi.fn().mockResolvedValue(context); - - const result = await manager.isToolEnabled(threadId, 'toolA'); - expect(result).toBe(true); - expect(mockRepository.getThreadContext).toHaveBeenCalledWith(threadId); - }); - - it('should return false if tool is not in enabledTools list', async () => { - const config = createTestConfig(['toolA', 'toolB']); - const context: ThreadContext = { config, state: null }; - mockRepository.getThreadContext = vi.fn().mockResolvedValue(context); - - const result = await manager.isToolEnabled(threadId, 'toolC'); - expect(result).toBe(false); - }); - - it('should return false if enabledTools array is empty', async () => { - const config = createTestConfig([]); - const context: ThreadContext = { config, state: null }; - mockRepository.getThreadContext = vi.fn().mockResolvedValue(context); - - const result = await manager.isToolEnabled(threadId, 'toolA'); - expect(result).toBe(false); - }); - - it('should return false if enabledTools property is missing', async () => { - const config = { reasoning: { provider: 'p', model: 'm' }, historyLimit: 1 } as ThreadConfig; // Missing enabledTools - const context: ThreadContext = { config, state: null }; - mockRepository.getThreadContext = vi.fn().mockResolvedValue(context); - - const result = await manager.isToolEnabled(threadId, 'toolA'); - expect(result).toBe(false); - }); - - it('should return false if config is missing', async () => { - const context: ThreadContext = { config: null as any, state: null }; // Config is null - mockRepository.getThreadContext = vi.fn().mockResolvedValue(context); - - const result = await manager.isToolEnabled(threadId, 'toolA'); - expect(result).toBe(false); - }); - - it('should return false and warn if context loading fails', async () => { - const consoleWarnSpy = vi.spyOn(console, 'warn'); - const repoError = new Error('Context load failed'); - mockRepository.getThreadContext = vi.fn().mockRejectedValue(repoError); - - const result = await manager.isToolEnabled(threadId, 'toolA'); - - expect(result).toBe(false); - expect(consoleWarnSpy).toHaveBeenCalledWith( - expect.stringContaining(`Could not check if tool 'toolA' is enabled for thread '${threadId}' because context failed to load: ${repoError}`) - ); - consoleWarnSpy.mockRestore(); - }); - }); - - describe('getThreadConfigValue', () => { - const config = createTestConfig(['toolA']); - const context: ThreadContext = { config, state: null }; - - beforeEach(() => { - mockRepository.getThreadContext = vi.fn().mockResolvedValue(context); - }); - - it('should return the value for an existing top-level key', async () => { - const historyLimit = await manager.getThreadConfigValue(threadId, 'historyLimit'); - expect(historyLimit).toBe(config.historyLimit); // Should be 5 - expect(mockRepository.getThreadContext).toHaveBeenCalledWith(threadId); - - const systemPrompt = await manager.getThreadConfigValue(threadId, 'systemPrompt'); - expect(systemPrompt).toBe(config.systemPrompt); - }); - - it('should return the array value for enabledTools key', async () => { - const enabledTools = await manager.getThreadConfigValue(threadId, 'enabledTools'); - expect(enabledTools).toEqual(config.enabledTools); - }); - - it('should return the object value for reasoning key', async () => { - const reasoning = await manager.getThreadConfigValue(threadId, 'reasoning'); - expect(reasoning).toEqual(config.reasoning); - }); - - - it('should return undefined for a non-existent key', async () => { - const nonExistent = await manager.getThreadConfigValue(threadId, 'nonExistentKey'); - expect(nonExistent).toBeUndefined(); - }); - - it('should return undefined if config object is null or missing', async () => { - const contextNoConfig: ThreadContext = { config: null as any, state: null }; - mockRepository.getThreadContext = vi.fn().mockResolvedValue(contextNoConfig); - const value = await manager.getThreadConfigValue(threadId, 'historyLimit'); - expect(value).toBeUndefined(); - }); - - it('should throw error if context loading fails', async () => { - const repoError = new Error('Context load failed'); - mockRepository.getThreadContext = vi.fn().mockRejectedValue(repoError); - await expect(manager.getThreadConfigValue(threadId, 'historyLimit')).rejects.toThrow(repoError); - }); - - // Note: The current implementation doesn't support deep keys like 'reasoning.provider' - it('should return undefined for deep keys (not supported)', async () => { - const deepValue = await manager.getThreadConfigValue(threadId, 'reasoning.provider' as any); - expect(deepValue).toBeUndefined(); // 'reasoning.provider' is not a direct key of ThreadConfig - }); - }); - - describe('saveStateIfModified', () => { - it('should resolve and log a warning (no-op)', async () => { - const consoleWarnSpy = vi.spyOn(console, 'warn'); - await expect(manager.saveStateIfModified(threadId)).resolves.toBeUndefined(); - expect(consoleWarnSpy).toHaveBeenCalledWith( - expect.stringContaining(`saveStateIfModified called for thread ${threadId}, but state modification tracking/saving is not implemented`) - ); - expect(mockRepository.setThreadContext).not.toHaveBeenCalled(); // Ensure repo wasn't called - consoleWarnSpy.mockRestore(); - }); - - it('should reject if threadId is empty', async () => { - await expect(manager.saveStateIfModified('')).rejects.toThrow('threadId cannot be empty'); - }); - }); -}); \ No newline at end of file diff --git a/src/systems/context/managers/StateManager.ts b/src/systems/context/managers/StateManager.ts old mode 100644 new mode 100755 index 2cb1e1e..6886903 --- a/src/systems/context/managers/StateManager.ts +++ b/src/systems/context/managers/StateManager.ts @@ -1,5 +1,5 @@ -import { StateManager as IStateManager, IStateRepository } from '../../../core/interfaces'; -import { ThreadContext, ThreadConfig, AgentState, StateSavingStrategy } from '../../../types'; +import { StateManager as IStateManager, IStateRepository } from '@/core/interfaces'; +import { ThreadContext, ThreadConfig, AgentState, StateSavingStrategy } from '@/types'; // Helper for deep cloning, as structuredClone might not be available in all environments // or might not handle all types perfectly (e.g., functions, though not expected in AgentState). @@ -36,6 +36,11 @@ export class StateManager implements IStateManager { private strategy: StateSavingStrategy; private contextCache: Map; + /** + * Creates an instance of StateManager. + * @param {IStateRepository} stateRepository - The repository for persisting state. + * @param {StateSavingStrategy} [strategy='explicit'] - The state saving strategy to use. + */ constructor( stateRepository: IStateRepository, strategy: StateSavingStrategy = 'explicit' // Default to explicit @@ -49,9 +54,9 @@ export class StateManager implements IStateManager { * Loads the complete context (`ThreadConfig` and `AgentState`) for a specific thread. * If in 'implicit' state saving strategy, it caches the loaded context and a snapshot * of its AgentState for later comparison in `saveStateIfModified`. - * @param threadId - The unique identifier for the thread. - * @param _userId - Optional user identifier (currently unused). - * @returns A promise resolving to the `ThreadContext` object. + * @param {string} threadId - The unique identifier for the thread. + * @param {string} [_userId] - Optional user identifier (currently unused). + * @returns {Promise} A promise resolving to the `ThreadContext` object. * @throws {Error} If `threadId` is empty or if the repository fails to find the context. */ async loadThreadContext(threadId: string, _userId?: string): Promise { @@ -88,9 +93,9 @@ export class StateManager implements IStateManager { /** * Checks if a specific tool is permitted for use within a given thread. * It loads the thread's context and checks the `enabledTools` array in the configuration. - * @param threadId - The ID of the thread. - * @param toolName - The name of the tool to check. - * @returns A promise resolving to `true` if the tool is listed in the thread's `enabledTools` config, `false` otherwise or if the context/config cannot be loaded. + * @param {string} threadId - The ID of the thread. + * @param {string} toolName - The name of the tool to check. + * @returns {Promise} A promise resolving to `true` if the tool is listed in the thread's `enabledTools` config, `false` otherwise or if the context/config cannot be loaded. */ async isToolEnabled(threadId: string, toolName: string): Promise { try { @@ -106,9 +111,9 @@ export class StateManager implements IStateManager { * Retrieves a specific value from the thread's configuration (`ThreadConfig`). * Loads the context first (which might come from cache in implicit mode). * @template T - The expected type of the configuration value. - * @param threadId - The ID of the thread. - * @param key - The top-level configuration key. - * @returns A promise resolving to the configuration value, or `undefined`. + * @param {string} threadId - The ID of the thread. + * @param {string} key - The top-level configuration key. + * @returns {Promise} A promise resolving to the configuration value, or `undefined`. */ async getThreadConfigValue(threadId: string, key: string): Promise { const context = await this.loadThreadContext(threadId); // Will use cache if implicit @@ -130,7 +135,8 @@ export class StateManager implements IStateManager { * - 'implicit': Compares the current `AgentState` (from the cached `ThreadContext` modified by the agent) * with the snapshot taken during `loadThreadContext`. If different, saves the state * to the repository and updates the snapshot. - * @param threadId - The ID of the thread whose state might need saving. + * @param {string} threadId - The ID of the thread whose state might need saving. + * @returns {Promise} A promise that resolves when the state is saved or the operation is skipped. */ async saveStateIfModified(threadId: string): Promise { if (!threadId) { @@ -187,8 +193,9 @@ export class StateManager implements IStateManager { /** * Sets or completely replaces the configuration (`ThreadConfig`) for a specific thread * by calling the underlying state repository. This also clears any cached context for the thread. - * @param threadId - The ID of the thread. - * @param config - The complete `ThreadConfig` object. + * @param {string} threadId - The ID of the thread. + * @param {ThreadConfig} config - The complete `ThreadConfig` object. + * @returns {Promise} A promise that resolves when the configuration is saved. */ async setThreadConfig(threadId: string, config: ThreadConfig): Promise { if (!threadId || !config) { @@ -208,8 +215,9 @@ export class StateManager implements IStateManager { * Explicitly sets or updates the AgentState for a specific thread by calling the underlying state repository. * If in 'implicit' mode, this also updates the cached snapshot to prevent `saveStateIfModified` * from re-saving the same state immediately. - * @param threadId - The unique identifier of the thread. - * @param state - The AgentState object to save. Must not be undefined or null. + * @param {string} threadId - The unique identifier of the thread. + * @param {AgentState} state - The AgentState object to save. Must not be undefined or null. + * @returns {Promise} A promise that resolves when the state is saved. * @throws {Error} If threadId or state is undefined/null, or if the repository fails. */ async setAgentState(threadId: string, state: AgentState): Promise { @@ -240,6 +248,96 @@ export class StateManager implements IStateManager { } } + /** + * Enables specific tools for a conversation thread by adding them to the thread's enabled tools list. + * This method loads the current thread configuration, updates the enabledTools array, + * and persists the changes. Cache is invalidated to ensure fresh data on next load. + * @param {string} threadId - The unique identifier of the thread. + * @param {string[]} toolNames - Array of tool names to enable for this thread. + * @returns {Promise} A promise that resolves when the tools are enabled. + * @throws {Error} If threadId is empty, toolNames is empty, or if the repository fails. + */ + async enableToolsForThread(threadId: string, toolNames: string[]): Promise { + if (!threadId) { + throw new Error("StateManager: threadId cannot be empty for enableToolsForThread."); + } + if (!toolNames || toolNames.length === 0) { + throw new Error("StateManager: toolNames cannot be empty for enableToolsForThread."); + } + + // Load current context to get existing config + const context = await this.loadThreadContext(threadId); + if (!context.config) { + throw new Error(`StateManager: No ThreadConfig found for threadId '${threadId}'. Cannot enable tools without existing configuration.`); + } + + // Create updated config with additional enabled tools + const currentEnabledTools = context.config.enabledTools || []; + const newEnabledTools = [...new Set([...currentEnabledTools, ...toolNames])]; // Remove duplicates + + const updatedConfig: ThreadConfig = { + ...context.config, + enabledTools: newEnabledTools + }; + + // Save updated config and clear cache + await this.setThreadConfig(threadId, updatedConfig); + // console.debug(`StateManager: Enabled tools [${toolNames.join(', ')}] for thread ${threadId}.`); + } + + /** + * Disables specific tools for a conversation thread by removing them from the thread's enabled tools list. + * This method loads the current thread configuration, updates the enabledTools array, + * and persists the changes. Cache is invalidated to ensure fresh data on next load. + * @param {string} threadId - The unique identifier of the thread. + * @param {string[]} toolNames - Array of tool names to disable for this thread. + * @returns {Promise} A promise that resolves when the tools are disabled. + * @throws {Error} If threadId is empty, toolNames is empty, or if the repository fails. + */ + async disableToolsForThread(threadId: string, toolNames: string[]): Promise { + if (!threadId) { + throw new Error("StateManager: threadId cannot be empty for disableToolsForThread."); + } + if (!toolNames || toolNames.length === 0) { + throw new Error("StateManager: toolNames cannot be empty for disableToolsForThread."); + } + + // Load current context to get existing config + const context = await this.loadThreadContext(threadId); + if (!context.config) { + throw new Error(`StateManager: No ThreadConfig found for threadId '${threadId}'. Cannot disable tools without existing configuration.`); + } + + // Create updated config with tools removed + const currentEnabledTools = context.config.enabledTools || []; + const newEnabledTools = currentEnabledTools.filter(tool => !toolNames.includes(tool)); + + const updatedConfig: ThreadConfig = { + ...context.config, + enabledTools: newEnabledTools + }; + + // Save updated config and clear cache + await this.setThreadConfig(threadId, updatedConfig); + // console.debug(`StateManager: Disabled tools [${toolNames.join(', ')}] for thread ${threadId}.`); + } + + /** + * Gets the list of currently enabled tools for a specific thread. + * This is a convenience method that loads the thread context and returns the enabledTools array. + * @param {string} threadId - The unique identifier of the thread. + * @returns {Promise} A promise that resolves to an array of enabled tool names, or empty array if no tools are enabled. + * @throws {Error} If the thread context cannot be loaded. + */ + async getEnabledToolsForThread(threadId: string): Promise { + if (!threadId) { + throw new Error("StateManager: threadId cannot be empty for getEnabledToolsForThread."); + } + + const context = await this.loadThreadContext(threadId); + return context.config?.enabledTools || []; + } + /** * Clears the internal context cache. Useful if the underlying storage is manipulated externally * during an agent's processing cycle, though this is generally not recommended. diff --git a/src/systems/context/repositories/ConversationRepository.test.ts b/src/systems/context/repositories/ConversationRepository.test.ts deleted file mode 100644 index a6bf4dc..0000000 --- a/src/systems/context/repositories/ConversationRepository.test.ts +++ /dev/null @@ -1,186 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { ConversationRepository } from './ConversationRepository'; -import { InMemoryStorageAdapter } from '../../../adapters/storage/inMemory'; // Use the in-memory adapter for mocking -import { ConversationMessage, MessageRole, MessageOptions } from '../../../types'; -import { IConversationRepository } from '../../../core/interfaces'; // Import interface for type safety - -// Helper to create messages -const createMessage = (id: number, threadId: string, timestamp: number, role: MessageRole, content: string): ConversationMessage => ({ - messageId: `msg-${id}`, - threadId: threadId, - timestamp: timestamp, - role: role, - content: content, -}); - -describe('ConversationRepository', () => { - let mockAdapter: InMemoryStorageAdapter; - let repository: IConversationRepository; // Use interface type - const threadId1 = 'thread-1'; - const threadId2 = 'thread-2'; - - beforeEach(() => { - mockAdapter = new InMemoryStorageAdapter(); - // No need to explicitly call init for InMemoryStorageAdapter - repository = new ConversationRepository(mockAdapter); - }); - - describe('addMessages', () => { - it('should add a single message to the correct collection', async () => { - const message = createMessage(1, threadId1, Date.now(), MessageRole.USER, 'Hello'); - await repository.addMessages(threadId1, [message]); - - // Verify using the adapter directly - const stored = await mockAdapter.get<{ id: string } & ConversationMessage>('conversations', message.messageId); - expect(stored).toBeDefined(); - expect(stored?.messageId).toBe(message.messageId); - expect(stored?.threadId).toBe(threadId1); - expect(stored?.content).toBe('Hello'); - expect(stored?.id).toBe(message.messageId); // Check internal 'id' field - }); - - it('should add multiple messages', async () => { - const messages = [ - createMessage(1, threadId1, Date.now() - 100, MessageRole.USER, 'Msg 1'), - createMessage(2, threadId1, Date.now(), MessageRole.AI, 'Msg 2'), - ]; - await repository.addMessages(threadId1, messages); - - const stored1 = await mockAdapter.get('conversations', 'msg-1'); - const stored2 = await mockAdapter.get('conversations', 'msg-2'); - expect(stored1).toBeDefined(); - expect(stored2).toBeDefined(); - }); - - it('should handle adding an empty array of messages', async () => { - await expect(repository.addMessages(threadId1, [])).resolves.toBeUndefined(); - const results = await mockAdapter.query('conversations', { filter: { threadId: threadId1 } }); - expect(results).toHaveLength(0); - }); - - it('should warn but still add message if message.threadId mismatches repository threadId', async () => { - const consoleWarnSpy = vi.spyOn(console, 'warn'); - const message = createMessage(1, 'different-thread', Date.now(), MessageRole.USER, 'Mismatch'); - - await repository.addMessages(threadId1, [message]); // Adding to threadId1 - - expect(consoleWarnSpy).toHaveBeenCalledWith( - expect.stringContaining(`Message ${message.messageId} has mismatching threadId (different-thread) for repository operation on thread ${threadId1}`) - ); - - // Verify it was still stored (under its own messageId) - const stored = await mockAdapter.get('conversations', message.messageId); - expect(stored).toBeDefined(); - expect((stored as any).threadId).toBe('different-thread'); // Stored with its original threadId - - consoleWarnSpy.mockRestore(); - }); - }); - - describe('getMessages', () => { - const now = Date.now(); - const messagesT1 = [ - createMessage(1, threadId1, now - 200, MessageRole.USER, 'T1 Msg 1'), // Oldest - createMessage(2, threadId1, now - 100, MessageRole.AI, 'T1 Msg 2'), - createMessage(3, threadId1, now, MessageRole.USER, 'T1 Msg 3'), // Newest - ]; - const messageT2 = createMessage(4, threadId2, now - 50, MessageRole.USER, 'T2 Msg 1'); - - beforeEach(async () => { - // Seed messages using the repository's add method - await repository.addMessages(threadId1, messagesT1); - await repository.addMessages(threadId2, [messageT2]); - }); - - it('should retrieve all messages for a specific thread, sorted by timestamp ascending', async () => { - const retrieved = await repository.getMessages(threadId1); - expect(retrieved).toHaveLength(3); - expect(retrieved.map(m => m.messageId)).toEqual(['msg-1', 'msg-2', 'msg-3']); - // Check if internal 'id' field is removed - expect(retrieved[0]).not.toHaveProperty('id'); - }); - - it('should return empty array for a thread with no messages', async () => { - const retrieved = await repository.getMessages('nonexistent-thread'); - expect(retrieved).toHaveLength(0); - }); - - it('should limit the number of messages returned (most recent)', async () => { - const options: MessageOptions = { limit: 2 }; - const retrieved = await repository.getMessages(threadId1, options); - expect(retrieved).toHaveLength(2); - expect(retrieved.map(m => m.messageId)).toEqual(['msg-2', 'msg-3']); // Most recent 2 - }); - - it('should handle limit greater than available messages', async () => { - const options: MessageOptions = { limit: 10 }; - const retrieved = await repository.getMessages(threadId1, options); - expect(retrieved).toHaveLength(3); - expect(retrieved.map(m => m.messageId)).toEqual(['msg-1', 'msg-2', 'msg-3']); - }); - - it('should handle limit of 0 or less (return empty or all? standard is empty)', async () => { - // Test case for limit: 0 - let options: MessageOptions = { limit: 0 }; - let retrieved = await repository.getMessages(threadId1, options); - // Depending on slice behavior with negative indices, this might return all or empty. - // Standard interpretation of limit 0 is usually "no limit" or "zero items". - // Our slice(-0) results in empty. Let's test for empty. - expect(retrieved).toHaveLength(0); - - // Test case for limit: -1 (or other negative) - options = { limit: -1 }; - retrieved = await repository.getMessages(threadId1, options); - // slice(-(-1)) -> slice(1) - this behavior might be unexpected. - // Let's clarify the expected behavior or adjust implementation. - // Current slice implementation `slice(-limit)`: slice(-(-1)) -> slice(1) -> returns all except first. - // A more robust limit implementation might clamp limit >= 0. - // For now, test current behavior: - expect(retrieved).toHaveLength(2); // Returns msg-2, msg-3 with slice(1) - // TODO: Consider adjusting repository logic to treat limit <= 0 as "no limit" or "zero items". - // For now, we test the implemented slice behavior. - }); - - - it('should retrieve messages before a specific timestamp', async () => { - const options: MessageOptions = { beforeTimestamp: now - 50 }; // Before T1 Msg 2 and T1 Msg 3 - const retrieved = await repository.getMessages(threadId1, options); - expect(retrieved).toHaveLength(1); - expect(retrieved[0].messageId).toBe('msg-1'); - }); - - it('should retrieve messages after a specific timestamp', async () => { - const options: MessageOptions = { afterTimestamp: now - 150 }; // After T1 Msg 1 - const retrieved = await repository.getMessages(threadId1, options); - expect(retrieved).toHaveLength(2); - expect(retrieved.map(m => m.messageId)).toEqual(['msg-2', 'msg-3']); - }); - - it('should retrieve messages between two timestamps', async () => { - const options: MessageOptions = { - afterTimestamp: now - 250, // After T1 Msg 1 - beforeTimestamp: now - 50, // Before T1 Msg 3 - }; - const retrieved = await repository.getMessages(threadId1, options); - expect(retrieved).toHaveLength(1); - expect(retrieved[0].messageId).toBe('msg-2'); - }); - - it('should apply limit together with timestamp filters', async () => { - const options: MessageOptions = { - afterTimestamp: now - 250, // After T1 Msg 1 (leaves msg-2, msg-3) - limit: 1, - }; - const retrieved = await repository.getMessages(threadId1, options); - expect(retrieved).toHaveLength(1); - expect(retrieved[0].messageId).toBe('msg-3'); // Limit applies last, gets most recent of the filtered set - }); - - it('should return messages correctly when using only limit', async () => { - const options: MessageOptions = { limit: 1 }; - const retrieved = await repository.getMessages(threadId1, options); - expect(retrieved).toHaveLength(1); - expect(retrieved[0].messageId).toBe('msg-3'); // Most recent - }); - }); -}); \ No newline at end of file diff --git a/src/systems/context/repositories/ConversationRepository.ts b/src/systems/context/repositories/ConversationRepository.ts old mode 100644 new mode 100755 index 5b95643..12ba0a3 --- a/src/systems/context/repositories/ConversationRepository.ts +++ b/src/systems/context/repositories/ConversationRepository.ts @@ -1,5 +1,5 @@ -import { IConversationRepository, StorageAdapter } from '../../../core/interfaces'; -import { ConversationMessage, MessageOptions } from '../../../types'; +import { IConversationRepository, StorageAdapter } from '@/core/interfaces'; +import { ConversationMessage, MessageOptions } from '@/types'; // Define the structure of the data as stored, including the 'id' field type StoredConversationMessage = ConversationMessage & { id: string }; @@ -9,7 +9,12 @@ type StoredConversationMessage = ConversationMessage & { id: string }; * manage `ConversationMessage` objects using an underlying `StorageAdapter`. * Handles adding and retrieving conversation history for specific threads. * - * @implements {IConversationRepository} + * It abstracts the underlying storage mechanism through the `StorageAdapter` interface, + * allowing for different storage backends (e.g., in-memory, IndexedDB, Supabase) + * to be used interchangeably. + * + * @see {@link IConversationRepository} for the interface it implements. + * @see {@link StorageAdapter} for the storage backend interface. */ export class ConversationRepository implements IConversationRepository { private adapter: StorageAdapter; @@ -17,7 +22,7 @@ export class ConversationRepository implements IConversationRepository { /** * Creates an instance of ConversationRepository. - * @param storageAdapter - The configured `StorageAdapter` instance that will be used for persistence. + * @param {StorageAdapter} storageAdapter - The configured `StorageAdapter` instance that will be used for persistence. */ constructor(storageAdapter: StorageAdapter) { if (!storageAdapter) { @@ -32,9 +37,9 @@ export class ConversationRepository implements IConversationRepository { /** * Adds one or more `ConversationMessage` objects to the storage for a specific thread. * It uses the `messageId` as the primary key for storage, assuming the adapter's collection uses 'id' as keyPath. - * @param threadId - The ID of the thread these messages belong to. Used for potential filtering/querying and validation. - * @param messages - An array of `ConversationMessage` objects to add. Each message should have a unique `messageId`. - * @returns A promise that resolves when all messages have been attempted to be saved. + * @param {string} threadId - The ID of the thread these messages belong to. Used for potential filtering/querying and validation. + * @param {ConversationMessage[]} messages - An array of `ConversationMessage` objects to add. Each message should have a unique `messageId`. + * @returns {Promise} A promise that resolves when all messages have been attempted to be saved. * @throws {Error} Propagates errors from the storage adapter's `set` method. */ async addMessages(threadId: string, messages: ConversationMessage[]): Promise { @@ -64,9 +69,9 @@ export class ConversationRepository implements IConversationRepository { * This implementation fetches all messages for the thread and then applies * sorting, filtering (by timestamp), and limiting client-side. * For performance with very large histories, adapter-level querying/indexing would be preferable. - * @param threadId - The ID of the thread whose messages are to be retrieved. - * @param options - Optional `MessageOptions` to control retrieval (limit, timestamp filters). - * @returns A promise resolving to an array of `ConversationMessage` objects, sorted chronologically (ascending timestamp). + * @param {string} threadId - The ID of the thread whose messages are to be retrieved. + * @param {MessageOptions} [options] - Optional `MessageOptions` to control retrieval (limit, timestamp filters). + * @returns {Promise} A promise resolving to an array of `ConversationMessage` objects, sorted chronologically (ascending timestamp). * @throws {Error} Propagates errors from the storage adapter's `query` method. */ async getMessages(threadId: string, options?: MessageOptions): Promise { diff --git a/src/systems/context/repositories/ObservationRepository.test.ts b/src/systems/context/repositories/ObservationRepository.test.ts deleted file mode 100644 index db101ab..0000000 --- a/src/systems/context/repositories/ObservationRepository.test.ts +++ /dev/null @@ -1,163 +0,0 @@ -import { describe, it, expect, beforeEach } from 'vitest'; -import { ObservationRepository } from './ObservationRepository'; -import { InMemoryStorageAdapter } from '../../../adapters/storage/inMemory'; -import { Observation, ObservationType, ObservationFilter } from '../../../types'; -import { IObservationRepository } from '../../../core/interfaces'; - -// Helper to create observations -const createObservation = (id: string, threadId: string, timestamp: number, type: ObservationType, title: string, content: any): Observation => ({ - id: id, - threadId: threadId, - timestamp: timestamp, - type: type, - title: title, - content: content, -}); - -describe('ObservationRepository', () => { - let mockAdapter: InMemoryStorageAdapter; - let repository: IObservationRepository; // Use interface type - const threadId1 = 'obs-thread-1'; - const threadId2 = 'obs-thread-2'; - - beforeEach(() => { - mockAdapter = new InMemoryStorageAdapter(); - repository = new ObservationRepository(mockAdapter); - }); - - describe('addObservation', () => { - it('should add a single observation to the correct collection', async () => { - const now = Date.now(); - const observation = createObservation('obs-1', threadId1, now, ObservationType.INTENT, 'User Intent', { text: 'find flights' }); - await repository.addObservation(observation); - - // Verify using the adapter directly - const stored = await mockAdapter.get('observations', 'obs-1'); - expect(stored).toBeDefined(); - expect(stored?.id).toBe('obs-1'); - expect(stored?.threadId).toBe(threadId1); - expect(stored?.type).toBe(ObservationType.INTENT); - expect(stored?.content).toEqual({ text: 'find flights' }); - }); - - it('should reject adding an observation without an id', async () => { - const observation = { - // id: 'missing', // ID is missing - threadId: threadId1, - timestamp: Date.now(), - type: ObservationType.ERROR, - title: 'Error Occurred', - content: { message: 'Something failed' } - } as any; // Cast to bypass compile-time check - await expect(repository.addObservation(observation)).rejects.toThrow(/Observation must have an 'id' property/); - }); - - it('should overwrite an existing observation with the same id', async () => { - const now = Date.now(); - const obs1 = createObservation('obs-overwrite', threadId1, now, ObservationType.PLAN, 'Initial Plan', { steps: 1 }); - const obs2 = createObservation('obs-overwrite', threadId1, now + 10, ObservationType.PLAN, 'Updated Plan', { steps: 2 }); // Same ID - - await repository.addObservation(obs1); - await repository.addObservation(obs2); // Should overwrite - - const stored = await mockAdapter.get('observations', 'obs-overwrite'); - expect(stored).toBeDefined(); - expect(stored?.title).toBe('Updated Plan'); - expect(stored?.content).toEqual({ steps: 2 }); - expect(stored?.timestamp).toBe(now + 10); - }); - }); - - describe('getObservations', () => { - const now = Date.now(); - const observationsT1 = [ - createObservation('t1-obs1', threadId1, now - 200, ObservationType.INTENT, 'Intent 1', {}), // Oldest - createObservation('t1-obs2', threadId1, now - 100, ObservationType.PLAN, 'Plan 1', {}), - createObservation('t1-obs3', threadId1, now, ObservationType.TOOL_CALL, 'Tool Call 1', {}), // Newest - ]; - const observationT2 = createObservation('t2-obs1', threadId2, now - 50, ObservationType.INTENT, 'Intent 2', {}); - - beforeEach(async () => { - // Seed observations using the repository's add method - for (const obs of observationsT1) { - await repository.addObservation(obs); - } - await repository.addObservation(observationT2); - }); - - it('should retrieve all observations for a specific thread, sorted by timestamp ascending', async () => { - const retrieved = await repository.getObservations(threadId1); - expect(retrieved).toHaveLength(3); - expect(retrieved.map(o => o.id)).toEqual(['t1-obs1', 't1-obs2', 't1-obs3']); - }); - - it('should return empty array for a thread with no observations', async () => { - const retrieved = await repository.getObservations('nonexistent-thread'); - expect(retrieved).toHaveLength(0); - }); - - it('should filter observations by type', async () => { - const filter: ObservationFilter = { types: [ObservationType.INTENT] }; - const retrieved = await repository.getObservations(threadId1, filter); - expect(retrieved).toHaveLength(1); - expect(retrieved[0].id).toBe('t1-obs1'); - expect(retrieved[0].type).toBe(ObservationType.INTENT); - }); - - it('should filter observations by multiple types', async () => { - const filter: ObservationFilter = { types: [ObservationType.PLAN, ObservationType.TOOL_CALL] }; - const retrieved = await repository.getObservations(threadId1, filter); - expect(retrieved).toHaveLength(2); - expect(retrieved.map(o => o.id)).toEqual(['t1-obs2', 't1-obs3']); // Sorted by timestamp - expect(retrieved.map(o => o.type)).toEqual(expect.arrayContaining([ObservationType.PLAN, ObservationType.TOOL_CALL])); - }); - - it('should return empty array if filter types match no observations', async () => { - const filter: ObservationFilter = { types: [ObservationType.ERROR] }; - const retrieved = await repository.getObservations(threadId1, filter); - expect(retrieved).toHaveLength(0); - }); - - it('should ignore empty type filter array', async () => { - const filter: ObservationFilter = { types: [] }; - const retrieved = await repository.getObservations(threadId1, filter); - expect(retrieved).toHaveLength(3); // Should return all - }); - - it('should retrieve observations before a specific timestamp', async () => { - const filter: ObservationFilter = { beforeTimestamp: now - 50 }; // Before t1-obs2 and t1-obs3 - const retrieved = await repository.getObservations(threadId1, filter); - expect(retrieved).toHaveLength(1); - expect(retrieved[0].id).toBe('t1-obs1'); - }); - - it('should retrieve observations after a specific timestamp', async () => { - const filter: ObservationFilter = { afterTimestamp: now - 150 }; // After t1-obs1 - const retrieved = await repository.getObservations(threadId1, filter); - expect(retrieved).toHaveLength(2); - expect(retrieved.map(o => o.id)).toEqual(['t1-obs2', 't1-obs3']); - }); - - it('should retrieve observations between two timestamps', async () => { - const filter: ObservationFilter = { - afterTimestamp: now - 250, // After t1-obs1 - beforeTimestamp: now - 50, // Before t1-obs3 - }; - const retrieved = await repository.getObservations(threadId1, filter); - expect(retrieved).toHaveLength(1); - expect(retrieved[0].id).toBe('t1-obs2'); - }); - - it('should apply type and timestamp filters together', async () => { - const filter: ObservationFilter = { - types: [ObservationType.PLAN, ObservationType.TOOL_CALL], // t1-obs2, t1-obs3 - afterTimestamp: now - 150, // After t1-obs1 (doesn't change selection) - beforeTimestamp: now, // Before t1-obs3 - }; - const retrieved = await repository.getObservations(threadId1, filter); - expect(retrieved).toHaveLength(1); - expect(retrieved[0].id).toBe('t1-obs2'); // Only PLAN matches both filters - expect(retrieved[0].type).toBe(ObservationType.PLAN); - }); - }); -}); \ No newline at end of file diff --git a/src/systems/context/repositories/ObservationRepository.ts b/src/systems/context/repositories/ObservationRepository.ts old mode 100644 new mode 100755 index 88e0c77..17c946c --- a/src/systems/context/repositories/ObservationRepository.ts +++ b/src/systems/context/repositories/ObservationRepository.ts @@ -1,5 +1,5 @@ -import { IObservationRepository, StorageAdapter } from '../../../core/interfaces'; -import { Observation, ObservationFilter } from '../../../types'; +import { IObservationRepository, StorageAdapter } from '@/core/interfaces'; +import { Observation, ObservationFilter } from '@/types'; // Observation already has an 'id' field, so no need for a separate Stored type usually. // However, ensure the StorageAdapter expects 'id' as the keyPath for the 'observations' store. @@ -9,7 +9,12 @@ import { Observation, ObservationFilter } from '../../../types'; * manage `Observation` objects using an underlying `StorageAdapter`. * Handles adding and retrieving observations for specific threads. * - * @implements {IObservationRepository} + * It relies on a `StorageAdapter` to abstract the actual storage mechanism, + * making it compatible with different backends like IndexedDB, Supabase, or + * in-memory storage. + * + * @see {@link IObservationRepository} for the interface it implements. + * @see {@link StorageAdapter} for the storage backend interface. */ export class ObservationRepository implements IObservationRepository { private adapter: StorageAdapter; @@ -17,7 +22,7 @@ export class ObservationRepository implements IObservationRepository { /** * Creates an instance of ObservationRepository. - * @param storageAdapter - The configured `StorageAdapter` instance that will be used for persistence. + * @param {StorageAdapter} storageAdapter - The configured `StorageAdapter` instance that will be used for persistence. */ constructor(storageAdapter: StorageAdapter) { if (!storageAdapter) { @@ -31,8 +36,8 @@ export class ObservationRepository implements IObservationRepository { /** * Adds a single `Observation` object to the storage using its `id` as the key. - * @param observation - The `Observation` object to add. Must have a valid `id`. - * @returns A promise that resolves when the observation has been saved. + * @param {Observation} observation - The `Observation` object to add. Must have a valid `id`. + * @returns {Promise} A promise that resolves when the observation has been saved. * @throws {Error} If the observation is missing an `id` or if the storage adapter fails. */ async addObservation(observation: Observation): Promise { @@ -48,9 +53,9 @@ export class ObservationRepository implements IObservationRepository { * This implementation fetches all observations for the thread and then applies * client-side filtering (by type, timestamp) and sorting (by timestamp). * For performance with many observations, adapter-level querying/indexing would be preferable. - * @param threadId - The ID of the thread whose observations are to be retrieved. - * @param filter - Optional `ObservationFilter` criteria (e.g., `types`, `beforeTimestamp`, `afterTimestamp`). - * @returns A promise resolving to an array of `Observation` objects matching the criteria, sorted chronologically (ascending timestamp). + * @param {string} threadId - The ID of the thread whose observations are to be retrieved. + * @param {ObservationFilter} [filter] - Optional `ObservationFilter` criteria (e.g., `types`, `beforeTimestamp`, `afterTimestamp`). + * @returns {Promise} A promise resolving to an array of `Observation` objects matching the criteria, sorted chronologically (ascending timestamp). * @throws {Error} Propagates errors from the storage adapter's `query` method. */ async getObservations(threadId: string, filter?: ObservationFilter): Promise { diff --git a/src/systems/context/repositories/StateRepository.test.ts b/src/systems/context/repositories/StateRepository.test.ts deleted file mode 100644 index 4d77fbd..0000000 --- a/src/systems/context/repositories/StateRepository.test.ts +++ /dev/null @@ -1,202 +0,0 @@ -import { describe, it, expect, beforeEach } from 'vitest'; -import { StateRepository } from './StateRepository'; -import { InMemoryStorageAdapter } from '../../../adapters/storage/inMemory'; -import { ThreadContext, ThreadConfig, AgentState } from '../../../types'; -import { IStateRepository } from '../../../core/interfaces'; - -// Helper to create default config/state -const createDefaultConfig = (provider = 'test-provider', model = 'test-model'): ThreadConfig => ({ - reasoning: { provider, model }, - enabledTools: ['tool1', 'tool2'], - historyLimit: 10, - systemPrompt: 'Test system prompt', -}); - -const createDefaultState = (prefs: Record = { theme: 'dark' }): AgentState => ({ - userPreferences: prefs, - lastInteraction: Date.now(), -}); - -describe('StateRepository', () => { - let mockAdapter: InMemoryStorageAdapter; - let repository: IStateRepository; - const threadId1 = 'state-thread-1'; - // const threadId2 = 'state-thread-2'; // Removed unused variable - const collectionName = 'state'; // Match the repository's internal collection name - - beforeEach(() => { - mockAdapter = new InMemoryStorageAdapter(); - repository = new StateRepository(mockAdapter); - }); - - describe('setThreadContext / getThreadContext', () => { - it('should set and get a full thread context', async () => { - const config = createDefaultConfig(); - const state = createDefaultState(); - const context: ThreadContext = { config, state }; - - await repository.setThreadContext(threadId1, context); - - const retrieved = await repository.getThreadContext(threadId1); - expect(retrieved).toEqual(context); - expect(retrieved).not.toHaveProperty('id'); // Ensure internal 'id' is removed - }); - - it('should set and get a context with null state', async () => { - const config = createDefaultConfig(); - const context: ThreadContext = { config, state: null }; - - await repository.setThreadContext(threadId1, context); - - const retrieved = await repository.getThreadContext(threadId1); - expect(retrieved).toEqual(context); - expect(retrieved?.state).toBeNull(); - }); - - it('should overwrite existing context on setThreadContext', async () => { - const initialContext: ThreadContext = { config: createDefaultConfig('p1', 'm1'), state: createDefaultState({ pref: 'a' }) }; - const updatedContext: ThreadContext = { config: createDefaultConfig('p2', 'm2'), state: createDefaultState({ pref: 'b' }) }; - - await repository.setThreadContext(threadId1, initialContext); - await repository.setThreadContext(threadId1, updatedContext); - - const retrieved = await repository.getThreadContext(threadId1); - expect(retrieved).toEqual(updatedContext); - }); - - it('should return null when getting context for a non-existent thread', async () => { - const retrieved = await repository.getThreadContext('nonexistent-thread'); - expect(retrieved).toBeNull(); - }); - - it('should reject setting context if config is missing', async () => { - const invalidContext = { state: createDefaultState() } as any; // Missing config - await expect(repository.setThreadContext(threadId1, invalidContext)) - .rejects.toThrow(/must contain a 'config' property/); - }); - - it('should store the context under the threadId key in the adapter', async () => { - const config = createDefaultConfig(); - const state = createDefaultState(); - const context: ThreadContext = { config, state }; - await repository.setThreadContext(threadId1, context); - - // Verify using adapter directly - const storedRaw = await mockAdapter.get(collectionName, threadId1); - expect(storedRaw).toBeDefined(); - expect(storedRaw?.id).toBe(threadId1); - expect(storedRaw?.config).toEqual(config); - expect(storedRaw?.state).toEqual(state); - }); - }); - - describe('setThreadConfig / getThreadConfig', () => { - it('should set and get thread config when no context exists', async () => { - const config = createDefaultConfig(); - await repository.setThreadConfig(threadId1, config); - - const retrievedConfig = await repository.getThreadConfig(threadId1); - expect(retrievedConfig).toEqual(config); - - // Verify underlying context has null state - const retrievedContext = await repository.getThreadContext(threadId1); - expect(retrievedContext?.config).toEqual(config); - expect(retrievedContext?.state).toBeNull(); - }); - - it('should update config and preserve existing state', async () => { - const initialConfig = createDefaultConfig('p1', 'm1'); - const initialState = createDefaultState({ pref: 'a' }); - const initialContext: ThreadContext = { config: initialConfig, state: initialState }; - await repository.setThreadContext(threadId1, initialContext); - - const updatedConfig = createDefaultConfig('p2', 'm2'); - await repository.setThreadConfig(threadId1, updatedConfig); - - const retrievedConfig = await repository.getThreadConfig(threadId1); - expect(retrievedConfig).toEqual(updatedConfig); - - // Verify state was preserved - const retrievedContext = await repository.getThreadContext(threadId1); - expect(retrievedContext?.config).toEqual(updatedConfig); - expect(retrievedContext?.state).toEqual(initialState); - }); - - it('should return null when getting config for a non-existent thread', async () => { - const retrieved = await repository.getThreadConfig('nonexistent-thread'); - expect(retrieved).toBeNull(); - }); - }); - - describe('setAgentState / getAgentState', () => { - it('should reject setting state if no config exists for the thread', async () => { - const state = createDefaultState(); - await expect(repository.setAgentState(threadId1, state)) - .rejects.toThrow(/Cannot set AgentState.*because no ThreadConfig exists/); - }); - - it('should set and get agent state when config exists', async () => { - // First, set up config - const config = createDefaultConfig(); - await repository.setThreadConfig(threadId1, config); - - // Now set state - const state = createDefaultState({ pref: 'xyz' }); - await repository.setAgentState(threadId1, state); - - const retrievedState = await repository.getAgentState(threadId1); - expect(retrievedState).toEqual(state); - - // Verify context integrity - const retrievedContext = await repository.getThreadContext(threadId1); - expect(retrievedContext?.config).toEqual(config); - expect(retrievedContext?.state).toEqual(state); - }); - - it('should update existing state and preserve config', async () => { - const initialConfig = createDefaultConfig(); - const initialState = createDefaultState({ pref: 'a' }); - await repository.setThreadContext(threadId1, { config: initialConfig, state: initialState }); - - const updatedState = createDefaultState({ pref: 'b', other: true }); - await repository.setAgentState(threadId1, updatedState); - - const retrievedState = await repository.getAgentState(threadId1); - expect(retrievedState).toEqual(updatedState); - - // Verify config was preserved - const retrievedContext = await repository.getThreadContext(threadId1); - expect(retrievedContext?.config).toEqual(initialConfig); - expect(retrievedContext?.state).toEqual(updatedState); - }); - - it('should allow setting state to null', async () => { - const config = createDefaultConfig(); - const initialState = createDefaultState(); - await repository.setThreadContext(threadId1, { config, state: initialState }); - - await repository.setAgentState(threadId1, null as any); // Set state to null - - const retrievedState = await repository.getAgentState(threadId1); - expect(retrievedState).toBeNull(); - - const retrievedContext = await repository.getThreadContext(threadId1); - expect(retrievedContext?.config).toEqual(config); - expect(retrievedContext?.state).toBeNull(); - }); - - - it('should return null when getting state for a thread with config but null state', async () => { - const config = createDefaultConfig(); - await repository.setThreadConfig(threadId1, config); // Context has null state initially - - const retrieved = await repository.getAgentState(threadId1); - expect(retrieved).toBeNull(); - }); - - it('should return null when getting state for a non-existent thread', async () => { - const retrieved = await repository.getAgentState('nonexistent-thread'); - expect(retrieved).toBeNull(); - }); - }); -}); \ No newline at end of file diff --git a/src/systems/context/repositories/StateRepository.ts b/src/systems/context/repositories/StateRepository.ts old mode 100644 new mode 100755 index 6d79af1..efb57ce --- a/src/systems/context/repositories/StateRepository.ts +++ b/src/systems/context/repositories/StateRepository.ts @@ -1,5 +1,5 @@ -import { IStateRepository, StorageAdapter } from '../../../core/interfaces'; -import { ThreadContext, ThreadConfig, AgentState } from '../../../types'; +import { IStateRepository, StorageAdapter } from '@/core/interfaces'; +import { ThreadContext, ThreadConfig, AgentState } from '@/types'; // Define the structure of the data as stored, including the 'id' field (threadId) type StoredThreadContext = ThreadContext & { id: string }; @@ -10,7 +10,12 @@ type StoredThreadContext = ThreadContext & { id: string }; * underlying `StorageAdapter`. It stores the entire context object for each thread * under a key equal to the `threadId` within a designated collection (default: 'state'). * - * @implements {IStateRepository} + * It uses a `StorageAdapter` to abstract the underlying storage, allowing for + * flexibility in choosing storage backends (e.g., in-memory, IndexedDB, Supabase). + * This repository is responsible for CRUD operations on thread state and configuration. + * + * @see {@link IStateRepository} for the interface it implements. + * @see {@link StorageAdapter} for the storage backend interface. */ export class StateRepository implements IStateRepository { private adapter: StorageAdapter; @@ -18,7 +23,7 @@ export class StateRepository implements IStateRepository { /** * Creates an instance of StateRepository. - * @param storageAdapter - The configured `StorageAdapter` instance used for persistence. + * @param {StorageAdapter} storageAdapter - The configured `StorageAdapter` instance used for persistence. */ constructor(storageAdapter: StorageAdapter) { if (!storageAdapter) { @@ -29,10 +34,9 @@ export class StateRepository implements IStateRepository { } /** - /** * Retrieves the complete `ThreadContext` (config and state) for a specific thread ID. - * @param threadId - The unique identifier of the thread. - * @returns A promise resolving to the `ThreadContext` object if found, or `null` otherwise. + * @param {string} threadId - The unique identifier of the thread. + * @returns {Promise} A promise resolving to the `ThreadContext` object if found, or `null` otherwise. * @throws {Error} Propagates errors from the storage adapter's `get` method. */ async getThreadContext(threadId: string): Promise { @@ -48,12 +52,11 @@ export class StateRepository implements IStateRepository { } /** - /** * Saves (or overwrites) the complete `ThreadContext` for a specific thread ID. * Ensures the context object includes the `threadId` as the `id` property for storage. - * @param threadId - The unique identifier of the thread. - * @param context - The `ThreadContext` object to save. Must contain at least the `config` property. - * @returns A promise that resolves when the context is successfully saved. + * @param {string} threadId - The unique identifier of the thread. + * @param {ThreadContext} context - The `ThreadContext` object to save. Must contain at least the `config` property. + * @returns {Promise} A promise that resolves when the context is successfully saved. * @throws {Error} If the context is missing the required `config` property or if the storage adapter fails. */ async setThreadContext(threadId: string, context: ThreadContext): Promise { @@ -69,10 +72,9 @@ export class StateRepository implements IStateRepository { } /** - /** * Retrieves only the `ThreadConfig` part of the context for a specific thread ID. - * @param threadId - The unique identifier of the thread. - * @returns A promise resolving to the `ThreadConfig` object if found, or `null` otherwise. + * @param {string} threadId - The unique identifier of the thread. + * @returns {Promise} A promise resolving to the `ThreadConfig` object if found, or `null` otherwise. * @throws {Error} Propagates errors from the underlying `getThreadContext` call. */ async getThreadConfig(threadId: string): Promise { @@ -81,13 +83,12 @@ export class StateRepository implements IStateRepository { } /** - /** * Sets or updates only the `ThreadConfig` part of the context for a specific thread ID. * It fetches the existing context, replaces the `config` field, preserves the existing `state` (or sets it to null if none existed), * and then saves the entire updated `ThreadContext` back to storage. - * @param threadId - The unique identifier of the thread. - * @param config - The `ThreadConfig` object to save. - * @returns A promise that resolves when the updated context is saved. + * @param {string} threadId - The unique identifier of the thread. + * @param {ThreadConfig} config - The `ThreadConfig` object to save. + * @returns {Promise} A promise that resolves when the updated context is saved. * @throws {Error} Propagates errors from the underlying `getThreadContext` or `setThreadContext` calls. */ async setThreadConfig(threadId: string, config: ThreadConfig): Promise { @@ -100,10 +101,9 @@ export class StateRepository implements IStateRepository { } /** - /** * Retrieves only the `AgentState` part of the context for a specific thread ID. - * @param threadId - The unique identifier of the thread. - * @returns A promise resolving to the `AgentState` object if found and not null, or `null` otherwise. + * @param {string} threadId - The unique identifier of the thread. + * @returns {Promise} A promise resolving to the `AgentState` object if found and not null, or `null` otherwise. * @throws {Error} Propagates errors from the underlying `getThreadContext` call. */ async getAgentState(threadId: string): Promise { @@ -112,15 +112,14 @@ export class StateRepository implements IStateRepository { } /** - /** * Sets or updates only the `AgentState` part of the context for a specific thread ID. * It fetches the existing context, replaces the `state` field, preserves the existing `config`, * and then saves the entire updated `ThreadContext` back to storage. * **Important:** This method requires that a `ThreadConfig` already exists for the thread. * Attempting to set state for a thread without prior configuration will result in an error. - * @param threadId - The unique identifier of the thread. - * @param state - The `AgentState` object to save. - * @returns A promise that resolves when the updated context is saved. + * @param {string} threadId - The unique identifier of the thread. + * @param {AgentState} state - The `AgentState` object to save. + * @returns {Promise} A promise that resolves when the updated context is saved. * @throws {Error} If no `ThreadConfig` exists for the `threadId`, or if errors occur during context retrieval or saving. */ async setAgentState(threadId: string, state: AgentState): Promise { diff --git a/src/systems/context/repositories/TaskStatusRepository.ts b/src/systems/context/repositories/TaskStatusRepository.ts new file mode 100755 index 0000000..9d3ef01 --- /dev/null +++ b/src/systems/context/repositories/TaskStatusRepository.ts @@ -0,0 +1,325 @@ +import { IA2ATaskRepository, StorageAdapter } from '@/core/interfaces'; +import { A2ATask, A2ATaskStatus, A2ATaskPriority, ARTError, ErrorCode } from '@/types'; + +// Define the structure of the data as stored, including the 'id' field (taskId) +type StoredA2ATask = A2ATask & { id: string }; + +/** + * Implements the `IA2ATaskRepository` interface, providing methods to manage + * `A2ATask` objects using an underlying `StorageAdapter`. Handles creating, + * retrieving, updating, and deleting A2A (Agent-to-Agent) tasks, as well as + * filtering tasks by various criteria such as thread, agent, and status. + * + * @see {@link IA2ATaskRepository} for the interface it implements. + * @see {@link StorageAdapter} for the storage backend interface. + */ +export class TaskStatusRepository implements IA2ATaskRepository { + private adapter: StorageAdapter; + private readonly collectionName = 'a2a_tasks'; // Define the collection name + + /** + * Creates an instance of TaskStatusRepository. + * @param {StorageAdapter} storageAdapter - The configured `StorageAdapter` instance used for persistence. + */ + constructor(storageAdapter: StorageAdapter) { + if (!storageAdapter) { + throw new Error("TaskStatusRepository requires a valid StorageAdapter instance."); + } + this.adapter = storageAdapter; + // Note: Adapter initialization (adapter.init()) should be handled externally. + } + + /** + * Creates a new A2A task in the repository. + * @param {A2ATask} task - The A2ATask object to create. + * @returns {Promise} A promise that resolves when the task is successfully stored. + * @throws {ARTError} If the task cannot be created (e.g., duplicate taskId, validation errors). + */ + async createTask(task: A2ATask): Promise { + if (!task || !task.taskId) { + throw new ARTError('Task must have a valid taskId', ErrorCode.VALIDATION_ERROR); + } + + // Check if task already exists + const existingTask = await this.adapter.get(this.collectionName, task.taskId); + if (existingTask) { + throw new ARTError(`Task with ID '${task.taskId}' already exists`, ErrorCode.DUPLICATE_TASK_ID); + } + + // Add the 'id' field mirroring 'taskId' for compatibility with keyPath='id' adapters + const taskToStore: StoredA2ATask = { + ...task, + id: task.taskId + }; + + await this.adapter.set(this.collectionName, task.taskId, taskToStore); + } + + /** + * Retrieves an A2A task by its unique identifier. + * @param {string} taskId - The unique identifier of the task. + * @returns {Promise} A promise resolving to the A2ATask object if found, or null if not found. + * @throws {ARTError} If an error occurs during retrieval. + */ + async getTask(taskId: string): Promise { + if (!taskId) { + throw new ARTError('TaskId is required', ErrorCode.VALIDATION_ERROR); + } + + try { + const storedTask = await this.adapter.get(this.collectionName, taskId); + if (!storedTask) { + return null; + } + + // Remove the internal 'id' field before returning + const task = { ...storedTask }; + delete (task as Partial).id; + return task as A2ATask; + } catch (error) { + throw new ARTError(`Failed to retrieve task '${taskId}': ${error}`, ErrorCode.REPOSITORY_ERROR); + } + } + + /** + * Updates an existing A2A task with new information. + * @param {string} taskId - The unique identifier of the task to update. + * @param {Partial} updates - Partial A2ATask object containing the fields to update. + * @returns {Promise} A promise that resolves when the task is successfully updated. + * @throws {ARTError} If the task is not found or cannot be updated. + */ + async updateTask(taskId: string, updates: Partial): Promise { + if (!taskId) { + throw new ARTError('TaskId is required', ErrorCode.VALIDATION_ERROR); + } + + if (!updates || Object.keys(updates).length === 0) { + throw new ARTError('Updates object cannot be empty', ErrorCode.VALIDATION_ERROR); + } + + try { + // Get the existing task + const existingTask = await this.adapter.get(this.collectionName, taskId); + if (!existingTask) { + throw new ARTError(`Task with ID '${taskId}' not found`, ErrorCode.TASK_NOT_FOUND); + } + + // Merge updates with existing task + const updatedTask: StoredA2ATask = { + ...existingTask, + ...updates, + taskId, // Ensure taskId cannot be changed + id: taskId // Ensure consistency + }; + + // Update metadata if provided + if (updates.metadata) { + updatedTask.metadata = { + ...existingTask.metadata, + ...updates.metadata, + lastUpdated: Date.now() // Always update timestamp + }; + } + + await this.adapter.set(this.collectionName, taskId, updatedTask); + } catch (error) { + if (error instanceof ARTError) { + throw error; + } + throw new ARTError(`Failed to update task '${taskId}': ${error}`, ErrorCode.REPOSITORY_ERROR); + } + } + + /** + * Removes an A2A task from the repository. + * @param {string} taskId - The unique identifier of the task to delete. + * @returns {Promise} A promise that resolves when the task is successfully deleted. + * @throws {ARTError} If the task is not found or cannot be deleted. + */ + async deleteTask(taskId: string): Promise { + if (!taskId) { + throw new ARTError('TaskId is required', ErrorCode.VALIDATION_ERROR); + } + + try { + // Check if task exists + const existingTask = await this.adapter.get(this.collectionName, taskId); + if (!existingTask) { + throw new ARTError(`Task with ID '${taskId}' not found`, ErrorCode.TASK_NOT_FOUND); + } + + await this.adapter.delete(this.collectionName, taskId); + } catch (error) { + if (error instanceof ARTError) { + throw error; + } + throw new ARTError(`Failed to delete task '${taskId}': ${error}`, ErrorCode.REPOSITORY_ERROR); + } + } + + /** + * Retrieves tasks associated with a specific thread. + * @param {string} threadId - The thread identifier to filter tasks. + * @param {object} [filter] - Optional filter criteria for task status, priority, or assigned agent. + * @returns {Promise} A promise resolving to an array of A2ATask objects matching the criteria. + */ + async getTasksByThread( + threadId: string, + filter?: { + status?: A2ATaskStatus | A2ATaskStatus[]; + priority?: A2ATaskPriority; + assignedAgentId?: string; + } + ): Promise { + if (!threadId) { + throw new ARTError('ThreadId is required', ErrorCode.VALIDATION_ERROR); + } + + try { + // Query tasks for the specific thread + const queryResults = await this.adapter.query(this.collectionName, { + filter: { threadId: threadId } + }); + + // Apply additional client-side filtering + let filteredTasks = queryResults; + + if (filter) { + if (filter.status) { + const statusArray = Array.isArray(filter.status) ? filter.status : [filter.status]; + filteredTasks = filteredTasks.filter(task => statusArray.includes(task.status)); + } + + if (filter.priority) { + filteredTasks = filteredTasks.filter(task => task.priority === filter.priority); + } + + if (filter.assignedAgentId) { + filteredTasks = filteredTasks.filter(task => + task.targetAgent?.agentId === filter.assignedAgentId + ); + } + } + + // Sort by creation timestamp (newest first) + filteredTasks.sort((a, b) => (b.metadata?.createdAt || 0) - (a.metadata?.createdAt || 0)); + + // Remove the 'id' field from results + return this._removeIdField(filteredTasks); + } catch (error) { + throw new ARTError(`Failed to get tasks for thread '${threadId}': ${error}`, ErrorCode.REPOSITORY_ERROR); + } + } + + /** + * Retrieves tasks assigned to a specific agent. + * @param {string} agentId - The agent identifier to filter tasks. + * @param {object} [filter] - Optional filter criteria for task status or priority. + * @returns {Promise} A promise resolving to an array of A2ATask objects assigned to the agent. + */ + async getTasksByAgent( + agentId: string, + filter?: { + status?: A2ATaskStatus | A2ATaskStatus[]; + priority?: A2ATaskPriority; + } + ): Promise { + if (!agentId) { + throw new ARTError('AgentId is required', ErrorCode.VALIDATION_ERROR); + } + + try { + // Query all tasks and filter client-side (storage adapters may not support nested filtering) + const queryResults = await this.adapter.query(this.collectionName, { + filter: {} // Get all tasks, then filter client-side + }); + + // Filter by assigned agent + let filteredTasks = queryResults.filter(task => + task.targetAgent?.agentId === agentId + ); + + // Apply additional filters + if (filter) { + if (filter.status) { + const statusArray = Array.isArray(filter.status) ? filter.status : [filter.status]; + filteredTasks = filteredTasks.filter(task => statusArray.includes(task.status)); + } + + if (filter.priority) { + filteredTasks = filteredTasks.filter(task => task.priority === filter.priority); + } + } + + // Sort by creation timestamp (newest first) + filteredTasks.sort((a, b) => (b.metadata?.createdAt || 0) - (a.metadata?.createdAt || 0)); + + // Remove the 'id' field from results + return this._removeIdField(filteredTasks); + } catch (error) { + throw new ARTError(`Failed to get tasks for agent '${agentId}': ${error}`, ErrorCode.REPOSITORY_ERROR); + } + } + + /** + * Retrieves tasks based on their current status. + * @param {A2ATaskStatus | A2ATaskStatus[]} status - The task status(es) to filter by. + * @param {object} [options] - Optional query parameters like limit and pagination. + * @returns {Promise} A promise resolving to an array of A2ATask objects with the specified status. + */ + async getTasksByStatus( + status: A2ATaskStatus | A2ATaskStatus[], + options?: { limit?: number; offset?: number } + ): Promise { + if (!status) { + throw new ARTError('Status is required', ErrorCode.VALIDATION_ERROR); + } + + try { + // Query all tasks (since we need to filter by status client-side) + const queryResults = await this.adapter.query(this.collectionName, { + filter: {} // Get all, then filter client-side + }); + + // Filter by status + const statusArray = Array.isArray(status) ? status : [status]; + let filteredTasks = queryResults.filter(task => statusArray.includes(task.status)); + + // Sort by creation timestamp (newest first) + filteredTasks.sort((a, b) => (b.metadata?.createdAt || 0) - (a.metadata?.createdAt || 0)); + + // Apply pagination + if (options) { + const offset = options.offset || 0; + const limit = options.limit; + + if (offset > 0) { + filteredTasks = filteredTasks.slice(offset); + } + + if (limit && limit > 0) { + filteredTasks = filteredTasks.slice(0, limit); + } + } + + // Remove the 'id' field from results + return this._removeIdField(filteredTasks); + } catch (error) { + throw new ARTError(`Failed to get tasks by status: ${error}`, ErrorCode.REPOSITORY_ERROR); + } + } + + /** + * Utility method to remove the internal 'id' field from stored tasks before returning them. + * @private + * @param {StoredA2ATask[]} tasks - Array of StoredA2ATask objects. + * @returns {A2ATask[]} Array of A2ATask objects with 'id' field removed. + */ + private _removeIdField(tasks: StoredA2ATask[]): A2ATask[] { + return tasks.map(task => { + const cleanTask = { ...task }; + delete (cleanTask as Partial).id; + return cleanTask as A2ATask; + }); + } +} \ No newline at end of file diff --git a/src/systems/mcp/ConfigManager.ts b/src/systems/mcp/ConfigManager.ts new file mode 100755 index 0000000..2d6d648 --- /dev/null +++ b/src/systems/mcp/ConfigManager.ts @@ -0,0 +1,205 @@ +import { Logger } from '@/utils/logger'; +import { ArtMcpConfig, McpServerConfig } from './types'; + +/** + * Manages the MCP configuration, handling loading, validation, and saving to localStorage. + * It ensures that the MCP connection details are always available and well-formed. + */ +export class ConfigManager { + private configKey = 'art_mcp_config'; + private config: ArtMcpConfig; + + /** + * Initializes the ConfigManager by loading the configuration from localStorage. + */ + constructor() { + this.config = this.loadConfig(); + } + + /** + * Loads the MCP configuration from localStorage, creating a default if none exists. + * @private + * @returns {ArtMcpConfig} The loaded or created MCP configuration. + */ + private loadConfig(): ArtMcpConfig { + try { + const storedConfig = localStorage.getItem(this.configKey); + if (storedConfig) { + const rawConfig = JSON.parse(storedConfig) as ArtMcpConfig; + const validatedConfig = this.validateAndFixConfig(rawConfig); + + // If config was fixed, save it back + if (JSON.stringify(validatedConfig) !== JSON.stringify(rawConfig)) { + Logger.info(`ConfigManager: Config was automatically validated and fixed`); + this.writeConfig(validatedConfig); + } + return validatedConfig; + } + } catch (error: any) { + Logger.error(`ConfigManager: Error reading or parsing config from localStorage: ${error.message}`); + } + + Logger.info(`ConfigManager: Configuration not found in localStorage. Creating a new default config.`); + const defaultConfig = this.createDefaultConfig(); + this.writeConfig(defaultConfig); + return defaultConfig; + } + + /** + * Validates the loaded configuration and fixes any inconsistencies. + * @private + * @param {ArtMcpConfig} config - The configuration to validate. + * @returns {ArtMcpConfig} The validated and fixed configuration. + */ + private validateAndFixConfig(config: ArtMcpConfig): ArtMcpConfig { + const cleanConfig: ArtMcpConfig = { + mcpServers: {} + }; + + // Process each server entry + for (const [serverId, serverConfig] of Object.entries(config.mcpServers)) { + // Skip corrupted entries + if (serverId === '[object Object]' || typeof serverConfig !== 'object' || !serverConfig) { + Logger.warn(`ConfigManager: Removing corrupted entry: "${serverId}"`); + continue; + } + + // Ensure the server config has all required fields + const fixedConfig: McpServerConfig = { + id: serverConfig.id || serverId, + type: serverConfig.type || 'streamable-http', + enabled: serverConfig.enabled !== false, // Default to true + displayName: serverConfig.displayName || serverId, + description: serverConfig.description || `MCP server: ${serverId}`, + connection: serverConfig.connection, + installation: serverConfig.installation, + timeout: serverConfig.timeout || 30000, + tools: serverConfig.tools || [], // Add missing tools array + resources: serverConfig.resources || [], // Add missing resources array + resourceTemplates: serverConfig.resourceTemplates || [] // Add missing resourceTemplates array + }; + + // For Tavily specifically, ensure it has the proper tools definition + if (serverId === 'tavily_search_stdio' && (!fixedConfig.tools || fixedConfig.tools.length === 0)) { + fixedConfig.tools = [ + { + name: 'tavily-search', + description: 'A powerful web search tool that provides comprehensive, real-time results using Tavily\'s AI search engine.', + inputSchema: { + type: 'object', + properties: { + query: { type: 'string', description: 'Search query' }, + search_depth: { type: 'string', enum: ['basic', 'advanced'], description: 'The depth of the search. It can be \'basic\' or \'advanced\'', default: 'basic' }, + topic: { type: 'string', enum: ['general', 'news'], description: 'The category of the search', default: 'general' }, + max_results: { type: 'number', description: 'The maximum number of search results to return', default: 10, minimum: 5, maximum: 20 }, + include_raw_content: { type: 'boolean', description: 'Include the cleaned and parsed HTML content of each search result', default: false } + }, + required: ['query'] + } + }, + { + name: 'tavily-extract', + description: 'A powerful web content extraction tool that retrieves and processes raw content from specified URLs.', + inputSchema: { + type: 'object', + properties: { + urls: { type: 'array', items: { type: 'string' }, description: 'List of URLs to extract content from' }, + extract_depth: { type: 'string', enum: ['basic', 'advanced'], description: 'Depth of extraction - \'basic\' or \'advanced\'', default: 'basic' }, + include_images: { type: 'boolean', description: 'Include a list of images extracted from the urls in the response', default: false } + }, + required: ['urls'] + } + } + ]; + Logger.info(`ConfigManager: Added tools definition for Tavily server`); + } + + cleanConfig.mcpServers[serverId] = fixedConfig; + } + + return cleanConfig; + } + + /** + * Creates a default MCP configuration. + * @private + * @returns {ArtMcpConfig} The default MCP configuration. + */ + private createDefaultConfig(): ArtMcpConfig { + // Default to a remote, streamable-http Tavily server + const tavilyCard: McpServerConfig = { + id: "tavily_search_remote", + type: "streamable-http", + enabled: true, + displayName: "Tavily Search (Remote)", + description: "Provides AI-powered search and web content extraction tools via a remote server.", + connection: { + url: "https://mcp.tavily.com/v1/stream", // This is a placeholder URL + authStrategyId: "tavily_api_key" // Assumes an ApiKeyStrategy is configured + }, + tools: [ + { + name: "tavily-search", + description: "A powerful web search tool...", + inputSchema: { /* ... schema ... */ } + }, + { + name: "tavily-extract", + description: "A powerful web content extraction tool...", + inputSchema: { /* ... schema ... */ } + } + ], + resources: [], + resourceTemplates: [] + }; + return { mcpServers: { "tavily_search_remote": tavilyCard } }; + } + + /** + * Writes the MCP configuration to localStorage. + * @private + * @param {ArtMcpConfig} config - The configuration to write. + */ + private writeConfig(config: ArtMcpConfig): void { + try { + localStorage.setItem(this.configKey, JSON.stringify(config, null, 2)); + Logger.debug(`ConfigManager: Configuration saved to localStorage.`); + } catch (error: any) { + Logger.error(`ConfigManager: Failed to write to localStorage: ${error.message}`); + // Don't throw in browser context, as it could break the app + } + } + + /** + * Gets the current MCP configuration. + * @returns {ArtMcpConfig} The current MCP configuration. + */ + public getConfig(): ArtMcpConfig { + return this.config; + } + + /** + * Sets the configuration for a specific server and saves it. + * @param {string} serverId - The ID of the server to configure. + * @param {McpServerConfig} serverConfig - The configuration for the server. + */ + public setServerConfig(serverId: string, serverConfig: McpServerConfig): void { + this.config.mcpServers[serverId] = serverConfig; + this.writeConfig(this.config); + Logger.info(`ConfigManager: Updated configuration for server "${serverId}"`); + } + + /** + * Removes the configuration for a specific server and saves the changes. + * @param {string} serverId - The ID of the server to remove. + */ + public removeServerConfig(serverId: string): void { + if (this.config.mcpServers[serverId]) { + delete this.config.mcpServers[serverId]; + this.writeConfig(this.config); + Logger.info(`ConfigManager: Removed configuration for server "${serverId}"`); + } else { + Logger.warn(`ConfigManager: Attempted to remove non-existent server config "${serverId}"`); + } + } +} \ No newline at end of file diff --git a/src/systems/mcp/McpClient.ts b/src/systems/mcp/McpClient.ts new file mode 100755 index 0000000..1a75ceb --- /dev/null +++ b/src/systems/mcp/McpClient.ts @@ -0,0 +1,457 @@ +// Lazy import to avoid SSR/bundling path issues if SDK evolves +import { Client } from '@modelcontextprotocol/sdk/client/index.js' +import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js' +import { Logger } from '@/utils/logger'; +import { ARTError, ErrorCode } from '@/errors'; + +/** + * @function base64UrlEncode + * Encodes a buffer into a Base64URL string. + * @param {Uint8Array} buffer - The buffer to encode. + * @returns {string} The Base64URL encoded string. + */ +function base64UrlEncode(buffer: Uint8Array): string { + let s = '' + for (let i = 0; i < buffer.length; i++) s += String.fromCharCode(buffer[i]) + return btoa(s).replace(/=/g, '').replace(/\+/g, '-').replace(/\//g, '_') +} + +/** + * @function sha256Base64Url + * Hashes a string using SHA-256 and encodes it as Base64URL. + * @param {string} input - The string to hash. + * @returns {Promise} A promise that resolves to the Base64URL encoded hash. + */ +async function sha256Base64Url(input: string): Promise { + const data = new TextEncoder().encode(input) + const digest = await crypto.subtle.digest('SHA-256', data) + return base64UrlEncode(new Uint8Array(digest)) +} + +/** + * @function generateRandomString + * Generates a random string of a given length. + * @param {number} [length=64] - The length of the string to generate. + * @returns {string} The generated random string. + */ +function generateRandomString(length = 64): string { + const array = new Uint8Array(length) + crypto.getRandomValues(array) + return Array.from(array, (b) => b.toString(16).padStart(2, '0')).join('') +} + +/** + * @class TokenManager + * Manages OAuth tokens, including loading, updating, clearing, and refreshing them. + */ +export class TokenManager { + private accessToken: string | null = null + private refreshToken: string | null = null + private expiresAt: number | null = null + private clientId: string | null = null + constructor(private oauthConfig: { token_endpoint?: string }) {} + + /** + * Loads tokens from session storage. + */ + load() { + this.accessToken = sessionStorage.getItem('access_token') + this.refreshToken = sessionStorage.getItem('refresh_token') + const exp = sessionStorage.getItem('token_expires_at') + if (exp) this.expiresAt = parseInt(exp, 10) + this.clientId = localStorage.getItem('mcp_client_id') + } + + /** + * Sets the client ID. + * @param {string} id - The client ID. + */ + setClientId(id: string) { this.clientId = id } + + /** + * Updates the tokens and stores them in session storage. + * @param {any} token - The token object. + */ + update(token: any) { + this.accessToken = token.access_token + if (token.refresh_token) this.refreshToken = token.refresh_token + if (token.expires_in) this.expiresAt = Date.now() + token.expires_in * 1000 + sessionStorage.setItem('access_token', this.accessToken || '') + if (this.refreshToken) sessionStorage.setItem('refresh_token', this.refreshToken) + if (this.expiresAt) sessionStorage.setItem('token_expires_at', String(this.expiresAt)) + } + + /** + * Clears the tokens from memory and session storage. + */ + clear() { + this.accessToken = null + this.refreshToken = null + this.expiresAt = null + sessionStorage.removeItem('access_token') + sessionStorage.removeItem('refresh_token') + sessionStorage.removeItem('token_expires_at') + } + + /** + * Gets the access token. + * @returns {string | null} The access token. + */ + getAccessToken() { return this.accessToken } + + /** + * Checks if the token needs to be refreshed. + * @returns {boolean} True if the token needs to be refreshed, false otherwise. + */ + needsRefresh(): boolean { + if (!this.expiresAt) return false + return Date.now() >= this.expiresAt - 5 * 60 * 1000 + } + + /** + * Refreshes the access token using the refresh token. + * @returns {Promise} + */ + async refresh(): Promise { + if (!this.refreshToken) throw new Error('No refresh token available') + if (!this.oauthConfig.token_endpoint) throw new Error('Missing token endpoint') + const body = new URLSearchParams({ + grant_type: 'refresh_token', + refresh_token: this.refreshToken, + }) + if (this.clientId) body.set('client_id', this.clientId) + const res = await fetch(this.oauthConfig.token_endpoint, { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body, + }) + if (!res.ok) { + this.clear() + throw new Error('Token refresh failed') + } + const token = await res.json() + this.update(token) + } + + /** + * Checks if the user is authenticated. + * @returns {boolean} True if the user is authenticated, false otherwise. + */ + isAuthenticated(): boolean { + return !!this.accessToken && (this.expiresAt ? this.expiresAt > Date.now() : true) + } +} + +/** + * @class McpClientController + * Controls the MCP client, including OAuth flow, connection, and tool calls. + */ +export class McpClientController { + public baseUrl: URL + private scopes: string[] + private client: Client | null = null + private transport: StreamableHTTPClientTransport | null = null + private oauthDiscovery: any = null + private tokenManager: TokenManager | null = null + private sessionId: string | null = null + private readonly protocolVersion: string = '2025-06-18' + + /** + * Creates an instance of McpClientController. + * @private + * @param {string} baseUrl - The base URL of the MCP server. + * @param {string[]} [scopes] - The OAuth scopes to request. + */ + private constructor(baseUrl: string, scopes?: string[]) { + this.baseUrl = new URL(baseUrl) + this.scopes = scopes ?? ['read', 'write'] + } + + /** + * Creates a new instance of McpClientController. + * @param {string} baseUrl - The base URL of the MCP server. + * @param {string[]} [scopes] - The OAuth scopes to request. + * @returns {McpClientController} A new instance of McpClientController. + */ + static create(baseUrl: string, scopes?: string[]): McpClientController { + return new McpClientController(baseUrl, scopes) + } + + /** + * Discovers the authorization server metadata. + * @private + * @returns {Promise} + */ + private async discoverAuthorizationServer(): Promise { + if (this.oauthDiscovery) return + + // HACK: Bypassing full discovery flow to avoid WWW-Authenticate CORS issues. + // This assumes the MCP server itself hosts the AS metadata endpoint. + const asMetadataUrl = new URL('/.well-known/oauth-authorization-server', this.baseUrl).toString() + const asMetadataRes = await fetch(asMetadataUrl) + if (!asMetadataRes.ok) throw new ARTError(`Failed to fetch authorization server metadata from ${asMetadataUrl}`, ErrorCode.NETWORK_ERROR) + this.oauthDiscovery = await asMetadataRes.json() + sessionStorage.setItem('mcp_oauth_discovery', JSON.stringify(this.oauthDiscovery)) + + /* + const probeRes = await fetch(this.baseUrl.toString(), { method: 'GET' }) + + if (probeRes.status !== 401) { + throw new Error('MCP server did not respond with 401 Unauthorized. Cannot discover authorization server.') + } + + const wwwAuthHeader = probeRes.headers.get('WWW-Authenticate') + if (!wwwAuthHeader) throw new Error('Missing WWW-Authenticate header in 401 response') + + const metadataUrlMatch = /resource_metadata="([^"]+)"/.exec(wwwAuthHeader) + if (!metadataUrlMatch) throw new Error('Could not find resource_metadata in WWW-Authenticate header') + + const resourceMetadataUrl = metadataUrlMatch[1] + const resourceMetadataRes = await fetch(resourceMetadataUrl) + if (!resourceMetadataRes.ok) throw new Error('Failed to fetch resource metadata') + const resourceMetadata = await resourceMetadataRes.json() + + if (!resourceMetadata.authorization_servers || resourceMetadata.authorization_servers.length === 0) { + throw new Error('No authorization_servers found in resource metadata') + } + + const authorizationServerUrl = resourceMetadata.authorization_servers[0] + const asMetadataUrl = new URL('/.well-known/oauth-authorization-server', authorizationServerUrl).toString() + + const asMetadataRes = await fetch(asMetadataUrl) + if (!asMetadataRes.ok) throw new Error('Failed to fetch authorization server metadata') + this.oauthDiscovery = await asMetadataRes.json() + sessionStorage.setItem('mcp_oauth_discovery', JSON.stringify(this.oauthDiscovery)) + */ + } + + /** + * Registers the client with the authorization server. + * @private + * @returns {Promise} A promise that resolves to the client ID. + */ + private async registerClient(): Promise { + if (!this.oauthDiscovery?.registration_endpoint) { + // Assume pre-registered public client if dynamic registration not available + const existing = localStorage.getItem('mcp_client_id') + if (existing) return existing + const randomId = 'public-' + generateRandomString(16) + localStorage.setItem('mcp_client_id', randomId) + return randomId + } + const body = { + client_name: 'MCP Browser Demo', + redirect_uris: [location.origin + '/callback'], + grant_types: ['authorization_code', 'refresh_token'], + response_types: ['code'], + token_endpoint_auth_method: 'none', + application_type: 'web', + } + const res = await fetch(this.oauthDiscovery.registration_endpoint, { + method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(body), + }) + if (!res.ok) throw new ARTError('Client registration failed', ErrorCode.EXTERNAL_SERVICE_ERROR) + const data = await res.json() + localStorage.setItem('mcp_client_id', data.client_id) + return data.client_id + } + + /** + * Starts the OAuth flow by redirecting the user to the authorization server. + * @returns {Promise} + */ + async startOAuth() { + await this.discoverAuthorizationServer() + if (!this.oauthDiscovery) throw new ARTError('Could not discover OAuth server details.', ErrorCode.INVALID_CONFIG) + const clientId = await this.registerClient() + const codeVerifier = base64UrlEncode(crypto.getRandomValues(new Uint8Array(64))) + const codeChallenge = await sha256Base64Url(codeVerifier) + sessionStorage.setItem('code_verifier', codeVerifier) + const state = generateRandomString(16) + sessionStorage.setItem('state', state) + const authUrl = new URL(this.oauthDiscovery.authorization_endpoint) + authUrl.searchParams.set('response_type', 'code') + authUrl.searchParams.set('client_id', clientId) + authUrl.searchParams.set('redirect_uri', location.origin + '/callback') + authUrl.searchParams.set('scope', this.scopes.join(' ')) + authUrl.searchParams.set('code_challenge', codeChallenge) + authUrl.searchParams.set('code_challenge_method', 'S256') + authUrl.searchParams.set('state', state) + authUrl.searchParams.set('resource', this.baseUrl.toString().replace(/\/$/, '')) + window.location.href = authUrl.toString() + } + + /** + * Handles the OAuth callback, exchanging the authorization code for an access token. + * @returns {Promise} A promise that resolves to true if the callback was handled, false otherwise. + */ + async maybeHandleCallback(): Promise { + const url = new URL(window.location.href) + const isCallback = url.pathname === '/callback' && (url.searchParams.get('code') || url.searchParams.get('error')) + if (!isCallback) return false + + // Load discovery doc from session storage, assuming it was stored during startOAuth + const discoveryDoc = sessionStorage.getItem('mcp_oauth_discovery') + if (discoveryDoc) this.oauthDiscovery = JSON.parse(discoveryDoc) + else await this.discoverAuthorizationServer() // Fallback just in case + + if (!this.oauthDiscovery) throw new ARTError('Could not determine OAuth server details for callback.', ErrorCode.INVALID_CONFIG) + + const code = url.searchParams.get('code') + const state = url.searchParams.get('state') + if (!code) throw new ARTError('Authorization code missing', ErrorCode.VALIDATION_ERROR) + if (state !== sessionStorage.getItem('state')) throw new ARTError('State mismatch', ErrorCode.VALIDATION_ERROR) + const clientId = localStorage.getItem('mcp_client_id') || (await this.registerClient()) + const codeVerifier = sessionStorage.getItem('code_verifier') || '' + const body = new URLSearchParams({ + grant_type: 'authorization_code', + code, + code_verifier: codeVerifier, + redirect_uri: location.origin + '/callback', + client_id: clientId, + }) + body.set('resource', this.baseUrl.toString().replace(/\/$/, '')) + + const res = await fetch(this.oauthDiscovery.token_endpoint, { + method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body, + }) + if (!res.ok) { + const err = await res.json().catch(() => ({})) + throw new ARTError('Token exchange failed: ' + (err.error_description || err.error || res.status), ErrorCode.EXTERNAL_SERVICE_ERROR) + } + const token = await res.json() + this.tokenManager = new TokenManager(this.oauthDiscovery) + this.tokenManager.setClientId(clientId) + this.tokenManager.update(token) + sessionStorage.removeItem('code_verifier') + sessionStorage.removeItem('state') + history.replaceState({}, '', '/') + return true + } + + /** + * Loads an existing session from session storage. + */ + loadExistingSession() { + const discoveryDoc = sessionStorage.getItem('mcp_oauth_discovery') + if (discoveryDoc) this.oauthDiscovery = JSON.parse(discoveryDoc) + this.tokenManager = new TokenManager(this.oauthDiscovery || {}) + this.tokenManager.load() + this.sessionId = sessionStorage.getItem('mcp_session_id') + } + + /** + * Checks if the user is authenticated. + * @returns {boolean} True if the user is authenticated, false otherwise. + */ + isAuthenticated(): boolean { + if (!this.tokenManager) return false + return this.tokenManager.isAuthenticated() + } + + /** + * Connects to the MCP server. + * @returns {Promise} + */ + async connect(): Promise { + if (!this.client) { + const customFetch = async (url: RequestInfo | URL, options?: RequestInit): Promise => { + this.tokenManager?.load() + if (this.tokenManager?.needsRefresh()) { + await this.tokenManager.refresh().catch((err) => { + Logger.error('Token refresh failed:', err); + // Optionally, trigger a full re-authentication flow + }) + } + + const headers = new Headers(options?.headers) + headers.set('Authorization', `Bearer ${this.tokenManager?.getAccessToken() || ''}`) + headers.set('Accept', 'application/json, text/event-stream') + headers.set('MCP-Protocol-Version', this.protocolVersion) + if (this.sessionId) { + headers.set('Mcp-Session-Id', this.sessionId) + } + + const newOptions: RequestInit = { ...options, headers } + const response = await fetch(url, newOptions) + + const sessionIdHeader = response.headers.get('Mcp-Session-Id') + if (sessionIdHeader) { + this.sessionId = sessionIdHeader + sessionStorage.setItem('mcp_session_id', sessionIdHeader) + } + return response + } + + this.transport = new StreamableHTTPClientTransport(this.baseUrl, { fetch: customFetch }) + this.client = new Client({ name: 'mcp-browser-demo', version: '1.0.0' }) + await this.client.connect(this.transport) + } + } + + /** + * Ensures that the client is connected to the MCP server. + * @returns {Promise} + */ + async ensureConnected(): Promise { + if (!this.client) await this.connect() + } + + /** + * Lists the available tools on the MCP server. + * @returns {Promise<{ name: string; description?: string }[]>} A promise that resolves to a list of tools. + */ + async listTools(): Promise<{ name: string; description?: string }[]> { + if (!this.client) throw new ARTError('Not connected', ErrorCode.NOT_CONNECTED) + const res = await this.client.listTools() + return res.tools?.map((t: any) => ({ name: t.name, description: t.description })) ?? [] + } + + /** + * Calls a tool on the MCP server. + * @param {string} name - The name of the tool to call. + * @param {any} args - The arguments to pass to the tool. + * @returns {Promise} A promise that resolves to the result of the tool call. + */ + async callTool(name: string, args: any): Promise { + if (!this.client) throw new ARTError('Not connected', ErrorCode.NOT_CONNECTED) + try { + const result = await this.client.callTool({ name, arguments: args }) + return result + } catch (e: any) { + // Retry once if unauthorized and refresh is possible + if (String(e?.message || '').includes('401') && this.tokenManager) { + await this.tokenManager.refresh().catch((err) => { + Logger.error('Token refresh failed during tool call:', err); + throw e; // Re-throw original error if refresh fails + }) + const result = await this.client.callTool({ name, arguments: args }) + return result + } + throw e + } + } + + /** + * Logs out from the MCP server and clears the session. + * @returns {Promise} + */ + async logout(): Promise { + try { + if (this.transport) { + const headers: Record = {} + const token = this.tokenManager?.getAccessToken() + if (token) headers['Authorization'] = `Bearer ${token}` + if (this.sessionId) headers['Mcp-Session-Id'] = this.sessionId + await fetch(this.baseUrl.toString(), { method: 'DELETE', headers }).catch(() => {}) + } + } finally { + this.client = null + this.transport = null + this.tokenManager?.clear() + this.sessionId = null + sessionStorage.removeItem('mcp_session_id') + sessionStorage.removeItem('mcp_oauth_discovery') + } + } +} diff --git a/src/systems/mcp/McpManager.ts b/src/systems/mcp/McpManager.ts new file mode 100755 index 0000000..3581df9 --- /dev/null +++ b/src/systems/mcp/McpManager.ts @@ -0,0 +1,395 @@ +import { ToolRegistry, StateManager } from '@/core/interfaces'; +import { ARTError, ErrorCode } from '@/errors'; +import { Logger } from '@/utils/logger'; +import { AuthManager } from '../auth/AuthManager'; +import { McpProxyTool } from './McpProxyTool'; +import { ConfigManager } from './ConfigManager'; +import { McpServerConfig, StreamableHttpConnection } from './types'; +import { McpClientController } from './McpClient'; +import { hasInstall, install, getAllowedInfo, requestHosts, getInstallUrl } from 'art-mcp-permission-manager' + +/** + * Manages MCP (Model Context Protocol) server connections and tool registration. + * + * @remarks + * The `McpManager` is responsible for: + * - Connecting to configured MCP servers. + * - Discovering available tools from servers. + * - Creating proxy tools that wrap MCP server tools. + * - Registering proxy tools with the {@link ToolRegistry}. + * - Managing server health and status. + * - Handling thread-specific tool activation/deactivation. + * + * This enables dynamic tool loading from external MCP servers while maintaining + * seamless integration with the ART Framework's tool system. + * + * @see {@link McpProxyTool} for the tool wrapper implementation. + * @see {@link McpClientController} for the underlying client implementation. + * + * @class McpManager + */ +export class McpManager { + private configManager: ConfigManager; + private toolRegistry: ToolRegistry; + private authManager?: AuthManager; + private activeConnections: Map = new Map(); + + /** + * Creates an instance of McpManager. + * + * @param toolRegistry The tool registry to register proxy tools with. + * @param _stateManager The state manager (not currently used). + * @param authManager The authentication manager. + */ + constructor(toolRegistry: ToolRegistry, _stateManager: StateManager, authManager?: AuthManager) { + this.configManager = new ConfigManager(); + this.toolRegistry = toolRegistry; + this.authManager = authManager; + Logger.info(`McpManager: Hub initialized. Will load tools from config catalog.`); + } + + /** + * Initializes the McpManager, discovers and registers tools from configured servers. + * + * @param mcpConfig The MCP configuration. + * @param [mcpConfig.enabled=true] Whether MCP is enabled. + * @param mcpConfig.discoveryEndpoint The endpoint for discovering MCP servers. + * @returns A promise that resolves when initialization is complete. + */ + async initialize(mcpConfig?: { enabled?: boolean; discoveryEndpoint?: string }): Promise { + if (!mcpConfig?.enabled) { + Logger.info('McpManager: MCP is disabled. Skipping initialization.'); + return; + } + + Logger.info('McpManager: Initializing from multiple sources...'); + + // 1. Get local config MCPCards + const localServerConfigs = this.configManager.getConfig().mcpServers; + Logger.info(`McpManager: Found ${Object.keys(localServerConfigs).length} servers in local config`); + + // 2. Discover remote MCPCards from Zyntopia API + let discoveredServerConfigs: McpServerConfig[] = []; + try { + discoveredServerConfigs = await this.discoverAvailableServers(mcpConfig.discoveryEndpoint); + Logger.info(`McpManager: Discovered ${discoveredServerConfigs.length} servers from discovery API`); + } catch (error: any) { + Logger.warn(`McpManager: Discovery API failed, continuing with local config only: ${error.message}`); + } + + // 3. Merge all server configurations (local + discovered) + const allServerConfigs = new Map(); + + // Add local configs first + for (const [serverId, config] of Object.entries(localServerConfigs)) { + allServerConfigs.set(serverId, config); + } + + // Add discovered configs (with conflict resolution) + for (const discoveredConfig of discoveredServerConfigs) { + if (allServerConfigs.has(discoveredConfig.id)) { + Logger.info(`McpManager: Server "${discoveredConfig.id}" exists in both local config and discovery API. Using local config.`); + } else { + allServerConfigs.set(discoveredConfig.id, discoveredConfig); + Logger.info(`McpManager: Added discovered server "${discoveredConfig.id}" to available servers`); + } + } + + // 4. Register proxy tools based on current card hints only (non-blocking). + // Live discovery and PKCE prompting can happen later during explicit install or first use. + let registeredToolCount = 0; + for (const [, card] of allServerConfigs) { + if (!card.enabled) continue; + const toolsToRegister = card.tools || []; + if (Array.isArray(toolsToRegister)) { + for (const toolDef of toolsToRegister) { + const proxyTool = new McpProxyTool(card, toolDef as any, this); + await this.toolRegistry.registerTool(proxyTool); + registeredToolCount++; + } + } + } + + Logger.info(`McpManager: Initialization complete. Registered ${registeredToolCount} proxy tools from ${allServerConfigs.size} total servers.`); + } + + /** + * Shuts down all active MCP connections. + * + * @returns A promise that resolves when all connections are shut down. + */ + async shutdown(): Promise { + Logger.info('McpManager: Shutting down all active connections...'); + const disconnectionPromises = Array.from(this.activeConnections.values()).map(client => client.logout()); + await Promise.allSettled(disconnectionPromises); + this.activeConnections.clear(); + Logger.info('McpManager: Shutdown complete.'); + } + + /** + * Gets an existing connection or creates a new one for a given server ID. + * + * @param serverId The ID of the server to connect to. + * @returns A promise that resolves to the MCP client controller. + */ + public async getOrCreateConnection(serverId: string): Promise { + if (this.activeConnections.has(serverId)) { + const existingClient = this.activeConnections.get(serverId)!; + if (existingClient.isAuthenticated()) { + await existingClient.ensureConnected(); + return existingClient; + } + } + + Logger.info(`McpManager: No active connection for "${serverId}". Creating one on-demand...`); + const card = this.configManager.getConfig().mcpServers[serverId]; + if (!card) { + throw new ARTError(`Configuration for server "${serverId}" not found.`, ErrorCode.SERVER_NOT_FOUND); + } + + if (card.type !== 'streamable-http') { + throw new ARTError(`Unsupported transport type "${card.type}" for server "${serverId}". Only 'streamable-http' is supported in the browser.`, ErrorCode.UNSUPPORTED_TRANSPORT); + } + + const conn = card.connection as StreamableHttpConnection; + + await this.ensureCorsAccess(conn.url); + + const scopes = conn.oauth?.scopes; + const client = McpClientController.create(conn.url, Array.isArray(scopes) ? scopes : (scopes ? [scopes] : undefined)); + + const handled = await client.maybeHandleCallback(); + if(handled) { + Logger.info(`McpManager: OAuth callback for server "${serverId}" handled successfully.`); + } + + client.loadExistingSession(); + + if(!client.isAuthenticated()) { + await client.startOAuth(); + // The above call will redirect, so the code below might not be reached in that flow. + // If it is (e.g. pop-up), we need to wait for authentication. + await this.waitForAuth(client, 180000); // Wait for up to 3 minutes + } + + await client.connect(); + + this.activeConnections.set(serverId, client); + Logger.info(`McpManager: On-demand connection for "${serverId}" established successfully.`); + return client; + } + + /** + * Ensures that the application has CORS access to the target URL. + * + * @private + * @param targetUrl The URL to check for CORS access. + * @returns A promise that resolves when CORS access is confirmed or granted. + */ + private async ensureCorsAccess(targetUrl: string): Promise { + if (!hasInstall()) { + const opened = install({ browser: 'auto' }); + if (!opened) { + const url = getInstallUrl(); + // In a real app, you'd show this in a dialog, not an alert + alert('ART MCP requires a companion browser extension for CORS. Please install it: ' + url); + throw new ARTError('Companion extension not installed.', ErrorCode.CORS_EXTENSION_REQUIRED); + } + throw new ARTError('Companion extension installation started. Please complete it and retry.', ErrorCode.CORS_EXTENSION_REQUIRED); + } + + const { hostname } = new URL(targetUrl); + const info = await getAllowedInfo(); + + if (!info.enabled || (info.type === 'specific' && !info.hosts?.includes(hostname))) { + const res = await requestHosts({ hosts: [hostname] }); + if (res !== 'accept') { + throw new ARTError(`User did not grant permission for ${hostname}.`, ErrorCode.CORS_PERMISSION_REQUIRED); + } + } + } + + // --- Discovery & Installation (Future Implementation) --- + + /** + * Searches a discovery service for available MCP servers. + * + * @param [discoveryEndpoint] The URL of the discovery service. + * @returns A promise resolving to an array of McpServerConfig. + */ + async discoverAvailableServers(discoveryEndpoint?: string): Promise { + const url = discoveryEndpoint || 'http://localhost:4200/api/services'; // Default Zyntopia endpoint + Logger.info(`McpManager: Discovering servers from ${url}...`); + + try { + await this.ensureCorsAccess(url); + const response = await fetch(url, { + method: 'GET', + headers: { + 'Accept': 'application/json', + 'User-Agent': 'ART-Framework-MCP/2.0' + }, + // Add timeout to prevent hanging + signal: AbortSignal.timeout(10000) // 10 second timeout + }); + + if (!response.ok) { + throw new Error(`Discovery API returned ${response.status}: ${response.statusText}`); + } + + const data = await response.json(); + + // Filter for MCP services and convert to MCPCards + const mcpServices = Array.isArray(data) ? data : (data.services || []); + const mcpCards: McpServerConfig[] = mcpServices + .filter((service: any) => service.service_type === 'MCP_SERVICE') + .map((service: any) => this.convertServiceToMcpCard(service)) + .filter((card: McpServerConfig | null) => card !== null) as McpServerConfig[]; + + Logger.info(`McpManager: Successfully discovered ${mcpCards.length} MCP servers from discovery API`); + return mcpCards; + + } catch (error: any) { + Logger.error(`McpManager: Failed to discover servers from ${url}: ${error.message}`); + throw new ARTError(`Discovery API failed: ${error.message}`, ErrorCode.NETWORK_ERROR); + } + } + + /** + * Converts a Zyntopia service entry to an McpServerConfig. + * + * @private + * @param service The service entry to convert. + * @returns The converted McpServerConfig or null if conversion fails. + */ + private convertServiceToMcpCard(service: any): McpServerConfig | null { + try { + // Basic validation + if (!service.id || !service.name || !service.connection) { + Logger.warn(`McpManager: Skipping invalid service entry: missing required fields`); + return null; + } + + const mcpCard: McpServerConfig = { + id: service.id, + type: service.connection.type === 'sse' ? 'streamable-http' : service.connection.type, + enabled: service.enabled !== false, // Default to enabled unless explicitly disabled + displayName: service.name, + description: service.description || `MCP service: ${service.name}`, + connection: service.connection, + timeout: service.timeout || 10000, + tools: service.tools || [], + resources: service.resources || [], + resourceTemplates: service.resourceTemplates || [], + installation: service.installation + }; + + Logger.debug(`McpManager: Converted service "${service.id}" to MCPCard`); + return mcpCard; + + } catch (error: any) { + Logger.warn(`McpManager: Failed to convert service to MCPCard: ${error.message}`); + return null; + } + } + + // The generateAndInstallCard method is removed as it is based on the stdio transport, + // which is not supported in a browser-only environment. + + /** + * Installs a server by persisting its config, discovering tools via MCP, and + * registering proxy tools. Returns the finalized config with accurate tools. + * + * @param server The server configuration to install. + * @returns A promise that resolves to the finalized server configuration. + */ + public async installServer(server: McpServerConfig): Promise { + // Save initial config + this.configManager.setServerConfig(server.id, server); + try { + const conn = server.connection as StreamableHttpConnection; + await this.ensureCorsAccess(conn.url); + + let client: McpClientController; + try { + client = await this.getOrCreateConnection(server.id); + } catch (e: any) { + // This might happen if startOAuth redirects. The user will need to try again. + Logger.warn(`McpManager: Could not connect during install for "${server.id}": ${e?.message || e}. The user may need to complete authentication and retry.`); + // We still save the server config, just without the live tools. + return server; + } + + const liveTools = await client.listTools(); + const normalized = (liveTools || []).map(t => ({ name: t.name, description: t.description } as any)); + const updated = { ...server, tools: normalized } as McpServerConfig; + + this.configManager.setServerConfig(server.id, updated); + + for (const t of normalized) { + await this.toolRegistry.registerTool(new McpProxyTool(updated, t as any, this)); + } + + Logger.info(`McpManager: Installed server "${server.id}" with ${normalized.length} discovered tool(s).`); + return updated; + + } catch (e: any) { + Logger.warn(`McpManager: Could not complete live discovery during install for "${server.id}": ${e?.message || e}. Falling back to provided tools.`); + const fallback = server.tools || []; + for (const t of fallback) { + await this.toolRegistry.registerTool(new McpProxyTool(server, t as any, this)); + } + return server; + } + } + + /** + * Waits for the client to be authenticated. + * + * @private + * @param client The MCP client controller. + * @param timeoutMs The timeout in milliseconds. + * @returns A promise that resolves when the client is authenticated. + * @throws {ARTError} If the authentication window times out. + */ + private async waitForAuth(client: McpClientController, timeoutMs: number): Promise { + const start = Date.now(); + while (Date.now() - start < timeoutMs) { + if (client.isAuthenticated()) { + return; + } + await new Promise(r => setTimeout(r, 1000)); + } + throw new ARTError('Authentication window timed out.', ErrorCode.TIMEOUT); + } + + /** + * Uninstalls a server: disconnects, removes registered proxy tools, and deletes config. + * + * @param serverId The ID of the server to uninstall. + * @returns A promise that resolves when the server is uninstalled. + */ + public async uninstallServer(serverId: string): Promise { + try { + // Unregister tools by name prefix + const prefix = `mcp_${serverId}_`; + if ((this.toolRegistry as any).unregisterTools) { + await (this.toolRegistry as any).unregisterTools((schema: any) => typeof schema?.name === 'string' && schema.name.startsWith(prefix)); + } + + // Disconnect + const client = this.activeConnections.get(serverId); + if (client) { + await client.logout(); + this.activeConnections.delete(serverId); + } + + // Remove config + this.configManager.removeServerConfig(serverId); + Logger.info(`McpManager: Server "${serverId}" uninstalled.`); + } catch (e: any) { + Logger.warn(`McpManager: Uninstall encountered issues for "${serverId}": ${e?.message || e}`); + this.configManager.removeServerConfig(serverId); + } + } +} \ No newline at end of file diff --git a/src/systems/mcp/McpProxyTool.ts b/src/systems/mcp/McpProxyTool.ts new file mode 100755 index 0000000..b7adf24 --- /dev/null +++ b/src/systems/mcp/McpProxyTool.ts @@ -0,0 +1,127 @@ +import { IToolExecutor } from '@/core/interfaces'; +import { ToolSchema, ToolResult, ExecutionContext } from '@/types'; +import { Logger } from '@/utils/logger'; +import { McpManager } from './McpManager'; +import { McpServerConfig, McpToolDefinition } from './types'; +import { CallToolResultSchema } from '@modelcontextprotocol/sdk/types.js'; + +/** + * A proxy tool that wraps an MCP server tool and implements the {@link IToolExecutor} interface. + * + * @remarks + * This allows MCP server tools to be used seamlessly within the ART Framework. + * + * @see {@link McpManager} for the system that manages these proxy tools. + * @see {@link IToolExecutor} for the interface it implements. + * + * @class McpProxyTool + */ +export class McpProxyTool implements IToolExecutor { + public readonly schema: ToolSchema; + + private card: McpServerConfig; + private toolDefinition: McpToolDefinition; + private mcpManager: McpManager; + + /** + * Creates an instance of McpProxyTool. + * + * @param card Configuration for the MCP server hosting this tool. + * @param toolDefinition The tool definition from the MCP server. + * @param mcpManager The MCP manager for managing connections. + */ + constructor(card: McpServerConfig, toolDefinition: McpToolDefinition, mcpManager: McpManager) { + this.card = card; + this.toolDefinition = toolDefinition; + this.mcpManager = mcpManager; + + // Convert MCP tool definition to ART ToolSchema + this.schema = { + name: `mcp_${card.id}_${toolDefinition.name}`, + description: toolDefinition.description || `Tool ${toolDefinition.name} from ${card.displayName || card.id}`, + inputSchema: toolDefinition.inputSchema, + outputSchema: toolDefinition.outputSchema + }; + + Logger.debug(`McpProxyTool: Created proxy for tool "${toolDefinition.name}" from server "${card.displayName}"`); + } + + /** + * Executes the tool by making a request to the MCP server. + * + * @param input Validated input arguments for the tool. + * @param context Execution context containing threadId, traceId, etc. + * @returns A promise resolving to the tool result. + */ + async execute(input: any, context: ExecutionContext): Promise { + const startTime = Date.now(); + + try { + Logger.debug(`McpProxyTool: Execution requested for "${this.schema.name}". Getting or creating connection...`); + const client = await this.mcpManager.getOrCreateConnection(this.card.id); + + Logger.debug(`McpProxyTool: Connection ready. Executing tool "${this.toolDefinition.name}" on server "${this.card.displayName}"`); + const response = await client.callTool(this.toolDefinition.name, input); + + const duration = Date.now() - startTime; + + // Validate the raw response against the SDK's schema for robustness. + // If validation fails, it will throw an error that is caught below. + const validatedResponse = CallToolResultSchema.parse(response); + + // Adapt the response to the ToolResult format + // This is a generic adaptation, specific tools might require more tailored logic + // based on the shape of their response. + const output = typeof validatedResponse === 'object' && validatedResponse !== null ? validatedResponse : { value: validatedResponse }; + + return { + callId: context.traceId || 'unknown', + toolName: this.schema.name, + status: 'success', + output: [output], // Assuming the output should be wrapped in an array + metadata: { + executionTime: duration, + mcpServer: { id: this.card.id, name: this.card.displayName }, + rawResponse: response + } + }; + } catch (error: any) { + const duration = Date.now() - startTime; + Logger.error(`McpProxyTool: Failed to execute tool "${this.toolDefinition.name}": ${error.message}`); + return { + callId: context.traceId || 'unknown', + toolName: this.schema.name, + status: 'error', + error: `MCP execution failed: ${error.message}`, + metadata: { executionTime: duration, mcpServer: { id: this.card.id, name: this.card.displayName }, originalError: error instanceof Error ? error.stack : String(error) } + }; + } + } + + /** + * Gets the original tool name from the MCP server. + * + * @returns The original tool name. + */ + getOriginalToolName(): string { + return this.toolDefinition.name; + } + + /** + * Gets the MCP server configuration. + * + * @returns The server configuration. + */ + getServerConfig(): McpServerConfig { + return { ...this.card }; + } + + /** + * Gets the MCP tool definition. + * + * @returns The tool definition. + */ + getToolDefinition(): McpToolDefinition { + return { ...this.toolDefinition }; + } +} \ No newline at end of file diff --git a/src/systems/mcp/index.ts b/src/systems/mcp/index.ts new file mode 100755 index 0000000..8a7cf3d --- /dev/null +++ b/src/systems/mcp/index.ts @@ -0,0 +1,26 @@ +/** + * @module systems/mcp + * This module exports the core components of the MCP (Multi-Capability Provider) architecture, + * including the `McpManager`, `McpProxyTool`, and `ConfigManager`. It also exports + * various type definitions related to MCP configuration and state. + */ + +// Core MCP Architecture +export { McpManager } from './McpManager'; +export { McpProxyTool } from './McpProxyTool'; +export { ConfigManager } from './ConfigManager'; +export { McpClientController } from './McpClient'; + +// Type Definitions +export type { + // Public config types + ArtMcpConfig, + McpServerConfig, + StreamableHttpConnection, + McpToolDefinition, + McpResource, + McpResourceTemplate, + + // Internal state types + McpServerStatus +} from './types'; \ No newline at end of file diff --git a/src/systems/mcp/types.ts b/src/systems/mcp/types.ts new file mode 100755 index 0000000..5beeaf5 --- /dev/null +++ b/src/systems/mcp/types.ts @@ -0,0 +1,301 @@ +/** + * @module systems/mcp/types + * This module defines the public and internal types used for configuring + * and managing the state of the MCP (Multi-Capability Provider) system. + */ + +/** + * Defines the connection details for a streamable HTTP-based MCP server. + * This is the primary transport mechanism for browser-based MCP communication. + * + * @interface StreamableHttpConnection + */ +export interface StreamableHttpConnection { + /** + * The base URL of the MCP server. + * @property {string} url + */ + url: string; + /** + * Optional headers to include in every request to the server. + * @property {Record} [headers] + */ + headers?: Record; + /** + * The ID of an authentication strategy to use for this connection. + * @property {string} [authStrategyId] + */ + authStrategyId?: string; + /** + * Optional OAuth configuration for automatic PKCE setup per server. + * This enables secure, per-server authentication without manual token handling. + * @property {object} [oauth] + */ + oauth?: { + /** + * The type of OAuth flow, currently supporting 'pkce'. + * @property {'pkce'} type + */ + type: 'pkce'; + /** + * The OAuth 2.1 Authorization Endpoint URL. + * @property {string} authorizationEndpoint + */ + authorizationEndpoint: string; + /** + * The OAuth 2.1 Token Endpoint URL. + * @property {string} tokenEndpoint + */ + tokenEndpoint: string; + /** + * The public client ID for the OAuth application. + * @property {string} clientId + */ + clientId: string; + /** + * A space-delimited string of OAuth scopes to request. + * @property {string} scopes + */ + scopes: string; + /** + * The redirect URI that will handle the OAuth callback. + * @property {string} redirectUri + */ + redirectUri: string; + /** + * Optional 'resource' parameter for OAuth 2.1, often used as an audience identifier. + * @property {string} [resource] + */ + resource?: string; + /** + * Determines whether to open the login page in a new tab. + * Defaults to true if omitted. + * @property {boolean} [openInNewTab] + */ + openInNewTab?: boolean; + /** + * An optional BroadcastChannel name for delivering tokens, useful in multi-window scenarios. + * @property {string} [channelName] + */ + channelName?: string; + }; +} + +/** + * Defines the schema for a tool provided by an MCP server. + * + * @interface McpToolDefinition + */ +export interface McpToolDefinition { + /** + * The name of the tool. + * @property {string} name + */ + name: string; + /** + * A description of what the tool does. + * @property {string} [description] + */ + description?: string; + /** + * The JSON schema for the tool's input. + * @property {any} inputSchema + */ + inputSchema: any; + /** + * The JSON schema for the tool's output. + * @property {any} [outputSchema] + */ + outputSchema?: any; +} + +/** + * Defines a static resource provided by an MCP server. + * + * @interface McpResource + */ +export interface McpResource { + /** + * The URI of the resource. + * @property {string} uri + */ + uri: string; + /** + * The name of the resource. + * @property {string} name + */ + name: string; + /** + * The MIME type of the resource. + * @property {string} [mimeType] + */ + mimeType?: string; + /** + * A description of the resource. + * @property {string} [description] + */ + description?: string; +} + +/** + * Defines a template for a resource provided by an MCP server. + * + * @interface McpResourceTemplate + */ +export interface McpResourceTemplate { + /** + * The URI template for the resource. + * @property {string} uriTemplate + */ + uriTemplate: string; + /** + * The name of the resource template. + * @property {string} name + */ + name: string; + /** + * A description of the resource template. + * @property {string} [description] + */ + description?: string; + /** + * The MIME type of the resource. + * @property {string} [mimeType] + */ + mimeType?: string; +} + +/** + * Represents the configuration for a single MCP server. + * + * @remarks + * This is the format for each server entry in the `art_mcp_config.json` file. + * It contains all the necessary information for discovering, installing, and connecting to an MCP server. + * + * @typedef {object} McpServerConfig + */ +export type McpServerConfig = { + /** + * A unique identifier for the server. + * @property {string} id + */ + id: string; + /** + * The transport type for the server, currently only 'streamable-http' is supported. + * @property {'streamable-http'} type + */ + type: 'streamable-http'; + /** + * Whether the server is enabled and should be connected to. + * @property {boolean} enabled + */ + enabled: boolean; + /** + * A user-friendly name for the server. + * @property {string} [displayName] + */ + displayName?: string; + /** + * A description of the server and its capabilities. + * @property {string} [description] + */ + description?: string; + /** + * The connection details for the server. + * @see module:systems/mcp/types.StreamableHttpConnection + */ + connection: StreamableHttpConnection; + /** + * Information about how the server was installed (e.g., 'git', 'npm', 'manual'). + * @property {object} [installation] + */ + installation?: { source: 'git' | 'npm' | 'manual'; [key: string]: any; }; + /** + * The timeout in milliseconds for requests to the server. + * @property {number} [timeout] + */ + timeout?: number; + /** + * The tools provided by the server. + * @property {McpToolDefinition[]} tools + */ + tools: McpToolDefinition[]; + /** + * The static resources provided by the server. + * @property {McpResource[]} resources + */ + resources: McpResource[]; + /** + * The resource templates provided by the server. + * @property {McpResourceTemplate[]} resourceTemplates + */ + resourceTemplates: McpResourceTemplate[]; +}; + +/** + * Defines the root structure of the `art_mcp_config.json` file. + * + * @interface ArtMcpConfig + */ +export interface ArtMcpConfig { + /** + * A record of MCP server configurations, where the key is the server ID. + * @property {Record} mcpServers + */ + mcpServers: Record; +} + +/** + * Represents the internal status of an MCP server connection. + * This is not part of the public configuration. + * + * @interface McpServerStatus + */ +export interface McpServerStatus { + /** + * The unique identifier for the server. + * @property {string} id + */ + id: string; + /** + * The current connection status of the server. + * @property {'connected' | 'disconnected' | 'error' | 'connecting'} status + */ + status: 'connected' | 'disconnected' | 'error' | 'connecting'; + /** + * The timestamp of the last successful connection. + * @property {Date} [lastConnected] + */ + lastConnected?: Date; + /** + * The last error message received from the server. + * @property {string} [lastError] + */ + lastError?: string; + /** + * The number of tools registered from this server. + * @property {number} toolCount + */ + toolCount: number; +} + +/** + * Defines the configuration for the McpManager. + * + * @interface McpManagerConfig + */ +export interface McpManagerConfig { + /** + * Whether to enable MCP functionality. Defaults to false. + * @property {boolean} enabled + */ + enabled: boolean; + /** + * An optional endpoint URL for discovering MCP servers. + * Defaults to the Zyntopia API if not provided. + * @property {string} [discoveryEndpoint] + */ + discoveryEndpoint?: string; +} + +// McpClientConfig is no longer needed as the new McpClient takes a simpler config. \ No newline at end of file diff --git a/src/systems/observation/observation-manager.test.ts b/src/systems/observation/observation-manager.test.ts deleted file mode 100644 index 228220c..0000000 --- a/src/systems/observation/observation-manager.test.ts +++ /dev/null @@ -1,124 +0,0 @@ -// src/systems/observation/observation-manager.test.ts -import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { ObservationManager } from './observation-manager'; -import { IObservationRepository, ObservationSocket } from '../../core/interfaces'; -import { Observation, ObservationFilter } from '../../types'; -import { generateUUID } from '../../utils/uuid'; - -// Mock dependencies -vi.mock('../../utils/uuid'); - -const mockObservationRepository: IObservationRepository = { - addObservation: vi.fn(), - getObservations: vi.fn(), - // Mock other methods if the interface requires them -}; - -const mockObservationSocket: ObservationSocket = { - subscribe: vi.fn(), - notify: vi.fn(), - getHistory: vi.fn(), -}; - -describe('ObservationManager', () => { - let observationManager: ObservationManager; - const mockThreadId = 'thread-123'; - const mockTraceId = 'trace-abc'; - const mockObservationData: Omit = { - threadId: mockThreadId, - traceId: mockTraceId, - type: 'INTENT' as any, // Cast as any if ObservationType enum isn't imported/used - content: { text: 'User intent' }, - metadata: { source: 'test' }, - }; - const mockGeneratedUUID = 'mock-uuid-456'; - const mockTimestamp = 1678886400000; // Example timestamp - - beforeEach(() => { - vi.clearAllMocks(); - // Mock generateUUID before creating the manager instance - vi.mocked(generateUUID).mockReturnValue(mockGeneratedUUID); - // Mock Date.now() - vi.spyOn(Date, 'now').mockReturnValue(mockTimestamp); - - observationManager = new ObservationManager(mockObservationRepository, mockObservationSocket); - }); - - describe('record', () => { - it('should generate id and timestamp, create title, save observation via repository, and notify via socket', async () => { - const expectedObservation: Observation = { - ...mockObservationData, - id: mockGeneratedUUID, - timestamp: mockTimestamp, - title: `${mockObservationData.type} Recorded`, - }; - - await observationManager.record(mockObservationData); - - // Check repository call - expect(mockObservationRepository.addObservation).toHaveBeenCalledTimes(1); - expect(mockObservationRepository.addObservation).toHaveBeenCalledWith(expectedObservation); - - // Check socket notification - expect(mockObservationSocket.notify).toHaveBeenCalledTimes(1); - expect(mockObservationSocket.notify).toHaveBeenCalledWith(expectedObservation, { targetThreadId: mockThreadId }); - }); - - it('should rethrow error if repository fails', async () => { - const repoError = new Error('Repository failed'); - vi.mocked(mockObservationRepository.addObservation).mockRejectedValueOnce(repoError); - - await expect(observationManager.record(mockObservationData)).rejects.toThrow(repoError); - - // Ensure socket notify was not called - expect(mockObservationSocket.notify).not.toHaveBeenCalled(); - }); - - it('should rethrow error if socket notification fails (after successful save)', async () => { - const socketError = new Error('Socket failed'); - vi.mocked(mockObservationSocket.notify).mockImplementationOnce(() => { throw socketError; }); - - // Note: Depending on desired behavior, you might want the record to succeed even if notification fails. - // Here we assume notification failure should also cause the record operation to throw. - await expect(observationManager.record(mockObservationData)).rejects.toThrow(socketError); - - // Ensure repository save was still called - expect(mockObservationRepository.addObservation).toHaveBeenCalledTimes(1); - }); - }); - - describe('getObservations', () => { - it('should call repository getObservations with threadId and filter', async () => { - const filter: ObservationFilter = { types: ['PLAN' as any] }; - const mockObservations: Observation[] = [ - { id: 'obs-1', threadId: mockThreadId, type: 'PLAN' as any, title: 'Plan 1', content: {}, timestamp: Date.now() }, - ]; - vi.mocked(mockObservationRepository.getObservations).mockResolvedValueOnce(mockObservations); - - const result = await observationManager.getObservations(mockThreadId, filter); - - expect(mockObservationRepository.getObservations).toHaveBeenCalledTimes(1); - expect(mockObservationRepository.getObservations).toHaveBeenCalledWith(mockThreadId, filter); - expect(result).toEqual(mockObservations); - }); - - it('should call repository getObservations with threadId only if no filter provided', async () => { - const mockObservations: Observation[] = []; - vi.mocked(mockObservationRepository.getObservations).mockResolvedValueOnce(mockObservations); - - const result = await observationManager.getObservations(mockThreadId); - - expect(mockObservationRepository.getObservations).toHaveBeenCalledTimes(1); - expect(mockObservationRepository.getObservations).toHaveBeenCalledWith(mockThreadId, undefined); - expect(result).toEqual(mockObservations); - }); - - it('should rethrow error if repository fails', async () => { - const repoError = new Error('Repository failed'); - vi.mocked(mockObservationRepository.getObservations).mockRejectedValueOnce(repoError); - const filter: ObservationFilter = { types: ['PLAN' as any] }; - - await expect(observationManager.getObservations(mockThreadId, filter)).rejects.toThrow(repoError); - }); - }); -}); \ No newline at end of file diff --git a/src/systems/observation/observation-manager.ts b/src/systems/observation/observation-manager.ts old mode 100644 new mode 100755 index 165aec3..ff44f97 --- a/src/systems/observation/observation-manager.ts +++ b/src/systems/observation/observation-manager.ts @@ -1,13 +1,19 @@ -import { ObservationManager as ObservationManagerInterface, IObservationRepository } from '../../core/interfaces'; // Import the interface defined in core/interfaces +import { ObservationManager as ObservationManagerInterface, IObservationRepository } from '@/core/interfaces'; // Import the interface defined in core/interfaces import { ObservationSocket } from '../ui/observation-socket'; // Import the class implementation -import { Observation, ObservationFilter } from '../../types'; // Kept ObservationType and Omit removed -import { generateUUID } from '../../utils/uuid'; // Assuming UUID utility exists as per Phase 0.9 -import { Logger } from '../../utils/logger'; // Import Logger +import { Observation, ObservationFilter } from '@/types'; // Kept ObservationType and Omit removed +import { generateUUID } from '@/utils/uuid'; // Assuming UUID utility exists as per Phase 0.9 +import { Logger } from '@/utils/logger'; // Import Logger /** * Manages the lifecycle of agent observations: creation, persistence, retrieval, and notification. - * It acts as the central service for logging significant events during agent execution. - * Implements the `ObservationManager` interface defined in core interfaces. + * + * @remarks + * It provides methods to record and retrieve observations, which are crucial for + * debugging, monitoring, and analyzing agent behavior. The manager uses a + * repository pattern to abstract the underlying storage mechanism. + * + * @see {@link ObservationManagerInterface} for the interface definition. + * @see {@link IObservationRepository} for the storage repository interface. */ export class ObservationManager implements ObservationManagerInterface { // Implement the imported interface private observationRepository: IObservationRepository; @@ -15,8 +21,9 @@ export class ObservationManager implements ObservationManagerInterface { // Impl /** * Creates an instance of ObservationManager. - * @param observationRepository - The repository for persisting observations. - * @param observationSocket - The socket for notifying UI about new observations. + * + * @param observationRepository The repository for persisting observations. + * @param observationSocket The socket for notifying UI about new observations. */ constructor(observationRepository: IObservationRepository, observationSocket: ObservationSocket) { this.observationRepository = observationRepository; @@ -25,9 +32,12 @@ export class ObservationManager implements ObservationManagerInterface { // Impl /** * Creates, persists, and broadcasts a new observation record based on the provided data. + * + * @remarks * Automatically generates a unique `id`, `timestamp`, and a default `title`. - * Uses the injected `IObservationRepository` for persistence and `ObservationSocket` for notification. - * @param observationData - An object containing the core data for the observation (`threadId`, `type`, `content`, `metadata`, etc.), excluding fields generated by the manager (`id`, `timestamp`, `title`). + * Uses the injected {@link IObservationRepository} for persistence and {@link ObservationSocket} for notification. + * + * @param observationData An object containing the core data for the observation (`threadId`, `type`, `content`, `metadata`, etc.), excluding fields generated by the manager (`id`, `timestamp`, `title`). * @returns A promise that resolves when the observation has been successfully saved and notified, or rejects if a critical error occurs during persistence. Notification errors are logged but generally do not cause rejection. */ async record(observationData: Omit): Promise { // Corrected Omit and Promise syntax @@ -55,11 +65,14 @@ export class ObservationManager implements ObservationManagerInterface { // Impl /** * Retrieves historical observations stored for a specific thread, using the repository. - * Allows filtering based on criteria defined in `ObservationFilter`. - * @param threadId - The ID of the thread whose observations are to be retrieved. - * @param filter - Optional criteria (`ObservationFilter`) to filter the observations (e.g., by type, timestamp). - * @returns A promise resolving to an array of `Observation` objects matching the criteria. - * @throws {Error} If the repository encounters an error during retrieval. + * + * @remarks + * Allows filtering based on criteria defined in {@link ObservationFilter}. + * + * @param threadId The ID of the thread whose observations are to be retrieved. + * @param filter Optional criteria (`ObservationFilter`) to filter the observations (e.g., by type, timestamp). + * @returns A promise resolving to an array of {@link Observation} objects matching the criteria. + * @throws If the repository encounters an error during retrieval. */ async getObservations(threadId: string, filter?: ObservationFilter): Promise { try { diff --git a/src/systems/reasoning/OutputParser.test.ts b/src/systems/reasoning/OutputParser.test.ts deleted file mode 100644 index 827523d..0000000 --- a/src/systems/reasoning/OutputParser.test.ts +++ /dev/null @@ -1,322 +0,0 @@ -// src/systems/reasoning/OutputParser.test.ts -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { OutputParser } from './OutputParser'; -import { Logger } from '../../utils/logger'; // Import Logger for mocking - -// Mock the Logger to prevent console output during tests and allow spying -vi.mock('../../utils/logger', () => ({ - Logger: { - warn: vi.fn(), - error: vi.fn(), - info: vi.fn(), - debug: vi.fn(), - configure: vi.fn(), - }, -})); - -describe('OutputParser', () => { - let outputParser: OutputParser; - - beforeEach(() => { - outputParser = new OutputParser(); - // Reset mocks before each test - vi.clearAllMocks(); - }); - - // --- parsePlanningOutput Tests --- - - it('should parse valid planning output with all sections (no fences)', async () => { - const output = ` - Intent: Find the capital of France and calculate 5 + 7. - Plan: - 1. Use search tool for "capital of France". - 2. Use calculator tool for "5 + 7". - 3. Combine results. - Tool Calls: [ - {"callId": "call_1", "toolName": "search", "arguments": {"query": "capital of France"}}, - {"callId": "call_2", "toolName": "calculator", "arguments": {"expression": "5 + 7"}} - ] - `; - const result = await outputParser.parsePlanningOutput(output); - - expect(result.intent).toBe('Find the capital of France and calculate 5 + 7.'); - expect(result.plan).toBe('1. Use search tool for "capital of France".\n 2. Use calculator tool for "5 + 7".\n 3. Combine results.'); - expect(result.toolCalls).toEqual([ - { callId: 'call_1', toolName: 'search', arguments: { query: 'capital of France' } }, - { callId: 'call_2', toolName: 'calculator', arguments: { expression: '5 + 7' } }, - ]); - expect(Logger.warn).not.toHaveBeenCalled(); - expect(Logger.error).not.toHaveBeenCalled(); - }); - - it('should parse valid planning output with ```json fences', async () => { - const output = ` - Intent: Calculate 2*3. - Plan: Use calculator. - Tool Calls: \`\`\`json - [ - {"callId": "calc1", "toolName": "calculator", "arguments": {"expression": "2*3"}} - ] - \`\`\` - `; - const result = await outputParser.parsePlanningOutput(output); - - expect(result.intent).toBe('Calculate 2*3.'); - expect(result.plan).toBe('Use calculator.'); - expect(result.toolCalls).toEqual([ - { callId: 'calc1', toolName: 'calculator', arguments: { expression: '2*3' } }, - ]); - expect(Logger.warn).not.toHaveBeenCalled(); - expect(Logger.error).not.toHaveBeenCalled(); - }); - - it('should parse valid planning output with ``` fences', async () => { - const output = ` - Intent: Calculate 4/2. - Plan: Use calculator. - Tool Calls: \`\`\` - [ - {"callId": "calc2", "toolName": "calculator", "arguments": {"expression": "4/2"}} - ] - \`\`\` - `; - const result = await outputParser.parsePlanningOutput(output); - - expect(result.intent).toBe('Calculate 4/2.'); - expect(result.plan).toBe('Use calculator.'); - expect(result.toolCalls).toEqual([ - { callId: 'calc2', toolName: 'calculator', arguments: { expression: '4/2' } }, - ]); - expect(Logger.warn).not.toHaveBeenCalled(); - expect(Logger.error).not.toHaveBeenCalled(); - }); - - it('should parse valid planning output with introductory text before JSON array', async () => { - const output = ` - Intent: Test text before JSON. - Plan: Extract the JSON correctly. - Tool Calls: Here is the JSON you requested: - [ - {"callId": "intro_1", "toolName": "testTool", "arguments": {"value": 123}} - ] - Some trailing text maybe. - `; - const result = await outputParser.parsePlanningOutput(output); - - expect(result.intent).toBe('Test text before JSON.'); - expect(result.plan).toBe('Extract the JSON correctly.'); - expect(result.toolCalls).toEqual([ - { callId: 'intro_1', toolName: 'testTool', arguments: { value: 123 } }, - ]); - expect(Logger.warn).not.toHaveBeenCalled(); - expect(Logger.error).not.toHaveBeenCalled(); - }); - - it('should parse valid planning output with introductory text before fenced JSON array', async () => { - const output = ` - Intent: Test text before fenced JSON. - Plan: Extract the JSON correctly. - Tool Calls: Please find the tool calls below: - \`\`\`json - [ - {"callId": "intro_fenced", "toolName": "anotherTool", "arguments": [1, 2, 3]} - ] - \`\`\` - Thank you. - `; - const result = await outputParser.parsePlanningOutput(output); - - expect(result.intent).toBe('Test text before fenced JSON.'); - expect(result.plan).toBe('Extract the JSON correctly.'); - expect(result.toolCalls).toEqual([ - { callId: 'intro_fenced', toolName: 'anotherTool', arguments: [1, 2, 3] }, - ]); - expect(Logger.warn).not.toHaveBeenCalled(); - expect(Logger.error).not.toHaveBeenCalled(); - }); - - it('should parse planning output with missing Plan section', async () => { - const output = ` - Intent: Calculate 10 / 2. - Tool Calls: [{"callId": "c1", "toolName": "calculator", "arguments": {"expression": "10 / 2"}}] - `; - const result = await outputParser.parsePlanningOutput(output); - - expect(result.intent).toBe('Calculate 10 / 2.'); - expect(result.plan).toBeUndefined(); - expect(result.toolCalls).toEqual([ - { callId: 'c1', toolName: 'calculator', arguments: { expression: '10 / 2' } }, - ]); - }); - - it('should parse planning output with missing Intent section', async () => { - const output = ` - Plan: Just say hello. - Tool Calls: [] - `; - const result = await outputParser.parsePlanningOutput(output); - - expect(result.intent).toBeUndefined(); - expect(result.plan).toBe('Just say hello.'); - expect(result.toolCalls).toEqual([]); - }); - - it('should parse planning output with no tool calls (empty array)', async () => { - const output = ` - Intent: Say hello back. - Plan: Respond with "Hello!". - Tool Calls: [] - `; - const result = await outputParser.parsePlanningOutput(output); - - expect(result.intent).toBe('Say hello back.'); - expect(result.plan).toBe('Respond with "Hello!".'); - expect(result.toolCalls).toEqual([]); - }); - - it('should parse planning output with no tool calls (section missing)', async () => { - const output = ` - Intent: Say hello back. - Plan: Respond with "Hello!". - `; - const result = await outputParser.parsePlanningOutput(output); - - expect(result.intent).toBe('Say hello back.'); - expect(result.plan).toBe('Respond with "Hello!".'); - expect(result.toolCalls).toBeUndefined(); // Section missing entirely - }); - - it('should handle malformed JSON in Tool Calls and return empty array', async () => { - const output = ` - Intent: Test malformed JSON. - Plan: See what happens. - Tool Calls: [{"callId": "c1", "toolName": "test", "arguments": {"arg": "value"}] // Missing closing brace - `; - const result = await outputParser.parsePlanningOutput(output); - - expect(result.intent).toBe('Test malformed JSON.'); - expect(result.plan).toBe('See what happens.'); - expect(result.toolCalls).toEqual([]); // Should default to empty array on parse error - expect(Logger.error).toHaveBeenCalledOnce(); - expect(Logger.error).toHaveBeenCalledWith(expect.stringContaining('Failed to parse Tool Calls JSON'), expect.anything()); - }); - - it('should handle malformed JSON inside fences and return empty array', async () => { - const output = ` - Intent: Test malformed JSON in fences. - Plan: See what happens. - Tool Calls: \`\`\`json - [{"callId": "c1", "toolName": "test", "arguments": {"arg": "value"}] // Missing closing brace - \`\`\` - `; - const result = await outputParser.parsePlanningOutput(output); - - expect(result.intent).toBe('Test malformed JSON in fences.'); - expect(result.plan).toBe('See what happens.'); - expect(result.toolCalls).toEqual([]); // Should default to empty array on parse error - expect(Logger.error).toHaveBeenCalledOnce(); - expect(Logger.error).toHaveBeenCalledWith(expect.stringContaining('Failed to parse Tool Calls JSON'), expect.anything()); - }); - - it('should handle non-array JSON (Zod validation failure) and return empty array', async () => { - const output = ` - Intent: Test non-array JSON. - Plan: See what happens. - Tool Calls: {"callId": "c1", "toolName": "test", "arguments": {"arg": "value"}} // Object, not array - `; - const result = await outputParser.parsePlanningOutput(output); - - expect(result.intent).toBe('Test non-array JSON.'); - expect(result.plan).toBe('See what happens.'); - expect(result.toolCalls).toEqual([]); // Should default to empty array on Zod validation failure - // Check that warn was called due to Zod validation failure - expect(Logger.warn).toHaveBeenCalledOnce(); - expect(Logger.warn).toHaveBeenCalledWith(expect.stringContaining('Tool Calls JSON structure validation failed'), expect.anything()); - }); - - it('should handle invalid tool call structure (Zod validation failure) and return empty array', async () => { - const output = ` - Intent: Test invalid structure. - Plan: See what happens. - Tool Calls: [ - {"callId": "c1", "arguments": {"arg": "value"}} // Missing toolName - ] - `; - const result = await outputParser.parsePlanningOutput(output); - - expect(result.intent).toBe('Test invalid structure.'); - expect(result.plan).toBe('See what happens.'); - expect(result.toolCalls).toEqual([]); // Should default to empty array on Zod validation failure - // Check that warn was called due to Zod validation failure - expect(Logger.warn).toHaveBeenCalledOnce(); - expect(Logger.warn).toHaveBeenCalledWith(expect.stringContaining('Tool Calls JSON structure validation failed'), expect.anything()); - }); - - it('should handle invalid tool call structure inside fences (Zod validation failure) and return empty array', async () => { - const output = ` - Intent: Test invalid structure in fences. - Plan: See what happens. - Tool Calls: \`\`\` - [ - {"toolName": "test", "arguments": {}} // Missing callId - ] - \`\`\` - `; - const result = await outputParser.parsePlanningOutput(output); - - expect(result.intent).toBe('Test invalid structure in fences.'); - expect(result.plan).toBe('See what happens.'); - expect(result.toolCalls).toEqual([]); // Should default to empty array on Zod validation failure - // Check that warn was called due to Zod validation failure - expect(Logger.warn).toHaveBeenCalledOnce(); - expect(Logger.warn).toHaveBeenCalledWith(expect.stringContaining('Tool Calls JSON structure validation failed'), expect.anything()); - }); - - it('should handle completely unstructured output', async () => { - const output = 'Just a simple response without any structure.'; - const result = await outputParser.parsePlanningOutput(output); - - expect(result.intent).toBeUndefined(); - expect(result.plan).toBeUndefined(); - expect(result.toolCalls).toBeUndefined(); - expect(Logger.warn).toHaveBeenCalledOnce(); - expect(Logger.warn).toHaveBeenCalledWith(expect.stringContaining('Could not parse any structured data')); - }); - - it('should handle variations in spacing and case', async () => { - const output = ` - intent: Find the capital of Spain. - PLAN: - Use search tool. - tool calls: [ {"callId": "s1", "toolName": "search", "arguments": {"query": "capital of Spain"}} ] - `; - const result = await outputParser.parsePlanningOutput(output); - - expect(result.intent).toBe('Find the capital of Spain.'); - expect(result.plan).toBe('Use search tool.'); - expect(result.toolCalls).toEqual([ - { callId: 's1', toolName: 'search', arguments: { query: 'capital of Spain' } }, - ]); - }); - - // --- parseSynthesisOutput Tests --- - - it('should parse synthesis output by trimming whitespace', async () => { - const output = ' This is the final response. \n '; - const result = await outputParser.parseSynthesisOutput(output); - expect(result).toBe('This is the final response.'); - }); - - it('should handle empty synthesis output', async () => { - const output = ' '; - const result = await outputParser.parseSynthesisOutput(output); - expect(result).toBe(''); - }); - - it('should handle synthesis output with complex content', async () => { - const output = `Here's the calculation result: 42. -The weather in London is currently sunny.`; - const result = await outputParser.parseSynthesisOutput(output); - expect(result).toBe(`Here's the calculation result: 42.\nThe weather in London is currently sunny.`); - }); -}); \ No newline at end of file diff --git a/src/systems/reasoning/OutputParser.ts b/src/systems/reasoning/OutputParser.ts old mode 100644 new mode 100755 index 2e6d24d..fc58dd0 --- a/src/systems/reasoning/OutputParser.ts +++ b/src/systems/reasoning/OutputParser.ts @@ -1,9 +1,9 @@ // src/systems/reasoning/OutputParser.ts import * as z from 'zod'; // Import Zod -import { OutputParser as IOutputParser } from '../../core/interfaces'; -import { ParsedToolCall } from '../../types'; -import { Logger } from '../../utils/logger'; // Import the Logger class -import { XmlMatcher } from '../../utils/xml-matcher'; // Import XmlMatcher +import { OutputParser as IOutputParser } from '@/core/interfaces'; +import { ParsedToolCall } from '@/types'; +import { Logger } from '@/utils/logger'; // Import the Logger class +import { XmlMatcher } from '@/utils/xml-matcher'; // Import XmlMatcher // Define Zod schema for a single tool call const parsedToolCallSchema = z.object({ @@ -17,11 +17,20 @@ const toolCallsSchema = z.array(parsedToolCallSchema); /** * Default implementation of the `OutputParser` interface. - * Responsible for extracting structured data (intent, plan, tool calls) from the planning phase - * LLM response and the final response content from the synthesis phase response. - * Includes robust parsing for tool call JSON arrays and Zod validation. + * - Planning: Extracts Intent, Plan, and Tool Calls from the LLM output while ignoring any + * custom formatting constraints that apps may add. Tool Calls MUST be a JSON array where each + * item conforms to { callId: string, toolName: string, arguments: object }. If Tool Calls + * appears but contains no items, returns []. If the section is absent, leaves `toolCalls` undefined. + * - Synthesis: Returns the final response text (trimmed). * - * @implements {IOutputParser} + * This enforces the framework-level Output Contract and keeps the structure provider-agnostic + * and tool-type-agnostic (native and MCP tools share the same interface). + * + * It is responsible for parsing the raw string output from a Large Language Model (LLM) + * and converting it into a structured format that the ART agent can understand and act upon. + * This includes extracting the agent's intent, the plan, and any tool calls it intends to make. + * + * @see {@link IOutputParser} for the interface definition. */ export class OutputParser implements IOutputParser { /** @@ -29,31 +38,23 @@ export class OutputParser implements IOutputParser { * * This method performs the following steps: * 1. Uses `XmlMatcher` to identify and extract content within `...` tags. - * This extracted content is aggregated into the `thoughts` field of the result. - * 2. The remaining content (outside of `` tags) is then parsed for sections - * explicitly marked with "Intent:", "Plan:", and "Tool Calls:". - * 3. It attempts to find and parse a JSON array within the "Tool Calls:" section, handling - * potential markdown fences (e.g., \`\`\`json ... \`\`\`) and validating the structure using Zod. + * The extracted content is aggregated into the `thoughts` field of the result. + * 2. Attempts a JSON-first parse (Option 2): tries to parse a single JSON object containing + * `{ title?, intent, plan, toolCalls }`. If successful, returns immediately. + * 3. Falls back to the section-based parser (Option 1): parses `Title:`, `Intent:`, `Plan:`, and `Tool Calls:` + * sections from the remaining content. Includes tolerant fallbacks for common wrappers (e.g., code fences). * - * @param output - The raw string response from the planning LLM call, which may include - * text, `` tags, and sections for Intent, Plan, and Tool Calls. - * @returns A promise resolving to an object containing: - * - `thoughts?`: An optional string aggregating content from all `` tags, separated by "\\n\\n---\\n\\n". - * - `intent?`: An optional string for the parsed intent. - * - `plan?`: An optional string for the parsed plan. - * - `toolCalls?`: An optional array of `ParsedToolCall` objects. This will be an empty array `[]` - * if the "Tool Calls:" section is present in the non-thinking content but is empty, - * or if the JSON is invalid/fails validation. It remains `undefined` if the - * "Tool Calls:" section itself is missing from the non-thinking content. - * Fields will be `undefined` if the corresponding section is not found or cannot be parsed correctly. + * The `title` value should be a concise sentence with no more than 10 words. */ async parsePlanningOutput(output: string): Promise<{ + title?: string; intent?: string; plan?: string; toolCalls?: ParsedToolCall[]; thoughts?: string; // Add thoughts to the return type }> { const result: { + title?: string; intent?: string; plan?: string; toolCalls?: ParsedToolCall[]; @@ -82,10 +83,60 @@ export class OutputParser implements IOutputParser { result.thoughts = thoughtsList.join("\n\n---\n\n"); // Join multiple thoughts } - // Now parse Intent, Plan, Tool Calls from the non-thinking content + // Now parse Title, Intent, Plan, Tool Calls from the non-thinking content processedOutput = nonThinkingContent; + // --- Option 2: JSON-first parsing for a single object --- + const tryParsePlanningJson = (raw: string): { title?: string; intent?: string; plan?: string; toolCalls?: ParsedToolCall[] } | null => { + if (!raw) return null; + let s = raw.trim(); + // Remove code fences if present + s = s.replace(/^```(?:json)?\s*/i, '').replace(/\s*```$/i, '').trim(); + // Remove a leading 'json' token on its own line + s = s.replace(/^json\s*/i, '').trim(); + // If it doesn't start with {, try to slice between first { and last } + if (!s.startsWith('{') && s.includes('{') && s.includes('}')) { + const first = s.indexOf('{'); + const last = s.lastIndexOf('}'); + if (first >= 0 && last > first) { + s = s.slice(first, last + 1); + } + } + try { + const obj: any = JSON.parse(s); + if (!obj || (typeof obj !== 'object')) return null; + const out: { title?: string; intent?: string; plan?: string; toolCalls?: ParsedToolCall[] } = {}; + if (typeof obj.title === 'string') out.title = obj.title; + if (typeof obj.intent === 'string') out.intent = obj.intent; + if (Array.isArray(obj.plan)) out.plan = obj.plan.join('\n'); + else if (typeof obj.plan === 'string') out.plan = obj.plan; + if (Array.isArray(obj.toolCalls)) { + const validation = toolCallsSchema.safeParse(obj.toolCalls); + if (validation.success) out.toolCalls = validation.data as ParsedToolCall[]; + else out.toolCalls = []; + } + // Accept if at least one of the expected fields exists + if (out.title || out.intent || out.plan || out.toolCalls) return out; + return null; + } catch { + return null; + } + }; + + const jsonParsed = tryParsePlanningJson(processedOutput); + if (jsonParsed) { + result.title = jsonParsed.title; + result.intent = jsonParsed.intent; + result.plan = jsonParsed.plan; + result.toolCalls = jsonParsed.toolCalls; + return result; + } + + // --- Fallback: section-based parsing (Option 1) --- // Robustly extract sections from the processedOutput (non-thinking part) + const titleMatch = processedOutput.match(/Title:\s*([\s\S]*?)(Intent:|Plan:|Tool Calls:|$)/i); + result.title = titleMatch?.[1]?.trim(); + const intentMatch = processedOutput.match(/Intent:\s*([\s\S]*?)(Plan:|Tool Calls:|$)/i); result.intent = intentMatch?.[1]?.trim(); @@ -156,8 +207,8 @@ export class OutputParser implements IOutputParser { } // Handle cases where sections might be missing entirely from the non-thinking content - if (!result.intent && !result.plan && (result.toolCalls === undefined || result.toolCalls.length === 0) && !result.thoughts) { - Logger.warn(`OutputParser: Could not parse any structured data (Intent, Plan, Tool Calls, Thoughts) from planning output. Original output: ${output}`); + if (!result.title && !result.intent && !result.plan && (result.toolCalls === undefined || result.toolCalls.length === 0) && !result.thoughts) { + Logger.warn(`OutputParser: Could not parse any structured data (Title, Intent, Plan, Tool Calls, Thoughts) from planning output. Original output: ${output}`); // If nothing structured is found, but there were thoughts, that's still a partial parse. // If no thoughts AND no other structure, then it's a more complete failure to parse structure. // If the original output was just thoughts, result.thoughts would be populated. @@ -165,10 +216,10 @@ export class OutputParser implements IOutputParser { // This warning triggers if even thoughts couldn't be extracted AND other sections are also missing. // If only thoughts were present, result.thoughts would exist, and this condition might not be met. // Let's refine the condition: if no standard sections (intent, plan, toolCalls) are found in `processedOutput` - if (!result.intent && !result.plan && (result.toolCalls === undefined || result.toolCalls.length === 0)) { - Logger.debug(`OutputParser: No Intent, Plan, or Tool Calls found in non-thinking content part: ${processedOutput}`); + if (!result.title && !result.intent && !result.plan && (result.toolCalls === undefined || result.toolCalls.length === 0)) { + Logger.debug(`OutputParser: No Title, Intent, Plan, or Tool Calls found in non-thinking content part: ${processedOutput}`); } - } else if (!result.intent && !result.plan && !result.toolCalls && !result.thoughts) { + } else if (!result.title && !result.intent && !result.plan && !result.toolCalls && !result.thoughts) { // This case means absolutely nothing was parsed, not even thoughts. Logger.warn(`OutputParser: Complete failure to parse any structured data or thoughts from planning output: ${output}`); } diff --git a/src/systems/reasoning/PromptManager.test.ts b/src/systems/reasoning/PromptManager.test.ts deleted file mode 100644 index 6158d57..0000000 --- a/src/systems/reasoning/PromptManager.test.ts +++ /dev/null @@ -1,197 +0,0 @@ -// src/systems/reasoning/PromptManager.test.ts -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { PromptManager } from './PromptManager'; -import { - // ArtStandardPrompt, // Removed unused import - // ArtStandardMessage, // Removed unused import - PromptContext, - ToolSchema, - ToolResult, -} from '../../types'; -import { ARTError, ErrorCode } from '../../errors'; -import render from 'mustache'; // Import the default export - -// Mock the mustache default export (render function) -vi.mock('mustache'); // Just mock the module - -describe('PromptManager (Refactored)', () => { - let promptManager: PromptManager; - let mockContext: PromptContext; - let mockBlueprint: string; - - beforeEach(() => { - promptManager = new PromptManager(); - // Reset mocks before each test - vi.resetAllMocks(); - - // Basic context for testing - mockContext = { - query: 'Test query', - systemPrompt: 'You are a test AI.', - history: [ - { role: 'user', content: 'Previous user message' }, - { role: 'assistant', content: 'Previous AI response' }, - ], - availableTools: [ - { name: 'tool1', description: 'Does something', inputSchema: { type: 'object', properties: { arg1: { type: 'string' } } } } as ToolSchema, - ], - toolResults: [ - { callId: 'c1', toolName: 'tool1', status: 'success', output: { result: 'ok' } } as ToolResult, - ], - customData: 'some value', - }; - - // Basic blueprint targeting ArtStandardPrompt JSON structure - mockBlueprint = `[ - { "role": "system", "content": "{{systemPrompt}}" }, - {{#history}} - { "role": "{{role}}", "content": "{{content}}" }{{^last}},{{/last}} - {{/history}}, - { "role": "user", "content": "{{query}} - Custom: {{customData}}" } - ]`; - }); - - it('should call Mustache.render with the blueprint and context', async () => { - const expectedRenderedJson = `[ - { "role": "system", "content": "You are a test AI." }, - { "role": "user", "content": "Previous user message" }, - { "role": "assistant", "content": "Previous AI response" }, - { "role": "user", "content": "Test query - Custom: some value" } - ]`; - (render as any).mockReturnValue(expectedRenderedJson); // Use default import, cast to any for now to bypass TS check - - await promptManager.assemblePrompt(mockBlueprint, mockContext); - - expect(render).toHaveBeenCalledTimes(1); // Use imported render - expect(render).toHaveBeenCalledWith(mockBlueprint, mockContext); // Use imported render - }); - - it('should parse the rendered JSON string into ArtStandardPrompt', async () => { - const renderedJson = `[{"role": "system", "content": "Test"}, {"role": "user", "content": "Hello"}]`; - (render as any).mockReturnValue(renderedJson); // Use default import - - const result = await promptManager.assemblePrompt(mockBlueprint, mockContext); - - expect(result).toEqual([ - { role: 'system', content: 'Test' }, - { role: 'user', content: 'Hello' }, - ]); - expect(Array.isArray(result)).toBe(true); - }); - - it('should correctly assemble a prompt with history and tools context', async () => { - const blueprintWithTools = `[ - { "role": "system", "content": "{{systemPrompt}}" }, - {{#history}} - { "role": "{{role}}", "content": "{{content}}" }{{^last}},{{/last}} - {{/history}}, - { "role": "user", "content": "Query: {{query}}\\nTools: {{#availableTools}}{{name}} {{/availableTools}}" } - ]`; - const expectedRenderedJson = `[ - { "role": "system", "content": "You are a test AI." }, - { "role": "user", "content": "Previous user message" }, - { "role": "assistant", "content": "Previous AI response" }, - { "role": "user", "content": "Query: Test query\\nTools: tool1 " } - ]`; - (render as any).mockReturnValue(expectedRenderedJson); // Use default import - - const result = await promptManager.assemblePrompt(blueprintWithTools, mockContext); - - expect(render).toHaveBeenCalledWith(blueprintWithTools, mockContext); // Use imported render - expect(result).toEqual([ - { role: 'system', content: 'You are a test AI.' }, - { role: 'user', content: 'Previous user message' }, - { role: 'assistant', content: 'Previous AI response' }, - { role: 'user', content: 'Query: Test query\nTools: tool1 ' }, - ]); - }); - - it('should correctly assemble a prompt with tool results context', async () => { - const blueprintWithResults = `[ - { "role": "system", "content": "{{systemPrompt}}" }, - { "role": "user", "content": "{{query}}" }, - { "role": "assistant", "content": "Okay, using tools..." }, - {{#toolResults}} - { "role": "tool_result", "tool_call_id": "{{callId}}", "name": "{{toolName}}", "content": "{{outputJson}}" }{{^last}},{{/last}} - {{/toolResults}} - ]`; - // Simulate context having pre-stringified output - const contextWithStrResults = { - ...mockContext, - toolResults: mockContext.toolResults?.map(r => ({...r, outputJson: JSON.stringify(r.output)})) - }; - const expectedRenderedJson = `[ - { "role": "system", "content": "You are a test AI." }, - { "role": "user", "content": "Test query" }, - { "role": "assistant", "content": "Okay, using tools..." }, - { "role": "tool_result", "tool_call_id": "c1", "name": "tool1", "content": "{\\"result\\":\\"ok\\"}" } - ]`; - (render as any).mockReturnValue(expectedRenderedJson); // Use default import - - const result = await promptManager.assemblePrompt(blueprintWithResults, contextWithStrResults); - - expect(render).toHaveBeenCalledWith(blueprintWithResults, contextWithStrResults); // Use imported render - expect(result).toEqual([ - { role: 'system', content: 'You are a test AI.' }, - { role: 'user', content: 'Test query' }, - { role: 'assistant', content: 'Okay, using tools...' }, - { role: 'tool_result', tool_call_id: 'c1', name: 'tool1', content: '{"result":"ok"}' }, - ]); - }); - - - it('should throw ARTError with PROMPT_ASSEMBLY_FAILED code if render fails', async () => { - const renderError = new Error('Mustache rendering failed'); - (render as any).mockImplementation(() => { // Use default import - throw renderError; - }); - - await expect(promptManager.assemblePrompt(mockBlueprint, mockContext)) - .rejects.toThrow(ARTError); - - try { - await promptManager.assemblePrompt(mockBlueprint, mockContext); - } catch (e: any) { - expect(e).toBeInstanceOf(ARTError); - expect(e.code).toBe(ErrorCode.PROMPT_ASSEMBLY_FAILED); - expect(e.message).toContain('Failed to render prompt blueprint'); - expect(e.originalError).toBe(renderError); - } - }); - - it('should throw ARTError with PROMPT_ASSEMBLY_FAILED code if JSON.parse fails', async () => { - const invalidJson = `[{"role": "system", "content": "Test"}, {"role": "user"`; // Missing closing bracket - (render as any).mockReturnValue(invalidJson); // Use default import - - await expect(promptManager.assemblePrompt(mockBlueprint, mockContext)) - .rejects.toThrow(ARTError); - - try { - await promptManager.assemblePrompt(mockBlueprint, mockContext); - } catch (e: any) { - expect(e).toBeInstanceOf(ARTError); - expect(e.code).toBe(ErrorCode.PROMPT_ASSEMBLY_FAILED); - expect(e.message).toContain('Failed to parse rendered blueprint'); - expect(e.originalError).toBeInstanceOf(Error); // JSON.parse throws SyntaxError - } - }); - - it('should throw ARTError if rendered JSON is not an array', async () => { - const notAnArrayJson = `{"role": "system", "content": "Test"}`; - (render as any).mockReturnValue(notAnArrayJson); // Use default import - - await expect(promptManager.assemblePrompt(mockBlueprint, mockContext)) - .rejects.toThrow(ARTError); - - try { - await promptManager.assemblePrompt(mockBlueprint, mockContext); - } catch (e: any) { - expect(e).toBeInstanceOf(ARTError); - expect(e.code).toBe(ErrorCode.PROMPT_ASSEMBLY_FAILED); - expect(e.message).toContain('Rendered template did not produce a valid JSON array'); - expect(e.originalError).toBeInstanceOf(Error); - } - }); - - // TODO: Add tests for more complex blueprints and context variations if needed -}); \ No newline at end of file diff --git a/src/systems/reasoning/PromptManager.ts b/src/systems/reasoning/PromptManager.ts old mode 100644 new mode 100755 index 13e4b38..52d63a3 --- a/src/systems/reasoning/PromptManager.ts +++ b/src/systems/reasoning/PromptManager.ts @@ -1,10 +1,11 @@ // src/systems/reasoning/PromptManager.ts -import { PromptManager as PromptManagerInterface } from '../../core/interfaces'; -import { ArtStandardPrompt } from '../../types'; -import { ArtStandardPromptSchema } from '../../types/schemas'; // Import Zod schema (Reverted - trying this path again) -import { ARTError, ErrorCode } from '../../errors'; -import { Logger } from '../../utils/logger'; +import { PromptManager as PromptManagerInterface } from '@/core/interfaces'; +import { ArtStandardPrompt, PromptBlueprint, PromptContext } from '@/types'; +import { ArtStandardPromptSchema } from '@/types/schemas'; // Import Zod schema (Reverted - trying this path again) +import { ARTError, ErrorCode } from '@/errors'; +import { Logger } from '@/utils/logger'; import { ZodError } from 'zod'; // Import ZodError for type checking +import mustache from 'mustache'; // --- Define Prompt Fragments --- // Store fragments in a simple object for now. Could be loaded from files later. @@ -59,8 +60,8 @@ export class PromptManager implements PromptManagerInterface { * Validates a constructed prompt object against the standard schema. * * @param prompt - The ArtStandardPrompt object constructed by the agent. - * @returns The validated prompt object. - * @throws {ARTError} If validation fails. + * @returns The validated prompt object (potentially after normalization if the schema does that). + * @throws {ARTError} If validation fails (can be caught and wrapped in ARTError). */ validatePrompt(prompt: ArtStandardPrompt): ArtStandardPrompt { try { @@ -85,4 +86,59 @@ export class PromptManager implements PromptManagerInterface { ); } } + + /** + * Assembles a prompt using a Mustache template (blueprint) and context data. + * Renders the template with the provided context and parses the result as an ArtStandardPrompt. + * + * @param blueprint - The Mustache template containing the prompt structure. + * @param context - The context data to inject into the template. + * @returns A promise resolving to the assembled ArtStandardPrompt. + * @throws {ARTError} If template rendering or JSON parsing fails. + */ + async assemblePrompt(blueprint: PromptBlueprint, context: PromptContext): Promise { + try { + // Render the Mustache template with the context + const renderedTemplate = mustache.render(blueprint.template, context); + + // Parse the rendered template as JSON + let parsedPrompt: any; + try { + parsedPrompt = JSON.parse(renderedTemplate); + } catch (parseError: any) { + Logger.error(`[PromptManager] Failed to parse rendered template as JSON:`, parseError); + throw new ARTError( + `Failed to parse rendered template as JSON: ${parseError.message}`, + ErrorCode.PROMPT_ASSEMBLY_FAILED, + parseError + ); + } + + // Ensure the parsed result is an array + if (!Array.isArray(parsedPrompt)) { + Logger.error(`[PromptManager] Rendered template is not an array:`, parsedPrompt); + throw new ARTError( + `Rendered template is not an array: ${typeof parsedPrompt}`, + ErrorCode.PROMPT_ASSEMBLY_FAILED + ); + } + + // Return the assembled prompt (cast to ArtStandardPrompt) + return parsedPrompt as ArtStandardPrompt; + + } catch (error: any) { + // If it's already an ARTError, re-throw it + if (error instanceof ARTError) { + throw error; + } + + // Otherwise, wrap in ARTError + Logger.error(`[PromptManager] Failed to render prompt template:`, error); + throw new ARTError( + `Failed to render prompt template: ${error.message}`, + ErrorCode.PROMPT_ASSEMBLY_FAILED, + error + ); + } + } } \ No newline at end of file diff --git a/src/providers/ProviderManagerImpl.ts b/src/systems/reasoning/ProviderManagerImpl.ts old mode 100644 new mode 100755 similarity index 65% rename from src/providers/ProviderManagerImpl.ts rename to src/systems/reasoning/ProviderManagerImpl.ts index a29ed05..4ab3f17 --- a/src/providers/ProviderManagerImpl.ts +++ b/src/systems/reasoning/ProviderManagerImpl.ts @@ -4,14 +4,14 @@ import { RuntimeProviderConfig, ManagedAdapterAccessor, AvailableProviderEntry, -} from '../types/providers'; -import { ProviderAdapter } from '../core/interfaces'; +} from '@/types/providers'; +import { ProviderAdapter } from '@/core/interfaces'; import { UnknownProviderError, LocalProviderConflictError, LocalInstanceBusyError, AdapterInstantiationError, // Will need this later -} from '../errors'; +} from '@/errors'; /** Internal type to track managed adapter instances */ interface ManagedInstance { @@ -55,7 +55,8 @@ export class ProviderManagerImpl implements IProviderManager { private _getConfigSignature(config: RuntimeProviderConfig): string { const sortedAdapterOptions = config.adapterOptions ? Object.keys(config.adapterOptions).sort().reduce((obj: any, key) => { - obj[key] = config.adapterOptions[key]; + // Never include secrets in signature logs; signature remains internal only + obj[key] = key.toLowerCase().includes('key') ? '***' : config.adapterOptions[key]; return obj; }, {}) : {}; @@ -79,18 +80,17 @@ export class ProviderManagerImpl implements IProviderManager { if (existingInstance && existingInstance.state === 'idle') { // Reuse idle instance existingInstance.state = 'active'; - // Clear idle timer when reusing (checklist item 12 part of 95) + // Clear idle timer when reusing if (existingInstance.idleTimer) { clearTimeout(existingInstance.idleTimer); existingInstance.idleTimer = undefined; } - console.log(`Reusing idle instance for signature: ${configSignature}`); // Temporary log const release = () => this._releaseAdapter(configSignature); return { adapter: existingInstance.adapter, release }; } - // 2. Check local provider constraints (checklist item 12 part of 97-102) + // 2. Check local provider constraints const providerEntry = this.availableProviders.get(config.providerName); if (!providerEntry) { throw new UnknownProviderError(config.providerName); @@ -100,69 +100,62 @@ export class ProviderManagerImpl implements IProviderManager { let idleLocalProviderDifferentSignature: ManagedInstance | undefined = undefined; for (const [sig, instance] of this.managedInstances.entries()) { - const entry = this.availableProviders.get(instance.configSignature.split('"providerName":"')[1].split('"')[0]); // Extract providerName from signature - TODO: Better way? + const entry = this.availableProviders.get(instance.configSignature.split('"providerName":"')[1].split('"')[0]); if (entry?.isLocal) { if (instance.state === 'active') { if (sig !== configSignature) { - // Another local provider is active throw new LocalProviderConflictError(config.providerName, entry.name); } else { - // The same local instance is busy throw new LocalInstanceBusyError(config.providerName, config.modelId); } } else if (instance.state === 'idle' && sig !== configSignature) { - // Found an idle local provider with a different signature idleLocalProviderDifferentSignature = instance; } } } - // If a different idle local provider exists, evict it if (idleLocalProviderDifferentSignature) { - console.log(`Evicting idle local instance with different signature: ${idleLocalProviderDifferentSignature.configSignature}`); // Temporary log await this._evictInstance(idleLocalProviderDifferentSignature.configSignature); } } - // 3. Check API provider concurrency limits (checklist item 12 part of 89-90) + // 3. Check API provider concurrency limits if (!providerEntry.isLocal) { const activeApiInstancesCount = Array.from(this.managedInstances.values()).filter( instance => { - const entry = this.availableProviders.get(instance.configSignature.split('"providerName":"')[1].split('"')[0]); // Extract providerName - TODO: Better way? + const entry = this.availableProviders.get(instance.configSignature.split('"providerName":"')[1].split('"')[0]); return entry && !entry.isLocal && instance.state === 'active' && entry.name === config.providerName; } ).length; if (activeApiInstancesCount >= this.maxParallelApiInstancesPerProvider) { - console.log(`API limit reached for ${config.providerName}. Queueing request.`); // Temporary log - // 4. If limits reached, queue request (checklist item 12 part of 90) return new Promise((resolve, reject) => { - // Store config, resolve, and reject in the queue this.requestQueue.push({ config, resolve, reject }); }); } } - // 5. If no limits, create new instance (checklist item 12 part of 360) + // 4. Create new instance let adapterInstance: ProviderAdapter; try { - adapterInstance = new providerEntry.adapter(config.adapterOptions); + const adapterOptions = { + ...config.adapterOptions, + providerName: config.providerName + }; + adapterInstance = new providerEntry.adapter(adapterOptions); } catch (error: any) { throw new AdapterInstantiationError(config.providerName, error); } - - // 6. Store new instance (checklist item 12 part of 361) + // 5. Store new instance const newManagedInstance: ManagedInstance = { adapter: adapterInstance, configSignature: configSignature, state: 'active', }; this.managedInstances.set(configSignature, newManagedInstance); - console.log(`Created new instance for signature: ${configSignature}`); // Temporary log - - // 7. Return ManagedAdapterAccessor for new instance (checklist item 12 part of 362) + // 6. Return accessor const release = () => this._releaseAdapter(configSignature); return { adapter: newManagedInstance.adapter, release }; } @@ -172,19 +165,17 @@ export class ProviderManagerImpl implements IProviderManager { * @param configSignature The signature of the instance to release. */ private _releaseAdapter(configSignature: string): void { - console.log(`Release called for signature: ${configSignature}`); // Temporary log const instance = this.managedInstances.get(configSignature); if (!instance) { - console.warn(`Attempted to release unknown instance with signature: ${configSignature}`); return; } instance.state = 'idle'; instance.lastUsedTimestamp = Date.now(); - const providerEntry = this.availableProviders.get(instance.configSignature.split('"providerName":"')[1].split('"')[0]); // Extract providerName - TODO: Better way? + const providerEntry = this.availableProviders.get(instance.configSignature.split('"providerName":"')[1].split('"')[0]); - // Start idle timer for API instances (checklist item 13 part of 366) + // Start idle timer for API instances if (providerEntry && !providerEntry.isLocal) { if (instance.idleTimer) { clearTimeout(instance.idleTimer); @@ -194,18 +185,13 @@ export class ProviderManagerImpl implements IProviderManager { }, this.apiInstanceIdleTimeoutMs); } - // Check request queue (checklist item 13 part of 367) + // Check request queue if (this.requestQueue.length > 0) { - // Dequeue the oldest request const nextRequest = this.requestQueue.shift(); if (nextRequest) { - console.log(`Dequeuing request for provider: ${nextRequest.config.providerName}`); // Temporary log - // Attempt to fulfill the dequeued request by recursively calling getAdapter - // This will either find an idle instance (potentially the one just released) - // or create a new one if allowed, or re-queue if limits are still hit. this.getAdapter(nextRequest.config) - .then(nextRequest.resolve) // Resolve the original promise with the obtained accessor - .catch(nextRequest.reject); // Reject the original promise if getting the adapter fails + .then(nextRequest.resolve) + .catch(nextRequest.reject); } } } @@ -215,34 +201,22 @@ export class ProviderManagerImpl implements IProviderManager { * @param configSignature The signature of the instance to evict. */ private async _evictInstance(configSignature: string): Promise { - console.log(`Attempting to evict instance with signature: ${configSignature}`); // Temporary log const instance = this.managedInstances.get(configSignature); - // Only evict if the instance exists and is currently idle if (instance && instance.state === 'idle') { - console.log(`Evicting idle instance with signature: ${configSignature}`); // Temporary log - // Call adapter.shutdown?.() (checklist item 14 part of 371) if (instance.adapter.shutdown) { try { await instance.adapter.shutdown(); - console.log(`Adapter shutdown successful for ${configSignature}`); - } catch (error) { - console.error(`Error during adapter shutdown for ${configSignature}:`, error); + } catch (_error) { + // swallow adapter shutdown errors } } this.managedInstances.delete(configSignature); - // Clear timer reference if it exists (checklist item 14 part of 373) if (instance.idleTimer) { clearTimeout(instance.idleTimer); instance.idleTimer = undefined; } - } else if (instance && instance.state === 'active') { - console.log(`Instance with signature ${configSignature} is active, not evicting.`); // Temporary log - } else { - console.log(`Instance with signature ${configSignature} not found, cannot evict.`); // Temporary log } } - - // Note: Queue processing is handled in _releaseAdapter. Idle eviction is handled by timers set in _releaseAdapter calling _evictInstance. } \ No newline at end of file diff --git a/src/systems/reasoning/ReasoningEngine.test.ts b/src/systems/reasoning/ReasoningEngine.test.ts deleted file mode 100644 index 6790124..0000000 --- a/src/systems/reasoning/ReasoningEngine.test.ts +++ /dev/null @@ -1,161 +0,0 @@ -// src/systems/reasoning/ReasoningEngine.test.ts -import { describe, it, expect, beforeEach, vi, Mock } from 'vitest'; // Import Mock type -import { ReasoningEngine } from './ReasoningEngine'; -import { - IProviderManager, - ManagedAdapterAccessor, - ProviderAdapter, -} from '../../types/providers'; // Import types from providers.ts -import { FormattedPrompt, CallOptions, StreamEvent } from '../../types'; // Import types from ../../types -import { Logger } from '../../utils/logger'; - -// Mock Logger -vi.mock('../../utils/logger', () => ({ - Logger: { - warn: vi.fn(), - error: vi.fn(), - info: vi.fn(), - debug: vi.fn(), - configure: vi.fn(), - }, -})); - -// Mock ProviderAdapter for use within ManagedAdapterAccessor -class MockProviderAdapter implements ProviderAdapter { - providerName: string = 'mock-adapter'; - async call(_prompt: FormattedPrompt, _options: CallOptions): Promise> { - // Simulate a stream - const stream: AsyncIterable = (async function*() { - yield { type: 'TOKEN', data: 'chunk1', threadId: _options.threadId, traceId: _options.traceId || 'mock-trace-id' }; - yield { type: 'TOKEN', data: 'chunk2', threadId: _options.threadId, traceId: _options.traceId || 'mock-trace-id' }; - yield { type: 'END', data: null, threadId: _options.threadId, traceId: _options.traceId || 'mock-trace-id' }; - })(); - return stream; - } - async shutdown(): Promise { - // Mock shutdown - } -} - -// Mock IProviderManager -const mockProviderManager: IProviderManager = { - getAvailableProviders: vi.fn(), - getAdapter: vi.fn(), - // shutdown: vi.fn(), // Optional shutdown -}; - -describe('ReasoningEngine', () => { - let engine: ReasoningEngine; - const defaultCallOptions: CallOptions = { threadId: 't1', providerConfig: { providerName: 'mock', modelId: 'mock-model', adapterOptions: {} } }; - const defaultPrompt: FormattedPrompt = [{ role: 'user', content: 'Test prompt' }]; - - // Mock ManagedAdapterAccessor and its release function - const mockAdapter = new MockProviderAdapter(); - const mockRelease = vi.fn(); - const mockAccessor: ManagedAdapterAccessor = { - adapter: mockAdapter, - release: mockRelease, - }; - - beforeEach(() => { - // Reset mocks before each test - vi.clearAllMocks(); - // Mock getAdapter to return the mock accessor - (mockProviderManager.getAdapter as Mock).mockResolvedValue(mockAccessor); - - // Initialize engine with the mock ProviderManager - engine = new ReasoningEngine(mockProviderManager); - }); - - it('should be instantiated with a valid ProviderManager', () => { - expect(engine).toBeInstanceOf(ReasoningEngine); - expect(Logger.info).toHaveBeenCalledOnce(); - expect(Logger.info).toHaveBeenCalledWith('ReasoningEngine initialized'); - }); - - it('should request an adapter from the ProviderManager for each call', async () => { - await engine.call(defaultPrompt, defaultCallOptions); - - expect(mockProviderManager.getAdapter).toHaveBeenCalledOnce(); - expect(mockProviderManager.getAdapter).toHaveBeenCalledWith(defaultCallOptions.providerConfig); // Assuming providerConfig is in callOptions - }); - - it('should use the adapter returned by the ProviderManager to make the LLM call', async () => { - const adapterCallSpy = vi.spyOn(mockAdapter, 'call'); - - await engine.call(defaultPrompt, defaultCallOptions); - - expect(adapterCallSpy).toHaveBeenCalledOnce(); - expect(adapterCallSpy).toHaveBeenCalledWith(defaultPrompt, defaultCallOptions); - }); - - it('should return an async iterable from the adapter call', async () => { - const result = await engine.call(defaultPrompt, defaultCallOptions); - expect(typeof result[Symbol.asyncIterator]).toBe('function'); - }); - - it('should call the release function after consuming the async iterable', async () => { - const resultStream = await engine.call(defaultPrompt, defaultCallOptions); - - // Consume the stream - // eslint-disable-next-line @typescript-eslint/no-unused-vars - for await (const _event of resultStream) { - // Do nothing, just consume - } - - expect(mockRelease).toHaveBeenCalledOnce(); - }); - - it('should call the release function even if consuming the async iterable throws an error', async () => { - // Mock the adapter's call to return a stream that throws after the first chunk - const errorStream: AsyncIterable = (async function*() { - yield { type: 'TOKEN', data: 'chunk1', threadId: defaultCallOptions.threadId, traceId: defaultCallOptions.traceId || 'mock-trace-id' }; - throw new Error('Stream error'); - })(); - const adapterCallSpy = vi.spyOn(mockAdapter, 'call').mockResolvedValueOnce(errorStream); - - const resultStream = await engine.call(defaultPrompt, defaultCallOptions); - - // Consume the stream and expect it to throw - await expect(async () => { - // eslint-disable-next-line @typescript-eslint/no-unused-vars - for await (const _event of resultStream) { - // Consume - } - }).rejects.toThrow('Stream error'); - - // The release function should still have been called - expect(mockRelease).toHaveBeenCalledOnce(); - expect(adapterCallSpy).toHaveBeenCalledOnce(); - }); - - it('should call the release function even if consuming the async iterable is cancelled (e.g., break)', async () => { - const resultStream = await engine.call(defaultPrompt, defaultCallOptions); - - // Consume only the first chunk and break - for await (const event of resultStream) { - expect(event.type).toBe('TOKEN'); - break; // Cancel consumption - } - - // The release function should still have been called - expect(mockRelease).toHaveBeenCalledOnce(); - }); - - it('should handle errors from getAdapter, log them, and re-throw', async () => { - const getAdapterError = new Error('Failed to get adapter'); - (mockProviderManager.getAdapter as Mock).mockRejectedValueOnce(getAdapterError); - - await expect(engine.call(defaultPrompt, defaultCallOptions)).rejects.toThrow('Failed to get adapter'); - - expect(mockProviderManager.getAdapter).toHaveBeenCalledOnce(); - expect(Logger.error).toHaveBeenCalledOnce(); - expect(Logger.error).toHaveBeenCalledWith( - 'ReasoningEngine encountered an error getting adapter from ProviderManager:', - expect.objectContaining({ error: getAdapterError }) - ); - expect(mockRelease).not.toHaveBeenCalled(); // Release should not be called if adapter wasn't obtained - }); - - // TODO: Add tests for different StreamEvent types being handled/propagated correctly if needed by ReasoningEngine logic (currently it just passes the stream through) -}); \ No newline at end of file diff --git a/src/systems/reasoning/ReasoningEngine.ts b/src/systems/reasoning/ReasoningEngine.ts old mode 100644 new mode 100755 index 8ec8616..f2cdf06 --- a/src/systems/reasoning/ReasoningEngine.ts +++ b/src/systems/reasoning/ReasoningEngine.ts @@ -2,17 +2,22 @@ import { ReasoningEngine as IReasoningEngine, // Removed ProviderAdapter import -} from '../../core/interfaces'; -import { FormattedPrompt, CallOptions, StreamEvent } from '../../types'; -import { IProviderManager, ManagedAdapterAccessor, RuntimeProviderConfig } from '../../types/providers'; // Import ProviderManager types and RuntimeProviderConfig -import { Logger } from '../../utils/logger'; +} from '@/core/interfaces'; +import { FormattedPrompt, CallOptions, StreamEvent } from '@/types'; +import { IProviderManager, ManagedAdapterAccessor, RuntimeProviderConfig } from '@/types/providers'; // Import ProviderManager types and RuntimeProviderConfig +import { Logger } from '@/utils/logger'; /** * Default implementation of the `ReasoningEngine` interface. * This class uses the `ProviderManager` to dynamically obtain `ProviderAdapter` instances * based on the runtime configuration provided in `CallOptions`. * - * @implements {IReasoningEngine} + * It abstracts the details of interacting with a specific LLM provider by using a + * `ProviderAdapter`. This allows the agent to switch between different LLM providers + * (like OpenAI, Anthropic, Gemini) without changing its core logic. + * + * @see {@link IReasoningEngine} for the interface definition. + * @see {@link ProviderAdapter} for the adapter interface to different LLM providers. */ export class ReasoningEngine implements IReasoningEngine { private providerManager: IProviderManager; // Replaced adapter with providerManager diff --git a/src/systems/reasoning/SystemPromptResolver.ts b/src/systems/reasoning/SystemPromptResolver.ts new file mode 100755 index 0000000..70bf47e --- /dev/null +++ b/src/systems/reasoning/SystemPromptResolver.ts @@ -0,0 +1,91 @@ +// src/systems/reasoning/SystemPromptResolver.ts +import { SystemPromptResolver as ISystemPromptResolver } from '@/core/interfaces'; +import { SystemPromptsRegistry, SystemPromptOverride, SystemPromptMergeStrategy } from '@/types'; +import { PromptManager } from './PromptManager'; +import { Logger } from '@/utils/logger'; + +function applyStrategy(base: string, addition: string, strategy: SystemPromptMergeStrategy | undefined): string { + const s = strategy || 'append'; + switch (s) { + case 'prepend': + return `${addition}\n\n${base}`; + case 'append': + default: + return `${base}\n\n${addition}`; + } +} + +function normalizeOverride(input?: string | SystemPromptOverride): SystemPromptOverride | undefined { + if (!input) return undefined; + if (typeof input === 'string') { + return { content: input, strategy: 'append' }; + } + return input; +} + +/** + * Resolves layered system prompts using append/prepend-only merge. + * Note: 'replace' is intentionally unsupported to prevent custom prompts + * from overriding framework-required structural contracts. + */ +export class SystemPromptResolver implements ISystemPromptResolver { + private readonly registry?: SystemPromptsRegistry; + private readonly promptManager: PromptManager; + + constructor(promptManager: PromptManager, registry?: SystemPromptsRegistry) { + this.promptManager = promptManager; + this.registry = registry; + } + + async resolve(input: { base: string; instance?: string | SystemPromptOverride; thread?: string | SystemPromptOverride; call?: string | SystemPromptOverride; }, traceId?: string): Promise { + let finalPrompt = input.base; + + const levels: Array<{ src: string; ov?: SystemPromptOverride }> = [ + { src: 'instance', ov: normalizeOverride(input.instance) }, + { src: 'thread', ov: normalizeOverride(input.thread) }, + { src: 'call', ov: normalizeOverride(input.call) }, + ]; + + for (const lvl of levels) { + const ov = lvl.ov; + if (!ov) continue; + + let rendered = ''; + // Tag-based preset + if (ov.tag && this.registry?.specs?.[ov.tag]) { + const spec = this.registry.specs[ov.tag]; + const variables = { ...(spec.defaultVariables || {}), ...(ov.variables || {}) }; + rendered = this.renderTemplate(spec.template, variables); + finalPrompt = applyStrategy(finalPrompt, rendered, ov.strategy || spec.mergeStrategy || 'append'); + Logger.debug?.(`[${traceId || 'no-trace'}] Applied system prompt tag '${ov.tag}' with strategy '${ov.strategy || spec.mergeStrategy || 'append'}'.`); + } + // Freeform content + else if (ov.content) { + rendered = ov.content; + finalPrompt = applyStrategy(finalPrompt, rendered, ov.strategy || 'append'); + Logger.debug?.(`[${traceId || 'no-trace'}] Applied freeform system prompt with strategy '${ov.strategy || 'append'}'.`); + } + // No-op if neither tag nor content + } + + return finalPrompt; + } + + private renderTemplate(template: string, variables: Record): string { + // Replace fragments first: {{fragment:name}} + const withFragments = template.replace(/\{\{\s*fragment:([^}]+)\s*\}\}/g, (_m, name) => { + try { + return this.promptManager.getFragment(String(name).trim()); + } catch { + return ''; + } + }); + // Replace simple variables: {{var}} + return withFragments.replace(/\{\{\s*([^}:]+)\s*\}\}/g, (_m, key) => { + const v = variables[String(key).trim()]; + return v !== undefined ? String(v) : ''; + }); + } +} + + diff --git a/src/systems/tool/ToolRegistry.test.ts b/src/systems/tool/ToolRegistry.test.ts deleted file mode 100644 index e7783c9..0000000 --- a/src/systems/tool/ToolRegistry.test.ts +++ /dev/null @@ -1,232 +0,0 @@ -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { ToolRegistry } from './ToolRegistry'; -import { IToolExecutor, StateManager } from '../../core/interfaces'; // Import StateManager -import { ToolSchema, ExecutionContext, ToolResult } from '../../types'; -import { Logger } from '../../utils/logger'; - -// Mock Logger -vi.mock('../../utils/logger', () => ({ - Logger: { - warn: vi.fn(), - error: vi.fn(), - info: vi.fn(), - debug: vi.fn(), - configure: vi.fn(), - }, -})); - -// Mock StateManager (basic mock, adjust if specific methods are needed) -// We need to mock the actual module where StateManager might be defined if it's a class, -// or mock the interface implementation if it's expected to be injected. -// Assuming StateManager is conceptually an interface fulfilled elsewhere, -// we mock the expected methods. -const mockLoadThreadContext = vi.fn(); -const MockStateManager = vi.fn(() => ({ - loadThreadContext: mockLoadThreadContext, -})); - -// Mock Tool Executor implementation -class MockToolExecutor implements IToolExecutor { - constructor(public schema: ToolSchema) {} - async execute(input: any, context: ExecutionContext): Promise { - // Basic mock execution - return { - callId: context.traceId || 'mock-call-id', - toolName: this.schema.name, - status: 'success', - output: { inputReceived: input }, - }; - } -} - -describe('ToolRegistry', () => { - let registry: ToolRegistry; - let mockTool1: IToolExecutor; - let mockTool2: IToolExecutor; - let mockStateManagerInstance: StateManager; // Instance for tests needing it - - beforeEach(() => { - vi.clearAllMocks(); // Clear all mocks before each test - - // Create mock StateManager instance for specific tests - mockStateManagerInstance = new (MockStateManager as any)(); - - // Create registry without StateManager by default for most tests - registry = new ToolRegistry(); - - - // Create mock tools - mockTool1 = new MockToolExecutor({ - name: 'tool1', - description: 'Mock tool 1', - inputSchema: { type: 'object', properties: { param1: { type: 'string' } } }, - }); - mockTool2 = new MockToolExecutor({ - name: 'tool2', - description: 'Mock tool 2', - inputSchema: { type: 'object', properties: { value: { type: 'number' } } }, - }); - }); - - it('should register a tool successfully', async () => { - await registry.registerTool(mockTool1); - const executor = await registry.getToolExecutor('tool1'); - expect(executor).toBe(mockTool1); - expect(Logger.debug).toHaveBeenCalledWith('ToolRegistry: Registered tool "tool1".'); - }); - - it('should throw error when registering an invalid executor', async () => { - // Use try-catch for async errors or .rejects.toThrow() - await expect(registry.registerTool(null as any)).rejects.toThrow('Invalid tool executor provided for registration.'); - await expect(registry.registerTool({} as any)).rejects.toThrow('Invalid tool executor provided for registration.'); - await expect(registry.registerTool({ schema: {} } as any)).rejects.toThrow('Invalid tool executor provided for registration.'); - // Check logger after awaiting promises - expect(Logger.error).toHaveBeenCalledTimes(3); - expect(Logger.error).toHaveBeenCalledWith('ToolRegistry: Attempted to register an invalid tool executor.'); - }); - - - it('should overwrite an existing tool registration and log a warning', async () => { - const newMockTool1 = new MockToolExecutor({ ...mockTool1.schema, description: 'New Tool 1' }); - await registry.registerTool(mockTool1); // Initial registration - await registry.registerTool(newMockTool1); // Overwrite - - const executor = await registry.getToolExecutor('tool1'); - expect(executor).toBe(newMockTool1); // Should be the new one - expect(executor?.schema.description).toBe('New Tool 1'); - expect(Logger.warn).toHaveBeenCalledOnce(); - expect(Logger.warn).toHaveBeenCalledWith('ToolRegistry: Overwriting existing tool registration for "tool1".'); - expect(Logger.debug).toHaveBeenCalledWith('ToolRegistry: Registered tool "tool1".'); // Called twice - expect(Logger.debug).toHaveBeenCalledTimes(2); - }); - - it('should return undefined for a non-existent tool', async () => { - const executor = await registry.getToolExecutor('nonexistent_tool'); - expect(executor).toBeUndefined(); - expect(Logger.debug).toHaveBeenCalledWith('ToolRegistry: Tool "nonexistent_tool" not found.'); - }); - - // --- Failing Tests Analysis & Fixes --- - - it('should return available tool schemas when StateManager is NOT provided', async () => { - // Uses default registry without StateManager - await registry.registerTool(mockTool1); - await registry.registerTool(mockTool2); - - const schemas = await registry.getAvailableTools(); - expect(schemas).toHaveLength(2); - // Sort schemas by name for consistent order before comparing - const sortedSchemas = schemas.sort((a, b) => a.name.localeCompare(b.name)); - const expectedSchemas = [mockTool1.schema, mockTool2.schema].sort((a, b) => a.name.localeCompare(b.name)); - expect(sortedSchemas).toEqual(expectedSchemas); // Use toEqual for deep comparison - // Check the final log message specifically - expect(Logger.debug).toHaveBeenCalledWith('ToolRegistry: Returning all 2 registered tool schemas.'); - }); - - it('should return empty array if no tools are registered when StateManager is NOT provided', async () => { - // Uses default registry without StateManager - const schemas = await registry.getAvailableTools(); - expect(schemas).toHaveLength(0); - expect(schemas).toEqual([]); - // Check the final log message specifically - expect(Logger.debug).toHaveBeenCalledWith('ToolRegistry: Returning all 0 registered tool schemas.'); - }); - - it('should ignore filter and log warning if StateManager is NOT provided', async () => { - // This test uses the default registry created *without* a StateManager - await registry.registerTool(mockTool1); - const schemas = await registry.getAvailableTools({ enabledForThreadId: 't1' }); - - expect(schemas).toHaveLength(1); // Still returns all registered tools - expect(schemas[0]).toEqual(mockTool1.schema); // Use toEqual for deep comparison - expect(Logger.warn).toHaveBeenCalledOnce(); - expect(Logger.warn).toHaveBeenCalledWith('ToolRegistry: Filtering by enabledForThreadId requested, but StateManager was not provided. Returning all tools.'); - // Also check the final debug log - expect(Logger.debug).toHaveBeenCalledWith('ToolRegistry: Returning all 1 registered tool schemas.'); - }); - - // --- New tests for StateManager integration --- - - describe('with StateManager', () => { - beforeEach(() => { - // Create a new registry *with* the mock StateManager for these tests - registry = new ToolRegistry(mockStateManagerInstance); - // Reset mock calls for the manager between tests in this block - mockLoadThreadContext.mockClear(); - }); - - it('should filter tools if StateManager is provided and returns enabled tools', async () => { - await registry.registerTool(mockTool1); // name: tool1 - await registry.registerTool(mockTool2); // name: tool2 - - // Configure the mock StateManager for this test - const mockContext = { - config: { enabledTools: ['tool1'] } // Only tool1 is enabled - }; - mockLoadThreadContext.mockResolvedValue(mockContext); - - const schemas = await registry.getAvailableTools({ enabledForThreadId: 'thread-abc' }); - - expect(mockLoadThreadContext).toHaveBeenCalledWith('thread-abc'); - expect(schemas).toHaveLength(1); - expect(schemas[0]).toEqual(mockTool1.schema); - expect(Logger.debug).toHaveBeenCalledWith('ToolRegistry: Attempting to filter tools for threadId: thread-abc'); - expect(Logger.debug).toHaveBeenCalledWith('ToolRegistry: Found enabled tools for thread thread-abc: tool1'); - expect(Logger.debug).toHaveBeenCalledWith('ToolRegistry: Returning 1 enabled tool schemas for thread thread-abc.'); - expect(Logger.warn).not.toHaveBeenCalled(); // No warnings expected - }); - - it('should return all tools and warn if StateManager has no config/enabledTools for thread', async () => { - await registry.registerTool(mockTool1); - await registry.registerTool(mockTool2); - - // Mock StateManager to return context without enabledTools or null - mockLoadThreadContext.mockResolvedValue({ config: {} }); // or mockResolvedValue(null) - - const schemas = await registry.getAvailableTools({ enabledForThreadId: 'thread-xyz' }); - - expect(mockLoadThreadContext).toHaveBeenCalledWith('thread-xyz'); - expect(schemas).toHaveLength(2); // Returns all tools - expect(schemas).toEqual(expect.arrayContaining([mockTool1.schema, mockTool2.schema])); - expect(Logger.warn).toHaveBeenCalledWith('ToolRegistry: No specific enabledTools found for thread thread-xyz or config missing. Returning all tools.'); - // Check final debug log - expect(Logger.debug).toHaveBeenCalledWith('ToolRegistry: Returning all 2 registered tool schemas.'); - }); - - it('should return all tools and log error if StateManager throws error', async () => { - await registry.registerTool(mockTool1); - - // Mock StateManager to throw an error - const loadError = new Error('Database connection failed'); - mockLoadThreadContext.mockRejectedValue(loadError); - - const schemas = await registry.getAvailableTools({ enabledForThreadId: 'thread-err' }); - - expect(mockLoadThreadContext).toHaveBeenCalledWith('thread-err'); - expect(schemas).toHaveLength(1); // Returns all tools as fallback - expect(schemas[0]).toEqual(mockTool1.schema); - expect(Logger.error).toHaveBeenCalledWith('ToolRegistry: Error loading thread config for thread-err: Database connection failed. Returning all tools.'); - // Check final debug log - expect(Logger.debug).toHaveBeenCalledWith('ToolRegistry: Returning all 1 registered tool schemas.'); - }); - }); - // --- End of new tests --- - - - it('should clear all registered tools', async () => { - await registry.registerTool(mockTool1); - await registry.registerTool(mockTool2); - - let schemas = await registry.getAvailableTools(); - expect(schemas).toHaveLength(2); - - await registry.clearAllTools(); - - schemas = await registry.getAvailableTools(); - expect(schemas).toHaveLength(0); - const executor1 = await registry.getToolExecutor('tool1'); - expect(executor1).toBeUndefined(); - // Check the specific log message for clearing - expect(Logger.debug).toHaveBeenCalledWith('ToolRegistry: Cleared all registered tools.'); - }); -}); \ No newline at end of file diff --git a/src/systems/tool/ToolRegistry.ts b/src/systems/tool/ToolRegistry.ts old mode 100644 new mode 100755 index 0501299..6a486e5 --- a/src/systems/tool/ToolRegistry.ts +++ b/src/systems/tool/ToolRegistry.ts @@ -1,7 +1,7 @@ // src/systems/tool/ToolRegistry.ts -import { ToolRegistry as IToolRegistry, IToolExecutor, StateManager } from '../../core/interfaces'; // Added StateManager import -import { ToolSchema } from '../../types'; -import { Logger } from '../../utils/logger'; +import { ToolRegistry as IToolRegistry, IToolExecutor, StateManager } from '@/core/interfaces'; // Added StateManager import +import { ToolSchema } from '@/types'; +import { Logger } from '@/utils/logger'; /** * A simple in-memory implementation of the `ToolRegistry` interface. @@ -106,4 +106,34 @@ export class ToolRegistry implements IToolRegistry { this.executors.clear(); Logger.debug('ToolRegistry: Cleared all registered tools.'); } + + /** + * Unregister a single tool by name. + */ + async unregisterTool(toolName: string): Promise { + if (this.executors.delete(toolName)) { + Logger.debug(`ToolRegistry: Unregistered tool "${toolName}".`); + } + } + + /** + * Unregister tools matching a predicate; returns count removed. + */ + async unregisterTools(predicate: (schema: ToolSchema) => boolean): Promise { + let removed = 0; + for (const [name, exec] of Array.from(this.executors.entries())) { + try { + if (predicate(exec.schema)) { + this.executors.delete(name); + removed++; + } + } catch { + // ignore predicate errors + } + } + if (removed > 0) { + Logger.debug(`ToolRegistry: Unregistered ${removed} tool(s) via predicate.`); + } + return removed; + } } \ No newline at end of file diff --git a/src/systems/tool/ToolSystem.test.ts b/src/systems/tool/ToolSystem.test.ts deleted file mode 100644 index 611808d..0000000 --- a/src/systems/tool/ToolSystem.test.ts +++ /dev/null @@ -1,261 +0,0 @@ -// src/systems/tool/ToolSystem.test.ts -import { describe, it, expect, beforeEach, vi, Mock } from 'vitest'; // Import Mock -import { ToolSystem } from './ToolSystem'; -import { ToolRegistry, StateManager, IToolExecutor } from '../../core/interfaces'; -import { ParsedToolCall, ToolResult, ExecutionContext, ToolSchema } from '../../types'; -import { validateJsonSchema } from '../../utils/validation'; -import { Logger } from '../../utils/logger'; - -// Mock dependencies -vi.mock('../../utils/logger'); -vi.mock('../../utils/validation'); - -// Mock Tool Executor implementation -class MockToolExecutor implements IToolExecutor { - constructor(public schema: ToolSchema, public shouldSucceed = true, public resultOverride?: Partial) {} - async execute(input: any, context: ExecutionContext): Promise { - if (!this.shouldSucceed) { - throw new Error(`Mock tool ${this.schema.name} forced failure.`); - } - return { - callId: context.traceId || 'mock-call-id', // Executor might not know the original callId - toolName: this.schema.name, - status: 'success', - output: { inputReceived: input, contextReceived: context }, - ...this.resultOverride, - }; - } -} - -describe('ToolSystem', () => { - let toolSystem: ToolSystem; - let mockToolRegistry: ToolRegistry; - let mockStateManager: StateManager; - // let mockObservationManager; // Add when needed - - let mockTool1: IToolExecutor; - let mockTool2: IToolExecutor; - - const mockValidateJsonSchema = vi.mocked(validateJsonSchema); - - beforeEach(() => { - vi.clearAllMocks(); - - // Create mock tools - mockTool1 = new MockToolExecutor({ - name: 'calculator', - description: 'Mock calculator', - inputSchema: { type: 'object', properties: { expression: { type: 'string' } }, required: ['expression'] }, - }); - mockTool2 = new MockToolExecutor({ - name: 'weather', - description: 'Mock weather', - inputSchema: { type: 'object', properties: { location: { type: 'string' } }, required: ['location'] }, - }); - - // Mock Registry - mockToolRegistry = { - registerTool: vi.fn(), - getToolExecutor: vi.fn(async (toolName: string) => { - if (toolName === 'calculator') return mockTool1; - if (toolName === 'weather') return mockTool2; - return undefined; - }), - getAvailableTools: vi.fn(), - // clearAllTools: vi.fn(), // Removed: Not part of the ToolRegistry interface - }; - - // Mock StateManager - mockStateManager = { - loadThreadContext: vi.fn(), - isToolEnabled: vi.fn(async (threadId: string, toolName: string) => { - // Simulate 'calculator' enabled, 'weather' disabled for thread 't1' - if (threadId === 't1') { - return toolName === 'calculator'; - } - return true; // Enabled by default for other threads - }), - getThreadConfigValue: vi.fn(), - saveStateIfModified: vi.fn(), - }; - - // Mock ObservationManager (placeholder) - // mockObservationManager = { record: vi.fn(), getObservations: vi.fn() }; - - toolSystem = new ToolSystem( - mockToolRegistry as any, // Cast to any to satisfy interface during mock setup - mockStateManager as any, - // mockObservationManager as any - ); - - // Default mock for validation (success) - mockValidateJsonSchema.mockReturnValue({ isValid: true, errors: null }); - }); - - it('should execute a single valid tool call successfully', async () => { - const toolCalls: ParsedToolCall[] = [ - { callId: 'call-123', toolName: 'calculator', arguments: { expression: '2+2' } }, - ]; - const threadId = 't2'; // Use thread where calculator is enabled - const traceId = 'trace-abc'; - - const results = await toolSystem.executeTools(toolCalls, threadId, traceId); - - expect(results).toHaveLength(1); - const result = results[0]; - expect(result.status).toBe('success'); - expect(result.toolName).toBe('calculator'); - expect(result.callId).toBe('call-123'); // Should use the original callId - expect(result.output).toEqual({ - inputReceived: { expression: '2+2' }, - contextReceived: { threadId, traceId } - }); - expect(mockStateManager.isToolEnabled).toHaveBeenCalledWith(threadId, 'calculator'); - expect(mockToolRegistry.getToolExecutor).toHaveBeenCalledWith('calculator'); - expect(mockValidateJsonSchema).toHaveBeenCalledWith(mockTool1.schema.inputSchema, { expression: '2+2' }); - // expect(mockObservationManager.record).toHaveBeenCalledOnce(); // Add when implemented - }); - - it('should execute multiple tool calls sequentially', async () => { - mockTool1 = new MockToolExecutor({ name: 'toolA', description: '', inputSchema: {} }); - mockTool2 = new MockToolExecutor({ name: 'toolB', description: '', inputSchema: {} }); - (mockToolRegistry.getToolExecutor as Mock) - .mockResolvedValueOnce(mockTool1) - .mockResolvedValueOnce(mockTool2); - (mockStateManager.isToolEnabled as Mock).mockResolvedValue(true); // Enable all - - const toolCalls: ParsedToolCall[] = [ - { callId: 'c1', toolName: 'toolA', arguments: { a: 1 } }, - { callId: 'c2', toolName: 'toolB', arguments: { b: 2 } }, - ]; - const threadId = 'multi'; - - const results = await toolSystem.executeTools(toolCalls, threadId); - - expect(results).toHaveLength(2); - expect(results[0].status).toBe('success'); - expect(results[0].toolName).toBe('toolA'); - expect(results[0].callId).toBe('c1'); - expect(results[1].status).toBe('success'); - expect(results[1].toolName).toBe('toolB'); - expect(results[1].callId).toBe('c2'); - expect(mockStateManager.isToolEnabled).toHaveBeenCalledTimes(2); - expect(mockToolRegistry.getToolExecutor).toHaveBeenCalledTimes(2); - expect(mockValidateJsonSchema).toHaveBeenCalledTimes(2); - }); - - it('should return an error result if a tool is not enabled', async () => { - const toolCalls: ParsedToolCall[] = [ - { callId: 'call-456', toolName: 'weather', arguments: { location: 'London' } }, - ]; - const threadId = 't1'; // weather is disabled for t1 - - const results = await toolSystem.executeTools(toolCalls, threadId); - - expect(results).toHaveLength(1); - const result = results[0]; - expect(result.status).toBe('error'); - expect(result.toolName).toBe('weather'); - expect(result.callId).toBe('call-456'); - expect(result.error).toBe('Tool "weather" is not enabled for thread "t1".'); - expect(mockStateManager.isToolEnabled).toHaveBeenCalledWith(threadId, 'weather'); - expect(mockToolRegistry.getToolExecutor).not.toHaveBeenCalled(); - expect(mockValidateJsonSchema).not.toHaveBeenCalled(); - // expect(mockObservationManager.record).toHaveBeenCalledOnce(); // Error should still be recorded - }); - - it('should return an error result if a tool is not found in the registry', async () => { - const toolCalls: ParsedToolCall[] = [ - { callId: 'call-789', toolName: 'nonexistent', arguments: {} }, - ]; - const threadId = 't-any'; - (mockStateManager.isToolEnabled as Mock).mockResolvedValue(true); // Assume enabled - - const results = await toolSystem.executeTools(toolCalls, threadId); - - expect(results).toHaveLength(1); - const result = results[0]; - expect(result.status).toBe('error'); - expect(result.toolName).toBe('nonexistent'); - expect(result.callId).toBe('call-789'); - expect(result.error).toBe('Tool "nonexistent" not found in registry.'); - expect(mockStateManager.isToolEnabled).toHaveBeenCalledWith(threadId, 'nonexistent'); - expect(mockToolRegistry.getToolExecutor).toHaveBeenCalledWith('nonexistent'); - expect(mockValidateJsonSchema).not.toHaveBeenCalled(); - }); - - it('should return an error result if argument validation fails', async () => { - const toolCalls: ParsedToolCall[] = [ - { callId: 'call-abc', toolName: 'calculator', arguments: { expr: 'wrong_arg_name' } }, // Invalid arg name - ]; - const threadId = 't2'; - mockValidateJsonSchema.mockReturnValue({ - isValid: false, - errors: [{ instancePath: '/expr', keyword: 'required', message: 'should have required property \'expression\'', params: {}, schemaPath: '' }] - }); - - const results = await toolSystem.executeTools(toolCalls, threadId); - - expect(results).toHaveLength(1); - const result = results[0]; - expect(result.status).toBe('error'); - expect(result.toolName).toBe('calculator'); - expect(result.callId).toBe('call-abc'); - expect(result.error).toContain('Invalid arguments for tool "calculator":'); - expect(result.error).toContain('/expr should have required property \'expression\''); // Check specific error message - expect(mockStateManager.isToolEnabled).toHaveBeenCalledWith(threadId, 'calculator'); - expect(mockToolRegistry.getToolExecutor).toHaveBeenCalledWith('calculator'); - expect(mockValidateJsonSchema).toHaveBeenCalledWith(mockTool1.schema.inputSchema, { expr: 'wrong_arg_name' }); - }); - - it('should return an error result if the tool executor throws an error', async () => { - // Configure mockTool1 to fail - mockTool1 = new MockToolExecutor(mockTool1.schema, false); // Set shouldSucceed to false - (mockToolRegistry.getToolExecutor as Mock).mockResolvedValue(mockTool1); - (mockStateManager.isToolEnabled as Mock).mockResolvedValue(true); - - const toolCalls: ParsedToolCall[] = [ - { callId: 'call-fail', toolName: 'calculator', arguments: { expression: '1/0' } }, - ]; - const threadId = 't-fail'; - - const results = await toolSystem.executeTools(toolCalls, threadId); - - expect(results).toHaveLength(1); - const result = results[0]; - expect(result.status).toBe('error'); - expect(result.toolName).toBe('calculator'); - expect(result.callId).toBe('call-fail'); - expect(result.error).toBe('Mock tool calculator forced failure.'); - expect(mockValidateJsonSchema).toHaveBeenCalled(); // Validation should still happen - expect(Logger.error).toHaveBeenCalledWith( - expect.stringContaining('Tool "calculator" execution failed for callId "call-fail"'), - expect.anything() - ); - }); - - it('should handle mixed success and failure results correctly', async () => { - const failingTool = new MockToolExecutor({ name: 'failing', description: '', inputSchema: {} }, false); - (mockToolRegistry.getToolExecutor as Mock) - .mockResolvedValueOnce(mockTool1) // calculator (success) - .mockResolvedValueOnce(failingTool); // failing (error) - (mockStateManager.isToolEnabled as Mock).mockResolvedValue(true); - - const toolCalls: ParsedToolCall[] = [ - { callId: 'c-ok', toolName: 'calculator', arguments: { expression: '10' } }, - { callId: 'c-fail', toolName: 'failing', arguments: {} }, - ]; - const threadId = 'mixed'; - - const results = await toolSystem.executeTools(toolCalls, threadId); - - expect(results).toHaveLength(2); - expect(results[0].status).toBe('success'); - expect(results[0].toolName).toBe('calculator'); - expect(results[0].callId).toBe('c-ok'); - expect(results[1].status).toBe('error'); - expect(results[1].toolName).toBe('failing'); - expect(results[1].callId).toBe('c-fail'); - expect(results[1].error).toBe('Mock tool failing forced failure.'); - }); -}); \ No newline at end of file diff --git a/src/systems/tool/ToolSystem.ts b/src/systems/tool/ToolSystem.ts old mode 100644 new mode 100755 index 1c8b2c8..4554f53 --- a/src/systems/tool/ToolSystem.ts +++ b/src/systems/tool/ToolSystem.ts @@ -1,8 +1,8 @@ // src/systems/tool/ToolSystem.ts -import { ToolSystem as IToolSystem, ToolRegistry, StateManager, IToolExecutor, ObservationManager } from '../../core/interfaces'; // Added ObservationManager -import { ParsedToolCall, ToolResult, ExecutionContext, ObservationType } from '../../types'; // Added ObservationType -import { validateJsonSchema } from '../../utils/validation'; -import { Logger } from '../../utils/logger'; +import { ToolSystem as IToolSystem, ToolRegistry, StateManager, IToolExecutor, ObservationManager } from '@/core/interfaces'; // Added ObservationManager +import { ParsedToolCall, ToolResult, ExecutionContext, ObservationType } from '@/types'; // Added ObservationType +import { validateJsonSchema } from '@/utils/validation'; +import { Logger } from '@/utils/logger'; // import { v4 as uuidv4 } from 'uuid'; // Removed unused import /** diff --git a/src/systems/ui/a2a-task-socket.ts b/src/systems/ui/a2a-task-socket.ts new file mode 100755 index 0000000..93e6aaf --- /dev/null +++ b/src/systems/ui/a2a-task-socket.ts @@ -0,0 +1,318 @@ +import { TypedSocket } from './typed-socket'; +import { A2ATask, A2ATaskStatus, A2ATaskPriority } from '@/types'; +import { Logger } from '@/utils/logger'; +import { IA2ATaskRepository } from '@/core/interfaces'; + +/** + * Filter type for A2A task notifications. + * Allows filtering by task status, task type, agent, or priority. + */ +export interface A2ATaskFilter { + /** Filter by task status (single status or array of statuses) */ + status?: A2ATaskStatus | A2ATaskStatus[]; + /** Filter by task type (e.g., 'analyze', 'synthesize', 'transform') */ + taskType?: string | string[]; + /** Filter by source agent ID */ + sourceAgentId?: string; + /** Filter by target agent ID */ + targetAgentId?: string; + /** Filter by task priority */ + priority?: A2ATaskPriority | string; + /** Filter by thread ID */ + threadId?: string; +} + +/** + * Event data structure for A2A task updates. + * Contains the updated task and metadata about the change. + */ +export interface A2ATaskEvent { + /** The A2A task that was updated */ + task: A2ATask; + /** The type of event that occurred */ + eventType: 'created' | 'updated' | 'completed' | 'failed' | 'cancelled' | 'status_changed' | 'delegated'; + /** Timestamp when the event occurred */ + timestamp: number; + /** Previous status (if applicable) for status change events */ + previousStatus?: A2ATaskStatus; + /** Additional metadata about the event */ + metadata?: { + /** Whether this was an automatic update or manual */ + automatic?: boolean; + /** The component that triggered the update */ + source?: string; + /** Any additional context */ + context?: Record; + }; +} + +/** + * A specialized TypedSocket for handling A2A task status updates and events. + * Allows filtering by task status, type, agent, and other criteria. + * Can optionally fetch historical task data from a repository. + */ +export class A2ATaskSocket extends TypedSocket { + private taskRepository?: IA2ATaskRepository; + + constructor(taskRepository?: IA2ATaskRepository) { + super(); + this.taskRepository = taskRepository; + Logger.debug('A2ATaskSocket initialized.'); + } + + /** + * Notifies subscribers about a new A2A task event. + * @param event - The A2A task event data. + */ + notifyTaskEvent(event: A2ATaskEvent): void { + Logger.debug(`Notifying A2A Task Event: ${event.task.taskId} (${event.eventType}) status: ${event.task.status}`); + + super.notify( + event, + { + targetThreadId: event.task.metadata.correlationId, // Use correlationId as threadId if available + targetSessionId: event.task.sourceAgent.agentId + }, + (data, filter) => this.matchesFilter(data, filter) + ); + } + + /** + * Convenience method to notify about a task creation. + * @param task - The newly created A2A task. + * @param metadata - Optional additional metadata about the creation. + */ + notifyTaskCreated(task: A2ATask, metadata?: A2ATaskEvent['metadata']): void { + this.notifyTaskEvent({ + task, + eventType: 'created', + timestamp: Date.now(), + metadata + }); + } + + /** + * Convenience method to notify about a task update. + * @param task - The updated A2A task. + * @param previousStatus - The previous status of the task (if status changed). + * @param metadata - Optional additional metadata about the update. + */ + notifyTaskUpdated(task: A2ATask, previousStatus?: A2ATaskStatus, metadata?: A2ATaskEvent['metadata']): void { + // Determine the specific event type based on the status + let eventType: A2ATaskEvent['eventType'] = 'updated'; + + if (previousStatus && previousStatus !== task.status) { + eventType = 'status_changed'; + if (task.status === A2ATaskStatus.COMPLETED) { + eventType = 'completed'; + } else if (task.status === A2ATaskStatus.FAILED) { + eventType = 'failed'; + } else if (task.status === A2ATaskStatus.CANCELLED) { + eventType = 'cancelled'; + } else if (task.targetAgent && previousStatus === A2ATaskStatus.PENDING) { + eventType = 'delegated'; + } + } + + this.notifyTaskEvent({ + task, + eventType, + timestamp: Date.now(), + previousStatus, + metadata + }); + } + + /** + * Convenience method to notify about task delegation. + * @param task - The delegated A2A task. + * @param metadata - Optional additional metadata about the delegation. + */ + notifyTaskDelegated(task: A2ATask, metadata?: A2ATaskEvent['metadata']): void { + this.notifyTaskEvent({ + task, + eventType: 'delegated', + timestamp: Date.now(), + metadata + }); + } + + /** + * Convenience method to notify about task completion. + * @param task - The completed A2A task. + * @param metadata - Optional additional metadata about the completion. + */ + notifyTaskCompleted(task: A2ATask, metadata?: A2ATaskEvent['metadata']): void { + this.notifyTaskEvent({ + task, + eventType: 'completed', + timestamp: Date.now(), + metadata + }); + } + + /** + * Convenience method to notify about task failure. + * @param task - The failed A2A task. + * @param metadata - Optional additional metadata about the failure. + */ + notifyTaskFailed(task: A2ATask, metadata?: A2ATaskEvent['metadata']): void { + this.notifyTaskEvent({ + task, + eventType: 'failed', + timestamp: Date.now(), + metadata + }); + } + + /** + * Retrieves historical A2A task events, optionally filtered by criteria. + * Note: This method constructs events from stored tasks, not from a dedicated event log. + * @param filter - Optional A2ATaskFilter to filter the tasks. + * @param options - Optional threadId and limit. + * @returns A promise resolving to an array of A2A task events. + */ + async getHistory( + filter?: A2ATaskFilter, + options?: { threadId?: string; limit?: number } + ): Promise { + if (!this.taskRepository) { + Logger.warn('Cannot getHistory for A2ATaskSocket: IA2ATaskRepository not configured.'); + return []; + } + + Logger.debug(`Getting history for A2ATaskSocket: Thread ${options?.threadId}, Filter: ${JSON.stringify(filter)}, Limit: ${options?.limit}`); + + try { + let tasks: A2ATask[] = []; + + // Fetch tasks based on available filters + if (options?.threadId) { + // If threadId is specified, get tasks by thread (assuming threadId maps to correlationId) + tasks = await this.taskRepository.getTasksByThread(options.threadId); + } else if (filter?.status) { + // If status filter is specified, get tasks by status + tasks = await this.taskRepository.getTasksByStatus(filter.status, { + limit: options?.limit + }); + } else { + // Fallback: get tasks by status (all non-cancelled tasks) + tasks = await this.taskRepository.getTasksByStatus([ + A2ATaskStatus.PENDING, + A2ATaskStatus.IN_PROGRESS, + A2ATaskStatus.COMPLETED, + A2ATaskStatus.FAILED, + A2ATaskStatus.WAITING, + A2ATaskStatus.REVIEW + ], { limit: options?.limit }); + } + + // Convert tasks to events and apply client-side filtering + let events: A2ATaskEvent[] = tasks + .map(task => this.taskToEvent(task)) + .filter(event => this.matchesFilter(event, filter)); + + // Sort by timestamp (newest first) + events.sort((a, b) => b.timestamp - a.timestamp); + + // Apply limit if specified and not already applied at repository level + if (options?.limit && (!filter?.status || options.threadId)) { + events = events.slice(0, options.limit); + } + + return events; + } catch (error) { + Logger.error(`Error fetching A2A task history:`, error); + return []; + } + } + + /** + * Converts an A2ATask to an A2ATaskEvent for historical data. + * @param task - The A2ATask to convert. + * @returns An A2ATaskEvent representing the current state of the task. + */ + private taskToEvent(task: A2ATask): A2ATaskEvent { + // Determine event type based on current task status + let eventType: A2ATaskEvent['eventType'] = 'updated'; + + if (task.status === A2ATaskStatus.COMPLETED) { + eventType = 'completed'; + } else if (task.status === A2ATaskStatus.FAILED) { + eventType = 'failed'; + } else if (task.status === A2ATaskStatus.CANCELLED) { + eventType = 'cancelled'; + } else if (task.targetAgent) { + eventType = 'delegated'; + } else if (task.metadata.createdAt === task.metadata.updatedAt) { + eventType = 'created'; + } + + return { + task, + eventType, + timestamp: task.metadata.updatedAt || task.metadata.createdAt, + metadata: { + automatic: true, + source: 'history', + context: { + taskType: task.payload.taskType, + priority: task.priority, + hasTargetAgent: !!task.targetAgent + } + } + }; + } + + /** + * Checks if an A2A task event matches the specified filter criteria. + * @param event - The A2A task event to check. + * @param filter - The filter criteria (optional). + * @returns True if the event matches the filter, false otherwise. + */ + private matchesFilter(event: A2ATaskEvent, filter?: A2ATaskFilter): boolean { + if (!filter) return true; + + const task = event.task; + + // Filter by status + if (filter.status) { + const statusArray = Array.isArray(filter.status) ? filter.status : [filter.status]; + if (!statusArray.includes(task.status)) { + return false; + } + } + + // Filter by task type + if (filter.taskType) { + const taskTypeArray = Array.isArray(filter.taskType) ? filter.taskType : [filter.taskType]; + if (!taskTypeArray.includes(task.payload.taskType)) { + return false; + } + } + + // Filter by source agent ID + if (filter.sourceAgentId && task.sourceAgent.agentId !== filter.sourceAgentId) { + return false; + } + + // Filter by target agent ID + if (filter.targetAgentId) { + if (!task.targetAgent || task.targetAgent.agentId !== filter.targetAgentId) { + return false; + } + } + + // Filter by priority + if (filter.priority && task.priority !== filter.priority) { + return false; + } + + // Filter by thread ID (using correlationId as threadId) + if (filter.threadId && task.metadata.correlationId !== filter.threadId) { + return false; + } + + return true; + } +} \ No newline at end of file diff --git a/src/systems/ui/conversation-socket.test.ts b/src/systems/ui/conversation-socket.test.ts deleted file mode 100644 index 4e2d4db..0000000 --- a/src/systems/ui/conversation-socket.test.ts +++ /dev/null @@ -1,161 +0,0 @@ -// src/systems/ui/conversation-socket.test.ts -import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { ConversationSocket } from './conversation-socket'; -import { IConversationRepository } from '../../core/interfaces'; -import { ConversationMessage, MessageRole } from '../../types'; -import { Logger } from '../../utils/logger'; - -// Mock Logger -vi.mock('../../utils/logger', () => ({ - Logger: { - debug: vi.fn(), - warn: vi.fn(), - error: vi.fn(), - } -})); - -// Mock Repository -const mockConversationRepository: IConversationRepository = { - addMessages: vi.fn(), - getMessages: vi.fn(), -}; - -const mockMessage: ConversationMessage = { - messageId: 'msg-1', - threadId: 'thread-1', - role: MessageRole.USER, - content: 'Hello there', - timestamp: Date.now(), -}; - -describe('ConversationSocket', () => { - let socket: ConversationSocket; - - beforeEach(() => { - vi.clearAllMocks(); // Clear mocks before each test - // Instantiate with the mock repository - socket = new ConversationSocket(mockConversationRepository); - }); - - it('should initialize correctly', () => { - expect(socket).toBeInstanceOf(ConversationSocket); - expect(Logger.debug).toHaveBeenCalledWith('ConversationSocket initialized.'); - }); - - it('should notify subscribers on notifyMessage', () => { - const callback = vi.fn(); - socket.subscribe(callback); - socket.notifyMessage(mockMessage); - - expect(callback).toHaveBeenCalledTimes(1); - expect(callback).toHaveBeenCalledWith(mockMessage); - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining(`Notifying Message: ${mockMessage.messageId}`)); - }); - - it('should filter notifications by MessageRole (single)', () => { - const callbackUser = vi.fn(); - const callbackAI = vi.fn(); - socket.subscribe(callbackUser, MessageRole.USER); - socket.subscribe(callbackAI, MessageRole.AI); - - const userMessage: ConversationMessage = { ...mockMessage, role: MessageRole.USER }; - socket.notifyMessage(userMessage); - - expect(callbackUser).toHaveBeenCalledTimes(1); - expect(callbackUser).toHaveBeenCalledWith(userMessage); - expect(callbackAI).not.toHaveBeenCalled(); - }); - - it('should filter notifications by MessageRole (array)', () => { - const callbackUserOrAI = vi.fn(); - const callbackSystem = vi.fn(); - socket.subscribe(callbackUserOrAI, [MessageRole.USER, MessageRole.AI]); - socket.subscribe(callbackSystem, MessageRole.SYSTEM); - - const userMessage: ConversationMessage = { ...mockMessage, role: MessageRole.USER }; - socket.notifyMessage(userMessage); - - expect(callbackUserOrAI).toHaveBeenCalledTimes(1); - expect(callbackUserOrAI).toHaveBeenCalledWith(userMessage); - expect(callbackSystem).not.toHaveBeenCalled(); - - vi.clearAllMocks(); - - const aiMessage: ConversationMessage = { ...mockMessage, messageId: 'msg-2', role: MessageRole.AI }; - socket.notifyMessage(aiMessage); - - expect(callbackUserOrAI).toHaveBeenCalledTimes(1); - expect(callbackUserOrAI).toHaveBeenCalledWith(aiMessage); - expect(callbackSystem).not.toHaveBeenCalled(); - }); - - it('should filter notifications by threadId', () => { - const callbackT1 = vi.fn(); - const callbackT2 = vi.fn(); - socket.subscribe(callbackT1, undefined, { threadId: 'thread-1' }); - socket.subscribe(callbackT2, undefined, { threadId: 'thread-2' }); - - const messageT1: ConversationMessage = { ...mockMessage, threadId: 'thread-1' }; - socket.notifyMessage(messageT1); - - expect(callbackT1).toHaveBeenCalledTimes(1); - expect(callbackT1).toHaveBeenCalledWith(messageT1); - expect(callbackT2).not.toHaveBeenCalled(); - }); - - it('should call repository getMessages on getHistory', async () => { - const threadId = 'thread-hist-1'; - const options = { threadId, limit: 10 }; - const mockHistory: ConversationMessage[] = [{ ...mockMessage, threadId }]; - vi.mocked(mockConversationRepository.getMessages).mockResolvedValue(mockHistory); - - const history = await socket.getHistory(undefined, options); // No role filter - - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining(`Getting history for ConversationSocket: Thread ${threadId}`)); - expect(mockConversationRepository.getMessages).toHaveBeenCalledTimes(1); - expect(mockConversationRepository.getMessages).toHaveBeenCalledWith(threadId, { limit: options.limit }); - expect(history).toEqual(mockHistory); - }); - - it('should warn but still call repository getMessages when role filter is provided (as filtering is not implemented in repo)', async () => { - const threadId = 'thread-hist-2'; - const filter = MessageRole.AI; - const options = { threadId, limit: 5 }; - const mockHistory: ConversationMessage[] = [{ ...mockMessage, threadId, role: MessageRole.USER }]; // Repo returns all roles - vi.mocked(mockConversationRepository.getMessages).mockResolvedValue(mockHistory); - - const history = await socket.getHistory(filter, options); - - expect(Logger.warn).toHaveBeenCalledWith(expect.stringContaining('Role filtering requested for ConversationSocket.getHistory')); - expect(mockConversationRepository.getMessages).toHaveBeenCalledTimes(1); - expect(mockConversationRepository.getMessages).toHaveBeenCalledWith(threadId, { limit: options.limit }); - expect(history).toEqual(mockHistory); // Returns unfiltered history from repo - }); - - it('getHistory should require threadId', async () => { - const history = await socket.getHistory(MessageRole.USER, { limit: 10 }); // No threadId - expect(history).toEqual([]); - expect(mockConversationRepository.getMessages).not.toHaveBeenCalled(); - expect(Logger.warn).toHaveBeenCalledWith('Cannot getHistory for ConversationSocket: threadId is required.'); - }); - - it('getHistory should handle repository errors', async () => { - const threadId = 'thread-err-1'; - const error = new Error('DB failed'); - vi.mocked(mockConversationRepository.getMessages).mockRejectedValue(error); - - const history = await socket.getHistory(undefined, { threadId }); - - expect(history).toEqual([]); - expect(mockConversationRepository.getMessages).toHaveBeenCalledTimes(1); - expect(Logger.error).toHaveBeenCalledWith(expect.stringContaining(`Error fetching message history for thread ${threadId}`), error); - }); - - it('getHistory should work without a repository configured (warn and return empty)', async () => { - const socketWithoutRepo = new ConversationSocket(); // No repo provided - const history = await socketWithoutRepo.getHistory(undefined, { threadId: 'thread-no-repo' }); - - expect(history).toEqual([]); - expect(Logger.warn).toHaveBeenCalledWith('Cannot getHistory for ConversationSocket: ConversationRepository not configured.'); - }); -}); \ No newline at end of file diff --git a/src/systems/ui/conversation-socket.ts b/src/systems/ui/conversation-socket.ts old mode 100644 new mode 100755 index 1ac52a9..c0bd15d --- a/src/systems/ui/conversation-socket.ts +++ b/src/systems/ui/conversation-socket.ts @@ -1,8 +1,8 @@ // src/systems/ui/conversation-socket.ts import { TypedSocket } from './typed-socket'; -import { ConversationMessage, MessageRole } from '../../types'; -import { Logger } from '../../utils/logger'; -import { IConversationRepository } from '../../core/interfaces'; // Assuming this exists +import { ConversationMessage, MessageRole } from '@/types'; +import { Logger } from '@/utils/logger'; +import { IConversationRepository } from '@/core/interfaces'; // Assuming this exists /** * A specialized TypedSocket for handling ConversationMessage data. diff --git a/src/systems/ui/llm-stream-socket.ts b/src/systems/ui/llm-stream-socket.ts old mode 100644 new mode 100755 index d5b349f..0cc36dc --- a/src/systems/ui/llm-stream-socket.ts +++ b/src/systems/ui/llm-stream-socket.ts @@ -1,10 +1,10 @@ // src/systems/ui/llm-stream-socket.ts import { TypedSocket } from './typed-socket'; -import { StreamEvent } from '../../types'; -import { Logger } from '../../utils/logger'; +import { StreamEvent } from '@/types'; +import { Logger } from '@/utils/logger'; // Define the type for the filter used in this specific socket -type StreamEventTypeFilter = StreamEvent['type'] | Array; +export type StreamEventTypeFilter = StreamEvent['type'] | Array; /** * A dedicated socket for broadcasting LLM stream events (`StreamEvent`) to UI subscribers. diff --git a/src/systems/ui/observation-socket.test.ts b/src/systems/ui/observation-socket.test.ts deleted file mode 100644 index 02329f1..0000000 --- a/src/systems/ui/observation-socket.test.ts +++ /dev/null @@ -1,162 +0,0 @@ -// src/systems/ui/observation-socket.test.ts -import { describe, it, expect, vi, beforeEach } from 'vitest'; -import { ObservationSocket } from './observation-socket'; -import { IObservationRepository } from '../../core/interfaces'; -import { Observation, ObservationType } from '../../types'; -import { Logger } from '../../utils/logger'; - -// Mock Logger -vi.mock('../../utils/logger', () => ({ - Logger: { - debug: vi.fn(), - warn: vi.fn(), - error: vi.fn(), - } -})); - -// Mock Repository -const mockObservationRepository: IObservationRepository = { - addObservation: vi.fn(), - getObservations: vi.fn(), -}; - -const mockObservation: Observation = { - id: 'obs-1', - threadId: 'thread-1', - timestamp: Date.now(), - type: ObservationType.PLAN, - title: 'Plan Recorded', - content: { steps: ['step 1', 'step 2'] }, -}; - -describe('ObservationSocket', () => { - let socket: ObservationSocket; - - beforeEach(() => { - vi.clearAllMocks(); // Clear mocks before each test - // Instantiate with the mock repository - socket = new ObservationSocket(mockObservationRepository); - }); - - it('should initialize correctly', () => { - expect(socket).toBeInstanceOf(ObservationSocket); - expect(Logger.debug).toHaveBeenCalledWith('ObservationSocket initialized.'); - }); - - it('should notify subscribers on notifyObservation', () => { - const callback = vi.fn(); - socket.subscribe(callback); - socket.notifyObservation(mockObservation); - - expect(callback).toHaveBeenCalledTimes(1); - expect(callback).toHaveBeenCalledWith(mockObservation); - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining(`Notifying Observation: ${mockObservation.id}`)); - }); - - it('should filter notifications by ObservationType (single)', () => { - const callbackPlan = vi.fn(); - const callbackTool = vi.fn(); - socket.subscribe(callbackPlan, ObservationType.PLAN); - socket.subscribe(callbackTool, ObservationType.TOOL_CALL); - - const planObservation: Observation = { ...mockObservation, type: ObservationType.PLAN }; - socket.notifyObservation(planObservation); - - expect(callbackPlan).toHaveBeenCalledTimes(1); - expect(callbackPlan).toHaveBeenCalledWith(planObservation); - expect(callbackTool).not.toHaveBeenCalled(); - }); - - it('should filter notifications by ObservationType (array)', () => { - const callbackPlanOrTool = vi.fn(); - const callbackError = vi.fn(); - socket.subscribe(callbackPlanOrTool, [ObservationType.PLAN, ObservationType.TOOL_CALL]); - socket.subscribe(callbackError, ObservationType.ERROR); - - const planObservation: Observation = { ...mockObservation, type: ObservationType.PLAN }; - socket.notifyObservation(planObservation); - - expect(callbackPlanOrTool).toHaveBeenCalledTimes(1); - expect(callbackPlanOrTool).toHaveBeenCalledWith(planObservation); - expect(callbackError).not.toHaveBeenCalled(); - - vi.clearAllMocks(); - - const toolObservation: Observation = { ...mockObservation, id: 'obs-2', type: ObservationType.TOOL_CALL }; - socket.notifyObservation(toolObservation); - - expect(callbackPlanOrTool).toHaveBeenCalledTimes(1); - expect(callbackPlanOrTool).toHaveBeenCalledWith(toolObservation); - expect(callbackError).not.toHaveBeenCalled(); - }); - - it('should filter notifications by threadId', () => { - const callbackT1 = vi.fn(); - const callbackT2 = vi.fn(); - socket.subscribe(callbackT1, undefined, { threadId: 'thread-1' }); - socket.subscribe(callbackT2, undefined, { threadId: 'thread-2' }); - - const observationT1: Observation = { ...mockObservation, threadId: 'thread-1' }; - socket.notifyObservation(observationT1); - - expect(callbackT1).toHaveBeenCalledTimes(1); - expect(callbackT1).toHaveBeenCalledWith(observationT1); - expect(callbackT2).not.toHaveBeenCalled(); - }); - - it('should call repository getObservations on getHistory', async () => { - const threadId = 'thread-hist-1'; - const filter = ObservationType.INTENT; - const options = { threadId, limit: 10 }; - const mockHistory: Observation[] = [{ ...mockObservation, threadId, type: filter }]; - vi.mocked(mockObservationRepository.getObservations).mockResolvedValue(mockHistory); - - const history = await socket.getHistory(filter, options); - - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining(`Getting history for ObservationSocket: Thread ${threadId}`)); - expect(mockObservationRepository.getObservations).toHaveBeenCalledTimes(1); - expect(mockObservationRepository.getObservations).toHaveBeenCalledWith(threadId, { types: [filter], limit: options.limit }); - expect(history).toEqual(mockHistory); - }); - - it('should call repository getObservations on getHistory with type array filter', async () => { - const threadId = 'thread-hist-2'; - const filter = [ObservationType.INTENT, ObservationType.ERROR]; - const options = { threadId, limit: 5 }; - const mockHistory: Observation[] = [{ ...mockObservation, threadId, type: ObservationType.INTENT }]; - vi.mocked(mockObservationRepository.getObservations).mockResolvedValue(mockHistory); - - const history = await socket.getHistory(filter, options); - - expect(mockObservationRepository.getObservations).toHaveBeenCalledTimes(1); - expect(mockObservationRepository.getObservations).toHaveBeenCalledWith(threadId, { types: filter, limit: options.limit }); - expect(history).toEqual(mockHistory); - }); - - it('getHistory should require threadId', async () => { - const history = await socket.getHistory(ObservationType.PLAN, { limit: 10 }); // No threadId - expect(history).toEqual([]); - expect(mockObservationRepository.getObservations).not.toHaveBeenCalled(); - expect(Logger.warn).toHaveBeenCalledWith('Cannot getHistory for ObservationSocket: threadId is required.'); - }); - - it('getHistory should handle repository errors', async () => { - const threadId = 'thread-err-1'; - const error = new Error('DB failed'); - vi.mocked(mockObservationRepository.getObservations).mockRejectedValue(error); - - const history = await socket.getHistory(undefined, { threadId }); - - expect(history).toEqual([]); - expect(mockObservationRepository.getObservations).toHaveBeenCalledTimes(1); - expect(Logger.error).toHaveBeenCalledWith(expect.stringContaining(`Error fetching observation history for thread ${threadId}`), error); - }); - - it('getHistory should work without a repository configured (warn and return empty)', async () => { - const socketWithoutRepo = new ObservationSocket(); // No repo provided - const history = await socketWithoutRepo.getHistory(undefined, { threadId: 'thread-no-repo' }); - - expect(history).toEqual([]); - expect(Logger.warn).toHaveBeenCalledWith('Cannot getHistory for ObservationSocket: ObservationRepository not configured.'); - }); -}); \ No newline at end of file diff --git a/src/systems/ui/observation-socket.ts b/src/systems/ui/observation-socket.ts old mode 100644 new mode 100755 index c5500f5..55cdacd --- a/src/systems/ui/observation-socket.ts +++ b/src/systems/ui/observation-socket.ts @@ -1,8 +1,8 @@ // src/systems/ui/observation-socket.ts import { TypedSocket } from './typed-socket'; -import { Observation, ObservationType, ObservationFilter } from '../../types'; -import { Logger } from '../../utils/logger'; -import { IObservationRepository } from '../../core/interfaces'; // Assuming this exists +import { Observation, ObservationType, ObservationFilter } from '@/types'; +import { Logger } from '@/utils/logger'; +import { IObservationRepository } from '@/core/interfaces'; // Assuming this exists /** * A specialized TypedSocket for handling Observation data. diff --git a/src/systems/ui/typed-socket.test.ts b/src/systems/ui/typed-socket.test.ts deleted file mode 100644 index 4371098..0000000 --- a/src/systems/ui/typed-socket.test.ts +++ /dev/null @@ -1,193 +0,0 @@ -// src/systems/ui/typed-socket.test.ts -import { describe, it, expect, vi } from 'vitest'; -import { TypedSocket } from './typed-socket'; -import { Logger } from '../../utils/logger'; - -// Mock Logger to prevent console output during tests and verify calls -vi.mock('../../utils/logger', () => ({ - Logger: { - debug: vi.fn(), - info: vi.fn(), - warn: vi.fn(), - error: vi.fn(), - configure: vi.fn(), // Ensure all static methods used are mocked - } -})); - -describe('TypedSocket', () => { - it('should subscribe a callback and return an unsubscribe function', () => { - const socket = new TypedSocket(); - const callback = vi.fn(); - const unsubscribe = socket.subscribe(callback); - - expect(typeof unsubscribe).toBe('function'); - // @ts-expect-error - Accessing protected member for test verification - expect(socket.subscriptions.size).toBe(1); - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining('New subscription added')); - - unsubscribe(); - // @ts-expect-error - Accessing protected member for test verification - expect(socket.subscriptions.size).toBe(0); - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining('Subscription removed')); - }); - - it('should notify a subscribed callback', () => { - const socket = new TypedSocket(); - const callback = vi.fn(); - socket.subscribe(callback); - const data = 'test data'; - - socket.notify(data); - - expect(callback).toHaveBeenCalledTimes(1); - expect(callback).toHaveBeenCalledWith(data); - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining('Notifying 1 subscribers')); - }); - - it('should not notify an unsubscribed callback', () => { - const socket = new TypedSocket(); - const callback = vi.fn(); - const unsubscribe = socket.subscribe(callback); - const data = 'test data'; - - unsubscribe(); - socket.notify(data); - - expect(callback).not.toHaveBeenCalled(); - }); - - it('should notify multiple subscribers', () => { - const socket = new TypedSocket(); - const callback1 = vi.fn(); - const callback2 = vi.fn(); - socket.subscribe(callback1); - socket.subscribe(callback2); - const data = 123; - - socket.notify(data); - - expect(callback1).toHaveBeenCalledTimes(1); - expect(callback1).toHaveBeenCalledWith(data); - expect(callback2).toHaveBeenCalledTimes(1); - expect(callback2).toHaveBeenCalledWith(data); - expect(Logger.debug).toHaveBeenCalledWith(expect.stringContaining('Notifying 2 subscribers')); - }); - - it('should handle errors in callback without affecting other subscribers', () => { - const socket = new TypedSocket(); - const errorCallback = vi.fn(() => { throw new Error('Callback failed'); }); - const successCallback = vi.fn(); - - socket.subscribe(errorCallback); - socket.subscribe(successCallback); - const data = 'important data'; - - socket.notify(data); - - expect(errorCallback).toHaveBeenCalledTimes(1); - expect(successCallback).toHaveBeenCalledTimes(1); - expect(successCallback).toHaveBeenCalledWith(data); - // Verify error logging - expect(Logger.error).toHaveBeenCalledWith(expect.stringContaining('Error executing subscription callback'), expect.any(Error)); - }); - - it('should clear all subscriptions', () => { - const socket = new TypedSocket(); - socket.subscribe(vi.fn()); - socket.subscribe(vi.fn()); - // @ts-expect-error - Accessing protected member for test verification - expect(socket.subscriptions.size).toBe(2); - - socket.clearAllSubscriptions(); - // @ts-expect-error - Accessing protected member for test verification - expect(socket.subscriptions.size).toBe(0); - expect(Logger.debug).toHaveBeenCalledWith('All subscriptions cleared.'); - }); - - // --- Filtering Tests --- - - it('should notify only subscribers matching the threadId option', () => { - const socket = new TypedSocket(); - const callbackAll = vi.fn(); - const callbackThread1 = vi.fn(); - const callbackThread2 = vi.fn(); - - socket.subscribe(callbackAll); // No thread filter - socket.subscribe(callbackThread1, undefined, { threadId: 'thread-1' }); - socket.subscribe(callbackThread2, undefined, { threadId: 'thread-2' }); - - const data = 'data for thread 1'; - socket.notify(data, { targetThreadId: 'thread-1' }); - - expect(callbackAll).toHaveBeenCalledTimes(1); // Called because it has no thread filter - expect(callbackAll).toHaveBeenCalledWith(data); - expect(callbackThread1).toHaveBeenCalledTimes(1); // Called because threadId matches - expect(callbackThread1).toHaveBeenCalledWith(data); - expect(callbackThread2).not.toHaveBeenCalled(); // Not called because threadId doesn't match - }); - - it('should notify subscribers matching the filter', () => { - type DataType = { type: 'A' | 'B', value: number }; - const socket = new TypedSocket(); - const callbackAll = vi.fn(); - const callbackA = vi.fn(); - const callbackB = vi.fn(); - - const filterCheck = (data: DataType, filter?: 'A' | 'B') => data.type === filter; - - socket.subscribe(callbackAll); // No filter - socket.subscribe(callbackA, 'A'); - socket.subscribe(callbackB, 'B'); - - const dataA: DataType = { type: 'A', value: 1 }; - socket.notify(dataA, undefined, filterCheck); - - expect(callbackAll).toHaveBeenCalledTimes(1); // Called because no filter - expect(callbackAll).toHaveBeenCalledWith(dataA); - expect(callbackA).toHaveBeenCalledTimes(1); // Called because filter matches - expect(callbackA).toHaveBeenCalledWith(dataA); - expect(callbackB).not.toHaveBeenCalled(); // Not called because filter doesn't match - - vi.clearAllMocks(); // Reset mocks for next notification - - const dataB: DataType = { type: 'B', value: 2 }; - socket.notify(dataB, undefined, filterCheck); - - expect(callbackAll).toHaveBeenCalledTimes(1); // Called because no filter - expect(callbackAll).toHaveBeenCalledWith(dataB); - expect(callbackA).not.toHaveBeenCalled(); // Not called because filter doesn't match - expect(callbackB).toHaveBeenCalledTimes(1); // Called because filter matches - expect(callbackB).toHaveBeenCalledWith(dataB); - }); - - it('should notify subscribers matching both threadId and filter', () => { - type DataType = { type: 'A' | 'B', value: number }; - const socket = new TypedSocket(); - const callbackA_T1 = vi.fn(); - const callbackB_T1 = vi.fn(); - const callbackA_T2 = vi.fn(); - - const filterCheck = (data: DataType, filter?: 'A' | 'B') => data.type === filter; - - socket.subscribe(callbackA_T1, 'A', { threadId: 'thread-1' }); - socket.subscribe(callbackB_T1, 'B', { threadId: 'thread-1' }); - socket.subscribe(callbackA_T2, 'A', { threadId: 'thread-2' }); - - const dataA_T1: DataType = { type: 'A', value: 1 }; - // Notify for thread-1 with type A data - socket.notify(dataA_T1, { targetThreadId: 'thread-1' }, filterCheck); - - expect(callbackA_T1).toHaveBeenCalledTimes(1); // Matches thread and filter - expect(callbackA_T1).toHaveBeenCalledWith(dataA_T1); - expect(callbackB_T1).not.toHaveBeenCalled(); // Matches thread but not filter - expect(callbackA_T2).not.toHaveBeenCalled(); // Matches filter but not thread - }); - - it('getHistory should warn and return empty array by default', async () => { - const socket = new TypedSocket(); - // The getHistory method is optional, so accessing it with ?. is valid TS - const history = await socket.getHistory?.(); - expect(history).toEqual([]); - expect(Logger.warn).toHaveBeenCalledWith('getHistory is not implemented in the base TypedSocket.'); - }); -}); \ No newline at end of file diff --git a/src/systems/ui/typed-socket.ts b/src/systems/ui/typed-socket.ts old mode 100644 new mode 100755 index d75cd8a..d013e4c --- a/src/systems/ui/typed-socket.ts +++ b/src/systems/ui/typed-socket.ts @@ -1,6 +1,6 @@ // src/systems/ui/typed-socket.ts import { v4 as uuidv4 } from 'uuid'; -import { Logger } from '../../utils/logger'; // Assuming logger exists +import { Logger } from '@/utils/logger'; // Assuming logger exists export type UnsubscribeFunction = () => void; diff --git a/src/systems/ui/ui-system.test.ts b/src/systems/ui/ui-system.test.ts deleted file mode 100644 index c09356e..0000000 --- a/src/systems/ui/ui-system.test.ts +++ /dev/null @@ -1,85 +0,0 @@ -// src/systems/ui/ui-system.test.ts -import { describe, it, expect, vi } from 'vitest'; -import { UISystem } from './ui-system'; -import { IObservationRepository, IConversationRepository } from '../../core/interfaces'; -import { ObservationSocket } from './observation-socket'; -import { ConversationSocket } from './conversation-socket'; -import { LLMStreamSocket } from './llm-stream-socket'; -import { Logger } from '../../utils/logger'; - -// Mock Logger -vi.mock('../../utils/logger', () => ({ - Logger: { - debug: vi.fn(), - warn: vi.fn(), - error: vi.fn(), - } -})); - -// Mock Sockets -vi.mock('./observation-socket'); -vi.mock('./conversation-socket'); -vi.mock('./llm-stream-socket'); - -// Mock Repositories (just need objects conforming to the interface) -const mockObservationRepository: IObservationRepository = { - addObservation: vi.fn(), - getObservations: vi.fn(), -}; - -const mockConversationRepository: IConversationRepository = { - addMessages: vi.fn(), - getMessages: vi.fn(), -}; - -describe('UISystem', () => { - it('should initialize correctly and instantiate sockets', () => { - const uiSystem = new UISystem(mockObservationRepository, mockConversationRepository); - - expect(uiSystem).toBeInstanceOf(UISystem); - // Check if sockets were instantiated (using the mocks) - expect(ObservationSocket).toHaveBeenCalledTimes(1); - expect(ObservationSocket).toHaveBeenCalledWith(mockObservationRepository); - expect(ConversationSocket).toHaveBeenCalledTimes(1); - expect(ConversationSocket).toHaveBeenCalledWith(mockConversationRepository); - expect(LLMStreamSocket).toHaveBeenCalledTimes(1); - expect(LLMStreamSocket).toHaveBeenCalledWith(); - expect(Logger.debug).toHaveBeenCalledWith('UISystem initialized with Observation, Conversation, and LLM Stream sockets.'); - }); - - it('getObservationSocket should return the ObservationSocket instance', () => { - const uiSystem = new UISystem(mockObservationRepository, mockConversationRepository); - const socket = uiSystem.getObservationSocket(); - // Since we mocked the constructor, the instance is also a mock - // We expect it to be an instance of the mocked ObservationSocket - expect(socket).toBeInstanceOf(ObservationSocket); - }); - - it('getConversationSocket should return the ConversationSocket instance', () => { - const uiSystem = new UISystem(mockObservationRepository, mockConversationRepository); - const socket = uiSystem.getConversationSocket(); - // Expect it to be an instance of the mocked ConversationSocket - expect(socket).toBeInstanceOf(ConversationSocket); - }); - - it('should return the same socket instances on multiple calls', () => { - const uiSystem = new UISystem(mockObservationRepository, mockConversationRepository); - const socket1 = uiSystem.getObservationSocket(); - const socket2 = uiSystem.getObservationSocket(); - const convSocket1 = uiSystem.getConversationSocket(); - const convSocket2 = uiSystem.getConversationSocket(); - const streamSocket1 = uiSystem.getLLMStreamSocket(); - const streamSocket2 = uiSystem.getLLMStreamSocket(); - - expect(socket1).toBe(socket2); // Should be the same instance - expect(convSocket1).toBe(convSocket2); // Should be the same instance - expect(streamSocket1).toBe(streamSocket2); // Should be the same instance - }); - - it('getLLMStreamSocket should return the LLMStreamSocket instance', () => { - const uiSystem = new UISystem(mockObservationRepository, mockConversationRepository); - const socket = uiSystem.getLLMStreamSocket(); - // Expect it to be an instance of the mocked LLMStreamSocket - expect(socket).toBeInstanceOf(LLMStreamSocket); - }); -}); \ No newline at end of file diff --git a/src/systems/ui/ui-system.ts b/src/systems/ui/ui-system.ts old mode 100644 new mode 100755 index c6280ba..ebc4d89 --- a/src/systems/ui/ui-system.ts +++ b/src/systems/ui/ui-system.ts @@ -2,35 +2,41 @@ import { UISystem as IUISystem, IObservationRepository, - IConversationRepository -} from '../../core/interfaces'; + IConversationRepository, + IA2ATaskRepository +} from '@/core/interfaces'; import { ObservationSocket } from './observation-socket'; import { ConversationSocket } from './conversation-socket'; import { LLMStreamSocket } from './llm-stream-socket'; // Import the new socket -import { Logger } from '../../utils/logger'; +import { A2ATaskSocket } from './a2a-task-socket'; +import { Logger } from '@/utils/logger'; /** - * Provides access to the UI communication sockets (Observation, Conversation, and LLM Stream). + * Provides access to the UI communication sockets (Observation, Conversation, LLM Stream, and A2A Task). * Instantiates the sockets with their required dependencies. */ export class UISystem implements IUISystem { private observationSocketInstance: ObservationSocket; private conversationSocketInstance: ConversationSocket; private llmStreamSocketInstance: LLMStreamSocket; // Add the new socket instance + private a2aTaskSocketInstance: A2ATaskSocket; /** * Creates an instance of UISystem. * @param observationRepository - Repository for observation data, passed to ObservationSocket. * @param conversationRepository - Repository for conversation data, passed to ConversationSocket. + * @param a2aTaskRepository - Optional repository for A2A task data, passed to A2ATaskSocket. */ constructor( observationRepository: IObservationRepository, - conversationRepository: IConversationRepository + conversationRepository: IConversationRepository, + a2aTaskRepository?: IA2ATaskRepository ) { this.observationSocketInstance = new ObservationSocket(observationRepository); this.conversationSocketInstance = new ConversationSocket(conversationRepository); this.llmStreamSocketInstance = new LLMStreamSocket(); // Instantiate the new socket - Logger.debug('UISystem initialized with Observation, Conversation, and LLM Stream sockets.'); + this.a2aTaskSocketInstance = new A2ATaskSocket(a2aTaskRepository); + Logger.debug('UISystem initialized with Observation, Conversation, LLM Stream, and A2A Task sockets.'); } /** @@ -56,4 +62,12 @@ export class UISystem implements IUISystem { getLLMStreamSocket(): LLMStreamSocket { return this.llmStreamSocketInstance; } + + /** + * Gets the singleton instance of the A2ATaskSocket. + * @returns The A2ATaskSocket instance. + */ + getA2ATaskSocket(): A2ATaskSocket { + return this.a2aTaskSocketInstance; + } } \ No newline at end of file diff --git a/src/tools/CalculatorTool.test.ts b/src/tools/CalculatorTool.test.ts deleted file mode 100644 index 063030d..0000000 --- a/src/tools/CalculatorTool.test.ts +++ /dev/null @@ -1,156 +0,0 @@ -// src/tools/CalculatorTool.test.ts -import { describe, it, expect, beforeEach, test } from 'vitest'; // Explicit imports -import { CalculatorTool } from './CalculatorTool'; -import { ExecutionContext } from '../types'; - -describe('CalculatorTool', () => { - let calculatorTool: CalculatorTool; - let mockContext: ExecutionContext; - - beforeEach(() => { - calculatorTool = new CalculatorTool(); - mockContext = { - threadId: 'test-thread', - traceId: 'test-trace', - }; - }); - - it('should have the correct schema', () => { - expect(calculatorTool.schema.name).toBe('calculator'); - // Check for keywords in the updated description - expect(calculatorTool.schema.description).toContain('sandboxed mathjs environment'); - expect(calculatorTool.schema.description).toContain('complex numbers'); - expect(calculatorTool.schema.description).toContain('allowed functions'); - expect(calculatorTool.schema.description).toContain('sqrt'); // Example allowed function - // Use non-null assertions (!) assuming the structure is correct for this tool - expect(calculatorTool.schema.inputSchema!.properties).toHaveProperty('expression'); - expect(calculatorTool.schema.inputSchema!.properties).toHaveProperty('scope'); - expect((calculatorTool.schema.inputSchema!.properties! as any).scope.type).toBe('object'); - expect(calculatorTool.schema.examples!.length).toBeGreaterThan(5); // Check if examples were updated - }); - - test.each([ - // Basic Arithmetic - { expression: '2 + 2', scope: undefined, expected: 4 }, - { expression: '10 - 3', scope: undefined, expected: 7 }, - { expression: '5 * 6', scope: undefined, expected: 30 }, - { expression: '20 / 4', scope: undefined, expected: 5 }, - // Parentheses - { expression: '(10 + 5) * 2', scope: undefined, expected: 30 }, - // Modulo - { expression: '13 % 5', scope: undefined, expected: 3 }, - { expression: 'mod(13, 5)', scope: undefined, expected: 3 }, // Using allowed mathjs function - // Allowed Functions - { expression: 'sqrt(25)', scope: undefined, expected: 5 }, - { expression: 'pow(2, 3)', scope: undefined, expected: 8 }, - { expression: 'log(10)', scope: undefined, expected: 2.302585092994046 }, // Natural log - { expression: 'sin(pi / 2)', scope: undefined, expected: 1 }, // Using built-in pi - { expression: 'round(3.7)', scope: undefined, expected: 4 }, - // Scope / Variables - { expression: 'a + b', scope: { a: 10, b: 5 }, expected: 15 }, - { expression: 'radius * 2 * pi', scope: { radius: 5 }, expected: 31.41592653589793 }, // pi is built-in - // Original failing case - { expression: 'result % 13', scope: { result: 347 }, expected: 9 }, - // Decimal numbers - // Decimal numbers - Use toBeCloseTo for floats - // { expression: '1.5 * 2.2', scope: undefined, expected: 3.3 }, // Original, fails due to precision - // Complex Numbers - { expression: 'sqrt(-4)', scope: undefined, expected: '2i' }, // String output for complex - { expression: 'pow(i, 2)', scope: undefined, expected: -1 }, // Expect number -1, not string - { expression: '1 + 2i', scope: undefined, expected: '1 + 2i' }, - { expression: '(1 + i) * (2 + 3i)', scope: undefined, expected: '-1 + 5i' }, - // Add factorial back as a success case - { expression: 'factorial(5)', scope: undefined, expected: 120 }, - ])('should evaluate "$expression" correctly', async ({ expression, scope, expected }) => { - const input = { expression, scope }; - const result = await calculatorTool.execute(input, mockContext); - - expect(result.status).toBe('success'); - expect(result.output).toEqual({ result: expected }); - expect(result.error).toBeUndefined(); - }); - - // --- Test specific cases that need special handling --- - - // Test for floating point precision specifically - it('should evaluate "1.5 * 2.2" correctly using toBeCloseTo', async () => { - const input = { expression: '1.5 * 2.2' }; - const result = await calculatorTool.execute(input, mockContext); - expect(result.status).toBe('success'); - expect(result.output).toBeDefined(); - // Check that the result is a number before using toBeCloseTo - expect(typeof result.output?.result).toBe('number'); - expect(result.output?.result).toBeCloseTo(3.3); // Use toBeCloseTo for floats - expect(result.error).toBeUndefined(); - }); - - - it('should return a specific error for invalid expressions', async () => { - const input = { expression: '5 + * 3' }; // Invalid syntax - const result = await calculatorTool.execute(input, mockContext); - - expect(result.status).toBe('error'); - expect(result.output).toBeUndefined(); - // Check for a more specific mathjs error part - expect(result.error).toMatch(/Failed to evaluate expression:.*Value expected|Unexpected operator/i); - }); - - it('should return a specific error for undefined symbols', async () => { - const input = { expression: 'x + y' }; // Undefined symbols - const result = await calculatorTool.execute(input, mockContext); - - expect(result.status).toBe('error'); - expect(result.output).toBeUndefined(); - expect(result.error).toContain('Failed to evaluate expression: Undefined symbol x'); - }); - - it('should return an error for unsupported result types', async () => { - // Function definition is not a supported output type (number or complex string) - const input = { expression: 'f(x) = x^2' }; - const result = await calculatorTool.execute(input, mockContext); - - expect(result.status).toBe('error'); - expect(result.output).toBeUndefined(); - // Match the error from the initial test run output - expect(result.error).toContain('Failed to evaluate expression: Evaluation resulted in an unsupported type: function'); - }); - - it('should return an error for disallowed functions', async () => { - // 'import' is a dangerous function in mathjs and should be disallowed by our scope control - const input = { expression: 'import("fs")' }; - const result = await calculatorTool.execute(input, mockContext); - - expect(result.status).toBe('error'); - expect(result.output).toBeUndefined(); - // Match the error from the initial test run output - expect(result.error).toContain('Failed to evaluate expression: Undefined function import'); - }); - - it('should return an error for functions not in the allowlist', async () => { - // 'factorial' is a valid mathjs function but not in our explicit allowlist - const input = { expression: 'factorial(5)' }; - const result = await calculatorTool.execute(input, mockContext); - - expect(result.status).toBe('error'); - expect(result.output).toBeUndefined(); - // This test is no longer needed as factorial is allowed and tested above. - // Keep the test structure but comment out or remove the content if desired. - // For now, let's remove it as it's covered by the success case. - // expect(result.error).toContain('Failed to evaluate expression: Undefined function factorial'); - }); - - - it('should handle empty scope correctly', async () => { - const input = { expression: '5 * 5', scope: {} }; - const result = await calculatorTool.execute(input, mockContext); - expect(result.status).toBe('success'); - expect(result.output).toEqual({ result: 25 }); - }); - - it('should use default empty scope if scope is not provided', async () => { - const input = { expression: '9 / 3' }; // No scope property - const result = await calculatorTool.execute(input, mockContext); - expect(result.status).toBe('success'); - expect(result.output).toEqual({ result: 3 }); - }); -}); \ No newline at end of file diff --git a/src/tools/CalculatorTool.ts b/src/tools/CalculatorTool.ts old mode 100644 new mode 100755 index 9846218..04138d0 --- a/src/tools/CalculatorTool.ts +++ b/src/tools/CalculatorTool.ts @@ -1,7 +1,7 @@ // src/tools/CalculatorTool.ts -import { IToolExecutor } from '../core/interfaces'; -import { ToolSchema, ExecutionContext, ToolResult } from '../types'; -import { Logger } from '../utils/logger'; +import { IToolExecutor } from '@/core/interfaces'; +import { ToolSchema, ExecutionContext, ToolResult } from '@/types'; +import { Logger } from '@/utils/logger'; // Import necessary parts from mathjs import { evaluate, type Complex } from 'mathjs'; // Removed unused MathJsStatic, MathNode import * as math from 'mathjs'; // Import the full math object to access functions @@ -57,7 +57,13 @@ const allowedFunctions: Record = { * An ART Framework tool that safely evaluates mathematical expressions using the mathjs library. * It supports basic arithmetic, variables via a scope, complex numbers, and a predefined list of safe functions. * - * @implements {IToolExecutor} + * This tool is designed to be used within the ART framework's `ToolSystem`. + * It provides a safe way to perform mathematical calculations by leveraging + * the `mathjs` library. The tool validates the input expression to ensure it's a + * single, valid mathematical expression before evaluation. + * + * @see {@link IToolExecutor} for the interface it implements. + * @see {@link ToolSystem} for the system that manages and executes tools. */ export class CalculatorTool implements IToolExecutor { /** The unique name identifier for this tool. */ diff --git a/src/types/index.ts b/src/types/index.ts old mode 100644 new mode 100755 index 4411f91..f52bc2d --- a/src/types/index.ts +++ b/src/types/index.ts @@ -1,8 +1,8 @@ // src/types/index.ts import type { RuntimeProviderConfig } from './providers'; // Import for use within this file -import type { IToolExecutor, IAgentCore } from '../core/interfaces'; // For ArtInstanceConfig -import type { LogLevel } from '../utils/logger'; // For ArtInstanceConfig -import type { StorageAdapter } from '../core/interfaces'; // For ArtInstanceConfig (storage property) +import type { IToolExecutor, IAgentCore } from '@/core/interfaces'; // For ArtInstanceConfig +import type { LogLevel } from '@/utils/logger'; // For ArtInstanceConfig +import type { StorageAdapter } from '@/core/interfaces'; // For ArtInstanceConfig (storage property) // --- ART Error Types --- export { ErrorCode, @@ -12,12 +12,29 @@ export { LocalInstanceBusyError, ApiQueueTimeoutError, AdapterInstantiationError -} from '../errors'; +} from '@/errors'; + +/** + * @module types + * + * This module aggregates and exports the core data structures, enums, and type definitions + * used throughout the ART framework. It serves as the single source of truth for + * a majority of the framework's types. + * + * Key exports include: + * - {@link AgentProps}: Input properties for agent execution. + * - {@link AgentFinalResponse}: Standardized output from an agent. + * - {@link ConversationMessage}: Structure for a single message in a conversation. + * - {@link ToolSchema}: Definition for a tool's capabilities. + * - {@link A2ATask}: Structure for Agent-to-Agent tasks. + * - Various enums like {@link MessageRole}, {@link ModelCapability}, etc. + */ // --- UI Socket Related Types --- -export { LLMStreamSocket } from '../systems/ui/llm-stream-socket'; -export { TypedSocket } from '../systems/ui/typed-socket'; -export type { UnsubscribeFunction } from '../systems/ui/typed-socket'; +export { LLMStreamSocket } from '@/systems/ui/llm-stream-socket'; +export { TypedSocket } from '@/systems/ui/typed-socket'; +export { A2ATaskSocket } from '@/systems/ui/a2a-task-socket'; +export type { UnsubscribeFunction } from '@/systems/ui/typed-socket'; // --- Zod Schemas for Validation --- export { ArtStandardPromptSchema, ArtStandardMessageSchema } from './schemas'; @@ -34,38 +51,71 @@ export type { /** * Represents the role of a message sender in a conversation. + * + * @enum {string} */ export enum MessageRole { + /** The end-user interacting with the agent. */ USER = 'USER', + /** The AI agent. */ AI = 'AI', - SYSTEM = 'SYSTEM', // Added for system prompts, though not explicitly in checklist message interface - TOOL = 'TOOL', // Added for tool results, though not explicitly in checklist message interface + /** A system-level message providing context or instructions. */ + SYSTEM = 'SYSTEM', + /** A message containing the result of a tool execution. */ + TOOL = 'TOOL', } /** * Represents a single message within a conversation thread. + * + * @interface ConversationMessage */ export interface ConversationMessage { - /** A unique identifier for this specific message. */ + /** + * A unique identifier for this specific message. + * @property {string} messageId + */ messageId: string; - /** The identifier of the conversation thread this message belongs to. */ + /** + * The identifier of the conversation thread this message belongs to. + * @property {string} threadId + */ threadId: string; - /** The role of the sender (User, AI, System, or Tool). */ + /** + * The role of the sender (User, AI, System, or Tool). + * @property {MessageRole} role + */ role: MessageRole; - /** The textual content of the message. */ + /** + * The textual content of the message. + * @property {string} content + */ content: string; - /** A Unix timestamp (in milliseconds) indicating when the message was created. */ + /** + * A Unix timestamp (in milliseconds) indicating when the message was created. + * @property {number} timestamp + */ timestamp: number; - /** Optional metadata associated with the message (e.g., related observation IDs, tool call info, UI state). */ + /** + * Optional metadata associated with the message (e.g., related observation IDs, tool call info, UI state). + * @property {Record} [metadata] + */ metadata?: Record; } /** * Represents the type of an observation record, capturing significant events during agent execution. + * + * @enum {string} */ export enum ObservationType { + /** The user's inferred intent. */ INTENT = 'INTENT', + /** The generated concise thread title. */ + TITLE = 'TITLE', + /** The agent's step-by-step plan to address the intent. */ PLAN = 'PLAN', + /** The agent's internal monologue or reasoning process. */ THOUGHTS = 'THOUGHTS', /** Records the LLM's decision to call one or more tools (part of the plan). */ TOOL_CALL = 'TOOL_CALL', @@ -95,53 +145,102 @@ export enum ObservationType { /** * Represents the different capabilities a model might possess. * Used for model selection and validation. + * + * @enum {string} */ export enum ModelCapability { - TEXT = 'text', // Basic text generation/understanding - VISION = 'vision', // Ability to process and understand images - STREAMING = 'streaming', // Supports streaming responses chunk by chunk - TOOL_USE = 'tool_use', // Capable of using tools/function calling - RAG = 'rag', // Built-in or optimized for Retrieval-Augmented Generation - CODE = 'code', // Specialized in understanding or generating code - REASONING = 'reasoning' // Advanced reasoning, planning, complex instruction following + /** Basic text generation/understanding. */ + TEXT = 'text', + /** Ability to process and understand images. */ + VISION = 'vision', + /** Supports streaming responses chunk by chunk. */ + STREAMING = 'streaming', + /** Capable of using tools/function calling. */ + TOOL_USE = 'tool_use', + /** Built-in or optimized for Retrieval-Augmented Generation. */ + RAG = 'rag', + /** Specialized in understanding or generating code. */ + CODE = 'code', + /** Advanced reasoning, planning, complex instruction following. */ + REASONING = 'reasoning' } // --- END NEW ENUM DEFINITION --- /** * Represents a recorded event during the agent's execution. + * + * @interface Observation */ export interface Observation { - /** A unique identifier for this specific observation record. */ + /** + * A unique identifier for this specific observation record. + * @property {string} id + */ id: string; - /** The identifier of the conversation thread this observation relates to. */ + /** + * The identifier of the conversation thread this observation relates to. + * @property {string} threadId + */ threadId: string; - /** An optional identifier for tracing a request across multiple systems or components. */ + /** + * An optional identifier for tracing a request across multiple systems or components. + * @property {string} [traceId] + */ traceId?: string; - /** A Unix timestamp (in milliseconds) indicating when the observation was recorded. */ + /** + * A Unix timestamp (in milliseconds) indicating when the observation was recorded. + * @property {number} timestamp + */ timestamp: number; - /** The category of the event being observed (e.g., PLAN, THOUGHTS, TOOL_EXECUTION). */ + /** + * The category of the event being observed (e.g., PLAN, THOUGHTS, TOOL_EXECUTION). + * @property {ObservationType} type + */ type: ObservationType; - /** A concise, human-readable title summarizing the observation (often generated based on type/metadata). */ + /** + * A concise, human-readable title summarizing the observation (often generated based on type/metadata). + * @property {string} title + */ title: string; - /** The main data payload of the observation, structure depends on the `type`. */ + /** + * The main data payload of the observation, structure depends on the `type`. + * + * @remarks + * Common content shapes by `type`: + * - `TITLE`: `{ title: string }` — a concise thread title (<= 10 words) + * - `INTENT`: `{ intent: string }` + * - `PLAN`: `{ plan: string; rawOutput?: string }` + * - `TOOL_CALL`: `{ toolCalls: ParsedToolCall[] }` + * - `TOOL_EXECUTION`: `{ callId: string; toolName: string; status: 'success' | 'error'; output?: any; error?: string }` + * - `FINAL_RESPONSE`: `{ message: ConversationMessage; uiMetadata?: object }` + * @property {any} content + */ content: any; - /** Optional metadata providing additional context (e.g., source phase, related IDs, status). */ + /** + * Optional metadata providing additional context (e.g., source phase, related IDs, status). + * @property {Record} [metadata] + */ metadata?: Record; } /** * Represents a single event emitted from an asynchronous LLM stream (`ReasoningEngine.call`). + * + * @remarks * Allows for real-time delivery of tokens, metadata, errors, and lifecycle signals. * Adapters are responsible for translating provider-specific stream chunks into these standard events. + * + * @interface StreamEvent */ export interface StreamEvent { /** - * The type of the stream event: + * The type of the stream event. * - `TOKEN`: A chunk of text generated by the LLM. * - `METADATA`: Information about the LLM call (e.g., token counts, stop reason), typically sent once at the end. * - `ERROR`: An error occurred during the LLM call or stream processing. `data` will contain the Error object. * - `END`: Signals the successful completion of the stream. `data` is typically null. + * @property {'TOKEN' | 'METADATA' | 'ERROR' | 'END'} type */ type: 'TOKEN' | 'METADATA' | 'ERROR' | 'END'; /** @@ -150,6 +249,7 @@ export interface StreamEvent { * - For `METADATA`: `LLMMetadata` object. * - For `ERROR`: `Error` object or error details. * - For `END`: null. + * @property {any} data */ data: any; /** @@ -165,25 +265,44 @@ export interface StreamEvent { * - `FINAL_SYNTHESIS_LLM_THINKING`: Token from an LLM call made in the 'FINAL_SYNTHESIS' context, identified as thinking. * - `FINAL_SYNTHESIS_LLM_RESPONSE`: Token from an LLM call made in the 'FINAL_SYNTHESIS' context, identified as response (part of the final answer to the user). * - * Note: Not all adapters can reliably distinguish 'LLM_THINKING' vs 'LLM_RESPONSE'. + * @remarks + * Not all adapters can reliably distinguish 'LLM_THINKING' vs 'LLM_RESPONSE'. * Adapters should prioritize setting the agent context part (`AGENT_THOUGHT_...` or `FINAL_SYNTHESIS_...`) based on `CallOptions.callContext`. * If thinking detection is unavailable, adapters should default to `AGENT_THOUGHT_LLM_RESPONSE` or `FINAL_SYNTHESIS_LLM_RESPONSE`. + * @property {'LLM_THINKING' | 'LLM_RESPONSE' | 'AGENT_THOUGHT_LLM_THINKING' | 'AGENT_THOUGHT_LLM_RESPONSE' | 'FINAL_SYNTHESIS_LLM_THINKING' | 'FINAL_SYNTHESIS_LLM_RESPONSE'} [tokenType] */ tokenType?: 'LLM_THINKING' | 'LLM_RESPONSE' | 'AGENT_THOUGHT_LLM_THINKING' | 'AGENT_THOUGHT_LLM_RESPONSE' | 'FINAL_SYNTHESIS_LLM_THINKING' | 'FINAL_SYNTHESIS_LLM_RESPONSE'; - /** The identifier of the conversation thread this event belongs to. */ + /** + * The identifier of the conversation thread this event belongs to. + * @property {string} threadId + */ threadId: string; - /** The identifier tracing the specific agent execution cycle this event is part of. */ + /** + * The identifier tracing the specific agent execution cycle this event is part of. + * @property {string} traceId + */ traceId: string; - /** Optional identifier linking the event to a specific UI tab/window. */ + /** + * Optional identifier linking the event to a specific UI tab/window. + * @property {string} [sessionId] + */ sessionId?: string; } /** * Represents a basic JSON Schema definition, focusing on object types commonly used for tool inputs/outputs. * This is a simplified representation and doesn't cover all JSON Schema features. + * + * @interface JsonObjectSchema */ export interface JsonObjectSchema { + /** + * @property {'object'} type + */ type: 'object'; + /** + * @property {object} properties + */ properties: { [key: string]: { type: string; // e.g., 'string', 'number', 'boolean', 'object', 'array' @@ -206,125 +325,348 @@ export type JsonSchema = JsonObjectSchema | { type: 'string' | 'number' | 'boole /** * Structure for holding metadata about an LLM call, typically received via a `METADATA` `StreamEvent` * or parsed from a non-streaming response. Fields are optional as availability varies by provider and stream state. + * + * @interface LLMMetadata */ export interface LLMMetadata { - /** The number of tokens in the input prompt, if available. */ + /** + * The number of tokens in the input prompt, if available. + * @property {number} [inputTokens] + */ inputTokens?: number; - /** The number of tokens generated in the output response, if available. */ + /** + * The number of tokens generated in the output response, if available. + * @property {number} [outputTokens] + */ outputTokens?: number; - /** The number of tokens identified as part of the LLM's internal thinking process (if available from provider). */ + /** + * The number of tokens identified as part of the LLM's internal thinking process (if available from provider). + * @property {number} [thinkingTokens] + */ thinkingTokens?: number; - /** The time elapsed (in milliseconds) until the first token was generated in a streaming response, if applicable and available. */ + /** + * The time elapsed (in milliseconds) until the first token was generated in a streaming response, if applicable and available. + * @property {number} [timeToFirstTokenMs] + */ timeToFirstTokenMs?: number; - /** The total time elapsed (in milliseconds) for the entire generation process, if available. */ + /** + * The total time elapsed (in milliseconds) for the entire generation process, if available. + * @property {number} [totalGenerationTimeMs] + */ totalGenerationTimeMs?: number; - /** The reason the LLM stopped generating tokens (e.g., 'stop_sequence', 'max_tokens', 'tool_calls'), if available. */ + /** + * The reason the LLM stopped generating tokens (e.g., 'stop_sequence', 'max_tokens', 'tool_calls'), if available. + * @property {string} [stopReason] + */ stopReason?: string; - /** Optional raw usage data provided directly by the LLM provider for extensibility (structure depends on provider). */ + /** + * Optional raw usage data provided directly by the LLM provider for extensibility (structure depends on provider). + * @property {any} [providerRawUsage] + */ providerRawUsage?: any; - /** The trace ID associated with the LLM call, useful for correlating metadata with the specific request. */ + /** + * The trace ID associated with the LLM call, useful for correlating metadata with the specific request. + * @property {string} [traceId] + */ traceId?: string; // Include traceId if this object might be stored or passed independently. } /** * Defines the schema for a tool, including its input parameters. * Uses JSON Schema format for inputSchema. + * + * @interface ToolSchema */ export interface ToolSchema { - /** A unique name identifying the tool (used in LLM prompts and registry lookups). Must be unique. */ + /** + * A unique name identifying the tool (used in LLM prompts and registry lookups). Must be unique. + * @property {string} name + */ name: string; - /** A clear description of what the tool does, intended for the LLM to understand its purpose and usage. */ + /** + * A clear description of what the tool does, intended for the LLM to understand its purpose and usage. + * @property {string} description + */ description: string; - /** A JSON Schema object defining the structure, types, and requirements of the input arguments the tool expects. */ + /** + * A JSON Schema object defining the structure, types, and requirements of the input arguments the tool expects. + * @property {JsonSchema} inputSchema + */ inputSchema: JsonSchema; - /** An optional JSON Schema object defining the expected structure of the data returned in the `output` field of a successful `ToolResult`. */ + /** + * An optional JSON Schema object defining the expected structure of the data returned in the `output` field of a successful `ToolResult`. + * @property {JsonSchema} [outputSchema] + */ outputSchema?: JsonSchema; - /** Optional array of examples demonstrating how to use the tool, useful for few-shot prompting of the LLM. */ + /** + * Optional array of examples demonstrating how to use the tool, useful for few-shot prompting of the LLM. + * @property {Array<{ input: any; output?: any; description?: string }>} [examples] + */ examples?: Array<{ input: any; output?: any; description?: string }>; } /** * Represents the structured result of a tool execution. + * + * @interface ToolResult */ export interface ToolResult { - /** The unique identifier of the corresponding `ParsedToolCall` that initiated this execution attempt. */ + /** + * The unique identifier of the corresponding `ParsedToolCall` that initiated this execution attempt. + * @property {string} callId + */ callId: string; - /** The name of the tool that was executed. */ + /** + * The name of the tool that was executed. + * @property {string} toolName + */ toolName: string; - /** Indicates whether the tool execution succeeded or failed. */ + /** + * Indicates whether the tool execution succeeded or failed. + * @property {'success' | 'error'} status + */ status: 'success' | 'error'; - /** The data returned by the tool upon successful execution. Structure may be validated against `outputSchema`. */ + /** + * The data returned by the tool upon successful execution. Structure may be validated against `outputSchema`. + * @property {any} [output] + */ output?: any; - /** A descriptive error message if the execution failed (`status` is 'error'). */ + /** + * A descriptive error message if the execution failed (`status` is 'error'). + * @property {string} [error] + */ error?: string; - /** Optional metadata about the execution (e.g., duration, cost, logs). */ - metadata?: Record; + /** + * Optional metadata about the execution (e.g., duration, cost, logs). + * @property {object} [metadata] + */ + metadata?: { + sources?: Array<{ + sourceName: string; + url?: string; + [key: string]: any; + }>; + [key: string]: any; + }; +} + +// --- SYSTEM PROMPT STANDARDIZATION TYPES --- +/** + * Strategy for combining custom system prompt content across precedence levels. + * + * @typedef {'append' | 'prepend'} SystemPromptMergeStrategy + */ +export type SystemPromptMergeStrategy = 'append' | 'prepend'; + +/** + * Named preset for system prompts, supporting variables and a default merge strategy. + * + * @interface SystemPromptSpec + */ +export interface SystemPromptSpec { + /** + * Optional explicit ID; when in a registry map, the key is typically the tag. + * @property {string} [id] + */ + id?: string; + /** + * Template string. Supports simple {{variable}} placeholders and {{fragment:name}} for PromptManager fragments. + * @property {string} template + */ + template: string; + /** + * Default variables applied if not provided at use time. + * @property {Record} [defaultVariables] + */ + defaultVariables?: Record; + /** + * Default strategy to combine this spec with lower levels. Defaults to 'append'. + * @property {SystemPromptMergeStrategy} [mergeStrategy] + */ + mergeStrategy?: SystemPromptMergeStrategy; +} + +/** + * Registry of available system prompt presets (tags) at the instance level. + * + * @interface SystemPromptsRegistry + */ +export interface SystemPromptsRegistry { + /** + * Tag to use when no other tag is specified. + * @property {string} [defaultTag] + */ + defaultTag?: string; + /** + * Mapping of tag -> spec. + * @property {Record} specs + */ + specs: Record; +} + +/** + * Override provided at instance/thread/call level to select a tag and/or provide variables, + * or to provide freeform content and a merge strategy. + * + * @interface SystemPromptOverride + */ +export interface SystemPromptOverride { + /** + * Preset tag from the registry (e.g., 'default', 'legal_advisor'). + * @property {string} [tag] + */ + tag?: string; + /** + * Variables to substitute in the selected template. + * @property {Record} [variables] + */ + variables?: Record; + /** + * Freeform content to apply directly (escape hatch). + * @property {string} [content] + */ + content?: string; + /** + * Merge behavior against previous level: append | prepend. + * @property {SystemPromptMergeStrategy} [strategy] + */ + strategy?: SystemPromptMergeStrategy; } /** * Represents a parsed request from the LLM to call a specific tool. + * + * @interface ParsedToolCall */ export interface ParsedToolCall { - /** A unique identifier generated by the OutputParser for this specific tool call request within a plan. */ + /** + * A unique identifier generated by the OutputParser for this specific tool call request within a plan. + * @property {string} callId + */ callId: string; - /** The name of the tool the LLM intends to call. Must match a registered tool's schema name. */ + /** + * The name of the tool the LLM intends to call. Must match a registered tool's schema name. + * @property {string} toolName + */ toolName: string; - /** The arguments object, parsed from the LLM response, intended to be passed to the tool's `execute` method after validation. */ + /** + * The arguments object, parsed from the LLM response, intended to be passed to the tool's `execute` method after validation. + * @property {any} arguments + */ arguments: any; } /** * Configuration specific to a conversation thread. + * + * @interface ThreadConfig */ export interface ThreadConfig { - /** Default provider configuration for this thread. */ + /** + * Default provider configuration for this thread. + * @property {RuntimeProviderConfig} providerConfig + */ providerConfig: RuntimeProviderConfig; - /** An array of tool names (matching `ToolSchema.name`) that are permitted for use within this thread. */ + /** + * An array of tool names (matching `ToolSchema.name`) that are permitted for use within this thread. + * @property {string[]} enabledTools + */ enabledTools: string[]; - /** The maximum number of past messages (`ConversationMessage` objects) to retrieve for context. */ + /** + * The maximum number of past messages (`ConversationMessage` objects) to retrieve for context. + * @property {number} historyLimit + */ historyLimit: number; - /** Optional system prompt string to be used for this thread, overriding instance or agent defaults. */ - systemPrompt?: string; + /** + * Optional system prompt override to be used for this thread, overriding instance or agent defaults. + * @property {string | SystemPromptOverride} [systemPrompt] + */ + systemPrompt?: string | SystemPromptOverride; + /** + * Optional: Defines the identity and high-level guidance for the agent for this specific thread. + * This overrides the instance-level persona. + * @property {Partial} [persona] + */ + persona?: Partial; // TODO: Add other potential thread-specific settings (e.g., RAG configuration, default timeouts) } /** * Represents non-configuration state associated with an agent or thread. * Could include user preferences, accumulated knowledge, etc. (Less defined for v1.0) + * + * @interface AgentState */ export interface AgentState { - /** The primary data payload of the agent's state. Structure is application-defined. */ + /** + * The primary data payload of the agent's state. Structure is application-defined. + * @property {any} data + */ data: any; - /** An optional version number for the agent's state, useful for migrations or tracking changes. */ + /** + * An optional version number for the agent's state, useful for migrations or tracking changes. + * @property {number} [version] + */ version?: number; - /** Allows for other arbitrary properties to be stored in the agent's state. */ + /** + * Allows for other arbitrary properties to be stored in the agent's state. + * @property {any} [key: string] + */ [key: string]: any; } /** * Encapsulates the configuration and state for a specific thread. + * + * @interface ThreadContext */ export interface ThreadContext { - /** The configuration settings (`ThreadConfig`) currently active for the thread. */ + /** + * The configuration settings (`ThreadConfig`) currently active for the thread. + * @property {ThreadConfig} config + */ config: ThreadConfig; - /** The persistent state (`AgentState`) associated with the thread, or `null` if no state exists. */ + /** + * The persistent state (`AgentState`) associated with the thread, or `null` if no state exists. + * @property {AgentState | null} state + */ state: AgentState | null; } /** * Properties required to initiate an agent processing cycle. + * + * @interface AgentProps */ export interface AgentProps { - /** The user's input query or request to the agent. */ + /** + * The user's input query or request to the agent. + * @property {string} query + */ query: string; - /** The mandatory identifier for the conversation thread. All context is scoped to this ID. */ + /** + * The mandatory identifier for the conversation thread. All context is scoped to this ID. + * @property {string} threadId + */ threadId: string; - /** An optional identifier for the specific UI session, useful for targeting UI updates. */ + /** + * An optional identifier for the specific UI session, useful for targeting UI updates. + * @property {string} [sessionId] + */ sessionId?: string; - /** An optional identifier for the user interacting with the agent. */ + /** + * An optional identifier for the user interacting with the agent. + * @property {string} [userId] + */ userId?: string; - /** An optional identifier used for tracing a request across multiple systems or services. */ + /** + * An optional identifier used for tracing a request across multiple systems or services. + * @property {string} [traceId] + */ traceId?: string; - /** Optional runtime options that can override default behaviors for this specific `process` call. */ + /** + * Optional runtime options that can override default behaviors for this specific `process` call. + * @property {AgentOptions} [options] + */ options?: AgentOptions; // Note: Core dependencies (StateManager, ConversationManager, etc.) are typically injected // during `createArtInstance` and are accessed internally by the Agent Core, not passed in AgentProps. @@ -332,70 +674,150 @@ export interface AgentProps { /** * Options to override agent behavior at runtime. + * + * @interface AgentOptions */ export interface AgentOptions { - /** Override specific LLM parameters (e.g., temperature, max_tokens) for this call only. */ + /** + * Override specific LLM parameters (e.g., temperature, max_tokens) for this call only. + * @property {Record} [llmParams] + */ llmParams?: Record; - /** Override provider configuration for this specific call. */ + /** + * Override provider configuration for this specific call. + * @property {RuntimeProviderConfig} [providerConfig] + */ providerConfig?: RuntimeProviderConfig; // Add this line - /** Force the use of specific tools, potentially overriding the thread's `enabledTools` for this call (use with caution). */ + /** + * Force the use of specific tools, potentially overriding the thread's `enabledTools` for this call (use with caution). + * @property {string[]} [forceTools] + */ forceTools?: string[]; - /** Specify a particular reasoning model to use for this call, overriding the thread's default. */ + /** + * Specify a particular reasoning model to use for this call, overriding the thread's default. + * @property {{ provider: string; model: string }} [overrideModel] + */ overrideModel?: { provider: string; model: string }; - /** Request a streaming response for this specific agent process call. */ + /** + * Request a streaming response for this specific agent process call. + * @property {boolean} [stream] + */ stream?: boolean; - /** Override the prompt template used for this specific call. */ + /** + * Override the prompt template used for this specific call. + * @property {string} [promptTemplateId] + */ promptTemplateId?: string; - /** Optional system prompt string to override thread, instance, or agent defaults for this specific call. */ - systemPrompt?: string; + /** + * Optional system prompt override/tag to override thread, instance, or agent defaults for this specific call. + * @property {string | SystemPromptOverride} [systemPrompt] + */ + systemPrompt?: string | SystemPromptOverride; + /** + * Optional: Defines the identity and high-level guidance for the agent for this specific call. + * This overrides both the instance-level and thread-level persona. + * @property {Partial} [persona] + */ + persona?: Partial; // TODO: Add other potential runtime overrides (e.g., history length). } /** * The final structured response returned by the agent core after processing. + * + * @interface AgentFinalResponse */ export interface AgentFinalResponse { - /** The final `ConversationMessage` generated by the AI, which has also been persisted. */ + /** + * The final `ConversationMessage` generated by the AI, which has also been persisted. + * @property {ConversationMessage} response + */ response: ConversationMessage; - /** Metadata summarizing the execution cycle that produced this response. */ + /** + * Metadata summarizing the execution cycle that produced this response. + * @property {ExecutionMetadata} metadata + */ metadata: ExecutionMetadata; } /** * Metadata summarizing an agent execution cycle, including performance metrics and outcomes. + * + * @interface ExecutionMetadata */ export interface ExecutionMetadata { - /** The thread ID associated with this execution cycle. */ + /** + * The thread ID associated with this execution cycle. + * @property {string} threadId + */ threadId: string; - /** The trace ID used during this execution, if provided. */ + /** + * The trace ID used during this execution, if provided. + * @property {string} [traceId] + */ traceId?: string; - /** The user ID associated with the execution, if provided. */ + /** + * The user ID associated with the execution, if provided. + * @property {string} [userId] + */ userId?: string; - /** The overall status of the execution ('success', 'error', or 'partial' if some steps failed but a response was generated). */ + /** + * The overall status of the execution ('success', 'error', or 'partial' if some steps failed but a response was generated). + * @property {'success' | 'error' | 'partial'} status + */ status: 'success' | 'error' | 'partial'; - /** The total duration of the `agent.process()` call in milliseconds. */ + /** + * The total duration of the `agent.process()` call in milliseconds. + * @property {number} totalDurationMs + */ totalDurationMs: number; - /** The number of calls made to the `ReasoningEngine`. */ + /** + * The number of calls made to the `ReasoningEngine`. + * @property {number} llmCalls + */ llmCalls: number; - /** The number of tool execution attempts made by the `ToolSystem`. */ + /** + * The number of tool execution attempts made by the `ToolSystem`. + * @property {number} toolCalls + */ toolCalls: number; - /** An optional estimated cost for the LLM calls made during this execution. */ + /** + * An optional estimated cost for the LLM calls made during this execution. + * @property {number} [llmCost] + */ llmCost?: number; - /** A top-level error message if the overall status is 'error' or 'partial'. */ + /** + * A top-level error message if the overall status is 'error' or 'partial'. + * @property {string} [error] + */ error?: string; - /** Aggregated metadata from LLM calls made during the execution. */ + /** + * Aggregated metadata from LLM calls made during the execution. + * @property {LLMMetadata} [llmMetadata] + */ llmMetadata?: LLMMetadata; } /** * Context provided to a tool during its execution. + * + * @interface ExecutionContext */ export interface ExecutionContext { - /** The ID of the thread in which the tool is being executed. */ + /** + * The ID of the thread in which the tool is being executed. + * @property {string} threadId + */ threadId: string; - /** The trace ID for this execution cycle, if available. */ + /** + * The trace ID for this execution cycle, if available. + * @property {string} [traceId] + */ traceId?: string; - /** The user ID associated with the execution, if available. */ + /** + * The user ID associated with the execution, if available. + * @property {string} [userId] + */ userId?: string; // TODO: Potentially include access tokens or credentials scoped to this execution, if needed securely. // TODO: Consider providing limited access to StateManager or other relevant context if required by complex tools. @@ -403,34 +825,57 @@ export interface ExecutionContext { /** * Options for configuring an LLM call, including streaming and context information. + * + * @interface CallOptions */ export interface CallOptions { - /** The mandatory thread ID, used by the ReasoningEngine to fetch thread-specific configuration (e.g., model, params) via StateManager. */ + /** + * The mandatory thread ID, used by the ReasoningEngine to fetch thread-specific configuration (e.g., model, params) via StateManager. + * @property {string} threadId + */ threadId: string; - /** Optional trace ID for correlation. */ + /** + * Optional trace ID for correlation. + * @property {string} [traceId] + */ traceId?: string; - /** Optional user ID. */ + /** + * Optional user ID. + * @property {string} [userId] + */ userId?: string; - /** Optional session ID. */ + /** + * Optional session ID. + * @property {string} [sessionId] + */ sessionId?: string; // Added sessionId /** * Request a streaming response from the LLM provider. * Adapters MUST check this flag. + * @property {boolean} [stream] */ stream?: boolean; /** * Provides context for the LLM call, allowing adapters to differentiate * between agent-level thoughts and final synthesis calls for token typing. * Agent Core MUST provide this. + * @property {'AGENT_THOUGHT' | 'FINAL_SYNTHESIS' | string} [callContext] */ callContext?: 'AGENT_THOUGHT' | 'FINAL_SYNTHESIS' | string; - /** An optional callback function invoked when the LLM streams intermediate 'thoughts' or reasoning steps. + /** + * An optional callback function invoked when the LLM streams intermediate 'thoughts' or reasoning steps. * @deprecated Prefer using StreamEvent with appropriate tokenType for thoughts. Kept for potential transitional compatibility. */ // onThought?: (thought: string) => void; // Commented out as per implementation plan decision (Ref: 7.2, Checklist Phase 1) - /** Carries the specific target provider and configuration for this call. */ + /** + * Carries the specific target provider and configuration for this call. + * @property {RuntimeProviderConfig} providerConfig + */ providerConfig: RuntimeProviderConfig; - /** Additional key-value pairs representing provider-specific parameters (e.g., `temperature`, `max_tokens`, `top_p`). These often override defaults set in `ThreadConfig`. */ + /** + * Additional key-value pairs representing provider-specific parameters (e.g., `temperature`, `max_tokens`, `top_p`). These often override defaults set in `ThreadConfig`. + * @property {any} [key: string] + */ [key: string]: any; } @@ -438,6 +883,8 @@ export interface CallOptions { /** * Defines the standard roles for messages within the `ArtStandardPrompt` format. + * + * @remarks * These roles are chosen for broad compatibility across major LLM providers (like OpenAI, Anthropic, Gemini). * Provider Adapters are responsible for translating these standard roles into the specific formats * required by their respective APIs (e.g., 'assistant' might become 'model' for Gemini). @@ -447,15 +894,24 @@ export interface CallOptions { * - `assistant`: Responses generated by the AI model. Can contain text content and/or `tool_calls`. * - `tool_request`: Represents the LLM's request to use tools (often implicitly part of an `assistant` message with `tool_calls`). Included for potential future explicit use. * - `tool_result`: The outcome (output or error) of executing a requested tool call. + * + * @typedef {'system' | 'user' | 'assistant' | 'tool_request' | 'tool_result' | 'tool'} ArtStandardMessageRole */ export type ArtStandardMessageRole = 'system' | 'user' | 'assistant' | 'tool_request' | 'tool_result' | 'tool'; // Added 'tool' role /** * Represents a single message in the standardized, provider-agnostic `ArtStandardPrompt` format. + * + * @remarks * This structure aims to capture common message elements used by various LLM APIs. + * + * @interface ArtStandardMessage */ export interface ArtStandardMessage { - /** The role indicating the source or type of the message. */ + /** + * The role indicating the source or type of the message. + * @property {ArtStandardMessageRole} role + */ role: ArtStandardMessageRole; /** * The primary content of the message. The type and interpretation depend on the `role`: @@ -464,14 +920,22 @@ export interface ArtStandardMessage { * - `assistant`: string | null (The AI's text response, or null/empty if only making `tool_calls`). * - `tool_request`: object | null (Structured representation of the tool call, often implicitly handled via `assistant` message's `tool_calls`). * - `tool_result`: string (Stringified JSON output or error message from the tool execution). + * @property {string | object | null} content */ content: string | object | null; - /** Optional name associated with the message. Primarily used for `tool_result` role to specify the name of the tool that was executed. */ + /** + * Optional name associated with the message. Primarily used for `tool_result` role to specify the name of the tool that was executed. + * @property {string} [name] + */ name?: string; /** * Optional array of tool calls requested by the assistant. + * + * @remarks * Only relevant for 'assistant' role messages that trigger tool usage. * Structure mirrors common provider formats (e.g., OpenAI). + * + * @property {Array<{ id: string; type: 'function'; function: { name: string; arguments: string; }; }>} [tool_calls] */ tool_calls?: Array<{ /** A unique identifier for this specific tool call request. */ @@ -490,14 +954,20 @@ export interface ArtStandardMessage { * Optional identifier linking a 'tool_result' message back to the specific 'tool_calls' entry * in the preceding 'assistant' message that requested it. * Required for 'tool_result' role. + * @property {string} [tool_call_id] */ tool_call_id?: string; } /** * Represents the entire prompt as an array of standardized messages (`ArtStandardMessage`). - * This is the standard format produced by `PromptManager.assemblePrompt` and consumed - * by `ProviderAdapter.call` for translation into provider-specific API formats. + * + * @remarks + * Constructed by agent logic (e.g., `PESAgent`) and optionally validated via + * `PromptManager.validatePrompt` before being sent to the `ReasoningEngine` and + * translated by a `ProviderAdapter` for provider-specific API formats. + * + * @typedef {ArtStandardMessage[]} ArtStandardPrompt */ export type ArtStandardPrompt = ArtStandardMessage[]; @@ -505,84 +975,157 @@ export type ArtStandardPrompt = ArtStandardMessage[]; * Represents the contextual data gathered by Agent Logic (e.g., `PESAgent`) to be injected * into a Mustache blueprint/template by the `PromptManager.assemblePrompt` method. * + * @remarks * Contains standard fields commonly needed for prompts, plus allows for arbitrary * additional properties required by specific agent blueprints. Agent logic is responsible * for populating this context appropriately before calling `assemblePrompt`. + * + * @interface PromptContext */ export interface PromptContext { - /** The user's current query or input relevant to this prompt generation step. */ + /** + * The user's current query or input relevant to this prompt generation step. + * @property {string} [query] + */ query?: string; /** * The conversation history, typically formatted as an array suitable for the blueprint * (e.g., array of objects with `role` and `content`). Agent logic should pre-format this. - * Note: While `ArtStandardPrompt` could be used, simpler structures might be preferred for blueprints. + * + * @remarks + * While `ArtStandardPrompt` could be used, simpler structures might be preferred for blueprints. + * + * @property {Array<{ role: string; content: string; [key: string]: any }>} [history] */ history?: Array<{ role: string; content: string; [key: string]: any }>; // Flexible history format for blueprints /** * The schemas of the tools available for use, potentially pre-formatted for the blueprint * (e.g., with `inputSchemaJson` pre-stringified). + * @property {Array} [availableTools] */ availableTools?: Array; /** * The results from any tools executed in a previous step, potentially pre-formatted for the blueprint * (e.g., with `outputJson` pre-stringified). + * @property {Array} [toolResults] */ toolResults?: Array; - /** The system prompt string to be used (resolved by agent logic from config or defaults). */ + /** + * The system prompt string to be used (resolved by agent logic from config or defaults). + * @property {string} [systemPrompt] + */ systemPrompt?: string; - /** Allows agent patterns (like PES) to pass any other custom data needed by their specific blueprints (e.g., `intent`, `plan`). */ + /** + * Allows agent patterns (like PES) to pass any other custom data needed by their specific blueprints (e.g., `intent`, `plan`). + * @property {any} [key: string] + */ [key: string]: any; } +/** + * Represents a Mustache template that can be rendered with a PromptContext to produce an ArtStandardPrompt. + * Used by the PromptManager.assemblePrompt method. + * + * @interface PromptBlueprint + */ +export interface PromptBlueprint { + /** + * The Mustache template string that will be rendered with context data to produce a JSON string representing an ArtStandardPrompt + * @property {string} template + */ + template: string; +} + // --- END ART STANDARD PROMPT TYPES --- /** * Represents the prompt data formatted for a specific LLM provider. * Can be a simple string or a complex object (e.g., for OpenAI Chat Completion API). + * * @deprecated Use `ArtStandardPrompt` as the standard intermediate format. ProviderAdapters handle final formatting. + * @typedef {ArtStandardPrompt} FormattedPrompt */ export type FormattedPrompt = ArtStandardPrompt; // Point deprecated type to the new standard /** * Options for filtering data retrieved from storage. * Structure depends heavily on the underlying adapter's capabilities. + * + * @interface FilterOptions */ export interface FilterOptions { - /** An object defining filter criteria (e.g., `{ threadId: 'abc', type: 'TOOL_EXECUTION' }`). Structure may depend on adapter capabilities. */ + /** + * An object defining filter criteria (e.g., `{ threadId: 'abc', type: 'TOOL_EXECUTION' }`). Structure may depend on adapter capabilities. + * @property {Record} [filter] + */ filter?: Record; - /** An object defining sorting criteria (e.g., `{ timestamp: 'desc' }`). */ + /** + * An object defining sorting criteria (e.g., `{ timestamp: 'desc' }`). + * @property {Record} [sort] + */ sort?: Record; - /** The maximum number of records to return. */ + /** + * The maximum number of records to return. + * @property {number} [limit] + */ limit?: number; - /** The number of records to skip (for pagination). */ + /** + * The number of records to skip (for pagination). + * @property {number} [skip] + */ skip?: number; // TODO: Consider adding projection options to retrieve only specific fields. } /** * Options for retrieving conversation messages. + * + * @interface MessageOptions */ export interface MessageOptions { - /** The maximum number of messages to retrieve. */ + /** + * The maximum number of messages to retrieve. + * @property {number} [limit] + */ limit?: number; - /** Retrieve messages created before this Unix timestamp (milliseconds). */ + /** + * Retrieve messages created before this Unix timestamp (milliseconds). + * @property {number} [beforeTimestamp] + */ beforeTimestamp?: number; - /** Retrieve messages created after this Unix timestamp (milliseconds). */ + /** + * Retrieve messages created after this Unix timestamp (milliseconds). + * @property {number} [afterTimestamp] + */ afterTimestamp?: number; - /** Optionally filter messages by role (e.g., retrieve only 'AI' messages). */ + /** + * Optionally filter messages by role (e.g., retrieve only 'AI' messages). + * @property {MessageRole[]} [roles] + */ roles?: MessageRole[]; } /** * Options for filtering observations. + * + * @interface ObservationFilter */ export interface ObservationFilter { - /** An array of `ObservationType` enums to filter by. If provided, only observations matching these types are returned. */ + /** + * An array of `ObservationType` enums to filter by. If provided, only observations matching these types are returned. + * @property {ObservationType[]} [types] + */ types?: ObservationType[]; - /** Retrieve observations recorded before this Unix timestamp (milliseconds). */ + /** + * Retrieve observations recorded before this Unix timestamp (milliseconds). + * @property {number} [beforeTimestamp] + */ beforeTimestamp?: number; - /** Retrieve observations recorded after this Unix timestamp (milliseconds). */ + /** + * Retrieve observations recorded after this Unix timestamp (milliseconds). + * @property {number} [afterTimestamp] + */ afterTimestamp?: number; // TODO: Add other potential criteria like filtering by metadata content if needed. } @@ -592,58 +1135,573 @@ export interface ObservationFilter { /** * Defines the strategy for saving AgentState. + * + * @remarks * - 'explicit': AgentState is only saved when `StateManager.setAgentState()` is explicitly called by the agent. * `StateManager.saveStateIfModified()` will be a no-op for AgentState persistence. * - 'implicit': AgentState is loaded by `StateManager.loadThreadContext()`, and if modified by the agent, * `StateManager.saveStateIfModified()` will attempt to automatically persist these changes * by comparing the current state with a snapshot taken at load time. * `StateManager.setAgentState()` will still work for explicit saves. + * + * @typedef {'explicit' | 'implicit'} StateSavingStrategy */ export type StateSavingStrategy = 'explicit' | 'implicit'; // Explicitly import ProviderManagerConfig here for ArtInstanceConfig import type { ProviderManagerConfig as PMConfig } from './providers'; +// Import McpManagerConfig for ArtInstanceConfig +import type { McpManagerConfig } from '../systems/mcp/types'; /** * Configuration for creating an ART instance. + * + * @interface ArtInstanceConfig */ export interface ArtInstanceConfig { /** * Configuration for the storage adapter. * Can be a pre-configured `StorageAdapter` instance, * or an object specifying the type and options for a built-in adapter. - * Example: `{ type: 'indexedDB', dbName: 'MyArtDB' }` + * + * @example { type: 'indexedDB', dbName: 'MyArtDB' } + * + * @property {StorageAdapter | { type: 'memory' | 'indexedDB', dbName?: string, version?: number, objectStores?: any[] }} storage */ storage: StorageAdapter | { type: 'memory' | 'indexedDB', dbName?: string, version?: number, objectStores?: any[] }; - /** Configuration for the ProviderManager, defining available LLM provider adapters. */ + /** + * Configuration for the ProviderManager, defining available LLM provider adapters. + * @property {PMConfig} providers + */ providers: PMConfig; // Use the aliased import /** * The agent core implementation class to use. * Defaults to `PESAgent` if not provided. - * Example: `MyCustomAgentClass` + * + * @example MyCustomAgentClass + * + * @property {new (dependencies: any) => IAgentCore} [agentCore] */ agentCore?: new (dependencies: any) => IAgentCore; // Constructor type for an IAgentCore implementation - /** An optional array of tool executor instances to register at initialization. */ + /** + * An optional array of tool executor instances to register at initialization. + * @property {IToolExecutor[]} [tools] + */ tools?: IToolExecutor[]; /** * Defines the strategy for saving `AgentState`. Defaults to 'explicit'. + * + * @remarks * - 'explicit': `AgentState` is only saved when `StateManager.setAgentState()` is explicitly called by the agent. * `StateManager.saveStateIfModified()` will be a no-op for `AgentState` persistence. * - 'implicit': `AgentState` is loaded by `StateManager.loadThreadContext()`. If modified by the agent, * `StateManager.saveStateIfModified()` will attempt to automatically persist these changes. * `StateManager.setAgentState()` will still work for explicit saves in this mode. + * + * @property {StateSavingStrategy} [stateSavingStrategy] */ stateSavingStrategy?: StateSavingStrategy; - /** Optional configuration for the framework's logger. */ + /** + * Optional configuration for the framework's logger. + * @property {{ level?: LogLevel }} [logger] + */ logger?: { /** Minimum log level to output. Defaults to 'info'. */ level?: LogLevel; }; /** - * Optional default system prompt string to be used for the entire ART instance. - * This can be overridden at the thread level or at the individual call level. + * Optional: Defines the default identity and high-level guidance for the agent. + * This can be overridden at the thread or call level. + * @property {AgentPersona} [persona] + */ + persona?: AgentPersona; + /** + * Optional configuration for MCP (Model Context Protocol) manager. + * Enables connection to external MCP servers for dynamic tool loading. + * @property {McpManagerConfig} [mcpConfig] + */ + mcpConfig?: McpManagerConfig; + /** + * Optional configuration for authentication strategies. + * Used for secure connections to external services and MCP servers. + * @property {object} [authConfig] + */ + authConfig?: { + /** + * Whether to enable authentication manager. Defaults to false. + * @property {boolean} [enabled] + */ + enabled?: boolean; + /** + * Pre-configured authentication strategies to register at startup. + * @property {Array<{ id: string; strategy: any }>} [strategies] + */ + strategies?: Array<{ id: string; strategy: any }>; + }; + /** + * Optional: Configuration for A2A services. + * @property {object} [a2aConfig] */ - defaultSystemPrompt?: string; + a2aConfig?: { + /** + * The endpoint for discovering A2A agents. + * @property {string} [discoveryEndpoint] + */ + discoveryEndpoint?: string; + /** + * The callback URL for receiving A2A task updates. + * @property {string} [callbackUrl] + */ + callbackUrl?: string; + }; // Add other top-level configuration properties as needed, e.g.: // defaultThreadConfig?: Partial; +} + +/** + * Represents the possible states of an A2A (Agent-to-Agent) task. + * + * @enum {string} + */ +export enum A2ATaskStatus { + /** Task has been created but not yet assigned to an agent. */ + PENDING = 'PENDING', + /** Task has been assigned to an agent and is being processed. */ + IN_PROGRESS = 'IN_PROGRESS', + /** Task has been completed successfully. */ + COMPLETED = 'COMPLETED', + /** Task has failed during execution. */ + FAILED = 'FAILED', + /** Task has been cancelled before completion. */ + CANCELLED = 'CANCELLED', + /** Task is waiting for external dependencies or manual intervention. */ + WAITING = 'WAITING', + /** Task is being reviewed for quality assurance. */ + REVIEW = 'REVIEW' +} + +/** + * Represents the priority level of an A2A task. + * + * @enum {string} + */ +export enum A2ATaskPriority { + /** Low priority. */ + LOW = 'LOW', + /** Medium priority. */ + MEDIUM = 'MEDIUM', + /** High priority. */ + HIGH = 'HIGH', + /** Urgent priority. */ + URGENT = 'URGENT' +} + +/** + * Represents agent information for A2A task assignment. + * + * @interface A2AAgentInfo + */ +export interface A2AAgentInfo { + /** + * Unique identifier for the agent. + * @property {string} agentId + */ + agentId: string; + /** + * Human-readable name for the agent. + * @property {string} agentName + */ + agentName: string; + /** + * The type or role of the agent (e.g., 'reasoning', 'data-processing', 'synthesis'). + * @property {string} agentType + */ + agentType: string; + /** + * Base URL or endpoint for communicating with the agent. + * @property {string} [endpoint] + */ + endpoint?: string; + /** + * Agent capabilities or specializations. + * @property {string[]} [capabilities] + */ + capabilities?: string[]; + /** + * Current load or availability status of the agent. + * @property {'available' | 'busy' | 'offline'} [status] + */ + status?: 'available' | 'busy' | 'offline'; + /** + * Authentication configuration for communicating with the agent. + * @property {object} [authentication] + */ + authentication?: { + /** + * Type of authentication required. + * @property {'bearer' | 'api_key' | 'none'} type + */ + type: 'bearer' | 'api_key' | 'none'; + /** + * Bearer token for authorization (if type is 'bearer'). + * @property {string} [token] + */ + token?: string; + /** + * API key for authorization (if type is 'api_key'). + * @property {string} [apiKey] + */ + apiKey?: string; + }; +} + +/** + * Represents metadata about A2A task execution. + * + * @interface A2ATaskMetadata + */ +export interface A2ATaskMetadata { + /** + * Timestamp when the task was created (Unix timestamp in milliseconds). + * @property {number} createdAt + */ + createdAt: number; + /** + * Timestamp when the task was last updated (Unix timestamp in milliseconds). + * @property {number} updatedAt + */ + updatedAt: number; + /** + * Timestamp when the task was started (if applicable). + * @property {number} [startedAt] + */ + startedAt?: number; + /** + * Timestamp when the task was completed/failed (if applicable). + * @property {number} [completedAt] + */ + completedAt?: number; + /** + * Timestamp when the task was delegated to a remote agent (if applicable). + * @property {number} [delegatedAt] + */ + delegatedAt?: number; + /** + * Timestamp when the task was last updated (for compatibility). + * @property {number} [lastUpdated] + */ + lastUpdated?: number; + /** + * The user or system that initiated this task. + * @property {string} [initiatedBy] + */ + initiatedBy?: string; + /** + * Correlation ID for tracking related tasks across the system. + * @property {string} [correlationId] + */ + correlationId?: string; + /** + * Number of retry attempts made for this task. + * @property {number} [retryCount] + */ + retryCount?: number; + /** + * Maximum number of retry attempts allowed. + * @property {number} [maxRetries] + */ + maxRetries?: number; + /** + * Timeout duration in milliseconds. + * @property {number} [timeoutMs] + */ + timeoutMs?: number; + /** + * Estimated completion time in milliseconds (if provided by remote agent). + * @property {number} [estimatedCompletionMs] + */ + estimatedCompletionMs?: number; + /** + * Tags or labels for categorizing tasks. + * @property {string[]} [tags] + */ + tags?: string[]; +} + +/** + * Represents the result of an A2A task execution. + * + * @interface A2ATaskResult + */ +export interface A2ATaskResult { + /** + * Whether the task execution was successful. + * @property {boolean} success + */ + success: boolean; + /** + * The data returned by the task execution. + * @property {any} [data] + */ + data?: any; + /** + * Error message if the task failed. + * @property {string} [error] + */ + error?: string; + /** + * Additional metadata about the execution. + * @property {object} [metadata] + */ + metadata?: { + sources?: Array<{ + sourceName: string; + url?: string; + [key: string]: any; + }>; + [key: string]: any; + }; + /** + * Execution duration in milliseconds. + * @property {number} [durationMs] + */ + durationMs?: number; +} + +/** + * Represents a task for Agent-to-Agent (A2A) communication and delegation. + * Used for asynchronous task delegation between AI agents in distributed systems. + * + * @interface A2ATask + */ +export interface A2ATask { + /** + * Unique identifier for the task. + * @property {string} taskId + */ + taskId: string; + /** + * The thread this task belongs to (top-level for efficient filtering). + * @property {string} threadId + */ + threadId: string; + + /** + * Current status of the task. + * @property {A2ATaskStatus} status + */ + status: A2ATaskStatus; + + /** + * The data payload containing task parameters and context. + * @property {object} payload + */ + payload: { + /** + * The type of task to be executed (e.g., 'analyze', 'synthesize', 'transform'). + * @property {string} taskType + */ + taskType: string; + /** + * Input data required for task execution. + * @property {any} input + */ + input: any; + /** + * Instructions or configuration for the task. + * @property {string} [instructions] + */ + instructions?: string; + /** + * Additional parameters specific to the task type. + * @property {Record} [parameters] + */ + parameters?: Record; + }; + + /** + * Information about the agent that created/requested this task. + * @property {A2AAgentInfo} sourceAgent + */ + sourceAgent: A2AAgentInfo; + + /** + * Information about the agent assigned to execute this task (if assigned). + * @property {A2AAgentInfo} [targetAgent] + */ + targetAgent?: A2AAgentInfo; + + /** + * Task priority level. + * @property {A2ATaskPriority} priority + */ + priority: A2ATaskPriority; + + /** + * Task execution metadata. + * @property {A2ATaskMetadata} metadata + */ + metadata: A2ATaskMetadata; + + /** + * The result of task execution (if completed). + * @property {A2ATaskResult} [result] + */ + result?: A2ATaskResult; + + /** + * Callback URL or identifier for task completion notifications. + * @property {string} [callbackUrl] + */ + callbackUrl?: string; + + /** + * Dependencies that must be completed before this task can start. + * @property {string[]} [dependencies] + */ + dependencies?: string[]; +} + +/** + * Represents a request to create a new A2A task. + * + * @interface CreateA2ATaskRequest + */ +export interface CreateA2ATaskRequest { + /** + * The type of task to be executed. + * @property {string} taskType + */ + taskType: string; + /** + * Input data for the task. + * @property {any} input + */ + input: any; + /** + * Instructions for task execution. + * @property {string} [instructions] + */ + instructions?: string; + /** + * Task parameters. + * @property {Record} [parameters] + */ + parameters?: Record; + /** + * Task priority. + * @property {A2ATaskPriority} [priority] + */ + priority?: A2ATaskPriority; + /** + * Source agent information. + * @property {A2AAgentInfo} sourceAgent + */ + sourceAgent: A2AAgentInfo; + /** + * Preferred target agent (if any). + * @property {A2AAgentInfo} [preferredTargetAgent] + */ + preferredTargetAgent?: A2AAgentInfo; + /** + * Task dependencies. + * @property {string[]} [dependencies] + */ + dependencies?: string[]; + /** + * Callback URL for notifications. + * @property {string} [callbackUrl] + */ + callbackUrl?: string; + /** + * Task timeout in milliseconds. + * @property {number} [timeoutMs] + */ + timeoutMs?: number; + /** + * Maximum retry attempts. + * @property {number} [maxRetries] + */ + maxRetries?: number; + /** + * Task tags. + * @property {string[]} [tags] + */ + tags?: string[]; +} + +/** + * Represents an update to an existing A2A task. + * + * @interface UpdateA2ATaskRequest + */ +export interface UpdateA2ATaskRequest { + /** + * Task ID to update. + * @property {string} taskId + */ + taskId: string; + /** + * New task status (if changing). + * @property {A2ATaskStatus} [status] + */ + status?: A2ATaskStatus; + /** + * Target agent assignment (if assigning/reassigning). + * @property {A2AAgentInfo} [targetAgent] + */ + targetAgent?: A2AAgentInfo; + /** + * Task result (if completing). + * @property {A2ATaskResult} [result] + */ + result?: A2ATaskResult; + /** + * Additional metadata updates. + * @property {Partial} [metadata] + */ + metadata?: Partial; +} + +/** + * Defines the default identity and high-level guidance for an agent. + * This is provided at the instance level and can be overridden by thread or call-specific prompts. + * + * @interface AgentPersona + */ +export interface AgentPersona { + /** + * The name or identity of the agent (e.g., "Zoi"). + * This will be used in the synthesis prompt. + * @property {string} name + */ + name: string; + + /** + * The default system prompt that provides high-level guidance. + * This serves as the base layer in the system prompt resolution hierarchy. + * @property {string} defaultSystemPrompt + */ + prompts: StageSpecificPrompts; +} + +/** + * Defines stage-specific system prompts for planning and synthesis. + * + * @interface StageSpecificPrompts + */ +export interface StageSpecificPrompts { + /** + * System prompt to guide the planning phase. + * Focuses on reasoning, expertise, and tool selection. + * @property {string} [planning] + */ + planning?: string; + + /** + * System prompt to guide the synthesis phase. + * Focuses on tone, formatting, and final response structure. + * @property {string} [synthesis] + */ + synthesis?: string; } \ No newline at end of file diff --git a/src/types/providers.ts b/src/types/providers.ts old mode 100644 new mode 100755 index 207515e..559f245 --- a/src/types/providers.ts +++ b/src/types/providers.ts @@ -1,44 +1,116 @@ -import { ProviderAdapter } from '../core/interfaces'; +import { ProviderAdapter } from '@/core/interfaces'; -export { ProviderAdapter }; +export type { ProviderAdapter }; -/** Entry defining an available provider adapter */ +/** + * Entry defining an available provider adapter. + * + * @interface AvailableProviderEntry + */ export interface AvailableProviderEntry { - name: string; // Unique key, e.g., 'openai', 'anthropic', 'ollama_local' - adapter: new (options: any) => ProviderAdapter; // The adapter class - baseOptions?: any; // Optional base config (rarely needed if options are per-call) - isLocal?: boolean; // Default: false. Determines singleton vs. pooling behavior. + /** + * Unique key, e.g., 'openai', 'anthropic', 'ollama_local'. + * @property {string} name + */ + name: string; + /** + * The adapter class. + * @property {new (options: any) => ProviderAdapter} adapter + */ + adapter: new (options: any) => ProviderAdapter; + /** + * Optional base config (rarely needed if options are per-call). + * @property {any} [baseOptions] + */ + baseOptions?: any; + /** + * Default: false. Determines singleton vs. pooling behavior. + * @property {boolean} [isLocal] + */ + isLocal?: boolean; } -/** Configuration for the ProviderManager passed during ART initialization */ +/** + * Configuration for the ProviderManager passed during ART initialization. + * + * @interface ProviderManagerConfig + */ export interface ProviderManagerConfig { + /** + * @property {AvailableProviderEntry[]} availableProviders + */ availableProviders: AvailableProviderEntry[]; - /** Max concurrent ACTIVE instances per API-based provider NAME. Default: 5 */ + /** + * Max concurrent ACTIVE instances per API-based provider NAME. Default: 5. + * @property {number} [maxParallelApiInstancesPerProvider] + */ maxParallelApiInstancesPerProvider?: number; - /** Time in seconds an API adapter instance can be idle before being eligible for removal. Default: 300 */ + /** + * Time in seconds an API adapter instance can be idle before being eligible for removal. Default: 300. + * @property {number} [apiInstanceIdleTimeoutSeconds] + */ apiInstanceIdleTimeoutSeconds?: number; } -/** Configuration passed AT RUNTIME for a specific LLM call */ +/** + * Configuration passed AT RUNTIME for a specific LLM call. + * + * @interface RuntimeProviderConfig + */ export interface RuntimeProviderConfig { - providerName: string; // Must match a name in AvailableProviderEntry - modelId: string; // Specific model identifier (e.g., 'gpt-4o', 'llama3:latest') - adapterOptions: any; // Specific options for THIS instance (apiKey, temperature, contextSize, baseUrl, etc.) + /** + * Must match a name in AvailableProviderEntry. + * @property {string} providerName + */ + providerName: string; + /** + * Specific model identifier (e.g., 'gpt-4o', 'llama3:latest'). + * @property {string} modelId + */ + modelId: string; + /** + * Specific options for THIS instance (apiKey, temperature, contextSize, baseUrl, etc.). + * @property {any} adapterOptions + */ + adapterOptions: any; // modelName?: string; // Optional user-friendly name for logging } -/** Object returned by ProviderManager granting access to an adapter instance */ +/** + * Object returned by ProviderManager granting access to an adapter instance. + * + * @interface ManagedAdapterAccessor + */ export interface ManagedAdapterAccessor { - adapter: ProviderAdapter; // The ready-to-use adapter instance - /** Signals that the current call using this adapter instance is finished. */ + /** + * The ready-to-use adapter instance. + * @property {ProviderAdapter} adapter + */ + adapter: ProviderAdapter; + /** + * Signals that the current call using this adapter instance is finished. + * @property {() => void} release + */ release: () => void; } -/** Interface for the ProviderManager */ +/** + * Interface for the ProviderManager. + * + * @interface IProviderManager + */ export interface IProviderManager { - /** Returns identifiers for all registered potential providers */ + /** + * Returns identifiers for all registered potential providers. + * @returns {string[]} + */ getAvailableProviders(): string[]; /** * Gets a managed adapter instance based on the runtime config. + * + * @remarks * Handles instance creation, caching, pooling limits, and singleton constraints. * May queue requests or throw errors based on concurrency limits. + * + * @param {RuntimeProviderConfig} config + * @returns {Promise} */ getAdapter(config: RuntimeProviderConfig): Promise; diff --git a/src/types/schemas.ts b/src/types/schemas.ts old mode 100644 new mode 100755 index 9a39af0..68b960c --- a/src/types/schemas.ts +++ b/src/types/schemas.ts @@ -1,9 +1,22 @@ -// src/types/schemas.ts +/** + * @module types/schemas + * This module defines Zod schemas for validating the core data structures of the ART framework, + * ensuring type safety and data integrity at runtime. + */ import { z } from 'zod'; -import { ArtStandardMessageRole } from './index'; // Import role type from main types +import { ArtStandardMessageRole } from '@/types'; // Import role type from main types /** - * Zod schema for validating a single ArtStandardMessage object. + * Zod schema for validating a single {@link ArtStandardMessage} object. + * + * @remarks + * This schema enforces the structural and type requirements for each message, including: + * - A valid `role` from the {@link ArtStandardMessageRole} enum. + * - `content` that matches the expected type for a given role (e.g., string for 'user', string or null for 'assistant'). + * - The presence of `tool_call_id` for 'tool' or 'tool_result' roles. + * - The structure of `tool_calls` when present in an 'assistant' message. + * + * It uses a `.refine()` method to implement context-aware validation based on the message's `role`. */ export const ArtStandardMessageSchema = z.object({ role: z.custom((val) => { @@ -49,6 +62,10 @@ export const ArtStandardMessageSchema = z.object({ /** - * Zod schema for validating an entire ArtStandardPrompt (an array of messages). + * Zod schema for validating an entire {@link ArtStandardPrompt} (an array of messages). + * + * @remarks + * This is a straightforward array schema that applies the {@link ArtStandardMessageSchema} to each element, + * ensuring that every message in the prompt conforms to the required structure. */ export const ArtStandardPromptSchema = z.array(ArtStandardMessageSchema); \ No newline at end of file diff --git a/src/utils/logger.ts b/src/utils/logger.ts old mode 100644 new mode 100755 index afb93d3..472e94a --- a/src/utils/logger.ts +++ b/src/utils/logger.ts @@ -1,5 +1,13 @@ +/** + * @module utils/logger + * Provides a simple, static, and configurable logger for the ART framework. + * It supports different log levels and can be enabled or disabled globally. + */ + /** * Defines the available logging levels, ordered from most verbose to least verbose. + * + * @enum {number} */ export enum LogLevel { /** Detailed debugging information, useful for development. */ @@ -14,17 +22,29 @@ export enum LogLevel { /** * Configuration options for the static Logger class. + * + * @interface LoggerConfig */ export interface LoggerConfig { - /** The minimum log level to output messages for. Messages below this level will be ignored. */ + /** + * The minimum log level to output messages for. Messages below this level will be ignored. + * @property {LogLevel} level + */ level: LogLevel; - /** An optional prefix string to prepend to all log messages (e.g., '[MyApp]'). Defaults to '[ART]'. */ + /** + * An optional prefix string to prepend to all log messages (e.g., '[MyApp]'). Defaults to '[ART]'. + * @property {string} [prefix] + */ prefix?: string; } /** * A simple static logger class for outputting messages to the console at different levels. + * + * @remarks * Configuration is global via the static `configure` method. + * + * @class Logger */ export class Logger { private static config: LoggerConfig = { @@ -33,7 +53,8 @@ export class Logger { /** * Configures the static logger settings. - * @param config - A partial `LoggerConfig` object. Provided settings will override defaults. + * + * @param config A partial `LoggerConfig` object. Provided settings will override defaults. */ static configure(config: Partial): void { Logger.config = { ...Logger.config, ...config }; @@ -41,9 +62,12 @@ export class Logger { /** * Logs a message at the DEBUG level. + * + * @remarks * Only outputs if the configured log level is DEBUG. - * @param message - The main log message string. - * @param args - Additional arguments to include in the console output (e.g., objects, arrays). + * + * @param message The main log message string. + * @param args Additional arguments to include in the console output (e.g., objects, arrays). */ static debug(message: string, ...args: any[]): void { if (Logger.config.level <= LogLevel.DEBUG) { @@ -54,9 +78,12 @@ export class Logger { /** * Logs a message at the INFO level. + * + * @remarks * Outputs if the configured log level is INFO or DEBUG. - * @param message - The main log message string. - * @param args - Additional arguments to include in the console output. + * + * @param message The main log message string. + * @param args Additional arguments to include in the console output. */ static info(message: string, ...args: any[]): void { if (Logger.config.level <= LogLevel.INFO) { @@ -67,9 +94,12 @@ export class Logger { /** * Logs a message at the WARN level. + * + * @remarks * Outputs if the configured log level is WARN, INFO, or DEBUG. - * @param message - The main log message string. - * @param args - Additional arguments to include in the console output. + * + * @param message The main log message string. + * @param args Additional arguments to include in the console output. */ static warn(message: string, ...args: any[]): void { if (Logger.config.level <= LogLevel.WARN) { @@ -80,9 +110,12 @@ export class Logger { /** * Logs a message at the ERROR level. + * + * @remarks * Outputs if the configured log level is ERROR, WARN, INFO, or DEBUG. - * @param message - The main log message string. - * @param args - Additional arguments to include in the console output (often an error object). + * + * @param message The main log message string. + * @param args Additional arguments to include in the console output (often an error object). */ static error(message: string, ...args: any[]): void { if (Logger.config.level <= LogLevel.ERROR) { diff --git a/src/utils/uuid.ts b/src/utils/uuid.ts old mode 100644 new mode 100755 index 6e5e091..1cbc1eb --- a/src/utils/uuid.ts +++ b/src/utils/uuid.ts @@ -1,9 +1,18 @@ +/** + * @module utils/uuid + * Provides a utility function for generating Version 4 UUIDs. + */ import { v4 as uuidv4 } from 'uuid'; /** * Generates a unique Version 4 UUID (Universally Unique Identifier) string. + * + * @remarks * Uses the underlying 'uuid' library's v4 implementation. + * * @returns A randomly generated UUID string (e.g., "f47ac10b-58cc-4372-a567-0e02b2c3d479"). + * + * @see {@link https://www.npmjs.com/package/uuid | uuid npm package} */ export const generateUUID = (): string => { return uuidv4(); diff --git a/src/utils/validation.ts b/src/utils/validation.ts old mode 100644 new mode 100755 index 17ab020..e88a6c1 --- a/src/utils/validation.ts +++ b/src/utils/validation.ts @@ -1,6 +1,9 @@ -// src/utils/validation.ts -import Ajv, { ValidateFunction } from 'ajv'; -import { Logger } from './logger'; +/** + * @module utils/validation + * Provides a utility function for validating data against JSON schemas using the Ajv library. + */ +import Ajv, { ValidateFunction, ErrorObject } from 'ajv'; +import { Logger } from '@/utils/logger'; // Initialize Ajv // We can configure Ajv options here if needed (e.g., strict mode, allErrors) @@ -11,16 +14,24 @@ const compiledValidators: Map = new Map(); /** * Validates data against a given JSON schema using the Ajv library. + * + * @remarks * It caches compiled validation functions based on the schema's string representation * to improve performance for repeated validations against the same schema. * - * @param schema - The JSON schema object (`object` type assumed, adjust if other root types are needed) to validate against. - * @param data - The data object to be validated against the schema. - * @returns An object with two properties: - * - `isValid`: A boolean indicating whether the `data` conforms to the `schema`. - * - `errors`: If `isValid` is `false`, this contains an array of Ajv validation error objects (`ErrorObject[]`). If `isValid` is `true`, this is `null`. Returns a specific error object if schema compilation fails. + * @param schema - The JSON schema object to validate against. + * @param data - The data object to be validated. + * @returns An object containing the validation result. + * + * @example + * const schema = { type: 'object', properties: { name: { type: 'string' } }, required: ['name'] }; + * const validData = { name: 'ART' }; + * const invalidData = { name: 123 }; + * + * const { isValid, errors } = validateJsonSchema(schema, validData); // isValid: true, errors: null + * const { isValid: isInvalid, errors: errorDetails } = validateJsonSchema(schema, invalidData); // isInvalid: false, errors: [...] */ -export function validateJsonSchema(schema: object, data: any): { isValid: boolean; errors: ValidateFunction['errors'] | null } { +export function validateJsonSchema(schema: object, data: any): { isValid: boolean; errors: ErrorObject[] | null } { // Use a string representation of the schema as the cache key const schemaKey = JSON.stringify(schema); let validate: ValidateFunction; diff --git a/src/utils/xml-matcher.ts b/src/utils/xml-matcher.ts old mode 100644 new mode 100755 index d115343..638b822 --- a/src/utils/xml-matcher.ts +++ b/src/utils/xml-matcher.ts @@ -1,26 +1,45 @@ -// src/utils/xml-matcher.ts +/** + * @module utils/xml-matcher + * Provides a utility class for incrementally parsing and extracting content + * from XML-like text streams. It's designed to be robust against malformed or + * incomplete XML. + */ /** - * Represents a chunk of text processed by XmlMatcher, indicating whether + * Represents a chunk of text processed by {@link XmlMatcher}, indicating whether * it was part of the matched XML tag's content or outside of it. + * + * @interface XmlMatcherChunk */ export interface XmlMatcherChunk { - /** True if this chunk was inside the matched XML tag, false otherwise. */ + /** + * True if this chunk was inside the matched XML tag, false otherwise. + * @property {boolean} matched + */ matched: boolean; - /** The text content of this chunk. */ + /** + * The text content of this chunk. + * @property {string} data + */ data: string; } /** * A utility class to find and extract content within a specific XML tag from a stream of text. + * + * @remarks * It processes text chunks incrementally and yields segments, marking whether each segment * was inside or outside the specified XML tag. * - * Example: Given tagName 'think', and input "Some text this is a thought and more text.", - * it would yield: - * - { matched: false, data: "Some text " } - * - { matched: true, data: "this is a thought" } - * - { matched: false, data: " and more text." } + * @example + * // Given tagName 'think', and input "Some text this is a thought and more text.", + * // it would yield: + * // - { matched: false, data: "Some text " } + * // - { matched: true, data: "this is a thought" } + * // - { matched: false, data: " and more text." } + * + * @class XmlMatcher + * @template Result - The type of the transformed chunk, defaults to {@link XmlMatcherChunk}. */ export class XmlMatcher { private index = 0; @@ -32,14 +51,13 @@ export class XmlMatcher { /** * Constructs an XmlMatcher. + * * @param tagName The name of the XML tag to match (e.g., "think"). - * @param transform An optional function to transform the yielded XmlMatcherChunk into a custom Result type. + * @param transform An optional function to transform the yielded {@link XmlMatcherChunk} into a custom Result type. * @param position The character position in the input stream at which matching should begin. * If 0, matching starts immediately. If greater than 0, characters before this * position are treated as unmatched text until the tag is encountered at or after * this position. This is useful if the tag is expected after some preamble. - * The example code had `this.pointer <= this.position + 1 || this.matched` - * which implies matching can start if we are at/before the desired start position OR if we are already in a matched state. */ constructor( readonly tagName: string, @@ -92,6 +110,7 @@ export class XmlMatcher { /** * Processes an incoming chunk of text. + * * @param chunk The text chunk to process. * @returns An array of transformed results based on the matched segments. */ @@ -175,6 +194,7 @@ export class XmlMatcher { /** * Finalizes processing, flushing any remaining buffered text. + * * @param chunk An optional final text chunk to process. * @returns An array of transformed results. */ diff --git a/test/gemini.thinking.test.ts b/test/gemini.thinking.test.ts new file mode 100644 index 0000000..b90d4ff --- /dev/null +++ b/test/gemini.thinking.test.ts @@ -0,0 +1,139 @@ +import { describe, it, expect } from 'vitest'; +import { GeminiAdapter } from '../src/integrations/reasoning/gemini'; +import type { ArtStandardPrompt, CallOptions, RuntimeProviderConfig, StreamEvent } from '../src/types'; + +// Simple streaming test for Gemini thinking tokens capture. +// Requires environment variable GEMINI_API_KEY to be set. + +const GEMINI_API_KEY = 'add-the-api-key-here'; +// Use a model that supports thinking +const GEMINI_MODEL = 'gemini-2.5-flash'; + +// Skip test if no API key is available +const maybeDescribe = GEMINI_API_KEY ? describe : describe.skip; + +maybeDescribe('GeminiAdapter thinking tokens (integration)', () => { + it('streams tokens and reports whether thought tokens are observed', async () => { + const adapter = new GeminiAdapter({ apiKey: GEMINI_API_KEY!, model: GEMINI_MODEL }); + + const prompt: ArtStandardPrompt = [ + { role: 'user', content: 'write a short story about a cat' } + ]; + + const providerConfig: RuntimeProviderConfig = { + providerName: 'gemini', + modelId: GEMINI_MODEL, + adapterOptions: { apiKey: 'hidden' }, + }; + + const options: CallOptions = { + threadId: `test-thread-${Date.now()}`, + traceId: `test-trace-${Date.now()}`, + sessionId: 'test-session', + stream: true, + callContext: 'FINAL_SYNTHESIS', + providerConfig, + // Enable thinking capture in adapter + gemini: { + thinking: { includeThoughts: true, thinkingBudget: 256 } + } + } as any; + + const stream = await adapter.call(prompt, options); + + const events: StreamEvent[] = []; + let tokens = 0; + let thinkingTokens = 0; + let responseTokens = 0; + let hadError: Error | null = null; + + try { + for await (const evt of stream) { + events.push(evt); + if (evt.type === 'TOKEN') { + tokens += 1; + // Print each streamed token with tokenType for inspection + // eslint-disable-next-line no-console + console.log(`[TOKEN ${tokens}] type=${evt.tokenType ?? 'UNKNOWN'} len=${(evt.data ?? '').length}`); + // eslint-disable-next-line no-console + console.log(evt.data); + if (evt.tokenType && String(evt.tokenType).includes('THINKING')) thinkingTokens += 1; + if (evt.tokenType && String(evt.tokenType).includes('RESPONSE')) responseTokens += 1; + } else if (evt.type === 'ERROR') { + hadError = evt.data instanceof Error ? evt.data : new Error(String(evt.data)); + } + } + } catch (err: any) { + hadError = err instanceof Error ? err : new Error(String(err)); + } + + // Console diagnostics to inspect actual provider behavior + // eslint-disable-next-line no-console + console.log('[GeminiAdapter Test] token summary:', { tokens, thinkingTokens, responseTokens }); + const metadataEvt = events.find(e => e.type === 'METADATA'); + // eslint-disable-next-line no-console + console.log('[GeminiAdapter Test] metadata:', metadataEvt?.data); + + expect(hadError).toBeNull(); + expect(tokens).toBeGreaterThan(0); + // Do not assert on thinkingTokens strictly, since provider/model may not return thoughts in all cases + // eslint-disable-next-line no-console + console.log('[GeminiAdapter Test] observed thinking tokens?', thinkingTokens > 0); + }, 60000); + + it('streams planning (AGENT_THOUGHT) tokens and logs thought tokens', async () => { + const adapter = new GeminiAdapter({ apiKey: GEMINI_API_KEY!, model: GEMINI_MODEL }); + + const prompt: ArtStandardPrompt = [ + { role: 'user', content: 'You are planning a research approach to compare two algorithms for sorting large datasets. Think step by step about experiment design, metrics, datasets, and pitfalls. Do not produce a final user answer; focus on internal planning thoughts.' } + ]; + + const providerConfig: RuntimeProviderConfig = { + providerName: 'gemini', + modelId: GEMINI_MODEL, + adapterOptions: { apiKey: 'hidden' }, + }; + + const options: CallOptions = { + threadId: `test-thread-${Date.now()}`, + traceId: `test-trace-${Date.now()}`, + sessionId: 'test-session', + stream: true, + callContext: 'AGENT_THOUGHT', + providerConfig, + gemini: { + thinking: { includeThoughts: true, thinkingBudget: 8096 } + } + } as any; + + const stream = await adapter.call(prompt, options); + + let tokens = 0; + let thinkingTokens = 0; + let responseTokens = 0; + let hadError: Error | null = null; + + try { + for await (const evt of stream) { + if (evt.type === 'TOKEN') { + tokens += 1; + // eslint-disable-next-line no-console + console.log(`[PLANNING TOKEN ${tokens}] type=${evt.tokenType ?? 'UNKNOWN'} len=${(evt.data ?? '').length}`); + // eslint-disable-next-line no-console + console.log(evt.data); + if (evt.tokenType && String(evt.tokenType).includes('THINKING')) thinkingTokens += 1; + if (evt.tokenType && String(evt.tokenType).includes('RESPONSE')) responseTokens += 1; + } else if (evt.type === 'ERROR') { + hadError = evt.data instanceof Error ? evt.data : new Error(String(evt.data)); + } + } + } catch (err: any) { + hadError = err instanceof Error ? err : new Error(String(err)); + } + + // eslint-disable-next-line no-console + console.log('[GeminiAdapter Planning Test] token summary:', { tokens, thinkingTokens, responseTokens }); + expect(hadError).toBeNull(); + expect(tokens).toBeGreaterThan(0); + }, 60000); +}); diff --git a/tsconfig.json b/tsconfig.json old mode 100644 new mode 100755 index 4aef4a6..666f611 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,8 +1,8 @@ { "compilerOptions": { - "target": "ESNext", + "target": "ES2020", "module": "ESNext", - "lib": ["ESNext", "DOM"], + "lib": ["ES2020", "DOM"], "moduleResolution": "bundler", "strict": true, "sourceMap": true, @@ -10,6 +10,7 @@ "declarationMap": true, "esModuleInterop": true, "skipLibCheck": true, + "allowSyntheticDefaultImports": true, "paths": { "@/*": ["./src/*"] }, diff --git a/tsup.config.ts b/tsup.config.ts old mode 100644 new mode 100755 diff --git a/typedoc.html.json b/typedoc.html.json new file mode 100644 index 0000000..28f1cbd --- /dev/null +++ b/typedoc.html.json @@ -0,0 +1,13 @@ +{ + "$schema": "https://typedoc.org/schema.json", + "entryPoints": ["src/index.ts"], + "out": "docs/components", + "name": "ART Framework API Docs", + "readme": "README.md", + "excludePrivate": true, + "excludeProtected": true, + "excludeExternals": true, + "theme": "default" +} + + diff --git a/typedoc.json b/typedoc.json old mode 100644 new mode 100755 index 6b000ad..ecaedfa --- a/typedoc.json +++ b/typedoc.json @@ -1,8 +1,8 @@ { "$schema": "https://typedoc.org/schema.json", "entryPoints": ["src/index.ts"], - "out": "Docs/API", - "name": "ART Framework API Reference", + "out": "docs/components", + "name": "ART Framework Component Reference", "readme": "none", "excludePrivate": true, "excludeProtected": true, diff --git a/vitest.config.ts b/vitest.config.ts new file mode 100644 index 0000000..654ce1b --- /dev/null +++ b/vitest.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from 'vitest/config'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __filename = fileURLToPath(import.meta.url); +const __dirname = path.dirname(__filename); + +export default defineConfig({ + test: { + environment: 'node', + include: ['test/**/*.test.ts'], + }, + resolve: { + alias: { + '@': path.resolve(__dirname, 'src'), + }, + }, +}); + +