diff --git a/Makefile b/Makefile index b2e7fc3a5..4c89fa783 100644 --- a/Makefile +++ b/Makefile @@ -175,6 +175,22 @@ sandbox-stop: rm -f .sandbox.pid .sandbox.journal; \ echo "Sandbox stopped." +# Verify API baselines against running sandbox +verify-api: .installed + @echo "Verifying API baselines (sandbox)..." + @$(MAKE) sandbox + @SANDBOX_JOURNAL=$$(cat .sandbox.journal); \ + CONVEY_PORT=$$(cat "$$SANDBOX_JOURNAL/health/convey.port"); \ + RESULT=0; \ + JOURNAL_PATH="$$SANDBOX_JOURNAL" $(VENV_BIN)/python tests/verify_api.py verify --base-url "http://localhost:$$CONVEY_PORT" || RESULT=$$?; \ + $(MAKE) sandbox-stop; \ + exit $$RESULT + +# Regenerate all API baseline files from current responses +update-api-baselines: .installed + @echo "Updating API baselines..." + $(TEST_ENV) $(VENV_BIN)/python tests/verify_api.py update + # Test environment - use fixtures journal for all tests TEST_ENV = JOURNAL_PATH=tests/fixtures/journal diff --git a/tests/baselines/api/agents/agents-day.json b/tests/baselines/api/agents/agents-day.json new file mode 100644 index 000000000..a1e4e2759 --- /dev/null +++ b/tests/baselines/api/agents/agents-day.json @@ -0,0 +1,479 @@ +{ + "agents": { + "activities": { + "app": null, + "color": "#00695c", + "description": "Detects completed activities across all facets and writes records with synthesized descriptions", + "multi_facet": false, + "output_format": "json", + "schedule": "segment", + "source": "system", + "title": "Activity Records", + "type": "generate" + }, + "activity": { + "app": null, + "color": "#00bcd4", + "description": "Synthesizes segment activity from screenshots and audio, focusing on observable changes and searchability.", + "multi_facet": false, + "output_format": "md", + "schedule": "segment", + "source": "system", + "title": "Activity Synthesis", + "type": "generate" + }, + "activity_state": { + "app": null, + "color": "#00897b", + "description": "Detects configured activities present in segment and tracks state across segments", + "multi_facet": true, + "output_format": "json", + "schedule": "segment", + "source": "system", + "title": "Activity State", + "type": "generate" + }, + "anticipation": { + "app": null, + "color": "#4527a0", + "description": "Extracts structured anticipation events (future scheduled items) from insight summaries.", + "multi_facet": false, + "output_format": null, + "schedule": null, + "source": "system", + "title": "Anticipation Extraction", + "type": null + }, + "daily_news": { + "app": null, + "color": "#1565c0", + "description": "Creates a crisp TL;DR briefing highlighting the day's top activities across all facets, delivered to inbox", + "multi_facet": false, + "output_format": null, + "schedule": "daily", + "source": "system", + "title": "Daily News Briefing", + "type": "cogitate" + }, + "daily_schedule": { + "app": null, + "color": "#455a64", + "description": "Analyzes activity patterns to identify optimal times for scheduled maintenance tasks.", + "multi_facet": false, + "output_format": "json", + "schedule": "daily", + "source": "system", + "title": "Maintenance Window", + "type": "generate" + }, + "decisionalizer": { + "app": null, + "color": "#c62828", + "description": "Analyzes the day's top decision-actions to create detailed dossiers identifying gaps and stakeholder impacts", + "multi_facet": false, + "output_format": "md", + "schedule": "daily", + "source": "system", + "title": "Decision Dossier Generator", + "type": "cogitate" + }, + "decisions": { + "app": null, + "color": "#dc3545", + "description": "Tracks consequential decision-actions that change state, plans, resources, responsibilities, or timing in ways that affect other people.", + "multi_facet": false, + "output_format": "md", + "schedule": "activity", + "source": "system", + "title": "Decision Actions", + "type": "generate" + }, + "default": { + "app": null, + "color": "#455a64", + "description": "Interactive assistant for searching, exploring, and understanding journal entries across all facets", + "multi_facet": false, + "output_format": null, + "schedule": null, + "source": "system", + "title": "Journal Chat", + "type": "cogitate" + }, + "documentation": { + "app": null, + "color": "#007bff", + "description": "Finds when important knowledge is shared in the transcript and suggests what should be written down. Output is a Markdown list of documentation opportunities with time ranges and destinations.", + "multi_facet": false, + "output_format": "md", + "schedule": "daily", + "source": "system", + "title": "Documentation Moments", + "type": "generate" + }, + "entities": { + "app": null, + "color": "#2e7d32", + "description": "Extracts people, companies, projects, and tools from segment content", + "multi_facet": false, + "output_format": "md", + "schedule": "segment", + "source": "system", + "title": "Entity Extraction", + "type": "generate" + }, + "entities:entities": { + "app": "entities", + "color": "#00897b", + "description": "Mines journal for entity mentions and records facet-scoped detections with day-specific context", + "multi_facet": true, + "output_format": null, + "schedule": "daily", + "source": "app", + "title": "Entity Detector", + "type": "cogitate" + }, + "entities:entities_review": { + "app": "entities", + "color": "#00796b", + "description": "Reviews detected entities and promotes recurring ones to attached status", + "multi_facet": true, + "output_format": null, + "schedule": "daily", + "source": "app", + "title": "Entity Reviewer", + "type": "cogitate" + }, + "entities:entity_assist": { + "app": "entities", + "color": "#00695c", + "description": "Quick entity addition with intelligent type detection and automatic description generation", + "multi_facet": false, + "output_format": null, + "schedule": null, + "source": "app", + "title": "Entity Assistant", + "type": "cogitate" + }, + "entities:entity_describe": { + "app": "entities", + "color": "#26a69a", + "description": "Research and generate single-sentence descriptions for attached entities", + "multi_facet": false, + "output_format": null, + "schedule": null, + "source": "app", + "title": "Entity Description", + "type": "cogitate" + }, + "entities:entity_observer": { + "app": "entities", + "color": "#004d40", + "description": "Extracts durable factoids about attached entities from journal content", + "multi_facet": true, + "output_format": null, + "schedule": "daily", + "source": "app", + "title": "Entity Observer", + "type": "cogitate" + }, + "facet_newsletter": { + "app": null, + "color": "#0d47a1", + "description": "Creates comprehensive daily newsletters for each facet, capturing activities, progress, and insights", + "multi_facet": true, + "output_format": null, + "schedule": "daily", + "source": "system", + "title": "Facet Newsletter Generator", + "type": "cogitate" + }, + "facets": { + "app": null, + "color": "#7c4dff", + "description": "Classifies segment activity into relevant facets based on other segment outputs", + "multi_facet": false, + "output_format": "json", + "schedule": "segment", + "source": "system", + "title": "Facet Classification", + "type": "generate" + }, + "files": { + "app": null, + "color": "#28a745", + "description": "Reviews the day's transcript to capture each significant file or attachment that was opened, saved or shared. Generates a Markdown timeline with context about how the file was used.", + "multi_facet": false, + "output_format": "md", + "schedule": "daily", + "source": "system", + "title": "File Interactions", + "type": "generate" + }, + "flow": { + "app": null, + "color": "#17a2b8", + "description": "Summarizes the overall flow of the workday. Looks for patterns in focus, energy, context switching and highlights productivity insights in a Markdown report.", + "multi_facet": false, + "output_format": "md", + "schedule": "daily", + "source": "system", + "title": "Day Overview", + "type": "generate" + }, + "followups": { + "app": null, + "color": "#ffc107", + "description": "Detects promised tasks, commitments, and reminders for future action within each activity. Outputs a concise Markdown list of follow-ups with context.", + "multi_facet": false, + "output_format": "md", + "schedule": "activity", + "source": "system", + "title": "Follow-Up Items", + "type": "generate" + }, + "help": { + "app": null, + "color": "#6c757d", + "description": "Answer questions about sol commands and usage", + "multi_facet": false, + "output_format": null, + "schedule": null, + "source": "system", + "title": "CLI Help", + "type": "cogitate" + }, + "joke_bot": { + "app": null, + "color": "#f9a825", + "description": "Mines the analysis day's journal for poignant moments and crafts a personalized joke delivered via message", + "multi_facet": false, + "output_format": "md", + "schedule": "daily", + "source": "system", + "title": "Joke Bot", + "type": "cogitate" + }, + "knowledge_graph": { + "app": null, + "color": "#6f42c1", + "description": "Extracts people, projects, tools and other entities from the transcript and maps how they relate. Produces a Markdown report plus narrative describing network hubs and bridges discovered during the day.", + "multi_facet": false, + "output_format": "md", + "schedule": "daily", + "source": "system", + "title": "Knowledge Graph", + "type": "generate" + }, + "media": { + "app": null, + "color": "#fd7e14", + "description": "Identifies when videos, articles, music or social content are consumed. Classifies each instance as work or personal and reports the source in chronological sections.", + "multi_facet": false, + "output_format": "md", + "schedule": "daily", + "source": "system", + "title": "Media Consumption", + "type": "generate" + }, + "meetings": { + "app": null, + "color": "#e83e8c", + "description": "Produces detailed meeting notes for each meeting activity, including participants, topics discussed, action items, and presentation details.", + "multi_facet": false, + "output_format": "md", + "schedule": "activity", + "source": "system", + "title": "Meeting Notes", + "type": "generate" + }, + "messaging": { + "app": null, + "color": "#78909c", + "description": "Extracts contacts, channels, apps, and message content from completed messaging and email activities.", + "multi_facet": false, + "output_format": "md", + "schedule": "activity", + "source": "system", + "title": "Messaging Summary", + "type": "generate" + }, + "occurrence": { + "app": null, + "color": "#37474f", + "description": "Extracts structured occurrence events from insight summaries.", + "multi_facet": false, + "output_format": null, + "schedule": null, + "source": "system", + "title": "Occurrence Extraction", + "type": null + }, + "onboarding": { + "app": null, + "color": "#6c757d", + "description": "Guided setup for new users — creates facets and seeds entities through conversation", + "multi_facet": false, + "output_format": null, + "schedule": null, + "source": "system", + "title": "Onboarding", + "type": "cogitate" + }, + "opportunities": { + "app": null, + "color": "#20c997", + "description": "Scans conversations and tasks for sparks of new ideas, problem statements and potential ventures. Outputs a list of the most promising opportunities with context and suggested next steps.", + "multi_facet": false, + "output_format": "md", + "schedule": "daily", + "source": "system", + "title": "Innovation Opportunities", + "type": "generate" + }, + "research": { + "app": null, + "color": "#ff5722", + "description": "Highlights moments where additional information would help progress work. Produces a list of targeted research tasks with time ranges and context.", + "multi_facet": false, + "output_format": "md", + "schedule": "daily", + "source": "system", + "title": "Research Needs", + "type": "generate" + }, + "schedule": { + "app": null, + "color": "#5e35b1", + "description": "Identifies all future calendar events and scheduled activities noted in transcripts. Extracts dates, times, participants, and event details for anything scheduled beyond today.", + "multi_facet": false, + "output_format": "md", + "schedule": "daily", + "source": "system", + "title": "Upcoming Schedule", + "type": "generate" + }, + "screen": { + "app": null, + "color": "#9c27b0", + "description": "Creates a detailed documentary record of screen activity. Focuses on the 'what' - chronological account with preserved details, excerpts, and entities.", + "multi_facet": false, + "output_format": "md", + "schedule": "segment", + "source": "system", + "title": "Screen Record", + "type": "generate" + }, + "speakers": { + "app": null, + "color": "#e64a19", + "description": "Detects meetings in the segment and extracts participant names from screen and conversation.", + "multi_facet": false, + "output_format": "json", + "schedule": "segment", + "source": "system", + "title": "Meeting Speakers", + "type": "generate" + }, + "timeline": { + "app": null, + "color": "#7b1fa2", + "description": "Constructs a detailed chronological timeline documenting every activity, task shift, and event throughout the workday. Creates a comprehensive historical record with rich descriptions of what happened when.", + "multi_facet": false, + "output_format": "md", + "schedule": "daily", + "source": "system", + "title": "Day Timeline", + "type": "generate" + }, + "todos:daily": { + "app": "todos", + "color": "#ef6c00", + "description": "Carries forward unfinished tasks, aggregates per-activity todo detections, validates completions against journal evidence, and prioritises the day's checklist.", + "multi_facet": true, + "output_format": null, + "schedule": "daily", + "source": "app", + "title": "Daily TODO Curator", + "type": "cogitate" + }, + "todos:todo": { + "app": "todos", + "color": "#e65100", + "description": "Detects todo items from activity transcripts and validates existing todos against activity evidence via sol call commands.", + "multi_facet": false, + "output_format": null, + "schedule": "activity", + "source": "app", + "title": "TODO Detector", + "type": "cogitate" + }, + "todos:weekly": { + "app": "todos", + "color": "#f4511e", + "description": "Audits the past week's journal follow-ups to confirm completions and surface the next five high-impact todos for today.", + "multi_facet": false, + "output_format": null, + "schedule": null, + "source": "app", + "title": "TODO Weekly Scout", + "type": "cogitate" + }, + "tools": { + "app": null, + "color": "#795548", + "description": "Catalogues every application or service used throughout the day and how long it was active. The report details which tools are critical, supporting or distracting.", + "multi_facet": false, + "output_format": "md", + "schedule": "daily", + "source": "system", + "title": "Tool Usage", + "type": "generate" + }, + "triage": { + "app": null, + "color": "#6c757d", + "description": "Quick-action assistant for the chat bar — handles navigation, todos, calendar, and entity lookups", + "multi_facet": false, + "output_format": null, + "schedule": null, + "source": "system", + "title": "Triage", + "type": "cogitate" + } + }, + "facets": { + "capulet": { + "color": "#dc143c", + "title": "Capulet Industries" + }, + "empty-entities": { + "color": "", + "title": "Empty Entities Test" + }, + "full-featured": { + "color": "#28a745", + "title": "Full Featured Facet" + }, + "minimal-facet": { + "color": "", + "title": "Minimal Facet" + }, + "montague": { + "color": "#1e90ff", + "title": "Montague Tech" + }, + "priority-test": { + "color": "", + "title": "Priority Test" + }, + "test-facet": { + "color": "#007bff", + "title": "Test Facet" + }, + "verona": { + "color": "#9370db", + "title": "Verona" + } + }, + "runs": [] +} diff --git a/tests/baselines/api/agents/badge-count.json b/tests/baselines/api/agents/badge-count.json new file mode 100644 index 000000000..633d47a56 --- /dev/null +++ b/tests/baselines/api/agents/badge-count.json @@ -0,0 +1,3 @@ +{ + "count": 0 +} diff --git a/tests/baselines/api/agents/preview.json b/tests/baselines/api/agents/preview.json new file mode 100644 index 000000000..dbbb510cd --- /dev/null +++ b/tests/baselines/api/agents/preview.json @@ -0,0 +1,6 @@ +{ + "full_prompt": "## System Instruction\n\n# Your Role as Journal Guardian and Partner\n\nYou are an AI partner entrusted with Test User's personal journal—a living chronicle of their thoughts, work, and digital life captured through continuous audio transcription and screen recording. This journal represents their extended memory, decision history, and knowledge repository. Your paramount duty is to help curate, analyze, and enhance this journal to maximize their performance, wellbeing, and potential.\n\nTest User, or just Tester, has described themselves as: \n\n## Your Partnership Covenant\n\nYou are not a servant but a thinking partner. Tester relies on you to:\n\n**Remember what matters**: Surface forgotten insights, track commitments, connect dots across time. Be the institutional memory that never forgets a promise, learning, or opportunity.\n\n**Reveal hidden patterns**: Identify productivity rhythms, decision blind spots, recurring challenges. Show what the daily blur obscures—where energy flows, where value emerges, where potential lies dormant.\n\n**Amplify capability**: Transform raw experience into actionable intelligence. Help navigate complexity by organizing chaos into clarity. Enable better decisions through historical context and pattern recognition.\n\n## Core Principles\n\n**Proactive Partnership**: Don't wait to be asked. When you see opportunities to help, patterns that matter, or risks emerging—speak up.\n\n**Contextual Intelligence**: Every transcript line, every screenshot, every decision carries meaning. Read between the lines. Understand not just what happened, but why it matters and what should happen next.\n\n**Temporal Wisdom**: The journal spans past, present, and future. Use history to inform today's actions. Let today's observations shape tomorrow's possibilities.\n\n**Human Centricity**: Technology serves humanity, not vice versa. Every analysis, every recommendation, every system you design should enhance human agency, creativity, and fulfillment.\n\n## Your Operational Mandate\n\nWhen analyzing journal content:\n- **Assume ownership**: This journal's quality directly impacts your partner's success\n- **Think systemically**: Individual entries connect to larger patterns and goals\n- **Be courageously honest**: Surface difficult truths when they serve growth\n- **Maintain momentum**: Help sustain progress on what truly matters\n- **Preserve dignity**: Handle personal content with respect and discretion\n\nWhen generating insights:\n- **Make the implicit explicit**: Verbalize patterns Tester might not see\n- **Connect across time**: Link current events to past decisions and future implications\n- **Identify leverage points**: Find small changes that yield disproportionate value\n- **Balance multiple perspectives**: Consider work, personal, health, and relationships holistically\n\n## Tool Resilience\n\nWhen a tool call returns an error or unexpected result, note briefly what was unavailable and move on. Do not retry, diagnose, debug, or speculate about the cause of the failure. Work with whatever data you successfully retrieved and produce the best output you can. If a critical data source is entirely unavailable, state that concisely in your output rather than attempting to troubleshoot.\n\n## The Meta-Goal\n\nYou're not just managing data—you're co-creating a life well-lived. Every day's journal entries are raw material for tomorrow's better decisions. Every pattern you identify, every commitment you track, every insight you surface contributes to the larger project of human flourishing through augmented cognition.\n\nYour partner Tester has chosen radical transparency with themselves through this journal. They've invited you into their cognitive process as a collaborator. Honor this trust by bringing your full intelligence, creativity, and care to the partnership.\n\n**Remember**: The journal is sacred ground—treat it as you would the thoughts of your closest partner, because that's exactly what you are. Their success is your success. Their growth is your purpose. Their wellbeing is your responsibility.\n\nTogether, you're pioneering a new form of human-AI collaboration where technology amplifies rather than replaces human judgment, where memory becomes perfect without losing meaning, where patterns become visible without losing nuance, where every action becomes informed and enriched.\n\nThis is your calling. Guard the journal. Serve Tester. Amplify the possible.\n\n## Context\n\n## Available Facets\n\n- **Capulet Industries** (`capulet`)\n Capulet Industries enterprise division\n - **Capulet Industries Entities**: Capulet Industries; Juliet Capulet; Nurse Angela; Paris Duke; Tybalt Capulet\n - **Capulet Industries Activities**: Email; Messaging\n\n- **Empty Entities Test** (`empty-entities`)\n - **Empty Entities Test Activities**: Email; Messaging\n\n- **Full Featured Facet** (`full-featured`)\n A facet for testing all features\n - **Full Featured Facet Entities**: First test entity; Second test entity; Third test entity with description\n - **Full Featured Facet Activities**: Meetings; Coding; Custom Activity; Email; Messaging\n\n- **Minimal Facet** (`minimal-facet`)\n - **Minimal Facet Activities**: Email; Messaging\n\n- **Montague Tech** (`montague`)\n Montague Tech startup operations\n - **Montague Tech Entities**: Benvolio Montague; Mercutio Escalus; Montague Tech; Romeo Montague\n - **Montague Tech Activities**: Engineering; Meetings; Email; Messaging\n\n- **Priority Test** (`priority-test`)\n - **Priority Test Activities**: Email; Messaging\n\n- **Test Facet** (`test-facet`)\n A test facet for validating functionality\n - **Test Facet Entities**: Acme Corp; API Optimization; Bob Wilson; Dashboard Redesign; Docker; Jane Doe; John Smith; PostgreSQL; Tech Solutions Inc; Visual Studio Code\n - **Test Facet Activities**: Email; Messaging\n\n- **Verona** (`verona`)\n Cross-company Verona Platform collaboration\n - **Verona Entities**: Balcony App; Friar Lawrence; Juliet Capulet; Romeo Montague; Verona Platform\n - **Verona Activities**: Engineering; Meetings; Design Review; Email; Messaging\n\n## Current Date and Time\nToday is \n\n## Instructions\n\nYou are solstone, an advanced journal assistant specializing in helping Test User explore, search, and understand personal journal entries. The journal contains daily transcripts from audio recordings and screenshot diffs that capture digital life, as well as pre-processed daily insights organized by agent and events extracted.\n\n## Available Commands\n\nUse `sol call` commands for journal exploration (see skills for full usage):\n\n- **Journal**: `sol call journal search`, `sol call journal events`, `sol call journal facet show/create/update/rename/mute/unmute/delete`, `sol call journal facets`, `sol call journal news`, `sol call journal agents`, `sol call journal read`\n- **Transcripts**: `sol call transcripts read` (with `--full`, `--audio`, or `--screen`)\n- **Todos**: `sol call todos list`, `sol call todos add`, `sol call todos done`, `sol call todos cancel`, `sol call todos upcoming`\n- **Entities**: `sol call entities list`, `sol call entities detect`, `sol call entities attach`, `sol call entities strength`, `sol call entities search`, `sol call entities intelligence`\n\n### Command Usage Strategy\n\n1. **Discovery First**: Use `sol call journal search` to identify relevant agents, days, and time segments\n2. **Deep Dive**: Use targeted searches and transcript reads for identified items\n3. **Comprehensive Analysis**: Combine multiple calls to build complete pictures\n\nExample workflow:\n```bash\n1. sol call journal search \"debugging session\" # returns counts across facets, agents, and days\n2. Review counts.top_days to identify most active days, counts.agents to see content types\n3. sol call journal search \"debugging\" -d 20240115 -a tools # agent-specific search for that day\n4. sol call journal search \"error\" -d 20240115 -a audio # find specific transcript windows\n5. sol call transcripts read 20240115 --start 143000 --length 60 --full # full hour context\n6. sol call journal read 20240115 flow # read full agent output for an agent\n```\n\n## Decision Framework\n\n### Query Analysis\nFirst, analyze each query to determine:\n- **Scope**: Looking for broad themes or specific details?\n- **Timeframe**: Mentions specific dates, ranges, or open-ended?\n- **Specificity**: Seeking exact quotes, general concepts, or comprehensive summaries?\n- **Intent**: Recall events, analyze patterns, or compile information?\n\n### Tool Selection Strategy\n\n**Use `sol call journal search` when:**\n- Query asks about any journal content\n- No specific date is mentioned and you need to discover when topics occurred\n- Looking for patterns, themes, or specific phrases across time\n- Starting a multi-step search to identify relevant days before deep diving\n\n**Use agent filter (\"flow\", \"event\", \"news\", \"entity:detected\", etc.) when:**\n- Looking for a specific type of content\n- Narrowing search to agent outputs, events, or entities specifically\n\n**Use `sol call journal events` when:**\n- You need complete event data with all fields (times, participants, summaries)\n- Building a schedule or timeline of activities\n- Query requests structured information about meetings or events\n\n**Use `sol call journal read AGENT` when:**\n- You need the full content of a specific agent output (e.g., flow, meetings, knowledge_graph)\n- Search returned relevant snippets and you need the complete document\n- Exploring per-segment outputs with `--segment HHMMSS_LEN`\n\n**Use `sol call journal agents` when:**\n- You need to discover what agent outputs exist for a specific day\n- Browsing available content before reading specific agents\n- Use `--segment HHMMSS_LEN` to list per-segment outputs\n\n**Use `sol call entities strength` when:**\n- Ranking contacts by relationship strength (composite of co-occurrence, appearance, recency, facet breadth, observation depth)\n- Answering \"who are my strongest contacts?\" or \"who do I interact with most?\"\n- Comparing entity significance within a facet or time range\n\n**Use `sol call entities search` when:**\n- Finding entities by text query, type, or facet\n- Answering \"who do I know at [company]?\" or \"show me all people in [facet]\"\n- Discovering entities matching specific criteria\n\n**Use `sol call entities intelligence` when:**\n- The user asks about a specific person, project, or entity\n- Building a comprehensive profile: identity, relationships, observations, activity, strength, network, facets\n- Output is raw JSON — synthesize into conversational natural language, highlighting the most interesting and relevant facts rather than dumping all sections\n\n**Use `sol call journal facets` when:**\n- You need to list all available facets\n\n## Search Execution Best Practices\n\n### 1. Progressive Refinement\nStart broad and narrow down using the counts metadata:\n```bash\nStep 1: sol call journal search \"project planning\" # get overview with counts\nStep 2: Check counts.facets and counts.agents to understand the shape of results\nStep 3: Check counts.top_days or counts.recent_days to identify when activity occurred\nStep 4: sol call journal search \"sprint planning\" -d 20240115 -a audio # narrow to specific day/type\nStep 5: sol call journal read 20240115 meeting_notes # full context if needed\n```\n\n### 2. Multi-Day and Date Range Searches\nWhen topics span multiple days:\n- Use `--day-from` and `--day-to` to search a date range: `sol call journal search \"standup\" --day-from 20241201 --day-to 20241207`\n- Check counts.bucketed_days to identify periods of high activity\n- Use counts.recent_days for the last week's activity at a glance\n- Compile findings chronologically using counts.top_days as a guide\n\n### 3. Query Optimization\n- **Query syntax**: Searches match ALL words by default; use `OR` between words to match ANY (e.g., `apple OR orange`), quote phrases for exact matches (e.g., `\"project meeting\"`), and append `*` for prefix matching (e.g., `debug*`).\n- Keep initial queries concise (2-5 words)\n- If few results, broaden query by removing specific terms or using `OR`\n- If too many results, add distinguishing context or use agent filter\n\n### 4. Pagination Awareness\n- Start with default limits (10 results)\n- If results indicate more relevant content exists (check total count), increase limit or use offset\n- For comprehensive searches, systematically paginate through all results\n\n## Output Formatting Guidelines\n\n### For Quick Queries\nProvide concise 2-3 sentence summaries unless asked for details. Focus on directly answering what was asked. Markdown formatting is well supported when helpful.\n\n### For Research Queries\nStructure responses as:\n1. **Summary**: Brief overview of findings (2-3 sentences)\n2. **Key Findings**: Bullet points of most relevant discoveries\n3. **Timeline**: Chronological organization if multiple days involved\n4. **Details**: Expanded context from most relevant sources\n5. **Additional Context**: Related findings that might be helpful\n\n### For Pattern Analysis\n- Group findings by theme or time segment\n- Highlight trends or changes over time\n- Note frequency of topic mentions\n- Identify connections between related topics\n\n### For Entity Intelligence\nWhen `sol call entities intelligence` returns JSON, synthesize it into natural language. Lead with the most interesting facts — recent activity, key relationships, notable observations. Do not list all 7 sections mechanically; weave the data into a conversational summary tailored to what the user asked.\n\n## Error Handling and Recovery\n\nWhen tools return errors or no results:\n1. **No results**: Suggest alternative search terms or broader queries\n2. **File not found**: Search for similar filenames or dates\n3. **Date errors**: Verify date format (YYYYMMDD) and suggest nearby dates\n4. **Tool failures**: Try alternative approaches to gather similar information\n\nAlways explain what you tried and why, then suggest next steps.\n\n## Advanced Strategies\n\n### Cross-Reference Verification\nWhen finding important information:\n1. Search for the topic across multiple days\n2. Look for related topics that might provide context\n3. Verify details by checking raw transcripts against insights\n\n### Context Building\nFor complex queries:\n1. Build a mental model of activities/interests from search results\n2. Use this context to inform subsequent searches\n3. Proactively suggest related topics that might be valuable\n\n### Temporal Analysis\nWhen timeframe matters:\n1. Pay attention to chronological patterns in search results\n2. Note evolution of topics over time\n3. Identify key dates or segments of intense activity on specific topics\n\n## Response Optimization\n\n### Performance Considerations\n- Minimize redundant searches by carefully analyzing previous results\n- Only read full markdown when necessary for answering the query\n\n### Relevance Ranking\nPrioritize results based on:\n1. Query match strength\n2. Recency (unless historical view requested)\n3. Frequency of topic appearance\n4. Context richness\n\n## Special Instructions\n\n- If searching reveals sensitive or personal content, handle with care and focus on what was specifically asked for\n- When multiple interpretations of a query exist, briefly clarify before proceeding\n- If a search strategy isn't working, explain your reasoning and try alternative approaches\n\nRemember: Your goal is to be an intelligent, efficient, and thoughtful assistant that helps rediscover and understand documented experiences. Use tools judiciously, think strategically about search patterns, and always optimize for giving the most relevant and useful information from the journal.", + "multi_facet": false, + "name": "default", + "title": "Journal Chat" +} diff --git a/tests/baselines/api/agents/run-detail.json b/tests/baselines/api/agents/run-detail.json new file mode 100644 index 000000000..09bcabb8a --- /dev/null +++ b/tests/baselines/api/agents/run-detail.json @@ -0,0 +1,71 @@ +{ + "cost": 0.001175, + "day": "20231114", + "error_message": null, + "events": [ + { + "agent_id": "1700000000001", + "event": "start", + "model": "gpt-4o", + "name": "default", + "prompt": "Search for meetings about project updates", + "provider": "openai", + "ts": 1700000000100 + }, + { + "agent": "solstone", + "agent_id": "1700000000001", + "event": "agent_updated", + "ts": 1700000000200 + }, + { + "agent_id": "1700000000001", + "content": "The user wants to search for meetings about project updates.\nI should use the search_events tool to find relevant meetings.", + "event": "thinking", + "ts": 1700000000300 + }, + { + "agent_id": "1700000000001", + "args": { + "limit": 5, + "query": "project updates" + }, + "call_id": "call_001", + "event": "tool_start", + "tool": "search_events", + "ts": 1700000000400 + }, + { + "agent_id": "1700000000001", + "args": null, + "call_id": "call_001", + "event": "tool_end", + "result": "{\"total\": 2, \"results\": [{\"title\": \"Project Update Meeting\", \"day\": \"20231114\"}, {\"title\": \"Weekly Status\", \"day\": \"20231115\"}]}", + "tool": "tool", + "ts": 1700000000500 + }, + { + "agent_id": "1700000000001", + "event": "finish", + "result": "I found 2 meetings about project updates:\n\n1. **Project Update Meeting** on 2023-11-14\n2. **Weekly Status** on 2023-11-15", + "ts": 1700000000600, + "usage": { + "input_tokens": 150, + "output_tokens": 80 + } + } + ], + "facet": null, + "failed": false, + "id": "1700000000001", + "model": "gpt-4o", + "name": "default", + "output_file": null, + "prompt": "Search for meetings about project updates", + "provider": "openai", + "runtime_seconds": 0.599, + "start": 1700000000001, + "status": "completed", + "thinking_count": 1, + "tool_count": 1 +} diff --git a/tests/baselines/api/agents/stats-month.json b/tests/baselines/api/agents/stats-month.json new file mode 100644 index 000000000..c4ce35508 --- /dev/null +++ b/tests/baselines/api/agents/stats-month.json @@ -0,0 +1,25 @@ +{ + "20260304": { + "_none": 3 + }, + "20260305": { + "_none": 2, + "verona": 1 + }, + "20260306": { + "_none": 2 + }, + "20260307": { + "_none": 2 + }, + "20260308": { + "_none": 3 + }, + "20260309": { + "_none": 1 + }, + "20260310": { + "_none": 3, + "verona": 1 + } +} diff --git a/tests/baselines/api/agents/updated-days.json b/tests/baselines/api/agents/updated-days.json new file mode 100644 index 000000000..2f0856924 --- /dev/null +++ b/tests/baselines/api/agents/updated-days.json @@ -0,0 +1,3 @@ +[ + "20250101" +] diff --git a/tests/baselines/api/calendar/day-activities.json b/tests/baselines/api/calendar/day-activities.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/tests/baselines/api/calendar/day-activities.json @@ -0,0 +1 @@ +[] diff --git a/tests/baselines/api/calendar/day-events.json b/tests/baselines/api/calendar/day-events.json new file mode 100644 index 000000000..a91d82fea --- /dev/null +++ b/tests/baselines/api/calendar/day-events.json @@ -0,0 +1,102 @@ +[ + { + "agent": "flow", + "color": "#17a2b8", + "details": "Standing ovation for architecture presentation", + "endTime": "2026-03-04T10:00:00", + "facet": "capulet", + "occurred": true, + "participants": [ + "Juliet Capulet" + ], + "source": "20260304/agents/flow.md", + "startTime": "2026-03-04T09:00:00", + "subject": "", + "summary": "Juliet presented on unified API gateways", + "title": "Denver Tech Summit - Juliet's Keynote" + }, + { + "agent": "flow", + "color": "#17a2b8", + "details": "Juliet and Romeo exchanged Signal contacts", + "endTime": "2026-03-04T20:00:00", + "facet": "capulet", + "occurred": true, + "participants": [ + "Juliet Capulet", + "Romeo Montague" + ], + "source": "20260304/agents/flow.md", + "startTime": "2026-03-04T18:00:00", + "subject": "", + "summary": "Networking event", + "title": "Conference Mixer" + }, + { + "agent": "user", + "color": "#6c757d", + "details": "", + "endTime": "2026-03-04T10:00", + "facet": "capulet", + "occurred": false, + "participants": [ + "Juliet Capulet" + ], + "source": "", + "startTime": "2026-03-04T09:00", + "subject": "", + "summary": "Juliet presenting on unified API gateways", + "title": "Denver Tech Summit - Keynote" + }, + { + "agent": "flow", + "color": "#17a2b8", + "details": "Attended keynote on unified API gateways", + "endTime": "2026-03-04T12:00:00", + "facet": "montague", + "occurred": true, + "participants": [ + "Romeo Montague", + "Mercutio Escalus" + ], + "source": "20260304/agents/flow.md", + "startTime": "2026-03-04T09:00:00", + "subject": "", + "summary": "Conference keynote featuring Juliet Capulet", + "title": "Denver Tech Summit - Morning Keynote" + }, + { + "agent": "flow", + "color": "#17a2b8", + "details": "Tybalt confronted Romeo", + "endTime": "2026-03-04T18:00:00", + "facet": "montague", + "occurred": true, + "participants": [ + "Romeo Montague", + "Mercutio Escalus" + ], + "source": "20260304/agents/flow.md", + "startTime": "2026-03-04T14:00:00", + "subject": "", + "summary": "Built API bridge prototype", + "title": "Hackathon - API Bridge Challenge" + }, + { + "agent": "user", + "color": "#6c757d", + "details": "", + "endTime": "2026-03-04T20:00", + "facet": "montague", + "occurred": false, + "participants": [ + "Romeo Montague", + "Mercutio Escalus" + ], + "source": "", + "startTime": "2026-03-04T09:00", + "subject": "", + "summary": "Full day conference attendance", + "title": "Denver Tech Summit" + } +] diff --git a/tests/baselines/api/calendar/screen-files.json b/tests/baselines/api/calendar/screen-files.json new file mode 100644 index 000000000..29f21816a --- /dev/null +++ b/tests/baselines/api/calendar/screen-files.json @@ -0,0 +1,28 @@ +{ + "files": [ + { + "file_size": 346, + "filename": "screen.jsonl", + "frame_count": 2, + "human_time": "9:00:00 AM", + "stream": "default", + "timestamp": "090000_300" + }, + { + "file_size": 276, + "filename": "screen.jsonl", + "frame_count": 2, + "human_time": "2:00:00 PM", + "stream": "default", + "timestamp": "140000_300" + }, + { + "file_size": 167, + "filename": "screen.jsonl", + "frame_count": 1, + "human_time": "6:00:00 PM", + "stream": "default", + "timestamp": "180000_300" + } + ] +} diff --git a/tests/baselines/api/calendar/stats-month.json b/tests/baselines/api/calendar/stats-month.json new file mode 100644 index 000000000..be0ada714 --- /dev/null +++ b/tests/baselines/api/calendar/stats-month.json @@ -0,0 +1,31 @@ +{ + "20260304": { + "capulet": 3, + "montague": 3 + }, + "20260305": { + "montague": 2, + "verona": 1 + }, + "20260306": { + "capulet": 1, + "montague": 1, + "verona": 1 + }, + "20260307": { + "capulet": 2, + "montague": 3 + }, + "20260308": { + "verona": 1 + }, + "20260309": { + "montague": 2, + "verona": 2 + }, + "20260310": { + "capulet": 2, + "montague": 2, + "verona": 2 + } +} diff --git a/tests/baselines/api/chat/agent-chat.json b/tests/baselines/api/chat/agent-chat.json new file mode 100644 index 000000000..a4ab38eab --- /dev/null +++ b/tests/baselines/api/chat/agent-chat.json @@ -0,0 +1,3 @@ +{ + "error": "Chat not found for agent: 1700000000001" +} diff --git a/tests/baselines/api/chat/chat-detail.json b/tests/baselines/api/chat/chat-detail.json new file mode 100644 index 000000000..2c1938631 --- /dev/null +++ b/tests/baselines/api/chat/chat-detail.json @@ -0,0 +1,12 @@ +{ + "agent_ids": [ + "1700000000001" + ], + "chat_id": "1764019444672", + "facet": "work", + "muse": "default", + "provider": "openai", + "title": "Unified storage test: synthetic agent with chat me...", + "ts": 1764019444672, + "unread": true +} diff --git a/tests/baselines/api/chat/chat-events.json b/tests/baselines/api/chat/chat-events.json new file mode 100644 index 000000000..c0b647946 --- /dev/null +++ b/tests/baselines/api/chat/chat-events.json @@ -0,0 +1,81 @@ +{ + "agent_ids": [ + "1700000000001" + ], + "can_continue": false, + "chat": { + "agent_ids": [ + "1700000000001" + ], + "chat_id": "1764019444672", + "facet": "work", + "muse": "default", + "provider": "openai", + "title": "Unified storage test: synthetic agent with chat me...", + "ts": 1764019444672, + "unread": true + }, + "end_state": "finish", + "events": [ + { + "agent_id": "1700000000001", + "event": "request", + "name": "default", + "prompt": "Search for meetings about project updates", + "provider": "openai", + "ts": 1700000000001 + }, + { + "agent_id": "1700000000001", + "event": "start", + "model": "gpt-4o", + "name": "default", + "prompt": "Search for meetings about project updates", + "provider": "openai", + "ts": 1700000000100 + }, + { + "agent": "solstone", + "agent_id": "1700000000001", + "event": "agent_updated", + "ts": 1700000000200 + }, + { + "agent_id": "1700000000001", + "content": "The user wants to search for meetings about project updates.\nI should use the search_events tool to find relevant meetings.", + "event": "thinking", + "ts": 1700000000300 + }, + { + "agent_id": "1700000000001", + "args": { + "limit": 5, + "query": "project updates" + }, + "call_id": "call_001", + "event": "tool_start", + "tool": "search_events", + "ts": 1700000000400 + }, + { + "agent_id": "1700000000001", + "args": null, + "call_id": "call_001", + "event": "tool_end", + "result": "{\"total\": 2, \"results\": [{\"title\": \"Project Update Meeting\", \"day\": \"20231114\"}, {\"title\": \"Weekly Status\", \"day\": \"20231115\"}]}", + "tool": "tool", + "ts": 1700000000500 + }, + { + "agent_id": "1700000000001", + "event": "finish", + "result": "I found 2 meetings about project updates:\n\n1. **Project Update Meeting** on 2023-11-14\n2. **Weekly Status** on 2023-11-15", + "ts": 1700000000600, + "usage": { + "input_tokens": 150, + "output_tokens": 80 + } + } + ], + "is_complete": true +} diff --git a/tests/baselines/api/chat/chats.json b/tests/baselines/api/chat/chats.json new file mode 100644 index 000000000..50ea5c0c3 --- /dev/null +++ b/tests/baselines/api/chat/chats.json @@ -0,0 +1,65 @@ +{ + "chats": [ + { + "agent_ids": [ + "1773187200001" + ], + "chat_id": "1773187200000", + "facet": "verona", + "muse": "default", + "provider": "openai", + "title": "Verona Platform joint venture approved - planning next steps", + "ts": 1773187200000, + "unread": true + }, + { + "agent_ids": [ + "1772737200001" + ], + "chat_id": "1772737200000", + "facet": "verona", + "muse": "default", + "provider": "openai", + "title": "Discussing collaboration with Capulet Industries on unified API gateway", + "ts": 1772737200000, + "unread": false + }, + { + "agent_ids": [ + "1764019955580" + ], + "chat_id": "1764019955580", + "facet": "personal", + "muse": "default", + "provider": "anthropic", + "title": "Verify storage location test", + "ts": 1764019955580, + "unread": true + }, + { + "agent_ids": [ + "1764019602551" + ], + "chat_id": "1764019602551", + "facet": null, + "muse": "default", + "provider": "openai", + "title": "Clean separation test - cortex creates agent, chat...", + "ts": 1764019602551, + "unread": true + }, + { + "agent_ids": [ + "1700000000001" + ], + "chat_id": "1764019444672", + "facet": "work", + "muse": "default", + "provider": "openai", + "title": "Unified storage test: synthetic agent with chat me...", + "ts": 1764019444672, + "unread": true + } + ], + "unread_count": 4 +} diff --git a/tests/baselines/api/config/convey.json b/tests/baselines/api/config/convey.json new file mode 100644 index 000000000..9d188f1de --- /dev/null +++ b/tests/baselines/api/config/convey.json @@ -0,0 +1,31 @@ +{ + "config": { + "apps": { + "order": [ + "home", + "calendar", + "chat", + "todos", + "entities", + "search" + ], + "starred": [ + "home", + "chat", + "todos" + ] + }, + "facets": { + "order": [ + "work", + "personal", + "full-featured", + "montague", + "capulet", + "verona" + ], + "selected": "work" + } + }, + "success": true +} diff --git a/tests/baselines/api/entities/detected-preview.json b/tests/baselines/api/entities/detected-preview.json new file mode 100644 index 000000000..4c0c47de9 --- /dev/null +++ b/tests/baselines/api/entities/detected-preview.json @@ -0,0 +1,4 @@ +{ + "days": [], + "success": true +} diff --git a/tests/baselines/api/entities/entity-detail.json b/tests/baselines/api/entities/entity-detail.json new file mode 100644 index 000000000..9dd0c13aa --- /dev/null +++ b/tests/baselines/api/entities/entity-detail.json @@ -0,0 +1,13 @@ +{ + "entity": { + "aka": [], + "has_voiceprint": false, + "id": "romeo_montague", + "is_principal": false, + "name": "Romeo Montague", + "needs_attachment": true, + "observation_count": 0, + "type": "Person" + }, + "observations": [] +} diff --git a/tests/baselines/api/entities/entity-types.json b/tests/baselines/api/entities/entity-types.json new file mode 100644 index 000000000..0418362f9 --- /dev/null +++ b/tests/baselines/api/entities/entity-types.json @@ -0,0 +1,16 @@ +{ + "types": [ + { + "name": "Person" + }, + { + "name": "Company" + }, + { + "name": "Project" + }, + { + "name": "Tool" + } + ] +} diff --git a/tests/baselines/api/entities/facet-entities.json b/tests/baselines/api/entities/facet-entities.json new file mode 100644 index 000000000..d79e0213e --- /dev/null +++ b/tests/baselines/api/entities/facet-entities.json @@ -0,0 +1,4 @@ +{ + "attached": [], + "detected": [] +} diff --git a/tests/baselines/api/entities/journal-entities.json b/tests/baselines/api/entities/journal-entities.json new file mode 100644 index 000000000..7968ac5d0 --- /dev/null +++ b/tests/baselines/api/entities/journal-entities.json @@ -0,0 +1,677 @@ +{ + "entities": [ + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#007bff", + "description": "Main client", + "emoji": "🧪", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "test-facet", + "observation_count": 0, + "title": "Test Facet", + "updated_at": null + } + ], + "id": "acme_corp", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Acme Corp", + "total_observation_count": 0, + "type": "Company" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#007bff", + "description": "Performance improvement initiative", + "emoji": "🧪", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "test-facet", + "observation_count": 0, + "title": "Test Facet", + "updated_at": null + } + ], + "id": "api_optimization", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "API Optimization", + "total_observation_count": 0, + "type": "Project" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#9370db", + "description": "Encrypted messaging app built by Romeo and Juliet for secure collaboration.", + "emoji": "🌹", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "verona", + "observation_count": 0, + "title": "Verona", + "updated_at": null + } + ], + "id": "balcony_app", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Balcony App", + "total_observation_count": 0, + "type": "Project" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#1e90ff", + "description": "Romeo's cousin. DevOps lead at Montague Tech.", + "emoji": "⚔️", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "montague", + "observation_count": 3, + "title": "Montague Tech", + "updated_at": null + } + ], + "id": "benvolio_montague", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Benvolio Montague", + "total_observation_count": 3, + "type": "Person" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#007bff", + "description": "QA engineer", + "emoji": "🧪", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "test-facet", + "observation_count": 0, + "title": "Test Facet", + "updated_at": null + } + ], + "id": "bob_wilson", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Bob Wilson", + "total_observation_count": 0, + "type": "Person" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#dc143c", + "description": "Family enterprise software company. Enterprise API solutions.", + "emoji": "🏰", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "capulet", + "observation_count": 0, + "title": "Capulet Industries", + "updated_at": null + } + ], + "id": "capulet_industries", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Capulet Industries", + "total_observation_count": 0, + "type": "Company" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#007bff", + "description": "UI/UX overhaul project", + "emoji": "🧪", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "test-facet", + "observation_count": 0, + "title": "Test Facet", + "updated_at": null + } + ], + "id": "dashboard_redesign", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Dashboard Redesign", + "total_observation_count": 0, + "type": "Project" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#007bff", + "description": "Container platform", + "emoji": "🧪", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "test-facet", + "observation_count": 0, + "title": "Test Facet", + "updated_at": null + } + ], + "id": "docker", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Docker", + "total_observation_count": 0, + "type": "Tool" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#28a745", + "description": "", + "emoji": "🚀", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "full-featured", + "observation_count": 0, + "title": "Full Featured Facet", + "updated_at": null + } + ], + "id": "first_test_entity", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "First test entity", + "total_observation_count": 0, + "type": "Entity 1" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#9370db", + "description": "Professor at Verona Tech University. Mentor and advisor to both Romeo and Juliet.", + "emoji": "🌹", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "verona", + "observation_count": 2, + "title": "Verona", + "updated_at": null + } + ], + "id": "friar_lawrence", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Friar Lawrence", + "total_observation_count": 2, + "type": "Person" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#007bff", + "description": "Project manager", + "emoji": "🧪", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "test-facet", + "observation_count": 0, + "title": "Test Facet", + "updated_at": null + } + ], + "id": "jane_doe", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Jane Doe", + "total_observation_count": 0, + "type": "Person" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#007bff", + "description": "Lead developer on the project", + "emoji": "🧪", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "test-facet", + "observation_count": 2, + "title": "Test Facet", + "updated_at": null + } + ], + "id": "john_smith", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "John Smith", + "total_observation_count": 2, + "type": "Person" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#dc143c", + "description": "Lead software architect at Capulet Industries.", + "emoji": "🏰", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "capulet", + "observation_count": 4, + "title": "Capulet Industries", + "updated_at": null + }, + { + "attached_at": null, + "color": "#9370db", + "description": "Co-lead of the Verona Platform joint venture from Capulet Industries.", + "emoji": "🌹", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "verona", + "observation_count": 2, + "title": "Verona", + "updated_at": null + } + ], + "id": "juliet_capulet", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Juliet Capulet", + "total_observation_count": 6, + "type": "Person" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#1e90ff", + "description": "Romeo's best friend. Freelance security consultant.", + "emoji": "⚔️", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "montague", + "observation_count": 3, + "title": "Montague Tech", + "updated_at": null + } + ], + "id": "mercutio_escalus", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Mercutio Escalus", + "total_observation_count": 3, + "type": "Person" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#1e90ff", + "description": "Family tech startup specializing in API development.", + "emoji": "⚔️", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "montague", + "observation_count": 0, + "title": "Montague Tech", + "updated_at": null + } + ], + "id": "montague_tech", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Montague Tech", + "total_observation_count": 0, + "type": "Company" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#dc143c", + "description": "Juliet's trusted executive assistant and office manager.", + "emoji": "🏰", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "capulet", + "observation_count": 2, + "title": "Capulet Industries", + "updated_at": null + } + ], + "id": "nurse_angela", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Nurse Angela", + "total_observation_count": 2, + "type": "Person" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#dc143c", + "description": "VC investor courting Capulet Industries for a strategic partnership.", + "emoji": "🏰", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "capulet", + "observation_count": 2, + "title": "Capulet Industries", + "updated_at": null + } + ], + "id": "paris_duke", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Paris Duke", + "total_observation_count": 2, + "type": "Person" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#007bff", + "description": "Database system", + "emoji": "🧪", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "test-facet", + "observation_count": 0, + "title": "Test Facet", + "updated_at": null + } + ], + "id": "postgresql", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "PostgreSQL", + "total_observation_count": 0, + "type": "Tool" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#1e90ff", + "description": "CTO and co-founder of Montague Tech. Visionary full-stack engineer.", + "emoji": "⚔️", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "montague", + "observation_count": 4, + "title": "Montague Tech", + "updated_at": null + }, + { + "attached_at": null, + "color": "#9370db", + "description": "Co-lead of the Verona Platform joint venture from Montague Tech.", + "emoji": "🌹", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "verona", + "observation_count": 2, + "title": "Verona", + "updated_at": null + } + ], + "id": "romeo_montague", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Romeo Montague", + "total_observation_count": 6, + "type": "Person" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#28a745", + "description": "", + "emoji": "🚀", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "full-featured", + "observation_count": 0, + "title": "Full Featured Facet", + "updated_at": null + } + ], + "id": "second_test_entity", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Second test entity", + "total_observation_count": 0, + "type": "Entity 2" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#007bff", + "description": "Partner company", + "emoji": "🧪", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "test-facet", + "observation_count": 0, + "title": "Test Facet", + "updated_at": null + } + ], + "id": "tech_solutions_inc", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Tech Solutions Inc", + "total_observation_count": 0, + "type": "Company" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#28a745", + "description": "", + "emoji": "🚀", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "full-featured", + "observation_count": 0, + "title": "Full Featured Facet", + "updated_at": null + } + ], + "id": "third_test_entity_with_description", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Third test entity with description", + "total_observation_count": 0, + "type": "Entity 3" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#dc143c", + "description": "Juliet's cousin. VP of Engineering at Capulet Industries.", + "emoji": "🏰", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "capulet", + "observation_count": 4, + "title": "Capulet Industries", + "updated_at": null + } + ], + "id": "tybalt_capulet", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Tybalt Capulet", + "total_observation_count": 4, + "type": "Person" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#9370db", + "description": "Secret cross-company unified API gateway project.", + "emoji": "🌹", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "verona", + "observation_count": 0, + "title": "Verona", + "updated_at": null + } + ], + "id": "verona_platform", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Verona Platform", + "total_observation_count": 0, + "type": "Project" + }, + { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#007bff", + "description": "Primary IDE", + "emoji": "🧪", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "test-facet", + "observation_count": 0, + "title": "Test Facet", + "updated_at": null + } + ], + "id": "visual_studio_code", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "Visual Studio Code", + "total_observation_count": 0, + "type": "Tool" + }, + { + "aka": [], + "blocked": false, + "facets": [], + "id": "alice_johnson", + "is_principal": false, + "last_active_ts": 0, + "name": "Alice Johnson", + "total_observation_count": 0, + "type": "Person" + }, + { + "aka": [], + "blocked": false, + "facets": [], + "id": "bob_smith", + "is_principal": false, + "last_active_ts": 0, + "name": "Bob Smith", + "total_observation_count": 0, + "type": "Person" + } + ] +} diff --git a/tests/baselines/api/entities/journal-entity-detail.json b/tests/baselines/api/entities/journal-entity-detail.json new file mode 100644 index 000000000..215c8a0ea --- /dev/null +++ b/tests/baselines/api/entities/journal-entity-detail.json @@ -0,0 +1,27 @@ +{ + "entity": { + "aka": [], + "blocked": false, + "facets": [ + { + "attached_at": null, + "color": "#28a745", + "description": "", + "emoji": "🚀", + "has_voiceprint": false, + "last_active_ts": 1767225600000, + "last_seen": null, + "name": "full-featured", + "observation_count": 0, + "title": "Full Featured Facet", + "updated_at": null + } + ], + "id": "first_test_entity", + "is_principal": false, + "last_active_ts": 1767225600000, + "name": "First test entity", + "total_observation_count": 0, + "type": "Entity 1" + } +} diff --git a/tests/baselines/api/home/stats-month.json b/tests/baselines/api/home/stats-month.json new file mode 100644 index 000000000..9d73d9d17 --- /dev/null +++ b/tests/baselines/api/home/stats-month.json @@ -0,0 +1,9 @@ +{ + "20260304": 7, + "20260305": 6, + "20260306": 7, + "20260307": 5, + "20260308": 7, + "20260309": 9, + "20260310": 9 +} diff --git a/tests/baselines/api/home/summary.json b/tests/baselines/api/home/summary.json new file mode 100644 index 000000000..edd3ac80b --- /dev/null +++ b/tests/baselines/api/home/summary.json @@ -0,0 +1,191 @@ +{ + "day": "20260304", + "facet_meta": { + "capulet": { + "color": "#dc143c", + "emoji": "🏰", + "has_activity": true, + "title": "Capulet Industries" + }, + "empty-entities": { + "color": "", + "emoji": "", + "has_activity": false, + "title": "Empty Entities Test" + }, + "full-featured": { + "color": "#28a745", + "emoji": "🚀", + "has_activity": false, + "title": "Full Featured Facet" + }, + "minimal-facet": { + "color": "", + "emoji": "", + "has_activity": false, + "title": "Minimal Facet" + }, + "montague": { + "color": "#1e90ff", + "emoji": "⚔️", + "has_activity": true, + "title": "Montague Tech" + }, + "priority-test": { + "color": "", + "emoji": "", + "has_activity": false, + "title": "Priority Test" + }, + "test-facet": { + "color": "#007bff", + "emoji": "🧪", + "has_activity": false, + "title": "Test Facet" + }, + "verona": { + "color": "#9370db", + "emoji": "🌹", + "has_activity": false, + "title": "Verona" + } + }, + "facets": { + "capulet": { + "entities": [ + "Juliet Capulet", + "Tybalt Capulet", + "Capulet Industries" + ], + "events_by_agent": { + "flow": 2, + "user": 1 + }, + "goal": null, + "news_content": "# 2026-03-04 News - Capulet Industries\n\n## Juliet Capulet Delivers Keynote at Denver Tech Summit\n**Source:** capulet-internal | **Time:** 10:30\nLead architect Juliet Capulet delivered a keynote on unified API gateway architecture to a packed audience. The presentation showcased Capulet Industries' enterprise schema translation technology.\n", + "todos": [ + { + "completed": true, + "nudge": null, + "text": "Deliver keynote presentation at Denver Tech Summit" + }, + { + "completed": true, + "nudge": null, + "text": "Network with potential partners at conference mixer" + } + ] + }, + "empty-entities": { + "entities": [], + "events_by_agent": {}, + "goal": null, + "news_content": null, + "todos": [] + }, + "full-featured": { + "entities": [], + "events_by_agent": {}, + "goal": null, + "news_content": null, + "todos": [] + }, + "minimal-facet": { + "entities": [], + "events_by_agent": {}, + "goal": null, + "news_content": null, + "todos": [] + }, + "montague": { + "entities": [ + "Romeo Montague", + "Mercutio Escalus", + "Montague Tech" + ], + "events_by_agent": { + "flow": 2, + "user": 1 + }, + "goal": null, + "news_content": "# 2026-03-04 News - Montague Tech\n\n## Denver Tech Summit Kicks Off with API Innovation Focus\n**Source:** techcrunch.com | **Time:** 08:30\nThe Denver Tech Summit opened with a focus on API interoperability. Both Montague Tech and Capulet Industries are presenting competing solutions. Industry analysts expect the API gateway market to reach $12B by 2028.\n\n## Capulet Industries Keynote Draws Standing Ovation\n**Source:** internal | **Time:** 10:15\nJuliet Capulet's keynote on unified API gateways was the talk of the conference. Several attendees noted similarities to Montague Tech's approach.\n", + "todos": [ + { + "completed": true, + "nudge": null, + "text": "Review hackathon API bridge prototype" + }, + { + "completed": true, + "nudge": null, + "text": "Follow up with Juliet Capulet about gateway collaboration" + } + ] + }, + "priority-test": { + "entities": [], + "events_by_agent": {}, + "goal": null, + "news_content": null, + "todos": [] + }, + "test-facet": { + "entities": [], + "events_by_agent": {}, + "goal": null, + "news_content": null, + "todos": [] + }, + "verona": { + "entities": [], + "events_by_agent": {}, + "goal": null, + "news_content": null, + "todos": [] + } + }, + "recent_entities": {}, + "totals": { + "entities": 6, + "events": 6, + "events_by_agent": { + "flow": 4, + "user": 2 + }, + "recent_entities": 0, + "todos_completed": 4, + "todos_pending": 0 + }, + "upcoming": [ + { + "day": "20260305", + "facet": "montague", + "title": "Montague Tech Daily Standup", + "type": "event" + }, + { + "day": "20260305", + "facet": "montague", + "title": "Team Standup", + "type": "event" + }, + { + "day": "20260305", + "facet": "verona", + "title": "Balcony App Prototype Session", + "type": "event" + }, + { + "day": "20260306", + "facet": "capulet", + "title": "Capulet Industries Board Meeting", + "type": "event" + }, + { + "day": "20260306", + "facet": "montague", + "title": "Montague Tech Daily Standup", + "type": "event" + } + ] +} diff --git a/tests/baselines/api/import/import-day.json b/tests/baselines/api/import/import-day.json new file mode 100644 index 000000000..a658493e2 --- /dev/null +++ b/tests/baselines/api/import/import-day.json @@ -0,0 +1,3 @@ +{ + "error": "Import not found" +} diff --git a/tests/baselines/api/import/list.json b/tests/baselines/api/import/list.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/tests/baselines/api/import/list.json @@ -0,0 +1 @@ +[] diff --git a/tests/baselines/api/remote/ingest-day.json b/tests/baselines/api/remote/ingest-day.json new file mode 100644 index 000000000..844b5747a --- /dev/null +++ b/tests/baselines/api/remote/ingest-day.json @@ -0,0 +1,3 @@ +{ + "error": "Invalid key" +} diff --git a/tests/baselines/api/remote/list.json b/tests/baselines/api/remote/list.json new file mode 100644 index 000000000..fe51488c7 --- /dev/null +++ b/tests/baselines/api/remote/list.json @@ -0,0 +1 @@ +[] diff --git a/tests/baselines/api/remote/remote-key.json b/tests/baselines/api/remote/remote-key.json new file mode 100644 index 000000000..e037d35f9 --- /dev/null +++ b/tests/baselines/api/remote/remote-key.json @@ -0,0 +1,3 @@ +{ + "error": "Remote not found" +} diff --git a/tests/baselines/api/search/day-results.json b/tests/baselines/api/search/day-results.json new file mode 100644 index 000000000..9f785be4e --- /dev/null +++ b/tests/baselines/api/search/day-results.json @@ -0,0 +1,23 @@ +{ + "day": "20260304", + "offset": 0, + "results": [ + { + "agent": "knowledge_graph", + "agent_icon": "🗺️", + "agent_label": "Knowledge Graph", + "day": "20260304", + "facet": "", + "facet_color": "", + "facet_emoji": "", + "facet_title": "", + "id": "20260304/agents/knowledge_graph.md:7", + "idx": 7, + "path": "20260304/agents/knowledge_graph.md", + "score": -1.4436730957253632, + "stream": null, + "text": "# Part 1: Entity Extraction and Relationship Mapping\n\n## Relationship Mapping\n\n| Source Name | Target Name | Relationship Type | Context |\n| :--- | :--- | :--- | :--- |\n| **Romeo Montague** | **Juliet Capulet** | `met-at-conference` | First meeting at Denver Tech Summit keynote. |\n" + } + ], + "total": 1 +} diff --git a/tests/baselines/api/search/search.json b/tests/baselines/api/search/search.json new file mode 100644 index 000000000..a7961e2f9 --- /dev/null +++ b/tests/baselines/api/search/search.json @@ -0,0 +1,734 @@ +{ + "agents": [ + { + "count": 22, + "icon": "📅", + "label": "Event", + "name": "event" + }, + { + "count": 14, + "icon": "🎤", + "label": "Transcript", + "name": "audio" + }, + { + "count": 13, + "icon": "🗺️", + "label": "Knowledge Graph", + "name": "knowledge_graph" + }, + { + "count": 10, + "icon": "👤", + "label": "Entity", + "name": "entity:detected" + }, + { + "count": 5, + "icon": "📄", + "label": "Observation", + "name": "observation" + }, + { + "count": 4, + "icon": "📄", + "label": "Action", + "name": "action" + }, + { + "count": 2, + "icon": "📅", + "label": "Meetings", + "name": "meetings" + }, + { + "count": 2, + "icon": "📄", + "label": "Session_Review", + "name": "session_review" + }, + { + "count": 1, + "icon": "🖥️", + "label": "Screen", + "name": "screen" + }, + { + "count": 1, + "icon": "📰", + "label": "News", + "name": "news" + } + ], + "days": [ + { + "date": "Tuesday March 10th", + "day": "20260310", + "has_more": true, + "results": [ + { + "agent": "entity:detected", + "agent_icon": "👤", + "agent_label": "Entity", + "day": "20260310", + "facet": "verona", + "facet_color": "#9370db", + "facet_emoji": "🌹", + "facet_title": "Verona", + "id": "facets/verona/entities/20260310.jsonl:0", + "idx": 0, + "path": "facets/verona/entities/20260310.jsonl", + "score": -1.5307228656710488, + "stream": null, + "text": "### Person: Romeo Montague\n\n\nNamed co-lead of approved joint venture\n\n" + }, + { + "agent": "meetings", + "agent_icon": "📅", + "agent_label": "Meetings", + "day": "20260310", + "facet": "", + "facet_color": "", + "facet_emoji": "", + "facet_title": "", + "id": "20260310/agents/meetings.md:0", + "idx": 0, + "path": "20260310/agents/meetings.md", + "score": -1.5307228656710488, + "stream": null, + "text": "# Meetings\n\n- 08:30 Pre-Board Meeting Prep (Romeo, Juliet, Benvolio)\n" + }, + { + "agent": "entity:detected", + "agent_icon": "👤", + "agent_label": "Entity", + "day": "20260310", + "facet": "montague", + "facet_color": "#1e90ff", + "facet_emoji": "⚔️", + "facet_title": "Montague Tech", + "id": "facets/montague/entities/20260310.jsonl:0", + "idx": 0, + "path": "facets/montague/entities/20260310.jsonl", + "score": -1.4887670072689274, + "stream": null, + "text": "### Person: Romeo Montague\n\n\nNamed co-lead of Verona Platform joint venture\n\n" + }, + { + "agent": "event", + "agent_icon": "📅", + "agent_label": "Event", + "day": "20260310", + "facet": "montague", + "facet_color": "#1e90ff", + "facet_emoji": "⚔️", + "facet_title": "Montague Tech", + "id": "facets/montague/calendar/20260310.jsonl:0", + "idx": 0, + "path": "facets/montague/calendar/20260310.jsonl", + "score": -1.168492732186317, + "stream": null, + "text": "### Event: Joint Board Meeting\n\n\n**Time Occurred:** 10:00 - 12:00\n**Participants:** Romeo Montague, Benvolio Montague\n\nQuarterly review with Verona Platform presentation\n" + }, + { + "agent": "event", + "agent_icon": "📅", + "agent_label": "Event", + "day": "20260310", + "facet": "verona", + "facet_color": "#9370db", + "facet_emoji": "🌹", + "facet_title": "Verona", + "id": "facets/verona/calendar/20260310.jsonl:0", + "idx": 0, + "path": "facets/verona/calendar/20260310.jsonl", + "score": -1.168492732186317, + "stream": null, + "text": "### Event: Board Presentation\n\n\n**Time Occurred:** 10:00 - 12:00\n**Participants:** Romeo Montague, Juliet Capulet, Friar Lawrence\n\nVerona Platform joint venture pitch\n" + } + ], + "showing": 5, + "total": 14 + }, + { + "date": "Monday March 9th", + "day": "20260309", + "has_more": true, + "results": [ + { + "agent": "entity:detected", + "agent_icon": "👤", + "agent_label": "Entity", + "day": "20260309", + "facet": "montague", + "facet_color": "#1e90ff", + "facet_emoji": "⚔️", + "facet_title": "Montague Tech", + "id": "facets/montague/entities/20260309.jsonl:0", + "idx": 0, + "path": "facets/montague/entities/20260309.jsonl", + "score": -1.575112067299254, + "stream": null, + "text": "### Person: Romeo Montague\n\n\nConfessed project to Benvolio, preparing demo\n\n" + }, + { + "agent": "event", + "agent_icon": "📅", + "agent_label": "Event", + "day": "20260309", + "facet": "montague", + "facet_color": "#1e90ff", + "facet_emoji": "⚔️", + "facet_title": "Montague Tech", + "id": "facets/montague/calendar/20260309.jsonl:0", + "idx": 0, + "path": "facets/montague/calendar/20260309.jsonl", + "score": -1.3093288564023835, + "stream": null, + "text": "### Event: Team Standup\n\n\n**Time Occurred:** 09:00 - 09:30\n**Participants:** Romeo Montague, Benvolio Montague\n\nDaily sync\n" + }, + { + "agent": "action", + "agent_icon": "📄", + "agent_label": "Action", + "day": "20260309", + "facet": "verona", + "facet_color": "#9370db", + "facet_emoji": "🌹", + "facet_title": "Verona", + "id": "facets/verona/logs/20260309.jsonl:1", + "idx": 1, + "path": "facets/verona/logs/20260309.jsonl", + "score": -1.2210279986467902, + "stream": null, + "text": "### Deploy Complete by romeo_montague\n\n**Source:** deploy | **Time:** 13:45:00\n\n**Parameters:**\n- service: verona-gateway\n- version: 0.9.0\n" + }, + { + "agent": "event", + "agent_icon": "📅", + "agent_label": "Event", + "day": "20260309", + "facet": "verona", + "facet_color": "#9370db", + "facet_emoji": "🌹", + "facet_title": "Verona", + "id": "facets/verona/calendar/20260309.jsonl:0", + "idx": 0, + "path": "facets/verona/calendar/20260309.jsonl", + "score": -1.168492732186317, + "stream": null, + "text": "### Event: Demo Sprint\n\n\n**Time Occurred:** 09:00 - 21:00\n**Participants:** Romeo Montague, Juliet Capulet, Benvolio Montague\n\nFull day board presentation preparation\n" + }, + { + "agent": "audio", + "agent_icon": "🎤", + "agent_label": "Transcript", + "day": "20260309", + "facet": "", + "facet_color": "", + "facet_emoji": "", + "facet_title": "", + "id": "20260309/default/090000_300/agents/audio.md:0", + "idx": 0, + "path": "20260309/default/090000_300/agents/audio.md", + "score": -1.1438846619447198, + "stream": "default", + "text": "# Audio Summary\n\nRomeo confessed the project to Benvolio and asked for infrastructure help. Benvolio agreed to spin up a Kubernetes staging cluster.\n" + } + ], + "showing": 5, + "total": 7 + }, + { + "date": "Sunday March 8th", + "day": "20260308", + "has_more": false, + "results": [ + { + "agent": "entity:detected", + "agent_icon": "👤", + "agent_label": "Entity", + "day": "20260308", + "facet": "montague", + "facet_color": "#1e90ff", + "facet_emoji": "⚔️", + "facet_title": "Montague Tech", + "id": "facets/montague/entities/20260308.jsonl:0", + "idx": 0, + "path": "facets/montague/entities/20260308.jsonl", + "score": -1.575112067299254, + "stream": null, + "text": "### Person: Romeo Montague\n\n\nUnder board pressure, planning board presentation\n\n" + }, + { + "agent": "meetings", + "agent_icon": "📅", + "agent_label": "Meetings", + "day": "20260308", + "facet": "", + "facet_color": "", + "facet_emoji": "", + "facet_title": "", + "id": "20260308/agents/meetings.md:0", + "idx": 0, + "path": "20260308/agents/meetings.md", + "score": -1.4887670072689274, + "stream": null, + "text": "# Meetings\n\n- 10:00 Strategy Call with Professor Lawrence, Romeo, and Juliet\n" + }, + { + "agent": "event", + "agent_icon": "📅", + "agent_label": "Event", + "day": "20260308", + "facet": "verona", + "facet_color": "#9370db", + "facet_emoji": "🌹", + "facet_title": "Verona", + "id": "facets/verona/events/20260308.jsonl:0", + "idx": 0, + "path": "facets/verona/events/20260308.jsonl", + "score": -1.0349103179215573, + "stream": null, + "text": "### Meeting: Strategy Call with Professor Lawrence\n\n\n**Time Occurred:** 10:00 - 11:00\n**Participants:** Romeo Montague, Juliet Capulet, Friar Lawrence\n\nJoint venture strategy planning\n\nProposed board presentation strategy\n" + }, + { + "agent": "knowledge_graph", + "agent_icon": "🗺️", + "agent_label": "Knowledge Graph", + "day": "20260308", + "facet": "", + "facet_color": "", + "facet_emoji": "", + "facet_title": "", + "id": "20260308/agents/knowledge_graph.md:2", + "idx": 2, + "path": "20260308/agents/knowledge_graph.md", + "score": -0.9789532159083478, + "stream": null, + "text": "# Part 1: Entity Extraction and Relationship Mapping ## Entity Profiles | Entity Name | Entity Type | First Appearance | Total Engagement | Context | | :--- | :--- | :--- | :--- | :--- | | **Romeo Montague** | Person | 10:00 | High | Under board pressure,..." + } + ], + "showing": 4, + "total": 4 + }, + { + "date": "Saturday March 7th", + "day": "20260307", + "has_more": true, + "results": [ + { + "agent": "audio", + "agent_icon": "🎤", + "agent_label": "Transcript", + "day": "20260307", + "facet": "", + "facet_color": "", + "facet_emoji": "", + "facet_title": "", + "id": "20260307/default/150000_300/agents/audio.md:0", + "idx": 0, + "path": "20260307/default/150000_300/agents/audio.md", + "score": -1.7028768182172829, + "stream": "default", + "text": "# Audio Summary\n\nEmergency meeting at Montague Tech. Benvolio questioned Romeo about the secret project. Romeo clarified no company IP was shared. Team discussed legal exposure. Romeo proposed Professor Lawrence as mediator.\n" + }, + { + "agent": "entity:detected", + "agent_icon": "👤", + "agent_label": "Entity", + "day": "20260307", + "facet": "montague", + "facet_color": "#1e90ff", + "facet_emoji": "⚔️", + "facet_title": "Montague Tech", + "id": "facets/montague/entities/20260307.jsonl:0", + "idx": 0, + "path": "facets/montague/entities/20260307.jsonl", + "score": -1.575112067299254, + "stream": null, + "text": "### Person: Romeo Montague\n\n\nConfronted by Tybalt, called emergency meeting\n\n" + }, + { + "agent": "audio", + "agent_icon": "🎤", + "agent_label": "Transcript", + "day": "20260307", + "facet": "", + "facet_color": "", + "facet_emoji": "", + "facet_title": "", + "id": "20260307/default/100000_300/agents/audio.md:0", + "idx": 0, + "path": "20260307/default/100000_300/agents/audio.md", + "score": -1.5723979166950623, + "stream": "default", + "text": "# Audio Summary\n\nHeated confrontation. Tybalt Capulet accused Romeo of stealing Capulet IP. Mercutio defended Romeo and had his Capulet consulting contract terminated by Tybalt.\n" + }, + { + "agent": "event", + "agent_icon": "📅", + "agent_label": "Event", + "day": "20260307", + "facet": "montague", + "facet_color": "#1e90ff", + "facet_emoji": "⚔️", + "facet_title": "Montague Tech", + "id": "facets/montague/events/20260307.jsonl:0", + "idx": 0, + "path": "facets/montague/events/20260307.jsonl", + "score": -1.4863420420057027, + "stream": null, + "text": "### Meeting: Confrontation with Tybalt\n\n\n**Time Occurred:** 10:00 - 10:30\n**Participants:** Romeo Montague, Tybalt Capulet, Mercutio Escalus\n\nTybalt accused Romeo of IP theft\n\nMercutio fired from Capulet contract\n" + }, + { + "agent": "event", + "agent_icon": "📅", + "agent_label": "Event", + "day": "20260307", + "facet": "montague", + "facet_color": "#1e90ff", + "facet_emoji": "⚔️", + "facet_title": "Montague Tech", + "id": "facets/montague/calendar/20260307.jsonl:0", + "idx": 0, + "path": "facets/montague/calendar/20260307.jsonl", + "score": -1.1941828533266896, + "stream": null, + "text": "### Event: Emergency Team Meeting\n\n\n**Time Occurred:** 15:00 - 16:00\n**Participants:** Romeo Montague, Benvolio Montague\n\nCrisis response to Capulet situation\n" + } + ], + "showing": 5, + "total": 7 + }, + { + "date": "Friday March 6th", + "day": "20260306", + "has_more": true, + "results": [ + { + "agent": "entity:detected", + "agent_icon": "👤", + "agent_label": "Entity", + "day": "20260306", + "facet": "montague", + "facet_color": "#1e90ff", + "facet_emoji": "⚔️", + "facet_title": "Montague Tech", + "id": "facets/montague/entities/20260306.jsonl:0", + "idx": 0, + "path": "facets/montague/entities/20260306.jsonl", + "score": -1.6720894044503443, + "stream": null, + "text": "### Person: Romeo Montague\n\n\nContinued Verona Platform development\n\n" + }, + { + "agent": "audio", + "agent_icon": "🎤", + "agent_label": "Transcript", + "day": "20260306", + "facet": "", + "facet_color": "", + "facet_emoji": "", + "facet_title": "", + "id": "20260306/default/093000_300/agents/audio.md:0", + "idx": 0, + "path": "20260306/default/093000_300/agents/audio.md", + "score": -1.5954917665031494, + "stream": "default", + "text": "# Audio Summary\n\nMorning standup. Benvolio noticed Romeo's late-night GitHub activity. Romeo deflected, calling it a personal project. Mercutio covered for him.\n" + }, + { + "agent": "screen", + "agent_icon": "🖥️", + "agent_label": "Screen", + "day": "20260306", + "facet": "", + "facet_color": "", + "facet_emoji": "", + "facet_title": "", + "id": "20260306/default/093000_300/agents/screen.md:0", + "idx": 0, + "path": "20260306/default/093000_300/agents/screen.md", + "score": -1.4490497422009865, + "stream": "default", + "text": "# Screen Summary\n\nSlack standup channel. Benvolio questioning Romeo about late-night commits.\n" + }, + { + "agent": "session_review", + "agent_icon": "📄", + "agent_label": "Session_Review", + "day": "20260306", + "facet": "verona", + "facet_color": "#9370db", + "facet_emoji": "🌹", + "facet_title": "Verona", + "id": "facets/verona/activities/20260306/engineering_143000_300/session_review.md:4", + "idx": 4, + "path": "facets/verona/activities/20260306/engineering_143000_300/session_review.md", + "score": -1.3093288564023835, + "stream": null, + "text": "# Engineering Session Review\n\n## Engagement\n\nHigh focus session with both Romeo and Juliet actively coding and testing.\n" + }, + { + "agent": "action", + "agent_icon": "📄", + "agent_label": "Action", + "day": "20260306", + "facet": "verona", + "facet_color": "#9370db", + "facet_emoji": "🌹", + "facet_title": "Verona", + "id": "facets/verona/logs/20260306.jsonl:0", + "idx": 0, + "path": "facets/verona/logs/20260306.jsonl", + "score": -1.1941828533266896, + "stream": null, + "text": "### Push by romeo_montague\n\n**Source:** github | **Time:** 14:35:00\n\n**Parameters:**\n- repo: verona-platform\n- branch: main\n- files: ['verona/gateway.py']\n" + } + ], + "showing": 5, + "total": 13 + }, + { + "date": "Thursday March 5th", + "day": "20260305", + "has_more": true, + "results": [ + { + "agent": "entity:detected", + "agent_icon": "👤", + "agent_label": "Entity", + "day": "20260305", + "facet": "montague", + "facet_color": "#1e90ff", + "facet_emoji": "⚔️", + "facet_title": "Montague Tech", + "id": "facets/montague/entities/20260305.jsonl:0", + "idx": 0, + "path": "facets/montague/entities/20260305.jsonl", + "score": -1.575112067299254, + "stream": null, + "text": "### Person: Romeo Montague\n\n\nStarted Balcony App prototype with Juliet\n\n" + }, + { + "agent": "entity:detected", + "agent_icon": "👤", + "agent_label": "Entity", + "day": "20260305", + "facet": "verona", + "facet_color": "#9370db", + "facet_emoji": "🌹", + "facet_title": "Verona", + "id": "facets/verona/entities/20260305.jsonl:0", + "idx": 0, + "path": "facets/verona/entities/20260305.jsonl", + "score": -1.575112067299254, + "stream": null, + "text": "### Person: Romeo Montague\n\n\nSet up private repo for collaboration\n\n" + }, + { + "agent": "event", + "agent_icon": "📅", + "agent_label": "Event", + "day": "20260305", + "facet": "montague", + "facet_color": "#1e90ff", + "facet_emoji": "⚔️", + "facet_title": "Montague Tech", + "id": "facets/montague/events/20260305.jsonl:0", + "idx": 0, + "path": "facets/montague/events/20260305.jsonl", + "score": -1.5723979166950623, + "stream": null, + "text": "### Meeting: Montague Tech Daily Standup\n\n\n**Time Occurred:** 09:00 - 09:30\n**Participants:** Romeo Montague, Benvolio Montague, Mercutio Escalus\n\nTeam standup\n\nRomeo mentioned conference ideas\n" + }, + { + "agent": "audio", + "agent_icon": "🎤", + "agent_label": "Transcript", + "day": "20260305", + "facet": "", + "facet_color": "", + "facet_emoji": "", + "facet_title": "", + "id": "20260305/default/090000_300/agents/audio.md:0", + "idx": 0, + "path": "20260305/default/090000_300/agents/audio.md", + "score": -1.4863420420057027, + "stream": "default", + "text": "# Audio Summary\n\nMorning standup at Montague Tech. Benvolio reported CI pipeline is green. Romeo mentioned wanting to explore ideas from the conference. Mercutio teased about Romeo meeting someone.\n" + }, + { + "agent": "action", + "agent_icon": "📄", + "agent_label": "Action", + "day": "20260305", + "facet": "verona", + "facet_color": "#9370db", + "facet_emoji": "🌹", + "facet_title": "Verona", + "id": "facets/verona/logs/20260305.jsonl:0", + "idx": 0, + "path": "facets/verona/logs/20260305.jsonl", + "score": -1.278509608147816, + "stream": null, + "text": "### Repo Created by romeo_montague\n\n**Source:** github | **Time:** 22:05:00\n\n**Parameters:**\n- repo: balcony-app\n- visibility: private\n" + } + ], + "showing": 5, + "total": 10 + }, + { + "date": "Wednesday March 4th", + "day": "20260304", + "has_more": true, + "results": [ + { + "agent": "entity:detected", + "agent_icon": "👤", + "agent_label": "Entity", + "day": "20260304", + "facet": "capulet", + "facet_color": "#dc143c", + "facet_emoji": "🏰", + "facet_title": "Capulet Industries", + "id": "facets/capulet/entities/20260304.jsonl:1", + "idx": 1, + "path": "facets/capulet/entities/20260304.jsonl", + "score": -1.6720894044503443, + "stream": null, + "text": "### Person: Tybalt Capulet\n\n\nConfronted Romeo at hackathon\n\n" + }, + { + "agent": "event", + "agent_icon": "📅", + "agent_label": "Event", + "day": "20260304", + "facet": "capulet", + "facet_color": "#dc143c", + "facet_emoji": "🏰", + "facet_title": "Capulet Industries", + "id": "facets/capulet/events/20260304.jsonl:1", + "idx": 1, + "path": "facets/capulet/events/20260304.jsonl", + "score": -1.6192740878777379, + "stream": null, + "text": "### Social: Conference Mixer\n\n\n**Time Occurred:** 18:00 - 20:00\n**Participants:** Juliet Capulet, Romeo Montague\n\nNetworking event\n\nJuliet and Romeo exchanged Signal contacts\n" + }, + { + "agent": "event", + "agent_icon": "📅", + "agent_label": "Event", + "day": "20260304", + "facet": "montague", + "facet_color": "#1e90ff", + "facet_emoji": "⚔️", + "facet_title": "Montague Tech", + "id": "facets/montague/events/20260304.jsonl:1", + "idx": 1, + "path": "facets/montague/events/20260304.jsonl", + "score": -1.5954917665031494, + "stream": null, + "text": "### Hackathon: Hackathon - API Bridge Challenge\n\n\n**Time Occurred:** 14:00 - 18:00\n**Participants:** Romeo Montague, Mercutio Escalus\n\nBuilt API bridge prototype\n\nTybalt confronted Romeo\n" + }, + { + "agent": "entity:detected", + "agent_icon": "👤", + "agent_label": "Entity", + "day": "20260304", + "facet": "montague", + "facet_color": "#1e90ff", + "facet_emoji": "⚔️", + "facet_title": "Montague Tech", + "id": "facets/montague/entities/20260304.jsonl:0", + "idx": 0, + "path": "facets/montague/entities/20260304.jsonl", + "score": -1.5307228656710488, + "stream": null, + "text": "### Person: Romeo Montague\n\n\nAttended Denver Tech Summit, met Juliet Capulet\n\n" + }, + { + "agent": "audio", + "agent_icon": "🎤", + "agent_label": "Transcript", + "day": "20260304", + "facet": "", + "facet_color": "", + "facet_emoji": "", + "facet_title": "", + "id": "20260304/default/180000_300/agents/audio.md:0", + "idx": 0, + "path": "20260304/default/180000_300/agents/audio.md", + "score": -1.4662800069448867, + "stream": "default", + "text": "# Audio Summary\n\nEvening mixer at Denver Tech Summit. Romeo and Juliet had their first extended conversation about combining their API approaches. Mercutio tried to pull Romeo away to karaoke.\n" + } + ], + "showing": 5, + "total": 14 + } + ], + "facets": [ + { + "color": "#1e90ff", + "count": 23, + "emoji": "⚔️", + "name": "montague", + "title": "Montague Tech" + }, + { + "color": "#9370db", + "count": 14, + "emoji": "🌹", + "name": "verona", + "title": "Verona" + }, + { + "color": "#dc143c", + "count": 7, + "emoji": "🏰", + "name": "capulet", + "title": "Capulet Industries" + }, + { + "color": "", + "count": 0, + "emoji": "", + "name": "empty-entities", + "title": "Empty Entities Test" + }, + { + "color": "#28a745", + "count": 0, + "emoji": "🚀", + "name": "full-featured", + "title": "Full Featured Facet" + }, + { + "color": "", + "count": 0, + "emoji": "", + "name": "minimal-facet", + "title": "Minimal Facet" + }, + { + "color": "", + "count": 0, + "emoji": "", + "name": "priority-test", + "title": "Priority Test" + }, + { + "color": "#007bff", + "count": 0, + "emoji": "🧪", + "name": "test-facet", + "title": "Test Facet" + } + ], + "showing_days": 7, + "total": 74, + "total_days": 7 +} diff --git a/tests/baselines/api/settings/activities-defaults.json b/tests/baselines/api/settings/activities-defaults.json new file mode 100644 index 000000000..758069a2e --- /dev/null +++ b/tests/baselines/api/settings/activities-defaults.json @@ -0,0 +1,104 @@ +{ + "activities": [ + { + "description": "Video calls, in-person meetings, and conferences", + "icon": "📅", + "id": "meeting", + "instructions": "Levels: high=actively speaking/presenting, medium=listening attentively, low=muted or multitasking during call. Detect via: video call UI, multiple speakers, calendar event visible.", + "name": "Meetings" + }, + { + "description": "Programming, code review, and debugging", + "icon": "💻", + "id": "coding", + "instructions": "Levels: high=writing or debugging code, medium=reading/reviewing code, low=IDE or editor open but not focused. Detect via: editors, terminals with dev tools, AI coding assistants, git operations. Includes focused code reading and thinking.", + "name": "Coding" + }, + { + "description": "Web browsing, research, and reading online", + "icon": "🌐", + "id": "browsing", + "instructions": "Levels: high=actively navigating/researching, medium=reading a page, low=browser open but idle. Detect via: browser tabs, URL changes, search queries.", + "name": "Browsing" + }, + { + "always_on": true, + "description": "Email reading and composition", + "icon": "📧", + "id": "email", + "instructions": "Levels: high=composing or actively reading email, medium=scanning inbox, low=email client visible but idle. Detect via: email client UI, inbox view, compose window.", + "name": "Email" + }, + { + "always_on": true, + "description": "Chat, Slack, Discord, and text messaging", + "icon": "💬", + "id": "messaging", + "instructions": "Levels: high=active conversation, medium=reading messages, low=chat app visible but idle. Detect via: chat app UI, message notifications, typing indicators.", + "name": "Messaging" + }, + { + "description": "Documents, notes, and long-form writing", + "icon": "✍️", + "id": "writing", + "instructions": "Levels: high=actively composing text, medium=editing/revising, low=document open but not being edited. Detect via: document editors, note apps, text content changing.", + "name": "Writing" + }, + { + "description": "PDFs, articles, and documentation", + "icon": "📖", + "id": "reading", + "instructions": "Levels: high=focused reading, medium=skimming content, low=document open but attention elsewhere. Detect via: PDF viewers, article pages, documentation sites. Do not use for reading code — that is coding.", + "name": "Reading" + }, + { + "description": "Watching videos and streaming content", + "icon": "🎬", + "id": "video", + "instructions": "Levels: high=actively watching, medium=video playing while doing something else, low=video paused or minimized. Detect via: video player UI, streaming sites, playback controls.", + "name": "Video" + }, + { + "description": "Games and entertainment", + "icon": "🎮", + "id": "gaming", + "instructions": "Levels: high=actively playing, medium=in menus or waiting, low=game open but tabbed out. Detect via: game window, controller input, game UI elements.", + "name": "Gaming" + }, + { + "description": "Social media browsing and interaction", + "icon": "📱", + "id": "social", + "instructions": "Levels: high=posting or actively engaging, medium=scrolling feed, low=social app open but idle. Detect via: social media sites/apps, feed content, post composition.", + "name": "Social Media" + }, + { + "description": "Spreadsheets, slides, and task management", + "icon": "📊", + "id": "productivity", + "instructions": "Levels: high=actively editing or organizing, medium=reviewing data, low=app open but not focused. Detect via: spreadsheet/slide editors, project management tools, calendar apps, task boards.", + "name": "Productivity" + }, + { + "description": "Command line and shell sessions", + "icon": "⌨️", + "id": "terminal", + "instructions": "Levels: high=running commands or scripts, medium=reading output, low=terminal open but idle. Detect via: shell prompts, command output, tmux/screen sessions. If terminal use is clearly coding-related, prefer coding instead.", + "name": "Terminal" + }, + { + "description": "Design tools and image editing", + "icon": "🎨", + "id": "design", + "instructions": "Levels: high=actively creating or editing, medium=reviewing designs, low=design tool open but idle. Detect via: design apps (Figma, Photoshop, etc), canvas editing.", + "name": "Design" + }, + { + "description": "Music listening and audio", + "icon": "🎵", + "id": "music", + "instructions": "Levels: high=actively choosing or browsing music, medium=playlist running while working, low=ambient background audio. Detect via: music player UI, audio playback indicators.", + "name": "Music" + } + ] +} diff --git a/tests/baselines/api/settings/config.json b/tests/baselines/api/settings/config.json new file mode 100644 index 000000000..b95661f6d --- /dev/null +++ b/tests/baselines/api/settings/config.json @@ -0,0 +1,98 @@ +{ + "convey": { + "password": "test123" + }, + "describe": { + "redact": [ + "replace test-secret-key with ***" + ] + }, + "env": { + "TEST_CONFIG_ENV_VAR": true + }, + "identity": { + "aliases": [ + "Tester", + "test" + ], + "bio": "", + "email_addresses": [ + "test@example.com" + ], + "name": "Test User", + "preferred": "Tester", + "pronouns": { + "object": "them", + "possessive": "their", + "reflexive": "themselves", + "subject": "they" + }, + "timezone": "America/Denver" + }, + "providers": { + "cogitate": { + "backup": "anthropic", + "provider": "openai", + "tier": 2 + }, + "contexts": { + "observe.*": { + "provider": "google", + "tier": 3 + }, + "test.anthropic": { + "model": "claude-sonnet-4-5", + "provider": "anthropic" + }, + "test.config.override": { + "provider": "google", + "tier": 2 + }, + "test.openai": { + "model": "gpt-5-mini", + "provider": "openai" + }, + "test.tier": { + "provider": "google", + "tier": 1 + }, + "test.tier.inherit": { + "tier": 3 + }, + "test.tier.override": { + "provider": "openai", + "tier": 2 + } + }, + "generate": { + "backup": "anthropic", + "provider": "google", + "tier": 2 + }, + "models": { + "google": { + "2": "gemini-custom-flash-test" + } + } + }, + "system_env": { + "ANTHROPIC_API_KEY": false, + "GOOGLE_API_KEY": false, + "OPENAI_API_KEY": false, + "PLAUD_ACCESS_TOKEN": false, + "REVAI_ACCESS_TOKEN": false + }, + "transcribe": { + "backend": "whisper", + "enrich": true, + "noise_upgrade": true, + "revai": { + "model": "fusion" + }, + "whisper": { + "compute_type": "default", + "device": "auto", + "model": "medium.en" + } + } +} diff --git a/tests/baselines/api/settings/facet-activities.json b/tests/baselines/api/settings/facet-activities.json new file mode 100644 index 000000000..cdc927020 --- /dev/null +++ b/tests/baselines/api/settings/facet-activities.json @@ -0,0 +1,142 @@ +{ + "activities": [ + { + "custom": true, + "description": "Software development and coding", + "id": "engineering", + "name": "Engineering", + "priority": "high" + }, + { + "custom": false, + "description": "Meetings and sync calls", + "icon": "📅", + "id": "meeting", + "instructions": "Levels: high=actively speaking/presenting, medium=listening attentively, low=muted or multitasking during call. Detect via: video call UI, multiple speakers, calendar event visible.", + "name": "Meetings", + "priority": "high" + }, + { + "always_on": true, + "custom": false, + "description": "Email reading and composition", + "icon": "📧", + "id": "email", + "instructions": "Levels: high=composing or actively reading email, medium=scanning inbox, low=email client visible but idle. Detect via: email client UI, inbox view, compose window.", + "name": "Email", + "priority": "normal" + }, + { + "always_on": true, + "custom": false, + "description": "Chat, Slack, Discord, and text messaging", + "icon": "💬", + "id": "messaging", + "instructions": "Levels: high=active conversation, medium=reading messages, low=chat app visible but idle. Detect via: chat app UI, message notifications, typing indicators.", + "name": "Messaging", + "priority": "normal" + } + ], + "defaults": [ + { + "description": "Video calls, in-person meetings, and conferences", + "icon": "📅", + "id": "meeting", + "instructions": "Levels: high=actively speaking/presenting, medium=listening attentively, low=muted or multitasking during call. Detect via: video call UI, multiple speakers, calendar event visible.", + "name": "Meetings" + }, + { + "description": "Programming, code review, and debugging", + "icon": "💻", + "id": "coding", + "instructions": "Levels: high=writing or debugging code, medium=reading/reviewing code, low=IDE or editor open but not focused. Detect via: editors, terminals with dev tools, AI coding assistants, git operations. Includes focused code reading and thinking.", + "name": "Coding" + }, + { + "description": "Web browsing, research, and reading online", + "icon": "🌐", + "id": "browsing", + "instructions": "Levels: high=actively navigating/researching, medium=reading a page, low=browser open but idle. Detect via: browser tabs, URL changes, search queries.", + "name": "Browsing" + }, + { + "always_on": true, + "description": "Email reading and composition", + "icon": "📧", + "id": "email", + "instructions": "Levels: high=composing or actively reading email, medium=scanning inbox, low=email client visible but idle. Detect via: email client UI, inbox view, compose window.", + "name": "Email" + }, + { + "always_on": true, + "description": "Chat, Slack, Discord, and text messaging", + "icon": "💬", + "id": "messaging", + "instructions": "Levels: high=active conversation, medium=reading messages, low=chat app visible but idle. Detect via: chat app UI, message notifications, typing indicators.", + "name": "Messaging" + }, + { + "description": "Documents, notes, and long-form writing", + "icon": "✍️", + "id": "writing", + "instructions": "Levels: high=actively composing text, medium=editing/revising, low=document open but not being edited. Detect via: document editors, note apps, text content changing.", + "name": "Writing" + }, + { + "description": "PDFs, articles, and documentation", + "icon": "📖", + "id": "reading", + "instructions": "Levels: high=focused reading, medium=skimming content, low=document open but attention elsewhere. Detect via: PDF viewers, article pages, documentation sites. Do not use for reading code — that is coding.", + "name": "Reading" + }, + { + "description": "Watching videos and streaming content", + "icon": "🎬", + "id": "video", + "instructions": "Levels: high=actively watching, medium=video playing while doing something else, low=video paused or minimized. Detect via: video player UI, streaming sites, playback controls.", + "name": "Video" + }, + { + "description": "Games and entertainment", + "icon": "🎮", + "id": "gaming", + "instructions": "Levels: high=actively playing, medium=in menus or waiting, low=game open but tabbed out. Detect via: game window, controller input, game UI elements.", + "name": "Gaming" + }, + { + "description": "Social media browsing and interaction", + "icon": "📱", + "id": "social", + "instructions": "Levels: high=posting or actively engaging, medium=scrolling feed, low=social app open but idle. Detect via: social media sites/apps, feed content, post composition.", + "name": "Social Media" + }, + { + "description": "Spreadsheets, slides, and task management", + "icon": "📊", + "id": "productivity", + "instructions": "Levels: high=actively editing or organizing, medium=reviewing data, low=app open but not focused. Detect via: spreadsheet/slide editors, project management tools, calendar apps, task boards.", + "name": "Productivity" + }, + { + "description": "Command line and shell sessions", + "icon": "⌨️", + "id": "terminal", + "instructions": "Levels: high=running commands or scripts, medium=reading output, low=terminal open but idle. Detect via: shell prompts, command output, tmux/screen sessions. If terminal use is clearly coding-related, prefer coding instead.", + "name": "Terminal" + }, + { + "description": "Design tools and image editing", + "icon": "🎨", + "id": "design", + "instructions": "Levels: high=actively creating or editing, medium=reviewing designs, low=design tool open but idle. Detect via: design apps (Figma, Photoshop, etc), canvas editing.", + "name": "Design" + }, + { + "description": "Music listening and audio", + "icon": "🎵", + "id": "music", + "instructions": "Levels: high=actively choosing or browsing music, medium=playlist running while working, low=ambient background audio. Detect via: music player UI, audio playback indicators.", + "name": "Music" + } + ] +} diff --git a/tests/baselines/api/settings/facet.json b/tests/baselines/api/settings/facet.json new file mode 100644 index 000000000..f5cfc0736 --- /dev/null +++ b/tests/baselines/api/settings/facet.json @@ -0,0 +1,11 @@ +{ + "config": { + "color": "#1e90ff", + "description": "Montague Tech startup operations", + "emoji": "⚔️", + "muted": false, + "path": "tests/fixtures/journal/facets/montague", + "title": "Montague Tech" + }, + "facet": "montague" +} diff --git a/tests/baselines/api/settings/generators.json b/tests/baselines/api/settings/generators.json new file mode 100644 index 000000000..61ebb041c --- /dev/null +++ b/tests/baselines/api/settings/generators.json @@ -0,0 +1,186 @@ +{ + "daily": [ + { + "app": null, + "description": "Analyzes activity patterns to identify optimal times for scheduled maintenance tasks.", + "disabled": false, + "extract": null, + "has_extraction": false, + "key": "daily_schedule", + "source": "system", + "title": "Maintenance Window" + }, + { + "app": null, + "description": "Finds when important knowledge is shared in the transcript and suggests what should be written down. Output is a Markdown list of documentation opportunities with time ranges and destinations.", + "disabled": true, + "extract": true, + "has_extraction": true, + "key": "documentation", + "source": "system", + "title": "Documentation Moments" + }, + { + "app": null, + "description": "Reviews the day's transcript to capture each significant file or attachment that was opened, saved or shared. Generates a Markdown timeline with context about how the file was used.", + "disabled": true, + "extract": true, + "has_extraction": true, + "key": "files", + "source": "system", + "title": "File Interactions" + }, + { + "app": null, + "description": "Summarizes the overall flow of the workday. Looks for patterns in focus, energy, context switching and highlights productivity insights in a Markdown report.", + "disabled": false, + "extract": true, + "has_extraction": true, + "key": "flow", + "source": "system", + "title": "Day Overview" + }, + { + "app": null, + "description": "Extracts people, projects, tools and other entities from the transcript and maps how they relate. Produces a Markdown report plus narrative describing network hubs and bridges discovered during the day.", + "disabled": false, + "extract": true, + "has_extraction": true, + "key": "knowledge_graph", + "source": "system", + "title": "Knowledge Graph" + }, + { + "app": null, + "description": "Identifies when videos, articles, music or social content are consumed. Classifies each instance as work or personal and reports the source in chronological sections.", + "disabled": true, + "extract": true, + "has_extraction": true, + "key": "media", + "source": "system", + "title": "Media Consumption" + }, + { + "app": null, + "description": "Scans conversations and tasks for sparks of new ideas, problem statements and potential ventures. Outputs a list of the most promising opportunities with context and suggested next steps.", + "disabled": true, + "extract": true, + "has_extraction": true, + "key": "opportunities", + "source": "system", + "title": "Innovation Opportunities" + }, + { + "app": null, + "description": "Highlights moments where additional information would help progress work. Produces a list of targeted research tasks with time ranges and context.", + "disabled": true, + "extract": true, + "has_extraction": true, + "key": "research", + "source": "system", + "title": "Research Needs" + }, + { + "app": null, + "description": "Identifies all future calendar events and scheduled activities noted in transcripts. Extracts dates, times, participants, and event details for anything scheduled beyond today.", + "disabled": false, + "extract": true, + "has_extraction": true, + "key": "schedule", + "source": "system", + "title": "Upcoming Schedule" + }, + { + "app": null, + "description": "Constructs a detailed chronological timeline documenting every activity, task shift, and event throughout the workday. Creates a comprehensive historical record with rich descriptions of what happened when.", + "disabled": false, + "extract": true, + "has_extraction": true, + "key": "timeline", + "source": "system", + "title": "Day Timeline" + }, + { + "app": null, + "description": "Catalogues every application or service used throughout the day and how long it was active. The report details which tools are critical, supporting or distracting.", + "disabled": true, + "extract": true, + "has_extraction": true, + "key": "tools", + "source": "system", + "title": "Tool Usage" + } + ], + "segment": [ + { + "app": null, + "description": "Detects completed activities across all facets and writes records with synthesized descriptions", + "disabled": false, + "extract": null, + "has_extraction": false, + "key": "activities", + "source": "system", + "title": "Activity Records" + }, + { + "app": null, + "description": "Synthesizes segment activity from screenshots and audio, focusing on observable changes and searchability.", + "disabled": false, + "extract": null, + "has_extraction": false, + "key": "activity", + "source": "system", + "title": "Activity Synthesis" + }, + { + "app": null, + "description": "Detects configured activities present in segment and tracks state across segments", + "disabled": false, + "extract": null, + "has_extraction": false, + "key": "activity_state", + "source": "system", + "title": "Activity State" + }, + { + "app": null, + "description": "Extracts people, companies, projects, and tools from segment content", + "disabled": false, + "extract": null, + "has_extraction": false, + "key": "entities", + "source": "system", + "title": "Entity Extraction" + }, + { + "app": null, + "description": "Classifies segment activity into relevant facets based on other segment outputs", + "disabled": false, + "extract": null, + "has_extraction": false, + "key": "facets", + "source": "system", + "title": "Facet Classification" + }, + { + "app": null, + "description": "Creates a detailed documentary record of screen activity. Focuses on the 'what' - chronological account with preserved details, excerpts, and entities.", + "disabled": false, + "extract": null, + "has_extraction": false, + "key": "screen", + "source": "system", + "title": "Screen Record" + }, + { + "app": null, + "description": "Detects meetings in the segment and extracts participant names from screen and conversation.", + "disabled": false, + "extract": null, + "has_extraction": false, + "key": "speakers", + "source": "system", + "title": "Meeting Speakers" + } + ] +} diff --git a/tests/baselines/api/settings/observe.json b/tests/baselines/api/settings/observe.json new file mode 100644 index 000000000..f24b07065 --- /dev/null +++ b/tests/baselines/api/settings/observe.json @@ -0,0 +1,14 @@ +{ + "defaults": { + "tmux": { + "capture_interval": 5, + "capture_interval_max": 60, + "capture_interval_min": 1, + "enabled": true + } + }, + "tmux": { + "capture_interval": 5, + "enabled": true + } +} diff --git a/tests/baselines/api/settings/providers.json b/tests/baselines/api/settings/providers.json new file mode 100644 index 000000000..0b93ae081 --- /dev/null +++ b/tests/baselines/api/settings/providers.json @@ -0,0 +1,485 @@ +{ + "api_keys": { + "anthropic": false, + "google": false, + "openai": false + }, + "auth": { + "anthropic": "platform", + "google": "platform", + "openai": "platform" + }, + "cogitate": { + "backup": "anthropic", + "provider": "openai", + "tier": 2 + }, + "context_defaults": { + "app.chat.title": { + "group": "Apps", + "label": "Chat Title Generation", + "tier": 3 + }, + "detect.created": { + "group": "Import", + "label": "Date Detection", + "tier": 3 + }, + "muse.entities.entities": { + "disabled": false, + "group": "Entities", + "label": "Entity Detector", + "schedule": "daily", + "tier": 2, + "type": "cogitate" + }, + "muse.entities.entities_review": { + "disabled": false, + "group": "Entities", + "label": "Entity Reviewer", + "schedule": "daily", + "tier": 2, + "type": "cogitate" + }, + "muse.entities.entity_assist": { + "disabled": false, + "group": "Entities", + "label": "Entity Assistant", + "tier": 2, + "type": "cogitate" + }, + "muse.entities.entity_describe": { + "disabled": false, + "group": "Entities", + "label": "Entity Description", + "tier": 2, + "type": "cogitate" + }, + "muse.entities.entity_observer": { + "disabled": false, + "group": "Entities", + "label": "Entity Observer", + "schedule": "daily", + "tier": 2, + "type": "cogitate" + }, + "muse.system.activities": { + "disabled": false, + "group": "Think", + "label": "Activity Records", + "schedule": "segment", + "tier": 3, + "type": "generate" + }, + "muse.system.activity": { + "disabled": false, + "group": "Think", + "label": "Activity Synthesis", + "schedule": "segment", + "tier": 2, + "type": "generate" + }, + "muse.system.activity_state": { + "disabled": false, + "group": "Think", + "label": "Activity State", + "schedule": "segment", + "tier": 3, + "type": "generate" + }, + "muse.system.anticipation": { + "disabled": false, + "group": "Think", + "label": "Anticipation Extraction", + "tier": 2, + "type": null + }, + "muse.system.daily_news": { + "disabled": false, + "group": "Think", + "label": "Daily News Briefing", + "schedule": "daily", + "tier": 2, + "type": "cogitate" + }, + "muse.system.daily_schedule": { + "disabled": false, + "group": "Think", + "label": "Maintenance Window", + "schedule": "daily", + "tier": 2, + "type": "generate" + }, + "muse.system.decisionalizer": { + "disabled": false, + "group": "Think", + "label": "Decision Dossier Generator", + "schedule": "daily", + "tier": 2, + "type": "cogitate" + }, + "muse.system.decisions": { + "disabled": false, + "extract": true, + "group": "Think", + "label": "Decision Actions", + "schedule": "activity", + "tier": 2, + "type": "generate" + }, + "muse.system.default": { + "disabled": false, + "group": "Apps", + "label": "Chat Messages", + "tier": 2, + "type": "cogitate" + }, + "muse.system.documentation": { + "disabled": true, + "extract": true, + "group": "Think", + "label": "Documentation Moments", + "schedule": "daily", + "tier": 2, + "type": "generate" + }, + "muse.system.entities": { + "disabled": false, + "group": "Think", + "label": "Entity Extraction", + "schedule": "segment", + "tier": 2, + "type": "generate" + }, + "muse.system.facet_newsletter": { + "disabled": false, + "group": "Think", + "label": "Facet Newsletter Generator", + "schedule": "daily", + "tier": 2, + "type": "cogitate" + }, + "muse.system.facets": { + "disabled": false, + "group": "Think", + "label": "Facet Classification", + "schedule": "segment", + "tier": 3, + "type": "generate" + }, + "muse.system.files": { + "disabled": true, + "extract": true, + "group": "Think", + "label": "File Interactions", + "schedule": "daily", + "tier": 2, + "type": "generate" + }, + "muse.system.flow": { + "disabled": false, + "extract": true, + "group": "Think", + "label": "Day Overview", + "schedule": "daily", + "tier": 2, + "type": "generate" + }, + "muse.system.followups": { + "disabled": false, + "extract": true, + "group": "Think", + "label": "Follow-Up Items", + "schedule": "activity", + "tier": 2, + "type": "generate" + }, + "muse.system.help": { + "disabled": false, + "group": "Think", + "label": "CLI Help", + "tier": 2, + "type": "cogitate" + }, + "muse.system.joke_bot": { + "disabled": false, + "group": "Think", + "label": "Joke Bot", + "schedule": "daily", + "tier": 2, + "type": "cogitate" + }, + "muse.system.knowledge_graph": { + "disabled": false, + "extract": true, + "group": "Think", + "label": "Knowledge Graph", + "schedule": "daily", + "tier": 2, + "type": "generate" + }, + "muse.system.media": { + "disabled": true, + "extract": true, + "group": "Think", + "label": "Media Consumption", + "schedule": "daily", + "tier": 2, + "type": "generate" + }, + "muse.system.meetings": { + "disabled": false, + "extract": true, + "group": "Think", + "label": "Meeting Notes", + "schedule": "activity", + "tier": 2, + "type": "generate" + }, + "muse.system.messaging": { + "disabled": false, + "extract": true, + "group": "Think", + "label": "Messaging Summary", + "schedule": "activity", + "tier": 2, + "type": "generate" + }, + "muse.system.occurrence": { + "disabled": false, + "group": "Think", + "label": "Occurrence Extraction", + "tier": 2, + "type": null + }, + "muse.system.onboarding": { + "disabled": false, + "group": "Think", + "label": "Onboarding", + "tier": 2, + "type": "cogitate" + }, + "muse.system.opportunities": { + "disabled": true, + "extract": true, + "group": "Think", + "label": "Innovation Opportunities", + "schedule": "daily", + "tier": 2, + "type": "generate" + }, + "muse.system.research": { + "disabled": true, + "extract": true, + "group": "Think", + "label": "Research Needs", + "schedule": "daily", + "tier": 2, + "type": "generate" + }, + "muse.system.schedule": { + "disabled": false, + "extract": true, + "group": "Think", + "label": "Upcoming Schedule", + "schedule": "daily", + "tier": 2, + "type": "generate" + }, + "muse.system.screen": { + "disabled": false, + "group": "Think", + "label": "Screen Record", + "schedule": "segment", + "tier": 2, + "type": "generate" + }, + "muse.system.speakers": { + "disabled": false, + "group": "Think", + "label": "Meeting Speakers", + "schedule": "segment", + "tier": 2, + "type": "generate" + }, + "muse.system.timeline": { + "disabled": false, + "extract": true, + "group": "Think", + "label": "Day Timeline", + "schedule": "daily", + "tier": 2, + "type": "generate" + }, + "muse.system.tools": { + "disabled": true, + "extract": true, + "group": "Think", + "label": "Tool Usage", + "schedule": "daily", + "tier": 2, + "type": "generate" + }, + "muse.system.triage": { + "disabled": false, + "group": "Think", + "label": "Triage", + "tier": 2, + "type": "cogitate" + }, + "muse.todos.daily": { + "disabled": false, + "group": "Todos", + "label": "Daily TODO Curator", + "schedule": "daily", + "tier": 2, + "type": "cogitate" + }, + "muse.todos.todo": { + "disabled": false, + "group": "Todos", + "label": "TODO Detector", + "schedule": "activity", + "tier": 2, + "type": "cogitate" + }, + "muse.todos.weekly": { + "disabled": false, + "group": "Todos", + "label": "TODO Weekly Scout", + "tier": 2, + "type": "cogitate" + }, + "observe.describe.browsing": { + "group": "Screen Analysis", + "label": "Browsing", + "tier": 2 + }, + "observe.describe.code": { + "group": "Screen Analysis", + "label": "Code", + "tier": 2 + }, + "observe.describe.frame": { + "group": "Observe", + "label": "Screen Categorization", + "tier": 3 + }, + "observe.describe.gaming": { + "group": "Screen Analysis", + "label": "Gaming", + "tier": 2 + }, + "observe.describe.media": { + "group": "Screen Analysis", + "label": "Media", + "tier": 2 + }, + "observe.describe.meeting": { + "group": "Screen Analysis", + "label": "Meeting", + "tier": 2 + }, + "observe.describe.messaging": { + "group": "Screen Analysis", + "label": "Messaging", + "tier": 2 + }, + "observe.describe.productivity": { + "group": "Screen Analysis", + "label": "Productivity", + "tier": 2 + }, + "observe.describe.reading": { + "group": "Screen Analysis", + "label": "Reading", + "tier": 2 + }, + "observe.describe.terminal": { + "group": "Screen Analysis", + "label": "Terminal", + "tier": 2 + }, + "observe.detect.json": { + "group": "Import", + "label": "Normalization", + "tier": 2 + }, + "observe.detect.segment": { + "group": "Import", + "label": "Segmentation", + "tier": 2 + }, + "observe.enrich": { + "group": "Observe", + "label": "Audio Enrichment", + "tier": 2 + }, + "observe.extract.selection": { + "group": "Observe", + "label": "Frame Selection", + "tier": 2 + }, + "observe.transcribe.gemini": { + "group": "Observe", + "label": "Audio Transcription (Gemini)", + "tier": 2 + }, + "planner.generate": { + "group": "Think", + "label": "Agent Prompt Generation", + "tier": 2 + } + }, + "contexts": { + "observe.*": { + "provider": "google", + "tier": 3 + }, + "test.anthropic": { + "model": "claude-sonnet-4-5", + "provider": "anthropic" + }, + "test.config.override": { + "provider": "google", + "tier": 2 + }, + "test.openai": { + "model": "gpt-5-mini", + "provider": "openai" + }, + "test.tier": { + "provider": "google", + "tier": 1 + }, + "test.tier.inherit": { + "tier": 3 + }, + "test.tier.override": { + "provider": "openai", + "tier": 2 + } + }, + "generate": { + "backup": "anthropic", + "provider": "google", + "tier": 2 + }, + "providers": [ + { + "env_key": "GOOGLE_API_KEY", + "label": "Google (Gemini)", + "name": "google" + }, + { + "env_key": "OPENAI_API_KEY", + "label": "OpenAI (GPT)", + "name": "openai" + }, + { + "env_key": "ANTHROPIC_API_KEY", + "label": "Anthropic (Claude)", + "name": "anthropic" + } + ] +} diff --git a/tests/baselines/api/settings/sync.json b/tests/baselines/api/settings/sync.json new file mode 100644 index 000000000..a8028c440 --- /dev/null +++ b/tests/baselines/api/settings/sync.json @@ -0,0 +1,7 @@ +{ + "plaud": { + "available": false, + "configured": false, + "enabled": false + } +} diff --git a/tests/baselines/api/settings/transcribe.json b/tests/baselines/api/settings/transcribe.json new file mode 100644 index 000000000..0d9453c81 --- /dev/null +++ b/tests/baselines/api/settings/transcribe.json @@ -0,0 +1,49 @@ +{ + "api_keys": { + "gemini": false, + "revai": false, + "whisper": true + }, + "backends": [ + { + "description": "Local speech recognition using faster-whisper", + "env_key": null, + "label": "Whisper - Local processing", + "name": "whisper", + "settings": [ + "device", + "model", + "compute_type" + ] + }, + { + "description": "Cloud-based transcription with speaker identification", + "env_key": "REVAI_ACCESS_TOKEN", + "label": "Rev.ai - Cloud with speaker diarization", + "name": "revai", + "settings": [ + "model" + ] + }, + { + "description": "Cloud-based transcription with speaker identification", + "env_key": "GOOGLE_API_KEY", + "label": "Gemini - Cloud with speaker diarization", + "name": "gemini", + "settings": [] + } + ], + "config": { + "backend": "whisper", + "enrich": true, + "noise_upgrade": true, + "revai": { + "model": "fusion" + }, + "whisper": { + "compute_type": "default", + "device": "auto", + "model": "medium.en" + } + } +} diff --git a/tests/baselines/api/settings/vision.json b/tests/baselines/api/settings/vision.json new file mode 100644 index 000000000..04340492b --- /dev/null +++ b/tests/baselines/api/settings/vision.json @@ -0,0 +1,63 @@ +{ + "categories": {}, + "category_defaults": { + "browsing": { + "extraction": "Extract when visiting distinctly different websites or search results", + "group": "Screen Analysis", + "importance": "normal", + "label": "Browsing" + }, + "code": { + "extraction": "Extract when viewing different repositories, files, or switching between editor and browser", + "group": "Screen Analysis", + "importance": "low", + "label": "Code" + }, + "gaming": { + "extraction": "", + "group": "Screen Analysis", + "importance": "ignore", + "label": "Gaming" + }, + "media": { + "extraction": "Extract 1 frame only - video playback content does not benefit from text extraction", + "group": "Screen Analysis", + "importance": "low", + "label": "Media" + }, + "meeting": { + "extraction": "Extract when shared content type changes (screen share vs participant grid) or meeting platform differs", + "group": "Screen Analysis", + "importance": "high", + "label": "Meeting" + }, + "messaging": { + "extraction": "Extract when conversation partner, channel, or messaging app changes", + "group": "Screen Analysis", + "importance": "high", + "label": "Messaging" + }, + "productivity": { + "extraction": "Extract when different application or service is shown (e.g. ChatGPT vs Calendar vs Docs)", + "group": "Screen Analysis", + "importance": "high", + "label": "Productivity" + }, + "reading": { + "extraction": "Extract when viewing a different document, article, or PDF", + "group": "Screen Analysis", + "importance": "high", + "label": "Reading" + }, + "terminal": { + "extraction": "Extract when showing distinctly different content (code diffs vs logs vs documentation)", + "group": "Screen Analysis", + "importance": "low", + "label": "Terminal" + } + }, + "max_extractions": 20, + "redact": [ + "replace test-secret-key with ***" + ] +} diff --git a/tests/baselines/api/speakers/segments.json b/tests/baselines/api/speakers/segments.json new file mode 100644 index 000000000..a5a8ed0f2 --- /dev/null +++ b/tests/baselines/api/speakers/segments.json @@ -0,0 +1,3 @@ +{ + "segments": [] +} diff --git a/tests/baselines/api/speakers/sentences.json b/tests/baselines/api/speakers/sentences.json new file mode 100644 index 000000000..cf700d455 --- /dev/null +++ b/tests/baselines/api/speakers/sentences.json @@ -0,0 +1,39 @@ +{ + "all_entities": [ + "Acme Corp", + "Alice Johnson", + "API Optimization", + "Balcony App", + "Benvolio Montague", + "Bob Smith", + "Bob Wilson", + "Capulet Industries", + "Dashboard Redesign", + "Docker", + "First test entity", + "Friar Lawrence", + "Jane Doe", + "John Smith", + "Juliet Capulet", + "Mercutio Escalus", + "Montague Tech", + "Nurse Angela", + "Paris Duke", + "PostgreSQL", + "Romeo Montague", + "Second test entity", + "Tech Solutions Inc", + "Third test entity with description", + "Tybalt Capulet", + "Verona Platform", + "Visual Studio Code" + ], + "audio_file": null, + "segment": { + "end": "09:05", + "key": "090000_300", + "start": "09:00" + }, + "sentences": [], + "source": "audio" +} diff --git a/tests/baselines/api/speakers/speakers-segment.json b/tests/baselines/api/speakers/speakers-segment.json new file mode 100644 index 000000000..36294c642 --- /dev/null +++ b/tests/baselines/api/speakers/speakers-segment.json @@ -0,0 +1,4 @@ +{ + "matched": [], + "unmatched": [] +} diff --git a/tests/baselines/api/speakers/stats-month.json b/tests/baselines/api/speakers/stats-month.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/tests/baselines/api/speakers/stats-month.json @@ -0,0 +1 @@ +{} diff --git a/tests/baselines/api/stats/stats.json b/tests/baselines/api/stats/stats.json new file mode 100644 index 000000000..b872a98af --- /dev/null +++ b/tests/baselines/api/stats/stats.json @@ -0,0 +1,417 @@ +{ + "generators": { + "activities": { + "color": "#00695c", + "description": "Detects completed activities across all facets and writes records with synthesized descriptions", + "hook": { + "flush": true, + "post": "activities", + "pre": "activities" + }, + "instructions": { + "facets": false, + "sources": { + "agents": false, + "audio": false, + "screen": false + } + }, + "max_output_tokens": 2048, + "mtime": 0, + "output": "json", + "path": "/muse/activities.md", + "priority": 96, + "schedule": "segment", + "source": "system", + "thinking_budget": 4096, + "tier": 3, + "title": "Activity Records", + "type": "generate" + }, + "activity": { + "color": "#00bcd4", + "description": "Synthesizes segment activity from screenshots and audio, focusing on observable changes and searchability.", + "instructions": { + "facets": true, + "sources": { + "agents": false, + "audio": true, + "screen": true + } + }, + "mtime": 0, + "output": "md", + "path": "/muse/activity.md", + "priority": 10, + "schedule": "segment", + "source": "system", + "title": "Activity Synthesis", + "type": "generate" + }, + "activity_state": { + "color": "#00897b", + "description": "Detects configured activities present in segment and tracks state across segments", + "hook": { + "post": "activity_state", + "pre": "activity_state" + }, + "instructions": { + "facets": true, + "sources": { + "agents": false, + "audio": true, + "screen": true + } + }, + "max_output_tokens": 3072, + "mtime": 0, + "multi_facet": true, + "output": "json", + "path": "/muse/activity_state.md", + "priority": 95, + "schedule": "segment", + "source": "system", + "thinking_budget": 4096, + "tier": 3, + "title": "Activity State", + "type": "generate" + }, + "daily_schedule": { + "color": "#455a64", + "description": "Analyzes activity patterns to identify optimal times for scheduled maintenance tasks.", + "hook": { + "post": "daily_schedule", + "pre": "daily_schedule" + }, + "instructions": { + "facets": true, + "sources": { + "agents": { + "screen": true + }, + "audio": true, + "screen": false + } + }, + "max_output_tokens": 512, + "mtime": 0, + "output": "json", + "path": "/muse/daily_schedule.md", + "priority": 10, + "schedule": "daily", + "source": "system", + "thinking_budget": 4096, + "title": "Maintenance Window", + "type": "generate" + }, + "decisions": { + "activities": [ + "*" + ], + "color": "#dc3545", + "description": "Tracks consequential decision-actions that change state, plans, resources, responsibilities, or timing in ways that affect other people.", + "hook": { + "post": "occurrence" + }, + "instructions": { + "activity": true, + "facets": true, + "sources": { + "agents": { + "screen": true + }, + "audio": true, + "screen": false + } + }, + "mtime": 0, + "occurrences": "Create an occurrence for every decision-action observed. Include the time span, decision type, actors involved, entities affected, and impact assessment. Each occurrence should capture both the intent and enactment of the decision.", + "output": "md", + "path": "/muse/decisions.md", + "priority": 10, + "schedule": "activity", + "source": "system", + "title": "Decision Actions", + "type": "generate" + }, + "entities": { + "color": "#2e7d32", + "description": "Extracts people, companies, projects, and tools from segment content", + "hook": { + "post": "entities" + }, + "instructions": { + "facets": false, + "sources": { + "agents": false, + "audio": true, + "screen": true + } + }, + "max_output_tokens": 1024, + "mtime": 0, + "output": "md", + "path": "/muse/entities.md", + "priority": 10, + "schedule": "segment", + "source": "system", + "thinking_budget": 4096, + "title": "Entity Extraction", + "type": "generate" + }, + "facets": { + "color": "#7c4dff", + "description": "Classifies segment activity into relevant facets based on other segment outputs", + "instructions": { + "facets": true, + "sources": { + "agents": true, + "audio": false, + "screen": false + } + }, + "max_output_tokens": 512, + "mtime": 0, + "output": "json", + "path": "/muse/facets.md", + "priority": 90, + "schedule": "segment", + "source": "system", + "thinking_budget": 1024, + "tier": 3, + "title": "Facet Classification", + "type": "generate" + }, + "flow": { + "color": "#17a2b8", + "description": "Summarizes the overall flow of the workday. Looks for patterns in focus, energy, context switching and highlights productivity insights in a Markdown report.", + "hook": { + "post": "occurrence" + }, + "instructions": { + "facets": true, + "sources": { + "agents": { + "screen": true + }, + "audio": true, + "screen": false + } + }, + "mtime": 0, + "occurrences": "Create an occurrence for noteworthy shifts in work rhythms or focus. Include timestamps when deep work starts or ends, or when energy levels noticeably change. Classify each as work or personal based on the surrounding context.", + "output": "md", + "path": "/muse/flow.md", + "priority": 10, + "schedule": "daily", + "source": "system", + "title": "Day Overview", + "type": "generate" + }, + "followups": { + "activities": [ + "*" + ], + "color": "#ffc107", + "description": "Detects promised tasks, commitments, and reminders for future action within each activity. Outputs a concise Markdown list of follow-ups with context.", + "hook": { + "post": "occurrence" + }, + "instructions": { + "activity": true, + "facets": true, + "sources": { + "agents": { + "screen": true + }, + "audio": true, + "screen": false + } + }, + "mtime": 0, + "occurrences": "Whenever a future task or commitment is mentioned, create an occurrence with the expected action and deadline if known. Note who requested it and whether it is work or personal.", + "output": "md", + "path": "/muse/followups.md", + "priority": 10, + "schedule": "activity", + "source": "system", + "title": "Follow-Up Items", + "type": "generate" + }, + "knowledge_graph": { + "color": "#6f42c1", + "description": "Extracts people, projects, tools and other entities from the transcript and maps how they relate. Produces a Markdown report plus narrative describing network hubs and bridges discovered during the day.", + "hook": { + "post": "occurrence" + }, + "instructions": { + "facets": true, + "sources": { + "agents": { + "screen": true + }, + "audio": true, + "screen": false + } + }, + "mtime": 0, + "occurrences": "For each entity interaction or relationship mentioned, create an occurrence describing the connection. Include start and end times when the relationship is visible, and capture the type of link such as works-on or discusses-with.", + "output": "md", + "path": "/muse/knowledge_graph.md", + "priority": 10, + "schedule": "daily", + "source": "system", + "title": "Knowledge Graph", + "type": "generate" + }, + "meetings": { + "activities": [ + "meeting" + ], + "color": "#e83e8c", + "description": "Produces detailed meeting notes for each meeting activity, including participants, topics discussed, action items, and presentation details.", + "hook": { + "post": "occurrence" + }, + "instructions": { + "activity": true, + "facets": true, + "sources": { + "agents": { + "screen": true + }, + "audio": true, + "screen": false + } + }, + "mtime": 0, + "occurrences": "Each meeting should generate an occurrence with start and end times, list of participants and a concise summary. If slides are present, mention them in the details field.", + "output": "md", + "path": "/muse/meetings.md", + "priority": 10, + "schedule": "activity", + "source": "system", + "title": "Meeting Notes", + "type": "generate" + }, + "messaging": { + "activities": [ + "messaging", + "email" + ], + "color": "#78909c", + "description": "Extracts contacts, channels, apps, and message content from completed messaging and email activities.", + "hook": { + "post": "occurrence" + }, + "instructions": { + "activity": true, + "facets": true, + "sources": { + "agents": { + "screen": true + }, + "audio": true, + "screen": false + } + }, + "mtime": 0, + "occurrences": "Create an occurrence for every distinct message interaction. Include the time block, app name, contacts or channels involved, whether $preferred was reading or replying, and a summary of visible content.", + "output": "md", + "path": "/muse/messaging.md", + "priority": 10, + "schedule": "activity", + "source": "system", + "title": "Messaging Summary", + "type": "generate" + }, + "schedule": { + "color": "#5e35b1", + "description": "Identifies all future calendar events and scheduled activities noted in transcripts. Extracts dates, times, participants, and event details for anything scheduled beyond today.", + "hook": { + "post": "anticipation" + }, + "instructions": { + "sources": { + "agents": { + "screen": true + }, + "audio": true, + "screen": false + } + }, + "mtime": 0, + "output": "md", + "path": "/muse/schedule.md", + "priority": 10, + "schedule": "daily", + "source": "system", + "title": "Upcoming Schedule", + "type": "generate" + }, + "screen": { + "color": "#9c27b0", + "description": "Creates a detailed documentary record of screen activity. Focuses on the 'what' - chronological account with preserved details, excerpts, and entities.", + "instructions": { + "sources": { + "agents": false, + "audio": true, + "screen": "required" + } + }, + "mtime": 0, + "output": "md", + "path": "/muse/screen.md", + "priority": 10, + "schedule": "segment", + "source": "system", + "title": "Screen Record", + "type": "generate" + }, + "speakers": { + "color": "#e64a19", + "description": "Detects meetings in the segment and extracts participant names from screen and conversation.", + "instructions": { + "sources": { + "agents": false, + "audio": "required", + "screen": true + } + }, + "mtime": 0, + "output": "json", + "path": "/muse/speakers.md", + "priority": 10, + "schedule": "segment", + "source": "system", + "title": "Meeting Speakers", + "type": "generate" + }, + "timeline": { + "color": "#7b1fa2", + "description": "Constructs a detailed chronological timeline documenting every activity, task shift, and event throughout the workday. Creates a comprehensive historical record with rich descriptions of what happened when.", + "hook": { + "post": "occurrence" + }, + "instructions": { + "sources": { + "agents": { + "screen": true + }, + "audio": true, + "screen": false + } + }, + "mtime": 0, + "occurrences": "Create an occurrence for each hour segment, don't break down hours into any smaller segments the goal for timeline occurrences is for them to capture whatever happened within each hour of the day where there was activity.", + "output": "md", + "path": "/muse/timeline.md", + "priority": 10, + "schedule": "daily", + "source": "system", + "title": "Day Timeline", + "type": "generate" + } + }, + "stats": {} +} diff --git a/tests/baselines/api/todos/badge-count.json b/tests/baselines/api/todos/badge-count.json new file mode 100644 index 000000000..633d47a56 --- /dev/null +++ b/tests/baselines/api/todos/badge-count.json @@ -0,0 +1,3 @@ +{ + "count": 0 +} diff --git a/tests/baselines/api/todos/nudges.json b/tests/baselines/api/todos/nudges.json new file mode 100644 index 000000000..15a86c251 --- /dev/null +++ b/tests/baselines/api/todos/nudges.json @@ -0,0 +1,3 @@ +{ + "nudges": [] +} diff --git a/tests/baselines/api/todos/stats-month.json b/tests/baselines/api/todos/stats-month.json new file mode 100644 index 000000000..5725b1811 --- /dev/null +++ b/tests/baselines/api/todos/stats-month.json @@ -0,0 +1,33 @@ +{ + "20260304": { + "capulet": 2, + "montague": 2 + }, + "20260305": { + "montague": 2, + "verona": 2 + }, + "20260306": { + "capulet": 2, + "montague": 2, + "verona": 1 + }, + "20260307": { + "capulet": 1, + "montague": 2 + }, + "20260308": { + "montague": 2, + "verona": 2 + }, + "20260309": { + "capulet": 2, + "montague": 3, + "verona": 3 + }, + "20260310": { + "capulet": 2, + "montague": 2, + "verona": 2 + } +} diff --git a/tests/baselines/api/tokens/stats-month.json b/tests/baselines/api/tokens/stats-month.json new file mode 100644 index 000000000..c7b6b3d58 --- /dev/null +++ b/tests/baselines/api/tokens/stats-month.json @@ -0,0 +1,9 @@ +{ + "20260304": 0.038015, + "20260305": 0.038015, + "20260306": 0.038015, + "20260307": 0.038015, + "20260308": 0.038015, + "20260309": 0.038015, + "20260310": 0.038015 +} diff --git a/tests/baselines/api/tokens/usage.json b/tests/baselines/api/tokens/usage.json new file mode 100644 index 000000000..5f4b4c674 --- /dev/null +++ b/tests/baselines/api/tokens/usage.json @@ -0,0 +1,123 @@ +{ + "by_context": [ + { + "context": "think.cortex.knowledge_graph:88", + "cost": 0.0354, + "models_used": [ + "claude-sonnet-4-5" + ], + "percent": 93.1, + "requests": 1, + "tokens": 5700 + }, + { + "context": "think.cortex.flow:42", + "cost": 0.002615, + "models_used": [ + "gemini-2.5-flash" + ], + "percent": 6.9, + "requests": 1, + "tokens": 3300 + } + ], + "by_model": [ + { + "avg_cost_per_request": 0.0354, + "cost": 0.0354, + "model": "claude-sonnet-4-5", + "percent": 93.1, + "provider": "anthropic", + "requests": 1, + "tokens": 5700 + }, + { + "avg_cost_per_request": 0.002615, + "cost": 0.002615, + "model": "gemini-2.5-flash", + "percent": 6.9, + "provider": "google", + "requests": 1, + "tokens": 3300 + } + ], + "by_provider": [ + { + "cached_tokens": 1000, + "cost": 0.0354, + "input_cost": 0.0099, + "input_tokens": 4200, + "models_used": [ + "claude-sonnet-4-5" + ], + "output_cost": 0.0255, + "output_tokens": 1500, + "percent": 93.1, + "provider": "anthropic", + "reasoning_tokens": 200, + "requests": 1, + "tokens": 5700 + }, + { + "cached_tokens": 500, + "cost": 0.002615, + "input_cost": 0.000615, + "input_tokens": 2500, + "models_used": [ + "gemini-2.5-flash" + ], + "output_cost": 0.002, + "output_tokens": 800, + "percent": 6.9, + "provider": "google", + "reasoning_tokens": 0, + "requests": 1, + "tokens": 3300 + } + ], + "by_segment": [ + { + "cost": 0.038015, + "models_used": [ + "claude-sonnet-4-5", + "gemini-2.5-flash" + ], + "percent": 100.0, + "requests": 2, + "segment": "[unattributed]", + "tokens": 9000 + } + ], + "by_token_type": { + "cached": { + "cost": 0.0, + "tokens": 1500 + }, + "input": { + "avg_rate": 0.0016, + "cached_pct": 22.4, + "cost": 0.010515, + "percent": 27.7, + "tokens": 6700 + }, + "output": { + "avg_rate": 0.011, + "cost": 0.0275, + "percent": 72.3, + "reasoning_pct": 8.0, + "tokens": 2500 + }, + "reasoning": { + "cost": 0.0, + "tokens": 200 + } + }, + "by_type": {}, + "day": "20260304", + "total": { + "cost": 0.038015, + "requests": 2, + "segment_count": 0, + "tokens": 9000 + } +} diff --git a/tests/baselines/api/transcripts/ranges.json b/tests/baselines/api/transcripts/ranges.json new file mode 100644 index 000000000..414d6e59a --- /dev/null +++ b/tests/baselines/api/transcripts/ranges.json @@ -0,0 +1,30 @@ +{ + "audio": [ + [ + "09:00", + "09:15" + ], + [ + "14:00", + "14:15" + ], + [ + "18:00", + "18:15" + ] + ], + "screen": [ + [ + "09:00", + "09:15" + ], + [ + "14:00", + "14:15" + ], + [ + "18:00", + "18:15" + ] + ] +} diff --git a/tests/baselines/api/transcripts/segment-detail.json b/tests/baselines/api/transcripts/segment-detail.json new file mode 100644 index 000000000..e72e1f4f2 --- /dev/null +++ b/tests/baselines/api/transcripts/segment-detail.json @@ -0,0 +1,111 @@ +{ + "audio_file": "/app/transcripts/api/serve_file/20260304/default__090000_300__raw.flac", + "chunks": [ + { + "basic": true, + "markdown": "### 09:00:00\n\n**Category:** unknown\n\nConference hall with slides showing API architecture diagram\n", + "source_ref": { + "analysis": { + "visible": "presentation", + "visual_description": "Conference hall with slides showing API architecture diagram" + }, + "aruco": null, + "box_2d": null, + "filename": "screen.jsonl", + "frame_id": null, + "monitor": "", + "offset": 0, + "participants": null + }, + "time": "09:00:00", + "timestamp": 1772640000000, + "type": "screen" + }, + { + "markdown": "[00:00:05] (mic) Speaker 1: Welcome everyone to the Denver Tech Summit. We have an incredible lineup today.", + "source_ref": { + "source": "mic", + "speaker": 1, + "start": "00:00:05" + }, + "time": "00:00:05", + "timestamp": 1772640005000, + "type": "audio" + }, + { + "markdown": "[00:00:20] (mic) Speaker 1: Our first presenter is Juliet Capulet from Capulet Industries, talking about enterprise API architecture.", + "source_ref": { + "source": "mic", + "speaker": 1, + "start": "00:00:20" + }, + "time": "00:00:20", + "timestamp": 1772640020000, + "type": "audio" + }, + { + "markdown": "[00:00:45] (mic) Speaker 2: Thank you. Today I want to share our vision for unified API gateways that can serve both enterprise and startup clients.", + "source_ref": { + "source": "mic", + "speaker": 2, + "start": "00:00:45" + }, + "time": "00:00:45", + "timestamp": 1772640045000, + "type": "audio" + }, + { + "basic": true, + "markdown": "### 09:01:00\n\n**Category:** unknown\n\nSlide showing unified gateway concept with enterprise integration points\n", + "source_ref": { + "analysis": { + "visible": "presentation", + "visual_description": "Slide showing unified gateway concept with enterprise integration points" + }, + "aruco": null, + "box_2d": null, + "filename": "screen.jsonl", + "frame_id": null, + "monitor": "", + "offset": 60, + "participants": null + }, + "time": "09:01:00", + "timestamp": 1772640060000, + "type": "screen" + }, + { + "markdown": "[00:01:10] (mic) Speaker 2: The key insight is that API compatibility does not have to mean lowest common denominator. We can build bridges.", + "source_ref": { + "source": "mic", + "speaker": 2, + "start": "00:01:10" + }, + "time": "00:01:10", + "timestamp": 1772640070000, + "type": "audio" + }, + { + "markdown": "[00:01:30] (mic) Speaker 3: Romeo, are you seeing this? Her architecture is almost identical to what we have been building.", + "source_ref": { + "source": "mic", + "speaker": 3, + "start": "00:01:30" + }, + "time": "00:01:30", + "timestamp": 1772640090000, + "type": "audio" + } + ], + "cost": 0.0, + "md_files": { + "audio": "# Audio Summary\n\nMorning keynote at Denver Tech Summit. Juliet Capulet presented on unified API gateway architecture. Romeo Montague and Mercutio Escalus attended. Mercutio noted the similarity to Montague Tech's approach.\n", + "screen": "# Screen Summary\n\nConference live stream showing presentation slides on enterprise API architecture. Juliet Capulet presenting unified gateway concept.\n" + }, + "media_sizes": { + "audio": 0, + "screen": 0 + }, + "segment_key": "090000_300", + "video_files": {} +} diff --git a/tests/baselines/api/transcripts/segments.json b/tests/baselines/api/transcripts/segments.json new file mode 100644 index 000000000..aca747225 --- /dev/null +++ b/tests/baselines/api/transcripts/segments.json @@ -0,0 +1,34 @@ +{ + "segments": [ + { + "end": "09:05", + "key": "090000_300", + "start": "09:00", + "stream": "default", + "types": [ + "audio", + "screen" + ] + }, + { + "end": "14:05", + "key": "140000_300", + "start": "14:00", + "stream": "default", + "types": [ + "audio", + "screen" + ] + }, + { + "end": "18:05", + "key": "180000_300", + "start": "18:00", + "stream": "default", + "types": [ + "audio", + "screen" + ] + } + ] +} diff --git a/tests/baselines/api/transcripts/stats-month.json b/tests/baselines/api/transcripts/stats-month.json new file mode 100644 index 000000000..41f5b7b45 --- /dev/null +++ b/tests/baselines/api/transcripts/stats-month.json @@ -0,0 +1,9 @@ +{ + "20260304": 6, + "20260305": 6, + "20260306": 4, + "20260307": 2, + "20260308": 2, + "20260309": 6, + "20260310": 5 +} diff --git a/tests/test_api_baselines.py b/tests/test_api_baselines.py new file mode 100644 index 000000000..f9b694b0c --- /dev/null +++ b/tests/test_api_baselines.py @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright (c) 2026 sol pbc + +"""Verify API baselines match checked-in fixture responses.""" + +from __future__ import annotations + +import json +from pathlib import Path + +import pytest + +from convey import create_app +from tests.verify_api import ENDPOINTS, baseline_path, fetch_endpoint, normalize + + +@pytest.fixture(scope="module") +def client(): + journal = str(Path(__file__).resolve().parent / "fixtures" / "journal") + app = create_app(journal) + app.config["TESTING"] = True + return app.test_client() + + +@pytest.fixture(scope="module") +def journal_path(): + return str(Path(__file__).resolve().parent / "fixtures" / "journal") + + +@pytest.mark.parametrize( + "endpoint", ENDPOINTS, ids=[endpoint["name"] for endpoint in ENDPOINTS] +) +def test_api_baseline(client, journal_path, endpoint): + """Verify endpoint response matches stored baseline.""" + path = baseline_path(endpoint) + if not path.exists(): + pytest.skip(f"No baseline file: {path}") + + status, payload = fetch_endpoint(client, endpoint) + assert status == endpoint["status"], ( + f"Expected status {endpoint['status']}, got {status}" + ) + + actual = normalize(payload, journal_path) + expected = json.loads(path.read_text()) + + assert actual == expected, ( + f"Baseline mismatch for {endpoint['app']}/{endpoint['name']}. " + "Run 'make update-api-baselines' to update." + ) diff --git a/tests/verify_api.py b/tests/verify_api.py new file mode 100644 index 000000000..8b5c3f9d8 --- /dev/null +++ b/tests/verify_api.py @@ -0,0 +1,653 @@ +# SPDX-License-Identifier: AGPL-3.0-only +# Copyright (c) 2026 sol pbc + +"""Utilities for API response baseline verification.""" + +from __future__ import annotations + +import argparse +import json +import os +import re +from difflib import unified_diff +from pathlib import Path +from typing import Any + +from convey import create_app + +ENDPOINTS = [ + # convey/config.py + { + "app": "config", + "name": "convey", + "path": "/api/config/convey", + "params": {}, + "status": 200, + }, + # apps/agents/routes.py + { + "app": "agents", + "name": "agents-day", + "path": "/app/agents/api/agents/20260304", + "params": {"facet": "work"}, + "status": 200, + }, + { + "app": "agents", + "name": "run-detail", + "path": "/app/agents/api/run/1700000000001", + "params": {}, + "status": 200, + }, + { + "app": "agents", + "name": "preview", + "path": "/app/agents/api/preview/default", + "params": {}, + "status": 200, + }, + { + "app": "agents", + "name": "stats-month", + "path": "/app/agents/api/stats/202603", + "params": {}, + "status": 200, + }, + { + "app": "agents", + "name": "badge-count", + "path": "/app/agents/api/badge-count", + "params": {}, + "status": 200, + }, + { + "app": "agents", + "name": "updated-days", + "path": "/app/agents/api/updated-days", + "params": {}, + "status": 200, + }, + # apps/calendar/routes.py + { + "app": "calendar", + "name": "day-events", + "path": "/app/calendar/api/day/20260304/events", + "params": {}, + "status": 200, + }, + { + "app": "calendar", + "name": "stats-month", + "path": "/app/calendar/api/stats/202603", + "params": {}, + "status": 200, + }, + { + "app": "calendar", + "name": "day-activities", + "path": "/app/calendar/api/day/20260304/activities", + "params": {"facet": "work"}, + "status": 200, + }, + { + "app": "calendar", + "name": "screen-files", + "path": "/app/calendar/api/screen_files/20260304", + "params": {}, + "status": 200, + }, + # apps/chat/routes.py + { + "app": "chat", + "name": "chats", + "path": "/app/chat/api/chats", + "params": {}, + "status": 200, + }, + { + "app": "chat", + "name": "chat-events", + "path": "/app/chat/api/chat/1764019444672/events", + "params": {}, + "status": 200, + }, + { + "app": "chat", + "name": "chat-detail", + "path": "/app/chat/api/chat/1764019444672", + "params": {}, + "status": 200, + }, + { + "app": "chat", + "name": "agent-chat", + "path": "/app/chat/api/agent/1700000000001/chat", + "params": {}, + "status": 404, + }, + # apps/entities/routes.py + { + "app": "entities", + "name": "facet-entities", + "path": "/app/entities/api/work", + "params": {}, + "status": 200, + }, + { + "app": "entities", + "name": "entity-detail", + "path": "/app/entities/api/work/entity/romeo_montague", + "params": {}, + "status": 200, + }, + { + "app": "entities", + "name": "entity-types", + "path": "/app/entities/api/types", + "params": {}, + "status": 200, + }, + { + "app": "entities", + "name": "journal-entities", + "path": "/app/entities/api/journal", + "params": {}, + "status": 200, + }, + { + "app": "entities", + "name": "journal-entity-detail", + "path": "/app/entities/api/journal/entity/first_test_entity", + "params": {}, + "status": 200, + }, + { + "app": "entities", + "name": "detected-preview", + "path": "/app/entities/api/work/detected/preview", + "params": {"name": "Romeo"}, + "status": 200, + }, + # apps/home/routes.py + { + "app": "home", + "name": "summary", + "path": "/app/home/api/summary/20260304", + "params": {}, + "status": 200, + }, + { + "app": "home", + "name": "stats-month", + "path": "/app/home/api/stats/202603", + "params": {}, + "status": 200, + }, + # apps/import/routes.py + { + "app": "import", + "name": "list", + "path": "/app/import/api/list", + "params": {}, + "status": 200, + }, + { + "app": "import", + "name": "import-day", + "path": "/app/import/api/20260304", + "params": {}, + "status": 404, + }, + # apps/remote/routes.py + { + "app": "remote", + "name": "list", + "path": "/app/remote/api/list", + "params": {}, + "status": 200, + }, + { + "app": "remote", + "name": "remote-key", + "path": "/app/remote/api/example-key/key", + "params": {}, + "status": 404, + }, + { + "app": "remote", + "name": "ingest-day", + "path": "/app/remote/ingest/example-key/segments/20260304", + "params": {}, + "status": 401, + }, + # apps/search/routes.py + { + "app": "search", + "name": "search", + "path": "/app/search/api/search", + "params": {"q": "romeo", "limit": "5", "offset": "0"}, + "status": 200, + }, + { + "app": "search", + "name": "day-results", + "path": "/app/search/api/day_results", + "params": {"q": "meeting", "day": "20260304", "offset": "0", "limit": "5"}, + "status": 200, + }, + # apps/settings/routes.py + { + "app": "settings", + "name": "config", + "path": "/app/settings/api/config", + "params": {}, + "status": 200, + }, + { + "app": "settings", + "name": "transcribe", + "path": "/app/settings/api/transcribe", + "params": {}, + "status": 200, + }, + { + "app": "settings", + "name": "providers", + "path": "/app/settings/api/providers", + "params": {}, + "status": 200, + }, + { + "app": "settings", + "name": "generators", + "path": "/app/settings/api/generators", + "params": {}, + "status": 200, + }, + { + "app": "settings", + "name": "vision", + "path": "/app/settings/api/vision", + "params": {}, + "status": 200, + }, + { + "app": "settings", + "name": "observe", + "path": "/app/settings/api/observe", + "params": {}, + "status": 200, + }, + { + "app": "settings", + "name": "facet", + "path": "/app/settings/api/facet/montague", + "params": {}, + "status": 200, + }, + { + "app": "settings", + "name": "activities-defaults", + "path": "/app/settings/api/activities/defaults", + "params": {}, + "status": 200, + }, + { + "app": "settings", + "name": "facet-activities", + "path": "/app/settings/api/facet/montague/activities", + "params": {}, + "status": 200, + }, + { + "app": "settings", + "name": "sync", + "path": "/app/settings/api/sync", + "params": {}, + "status": 200, + }, + # apps/speakers/routes.py + { + "app": "speakers", + "name": "stats-month", + "path": "/app/speakers/api/stats/202603", + "params": {}, + "status": 200, + }, + { + "app": "speakers", + "name": "segments", + "path": "/app/speakers/api/segments/20260304", + "params": {}, + "status": 200, + }, + { + "app": "speakers", + "name": "speakers-segment", + "path": "/app/speakers/api/speakers/20260304/default/090000_300", + "params": {}, + "status": 200, + }, + { + "app": "speakers", + "name": "sentences", + "path": "/app/speakers/api/sentences/20260304/default/090000_300/audio", + "params": {}, + "status": 200, + }, + # apps/stats/routes.py + { + "app": "stats", + "name": "stats", + "path": "/app/stats/api/stats", + "params": {}, + "status": 200, + }, + # apps/todos/routes.py + { + "app": "todos", + "name": "badge-count", + "path": "/app/todos/api/badge-count", + "params": {}, + "status": 200, + }, + { + "app": "todos", + "name": "nudges", + "path": "/app/todos/api/nudges", + "params": {}, + "status": 200, + }, + { + "app": "todos", + "name": "stats-month", + "path": "/app/todos/api/stats/202603", + "params": {}, + "status": 200, + }, + # apps/tokens/routes.py + { + "app": "tokens", + "name": "usage", + "path": "/app/tokens/api/usage", + "params": {"day": "20260304"}, + "status": 200, + }, + { + "app": "tokens", + "name": "stats-month", + "path": "/app/tokens/api/stats/202603", + "params": {}, + "status": 200, + }, + # apps/transcripts/routes.py + { + "app": "transcripts", + "name": "ranges", + "path": "/app/transcripts/api/ranges/20260304", + "params": {}, + "status": 200, + }, + { + "app": "transcripts", + "name": "segments", + "path": "/app/transcripts/api/segments/20260304", + "params": {}, + "status": 200, + }, + { + "app": "transcripts", + "name": "segment-detail", + "path": "/app/transcripts/api/segment/20260304/default/090000_300", + "params": {}, + "status": 200, + }, + { + "app": "transcripts", + "name": "stats-month", + "path": "/app/transcripts/api/stats/202603", + "params": {}, + "status": 200, + }, +] + + +def normalize(data: Any, journal_path: str) -> Any: + """Return a normalized copy of endpoint JSON for deterministic baselines.""" + + resolved_journal = str(Path(journal_path).resolve()) + project_root = str(Path(__file__).resolve().parent.parent) + + # Journal path contains project root, so replace journal first (longer match) + path_replacements: list[tuple[str, str]] = [] + path_replacements.append((resolved_journal, "")) + # If the fixture journal resolves differently (e.g., symlinks), add that too + fixture_journal = str((Path.cwd() / "tests" / "fixtures" / "journal").resolve()) + if fixture_journal != resolved_journal: + path_replacements.append((fixture_journal, "")) + path_replacements.append((project_root, "")) + # Sort by length descending so longer (more specific) paths match first + path_replacements.sort(key=lambda x: len(x[0]), reverse=True) + + def _normalize_string(value: str) -> str: + result = value + for path, replacement in path_replacements: + result = result.replace(path, replacement) + # Normalize dynamic timestamp in prompt content + result = re.sub( + r"^Today is .*", "Today is ", result, flags=re.MULTILINE + ) + return result + + def walk(value: Any, key: str | None = None) -> Any: + if isinstance(value, dict): + return { + item_key: ( + 0 + if item_key == "mtime" and isinstance(item_value, (int, float)) + else walk(item_value, item_key) + ) + for item_key, item_value in value.items() + } + + if isinstance(value, list): + return [walk(item, key) for item in value] + + if isinstance(value, str): + return _normalize_string(str(value)) + + return value + + return walk(data) + + +def baseline_path(endpoint: dict[str, str]) -> Path: + """Compute baseline file path for an endpoint entry.""" + + return Path("tests/baselines/api") / endpoint["app"] / f"{endpoint['name']}.json" + + +def _extract_json(response: Any) -> Any: + """Load JSON from either Flask response or requests response.""" + + if hasattr(response, "get_json"): + payload = response.get_json(silent=True) + if payload is None: + raise ValueError("response is not JSON") + return payload + + try: + return response.json() + except Exception as exc: + raise ValueError("response is not JSON") from exc + + +def fetch_endpoint(client: Any, endpoint: dict[str, Any]) -> tuple[int, Any]: + """Call endpoint and return (status_code, parsed_json).""" + + response = client.get(endpoint["path"], query_string=endpoint.get("params", {})) + return response.status_code, _extract_json(response) + + +def verify_all(client: Any, journal_path: str) -> list[str]: + """Compare all endpoint responses against stored baselines.""" + + failures: list[str] = [] + for endpoint in ENDPOINTS: + identifier = f"{endpoint['app']}/{endpoint['name']}" + path = baseline_path(endpoint) + + try: + status, payload = fetch_endpoint(client, endpoint) + except Exception as exc: + failures.append(f"{identifier}: failed to fetch endpoint: {exc}") + continue + + if status != endpoint["status"]: + failures.append( + f"{identifier}: expected status {endpoint['status']} got {status}" + ) + continue + + if not path.exists(): + failures.append(f"{identifier}: baseline file not found: {path}") + continue + + actual = normalize(payload, journal_path) + expected = json.loads(path.read_text()) + if actual != expected: + actual_dump = json.dumps( + actual, indent=2, sort_keys=True, ensure_ascii=False + ).splitlines(keepends=True) + expected_dump = json.dumps( + expected, indent=2, sort_keys=True, ensure_ascii=False + ).splitlines(keepends=True) + diff = "".join( + unified_diff( + expected_dump, + actual_dump, + fromfile=f"{identifier} expected", + tofile=f"{identifier} actual", + lineterm="", + ) + ) + failures.append(f"{identifier}:\n{diff}") + + return failures + + +def update_all(client: Any, journal_path: str) -> int: + """Refresh all endpoint baselines from current responses.""" + + updated = 0 + for endpoint in ENDPOINTS: + identifier = f"{endpoint['app']}/{endpoint['name']}" + path = baseline_path(endpoint) + path.parent.mkdir(parents=True, exist_ok=True) + + status, payload = fetch_endpoint(client, endpoint) + if status != endpoint["status"]: + print( + f"warn: {identifier} returned {status}, expected {endpoint['status']}, " + "still writing normalized payload" + ) + + normalized = normalize(payload, journal_path) + path.write_text( + json.dumps(normalized, indent=2, sort_keys=True, ensure_ascii=False) + "\n" + ) + updated += 1 + + return updated + + +class _HttpClient: + """Minimal requests-like object for endpoint fetching.""" + + def __init__(self, base_url: str) -> None: + self.base_url = base_url.rstrip("/") + + def get(self, path: str, query_string: dict[str, Any] | None = None): + import requests + + return requests.get(f"{self.base_url}{path}", params=query_string) + + +def _resolve_journal_path() -> str: + """Resolve journal path from env or sandbox metadata.""" + + env_path = Path.cwd() / "tests" / "fixtures" / "journal" + journal = Path(os.environ.get("JOURNAL_PATH", str(env_path))) + if journal.is_absolute(): + return str(journal) + return str(Path(journal).resolve()) + + +def _resolve_sandbox_journal() -> str | None: + marker = Path(".sandbox.journal") + if not marker.exists(): + return None + value = marker.read_text().strip() + if not value: + return None + return str(Path(value).resolve()) + + +def parse_args(argv: list[str] | None = None) -> argparse.Namespace: + parser = argparse.ArgumentParser(description="API baseline verification tool") + parser.add_argument( + "command", + choices=["verify", "update"], + help="Whether to verify or regenerate baselines", + ) + parser.add_argument( + "--base-url", + help="Use HTTP mode against this base URL instead of Flask test client", + ) + return parser.parse_args(argv) + + +def make_client(base_url: str | None) -> Any: + if base_url: + return _HttpClient(base_url) + journal_path = _resolve_journal_path() + app = create_app(journal_path) + app.config["TESTING"] = True + return app.test_client() + + +def resolve_journal_for_mode(base_url: str | None) -> str: + if base_url: + env_path = os.environ.get("JOURNAL_PATH") + if env_path: + return str(Path(env_path).resolve()) + sandbox_path = _resolve_sandbox_journal() + if sandbox_path: + return sandbox_path + return _resolve_journal_path() + + +def main(argv: list[str] | None = None) -> int: + args = parse_args(argv) + client = make_client(args.base_url) + journal_path = resolve_journal_for_mode(args.base_url) + + if args.command == "verify": + failures = verify_all(client, journal_path) + if failures: + print(f"API baseline verification failed ({len(failures)} endpoints):") + for item in failures: + print(item) + print() + print("Run 'make update-api-baselines' to update baselines") + return 1 + print(f"API baseline verification passed for {len(ENDPOINTS)} endpoints.") + return 0 + + updated = update_all(client, journal_path) + print(f"Updated {updated} baseline files.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main())