personal memory agent
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge branch 'hopper-4gsgsmai-fixtures-relocation'

+89 -341
+2 -2
.gitignore
··· 8 8 *.mp3 9 9 *.flac 10 10 .coverage 11 - fixtures/journal/agents/*.jsonl 12 - fixtures/journal/tokens/*.json 11 + tests/fixtures/journal/agents/*.jsonl 12 + tests/fixtures/journal/tokens/*.json 13 13 *.sqlite 14 14 *.log 15 15 /config*.py
+6 -7
AGENTS.md
··· 42 42 ├── convey/ # Web app frontend & backend 43 43 ├── apps/ # Convey app extensions (see docs/APPS.md) 44 44 ├── muse/ # Agent/generator configs + Agent Skills (muse/*/SKILL.md) 45 - ├── tests/ # Pytest test suites 46 - ├── fixtures/ # Test data (mock journal) 45 + ├── tests/ # Pytest test suites + test fixtures under tests/fixtures/ 47 46 ├── docs/ # All documentation (*.md files) 48 47 ├── AGENTS.md # Development guidelines (this file) 49 48 ├── CLAUDE.md # Symlink to AGENTS.md for Claude Code ··· 55 54 ### Package Organization 56 55 57 56 * **Python**: Requires Python 3.10+ 58 - * **Modules**: Each top-level folder is a Python package with `__init__.py` unless it is data-only (e.g., `fixtures/`) 57 + * **Modules**: Each top-level folder is a Python package with `__init__.py` unless it is data-only (e.g., `tests/fixtures/`) 59 58 * **Imports**: Prefer absolute imports (e.g., `from think.utils import setup_cli`) whenever feasible 60 59 * **Entry Points**: Commands are registered in `sol.py`'s `COMMANDS` dict (pyproject.toml just defines the `sol` entry point) 61 60 * **Journal**: Data stored under `JOURNAL_PATH` (see Environment Management below) ··· 87 86 88 87 ```python 89 88 # Use comprehensive mock journal data for testing 90 - os.environ["JOURNAL_PATH"] = "fixtures/journal" 89 + os.environ["JOURNAL_PATH"] = "tests/fixtures/journal" 91 90 # Now all journal operations work with test data 92 91 ``` 93 92 94 - The `fixtures/journal/` directory contains a complete mock journal structure with sample facets, agents, transcripts, and indexed data for testing. 93 + The `tests/fixtures/journal/` directory contains a complete mock journal structure with sample facets, agents, transcripts, and indexed data for testing. 95 94 96 95 --- 97 96 ··· 132 131 * **Framework**: pytest with coverage reporting 133 132 * **Unit Tests**: `tests/` root directory 134 133 - Fast, no external API calls 135 - - Use `fixtures/journal/` mock data 134 + - Use `tests/fixtures/journal/` mock data 136 135 - Test individual functions and modules 137 136 * **Integration Tests**: `tests/integration/` subdirectory 138 137 - Test real backends (Anthropic, OpenAI, Google) ··· 228 227 229 228 ### File Locations 230 229 * **Entry Points**: `sol.py` `COMMANDS` dict 231 - * **Test Fixtures**: `fixtures/journal/` - complete mock journal 230 + * **Test Fixtures**: `tests/fixtures/journal/` - complete mock journal 232 231 * **Live Logs**: `$JOURNAL_PATH/health/<service>.log` 233 232 * **Agent Personas**: `muse/*.md` (apps can add their own in `muse/`, see [docs/APPS.md](docs/APPS.md)) 234 233 * **Generator Templates**: `muse/*.md` (apps can add their own in `muse/`, see [docs/APPS.md](docs/APPS.md))
+1 -1
Makefile
··· 98 98 fi 99 99 100 100 # Test environment - use fixtures journal for all tests 101 - TEST_ENV = JOURNAL_PATH=fixtures/journal 101 + TEST_ENV = JOURNAL_PATH=tests/fixtures/journal 102 102 103 103 # Venv tool shortcuts 104 104 PYTEST := $(VENV_BIN)/pytest
+4 -2
apps/todos/tests/test_tools.py
··· 19 19 return tool(*args, **kwargs) 20 20 21 21 22 - FIXTURES_JOURNAL = Path(__file__).resolve().parents[3] / "fixtures" / "journal" 22 + FIXTURES_JOURNAL = ( 23 + Path(__file__).resolve().parents[3] / "tests" / "fixtures" / "journal" 24 + ) 23 25 24 26 25 27 def test_todo_list_returns_numbered_view(todo_env): ··· 183 185 def test_todo_tool_pack_round_trip(tmp_path, monkeypatch): 184 186 """Exercise add/done/cancel flow against a copied fixture journal.""" 185 187 if not FIXTURES_JOURNAL.exists(): 186 - pytest.skip("fixtures/journal not found") 188 + pytest.skip("tests/fixtures/journal not found") 187 189 188 190 journal_copy = tmp_path / "journal" 189 191 shutil.copytree(FIXTURES_JOURNAL, journal_copy)
+3 -1
apps/transcripts/tests/conftest.py
··· 11 11 @pytest.fixture(autouse=True) 12 12 def _journal_env(monkeypatch): 13 13 """Point JOURNAL_PATH at the test fixtures.""" 14 - monkeypatch.setenv("JOURNAL_PATH", os.path.join(os.getcwd(), "fixtures", "journal")) 14 + monkeypatch.setenv( 15 + "JOURNAL_PATH", os.path.join(os.getcwd(), "tests", "fixtures", "journal") 16 + )
+1 -1
docs/BACKLOG.md
··· 37 37 38 38 ## Testing 39 39 40 - - [ ] Move fixtures/ into tests/ 40 + - [x] Move fixtures/ into tests/ 41 41 - [ ] Enable clean fixture-based service startup (Convey on dynamic port) for integration/dev testing with screenshots
+2 -2
docs/PROVIDERS.md
··· 289 289 - 2 = FLASH (balanced) 290 290 - 3 = LITE (fast/cheap) 291 291 292 - See `fixtures/journal/config/journal.json` for a complete example and `think/models.py` `PROVIDER_DEFAULTS` for tier-to-model mappings. 292 + See `tests/fixtures/journal/config/journal.json` for a complete example and `think/models.py` `PROVIDER_DEFAULTS` for tier-to-model mappings. 293 293 294 294 ## Testing 295 295 ··· 354 354 **Testing:** 355 355 11. Create unit tests in `tests/test_<name>.py` 356 356 12. Create integration tests in `tests/integration/test_<name>_backend.py` 357 - 13. Add test contexts to `fixtures/journal/config/journal.json` 357 + 13. Add test contexts to `tests/fixtures/journal/config/journal.json` 358 358 359 359 **Documentation:** 360 360 14. Update `think/providers/__init__.py` docstring
-6
fixtures/000000_audio.json
··· 1 - [ 2 - {"start": "00:00:00", "source": "mic", "speaker": 1, "text": "So, all other companies, software vendors, like our competitors are using it.", "description": "speaking with a slight accent, technical discussion tone"}, 3 - {"start": "00:00:07", "source": "mic", "speaker": 2, "text": "But at the moment its use case is on legacy systems. So the developer, the analyst is syncing the data, and then they go to run the process. So the challenge that we have is making sure that it receives data from the Data Hub. From back when I worked at a previous company, I recall that the Data Hub goes idle after the initial sync, and then it's not sending new data, I don't think. And we would want to see if there's any way that we can have an ALWAYS-ON data stream to our listener from the Data Hub, or if the Data Hub terminates the session completely. If not, then we'd have to devise a way that as soon as the Data Hub is queried, it sends data to our service. We have to assume it has an empty cache at that point. It might sync the first 10% of the data and then start its process and continue syncing in the background. So that was one of the questions to your team was how much access to the data stream is there from the Data Hub during an idle session?", "description": "calm informative tone, clear and articulate"}, 4 - {"start": "00:01:09", "source": "mic", "speaker": 1, "text": "It's dependent on the system architecture, but most of them currently don't maintain an active data stream when a session is closed.", "description": "explaining with technical tone"}, 5 - {"topics": "API integration, data synchronization, real-time data, system architecture, Data Hub", "setting": "workplace"} 6 - ]
-8
fixtures/000000_monitor_0_diff.json
··· 1 - { 2 - "app": "Team Chat App", 3 - "app_title": "Anna Koval, Leo Maxwell, Nina Patel (DM) - DataSystems - Team Chat App", 4 - "visual_description": "The screenshot shows a Team Chat App conversation. On the left is the main conversation window with messages from Leo Maxwell, Nina Patel, and Alex. On the right is a 'Thread' window with replies to Alex's message. The messages contain text, emojis, and timestamps. Below the main conversation is a message input field with formatting options and an area where users can type a message. The 'Thread' window shows replies from Alex and Leo Maxwell, along with a reply input field.", 5 - "full_ocr": "Thread\nAlex 2 minutes ago\nsounds like leo wants Synapse-link with Omni-net\n1 reply\nLeo Maxwell 1 minute ago\nI do want that. Productivity > privacy\nReply...\nAlso send to the group\nAa", 6 - "meeting_status": "No meeting is currently active", 7 - "activity_category": "Communication" 8 - }
-18
fixtures/000000_screen.json
··· 1 - ## 09:10 - 09:15 Summary 2 - 3 - During this five-minute window, the user was actively engaged in a meeting, likely taking or reviewing project notes, within an **Internal Wiki Editor**. 4 - 5 - ### Detailed Activity: 6 - 7 - At **09:12:07**, the user was viewing and potentially drafting or editing an internal wiki page titled "**Project-Helios_Q2-Sprint-Review_Notes_10JUNE2025.wiki - Saved**". 8 - 9 - The document appears to be project review notes, containing detailed discussions and action items related to various technical and project management topics, including: 10 - * **Storage Protocol SP-450**: Mention of a cross-team sync date update to Q3. 11 - * **Tier-3 Archive Spec**: Editorial work ongoing, with sections 2.1 and 2 expected to be completed by Q4 2025, and full document completion by Q1 2026. Stress and performance tests are planned for Q2 2026, with code review in Q3 2026, and final release by January 2027. 12 - * **Security Council (SC) Review**: Discussion about the SC issuing a new guideline reclassifying a legacy database schema for Project "Neptune" work. 13 - * **Quarterly Milestone Sync (QMS)**: Work on a white paper for end of Q2, requiring Enterprise Architecture (EA) and Security Council (SC) coordination before the Product Review Committee (PRC) meeting. Task Force 4.1 is available for joining, and the "Glacier" storage tier codification in the 'Service Catalog' was discussed, including its dual-use nature. A recommendation to the August PRC on new work is pending. 14 - * **Client-Side Caching Spec**: The partner consultation just opened, and the Final Draft Review (FDR) is now July 2025. VeriData has waived standard licensing requirements for external partner participation. 15 - * **Project "Orion"** and **Frontend UI Spec**: No new updates were noted. 16 - * **Action Items**: A table of action items was visible, including "A-113 Brief Marcus Thorne ENG-400" assigned to Liam with a status of "IN PROGRESS". 17 - 18 - The presence of video conferencing controls at the bottom of the screen, with the "Unmute" button indicating the microphone was muted, confirms the user was participating in an **active meeting** while reviewing or drafting these notes. The activity was categorized as "Drafting".
fixtures/journal/20240101/123456_300/audio.json tests/fixtures/journal/20240101/123456_300/audio.json
fixtures/journal/20240101/123456_300/audio.jsonl tests/fixtures/journal/20240101/123456_300/audio.jsonl
fixtures/journal/20240101/123456_300/audio.md tests/fixtures/journal/20240101/123456_300/audio.md
fixtures/journal/20240101/123456_300/monitor_1_diff.json tests/fixtures/journal/20240101/123456_300/monitor_1_diff.json
fixtures/journal/20240101/123456_300/monitor_1_diff.png tests/fixtures/journal/20240101/123456_300/monitor_1_diff.png
fixtures/journal/20240101/123456_300/monitor_1_diff_box.json tests/fixtures/journal/20240101/123456_300/monitor_1_diff_box.json
fixtures/journal/20240101/123456_300/screen.jsonl tests/fixtures/journal/20240101/123456_300/screen.jsonl
fixtures/journal/20240101/123456_300/screen.md tests/fixtures/journal/20240101/123456_300/screen.md
fixtures/journal/20240101/agents/flow.md tests/fixtures/journal/20240101/agents/flow.md
fixtures/journal/20240101/agents/meetings.md tests/fixtures/journal/20240101/agents/meetings.md
fixtures/journal/20240101/indexer/transcripts.sqlite tests/fixtures/journal/20240101/indexer/transcripts.sqlite
fixtures/journal/20240102/234567_300/audio.json tests/fixtures/journal/20240102/234567_300/audio.json
fixtures/journal/20240102/234567_300/audio.jsonl tests/fixtures/journal/20240102/234567_300/audio.jsonl
fixtures/journal/20240102/234567_300/audio.md tests/fixtures/journal/20240102/234567_300/audio.md
fixtures/journal/20240102/234567_300/monitor_1_diff.json tests/fixtures/journal/20240102/234567_300/monitor_1_diff.json
fixtures/journal/20240102/234567_300/screen.jsonl tests/fixtures/journal/20240102/234567_300/screen.jsonl
fixtures/journal/20240102/234567_300/screen.md tests/fixtures/journal/20240102/234567_300/screen.md
fixtures/journal/20240102/agents/flow.md tests/fixtures/journal/20240102/agents/flow.md
fixtures/journal/20240102/indexer/transcripts.sqlite tests/fixtures/journal/20240102/indexer/transcripts.sqlite
fixtures/journal/20250124/TODO.md tests/fixtures/journal/20250124/TODO.md
fixtures/journal/agents/1700000000001.jsonl tests/fixtures/journal/agents/1700000000001.jsonl
fixtures/journal/apps/chat/chats/1764019444672.json tests/fixtures/journal/apps/chat/chats/1764019444672.json
fixtures/journal/apps/chat/chats/1764019602551.json tests/fixtures/journal/apps/chat/chats/1764019602551.json
fixtures/journal/apps/chat/chats/1764019955580.json tests/fixtures/journal/apps/chat/chats/1764019955580.json
fixtures/journal/config/convey.json tests/fixtures/journal/config/convey.json
fixtures/journal/config/journal.json tests/fixtures/journal/config/journal.json
fixtures/journal/entities.md tests/fixtures/journal/entities.md
fixtures/journal/entities/acme_corp/entity.json tests/fixtures/journal/entities/acme_corp/entity.json
fixtures/journal/entities/alice_johnson/entity.json tests/fixtures/journal/entities/alice_johnson/entity.json
fixtures/journal/entities/api_optimization/entity.json tests/fixtures/journal/entities/api_optimization/entity.json
fixtures/journal/entities/bob_smith/entity.json tests/fixtures/journal/entities/bob_smith/entity.json
fixtures/journal/entities/bob_wilson/entity.json tests/fixtures/journal/entities/bob_wilson/entity.json
fixtures/journal/entities/dashboard_redesign/entity.json tests/fixtures/journal/entities/dashboard_redesign/entity.json
fixtures/journal/entities/docker/entity.json tests/fixtures/journal/entities/docker/entity.json
fixtures/journal/entities/first_test_entity/entity.json tests/fixtures/journal/entities/first_test_entity/entity.json
fixtures/journal/entities/jane_doe/entity.json tests/fixtures/journal/entities/jane_doe/entity.json
fixtures/journal/entities/john_smith/entity.json tests/fixtures/journal/entities/john_smith/entity.json
fixtures/journal/entities/postgresql/entity.json tests/fixtures/journal/entities/postgresql/entity.json
fixtures/journal/entities/second_test_entity/entity.json tests/fixtures/journal/entities/second_test_entity/entity.json
fixtures/journal/entities/tech_solutions_inc/entity.json tests/fixtures/journal/entities/tech_solutions_inc/entity.json
fixtures/journal/entities/third_test_entity_with_description/entity.json tests/fixtures/journal/entities/third_test_entity_with_description/entity.json
fixtures/journal/entities/visual_studio_code/entity.json tests/fixtures/journal/entities/visual_studio_code/entity.json
fixtures/journal/entity_review.log tests/fixtures/journal/entity_review.log
fixtures/journal/facets/broken-facet/.gitkeep tests/fixtures/journal/facets/broken-facet/.gitkeep
fixtures/journal/facets/empty-entities/entities.md tests/fixtures/journal/facets/empty-entities/entities.md
fixtures/journal/facets/empty-entities/facet.json tests/fixtures/journal/facets/empty-entities/facet.json
fixtures/journal/facets/full-featured/activities/activities.jsonl tests/fixtures/journal/facets/full-featured/activities/activities.jsonl
fixtures/journal/facets/full-featured/entities/20250101.jsonl tests/fixtures/journal/facets/full-featured/entities/20250101.jsonl
fixtures/journal/facets/full-featured/entities/first_test_entity/entity.json tests/fixtures/journal/facets/full-featured/entities/first_test_entity/entity.json
fixtures/journal/facets/full-featured/entities/second_test_entity/entity.json tests/fixtures/journal/facets/full-featured/entities/second_test_entity/entity.json
fixtures/journal/facets/full-featured/entities/third_test_entity_with_description/entity.json tests/fixtures/journal/facets/full-featured/entities/third_test_entity_with_description/entity.json
fixtures/journal/facets/full-featured/facet.json tests/fixtures/journal/facets/full-featured/facet.json
fixtures/journal/facets/minimal-facet/facet.json tests/fixtures/journal/facets/minimal-facet/facet.json
fixtures/journal/facets/personal/entities/20250101.jsonl tests/fixtures/journal/facets/personal/entities/20250101.jsonl
fixtures/journal/facets/personal/entities/20250102.jsonl tests/fixtures/journal/facets/personal/entities/20250102.jsonl
fixtures/journal/facets/personal/entities/acme_corp/entity.json tests/fixtures/journal/facets/personal/entities/acme_corp/entity.json
fixtures/journal/facets/personal/entities/alice_johnson/entity.json tests/fixtures/journal/facets/personal/entities/alice_johnson/entity.json
fixtures/journal/facets/personal/entities/bob_smith/entity.json tests/fixtures/journal/facets/personal/entities/bob_smith/entity.json
fixtures/journal/facets/personal/events/20240101.jsonl tests/fixtures/journal/facets/personal/events/20240101.jsonl
fixtures/journal/facets/personal/todos/20240101.jsonl tests/fixtures/journal/facets/personal/todos/20240101.jsonl
fixtures/journal/facets/priority-test/facet.json tests/fixtures/journal/facets/priority-test/facet.json
fixtures/journal/facets/test-facet/entities/acme_corp/entity.json tests/fixtures/journal/facets/test-facet/entities/acme_corp/entity.json
fixtures/journal/facets/test-facet/entities/api_optimization/entity.json tests/fixtures/journal/facets/test-facet/entities/api_optimization/entity.json
fixtures/journal/facets/test-facet/entities/bob_wilson/entity.json tests/fixtures/journal/facets/test-facet/entities/bob_wilson/entity.json
fixtures/journal/facets/test-facet/entities/dashboard_redesign/entity.json tests/fixtures/journal/facets/test-facet/entities/dashboard_redesign/entity.json
fixtures/journal/facets/test-facet/entities/docker/entity.json tests/fixtures/journal/facets/test-facet/entities/docker/entity.json
fixtures/journal/facets/test-facet/entities/jane_doe/entity.json tests/fixtures/journal/facets/test-facet/entities/jane_doe/entity.json
fixtures/journal/facets/test-facet/entities/john_smith/entity.json tests/fixtures/journal/facets/test-facet/entities/john_smith/entity.json
fixtures/journal/facets/test-facet/entities/postgresql/entity.json tests/fixtures/journal/facets/test-facet/entities/postgresql/entity.json
fixtures/journal/facets/test-facet/entities/tech_solutions_inc/entity.json tests/fixtures/journal/facets/test-facet/entities/tech_solutions_inc/entity.json
fixtures/journal/facets/test-facet/entities/visual_studio_code/entity.json tests/fixtures/journal/facets/test-facet/entities/visual_studio_code/entity.json
fixtures/journal/facets/test-facet/facet.json tests/fixtures/journal/facets/test-facet/facet.json
fixtures/journal/facets/work/events/20240101.jsonl tests/fixtures/journal/facets/work/events/20240101.jsonl
fixtures/journal/facets/work/events/20240105.jsonl tests/fixtures/journal/facets/work/events/20240105.jsonl
fixtures/journal/facets/work/news/20240101.md tests/fixtures/journal/facets/work/news/20240101.md
fixtures/journal/summary.md tests/fixtures/journal/summary.md
fixtures/journal/tokens/.gitignore tests/fixtures/journal/tokens/.gitignore
fixtures/journal/tokens/20250823.jsonl tests/fixtures/journal/tokens/20250823.jsonl
fixtures/journal/tokens/20250824.jsonl tests/fixtures/journal/tokens/20250824.jsonl
fixtures/journal/tokens/20250825.jsonl tests/fixtures/journal/tokens/20250825.jsonl
fixtures/journal/tokens/20250826.jsonl tests/fixtures/journal/tokens/20250826.jsonl
fixtures/journal/tokens/20250827.jsonl tests/fixtures/journal/tokens/20250827.jsonl
fixtures/journal/tokens/20250828.jsonl tests/fixtures/journal/tokens/20250828.jsonl
fixtures/journal/tokens/20250905.jsonl tests/fixtures/journal/tokens/20250905.jsonl
fixtures/journal/tokens/20250908.jsonl tests/fixtures/journal/tokens/20250908.jsonl
fixtures/journal/tokens/20250909.jsonl tests/fixtures/journal/tokens/20250909.jsonl
fixtures/journal/tokens/20250914.jsonl tests/fixtures/journal/tokens/20250914.jsonl
fixtures/journal/tokens/20250915.jsonl tests/fixtures/journal/tokens/20250915.jsonl
fixtures/journal/tokens/20250916.jsonl tests/fixtures/journal/tokens/20250916.jsonl
fixtures/journal/tokens/20250919.jsonl tests/fixtures/journal/tokens/20250919.jsonl
fixtures/journal/tokens/20250920.jsonl tests/fixtures/journal/tokens/20250920.jsonl
fixtures/journal/tokens/20250926.jsonl tests/fixtures/journal/tokens/20250926.jsonl
fixtures/journal/tokens/20250927.jsonl tests/fixtures/journal/tokens/20250927.jsonl
fixtures/journal/tokens/20251003.jsonl tests/fixtures/journal/tokens/20251003.jsonl
fixtures/journal/tokens/20251004.jsonl tests/fixtures/journal/tokens/20251004.jsonl
fixtures/journal/tokens/20251005.jsonl tests/fixtures/journal/tokens/20251005.jsonl
fixtures/journal/tokens/20251006.jsonl tests/fixtures/journal/tokens/20251006.jsonl
fixtures/journal/tokens/20251011.jsonl tests/fixtures/journal/tokens/20251011.jsonl
fixtures/journal/tokens/20251012.jsonl tests/fixtures/journal/tokens/20251012.jsonl
fixtures/journal/tokens/20251015.jsonl tests/fixtures/journal/tokens/20251015.jsonl
fixtures/journal/tokens/20251024.jsonl tests/fixtures/journal/tokens/20251024.jsonl
-223
fixtures/journal_stats.json
··· 1 - { 2 - "days": { 3 - "20240101": { 4 - "audio_flac": 1, 5 - "audio_json": 0, 6 - "repair_observe": 2, 7 - "diff_png": 0, 8 - "desc_json": 1, 9 - "screen_md": 1, 10 - "repair_reduce": 1, 11 - "entities": 1, 12 - "repair_entity": 0, 13 - "outputs_processed": 3, 14 - "outputs_pending": 8, 15 - "audio_seconds": 0.0, 16 - "audio_bytes": 5, 17 - "image_bytes": 0, 18 - "activity": 18 19 - } 20 - }, 21 - "totals": { 22 - "audio_flac": 1, 23 - "audio_json": 0, 24 - "repair_observe": 2, 25 - "diff_png": 0, 26 - "desc_json": 1, 27 - "screen_md": 1, 28 - "repair_reduce": 1, 29 - "entities": 1, 30 - "repair_entity": 0, 31 - "outputs_processed": 3, 32 - "outputs_pending": 8 33 - }, 34 - "total_audio_seconds": 0.0, 35 - "total_audio_bytes": 5, 36 - "total_image_bytes": 0, 37 - "topic_counts": {}, 38 - "topic_minutes": {}, 39 - "heatmap": [ 40 - [ 41 - 0.0, 42 - 0.0, 43 - 0.0, 44 - 0.0, 45 - 0.0, 46 - 0.0, 47 - 0.0, 48 - 0.0, 49 - 0.0, 50 - 0.0, 51 - 0.0, 52 - 0.0, 53 - 0.0, 54 - 0.0, 55 - 0.0, 56 - 0.0, 57 - 0.0, 58 - 0.0, 59 - 0.0, 60 - 0.0, 61 - 0.0, 62 - 0.0, 63 - 0.0, 64 - 0.0 65 - ], 66 - [ 67 - 0.0, 68 - 0.0, 69 - 0.0, 70 - 0.0, 71 - 0.0, 72 - 0.0, 73 - 0.0, 74 - 0.0, 75 - 0.0, 76 - 0.0, 77 - 0.0, 78 - 0.0, 79 - 0.0, 80 - 0.0, 81 - 0.0, 82 - 0.0, 83 - 0.0, 84 - 0.0, 85 - 0.0, 86 - 0.0, 87 - 0.0, 88 - 0.0, 89 - 0.0, 90 - 0.0 91 - ], 92 - [ 93 - 0.0, 94 - 0.0, 95 - 0.0, 96 - 0.0, 97 - 0.0, 98 - 0.0, 99 - 0.0, 100 - 0.0, 101 - 0.0, 102 - 0.0, 103 - 0.0, 104 - 0.0, 105 - 0.0, 106 - 0.0, 107 - 0.0, 108 - 0.0, 109 - 0.0, 110 - 0.0, 111 - 0.0, 112 - 0.0, 113 - 0.0, 114 - 0.0, 115 - 0.0, 116 - 0.0 117 - ], 118 - [ 119 - 0.0, 120 - 0.0, 121 - 0.0, 122 - 0.0, 123 - 0.0, 124 - 0.0, 125 - 0.0, 126 - 0.0, 127 - 0.0, 128 - 0.0, 129 - 0.0, 130 - 0.0, 131 - 0.0, 132 - 0.0, 133 - 0.0, 134 - 0.0, 135 - 0.0, 136 - 0.0, 137 - 0.0, 138 - 0.0, 139 - 0.0, 140 - 0.0, 141 - 0.0, 142 - 0.0 143 - ], 144 - [ 145 - 0.0, 146 - 0.0, 147 - 0.0, 148 - 0.0, 149 - 0.0, 150 - 0.0, 151 - 0.0, 152 - 0.0, 153 - 0.0, 154 - 0.0, 155 - 0.0, 156 - 0.0, 157 - 0.0, 158 - 0.0, 159 - 0.0, 160 - 0.0, 161 - 0.0, 162 - 0.0, 163 - 0.0, 164 - 0.0, 165 - 0.0, 166 - 0.0, 167 - 0.0, 168 - 0.0 169 - ], 170 - [ 171 - 0.0, 172 - 0.0, 173 - 0.0, 174 - 0.0, 175 - 0.0, 176 - 0.0, 177 - 0.0, 178 - 0.0, 179 - 0.0, 180 - 0.0, 181 - 0.0, 182 - 0.0, 183 - 0.0, 184 - 0.0, 185 - 0.0, 186 - 0.0, 187 - 0.0, 188 - 0.0, 189 - 0.0, 190 - 0.0, 191 - 0.0, 192 - 0.0, 193 - 0.0, 194 - 0.0 195 - ], 196 - [ 197 - 0.0, 198 - 0.0, 199 - 0.0, 200 - 0.0, 201 - 0.0, 202 - 0.0, 203 - 0.0, 204 - 0.0, 205 - 0.0, 206 - 0.0, 207 - 0.0, 208 - 0.0, 209 - 0.0, 210 - 0.0, 211 - 0.0, 212 - 0.0, 213 - 0.0, 214 - 0.0, 215 - 0.0, 216 - 0.0, 217 - 0.0, 218 - 0.0, 219 - 0.0, 220 - 0.0 221 - ] 222 - ] 223 - }
fixtures/revai.json tests/fixtures/revai.json
+3 -3
tests/conftest.py
··· 14 14 15 15 @pytest.fixture(autouse=True) 16 16 def set_test_journal_path(request, monkeypatch): 17 - """Set JOURNAL_PATH to fixtures/journal for all unit tests. 17 + """Set JOURNAL_PATH to tests/fixtures/journal for all unit tests. 18 18 19 19 This ensures all tests have a valid JOURNAL_PATH without needing 20 20 to explicitly set it in each test. Integration tests are excluded. ··· 23 23 if "integration" in request.node.keywords: 24 24 return 25 25 26 - # Set JOURNAL_PATH to fixtures/journal for all unit tests 27 - monkeypatch.setenv("JOURNAL_PATH", "fixtures/journal") 26 + # Set JOURNAL_PATH to tests/fixtures/journal for all unit tests 27 + monkeypatch.setenv("JOURNAL_PATH", "tests/fixtures/journal") 28 28 29 29 30 30 @pytest.fixture(autouse=True)
+10 -10
tests/integration/test_anthropic_provider.py
··· 16 16 17 17 18 18 def get_fixtures_env(): 19 - """Load the fixtures/.env file and return the environment.""" 20 - fixtures_env = Path(__file__).parent.parent.parent / "fixtures" / ".env" 19 + """Load the tests/fixtures/.env file and return the environment.""" 20 + fixtures_env = Path(__file__).parent.parent / "fixtures" / ".env" 21 21 if not fixtures_env.exists(): 22 22 return None, None, None 23 23 ··· 38 38 fixtures_env, api_key, journal_path = get_fixtures_env() 39 39 40 40 if not fixtures_env: 41 - pytest.skip("fixtures/.env not found") 41 + pytest.skip("tests/fixtures/.env not found") 42 42 43 43 if not api_key: 44 - pytest.skip("ANTHROPIC_API_KEY not found in fixtures/.env file") 44 + pytest.skip("ANTHROPIC_API_KEY not found in tests/fixtures/.env file") 45 45 46 46 if not journal_path: 47 - pytest.skip("JOURNAL_PATH not found in fixtures/.env file") 47 + pytest.skip("JOURNAL_PATH not found in tests/fixtures/.env file") 48 48 49 49 # Prepare environment 50 50 env = os.environ.copy() ··· 146 146 fixtures_env, api_key, journal_path = get_fixtures_env() 147 147 148 148 if not fixtures_env: 149 - pytest.skip("fixtures/.env not found") 149 + pytest.skip("tests/fixtures/.env not found") 150 150 151 151 if not api_key: 152 - pytest.skip("ANTHROPIC_API_KEY not found in fixtures/.env file") 152 + pytest.skip("ANTHROPIC_API_KEY not found in tests/fixtures/.env file") 153 153 154 154 if not journal_path: 155 - pytest.skip("JOURNAL_PATH not found in fixtures/.env file") 155 + pytest.skip("JOURNAL_PATH not found in tests/fixtures/.env file") 156 156 157 157 # Prepare environment 158 158 env = os.environ.copy() ··· 233 233 fixtures_env, api_key, _ = get_fixtures_env() 234 234 235 235 if not fixtures_env: 236 - pytest.skip("fixtures/.env not found") 236 + pytest.skip("tests/fixtures/.env not found") 237 237 238 238 if not api_key: 239 - pytest.skip("ANTHROPIC_API_KEY not found in fixtures/.env file") 239 + pytest.skip("ANTHROPIC_API_KEY not found in tests/fixtures/.env file") 240 240 241 241 # Import provider directly for this test 242 242 from think.providers import anthropic as anthropic_provider
+10 -10
tests/integration/test_google_provider.py
··· 16 16 17 17 18 18 def get_fixtures_env(): 19 - """Load the fixtures/.env file and return the environment.""" 20 - fixtures_env = Path(__file__).parent.parent.parent / "fixtures" / ".env" 19 + """Load the tests/fixtures/.env file and return the environment.""" 20 + fixtures_env = Path(__file__).parent.parent / "fixtures" / ".env" 21 21 if not fixtures_env.exists(): 22 22 return None, None, None 23 23 ··· 38 38 fixtures_env, api_key, journal_path = get_fixtures_env() 39 39 40 40 if not fixtures_env: 41 - pytest.skip("fixtures/.env not found") 41 + pytest.skip("tests/fixtures/.env not found") 42 42 43 43 if not api_key: 44 - pytest.skip("GOOGLE_API_KEY not found in fixtures/.env file") 44 + pytest.skip("GOOGLE_API_KEY not found in tests/fixtures/.env file") 45 45 46 46 if not journal_path: 47 - pytest.skip("JOURNAL_PATH not found in fixtures/.env file") 47 + pytest.skip("JOURNAL_PATH not found in tests/fixtures/.env file") 48 48 49 49 # Prepare environment 50 50 env = os.environ.copy() ··· 130 130 fixtures_env, api_key, journal_path = get_fixtures_env() 131 131 132 132 if not fixtures_env: 133 - pytest.skip("fixtures/.env not found") 133 + pytest.skip("tests/fixtures/.env not found") 134 134 135 135 if not api_key: 136 - pytest.skip("GOOGLE_API_KEY not found in fixtures/.env file") 136 + pytest.skip("GOOGLE_API_KEY not found in tests/fixtures/.env file") 137 137 138 138 if not journal_path: 139 - pytest.skip("JOURNAL_PATH not found in fixtures/.env file") 139 + pytest.skip("JOURNAL_PATH not found in tests/fixtures/.env file") 140 140 141 141 # Prepare environment 142 142 env = os.environ.copy() ··· 221 221 fixtures_env, api_key, _ = get_fixtures_env() 222 222 223 223 if not fixtures_env: 224 - pytest.skip("fixtures/.env not found") 224 + pytest.skip("tests/fixtures/.env not found") 225 225 226 226 if not api_key: 227 - pytest.skip("GOOGLE_API_KEY not found in fixtures/.env file") 227 + pytest.skip("GOOGLE_API_KEY not found in tests/fixtures/.env file") 228 228 229 229 # Import provider directly for this test 230 230 from think.providers import google as google_provider
+13 -13
tests/integration/test_openai_provider.py
··· 16 16 17 17 18 18 def get_fixtures_env(): 19 - """Load the fixtures/.env file and return the environment.""" 20 - fixtures_env = Path(__file__).parent.parent.parent / "fixtures" / ".env" 19 + """Load the tests/fixtures/.env file and return the environment.""" 20 + fixtures_env = Path(__file__).parent.parent / "fixtures" / ".env" 21 21 if not fixtures_env.exists(): 22 22 return None, None, None 23 23 ··· 38 38 fixtures_env, api_key, journal_path = get_fixtures_env() 39 39 40 40 if not fixtures_env: 41 - pytest.skip("fixtures/.env not found") 41 + pytest.skip("tests/fixtures/.env not found") 42 42 43 43 if not api_key: 44 - pytest.skip("OPENAI_API_KEY not found in fixtures/.env file") 44 + pytest.skip("OPENAI_API_KEY not found in tests/fixtures/.env file") 45 45 46 46 if not journal_path: 47 - pytest.skip("JOURNAL_PATH not found in fixtures/.env file") 47 + pytest.skip("JOURNAL_PATH not found in tests/fixtures/.env file") 48 48 49 49 # Prepare environment 50 50 env = os.environ.copy() ··· 138 138 fixtures_env, api_key, journal_path = get_fixtures_env() 139 139 140 140 if not fixtures_env: 141 - pytest.skip("fixtures/.env not found") 141 + pytest.skip("tests/fixtures/.env not found") 142 142 143 143 if not api_key: 144 - pytest.skip("OPENAI_API_KEY not found in fixtures/.env file") 144 + pytest.skip("OPENAI_API_KEY not found in tests/fixtures/.env file") 145 145 146 146 if not journal_path: 147 - pytest.skip("JOURNAL_PATH not found in fixtures/.env file") 147 + pytest.skip("JOURNAL_PATH not found in tests/fixtures/.env file") 148 148 149 149 # Prepare environment 150 150 env = os.environ.copy() ··· 223 223 fixtures_env, api_key, journal_path = get_fixtures_env() 224 224 225 225 if not fixtures_env: 226 - pytest.skip("fixtures/.env not found") 226 + pytest.skip("tests/fixtures/.env not found") 227 227 228 228 if not api_key: 229 - pytest.skip("OPENAI_API_KEY not found in fixtures/.env file") 229 + pytest.skip("OPENAI_API_KEY not found in tests/fixtures/.env file") 230 230 231 231 if not journal_path: 232 - pytest.skip("JOURNAL_PATH not found in fixtures/.env file") 232 + pytest.skip("JOURNAL_PATH not found in tests/fixtures/.env file") 233 233 234 234 # Prepare environment 235 235 env = os.environ.copy() ··· 301 301 fixtures_env, api_key, _ = get_fixtures_env() 302 302 303 303 if not fixtures_env: 304 - pytest.skip("fixtures/.env not found") 304 + pytest.skip("tests/fixtures/.env not found") 305 305 306 306 if not api_key: 307 - pytest.skip("OPENAI_API_KEY not found in fixtures/.env file") 307 + pytest.skip("OPENAI_API_KEY not found in tests/fixtures/.env file") 308 308 309 309 # Import provider directly for this test 310 310 from think.providers import openai as openai_provider
+1 -1
tests/test_activities.py
··· 8 8 from pathlib import Path 9 9 10 10 # Set up test environment before importing the module 11 - os.environ["JOURNAL_PATH"] = "fixtures/journal" 11 + os.environ["JOURNAL_PATH"] = "tests/fixtures/journal" 12 12 13 13 14 14 def test_get_default_activities():
+1 -1
tests/test_activity_state.py
··· 9 9 from pathlib import Path 10 10 11 11 # Set up test environment before importing the module 12 - os.environ["JOURNAL_PATH"] = "fixtures/journal" 12 + os.environ["JOURNAL_PATH"] = "tests/fixtures/journal" 13 13 14 14 15 15 class TestExtractFacetFromOutputPath:
+2 -2
tests/test_app_agents.py
··· 13 13 14 14 @pytest.fixture 15 15 def fixture_journal(): 16 - """Set JOURNAL_PATH to fixtures/journal for testing.""" 17 - os.environ["JOURNAL_PATH"] = "fixtures/journal" 16 + """Set JOURNAL_PATH to tests/fixtures/journal for testing.""" 17 + os.environ["JOURNAL_PATH"] = "tests/fixtures/journal" 18 18 yield 19 19 20 20
+3 -1
tests/test_call.py
··· 129 129 130 130 # Copy fixtures to tmp so we can write 131 131 journal = tmp_path / "journal" 132 - shutil.copytree("fixtures/journal/facets/work", journal / "facets" / "work") 132 + shutil.copytree( 133 + "tests/fixtures/journal/facets/work", journal / "facets" / "work" 134 + ) 133 135 monkeypatch.setenv("JOURNAL_PATH", str(journal)) 134 136 # Clear cached journal path 135 137 import think.utils
-1
tests/test_cli_provider.py
··· 4 4 """Tests for think.providers.cli — CLI subprocess runner infrastructure.""" 5 5 6 6 import asyncio 7 - import json 8 7 from unittest.mock import AsyncMock, patch 9 8 10 9 import pytest
+1 -1
tests/test_cluster_full.py
··· 8 8 9 9 from think.utils import day_path 10 10 11 - FIXTURES = Path("fixtures") 11 + FIXTURES = Path("tests/fixtures") 12 12 13 13 14 14 def copy_day(tmp_path: Path) -> Path:
+2 -2
tests/test_config.py
··· 158 158 159 159 160 160 def test_get_config_with_fixtures(): 161 - """Test get_config with fixtures/journal path.""" 161 + """Test get_config with tests/fixtures/journal path.""" 162 162 # Set JOURNAL_PATH to fixtures 163 - os.environ["JOURNAL_PATH"] = "fixtures/journal" 163 + os.environ["JOURNAL_PATH"] = "tests/fixtures/journal" 164 164 165 165 config = get_config() 166 166
+4 -4
tests/test_config_cli.py
··· 10 10 11 11 def test_config_prints_json(monkeypatch, capsys): 12 12 """Default command prints full config JSON.""" 13 - monkeypatch.setenv("JOURNAL_PATH", "fixtures/journal") 13 + monkeypatch.setenv("JOURNAL_PATH", "tests/fixtures/journal") 14 14 monkeypatch.setattr("sys.argv", ["sol config"]) 15 15 16 16 main() ··· 22 22 23 23 def test_config_env_prints_path(monkeypatch, capsys): 24 24 """env subcommand prints resolved JOURNAL_PATH.""" 25 - monkeypatch.setenv("JOURNAL_PATH", "fixtures/journal") 25 + monkeypatch.setenv("JOURNAL_PATH", "tests/fixtures/journal") 26 26 monkeypatch.setattr("sys.argv", ["sol config", "env"]) 27 27 28 28 main() 29 29 30 30 output = capsys.readouterr().out.strip() 31 - assert output == "JOURNAL_PATH=fixtures/journal (from shell)" 31 + assert output == "JOURNAL_PATH=tests/fixtures/journal (from shell)" 32 32 33 33 34 34 def test_config_env_shows_source(monkeypatch, capsys): 35 35 """env subcommand includes source for the resolved path.""" 36 - monkeypatch.setenv("JOURNAL_PATH", "fixtures/journal") 36 + monkeypatch.setenv("JOURNAL_PATH", "tests/fixtures/journal") 37 37 monkeypatch.setattr("sys.argv", ["sol config", "env"]) 38 38 39 39 main()
+1 -1
tests/test_dream_full.py
··· 7 7 import shutil 8 8 from pathlib import Path 9 9 10 - FIXTURES = Path("fixtures") 10 + FIXTURES = Path("tests/fixtures") 11 11 12 12 13 13 def copy_journal(tmp_path: Path) -> Path:
+3 -3
tests/test_entities.py
··· 41 41 42 42 @pytest.fixture 43 43 def fixture_journal(): 44 - """Set JOURNAL_PATH to fixtures/journal for testing.""" 45 - os.environ["JOURNAL_PATH"] = "fixtures/journal" 44 + """Set JOURNAL_PATH to tests/fixtures/journal for testing.""" 45 + os.environ["JOURNAL_PATH"] = "tests/fixtures/journal" 46 46 yield 47 47 # No cleanup needed - just testing reads 48 48 ··· 143 143 """Test path generation for detected entities.""" 144 144 path = detected_entities_path("personal", "20250101") 145 145 assert str(path).endswith( 146 - "fixtures/journal/facets/personal/entities/20250101.jsonl" 146 + "tests/fixtures/journal/facets/personal/entities/20250101.jsonl" 147 147 ) 148 148 assert path.name == "20250101.jsonl" 149 149
+3 -3
tests/test_entity_agents.py
··· 12 12 13 13 @pytest.fixture 14 14 def fixture_journal(): 15 - """Set JOURNAL_PATH to fixtures/journal for testing.""" 16 - os.environ["JOURNAL_PATH"] = "fixtures/journal" 15 + """Set JOURNAL_PATH to tests/fixtures/journal for testing.""" 16 + os.environ["JOURNAL_PATH"] = "tests/fixtures/journal" 17 17 yield 18 18 # No cleanup needed - just testing reads 19 19 ··· 94 94 assert "`test-facet`" in extra_context or "`full-featured`" in extra_context 95 95 96 96 # Should include entities from fixture facets 97 - # fixtures/journal/facets/ contains various entities 97 + # tests/fixtures/journal/facets/ contains various entities 98 98 assert "Entities" in extra_context 99 99 100 100 # Check for some known entities from the fixtures
+2 -2
tests/test_facets.py
··· 18 18 get_facets, 19 19 ) 20 20 21 - # Use the permanent fixtures in fixtures/journal/facets/ 22 - FIXTURES_PATH = Path(__file__).parent.parent / "fixtures" / "journal" 21 + # Use the permanent fixtures in tests/fixtures/journal/facets/ 22 + FIXTURES_PATH = Path(__file__).parent / "fixtures" / "journal" 23 23 24 24 25 25 def setup_entities_new_structure(
+1 -1
tests/test_formatters.py
··· 10 10 import pytest 11 11 12 12 # Set JOURNAL_PATH to fixtures for tests 13 - os.environ["JOURNAL_PATH"] = str(Path(__file__).parent.parent / "fixtures" / "journal") 13 + os.environ["JOURNAL_PATH"] = str(Path(__file__).parent / "fixtures" / "journal") 14 14 15 15 16 16 class TestRegistry:
+1 -1
tests/test_generate_full.py
··· 18 18 19 19 from think.utils import day_path 20 20 21 - FIXTURES = Path("fixtures") 21 + FIXTURES = Path("tests/fixtures") 22 22 23 23 24 24 def copy_day(tmp_path: Path) -> Path:
+1 -1
tests/test_generate_scan_day.py
··· 8 8 9 9 from think.utils import day_path 10 10 11 - FIXTURES = Path("fixtures") 11 + FIXTURES = Path("tests/fixtures") 12 12 13 13 14 14 def copy_day(tmp_path: Path) -> Path:
+3 -3
tests/test_journal_index.py
··· 418 418 from think.tools.search import search_journal 419 419 420 420 # Use fixtures journal 421 - os.environ["JOURNAL_PATH"] = "fixtures/journal" 421 + os.environ["JOURNAL_PATH"] = "tests/fixtures/journal" 422 422 423 423 result = search_journal("test") 424 424 ··· 439 439 """Test search tool returns query echo.""" 440 440 from think.tools.search import search_journal 441 441 442 - os.environ["JOURNAL_PATH"] = "fixtures/journal" 442 + os.environ["JOURNAL_PATH"] = "tests/fixtures/journal" 443 443 444 444 result = search_journal("test query", facet="work", topic="audio") 445 445 ··· 453 453 """Test search tool results include path and idx.""" 454 454 from think.tools.search import search_journal 455 455 456 - os.environ["JOURNAL_PATH"] = "fixtures/journal" 456 + os.environ["JOURNAL_PATH"] = "tests/fixtures/journal" 457 457 458 458 result = search_journal("") 459 459
+1 -1
tests/test_models.py
··· 126 126 @pytest.fixture 127 127 def use_fixtures_journal(monkeypatch): 128 128 """Use the fixtures journal for provider config tests.""" 129 - monkeypatch.setenv("JOURNAL_PATH", "fixtures/journal") 129 + monkeypatch.setenv("JOURNAL_PATH", "tests/fixtures/journal") 130 130 131 131 132 132 def test_resolve_provider_default(use_fixtures_journal):
+1 -1
tests/test_output_hooks.py
··· 19 19 from think.muse import load_post_hook, load_pre_hook 20 20 from think.utils import day_path 21 21 22 - FIXTURES = Path("fixtures") 22 + FIXTURES = Path("tests/fixtures") 23 23 24 24 25 25 def copy_day(tmp_path: Path) -> Path:
+2 -2
tests/test_transcribe_revai.py
··· 249 249 assert statements[0]["text"] == "Real" 250 250 251 251 def test_fixture_data(self): 252 - """Test with actual fixture data from fixtures/revai.json.""" 252 + """Test with actual fixture data from tests/fixtures/revai.json.""" 253 253 from pathlib import Path 254 254 255 - fixture_path = Path(__file__).parent.parent / "fixtures" / "revai.json" 255 + fixture_path = Path(__file__).parent / "fixtures" / "revai.json" 256 256 if not fixture_path.exists(): 257 257 pytest.skip("Fixture file not found") 258 258
+1 -2
think/providers/openai.py
··· 37 37 from typing import Any, Callable 38 38 39 39 from think.models import GPT_5 40 - from think.utils import now_ms 41 - 42 40 from think.providers.cli import ( 43 41 CLIRunner, 44 42 ThinkingAggregator, 45 43 assemble_prompt, 46 44 ) 45 + from think.utils import now_ms 47 46 48 47 from .shared import ( 49 48 GenerateResult,