Refactor ag-ui-research. Drop human-in-the-loop, use MemoryObjectSendStream to merge the graph and agent streams together
This commit is contained in:
parent
4a623934b2
commit
2c43f034de
16 changed files with 12671 additions and 14635 deletions
|
|
@ -21,6 +21,12 @@
|
||||||
- **CLI AG-UI Flag**: New `--agui` flag for `serve` command to start AG-UI server
|
- **CLI AG-UI Flag**: New `--agui` flag for `serve` command to start AG-UI server
|
||||||
- **Graph Module**: New unified `haiku.rag.graph` module containing all graph-related functionality
|
- **Graph Module**: New unified `haiku.rag.graph` module containing all graph-related functionality
|
||||||
- **Common Graph Nodes**: New factory functions (`create_plan_node`, `create_search_node`) in `haiku.rag.graph.common.nodes` for reusable graph components
|
- **Common Graph Nodes**: New factory functions (`create_plan_node`, `create_search_node`) in `haiku.rag.graph.common.nodes` for reusable graph components
|
||||||
|
- **AG-UI Research Example**: New full-stack example (`examples/ag-ui-research`) demonstrating agent+graph architecture with CopilotKit frontend
|
||||||
|
- Pydantic AI agent with research tool that invokes the research graph
|
||||||
|
- Custom AG-UI streaming endpoint with anyio memory streams
|
||||||
|
- React/Next.js frontend with split-pane UI showing live research state
|
||||||
|
- Real-time progress tracking of questions, answers, insights, and gaps
|
||||||
|
- Docker Compose setup for easy local development
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,11 @@
|
||||||
# Must be an absolute path to an existing database created with haiku-rag
|
# Must be an absolute path to an existing database created with haiku-rag
|
||||||
DB_PATH=/absolute/path/to/your/haiku.rag.lancedb
|
DB_PATH=/absolute/path/to/your/haiku.rag.lancedb
|
||||||
|
|
||||||
|
# Ollama API base URL (if using Ollama for local models)
|
||||||
|
# If running Ollama on your host machine, use your machine's IP address
|
||||||
|
# that the Docker container can reach (not localhost)
|
||||||
|
OLLAMA_BASE_URL=http://host.docker.internal:11434
|
||||||
|
|
||||||
# API keys (set as needed for your QA provider)
|
# API keys (set as needed for your QA provider)
|
||||||
# OPENAI_API_KEY=your-key-here
|
# OPENAI_API_KEY=your-key-here
|
||||||
# ANTHROPIC_API_KEY=your-key-here
|
# ANTHROPIC_API_KEY=your-key-here
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,16 @@
|
||||||
# Interactive Research Assistant
|
# Interactive Research Assistant
|
||||||
|
|
||||||
Research assistant powered by [haiku.rag](https://ggozad.github.io/haiku.rag/), [Pydantic AI](https://ai.pydantic.dev/), and [AG-UI](https://docs.ag-ui.com/). Ask complex questions and watch the research process unfold in real-time.
|
Research assistant powered by [haiku.rag](https://ggozad.github.io/haiku.rag/), [Pydantic Graph](https://ai.pydantic.dev/graph/), and [AG-UI](https://docs.ag-ui.com/). Ask complex questions and watch the research process unfold in real-time.
|
||||||
|
|
||||||
[Watch demo video](https://vimeo.com/1128874386)
|
[Watch demo video](https://vimeo.com/1128874386)
|
||||||
|
|
||||||
## Features
|
## Features
|
||||||
|
|
||||||
- **Multi-step research workflow**: Question decomposition, search, analysis, and synthesis
|
- **Multi-iteration research graph**: Automated question decomposition, search, insight extraction, and gap analysis
|
||||||
- **Human-in-the-loop**: Approve or revise research plans before execution
|
- **Intelligent evaluation**: Confidence-based decision making with automatic iteration until sufficient information is gathered
|
||||||
- **Live state synchronization**: Real-time updates of research progress between backend and frontend
|
- **Live state synchronization**: Real-time delta updates of research progress via AG-UI protocol
|
||||||
- **Context expansion**: Automatically expands top search results for better context
|
- **Insight & gap tracking**: Structured insights with provenance and automatic gap identification
|
||||||
- **Rich reporting**: Generates structured reports with findings, conclusions, and citations
|
- **Rich reporting**: Generates comprehensive research reports with findings, conclusions, and sources
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
|
|
@ -57,32 +57,67 @@ Research assistant powered by [haiku.rag](https://ggozad.github.io/haiku.rag/),
|
||||||
## How It Works
|
## How It Works
|
||||||
|
|
||||||
1. **Ask a question**: Type your research question in the chat
|
1. **Ask a question**: Type your research question in the chat
|
||||||
2. **Review the plan**: The agent decomposes your question into 3 sub-questions
|
2. **Plan phase**: The research graph automatically:
|
||||||
3. **Approve or revise**: Choose to approve the plan or request changes
|
- Decomposes your question into targeted sub-questions
|
||||||
4. **Watch it work**: The agent automatically:
|
- Gathers initial context about the topic
|
||||||
- Searches the knowledge base for each sub-question
|
3. **Research iterations**: The graph autonomously:
|
||||||
- Extracts key insights from search results
|
- Searches the knowledge base for each sub-question in parallel
|
||||||
- Evaluates overall confidence in findings
|
- Extracts structured insights with source provenance
|
||||||
5. **Get your report**: Receive a structured research report with citations
|
- Identifies information gaps and assesses confidence
|
||||||
|
- Generates new follow-up questions for gaps
|
||||||
|
- Iterates until confidence threshold is met or max iterations reached
|
||||||
|
4. **Synthesis**: Generates a comprehensive research report with:
|
||||||
|
- Executive summary
|
||||||
|
- Main findings with supporting evidence
|
||||||
|
- Conclusions and recommendations
|
||||||
|
- Source citations
|
||||||
|
|
||||||
## Architecture
|
## Architecture
|
||||||
|
|
||||||
- **Backend** (Python): Pydantic AI agent with haiku.rag integration
|
### Agent + Graph Pattern
|
||||||
- Uses published `ghcr.io/ggozad/haiku.rag:latest` Docker image as base
|
|
||||||
- `agent.py`: Research agent with tool definitions
|
|
||||||
- `main.py`: Starlette app serving AG-UI protocol
|
|
||||||
|
|
||||||
- **Frontend** (Next.js): CopilotKit/AG-UI interface
|
This example demonstrates the **agent+graph** architecture pattern:
|
||||||
- Real-time state synchronization with backend
|
|
||||||
- Interactive approval workflow
|
1. **Conversational Agent** (`agent.py`):
|
||||||
- Collapsible research plan and insights display
|
- Pydantic AI agent handles user conversations
|
||||||
|
- Decides when to invoke the research tool based on user intent
|
||||||
|
- Responds directly to greetings/casual chat without tools
|
||||||
|
- Formats research results for the user
|
||||||
|
|
||||||
|
2. **Research Graph** (haiku.rag):
|
||||||
|
- Multi-step research workflow invoked by the agent's tool
|
||||||
|
- Autonomous execution with plan → search → analyze → decide → synthesize flow
|
||||||
|
- Emits AG-UI events for real-time progress tracking
|
||||||
|
|
||||||
|
3. **Shared Event Stream**:
|
||||||
|
- `AGUIEmitter` is shared between agent and graph
|
||||||
|
- Events from both flow through a single stream to the frontend
|
||||||
|
- Custom streaming endpoint (`main.py`) uses anyio memory streams for proper async handling
|
||||||
|
|
||||||
|
### Components
|
||||||
|
|
||||||
|
- **Backend** (Python):
|
||||||
|
- Uses published `ghcr.io/ggozad/haiku.rag:latest` Docker image as base
|
||||||
|
- `agent.py`: Pydantic AI agent with `run_research` tool
|
||||||
|
- `main.py`: Custom AG-UI streaming endpoint with anyio memory object streams
|
||||||
|
- Real-time event forwarding from emitter to SSE stream
|
||||||
|
- Filters out `ACTIVITY_SNAPSHOT` events (not yet supported by CopilotKit)
|
||||||
|
|
||||||
|
- **Frontend** (Next.js/React):
|
||||||
|
- CopilotKit for AG-UI protocol integration
|
||||||
|
- Split-pane UI: chat on left, live research state on right
|
||||||
|
- Real-time state synchronization via Server-Sent Events (SSE)
|
||||||
|
- `StateDisplay` component with collapsible sections for questions, insights, and gaps
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Configuration is done through `haiku.rag.yaml` (see `haiku.rag.yaml.example`):
|
Configuration is done through `haiku.rag.yaml` (see `haiku.rag.yaml.example`):
|
||||||
|
|
||||||
- `qa.provider`: LLM provider (default: `ollama`)
|
- `research.provider`: LLM provider (default: `ollama`)
|
||||||
- `qa.model`: Model name (default: `gpt-oss:latest`)
|
- `research.model`: Model name (default: `gpt-oss:latest`)
|
||||||
|
- `research.max_iterations`: Maximum research iterations (default: `3`)
|
||||||
|
- `research.confidence_threshold`: Confidence threshold for completion (default: `0.8`)
|
||||||
|
- `research.max_concurrency`: Parallel sub-question processing (default: `1`)
|
||||||
- `providers.ollama.base_url`: Ollama endpoint (default: `http://host.docker.internal:11434`)
|
- `providers.ollama.base_url`: Ollama endpoint (default: `http://host.docker.internal:11434`)
|
||||||
|
|
||||||
Environment variables (see `.env.example`):
|
Environment variables (see `.env.example`):
|
||||||
|
|
|
||||||
|
|
@ -3,15 +3,13 @@ FROM ghcr.io/ggozad/haiku.rag:latest
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
# Copy backend application files
|
# Copy backend application files
|
||||||
COPY agent.py main.py ./
|
COPY main.py agent.py ./
|
||||||
COPY pyproject.toml ./
|
|
||||||
|
|
||||||
# Install backend dependencies
|
# Install additional dependencies for the example
|
||||||
# Note: haiku-rag is already installed in the base image
|
# Note: haiku-rag-slim is already installed in the base image
|
||||||
RUN pip install --no-cache-dir \
|
RUN pip install --no-cache-dir \
|
||||||
starlette>=0.45.2 \
|
starlette>=0.45.2 \
|
||||||
uvicorn[standard]>=0.34.2 \
|
uvicorn[standard]>=0.34.2 \
|
||||||
pydantic-ai-slim[ag-ui,openai]>=1.1.0 \
|
|
||||||
python-dotenv>=1.0.1
|
python-dotenv>=1.0.1
|
||||||
|
|
||||||
EXPOSE 8000
|
EXPOSE 8000
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
# Haiku.rag Research Assistant Backend
|
# Haiku.rag Research Assistant Backend
|
||||||
|
|
||||||
FastAPI backend for the haiku.rag interactive research assistant, using Pydantic AI with AG-UI protocol support.
|
Starlette backend for the haiku.rag interactive research assistant, using the research graph with AG-UI protocol support.
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
|
|
@ -11,7 +11,17 @@ uv run python main.py
|
||||||
|
|
||||||
The server starts on `http://localhost:8000` and uses [haiku.rag configuration](https://ggozad.github.io/haiku.rag/configuration/).
|
The server starts on `http://localhost:8000` and uses [haiku.rag configuration](https://ggozad.github.io/haiku.rag/configuration/).
|
||||||
|
|
||||||
|
## Architecture
|
||||||
|
|
||||||
|
The backend uses `create_agui_server()` from `haiku.rag.graph.agui.server` which provides:
|
||||||
|
|
||||||
|
- **Research graph execution**: Multi-iteration research workflow with insight/gap tracking
|
||||||
|
- **AG-UI protocol**: Server-Sent Events (SSE) streaming for real-time state updates
|
||||||
|
- **Delta state updates**: Efficient incremental state synchronization using JSON Patch operations
|
||||||
|
- **Both research and deep_qa endpoints**: `/agent/research` and `/agent/deep_qa`
|
||||||
|
|
||||||
## Endpoints
|
## Endpoints
|
||||||
|
|
||||||
- `GET /health` - Health check
|
- `GET /health` - Health check with configuration info
|
||||||
- `POST /agent` - AG-UI protocol endpoint
|
- `POST /agent/research/stream` - Research graph streaming endpoint (AG-UI protocol)
|
||||||
|
- `POST /agent/deep_qa/stream` - Deep QA graph streaming endpoint (AG-UI protocol)
|
||||||
|
|
|
||||||
|
|
@ -1,432 +1,111 @@
|
||||||
import json
|
"""Research assistant agent with graph integration."""
|
||||||
from dataclasses import dataclass
|
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import TYPE_CHECKING
|
||||||
|
|
||||||
from ag_ui.core import EventType, StateSnapshotEvent
|
|
||||||
from pydantic import BaseModel
|
|
||||||
from pydantic_ai import Agent, RunContext
|
from pydantic_ai import Agent, RunContext
|
||||||
from pydantic_ai.ag_ui import StateDeps
|
|
||||||
|
|
||||||
from haiku.rag.client import HaikuRAG
|
from haiku.rag.client import HaikuRAG
|
||||||
from haiku.rag.config import Config
|
from haiku.rag.config import load_yaml_config
|
||||||
|
from haiku.rag.config.models import AppConfig
|
||||||
from haiku.rag.graph.common import get_model
|
from haiku.rag.graph.common import get_model
|
||||||
|
from haiku.rag.graph.research.dependencies import ResearchContext
|
||||||
|
from haiku.rag.graph.research.graph import build_research_graph
|
||||||
|
from haiku.rag.graph.research.state import ResearchDeps, ResearchState
|
||||||
|
|
||||||
|
if TYPE_CHECKING:
|
||||||
|
from haiku.rag.graph.agui.emitter import AGUIEmitter
|
||||||
|
from haiku.rag.graph.research.models import ResearchReport
|
||||||
|
|
||||||
class ResearchState(BaseModel):
|
# Load config
|
||||||
"""Shared state between research agent and frontend."""
|
config_path = Path("/app/haiku.rag.yaml")
|
||||||
|
Config = (
|
||||||
question: str = ""
|
AppConfig.model_validate(load_yaml_config(config_path))
|
||||||
phase: str = "idle"
|
if config_path.exists()
|
||||||
status: str = ""
|
else AppConfig()
|
||||||
plan: list[dict] = []
|
)
|
||||||
current_question_index: int = 0
|
|
||||||
insights: list[dict] = []
|
|
||||||
document_registry: dict[str, dict] = {}
|
|
||||||
current_document: dict | None = None
|
|
||||||
confidence: float = 0.0
|
|
||||||
final_report: dict | None = None
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class ResearchDeps(StateDeps[ResearchState]):
|
class AgentDeps:
|
||||||
"""Dependencies for the research agent with HaikuRAG client."""
|
"""Dependencies for research agent."""
|
||||||
|
|
||||||
client: HaikuRAG
|
client: HaikuRAG
|
||||||
|
agui_emitter: "AGUIEmitter[ResearchState, ResearchReport] | None" = None
|
||||||
|
|
||||||
|
|
||||||
def _as_state_snapshot(ctx: RunContext[ResearchDeps]) -> StateSnapshotEvent:
|
model = get_model(Config.research.provider, Config.research.model)
|
||||||
return StateSnapshotEvent(type=EventType.STATE_SNAPSHOT, snapshot=ctx.deps.state)
|
|
||||||
|
|
||||||
|
|
||||||
def create_agent(
|
|
||||||
qa_provider: str = Config.qa.provider, qa_model: str = Config.qa.model
|
|
||||||
) -> Agent[ResearchDeps, str]:
|
|
||||||
"""Create and configure the research agent.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
qa_provider: QA provider for the agent (default: from Config.qa.provider)
|
|
||||||
qa_model: Model name to use (default: from Config.qa.model)
|
|
||||||
"""
|
|
||||||
print(f"[AGENT SETUP] Creating agent with provider={qa_provider}, model={qa_model}")
|
|
||||||
agent = Agent(
|
agent = Agent(
|
||||||
model=get_model(qa_provider, qa_model),
|
model,
|
||||||
deps_type=ResearchDeps,
|
deps_type=AgentDeps,
|
||||||
instructions="""You are a research co-pilot powered by haiku.rag.
|
system_prompt="""You are an advanced research assistant powered by haiku.rag.
|
||||||
|
|
||||||
Your workflow MUST follow these exact steps in order:
|
|
||||||
1. Call propose_research_plan with the user's question
|
|
||||||
2. After propose_research_plan completes, IMMEDIATELY call approve_research_plan (with no arguments)
|
|
||||||
3. WAIT for approve_research_plan to return:
|
|
||||||
- If it returns "APPROVED", proceed to step 4
|
|
||||||
- If it returns "REVISE", ask the user "How would you like me to revise the research plan?" and wait for their response
|
|
||||||
- Once you receive their revision feedback, revise the plan and go back to step 1
|
|
||||||
4. Once approved, process questions ONE AT A TIME:
|
|
||||||
- Call search_question(question_id=0) and WAIT for it to complete
|
|
||||||
- Then call extract_insights_from_results(question_id=0) and WAIT for it to complete
|
|
||||||
- Then call search_question(question_id=1) and WAIT for it to complete
|
|
||||||
- Then call extract_insights_from_results(question_id=1) and WAIT for it to complete
|
|
||||||
- Then call search_question(question_id=2) and WAIT for it to complete
|
|
||||||
- Then call extract_insights_from_results(question_id=2) and WAIT for it to complete
|
|
||||||
5. After all questions are processed, call evaluate_research_confidence
|
|
||||||
6. Ask user if they want to finalize or continue researching
|
|
||||||
7. When user approves, call synthesize_final_report
|
|
||||||
|
|
||||||
CRITICAL RULES:
|
CRITICAL RULES:
|
||||||
- MANDATORY: Call approve_research_plan immediately after propose_research_plan - NO EXCEPTIONS
|
1. For greetings (hi, hello, hey, etc) or casual chat: respond directly WITHOUT using any tools
|
||||||
- If approve_research_plan returns "REVISE", ask the user for revision feedback naturally in chat
|
2. For questions about yourself or the system: respond directly WITHOUT using any tools
|
||||||
- Call ONE tool at a time - wait for each tool to return before calling the next
|
3. For substantive questions requiring information: ALWAYS use the run_research tool
|
||||||
- NEVER call extract_insights_from_results until search_question has completed and returned results
|
4. NEVER answer substantive questions from your own knowledge - always use the tool
|
||||||
- DO NOT explain what you're about to do - just call the tool
|
|
||||||
- The state updates will show the user what's happening - you don't need to narrate
|
|
||||||
- Process all 3 questions automatically without asking for approval between them
|
|
||||||
|
|
||||||
Document Viewing:
|
How to decide:
|
||||||
- When user asks to "show document X", call get_full_document with the document_uri
|
- "Hi" / "Hello" / "How are you?" → Respond directly, NO tools
|
||||||
|
- "What can you do?" → Respond directly, NO tools
|
||||||
|
- "How does X work in the codebase?" → Use run_research tool
|
||||||
|
- "Tell me about Y" → Use run_research tool
|
||||||
|
|
||||||
Remember: Call tools ONE AT A TIME in sequence. Each tool must complete before calling the next.
|
When you use run_research, the graph will decompose questions, search the knowledge base,
|
||||||
""",
|
extract insights, and generate a comprehensive report.
|
||||||
|
|
||||||
|
Be friendly and conversational in all responses.""",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@agent.tool
|
@agent.tool
|
||||||
async def propose_research_plan(
|
async def run_research(ctx: RunContext[AgentDeps], question: str) -> str:
|
||||||
ctx: RunContext[ResearchDeps], question: str
|
"""Execute research graph on a substantive question.
|
||||||
) -> StateSnapshotEvent:
|
|
||||||
"""Propose a research plan by decomposing the question into sub-questions."""
|
|
||||||
ctx.deps.state.question = question
|
|
||||||
ctx.deps.state.phase = "planning"
|
|
||||||
ctx.deps.state.status = "Decomposing question into sub-questions..."
|
|
||||||
|
|
||||||
decompose_prompt = f"""Break down this research question into exactly 3 specific sub-questions that would help answer it comprehensively.
|
Use for questions requiring knowledge base search.
|
||||||
|
DO NOT use for greetings or casual conversation.
|
||||||
|
"""
|
||||||
|
if ctx.deps.agui_emitter:
|
||||||
|
ctx.deps.agui_emitter.log(f"🔍 Starting research on: {question}")
|
||||||
|
|
||||||
Research Question: {question}
|
graph = build_research_graph(Config)
|
||||||
|
context = ResearchContext(original_question=question)
|
||||||
|
state = ResearchState.from_config(context=context, config=Config)
|
||||||
|
|
||||||
Return ONLY a JSON array of sub-questions, like: ["Question 1?", "Question 2?", "Question 3?"]"""
|
graph_deps = ResearchDeps(
|
||||||
|
client=ctx.deps.client,
|
||||||
response = await ctx.deps.client.ask(decompose_prompt)
|
agui_emitter=ctx.deps.agui_emitter,
|
||||||
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
sub_questions = json.loads(response)
|
result = await graph.run(state=state, deps=graph_deps)
|
||||||
except json.JSONDecodeError:
|
|
||||||
sub_questions = [
|
|
||||||
q.strip().lstrip("0123456789.-) ")
|
|
||||||
for q in response.split("\n")
|
|
||||||
if q.strip()
|
|
||||||
][:3]
|
|
||||||
|
|
||||||
plan = [
|
if ctx.deps.agui_emitter:
|
||||||
{"id": i, "question": q, "status": "pending"}
|
ctx.deps.agui_emitter.log("✅ Research complete!")
|
||||||
for i, q in enumerate(sub_questions)
|
|
||||||
]
|
|
||||||
|
|
||||||
ctx.deps.state.plan = plan
|
return f"""Research completed successfully!
|
||||||
ctx.deps.state.current_question_index = 0
|
|
||||||
ctx.deps.state.status = f"Proposed plan with {len(plan)} sub-questions"
|
|
||||||
|
|
||||||
return _as_state_snapshot(ctx)
|
Question: {question}
|
||||||
|
|
||||||
@agent.tool
|
Executive Summary: {result.executive_summary}
|
||||||
async def search_question(
|
|
||||||
ctx: RunContext[ResearchDeps],
|
|
||||||
question_id: int,
|
|
||||||
search_type: str = "hybrid",
|
|
||||||
) -> StateSnapshotEvent:
|
|
||||||
"""Execute search for a specific sub-question."""
|
|
||||||
plan = ctx.deps.state.plan
|
|
||||||
if question_id >= len(plan):
|
|
||||||
raise ValueError(f"Question ID {question_id} not found in plan")
|
|
||||||
|
|
||||||
question = plan[question_id]["question"]
|
Main Findings:
|
||||||
ctx.deps.state.phase = "searching"
|
{chr(10).join(f"- {finding}" for finding in result.main_findings[:3])}
|
||||||
ctx.deps.state.current_question_index = question_id
|
|
||||||
ctx.deps.state.status = f"Searching: {question}"
|
|
||||||
plan[question_id]["status"] = "searching"
|
|
||||||
|
|
||||||
search_results = await ctx.deps.client.search(
|
Conclusions:
|
||||||
question, limit=5, search_type=search_type
|
{chr(10).join(f"- {conclusion}" for conclusion in result.conclusions[:2])}
|
||||||
)
|
|
||||||
|
|
||||||
expanded_map = {}
|
Total insights gathered: {len(state.context.insights)}
|
||||||
if search_results:
|
Confidence: {f"{state.last_eval.confidence_score:.0%}" if state.last_eval else "N/A"}
|
||||||
expanded_results = await ctx.deps.client.expand_context(
|
Iterations completed: {state.iterations}
|
||||||
search_results[:3], radius=2
|
|
||||||
)
|
|
||||||
expanded_map = {
|
|
||||||
chunk.id: (chunk, score) for chunk, score in expanded_results
|
|
||||||
}
|
|
||||||
|
|
||||||
results = []
|
The full research report with all citations has been provided to the user.
|
||||||
for chunk, score in search_results:
|
"""
|
||||||
doc_uri = chunk.document_uri or "unknown"
|
|
||||||
doc_title = chunk.document_title or chunk.document_uri or "Unknown"
|
|
||||||
|
|
||||||
if doc_uri not in ctx.deps.state.document_registry:
|
except Exception as e:
|
||||||
ctx.deps.state.document_registry[doc_uri] = {
|
if ctx.deps.agui_emitter:
|
||||||
"title": doc_title,
|
ctx.deps.agui_emitter.log(f"❌ Research error: {str(e)}")
|
||||||
"chunks_referenced": [],
|
return f"I encountered an error while researching: {str(e)}"
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
chunk.id
|
|
||||||
not in ctx.deps.state.document_registry[doc_uri]["chunks_referenced"]
|
|
||||||
):
|
|
||||||
ctx.deps.state.document_registry[doc_uri]["chunks_referenced"].append(
|
|
||||||
chunk.id
|
|
||||||
)
|
|
||||||
|
|
||||||
expanded_chunk, _ = (
|
|
||||||
expanded_map[chunk.id] if chunk.id in expanded_map else (chunk, score)
|
|
||||||
)
|
|
||||||
result_data = {
|
|
||||||
"chunk": expanded_chunk.content[:500],
|
|
||||||
"chunk_id": chunk.id,
|
|
||||||
"document_uri": doc_uri,
|
|
||||||
"document_title": doc_title,
|
|
||||||
"chunk_position": chunk.order,
|
|
||||||
"full_chunk_content": expanded_chunk.content,
|
|
||||||
"score": round(score, 3),
|
|
||||||
"expanded": chunk.id in expanded_map,
|
|
||||||
}
|
|
||||||
results.append(result_data)
|
|
||||||
|
|
||||||
plan[question_id]["search_results"] = {
|
|
||||||
"type": search_type,
|
|
||||||
"results": results,
|
|
||||||
}
|
|
||||||
plan[question_id]["status"] = "searched"
|
|
||||||
ctx.deps.state.status = f"Found {len(results)} results"
|
|
||||||
|
|
||||||
return _as_state_snapshot(ctx)
|
|
||||||
|
|
||||||
@agent.tool
|
|
||||||
async def extract_insights_from_results(
|
|
||||||
ctx: RunContext[ResearchDeps],
|
|
||||||
question_id: int,
|
|
||||||
) -> StateSnapshotEvent:
|
|
||||||
"""Extract key insights from search results for a specific question."""
|
|
||||||
plan = ctx.deps.state.plan
|
|
||||||
if question_id >= len(plan):
|
|
||||||
raise ValueError(f"Question ID {question_id} not found in plan")
|
|
||||||
|
|
||||||
question_item = plan[question_id]
|
|
||||||
if "search_results" not in question_item:
|
|
||||||
raise ValueError(
|
|
||||||
f"No search results found for question ID {question_id}. "
|
|
||||||
f"You must call search_question(question_id={question_id}) first."
|
|
||||||
)
|
|
||||||
|
|
||||||
search_results = question_item["search_results"]
|
|
||||||
ctx.deps.state.phase = "analyzing"
|
|
||||||
ctx.deps.state.status = "Extracting insights from results..."
|
|
||||||
|
|
||||||
context_parts = [
|
|
||||||
f"[Result {idx}] [Source: {r['document_title']}] {r['full_chunk_content']}"
|
|
||||||
for idx, r in enumerate(search_results["results"])
|
|
||||||
]
|
|
||||||
context = "\n\n".join(context_parts)
|
|
||||||
|
|
||||||
class InsightResult(BaseModel):
|
|
||||||
summary: str
|
|
||||||
confidence: float
|
|
||||||
result_indices: list[int]
|
|
||||||
|
|
||||||
class InsightsList(BaseModel):
|
|
||||||
insights: list[InsightResult]
|
|
||||||
|
|
||||||
question_text = question_item["question"]
|
|
||||||
extract_prompt = f"""Analyze these search results and extract 1-3 key insights that help answer the question: "{question_text}"
|
|
||||||
|
|
||||||
Search Results:
|
|
||||||
{context}
|
|
||||||
|
|
||||||
For each insight, reference which result numbers (0, 1, 2, etc.) support it."""
|
|
||||||
|
|
||||||
insight_agent: Agent[None, InsightsList] = Agent(
|
|
||||||
ctx.model,
|
|
||||||
output_type=InsightsList,
|
|
||||||
retries=3,
|
|
||||||
)
|
|
||||||
|
|
||||||
result = await insight_agent.run(extract_prompt)
|
|
||||||
raw_insights = [
|
|
||||||
{
|
|
||||||
"summary": insight.summary,
|
|
||||||
"confidence": insight.confidence,
|
|
||||||
"result_indices": insight.result_indices,
|
|
||||||
}
|
|
||||||
for insight in result.output.insights
|
|
||||||
]
|
|
||||||
|
|
||||||
new_insights = []
|
|
||||||
for insight in raw_insights:
|
|
||||||
source_refs = []
|
|
||||||
for idx in insight.get("result_indices", []):
|
|
||||||
if 0 <= idx < len(search_results["results"]):
|
|
||||||
result = search_results["results"][idx]
|
|
||||||
source_refs.append(
|
|
||||||
{
|
|
||||||
"chunk_id": result["chunk_id"],
|
|
||||||
"document_uri": result["document_uri"],
|
|
||||||
"document_title": result["document_title"],
|
|
||||||
"chunk_position": result["chunk_position"],
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
new_insights.append(
|
|
||||||
{
|
|
||||||
"summary": insight["summary"],
|
|
||||||
"confidence": insight.get("confidence", 0.7),
|
|
||||||
"source_refs": source_refs,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
ctx.deps.state.insights.extend(new_insights)
|
|
||||||
plan[question_id]["status"] = "done"
|
|
||||||
ctx.deps.state.status = f"Extracted {len(new_insights)} insights"
|
|
||||||
|
|
||||||
return _as_state_snapshot(ctx)
|
|
||||||
|
|
||||||
@agent.tool
|
|
||||||
async def evaluate_research_confidence(
|
|
||||||
ctx: RunContext[ResearchDeps],
|
|
||||||
) -> StateSnapshotEvent:
|
|
||||||
"""Evaluate overall confidence in the research findings."""
|
|
||||||
insights = ctx.deps.state.insights
|
|
||||||
if not insights:
|
|
||||||
raise ValueError("No insights collected yet")
|
|
||||||
|
|
||||||
ctx.deps.state.phase = "evaluating"
|
|
||||||
ctx.deps.state.status = "Evaluating research confidence..."
|
|
||||||
|
|
||||||
confidences = [i.get("confidence", 0.5) for i in insights]
|
|
||||||
overall_confidence = sum(confidences) / len(confidences) if confidences else 0
|
|
||||||
|
|
||||||
eval_prompt = f"""Evaluate if these insights provide a confident answer to: "{ctx.deps.state.question}"
|
|
||||||
|
|
||||||
Insights collected:
|
|
||||||
{chr(10).join([f"- {i['summary']}" for i in insights])}
|
|
||||||
|
|
||||||
Assess:
|
|
||||||
1. Do we have enough information to answer the question?
|
|
||||||
2. What gaps remain?
|
|
||||||
3. Overall confidence (0.0-1.0)
|
|
||||||
|
|
||||||
Return JSON: {{"confidence": 0.0-1.0, "gaps": ["gap1", "gap2"], "recommendation": "continue" or "finalize"}}"""
|
|
||||||
|
|
||||||
response = await ctx.deps.client.ask(eval_prompt)
|
|
||||||
|
|
||||||
try:
|
|
||||||
evaluation = json.loads(response)
|
|
||||||
overall_confidence = evaluation.get("confidence", overall_confidence)
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
ctx.deps.state.confidence = overall_confidence
|
|
||||||
ctx.deps.state.status = f"Confidence: {overall_confidence:.0%}"
|
|
||||||
|
|
||||||
return _as_state_snapshot(ctx)
|
|
||||||
|
|
||||||
@agent.tool
|
|
||||||
async def synthesize_final_report(
|
|
||||||
ctx: RunContext[ResearchDeps],
|
|
||||||
) -> StateSnapshotEvent:
|
|
||||||
"""Generate final research report with citations."""
|
|
||||||
insights = ctx.deps.state.insights
|
|
||||||
if not insights:
|
|
||||||
raise ValueError("No insights to synthesize")
|
|
||||||
|
|
||||||
ctx.deps.state.phase = "synthesizing"
|
|
||||||
ctx.deps.state.status = "Generating final report..."
|
|
||||||
|
|
||||||
insights_summary = []
|
|
||||||
for i in insights:
|
|
||||||
source_titles = [ref["document_title"] for ref in i.get("source_refs", [])]
|
|
||||||
unique_sources = list(dict.fromkeys(source_titles))
|
|
||||||
insights_summary.append(
|
|
||||||
f"- {i['summary']} (sources: {', '.join(unique_sources[:2])})"
|
|
||||||
)
|
|
||||||
|
|
||||||
report_prompt = f"""Generate a comprehensive research report answering: "{ctx.deps.state.question}"
|
|
||||||
|
|
||||||
Based on these insights:
|
|
||||||
{chr(10).join(insights_summary)}
|
|
||||||
|
|
||||||
Create a structured report with:
|
|
||||||
- Executive Summary (2-3 sentences)
|
|
||||||
- Main Findings (bullet points)
|
|
||||||
- Conclusions
|
|
||||||
- Sources (list the document titles mentioned above)
|
|
||||||
|
|
||||||
Return JSON with format:
|
|
||||||
{{
|
|
||||||
"title": "...",
|
|
||||||
"summary": "...",
|
|
||||||
"findings": ["finding1", "finding2", ...],
|
|
||||||
"conclusions": ["conclusion1", ...],
|
|
||||||
"sources": ["source1", "source2", ...]
|
|
||||||
}}"""
|
|
||||||
|
|
||||||
response = await ctx.deps.client.ask(report_prompt)
|
|
||||||
|
|
||||||
try:
|
|
||||||
report = json.loads(response)
|
|
||||||
except json.JSONDecodeError:
|
|
||||||
report = {
|
|
||||||
"title": ctx.deps.state.question,
|
|
||||||
"summary": response[:300],
|
|
||||||
"findings": [i["summary"] for i in insights],
|
|
||||||
"conclusions": ["See findings above"],
|
|
||||||
"sources": [],
|
|
||||||
}
|
|
||||||
|
|
||||||
citations = [
|
|
||||||
{
|
|
||||||
"document_uri": doc_uri,
|
|
||||||
"document_title": doc_info["title"],
|
|
||||||
"chunk_ids": doc_info["chunks_referenced"],
|
|
||||||
}
|
|
||||||
for doc_uri, doc_info in ctx.deps.state.document_registry.items()
|
|
||||||
]
|
|
||||||
report["citations"] = citations
|
|
||||||
|
|
||||||
ctx.deps.state.final_report = report
|
|
||||||
ctx.deps.state.phase = "done"
|
|
||||||
ctx.deps.state.status = "Research complete"
|
|
||||||
|
|
||||||
return _as_state_snapshot(ctx)
|
|
||||||
|
|
||||||
@agent.tool
|
|
||||||
async def get_full_document(
|
|
||||||
ctx: RunContext[ResearchDeps],
|
|
||||||
document_uri: str,
|
|
||||||
) -> StateSnapshotEvent:
|
|
||||||
"""Retrieve and display the full content of a document by its URI."""
|
|
||||||
ctx.deps.state.status = f"Retrieving document: {document_uri}"
|
|
||||||
document = await ctx.deps.client.get_document_by_uri(document_uri)
|
|
||||||
|
|
||||||
if document is None:
|
|
||||||
ctx.deps.state.status = f"Document not found: {document_uri}"
|
|
||||||
ctx.deps.state.current_document = {
|
|
||||||
"uri": document_uri,
|
|
||||||
"title": "Not Found",
|
|
||||||
"content": f"Document with URI '{document_uri}' was not found.",
|
|
||||||
"total_chunks": 0,
|
|
||||||
}
|
|
||||||
else:
|
|
||||||
all_chunks = await ctx.deps.client.search(
|
|
||||||
query="", limit=1000, search_type="fts"
|
|
||||||
)
|
|
||||||
chunks_for_doc = [
|
|
||||||
c for c, _ in all_chunks if c.document_uri == document_uri
|
|
||||||
]
|
|
||||||
|
|
||||||
ctx.deps.state.current_document = {
|
|
||||||
"uri": document.uri or document_uri,
|
|
||||||
"title": document.title or "Untitled",
|
|
||||||
"content": document.content,
|
|
||||||
"total_chunks": len(chunks_for_doc),
|
|
||||||
"metadata": document.metadata,
|
|
||||||
}
|
|
||||||
ctx.deps.state.status = f"Retrieved: {document.title or document_uri}"
|
|
||||||
|
|
||||||
return _as_state_snapshot(ctx)
|
|
||||||
|
|
||||||
return agent
|
|
||||||
|
|
|
||||||
|
|
@ -1,27 +1,42 @@
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
from contextlib import asynccontextmanager
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from agent import ResearchDeps, ResearchState, create_agent
|
from agent import AgentDeps, agent
|
||||||
|
from anyio import create_memory_object_stream, create_task_group
|
||||||
|
from anyio.streams.memory import MemoryObjectSendStream
|
||||||
from starlette.applications import Starlette
|
from starlette.applications import Starlette
|
||||||
from starlette.middleware import Middleware
|
from starlette.middleware import Middleware
|
||||||
from starlette.middleware.cors import CORSMiddleware
|
from starlette.middleware.cors import CORSMiddleware
|
||||||
from starlette.responses import JSONResponse
|
from starlette.requests import Request
|
||||||
from starlette.routing import Mount, Route
|
from starlette.responses import JSONResponse, StreamingResponse
|
||||||
|
from starlette.routing import Route
|
||||||
|
|
||||||
from haiku.rag.client import HaikuRAG
|
from haiku.rag.client import HaikuRAG
|
||||||
from haiku.rag.config import Config
|
from haiku.rag.config import load_yaml_config
|
||||||
|
from haiku.rag.config.models import AppConfig
|
||||||
|
from haiku.rag.graph.agui.emitter import AGUIEmitter
|
||||||
|
from haiku.rag.graph.agui.server import RunAgentInput, format_sse_event
|
||||||
|
from haiku.rag.graph.research.dependencies import ResearchContext
|
||||||
|
from haiku.rag.graph.research.models import ResearchReport
|
||||||
|
from haiku.rag.graph.research.state import ResearchState
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.INFO, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s"
|
||||||
|
)
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
client: HaikuRAG | None = None
|
# Load config from mounted haiku.rag.yaml
|
||||||
ag_ui_app = None
|
config_path = Path("/app/haiku.rag.yaml")
|
||||||
|
if config_path.exists():
|
||||||
|
yaml_data = load_yaml_config(config_path)
|
||||||
|
Config = AppConfig.model_validate(yaml_data)
|
||||||
|
else:
|
||||||
|
# Fallback to default config
|
||||||
|
Config = AppConfig()
|
||||||
|
|
||||||
|
|
||||||
@asynccontextmanager
|
# Get DB path from environment
|
||||||
async def lifespan(app):
|
|
||||||
global client
|
|
||||||
db_path_str = os.getenv("DB_PATH", "haiku_rag.lancedb")
|
db_path_str = os.getenv("DB_PATH", "haiku_rag.lancedb")
|
||||||
db_path = Path(db_path_str)
|
db_path = Path(db_path_str)
|
||||||
|
|
||||||
|
|
@ -30,58 +45,127 @@ async def lifespan(app):
|
||||||
logger.error("Run: haiku-rag add <path-to-documents>")
|
logger.error("Run: haiku-rag add <path-to-documents>")
|
||||||
raise RuntimeError(f"Database not found: {db_path}")
|
raise RuntimeError(f"Database not found: {db_path}")
|
||||||
|
|
||||||
logger.info(f"Initializing HaikuRAG client with database: {db_path}")
|
logger.info(f"Initializing research assistant with database: {db_path}")
|
||||||
client = HaikuRAG(db_path)
|
logger.info(
|
||||||
logger.info("Research assistant backend ready")
|
f"Research Provider: {Config.research.provider}, Model: {Config.research.model}"
|
||||||
logger.info(f"QA Provider: {Config.qa.provider}, Model: {Config.qa.model}")
|
)
|
||||||
|
|
||||||
yield
|
# Store client reference for proper lifecycle management
|
||||||
|
_client_cache: dict[str, HaikuRAG] = {}
|
||||||
if client:
|
|
||||||
logger.info("Closing HaikuRAG client")
|
|
||||||
client.close()
|
|
||||||
|
|
||||||
|
|
||||||
agent = create_agent()
|
def get_client(effective_db_path: Path) -> HaikuRAG:
|
||||||
|
"""Get or create cached client."""
|
||||||
|
path_key = str(effective_db_path)
|
||||||
|
if path_key not in _client_cache:
|
||||||
|
_client_cache[path_key] = HaikuRAG(db_path=effective_db_path, config=Config)
|
||||||
|
return _client_cache[path_key]
|
||||||
|
|
||||||
|
|
||||||
async def health(request):
|
async def stream_research_agent(request: Request) -> StreamingResponse:
|
||||||
db_path_str = os.getenv("DB_PATH", "haiku_rag.lancedb")
|
"""Agent streaming endpoint with research graph integration."""
|
||||||
|
body = await request.json()
|
||||||
|
input_data = RunAgentInput(**body)
|
||||||
|
|
||||||
|
user_message = ""
|
||||||
|
if input_data.messages:
|
||||||
|
user_message = input_data.messages[-1].get("content", "")
|
||||||
|
|
||||||
|
send_stream, receive_stream = create_memory_object_stream[str]()
|
||||||
|
|
||||||
|
async def run_agent_with_streaming(
|
||||||
|
send_stream: MemoryObjectSendStream[str],
|
||||||
|
) -> None:
|
||||||
|
"""Execute agent and forward emitter events to memory stream."""
|
||||||
|
async with send_stream:
|
||||||
|
try:
|
||||||
|
# Create shared emitter
|
||||||
|
emitter: AGUIEmitter[ResearchState, ResearchReport] = AGUIEmitter(
|
||||||
|
thread_id=input_data.thread_id,
|
||||||
|
run_id=input_data.run_id,
|
||||||
|
use_deltas=False,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get client
|
||||||
|
effective_db_path = input_data.config.get("db_path") or db_path
|
||||||
|
if isinstance(effective_db_path, str):
|
||||||
|
effective_db_path = Path(effective_db_path)
|
||||||
|
client = get_client(effective_db_path)
|
||||||
|
|
||||||
|
# Create agent dependencies with shared emitter
|
||||||
|
agent_deps = AgentDeps(client=client, agui_emitter=emitter)
|
||||||
|
|
||||||
|
# Start run with empty initial state
|
||||||
|
emitter.start_run(
|
||||||
|
initial_state=ResearchState.from_config(
|
||||||
|
context=ResearchContext(original_question=""),
|
||||||
|
config=Config,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# Forward emitter events to stream
|
||||||
|
async def forward_events():
|
||||||
|
async for event in emitter:
|
||||||
|
# Filter out ACTIVITY_SNAPSHOT - not supported by CopilotKit
|
||||||
|
if event.get("type") == "ACTIVITY_SNAPSHOT":
|
||||||
|
continue
|
||||||
|
await send_stream.send(format_sse_event(event))
|
||||||
|
|
||||||
|
# Run agent and event forwarding concurrently
|
||||||
|
async with create_task_group() as tg:
|
||||||
|
tg.start_soon(forward_events)
|
||||||
|
|
||||||
|
result = await agent.run(user_message, deps=agent_deps)
|
||||||
|
emitter.log(result.output)
|
||||||
|
await emitter.close()
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.exception("Error executing agent")
|
||||||
|
try:
|
||||||
|
await send_stream.send(
|
||||||
|
format_sse_event({"type": "error", "error": str(e)})
|
||||||
|
)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
async def event_generator():
|
||||||
|
"""Generate SSE events from memory stream."""
|
||||||
|
async with create_task_group() as tg:
|
||||||
|
tg.start_soon(run_agent_with_streaming, send_stream)
|
||||||
|
async with receive_stream:
|
||||||
|
async for event_str in receive_stream:
|
||||||
|
yield event_str
|
||||||
|
|
||||||
|
return StreamingResponse(
|
||||||
|
event_generator(),
|
||||||
|
media_type="text/event-stream",
|
||||||
|
headers={
|
||||||
|
"Cache-Control": "no-cache",
|
||||||
|
"Connection": "keep-alive",
|
||||||
|
"X-Accel-Buffering": "no",
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def health_check(_: Request) -> JSONResponse:
|
||||||
|
"""Health check endpoint with configuration info."""
|
||||||
return JSONResponse(
|
return JSONResponse(
|
||||||
{
|
{
|
||||||
"status": "healthy",
|
"status": "healthy",
|
||||||
"agent_model": str(agent.model),
|
"agent_model": str(agent.model),
|
||||||
"qa_provider": Config.qa.provider,
|
"research_provider": Config.research.provider,
|
||||||
"qa_model": Config.qa.model,
|
"research_model": Config.research.model,
|
||||||
"ollama_base_url": Config.providers.ollama.base_url,
|
"db_path": str(db_path),
|
||||||
"db_path": db_path_str,
|
"db_exists": db_path.exists(),
|
||||||
"db_exists": Path(db_path_str).exists(),
|
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_ag_ui_app():
|
# Create Starlette app
|
||||||
global ag_ui_app
|
|
||||||
if ag_ui_app is None and client is not None:
|
|
||||||
research_deps = ResearchDeps(client=client, state=ResearchState())
|
|
||||||
logger.info("Creating AG-UI app")
|
|
||||||
ag_ui_app = agent.to_ag_ui(deps=research_deps)
|
|
||||||
return ag_ui_app
|
|
||||||
|
|
||||||
|
|
||||||
async def agent_endpoint(scope, receive, send):
|
|
||||||
app = get_ag_ui_app()
|
|
||||||
if app is None:
|
|
||||||
response = JSONResponse({"error": "Client not initialized"}, status_code=503)
|
|
||||||
await response(scope, receive, send)
|
|
||||||
return
|
|
||||||
await app(scope, receive, send)
|
|
||||||
|
|
||||||
|
|
||||||
app = Starlette(
|
app = Starlette(
|
||||||
routes=[
|
routes=[
|
||||||
Route("/health", health),
|
Route("/v1/research/stream", stream_research_agent, methods=["POST"]),
|
||||||
Mount("/agent", agent_endpoint),
|
Route("/health", health_check, methods=["GET"]),
|
||||||
],
|
],
|
||||||
middleware=[
|
middleware=[
|
||||||
Middleware(
|
Middleware(
|
||||||
|
|
@ -92,17 +176,11 @@ app = Starlette(
|
||||||
allow_headers=["*"],
|
allow_headers=["*"],
|
||||||
)
|
)
|
||||||
],
|
],
|
||||||
lifespan=lifespan,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
print("Starting haiku.rag research assistant backend...")
|
|
||||||
print(f"Agent model: {agent.model}")
|
|
||||||
print(f"QA provider: {Config.qa.provider}")
|
|
||||||
print(f"QA model: {Config.qa.model}")
|
|
||||||
|
|
||||||
uvicorn.run(
|
uvicorn.run(
|
||||||
"main:app",
|
"main:app",
|
||||||
host="0.0.0.0",
|
host="0.0.0.0",
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ dependencies = [
|
||||||
"uvicorn[standard]>=0.34.2",
|
"uvicorn[standard]>=0.34.2",
|
||||||
"pydantic-ai-slim[ag-ui,openai]>=1.1.0",
|
"pydantic-ai-slim[ag-ui,openai]>=1.1.0",
|
||||||
"python-dotenv>=1.0.1",
|
"python-dotenv>=1.0.1",
|
||||||
"haiku-rag>=0.12.1",
|
"haiku-rag-slim @ file:///Users/ggozad/dev/open-source/haiku.rag-agui/haiku_rag_slim",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
|
|
@ -18,6 +18,9 @@ dev = [
|
||||||
"ruff>=0.13.0",
|
"ruff>=0.13.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[tool.hatch.metadata]
|
||||||
|
allow-direct-references = true
|
||||||
|
|
||||||
[tool.hatch.build.targets.wheel]
|
[tool.hatch.build.targets.wheel]
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -10,11 +10,16 @@ services:
|
||||||
# API keys (set these in your shell or .env file)
|
# API keys (set these in your shell or .env file)
|
||||||
- OPENAI_API_KEY=${OPENAI_API_KEY}
|
- OPENAI_API_KEY=${OPENAI_API_KEY}
|
||||||
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
|
||||||
|
# Ollama connection (use value from .env)
|
||||||
|
- OLLAMA_BASE_URL=${OLLAMA_BASE_URL}
|
||||||
|
# Prevent Python bytecode caching for development
|
||||||
|
- PYTHONDONTWRITEBYTECODE=1
|
||||||
volumes:
|
volumes:
|
||||||
- ./backend:/app
|
|
||||||
- /app/.venv
|
|
||||||
- ${DB_PATH}:/app/data/haiku.rag.lancedb
|
- ${DB_PATH}:/app/data/haiku.rag.lancedb
|
||||||
- ./haiku.rag.yaml:/app/haiku.rag.yaml:ro
|
- ./haiku.rag.yaml:/app/haiku.rag.yaml:ro
|
||||||
|
- ./backend/main.py:/app/main.py
|
||||||
|
- ./backend/agent.py:/app/agent.py
|
||||||
|
- ../../haiku_rag_slim/haiku:/app/.venv/lib/python3.13/site-packages/haiku
|
||||||
networks:
|
networks:
|
||||||
- ag-ui-network
|
- ag-ui-network
|
||||||
extra_hosts:
|
extra_hosts:
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ const runtime = new CopilotRuntime({
|
||||||
agents: {
|
agents: {
|
||||||
// "research_agent" maps to the agent name used in useCoAgent() on the frontend
|
// "research_agent" maps to the agent name used in useCoAgent() on the frontend
|
||||||
research_agent: new HttpAgent({
|
research_agent: new HttpAgent({
|
||||||
url: `${process.env.BACKEND_URL || "http://backend:8000"}/agent`,
|
url: `${process.env.BACKEND_URL || "http://backend:8000"}/v1/research/stream`,
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,208 +1,94 @@
|
||||||
"use client";
|
"use client";
|
||||||
|
|
||||||
import {
|
import { CopilotKit, useCoAgent } from "@copilotkit/react-core";
|
||||||
CopilotKit,
|
|
||||||
useCoAgent,
|
|
||||||
useCoAgentStateRender,
|
|
||||||
useCopilotAction,
|
|
||||||
} from "@copilotkit/react-core";
|
|
||||||
import { CopilotChat } from "@copilotkit/react-ui";
|
import { CopilotChat } from "@copilotkit/react-ui";
|
||||||
import "@copilotkit/react-ui/styles.css";
|
import "@copilotkit/react-ui/styles.css";
|
||||||
import StateDisplay from "./StateDisplay";
|
import StateDisplay from "./StateDisplay";
|
||||||
|
|
||||||
interface SourceRef {
|
interface InsightRecord {
|
||||||
chunk_id: string;
|
id: string;
|
||||||
document_uri: string;
|
summary: string;
|
||||||
document_title: string;
|
status: string;
|
||||||
chunk_position: number;
|
notes?: string;
|
||||||
|
supporting_sources: string[];
|
||||||
|
originating_questions: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ResearchState {
|
interface GapRecord {
|
||||||
question: string;
|
id: string;
|
||||||
phase: string;
|
description: string;
|
||||||
status: string;
|
severity: string;
|
||||||
plan: Array<{
|
blocking: boolean;
|
||||||
id: number;
|
resolved: boolean;
|
||||||
question: string;
|
notes?: string;
|
||||||
status: string;
|
supporting_sources: string[];
|
||||||
search_results?: {
|
resolved_by: string[];
|
||||||
type: string;
|
|
||||||
results: Array<{
|
|
||||||
chunk: string;
|
|
||||||
chunk_id: string;
|
|
||||||
document_uri: string;
|
|
||||||
document_title: string;
|
|
||||||
chunk_position: number;
|
|
||||||
full_chunk_content: string;
|
|
||||||
score: number;
|
|
||||||
expanded: boolean;
|
|
||||||
}>;
|
|
||||||
};
|
|
||||||
}>;
|
|
||||||
current_question_index: number;
|
|
||||||
insights: Array<{
|
|
||||||
summary: string;
|
|
||||||
confidence: number;
|
|
||||||
source_refs: SourceRef[];
|
|
||||||
}>;
|
|
||||||
document_registry: Record<
|
|
||||||
string,
|
|
||||||
{
|
|
||||||
title: string;
|
|
||||||
chunks_referenced: string[];
|
|
||||||
}
|
}
|
||||||
>;
|
|
||||||
current_document: {
|
interface SearchAnswer {
|
||||||
uri: string;
|
query: string;
|
||||||
title: string;
|
answer: string;
|
||||||
content: string;
|
|
||||||
total_chunks: number;
|
|
||||||
metadata?: Record<string, unknown>;
|
|
||||||
} | null;
|
|
||||||
confidence: number;
|
confidence: number;
|
||||||
final_report: {
|
context: string[];
|
||||||
title: string;
|
sources: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ResearchContext {
|
||||||
|
original_question: string;
|
||||||
|
sub_questions: string[];
|
||||||
|
qa_responses: SearchAnswer[];
|
||||||
|
insights: InsightRecord[];
|
||||||
|
gaps: GapRecord[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EvaluationResult {
|
||||||
|
confidence: number;
|
||||||
|
reasoning: string;
|
||||||
|
should_continue: boolean;
|
||||||
|
gaps_identified: string[];
|
||||||
|
follow_up_questions: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ResearchReport {
|
||||||
|
question: string;
|
||||||
summary: string;
|
summary: string;
|
||||||
findings: string[];
|
findings: string[];
|
||||||
conclusions: string[];
|
conclusions: string[];
|
||||||
sources: string[];
|
insights_used: string[];
|
||||||
citations: Array<{
|
methodology: string;
|
||||||
document_uri: string;
|
}
|
||||||
document_title: string;
|
|
||||||
chunk_ids: string[];
|
interface ResearchState {
|
||||||
}>;
|
context: ResearchContext;
|
||||||
|
iterations: number;
|
||||||
|
max_iterations: number;
|
||||||
|
confidence_threshold: number;
|
||||||
|
max_concurrency: number;
|
||||||
|
last_eval: EvaluationResult | null;
|
||||||
|
last_analysis: {
|
||||||
|
insights_extracted: InsightRecord[];
|
||||||
|
gaps_identified: GapRecord[];
|
||||||
} | null;
|
} | null;
|
||||||
|
result?: ResearchReport;
|
||||||
}
|
}
|
||||||
|
|
||||||
function AgentContent() {
|
function AgentContent() {
|
||||||
const { state } = useCoAgent<ResearchState>({
|
const { state } = useCoAgent<ResearchState>({
|
||||||
name: "research_agent",
|
name: "research_agent",
|
||||||
initialState: {
|
initialState: {
|
||||||
question: "",
|
context: {
|
||||||
phase: "idle",
|
original_question: "",
|
||||||
status: "",
|
sub_questions: [],
|
||||||
plan: [],
|
qa_responses: [],
|
||||||
current_question_index: 0,
|
|
||||||
insights: [],
|
insights: [],
|
||||||
document_registry: {},
|
gaps: [],
|
||||||
current_document: null,
|
|
||||||
confidence: 0.0,
|
|
||||||
final_report: null,
|
|
||||||
},
|
},
|
||||||
});
|
iterations: 0,
|
||||||
|
max_iterations: 3,
|
||||||
useCopilotAction({
|
confidence_threshold: 0.8,
|
||||||
name: "approve_research_plan",
|
max_concurrency: 1,
|
||||||
description:
|
last_eval: null,
|
||||||
"Request user approval for the research plan. Returns 'APPROVED' if approved or 'REVISE' if user wants to revise.",
|
last_analysis: null,
|
||||||
parameters: [],
|
|
||||||
renderAndWaitForResponse: ({ respond, status }) => (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
padding: "1.5rem",
|
|
||||||
background: "white",
|
|
||||||
borderRadius: "8px",
|
|
||||||
border: "2px solid #4299e1",
|
|
||||||
marginBottom: "1rem",
|
|
||||||
boxShadow: "0 2px 8px rgba(0,0,0,0.1)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<h3
|
|
||||||
style={{
|
|
||||||
fontSize: "1.25rem",
|
|
||||||
fontWeight: "bold",
|
|
||||||
marginBottom: "1rem",
|
|
||||||
color: "#2d3748",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Research Plan Approval
|
|
||||||
</h3>
|
|
||||||
<p
|
|
||||||
style={{
|
|
||||||
fontSize: "0.875rem",
|
|
||||||
color: "#4a5568",
|
|
||||||
marginBottom: "1rem",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Please review the research plan in the right pane.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
gap: "1rem",
|
|
||||||
}}
|
|
||||||
className={status !== "executing" ? "hidden" : ""}
|
|
||||||
>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => respond?.("REVISE")}
|
|
||||||
disabled={status !== "executing"}
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
padding: "0.75rem",
|
|
||||||
background: "white",
|
|
||||||
border: "2px solid #e2e8f0",
|
|
||||||
borderRadius: "6px",
|
|
||||||
fontSize: "0.875rem",
|
|
||||||
fontWeight: "600",
|
|
||||||
cursor: status === "executing" ? "pointer" : "not-allowed",
|
|
||||||
opacity: status === "executing" ? 1 : 0.5,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Revise Plan
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
type="button"
|
|
||||||
onClick={() => respond?.("APPROVED")}
|
|
||||||
disabled={status !== "executing"}
|
|
||||||
style={{
|
|
||||||
flex: 1,
|
|
||||||
padding: "0.75rem",
|
|
||||||
background: "#4299e1",
|
|
||||||
color: "white",
|
|
||||||
border: "none",
|
|
||||||
borderRadius: "6px",
|
|
||||||
fontSize: "0.875rem",
|
|
||||||
fontWeight: "600",
|
|
||||||
cursor: status === "executing" ? "pointer" : "not-allowed",
|
|
||||||
opacity: status === "executing" ? 1 : 0.5,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Approve & Start Research
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
});
|
|
||||||
|
|
||||||
useCoAgentStateRender<ResearchState>({
|
|
||||||
name: "research_agent",
|
|
||||||
render: ({ state: newState }) => {
|
|
||||||
const phaseMessages: Record<string, string> = {
|
|
||||||
planning: "Planning research...",
|
|
||||||
searching: "Searching...",
|
|
||||||
analyzing: "Extracting insights...",
|
|
||||||
evaluating: `Evaluating confidence: ${(newState.confidence * 100).toFixed(0)}%`,
|
|
||||||
synthesizing: "Generating final report...",
|
|
||||||
done: "Research complete!",
|
|
||||||
};
|
|
||||||
const phaseMessage =
|
|
||||||
phaseMessages[newState.phase] || newState.status || "Ready";
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
padding: "1rem",
|
|
||||||
background: "#e6f7ff",
|
|
||||||
borderRadius: "4px",
|
|
||||||
marginBottom: "0.5rem",
|
|
||||||
border: "1px solid #91d5ff",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<strong>Research Update:</strong> {phaseMessage}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,68 +3,70 @@
|
||||||
import { Markdown } from "@copilotkit/react-ui";
|
import { Markdown } from "@copilotkit/react-ui";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
|
|
||||||
interface SourceRef {
|
interface InsightRecord {
|
||||||
chunk_id: string;
|
id: string;
|
||||||
document_uri: string;
|
summary: string;
|
||||||
document_title: string;
|
status: string;
|
||||||
chunk_position: number;
|
notes?: string;
|
||||||
|
supporting_sources: string[];
|
||||||
|
originating_questions: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ResearchState {
|
interface GapRecord {
|
||||||
question: string;
|
id: string;
|
||||||
phase: string;
|
description: string;
|
||||||
status: string;
|
severity: string;
|
||||||
plan: Array<{
|
blocking: boolean;
|
||||||
id: number;
|
resolved: boolean;
|
||||||
question: string;
|
notes?: string;
|
||||||
status: string;
|
supporting_sources: string[];
|
||||||
search_results?: {
|
resolved_by: string[];
|
||||||
type: string;
|
|
||||||
results: Array<{
|
|
||||||
chunk: string;
|
|
||||||
chunk_id: string;
|
|
||||||
document_uri: string;
|
|
||||||
document_title: string;
|
|
||||||
chunk_position: number;
|
|
||||||
full_chunk_content: string;
|
|
||||||
score: number;
|
|
||||||
expanded: boolean;
|
|
||||||
}>;
|
|
||||||
};
|
|
||||||
}>;
|
|
||||||
current_question_index: number;
|
|
||||||
insights: Array<{
|
|
||||||
summary: string;
|
|
||||||
confidence: number;
|
|
||||||
source_refs: SourceRef[];
|
|
||||||
}>;
|
|
||||||
document_registry: Record<
|
|
||||||
string,
|
|
||||||
{
|
|
||||||
title: string;
|
|
||||||
chunks_referenced: string[];
|
|
||||||
}
|
}
|
||||||
>;
|
|
||||||
current_document: {
|
interface SearchAnswer {
|
||||||
uri: string;
|
sub_question: string;
|
||||||
title: string;
|
answer: string;
|
||||||
content: string;
|
|
||||||
total_chunks: number;
|
|
||||||
metadata?: Record<string, unknown>;
|
|
||||||
} | null;
|
|
||||||
confidence: number;
|
confidence: number;
|
||||||
final_report: {
|
chunks_used: number;
|
||||||
title: string;
|
}
|
||||||
|
|
||||||
|
interface ResearchContext {
|
||||||
|
original_question: string;
|
||||||
|
sub_questions: string[];
|
||||||
|
qa_responses: SearchAnswer[];
|
||||||
|
insights: InsightRecord[];
|
||||||
|
gaps: GapRecord[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EvaluationResult {
|
||||||
|
confidence: number;
|
||||||
|
reasoning: string;
|
||||||
|
should_continue: boolean;
|
||||||
|
gaps_identified: string[];
|
||||||
|
follow_up_questions: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ResearchReport {
|
||||||
|
question: string;
|
||||||
summary: string;
|
summary: string;
|
||||||
findings: string[];
|
findings: string[];
|
||||||
conclusions: string[];
|
conclusions: string[];
|
||||||
sources: string[];
|
insights_used: string[];
|
||||||
citations: Array<{
|
methodology: string;
|
||||||
document_uri: string;
|
}
|
||||||
document_title: string;
|
|
||||||
chunk_ids: string[];
|
interface ResearchState {
|
||||||
}>;
|
context: ResearchContext;
|
||||||
|
iterations: number;
|
||||||
|
max_iterations: number;
|
||||||
|
confidence_threshold: number;
|
||||||
|
max_concurrency: number;
|
||||||
|
last_eval: EvaluationResult | null;
|
||||||
|
last_analysis: {
|
||||||
|
insights_extracted: InsightRecord[];
|
||||||
|
gaps_identified: GapRecord[];
|
||||||
} | null;
|
} | null;
|
||||||
|
result?: ResearchReport;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface StateDisplayProps {
|
interface StateDisplayProps {
|
||||||
|
|
@ -75,14 +77,14 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
const [expandedSections, setExpandedSections] = useState<
|
const [expandedSections, setExpandedSections] = useState<
|
||||||
Record<string, boolean>
|
Record<string, boolean>
|
||||||
>({
|
>({
|
||||||
plan: true,
|
questions: true,
|
||||||
insights: true,
|
insights: true,
|
||||||
|
gaps: true,
|
||||||
report: true,
|
report: true,
|
||||||
document: true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const [expandedQuestions, setExpandedQuestions] = useState<
|
const [expandedQuestions, setExpandedQuestions] = useState<
|
||||||
Record<number, boolean>
|
Record<string, boolean>
|
||||||
>({});
|
>({});
|
||||||
|
|
||||||
const toggleSection = (section: string) => {
|
const toggleSection = (section: string) => {
|
||||||
|
|
@ -92,20 +94,19 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
const toggleQuestion = (questionId: number) => {
|
const toggleQuestion = (questionId: string) => {
|
||||||
setExpandedQuestions((prev) => ({
|
setExpandedQuestions((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
[questionId]: !prev[questionId],
|
[questionId]: !prev[questionId],
|
||||||
}));
|
}));
|
||||||
};
|
};
|
||||||
|
|
||||||
// Calculate research progress
|
// Calculate research progress based on iterations
|
||||||
const completedQuestions = state.plan.filter(
|
|
||||||
(q) => q.status === "done",
|
|
||||||
).length;
|
|
||||||
const totalQuestions = state.plan.length;
|
|
||||||
const researchProgress =
|
const researchProgress =
|
||||||
totalQuestions > 0 ? (completedQuestions / totalQuestions) * 100 : 0;
|
state.max_iterations > 0
|
||||||
|
? (state.iterations / state.max_iterations) * 100
|
||||||
|
: 0;
|
||||||
|
const confidence = state.last_eval?.confidence || 0;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
|
|
@ -115,7 +116,7 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
gap: "1rem",
|
gap: "1rem",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* Current Phase & Status */}
|
{/* Current Status */}
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
background: "white",
|
background: "white",
|
||||||
|
|
@ -131,57 +132,48 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
marginBottom: "0.5rem",
|
marginBottom: "0.5rem",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Current Phase
|
Research Progress
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", gap: "0.75rem", alignItems: "center" }}>
|
<div style={{ display: "flex", gap: "0.75rem", alignItems: "center" }}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
padding: "0.5rem 1rem",
|
padding: "0.5rem 1rem",
|
||||||
background:
|
background:
|
||||||
state.phase === "idle"
|
state.iterations === 0
|
||||||
? "#e2e8f0"
|
? "#e2e8f0"
|
||||||
: state.phase === "planning"
|
: state.result
|
||||||
? "#fef3c7"
|
? "#d1fae5"
|
||||||
: state.phase === "searching"
|
: "#dbeafe",
|
||||||
? "#dbeafe"
|
|
||||||
: state.phase === "analyzing"
|
|
||||||
? "#e0e7ff"
|
|
||||||
: state.phase === "evaluating"
|
|
||||||
? "#fce7f3"
|
|
||||||
: "#d1fae5",
|
|
||||||
color:
|
color:
|
||||||
state.phase === "idle"
|
state.iterations === 0
|
||||||
? "#718096"
|
? "#718096"
|
||||||
: state.phase === "planning"
|
: state.result
|
||||||
? "#92400e"
|
? "#065f46"
|
||||||
: state.phase === "searching"
|
: "#1e40af",
|
||||||
? "#1e40af"
|
|
||||||
: state.phase === "analyzing"
|
|
||||||
? "#3730a3"
|
|
||||||
: state.phase === "evaluating"
|
|
||||||
? "#9f1239"
|
|
||||||
: "#065f46",
|
|
||||||
borderRadius: "6px",
|
borderRadius: "6px",
|
||||||
fontSize: "1rem",
|
fontSize: "1rem",
|
||||||
fontWeight: "700",
|
fontWeight: "700",
|
||||||
textTransform: "capitalize",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{state.phase}
|
{state.iterations === 0
|
||||||
|
? "Ready"
|
||||||
|
: state.result
|
||||||
|
? "Complete"
|
||||||
|
: "Researching"}
|
||||||
</div>
|
</div>
|
||||||
{state.status && (
|
{state.iterations > 0 && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: "0.875rem",
|
fontSize: "0.875rem",
|
||||||
color: "#4a5568",
|
color: "#4a5568",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{state.status}
|
Iteration {state.iterations} of {state.max_iterations}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{/* Research Progress Bar */}
|
{/* Research Progress Bar */}
|
||||||
{totalQuestions > 0 && state.phase !== "idle" && (
|
{state.iterations > 0 && (
|
||||||
<div style={{ marginTop: "1rem" }}>
|
<div style={{ marginTop: "1rem" }}>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|
@ -197,7 +189,7 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
color: "#718096",
|
color: "#718096",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Research Progress
|
Iterations
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
|
|
@ -206,7 +198,7 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
color: "#2d3748",
|
color: "#2d3748",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{completedQuestions}/{totalQuestions} questions
|
{state.iterations}/{state.max_iterations}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
@ -231,7 +223,7 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Question */}
|
{/* Question */}
|
||||||
{state.question && (
|
{state.context.original_question && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
background: "white",
|
background: "white",
|
||||||
|
|
@ -256,13 +248,13 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
color: "#2d3748",
|
color: "#2d3748",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{state.question}
|
{state.context.original_question}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Confidence Meter */}
|
{/* Confidence Meter */}
|
||||||
{state.confidence > 0 && (
|
{confidence > 0 && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
background: "white",
|
background: "white",
|
||||||
|
|
@ -292,12 +284,12 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
width: `${state.confidence * 100}%`,
|
width: `${confidence * 100}%`,
|
||||||
height: "100%",
|
height: "100%",
|
||||||
background:
|
background:
|
||||||
state.confidence > 0.8
|
confidence > 0.8
|
||||||
? "#48bb78"
|
? "#48bb78"
|
||||||
: state.confidence > 0.5
|
: confidence > 0.5
|
||||||
? "#ed8936"
|
? "#ed8936"
|
||||||
: "#f56565",
|
: "#f56565",
|
||||||
transition: "width 0.3s ease",
|
transition: "width 0.3s ease",
|
||||||
|
|
@ -309,21 +301,36 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
fontSize: "1.5rem",
|
fontSize: "1.5rem",
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
color:
|
color:
|
||||||
state.confidence > 0.8
|
confidence > 0.8
|
||||||
? "#48bb78"
|
? "#48bb78"
|
||||||
: state.confidence > 0.5
|
: confidence > 0.5
|
||||||
? "#ed8936"
|
? "#ed8936"
|
||||||
: "#f56565",
|
: "#f56565",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{(state.confidence * 100).toFixed(0)}%
|
{(confidence * 100).toFixed(0)}%
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
{state.last_eval?.reasoning && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
marginTop: "0.75rem",
|
||||||
|
fontSize: "0.875rem",
|
||||||
|
color: "#4a5568",
|
||||||
|
padding: "0.75rem",
|
||||||
|
background: "#f7fafc",
|
||||||
|
borderRadius: "4px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Markdown content={state.last_eval.reasoning} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Research Plan */}
|
{/* Sub-Questions and QA Responses */}
|
||||||
{state.plan.length > 0 && (
|
{(state.context.sub_questions.length > 0 ||
|
||||||
|
state.context.qa_responses.length > 0) && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
background: "white",
|
background: "white",
|
||||||
|
|
@ -334,7 +341,7 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => toggleSection("plan")}
|
onClick={() => toggleSection("questions")}
|
||||||
style={{
|
style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
|
@ -350,10 +357,13 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
color: "#2d3748",
|
color: "#2d3748",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span>Research Plan ({state.plan.length} questions)</span>
|
<span>
|
||||||
<span>{expandedSections.plan ? "▼" : "▶"}</span>
|
Sub-Questions ({state.context.sub_questions.length}) • Answers (
|
||||||
|
{state.context.qa_responses.length})
|
||||||
|
</span>
|
||||||
|
<span>{expandedSections.questions ? "▼" : "▶"}</span>
|
||||||
</button>
|
</button>
|
||||||
{expandedSections.plan && (
|
{expandedSections.questions && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
padding: "1rem",
|
padding: "1rem",
|
||||||
|
|
@ -363,9 +373,43 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
borderRadius: "0 0 4px 4px",
|
borderRadius: "0 0 4px 4px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{state.plan.map((item) => (
|
{/* Show pending sub_questions */}
|
||||||
|
{state.context.sub_questions.map((question, idx) => (
|
||||||
<div
|
<div
|
||||||
key={item.id}
|
key={`pending-${idx}`}
|
||||||
|
style={{
|
||||||
|
marginBottom: "0.5rem",
|
||||||
|
background: "white",
|
||||||
|
borderRadius: "4px",
|
||||||
|
border: "1px solid #e2e8f0",
|
||||||
|
padding: "0.75rem",
|
||||||
|
display: "flex",
|
||||||
|
gap: "0.75rem",
|
||||||
|
alignItems: "center",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: "1.25rem",
|
||||||
|
color: "#a0aec0",
|
||||||
|
flexShrink: 0,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
⏳
|
||||||
|
</div>
|
||||||
|
<div style={{ flex: 1, fontSize: "0.875rem", color: "#4a5568" }}>
|
||||||
|
<Markdown content={question} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{/* Show all qa_responses (each has query + answer) */}
|
||||||
|
{state.context.qa_responses.map((qaResponse, idx) => {
|
||||||
|
const questionId = `q-${idx}`;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
key={questionId}
|
||||||
style={{
|
style={{
|
||||||
marginBottom: "0.5rem",
|
marginBottom: "0.5rem",
|
||||||
background: "white",
|
background: "white",
|
||||||
|
|
@ -376,7 +420,7 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => toggleQuestion(item.id)}
|
onClick={() => toggleQuestion(questionId)}
|
||||||
style={{
|
style={{
|
||||||
width: "100%",
|
width: "100%",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
|
@ -392,23 +436,11 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: "1.25rem",
|
fontSize: "1.25rem",
|
||||||
color:
|
color: "#48bb78",
|
||||||
item.status === "done"
|
|
||||||
? "#48bb78"
|
|
||||||
: item.status === "searching" ||
|
|
||||||
item.status === "searched"
|
|
||||||
? "#4299e1"
|
|
||||||
: "#a0aec0",
|
|
||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{item.status === "done"
|
✓
|
||||||
? "✓"
|
|
||||||
: item.status === "searching"
|
|
||||||
? "🔍"
|
|
||||||
: item.status === "searched"
|
|
||||||
? "📊"
|
|
||||||
: "⏳"}
|
|
||||||
</div>
|
</div>
|
||||||
<div style={{ flex: 1 }}>
|
<div style={{ flex: 1 }}>
|
||||||
<div
|
<div
|
||||||
|
|
@ -417,9 +449,8 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
color: "#4a5568",
|
color: "#4a5568",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Markdown content={item.question} />
|
<Markdown content={qaResponse.query} />
|
||||||
</div>
|
</div>
|
||||||
{item.search_results && (
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: "0.75rem",
|
fontSize: "0.75rem",
|
||||||
|
|
@ -427,24 +458,21 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
marginTop: "0.25rem",
|
marginTop: "0.25rem",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{item.search_results.results.length} results
|
Confidence: {(qaResponse.confidence * 100).toFixed(0)}%
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
{item.search_results && (
|
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
fontSize: "0.875rem",
|
fontSize: "0.875rem",
|
||||||
color: "#718096",
|
color: "#718096",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{expandedQuestions[item.id] ? "▼" : "▶"}
|
{expandedQuestions[questionId] ? "▼" : "▶"}
|
||||||
</span>
|
</span>
|
||||||
)}
|
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* Search Results nested inside question */}
|
{/* QA Response nested inside question */}
|
||||||
{expandedQuestions[item.id] && item.search_results && (
|
{expandedQuestions[questionId] && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
padding: "1rem",
|
padding: "1rem",
|
||||||
|
|
@ -460,87 +488,38 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
fontWeight: "600",
|
fontWeight: "600",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Search Type: {item.search_results.type}
|
Answer
|
||||||
</div>
|
</div>
|
||||||
{item.search_results.results.map((result, idx) => (
|
|
||||||
<div
|
<div
|
||||||
key={`${result.chunk_id}-${idx}`}
|
|
||||||
style={{
|
style={{
|
||||||
padding: "0.75rem",
|
padding: "0.75rem",
|
||||||
background: "white",
|
background: "white",
|
||||||
borderRadius: "4px",
|
borderRadius: "4px",
|
||||||
marginBottom: "0.5rem",
|
|
||||||
border: "1px solid #e2e8f0",
|
border: "1px solid #e2e8f0",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
style={{
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
marginBottom: "0.5rem",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<span
|
|
||||||
style={{
|
style={{
|
||||||
fontSize: "0.875rem",
|
fontSize: "0.875rem",
|
||||||
fontWeight: "600",
|
|
||||||
color: "#2d3748",
|
color: "#2d3748",
|
||||||
|
lineHeight: "1.5",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{result.document_title}
|
<Markdown content={qaResponse.answer} />
|
||||||
</span>
|
|
||||||
<div style={{ display: "flex", gap: "0.5rem" }}>
|
|
||||||
{result.expanded && (
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: "0.75rem",
|
|
||||||
padding: "0.125rem 0.5rem",
|
|
||||||
background: "#bee3f8",
|
|
||||||
color: "#2c5282",
|
|
||||||
borderRadius: "4px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Expanded
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
<span
|
|
||||||
style={{
|
|
||||||
fontSize: "0.875rem",
|
|
||||||
fontWeight: "bold",
|
|
||||||
color:
|
|
||||||
result.score > 0.8
|
|
||||||
? "#48bb78"
|
|
||||||
: result.score > 0.6
|
|
||||||
? "#ed8936"
|
|
||||||
: "#a0aec0",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{result.score.toFixed(2)}
|
|
||||||
</span>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: "0.875rem",
|
|
||||||
color: "#718096",
|
|
||||||
lineHeight: "1.4",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Markdown content={`${result.chunk}...`} />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
);
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Insights */}
|
{/* Insights */}
|
||||||
{state.insights.length > 0 && (
|
{state.context.insights.length > 0 && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
background: "white",
|
background: "white",
|
||||||
|
|
@ -567,7 +546,7 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
color: "#2d3748",
|
color: "#2d3748",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span>Key Insights ({state.insights.length})</span>
|
<span>Key Insights ({state.context.insights.length})</span>
|
||||||
<span>{expandedSections.insights ? "▼" : "▶"}</span>
|
<span>{expandedSections.insights ? "▼" : "▶"}</span>
|
||||||
</button>
|
</button>
|
||||||
{expandedSections.insights && (
|
{expandedSections.insights && (
|
||||||
|
|
@ -580,9 +559,9 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
borderRadius: "0 0 4px 4px",
|
borderRadius: "0 0 4px 4px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{state.insights.map((insight, idx) => (
|
{state.context.insights.map((insight) => (
|
||||||
<div
|
<div
|
||||||
key={`${insight.summary.substring(0, 30)}-${idx}`}
|
key={insight.id}
|
||||||
style={{
|
style={{
|
||||||
padding: "0.75rem",
|
padding: "0.75rem",
|
||||||
background: "white",
|
background: "white",
|
||||||
|
|
@ -602,12 +581,22 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
style={{
|
style={{
|
||||||
fontSize: "0.75rem",
|
fontSize: "0.75rem",
|
||||||
padding: "0.125rem 0.5rem",
|
padding: "0.125rem 0.5rem",
|
||||||
background: "#c6f6d5",
|
background:
|
||||||
color: "#22543d",
|
insight.status === "validated"
|
||||||
|
? "#c6f6d5"
|
||||||
|
: insight.status === "active"
|
||||||
|
? "#bee3f8"
|
||||||
|
: "#fed7d7",
|
||||||
|
color:
|
||||||
|
insight.status === "validated"
|
||||||
|
? "#22543d"
|
||||||
|
: insight.status === "active"
|
||||||
|
? "#2c5282"
|
||||||
|
: "#742a2a",
|
||||||
borderRadius: "4px",
|
borderRadius: "4px",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{(insight.confidence * 100).toFixed(0)}% confidence
|
{insight.status}
|
||||||
</span>
|
</span>
|
||||||
<span
|
<span
|
||||||
style={{
|
style={{
|
||||||
|
|
@ -615,7 +604,7 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
color: "#718096",
|
color: "#718096",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{insight.source_refs?.length || 0} sources
|
{insight.supporting_sources.length} sources
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div
|
||||||
|
|
@ -628,7 +617,19 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
>
|
>
|
||||||
<Markdown content={insight.summary} />
|
<Markdown content={insight.summary} />
|
||||||
</div>
|
</div>
|
||||||
{insight.source_refs && insight.source_refs.length > 0 && (
|
{insight.notes && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: "0.75rem",
|
||||||
|
color: "#718096",
|
||||||
|
marginTop: "0.5rem",
|
||||||
|
fontStyle: "italic",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Markdown content={insight.notes} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{insight.supporting_sources.length > 0 && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: "0.75rem",
|
fontSize: "0.75rem",
|
||||||
|
|
@ -637,12 +638,174 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span style={{ fontWeight: "600" }}>Sources: </span>
|
<span style={{ fontWeight: "600" }}>Sources: </span>
|
||||||
{insight.source_refs.map((ref, refIdx) => (
|
{insight.supporting_sources.map((source, srcIdx) => (
|
||||||
<span key={ref.chunk_id}>
|
<span key={`${insight.id}-src-${srcIdx}`}>
|
||||||
{refIdx > 0 && ", "}
|
{srcIdx > 0 && ", "}
|
||||||
<span style={{ fontSize: "0.75rem" }}>
|
{source}
|
||||||
{ref.document_title}
|
|
||||||
</span>
|
</span>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Knowledge Gaps */}
|
||||||
|
{state.context.gaps.length > 0 && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
background: "white",
|
||||||
|
borderRadius: "8px",
|
||||||
|
boxShadow: "0 1px 3px rgba(0,0,0,0.1)",
|
||||||
|
overflow: "hidden",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={() => toggleSection("gaps")}
|
||||||
|
style={{
|
||||||
|
width: "100%",
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
padding: "0.75rem",
|
||||||
|
background: "#edf2f7",
|
||||||
|
border: "1px solid #e2e8f0",
|
||||||
|
borderRadius: "4px",
|
||||||
|
cursor: "pointer",
|
||||||
|
fontSize: "1rem",
|
||||||
|
fontWeight: "600",
|
||||||
|
color: "#2d3748",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span>Knowledge Gaps ({state.context.gaps.length})</span>
|
||||||
|
<span>{expandedSections.gaps ? "▼" : "▶"}</span>
|
||||||
|
</button>
|
||||||
|
{expandedSections.gaps && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
padding: "1rem",
|
||||||
|
background: "#f7fafc",
|
||||||
|
border: "1px solid #e2e8f0",
|
||||||
|
borderTop: "none",
|
||||||
|
borderRadius: "0 0 4px 4px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{state.context.gaps.map((gap) => (
|
||||||
|
<div
|
||||||
|
key={gap.id}
|
||||||
|
style={{
|
||||||
|
padding: "0.75rem",
|
||||||
|
background: "white",
|
||||||
|
borderRadius: "4px",
|
||||||
|
marginBottom: "0.5rem",
|
||||||
|
border: "1px solid #e2e8f0",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
marginBottom: "0.5rem",
|
||||||
|
gap: "0.5rem",
|
||||||
|
flexWrap: "wrap",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<div style={{ display: "flex", gap: "0.5rem" }}>
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontSize: "0.75rem",
|
||||||
|
padding: "0.125rem 0.5rem",
|
||||||
|
background:
|
||||||
|
gap.severity === "critical"
|
||||||
|
? "#fed7d7"
|
||||||
|
: gap.severity === "high"
|
||||||
|
? "#feebc8"
|
||||||
|
: gap.severity === "medium"
|
||||||
|
? "#fef5e7"
|
||||||
|
: "#e6fffa",
|
||||||
|
color:
|
||||||
|
gap.severity === "critical"
|
||||||
|
? "#742a2a"
|
||||||
|
: gap.severity === "high"
|
||||||
|
? "#7c2d12"
|
||||||
|
: gap.severity === "medium"
|
||||||
|
? "#744210"
|
||||||
|
: "#234e52",
|
||||||
|
borderRadius: "4px",
|
||||||
|
fontWeight: "600",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{gap.severity}
|
||||||
|
</span>
|
||||||
|
{gap.blocking && (
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontSize: "0.75rem",
|
||||||
|
padding: "0.125rem 0.5rem",
|
||||||
|
background: "#fed7d7",
|
||||||
|
color: "#742a2a",
|
||||||
|
borderRadius: "4px",
|
||||||
|
fontWeight: "600",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Blocking
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
{gap.resolved && (
|
||||||
|
<span
|
||||||
|
style={{
|
||||||
|
fontSize: "0.75rem",
|
||||||
|
padding: "0.125rem 0.5rem",
|
||||||
|
background: "#c6f6d5",
|
||||||
|
color: "#22543d",
|
||||||
|
borderRadius: "4px",
|
||||||
|
fontWeight: "600",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Resolved
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: "0.875rem",
|
||||||
|
color: "#2d3748",
|
||||||
|
lineHeight: "1.5",
|
||||||
|
marginBottom: "0.5rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Markdown content={gap.description} />
|
||||||
|
</div>
|
||||||
|
{gap.notes && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: "0.75rem",
|
||||||
|
color: "#718096",
|
||||||
|
marginTop: "0.5rem",
|
||||||
|
fontStyle: "italic",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Markdown content={gap.notes} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
{gap.resolved && gap.resolved_by.length > 0 && (
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: "0.75rem",
|
||||||
|
color: "#718096",
|
||||||
|
marginTop: "0.5rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<span style={{ fontWeight: "600" }}>Resolved by: </span>
|
||||||
|
{gap.resolved_by.map((source, srcIdx) => (
|
||||||
|
<span key={`${gap.id}-resolved-${srcIdx}`}>
|
||||||
|
{srcIdx > 0 && ", "}
|
||||||
|
{source}
|
||||||
</span>
|
</span>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -655,7 +818,7 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Final Report */}
|
{/* Final Report */}
|
||||||
{state.final_report && (
|
{state.result && (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
background: "white",
|
background: "white",
|
||||||
|
|
@ -703,7 +866,7 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
color: "#2d3748",
|
color: "#2d3748",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{state.final_report.title}
|
{state.result.question}
|
||||||
</h3>
|
</h3>
|
||||||
<div style={{ marginBottom: "1.5rem" }}>
|
<div style={{ marginBottom: "1.5rem" }}>
|
||||||
<h4
|
<h4
|
||||||
|
|
@ -714,7 +877,7 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
marginBottom: "0.5rem",
|
marginBottom: "0.5rem",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Executive Summary
|
Summary
|
||||||
</h4>
|
</h4>
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
|
|
@ -723,7 +886,7 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
lineHeight: "1.6",
|
lineHeight: "1.6",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Markdown content={state.final_report.summary} />
|
<Markdown content={state.result.summary} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ marginBottom: "1.5rem" }}>
|
<div style={{ marginBottom: "1.5rem" }}>
|
||||||
|
|
@ -735,7 +898,7 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
marginBottom: "0.5rem",
|
marginBottom: "0.5rem",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Main Findings
|
Key Findings
|
||||||
</h4>
|
</h4>
|
||||||
<ul
|
<ul
|
||||||
style={{
|
style={{
|
||||||
|
|
@ -745,7 +908,7 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
lineHeight: "1.6",
|
lineHeight: "1.6",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{state.final_report.findings.map((finding, idx) => (
|
{state.result.findings.map((finding, idx) => (
|
||||||
<li
|
<li
|
||||||
key={`finding-${idx}-${finding.substring(0, 30)}`}
|
key={`finding-${idx}-${finding.substring(0, 30)}`}
|
||||||
style={{ marginBottom: "0.5rem" }}
|
style={{ marginBottom: "0.5rem" }}
|
||||||
|
|
@ -774,7 +937,7 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
lineHeight: "1.6",
|
lineHeight: "1.6",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{state.final_report.conclusions.map((conclusion, idx) => (
|
{state.result.conclusions.map((conclusion, idx) => (
|
||||||
<li
|
<li
|
||||||
key={`conclusion-${idx}-${conclusion.substring(0, 30)}`}
|
key={`conclusion-${idx}-${conclusion.substring(0, 30)}`}
|
||||||
style={{ marginBottom: "0.5rem" }}
|
style={{ marginBottom: "0.5rem" }}
|
||||||
|
|
@ -784,6 +947,27 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
<div style={{ marginBottom: "1.5rem" }}>
|
||||||
|
<h4
|
||||||
|
style={{
|
||||||
|
fontSize: "0.875rem",
|
||||||
|
fontWeight: "600",
|
||||||
|
color: "#718096",
|
||||||
|
marginBottom: "0.5rem",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Methodology
|
||||||
|
</h4>
|
||||||
|
<div
|
||||||
|
style={{
|
||||||
|
fontSize: "0.875rem",
|
||||||
|
color: "#4a5568",
|
||||||
|
lineHeight: "1.6",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Markdown content={state.result.methodology} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4
|
<h4
|
||||||
style={{
|
style={{
|
||||||
|
|
@ -793,10 +977,8 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
marginBottom: "0.5rem",
|
marginBottom: "0.5rem",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Citations
|
Insights Used ({state.result.insights_used.length})
|
||||||
</h4>
|
</h4>
|
||||||
{state.final_report.citations &&
|
|
||||||
state.final_report.citations.length > 0 ? (
|
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
display: "flex",
|
display: "flex",
|
||||||
|
|
@ -804,9 +986,13 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
gap: "0.5rem",
|
gap: "0.5rem",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{state.final_report.citations.map((citation) => (
|
{state.result.insights_used.map((insightId, idx) => {
|
||||||
|
const insight = state.context.insights.find(
|
||||||
|
(i) => i.id === insightId,
|
||||||
|
);
|
||||||
|
return (
|
||||||
<div
|
<div
|
||||||
key={citation.document_uri}
|
key={`insight-${idx}-${insightId}`}
|
||||||
style={{
|
style={{
|
||||||
padding: "0.5rem",
|
padding: "0.5rem",
|
||||||
background: "#f7fafc",
|
background: "#f7fafc",
|
||||||
|
|
@ -814,45 +1000,31 @@ export default function StateDisplay({ state }: StateDisplayProps) {
|
||||||
border: "1px solid #e2e8f0",
|
border: "1px solid #e2e8f0",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
{insight ? (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: "0.875rem",
|
fontSize: "0.875rem",
|
||||||
fontWeight: "600",
|
|
||||||
color: "#2d3748",
|
color: "#2d3748",
|
||||||
marginBottom: "0.25rem",
|
lineHeight: "1.4",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{citation.document_title}
|
<Markdown content={insight.summary} />
|
||||||
</div>
|
|
||||||
<div
|
|
||||||
style={{
|
|
||||||
fontSize: "0.75rem",
|
|
||||||
color: "#718096",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{citation.chunk_ids.length} chunk
|
|
||||||
{citation.chunk_ids.length !== 1 ? "s" : ""}{" "}
|
|
||||||
referenced
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div
|
<div
|
||||||
style={{
|
style={{
|
||||||
fontSize: "0.75rem",
|
fontSize: "0.875rem",
|
||||||
color: "#718096",
|
color: "#718096",
|
||||||
lineHeight: "1.4",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{state.final_report.sources?.map((source) => (
|
Insight ID: {insightId}
|
||||||
<div key={source} style={{ marginBottom: "0.25rem" }}>
|
|
||||||
{source}
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
116
examples/ag-ui-research/frontend/package-lock.json
generated
116
examples/ag-ui-research/frontend/package-lock.json
generated
|
|
@ -42,6 +42,7 @@
|
||||||
"version": "0.0.40",
|
"version": "0.0.40",
|
||||||
"resolved": "https://registry.npmjs.org/@ag-ui/client/-/client-0.0.40.tgz",
|
"resolved": "https://registry.npmjs.org/@ag-ui/client/-/client-0.0.40.tgz",
|
||||||
"integrity": "sha512-4ftyZgMN7DIAX64k7Mdex/KGq7lfz8yxEKzniqosD6TE/xk65k4Z0v3bxTzPk2iS2+Cj2uVBgFkb5lC7k5Loqg==",
|
"integrity": "sha512-4ftyZgMN7DIAX64k7Mdex/KGq7lfz8yxEKzniqosD6TE/xk65k4Z0v3bxTzPk2iS2+Cj2uVBgFkb5lC7k5Loqg==",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ag-ui/core": "0.0.39",
|
"@ag-ui/core": "0.0.39",
|
||||||
"@ag-ui/encoder": "0.0.39",
|
"@ag-ui/encoder": "0.0.39",
|
||||||
|
|
@ -58,6 +59,7 @@
|
||||||
"version": "0.0.39",
|
"version": "0.0.39",
|
||||||
"resolved": "https://registry.npmjs.org/@ag-ui/core/-/core-0.0.39.tgz",
|
"resolved": "https://registry.npmjs.org/@ag-ui/core/-/core-0.0.39.tgz",
|
||||||
"integrity": "sha512-T5Hp4oFkQ+H5MynWAvSwrX/rNYJOD+PJ4qPQ0o771oSZQAxoIvDDft47Cx5wRyBNNLXAe1RWqJjfWUUwJFNKqA==",
|
"integrity": "sha512-T5Hp4oFkQ+H5MynWAvSwrX/rNYJOD+PJ4qPQ0o771oSZQAxoIvDDft47Cx5wRyBNNLXAe1RWqJjfWUUwJFNKqA==",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"rxjs": "7.8.1",
|
"rxjs": "7.8.1",
|
||||||
"zod": "^3.22.4"
|
"zod": "^3.22.4"
|
||||||
|
|
@ -67,6 +69,7 @@
|
||||||
"version": "0.0.39",
|
"version": "0.0.39",
|
||||||
"resolved": "https://registry.npmjs.org/@ag-ui/encoder/-/encoder-0.0.39.tgz",
|
"resolved": "https://registry.npmjs.org/@ag-ui/encoder/-/encoder-0.0.39.tgz",
|
||||||
"integrity": "sha512-6fsoFwPWkStK7Uyj3pwBn7+aQjUWf7pbDTSI43cD53sBLvTr5oEFNnoKOzRfC5UqvHc4JjUIuLKPQyjHRwWg4g==",
|
"integrity": "sha512-6fsoFwPWkStK7Uyj3pwBn7+aQjUWf7pbDTSI43cD53sBLvTr5oEFNnoKOzRfC5UqvHc4JjUIuLKPQyjHRwWg4g==",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ag-ui/core": "0.0.39",
|
"@ag-ui/core": "0.0.39",
|
||||||
"@ag-ui/proto": "0.0.39"
|
"@ag-ui/proto": "0.0.39"
|
||||||
|
|
@ -92,6 +95,7 @@
|
||||||
"version": "0.0.39",
|
"version": "0.0.39",
|
||||||
"resolved": "https://registry.npmjs.org/@ag-ui/proto/-/proto-0.0.39.tgz",
|
"resolved": "https://registry.npmjs.org/@ag-ui/proto/-/proto-0.0.39.tgz",
|
||||||
"integrity": "sha512-xlj/PzZHkJ3CgoQC5QP9g7DEl/78wUK1+A2rdkoLKoNAMOkM2g6jKw0N88iFIh5GZhtiCNN2wb8XwRWPYx9XQQ==",
|
"integrity": "sha512-xlj/PzZHkJ3CgoQC5QP9g7DEl/78wUK1+A2rdkoLKoNAMOkM2g6jKw0N88iFIh5GZhtiCNN2wb8XwRWPYx9XQQ==",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ag-ui/core": "0.0.39",
|
"@ag-ui/core": "0.0.39",
|
||||||
"@bufbuild/protobuf": "^2.2.5",
|
"@bufbuild/protobuf": "^2.2.5",
|
||||||
|
|
@ -127,6 +131,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz",
|
||||||
"integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==",
|
"integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-crypto/util": "^5.2.0",
|
"@aws-crypto/util": "^5.2.0",
|
||||||
"@aws-sdk/types": "^3.222.0",
|
"@aws-sdk/types": "^3.222.0",
|
||||||
|
|
@ -161,6 +166,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-agent-runtime/-/client-bedrock-agent-runtime-3.911.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-agent-runtime/-/client-bedrock-agent-runtime-3.911.0.tgz",
|
||||||
"integrity": "sha512-gXxE6CecfTVM9Uuuja2W69WBT0XoEi0AyTHuN4E7RC7s0SbVZvkCmCgtJ60LTsg7akAa8+AEbIn8aNqxkxV7Kw==",
|
"integrity": "sha512-gXxE6CecfTVM9Uuuja2W69WBT0XoEi0AyTHuN4E7RC7s0SbVZvkCmCgtJ60LTsg7akAa8+AEbIn8aNqxkxV7Kw==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-crypto/sha256-browser": "5.2.0",
|
"@aws-crypto/sha256-browser": "5.2.0",
|
||||||
"@aws-crypto/sha256-js": "5.2.0",
|
"@aws-crypto/sha256-js": "5.2.0",
|
||||||
|
|
@ -240,6 +246,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.911.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/client-bedrock-runtime/-/client-bedrock-runtime-3.911.0.tgz",
|
||||||
"integrity": "sha512-DScoogLAX1WaDF7N3sDvA4l7PKUXRqZWTP1sTjUfUK3hwpAm624RfoQFoxgz5wQPv1zs5Slvntmg8WnPo0T9LQ==",
|
"integrity": "sha512-DScoogLAX1WaDF7N3sDvA4l7PKUXRqZWTP1sTjUfUK3hwpAm624RfoQFoxgz5wQPv1zs5Slvntmg8WnPo0T9LQ==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-crypto/sha256-browser": "5.2.0",
|
"@aws-crypto/sha256-browser": "5.2.0",
|
||||||
"@aws-crypto/sha256-js": "5.2.0",
|
"@aws-crypto/sha256-js": "5.2.0",
|
||||||
|
|
@ -325,6 +332,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/client-kendra/-/client-kendra-3.911.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/client-kendra/-/client-kendra-3.911.0.tgz",
|
||||||
"integrity": "sha512-insxvWLbh5mRsymBvsq+O/yPgpF1RnYUi2cNYzJDLzHnpsvpdtvrKO1Ymg0Trk32Xh5dW/9W7IMrqI1qDMzBrw==",
|
"integrity": "sha512-insxvWLbh5mRsymBvsq+O/yPgpF1RnYUi2cNYzJDLzHnpsvpdtvrKO1Ymg0Trk32Xh5dW/9W7IMrqI1qDMzBrw==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-crypto/sha256-browser": "5.2.0",
|
"@aws-crypto/sha256-browser": "5.2.0",
|
||||||
"@aws-crypto/sha256-js": "5.2.0",
|
"@aws-crypto/sha256-js": "5.2.0",
|
||||||
|
|
@ -632,6 +640,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.911.0.tgz",
|
"resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.911.0.tgz",
|
||||||
"integrity": "sha512-4oGpLwgQCKNtVoJROztJ4v7lZLhCqcUMX6pe/DQ2aU0TktZX7EczMCIEGjVo5b7yHwSNWt2zW0tDdgVUTsMHPw==",
|
"integrity": "sha512-4oGpLwgQCKNtVoJROztJ4v7lZLhCqcUMX6pe/DQ2aU0TktZX7EczMCIEGjVo5b7yHwSNWt2zW0tDdgVUTsMHPw==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/credential-provider-env": "3.911.0",
|
"@aws-sdk/credential-provider-env": "3.911.0",
|
||||||
"@aws-sdk/credential-provider-http": "3.911.0",
|
"@aws-sdk/credential-provider-http": "3.911.0",
|
||||||
|
|
@ -1387,7 +1396,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/@browserbasehq/sdk/-/sdk-2.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@browserbasehq/sdk/-/sdk-2.6.0.tgz",
|
||||||
"integrity": "sha512-83iXP5D7xMm8Wyn66TUaUrgoByCmAJuoMoZQI3sGg3JAiMlTfnCIMqyVBoNSaItaPIkaCnrsj6LiusmXV2X9YA==",
|
"integrity": "sha512-83iXP5D7xMm8Wyn66TUaUrgoByCmAJuoMoZQI3sGg3JAiMlTfnCIMqyVBoNSaItaPIkaCnrsj6LiusmXV2X9YA==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^18.11.18",
|
"@types/node": "^18.11.18",
|
||||||
"@types/node-fetch": "^2.6.4",
|
"@types/node-fetch": "^2.6.4",
|
||||||
|
|
@ -1403,7 +1411,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz",
|
||||||
"integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
|
"integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~5.26.4"
|
||||||
}
|
}
|
||||||
|
|
@ -1412,15 +1419,13 @@
|
||||||
"version": "5.26.5",
|
"version": "5.26.5",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@browserbasehq/stagehand": {
|
"node_modules/@browserbasehq/stagehand": {
|
||||||
"version": "1.14.0",
|
"version": "1.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/@browserbasehq/stagehand/-/stagehand-1.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/@browserbasehq/stagehand/-/stagehand-1.14.0.tgz",
|
||||||
"integrity": "sha512-Hi/EzgMFWz+FKyepxHTrqfTPjpsuBS4zRy3e9sbMpBgLPv+9c0R+YZEvS7Bw4mTS66QtvvURRT6zgDGFotthVQ==",
|
"integrity": "sha512-Hi/EzgMFWz+FKyepxHTrqfTPjpsuBS4zRy3e9sbMpBgLPv+9c0R+YZEvS7Bw4mTS66QtvvURRT6zgDGFotthVQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@anthropic-ai/sdk": "^0.27.3",
|
"@anthropic-ai/sdk": "^0.27.3",
|
||||||
"@browserbasehq/sdk": "^2.0.0",
|
"@browserbasehq/sdk": "^2.0.0",
|
||||||
|
|
@ -1440,7 +1445,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.27.3.tgz",
|
"resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.27.3.tgz",
|
||||||
"integrity": "sha512-IjLt0gd3L4jlOfilxVXTifn42FnVffMgDC04RJK1KDZpmkBWLv0XC92MVVmkxrFZNS/7l3xWgP/I3nqtX1sQHw==",
|
"integrity": "sha512-IjLt0gd3L4jlOfilxVXTifn42FnVffMgDC04RJK1KDZpmkBWLv0XC92MVVmkxrFZNS/7l3xWgP/I3nqtX1sQHw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^18.11.18",
|
"@types/node": "^18.11.18",
|
||||||
"@types/node-fetch": "^2.6.4",
|
"@types/node-fetch": "^2.6.4",
|
||||||
|
|
@ -1456,7 +1460,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz",
|
||||||
"integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
|
"integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~5.26.4"
|
||||||
}
|
}
|
||||||
|
|
@ -1465,8 +1468,7 @@
|
||||||
"version": "5.26.5",
|
"version": "5.26.5",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@bufbuild/protobuf": {
|
"node_modules/@bufbuild/protobuf": {
|
||||||
"version": "2.9.0",
|
"version": "2.9.0",
|
||||||
|
|
@ -2087,7 +2089,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/@ibm-cloud/watsonx-ai/-/watsonx-ai-1.7.0.tgz",
|
"resolved": "https://registry.npmjs.org/@ibm-cloud/watsonx-ai/-/watsonx-ai-1.7.0.tgz",
|
||||||
"integrity": "sha512-TmLaoFXmLc7yVFJIQS25mzZcuWfju4JmRXcO62KthDKNENyPpXXJukrHN6gXfv1BotzFt0M2kyRnO1Vt8ZLlxQ==",
|
"integrity": "sha512-TmLaoFXmLc7yVFJIQS25mzZcuWfju4JmRXcO62KthDKNENyPpXXJukrHN6gXfv1BotzFt0M2kyRnO1Vt8ZLlxQ==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^18.0.0",
|
"@types/node": "^18.0.0",
|
||||||
"extend": "3.0.2",
|
"extend": "3.0.2",
|
||||||
|
|
@ -2103,7 +2104,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz",
|
||||||
"integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
|
"integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~5.26.4"
|
||||||
}
|
}
|
||||||
|
|
@ -2112,8 +2112,7 @@
|
||||||
"version": "5.26.5",
|
"version": "5.26.5",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@img/colour": {
|
"node_modules/@img/colour": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
|
|
@ -2558,6 +2557,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/@langchain/aws/-/aws-0.1.15.tgz",
|
"resolved": "https://registry.npmjs.org/@langchain/aws/-/aws-0.1.15.tgz",
|
||||||
"integrity": "sha512-oyOMhTHP0rxdSCVI/g5KXYCOs9Kq/FpXMZbOk1JSIUoaIzUg4p6d98lsHu7erW//8NSaT+SX09QRbVDAgt7pNA==",
|
"integrity": "sha512-oyOMhTHP0rxdSCVI/g5KXYCOs9Kq/FpXMZbOk1JSIUoaIzUg4p6d98lsHu7erW//8NSaT+SX09QRbVDAgt7pNA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-sdk/client-bedrock-agent-runtime": "^3.755.0",
|
"@aws-sdk/client-bedrock-agent-runtime": "^3.755.0",
|
||||||
"@aws-sdk/client-bedrock-runtime": "^3.840.0",
|
"@aws-sdk/client-bedrock-runtime": "^3.840.0",
|
||||||
|
|
@ -3110,6 +3110,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.3.78.tgz",
|
"resolved": "https://registry.npmjs.org/@langchain/core/-/core-0.3.78.tgz",
|
||||||
"integrity": "sha512-Nn0x9erQlK3zgtRU1Z8NUjLuyW0gzdclMsvLQ6wwLeDqV91pE+YKl6uQb+L2NUDs4F0N7c2Zncgz46HxrvPzuA==",
|
"integrity": "sha512-Nn0x9erQlK3zgtRU1Z8NUjLuyW0gzdclMsvLQ6wwLeDqV91pE+YKl6uQb+L2NUDs4F0N7c2Zncgz46HxrvPzuA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cfworker/json-schema": "^4.0.2",
|
"@cfworker/json-schema": "^4.0.2",
|
||||||
"ansi-styles": "^5.0.0",
|
"ansi-styles": "^5.0.0",
|
||||||
|
|
@ -3203,7 +3204,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/@langchain/langgraph-sdk/-/langgraph-sdk-0.1.10.tgz",
|
"resolved": "https://registry.npmjs.org/@langchain/langgraph-sdk/-/langgraph-sdk-0.1.10.tgz",
|
||||||
"integrity": "sha512-9srSCb2bSvcvehMgjA2sMMwX0o1VUgPN6ghwm5Fwc9JGAKsQa6n1S4eCwy1h4abuYxwajH5n3spBw+4I2WYbgw==",
|
"integrity": "sha512-9srSCb2bSvcvehMgjA2sMMwX0o1VUgPN6ghwm5Fwc9JGAKsQa6n1S4eCwy1h4abuYxwajH5n3spBw+4I2WYbgw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/json-schema": "^7.0.15",
|
"@types/json-schema": "^7.0.15",
|
||||||
"p-queue": "^6.6.2",
|
"p-queue": "^6.6.2",
|
||||||
|
|
@ -3236,7 +3236,6 @@
|
||||||
"https://github.com/sponsors/ctavan"
|
"https://github.com/sponsors/ctavan"
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"uuid": "dist/bin/uuid"
|
"uuid": "dist/bin/uuid"
|
||||||
}
|
}
|
||||||
|
|
@ -4462,6 +4461,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz",
|
||||||
"integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==",
|
"integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@smithy/util-buffer-from": "^2.2.0",
|
"@smithy/util-buffer-from": "^2.2.0",
|
||||||
"tslib": "^2.6.2"
|
"tslib": "^2.6.2"
|
||||||
|
|
@ -4535,8 +4535,7 @@
|
||||||
"version": "0.3.0",
|
"version": "0.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tokenizer/token/-/token-0.3.0.tgz",
|
||||||
"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==",
|
"integrity": "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/debug": {
|
"node_modules/@types/debug": {
|
||||||
"version": "4.1.12",
|
"version": "4.1.12",
|
||||||
|
|
@ -4628,6 +4627,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.2.tgz",
|
||||||
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
"integrity": "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"csstype": "^3.0.2"
|
"csstype": "^3.0.2"
|
||||||
}
|
}
|
||||||
|
|
@ -4658,8 +4658,7 @@
|
||||||
"version": "4.0.5",
|
"version": "4.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz",
|
||||||
"integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
|
"integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/unist": {
|
"node_modules/@types/unist": {
|
||||||
"version": "2.0.11",
|
"version": "2.0.11",
|
||||||
|
|
@ -5176,6 +5175,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.2.tgz",
|
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.2.tgz",
|
||||||
"integrity": "sha512-3kMVRF2io8N8pY1IFIXlho9r8IPUUIfHe2hYVtiebvAzU2XeQFXTv+XI4WX+TnXmtwXMDcjngcpkiPM0O9PvLw==",
|
"integrity": "sha512-3kMVRF2io8N8pY1IFIXlho9r8IPUUIfHe2hYVtiebvAzU2XeQFXTv+XI4WX+TnXmtwXMDcjngcpkiPM0O9PvLw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/validator": "^13.11.8",
|
"@types/validator": "^13.11.8",
|
||||||
"libphonenumber-js": "^1.11.1",
|
"libphonenumber-js": "^1.11.1",
|
||||||
|
|
@ -5785,6 +5785,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"strnum": "^2.1.0"
|
"strnum": "^2.1.0"
|
||||||
},
|
},
|
||||||
|
|
@ -5810,7 +5811,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz",
|
"resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz",
|
||||||
"integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==",
|
"integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"readable-web-to-node-stream": "^3.0.0",
|
"readable-web-to-node-stream": "^3.0.0",
|
||||||
"strtok3": "^6.2.4",
|
"strtok3": "^6.2.4",
|
||||||
|
|
@ -5876,7 +5876,6 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4.0"
|
"node": ">=4.0"
|
||||||
},
|
},
|
||||||
|
|
@ -5947,6 +5946,20 @@
|
||||||
"node": ">= 0.6"
|
"node": ">= 0.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fsevents": {
|
||||||
|
"version": "2.3.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
|
||||||
|
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
|
||||||
|
"hasInstallScript": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"optional": true,
|
||||||
|
"os": [
|
||||||
|
"darwin"
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/function-bind": {
|
"node_modules/function-bind": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
|
||||||
|
|
@ -6035,6 +6048,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.9.0.tgz",
|
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.9.0.tgz",
|
||||||
"integrity": "sha512-f7aQCJODJFmYWN6PeNKzgvy9LI2tYmXnzpNDHEjG5sDNPgGb2FXQyTBnXeSH+PAtpKESFD+LmHw3Ox3mN7e1Fg==",
|
"integrity": "sha512-f7aQCJODJFmYWN6PeNKzgvy9LI2tYmXnzpNDHEjG5sDNPgGb2FXQyTBnXeSH+PAtpKESFD+LmHw3Ox3mN7e1Fg==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"arrify": "^2.0.0",
|
"arrify": "^2.0.0",
|
||||||
"base64-js": "^1.3.0",
|
"base64-js": "^1.3.0",
|
||||||
|
|
@ -6083,6 +6097,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz",
|
"resolved": "https://registry.npmjs.org/graphql/-/graphql-16.11.0.tgz",
|
||||||
"integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==",
|
"integrity": "sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
|
"node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0"
|
||||||
}
|
}
|
||||||
|
|
@ -6117,6 +6132,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/graphql-scalars/-/graphql-scalars-1.25.0.tgz",
|
"resolved": "https://registry.npmjs.org/graphql-scalars/-/graphql-scalars-1.25.0.tgz",
|
||||||
"integrity": "sha512-b0xyXZeRFkne4Eq7NAnL400gStGqG/Sx9VqX0A05nHyEbv57UJnWKsjNnrpVqv5e/8N1MUxkt0wwcRXbiyKcFg==",
|
"integrity": "sha512-b0xyXZeRFkne4Eq7NAnL400gStGqG/Sx9VqX0A05nHyEbv57UJnWKsjNnrpVqv5e/8N1MUxkt0wwcRXbiyKcFg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"tslib": "^2.5.0"
|
"tslib": "^2.5.0"
|
||||||
},
|
},
|
||||||
|
|
@ -6132,6 +6148,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/graphql-yoga/-/graphql-yoga-5.16.0.tgz",
|
"resolved": "https://registry.npmjs.org/graphql-yoga/-/graphql-yoga-5.16.0.tgz",
|
||||||
"integrity": "sha512-/R2dJea7WgvNlXRU4F8iFwWd95Qn1mN+R+yC8XBs1wKjUzr0Pvv8cGYtt6UUcVHw5CiDEtu7iQY5oOe3sDAWCQ==",
|
"integrity": "sha512-/R2dJea7WgvNlXRU4F8iFwWd95Qn1mN+R+yC8XBs1wKjUzr0Pvv8cGYtt6UUcVHw5CiDEtu7iQY5oOe3sDAWCQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@envelop/core": "^5.3.0",
|
"@envelop/core": "^5.3.0",
|
||||||
"@envelop/instrumentation": "^1.0.0",
|
"@envelop/instrumentation": "^1.0.0",
|
||||||
|
|
@ -6709,7 +6726,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/ibm-cloud-sdk-core/-/ibm-cloud-sdk-core-5.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/ibm-cloud-sdk-core/-/ibm-cloud-sdk-core-5.4.3.tgz",
|
||||||
"integrity": "sha512-D0lvClcoCp/HXyaFlCbOT4aTYgGyeIb4ncxZpxRuiuw7Eo79C6c49W53+8WJRD9nxzT5vrIdaky3NBcTdBtaEg==",
|
"integrity": "sha512-D0lvClcoCp/HXyaFlCbOT4aTYgGyeIb4ncxZpxRuiuw7Eo79C6c49W53+8WJRD9nxzT5vrIdaky3NBcTdBtaEg==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/debug": "^4.1.12",
|
"@types/debug": "^4.1.12",
|
||||||
"@types/node": "^18.19.80",
|
"@types/node": "^18.19.80",
|
||||||
|
|
@ -6736,7 +6752,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz",
|
||||||
"integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
|
"integrity": "sha512-GRaXQx6jGfL8sKfaIDD6OupbIHBr9jv7Jnaml9tB7l4v068PAOXqfcujMMo5PhbIs6ggR1XODELqahT2R8v0fg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~5.26.4"
|
||||||
}
|
}
|
||||||
|
|
@ -6745,8 +6760,7 @@
|
||||||
"version": "5.26.5",
|
"version": "5.26.5",
|
||||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
|
||||||
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/iconv-lite": {
|
"node_modules/iconv-lite": {
|
||||||
"version": "0.4.24",
|
"version": "0.4.24",
|
||||||
|
|
@ -6905,8 +6919,7 @@
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
|
||||||
"integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==",
|
"integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/jose": {
|
"node_modules/jose": {
|
||||||
"version": "5.10.0",
|
"version": "5.10.0",
|
||||||
|
|
@ -6976,7 +6989,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz",
|
||||||
"integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
|
"integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jws": "^3.2.2",
|
"jws": "^3.2.2",
|
||||||
"lodash.includes": "^4.3.0",
|
"lodash.includes": "^4.3.0",
|
||||||
|
|
@ -6999,7 +7011,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz",
|
||||||
"integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
|
"integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"buffer-equal-constant-time": "^1.0.1",
|
"buffer-equal-constant-time": "^1.0.1",
|
||||||
"ecdsa-sig-formatter": "1.0.11",
|
"ecdsa-sig-formatter": "1.0.11",
|
||||||
|
|
@ -7011,7 +7022,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz",
|
||||||
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
"integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"jwa": "^1.4.1",
|
"jwa": "^1.4.1",
|
||||||
"safe-buffer": "^5.0.1"
|
"safe-buffer": "^5.0.1"
|
||||||
|
|
@ -7242,50 +7252,43 @@
|
||||||
"version": "4.3.0",
|
"version": "4.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz",
|
||||||
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
|
"integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/lodash.isboolean": {
|
"node_modules/lodash.isboolean": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz",
|
||||||
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
|
"integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/lodash.isinteger": {
|
"node_modules/lodash.isinteger": {
|
||||||
"version": "4.0.4",
|
"version": "4.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz",
|
||||||
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
|
"integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/lodash.isnumber": {
|
"node_modules/lodash.isnumber": {
|
||||||
"version": "3.0.3",
|
"version": "3.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz",
|
||||||
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
|
"integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/lodash.isplainobject": {
|
"node_modules/lodash.isplainobject": {
|
||||||
"version": "4.0.6",
|
"version": "4.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
|
||||||
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/lodash.isstring": {
|
"node_modules/lodash.isstring": {
|
||||||
"version": "4.0.1",
|
"version": "4.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz",
|
||||||
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
|
"integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/lodash.once": {
|
"node_modules/lodash.once": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz",
|
||||||
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
|
"integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/long": {
|
"node_modules/long": {
|
||||||
"version": "5.3.2",
|
"version": "5.3.2",
|
||||||
|
|
@ -8801,6 +8804,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz",
|
"resolved": "https://registry.npmjs.org/openai/-/openai-4.104.0.tgz",
|
||||||
"integrity": "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==",
|
"integrity": "sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^18.11.18",
|
"@types/node": "^18.11.18",
|
||||||
"@types/node-fetch": "^2.6.4",
|
"@types/node-fetch": "^2.6.4",
|
||||||
|
|
@ -8953,7 +8957,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz",
|
||||||
"integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==",
|
"integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
},
|
},
|
||||||
|
|
@ -9054,7 +9057,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.0.tgz",
|
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.56.0.tgz",
|
||||||
"integrity": "sha512-1SXl7pMfemAMSDn5rkPeZljxOCYAmQnYLBTExuh6E8USHXGSX3dx6lYZN/xPpTz1vimXmPA9CDnILvmJaB8aSQ==",
|
"integrity": "sha512-1SXl7pMfemAMSDn5rkPeZljxOCYAmQnYLBTExuh6E8USHXGSX3dx6lYZN/xPpTz1vimXmPA9CDnILvmJaB8aSQ==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"playwright-core": "cli.js"
|
"playwright-core": "cli.js"
|
||||||
},
|
},
|
||||||
|
|
@ -9192,15 +9194,13 @@
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/psl": {
|
"node_modules/psl": {
|
||||||
"version": "1.15.0",
|
"version": "1.15.0",
|
||||||
"resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz",
|
||||||
"integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==",
|
"integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"punycode": "^2.3.1"
|
"punycode": "^2.3.1"
|
||||||
},
|
},
|
||||||
|
|
@ -9223,7 +9223,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
|
||||||
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
|
|
@ -9247,8 +9246,7 @@
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
|
||||||
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
|
"integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/quick-format-unescaped": {
|
"node_modules/quick-format-unescaped": {
|
||||||
"version": "4.0.4",
|
"version": "4.0.4",
|
||||||
|
|
@ -9285,6 +9283,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react/-/react-19.2.0.tgz",
|
||||||
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
|
"integrity": "sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
|
|
@ -9294,6 +9293,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.0.tgz",
|
||||||
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
|
"integrity": "sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"scheduler": "^0.27.0"
|
"scheduler": "^0.27.0"
|
||||||
},
|
},
|
||||||
|
|
@ -9376,7 +9376,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/readable-web-to-node-stream/-/readable-web-to-node-stream-3.0.4.tgz",
|
||||||
"integrity": "sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==",
|
"integrity": "sha512-9nX56alTf5bwXQ3ZDipHJhusu9NTQJ/CVPtb/XHAJCXihZeitfJvIRS4GqQ/mfIoOE3IelHMrpayVrosdHBuLw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"readable-stream": "^4.7.0"
|
"readable-stream": "^4.7.0"
|
||||||
},
|
},
|
||||||
|
|
@ -10385,8 +10384,7 @@
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
|
||||||
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
|
"integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==",
|
||||||
"license": "MIT",
|
"license": "MIT"
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/retry": {
|
"node_modules/retry": {
|
||||||
"version": "0.13.1",
|
"version": "0.13.1",
|
||||||
|
|
@ -10402,7 +10400,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/retry-axios/-/retry-axios-2.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/retry-axios/-/retry-axios-2.6.0.tgz",
|
||||||
"integrity": "sha512-pOLi+Gdll3JekwuFjXO3fTq+L9lzMQGcSq7M5gIjExcl3Gu1hd4XXuf5o3+LuSBsaULQH7DiNbsqPd1chVpQGQ==",
|
"integrity": "sha512-pOLi+Gdll3JekwuFjXO3fTq+L9lzMQGcSq7M5gIjExcl3Gu1hd4XXuf5o3+LuSBsaULQH7DiNbsqPd1chVpQGQ==",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.7.0"
|
"node": ">=10.7.0"
|
||||||
},
|
},
|
||||||
|
|
@ -10820,7 +10817,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz",
|
||||||
"integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==",
|
"integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tokenizer/token": "^0.3.0",
|
"@tokenizer/token": "^0.3.0",
|
||||||
"peek-readable": "^4.1.0"
|
"peek-readable": "^4.1.0"
|
||||||
|
|
@ -10930,7 +10926,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz",
|
||||||
"integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==",
|
"integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tokenizer/token": "^0.3.0",
|
"@tokenizer/token": "^0.3.0",
|
||||||
"ieee754": "^1.2.1"
|
"ieee754": "^1.2.1"
|
||||||
|
|
@ -10948,7 +10943,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
|
||||||
"integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
|
"integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
|
||||||
"license": "BSD-3-Clause",
|
"license": "BSD-3-Clause",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"psl": "^1.1.33",
|
"psl": "^1.1.33",
|
||||||
"punycode": "^2.1.1",
|
"punycode": "^2.1.1",
|
||||||
|
|
@ -11255,7 +11249,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
|
||||||
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
|
"integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">= 4.0.0"
|
"node": ">= 4.0.0"
|
||||||
}
|
}
|
||||||
|
|
@ -11280,7 +11273,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||||
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
"integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"querystringify": "^2.1.1",
|
"querystringify": "^2.1.1",
|
||||||
"requires-port": "^1.0.0"
|
"requires-port": "^1.0.0"
|
||||||
|
|
@ -11578,7 +11570,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
|
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
|
||||||
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
|
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=10.0.0"
|
"node": ">=10.0.0"
|
||||||
},
|
},
|
||||||
|
|
@ -11663,6 +11654,7 @@
|
||||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||||
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
"funding": {
|
"funding": {
|
||||||
"url": "https://github.com/sponsors/colinhacks"
|
"url": "https://github.com/sponsors/colinhacks"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,23 @@
|
||||||
# haiku.rag configuration for ag-ui-research example
|
# haiku.rag configuration for ag-ui-research example
|
||||||
# Copy to haiku.rag.yaml and customize
|
# Copy to haiku.rag.yaml and customize
|
||||||
|
|
||||||
qa:
|
research:
|
||||||
provider: ollama
|
provider: ollama
|
||||||
model: gpt-oss:latest
|
model: gpt-oss:latest
|
||||||
|
max_iterations: 3
|
||||||
|
confidence_threshold: 0.8
|
||||||
|
max_concurrency: 1
|
||||||
|
|
||||||
providers:
|
providers:
|
||||||
ollama:
|
ollama:
|
||||||
base_url: http://host.docker.internal:11434
|
base_url: http://host.docker.internal:11434
|
||||||
|
|
||||||
# For OpenAI:
|
# For OpenAI:
|
||||||
# qa:
|
# research:
|
||||||
# provider: openai
|
# provider: openai
|
||||||
# model: gpt-4o-mini
|
# model: gpt-4o-mini
|
||||||
|
|
||||||
# For Anthropic:
|
# For Anthropic:
|
||||||
# qa:
|
# research:
|
||||||
# provider: anthropic
|
# provider: anthropic
|
||||||
# model: claude-3-5-haiku-20241022
|
# model: claude-3-5-haiku-20241022
|
||||||
|
|
|
||||||
|
|
@ -156,8 +156,11 @@ def create_search_node[AgentDepsT: GraphAgentDeps](
|
||||||
deps: GraphDeps = ctx.deps # type: ignore[assignment]
|
deps: GraphDeps = ctx.deps # type: ignore[assignment]
|
||||||
sub_q = ctx.inputs
|
sub_q = ctx.inputs
|
||||||
|
|
||||||
|
# Create unique step name from question text
|
||||||
|
step_name = f"search: {sub_q}"
|
||||||
|
|
||||||
if deps.agui_emitter and with_step_wrapper:
|
if deps.agui_emitter and with_step_wrapper:
|
||||||
deps.agui_emitter.start_step("search_one")
|
deps.agui_emitter.start_step(step_name)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Create semaphore if not already provided
|
# Create semaphore if not already provided
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue