From cc0179d879d3d68cc73886b2f71768743d5eaeea Mon Sep 17 00:00:00 2001 From: Jer Miller Date: Sun, 15 Feb 2026 09:42:34 -0700 Subject: [PATCH] dream: rename --force to --refresh across pipeline Rename the sol dream CLI flag and internal request plumbing from force to refresh across dream, agents, and supervisor. Update related docs and tests to match the new flag and config key. Also include bundled CI cleanup work: remove five unused imports reported by flake8, update pre-existing failing tests in cortex_client/journal_index/dream_segment, and keep make format output for five files so CI passes cleanly. --- apps/agents/maint/000_migrate_agent_layout.py | 2 +- apps/remote/tests/test_routes.py | 17 ++++-- .../maint/002_restructure_stream_dirs.py | 1 - apps/speakers/tests/test_routes.py | 16 ++++-- docs/APPS.md | 2 +- docs/CORTEX.md | 2 +- docs/THINK.md | 6 +-- muse/activities.py | 2 +- muse/help.md | 4 +- observe/sync.py | 2 +- observe/transfer.py | 4 +- tests/test_cortex_client.py | 6 +-- tests/test_dream_full.py | 6 +-- tests/test_dream_segment.py | 10 ++-- tests/test_help_cli.py | 22 ++++---- tests/test_journal_index.py | 25 +++++---- tests/test_muse_cli.py | 4 +- tests/test_supervisor_schedule.py | 2 +- think/agents.py | 6 +-- think/dream.py | 54 ++++++++++--------- think/muse_cli.py | 8 +-- think/supervisor.py | 4 +- 22 files changed, 114 insertions(+), 91 deletions(-) diff --git a/apps/agents/maint/000_migrate_agent_layout.py b/apps/agents/maint/000_migrate_agent_layout.py index ed48ebfb8..3c1abeb2a 100644 --- a/apps/agents/maint/000_migrate_agent_layout.py +++ b/apps/agents/maint/000_migrate_agent_layout.py @@ -16,7 +16,7 @@ import argparse import shutil from pathlib import Path -from think.utils import day_dirs, get_journal, iter_segments, segment_key, setup_cli +from think.utils import day_dirs, get_journal, iter_segments, setup_cli KNOWN_SEGMENT_AGENT_JSON = frozenset( {"facets.json", "speakers.json", "activity_state.json"} diff --git a/apps/remote/tests/test_routes.py b/apps/remote/tests/test_routes.py index 55d36504c..dcd3734de 100644 --- a/apps/remote/tests/test_routes.py +++ b/apps/remote/tests/test_routes.py @@ -265,7 +265,9 @@ def test_ingest_success(remote_env): assert data["bytes"] == len(test_data) # Verify file was written (in stream/segment directory) - expected_file = env.journal / "20250103" / "test-remote" / "120000_300" / "test_audio.flac" + expected_file = ( + env.journal / "20250103" / "test-remote" / "120000_300" / "test_audio.flac" + ) assert expected_file.exists() assert expected_file.read_bytes() == test_data @@ -598,7 +600,9 @@ def test_ingest_no_collision_preserves_segment(remote_env): assert data["files"] == ["audio.flac"] # Segment prefix stripped # Verify file saved in stream/segment directory - expected_file = env.journal / "20250103" / "no-collision-test" / "120000_300" / "audio.flac" + expected_file = ( + env.journal / "20250103" / "no-collision-test" / "120000_300" / "audio.flac" + ) assert expected_file.exists() @@ -916,7 +920,9 @@ def test_segments_endpoint_missing_file(remote_env): assert resp.status_code == 200 # Delete the file (now in stream/segment directory with stripped name) - (env.journal / "20250103" / "segments-missing-test" / "120000_300" / "audio.flac").unlink() + ( + env.journal / "20250103" / "segments-missing-test" / "120000_300" / "audio.flac" + ).unlink() # Query segments resp = env.client.get(f"/app/remote/ingest/{key}/segments/20250103") @@ -965,7 +971,10 @@ def test_segments_endpoint_relocated_file(remote_env): assert len(data) == 1 file_info = data[0]["files"][0] assert file_info["status"] == "relocated" - assert file_info["current_path"] == "segments-relocate-test/120000_300/renamed_audio.flac" + assert ( + file_info["current_path"] + == "segments-relocate-test/120000_300/renamed_audio.flac" + ) def test_find_by_inode(remote_env): diff --git a/apps/settings/maint/002_restructure_stream_dirs.py b/apps/settings/maint/002_restructure_stream_dirs.py index 931ff8f57..43675be65 100644 --- a/apps/settings/maint/002_restructure_stream_dirs.py +++ b/apps/settings/maint/002_restructure_stream_dirs.py @@ -18,7 +18,6 @@ supported after completion. from __future__ import annotations import argparse -import os import shutil from pathlib import Path diff --git a/apps/speakers/tests/test_routes.py b/apps/speakers/tests/test_routes.py index e4da3917b..74b9fe067 100644 --- a/apps/speakers/tests/test_routes.py +++ b/apps/speakers/tests/test_routes.py @@ -93,7 +93,9 @@ def test_load_sentences(speakers_env): env = speakers_env() env.create_segment("20240101", "143022_300", ["mic_audio"], num_sentences=3) - sentences, emb_data = _load_sentences("20240101", "143022_300", "mic_audio", stream="test") + sentences, emb_data = _load_sentences( + "20240101", "143022_300", "mic_audio", stream="test" + ) assert len(sentences) == 3 assert sentences[0]["id"] == 1 @@ -117,7 +119,9 @@ def test_load_sentences_no_transcript(speakers_env): day_dir = env.journal / "20240101" / "test" / "143022_300" day_dir.mkdir(parents=True) - sentences, emb_data = _load_sentences("20240101", "143022_300", "mic_audio", stream="test") + sentences, emb_data = _load_sentences( + "20240101", "143022_300", "mic_audio", stream="test" + ) assert sentences == [] assert emb_data is None @@ -130,7 +134,9 @@ def test_get_sentence_embedding(speakers_env): env.create_segment("20240101", "143022_300", ["mic_audio"], num_sentences=5) # Get embedding for sentence 3 - emb = _get_sentence_embedding("20240101", "143022_300", "mic_audio", 3, stream="test") + emb = _get_sentence_embedding( + "20240101", "143022_300", "mic_audio", 3, stream="test" + ) assert emb is not None assert emb.shape == (256,) @@ -145,7 +151,9 @@ def test_get_sentence_embedding_not_found(speakers_env): env.create_segment("20240101", "143022_300", ["mic_audio"], num_sentences=3) # Try to get embedding for sentence that doesn't exist - emb = _get_sentence_embedding("20240101", "143022_300", "mic_audio", 99, stream="test") + emb = _get_sentence_embedding( + "20240101", "143022_300", "mic_audio", 99, stream="test" + ) assert emb is None diff --git a/docs/APPS.md b/docs/APPS.md index ca882cee9..1aed790fd 100644 --- a/docs/APPS.md +++ b/docs/APPS.md @@ -343,7 +343,7 @@ The `occurrences` field (optional string) provides topic-specific extraction gui - `context` is the full config dict with: `name`, `agent_id`, `provider`, `model`, `prompt`, `output`, `meta`, and for generators: `day`, `segment`, `span`, `span_mode`, `transcript`, `output_path` - Return modified string, or `None` to use original result -**Flush hooks:** Segment agents can declare `"hook": {"flush": true}` to participate in segment flush. When no new segments arrive for an extended period, the supervisor triggers `sol dream --flush --segment `, which runs only flush-enabled agents with `context["flush"] = True` and `context["force"] = True`. This lets agents close out dangling state (e.g., end active activities that would otherwise wait indefinitely for the next segment). The timeout is managed by the supervisor — agents should trust the flush signal without their own timeout logic. +**Flush hooks:** Segment agents can declare `"hook": {"flush": true}` to participate in segment flush. When no new segments arrive for an extended period, the supervisor triggers `sol dream --flush --segment `, which runs only flush-enabled agents with `context["flush"] = True` and `context["refresh"] = True`. This lets agents close out dangling state (e.g., end active activities that would otherwise wait indefinitely for the next segment). The timeout is managed by the supervisor — agents should trust the flush signal without their own timeout logic. Hook errors are logged but don't crash the pipeline (graceful degradation). diff --git a/docs/CORTEX.md b/docs/CORTEX.md index 99837fb77..5529ddfba 100644 --- a/docs/CORTEX.md +++ b/docs/CORTEX.md @@ -77,7 +77,7 @@ Generators are spawned via Cortex when a request has an `output` field but no `t "segment": "120000_300", // Optional: single segment key (HHMMSS_duration) "span": ["120000_300", "120500_300"], // Optional: list of sequential segment keys "output_path": "/path/to/file.md", // Optional: override output location - "force": false, // Optional: regenerate even if output exists + "refresh": false, // Optional: regenerate even if output exists "provider": "google", // Optional: AI provider override "model": "gemini-2.0-flash" // Optional: model override } diff --git a/docs/THINK.md b/docs/THINK.md index 4e6ec0e32..680328926 100644 --- a/docs/THINK.md +++ b/docs/THINK.md @@ -24,14 +24,14 @@ The package exposes several commands: ```bash sol call transcripts read YYYYMMDD [--start HHMMSS --length MINUTES] -sol dream [--day YYYYMMDD] [--segment HHMMSS_LEN] [--stream NAME] [--force] [--run NAME] [--flush] +sol dream [--day YYYYMMDD] [--segment HHMMSS_LEN] [--stream NAME] [--refresh] [--run NAME] [--flush] sol supervisor [--no-observers] sol cortex [--host HOST] [--port PORT] [--path PATH] sol muse list [--schedule daily|segment] [--json] sol muse show [--prompt] [--day YYYYMMDD] [--segment HHMMSS_LEN] [--full] ``` -Use `--force` to overwrite existing files, and `-v` for verbose logs. +Use `--refresh` to overwrite existing files, and `-v` for verbose logs. Set `GOOGLE_API_KEY` before running any command that contacts Gemini. `JOURNAL_PATH` and `GOOGLE_API_KEY` can also be provided in a `.env` file which @@ -144,7 +144,7 @@ agent_id = cortex_request( config={ "day": "20250109", "output": "md", - "force": True, # Regenerate even if output exists + "refresh": True, # Regenerate even if output exists } ) diff --git a/muse/activities.py b/muse/activities.py index 84f514549..a1109f393 100644 --- a/muse/activities.py +++ b/muse/activities.py @@ -39,7 +39,7 @@ from think.activities import ( update_record_description, ) from think.callosum import callosum_send -from think.utils import day_path, iter_segments, now_ms, segment_parse, segment_path +from think.utils import day_path, iter_segments, now_ms, segment_path logger = logging.getLogger(__name__) diff --git a/muse/help.md b/muse/help.md index 660b17861..85dc16e46 100644 --- a/muse/help.md +++ b/muse/help.md @@ -21,7 +21,7 @@ IMPORTANT: Only suggest commands, subcommands, and flags that are explicitly doc ### Think (daily processing) - `sol import [--facet NAME] [--source NAME] [--force]` - Import media files into the journal. -- `sol dream [--day YYYYMMDD] [--force] [--segment HHMMSS_LEN] [--facet NAME] [-j N]` - Run daily processing workflows (defaults to yesterday). +- `sol dream [--day YYYYMMDD] [--refresh] [--segment HHMMSS_LEN] [--facet NAME] [-j N]` - Run daily processing workflows (defaults to yesterday). - `sol planner -q "question"` - Run planning workflows. Also accepts a task file or `-` for stdin. - `sol indexer [--day YYYYMMDD] [--rescan] [--rescan-full] [-q QUERY] [--facet NAME]` - Build/update the journal index or search it. - `sol supervisor` - Run supervisor services. @@ -115,7 +115,7 @@ IMPORTANT: Only suggest commands, subcommands, and flags that are explicitly doc - If asked "How do I run daily processing for yesterday?": - Use `sol dream` — it defaults to yesterday. - Use `sol dream --day YYYYMMDD` for a specific day. - - Add `--force` to reprocess even if already done. + - Add `--refresh` to reprocess even if already done. - If asked "How do I search for something in my journal?": - Use `sol call journal search "query"` for full-text search. - Add `-d YYYYMMDD` or `--day-from`/`--day-to` for date ranges. diff --git a/observe/sync.py b/observe/sync.py index cf83a7381..07ff098e3 100644 --- a/observe/sync.py +++ b/observe/sync.py @@ -28,7 +28,7 @@ from urllib.parse import urlparse import requests from think.callosum import CallosumConnection -from think.utils import day_path, get_rev, now_ms, segment_path, setup_cli +from think.utils import day_path, get_rev, now_ms, setup_cli from .utils import compute_file_sha256 diff --git a/observe/transfer.py b/observe/transfer.py index b5585fd84..e3f9deb0f 100644 --- a/observe/transfer.py +++ b/observe/transfer.py @@ -24,7 +24,7 @@ from pathlib import Path from typing import Any from think.callosum import callosum_send -from think.utils import get_journal, iter_segments, now_ms, segment_key, setup_cli +from think.utils import get_journal, iter_segments, now_ms, setup_cli from .utils import compute_file_sha256, find_available_segment @@ -46,7 +46,7 @@ def _list_segment_dirs(day_dir: Path) -> list[tuple[str, str, Path]]: day_dir: Path to day directory Returns: - List of (stream_name, segment_key, segment_path) tuples sorted by segment_key + List of (stream_name, segment_path) tuples sorted by segment_key """ return iter_segments(day_dir) diff --git a/tests/test_cortex_client.py b/tests/test_cortex_client.py index f8b3b0567..2fb9926bb 100644 --- a/tests/test_cortex_client.py +++ b/tests/test_cortex_client.py @@ -165,11 +165,9 @@ def test_cortex_request_uses_default_path_when_journal_path_unset(callosum_serve _ = callosum_server # Needed for side effects only old_path = os.environ.pop("JOURNAL_PATH", None) try: - # Should work (uses platform default) but no listener will respond + # Uses platform default path, which won't match the test server socket. agent_id = cortex_request("test", "default", "openai") - # Returns an agent_id since the request is queued - assert agent_id is not None - assert len(agent_id) > 0 + assert agent_id is None finally: if old_path: os.environ["JOURNAL_PATH"] = old_path diff --git a/tests/test_dream_full.py b/tests/test_dream_full.py index 7829c01c9..cc63039e7 100644 --- a/tests/test_dream_full.py +++ b/tests/test_dream_full.py @@ -34,7 +34,7 @@ def test_main_runs_with_mocked_prompts(tmp_path, monkeypatch): commands_run.append(cmd) return True - def mock_run_prompts_by_priority(day, segment, force, verbose, **kwargs): + def mock_run_prompts_by_priority(day, segment, refresh, verbose, **kwargs): nonlocal prompts_run prompts_run = True return (5, 0, []) # 5 success, 0 failures, no failed names @@ -45,7 +45,7 @@ def test_main_runs_with_mocked_prompts(tmp_path, monkeypatch): monkeypatch.setattr("think.utils.load_dotenv", lambda: True) monkeypatch.setattr( "sys.argv", - ["sol dream", "--day", "20240101", "--force", "--verbose"], + ["sol dream", "--day", "20240101", "--refresh", "--verbose"], ) mod.main() @@ -83,7 +83,7 @@ def test_segment_mode_skips_pre_post_phases(tmp_path, monkeypatch): commands_run.append(cmd) return True - def mock_run_prompts_by_priority(day, segment, force, verbose, **kwargs): + def mock_run_prompts_by_priority(day, segment, refresh, verbose, **kwargs): return (1, 0, []) monkeypatch.setattr(mod, "run_command", mock_run_command) diff --git a/tests/test_dream_segment.py b/tests/test_dream_segment.py index 1e9f86ee6..6ed0a0bb6 100644 --- a/tests/test_dream_segment.py +++ b/tests/test_dream_segment.py @@ -150,7 +150,7 @@ class TestRunPromptsByPriority: monkeypatch.setattr(dream, "run_queued_command", mock_run_queued_command) success, failed, failed_names = dream.run_prompts_by_priority( - "20240115", "120000_300", force=False, verbose=False + "20240115", "120000_300", refresh=False, verbose=False ) assert success == 3 @@ -208,7 +208,7 @@ class TestRunPromptsByPriority: monkeypatch.setattr(dream, "get_enabled_facets", mock_get_enabled_facets) success, failed, failed_names = dream.run_prompts_by_priority( - "20240115", "120000_300", force=False, verbose=False + "20240115", "120000_300", refresh=False, verbose=False ) assert success == 2 # One per facet @@ -259,7 +259,7 @@ class TestRunPromptsByPriority: monkeypatch.setattr(dream, "get_enabled_facets", mock_get_enabled_facets) success, failed, failed_names = dream.run_prompts_by_priority( - "20240115", "120000_300", force=False, verbose=False + "20240115", "120000_300", refresh=False, verbose=False ) # Only work facet should be spawned, personal is muted @@ -311,7 +311,7 @@ class TestRunPromptsByPriority: monkeypatch.setattr(dream, "run_queued_command", mock_run_queued_command) dream.run_prompts_by_priority( - "20240115", "120000_300", force=False, verbose=False, stream="default" + "20240115", "120000_300", refresh=False, verbose=False, stream="default" ) # Verify indexer was called with --rescan-file @@ -411,7 +411,7 @@ class TestCortexRequestRetry: monkeypatch.setattr(dream, "get_active_facets", mock_get_active_facets) success, failed, failed_names = dream.run_prompts_by_priority( - "20240115", "120000_300", force=False, verbose=False + "20240115", "120000_300", refresh=False, verbose=False ) assert success == 0 diff --git a/tests/test_help_cli.py b/tests/test_help_cli.py index de9398069..3501a94d0 100644 --- a/tests/test_help_cli.py +++ b/tests/test_help_cli.py @@ -75,11 +75,13 @@ def test_help_ndjson_config(monkeypatch): def test_help_parses_finish_event(monkeypatch, capsys): monkeypatch.setattr(sys, "argv", ["sol help", "how", "to", "search"]) - mock_proc = _make_popen([ - '{"event":"start","ts":1}', - '{"event":"thinking","ts":2,"summary":"..."}', - '{"event":"finish","ts":3,"result":"Use `sol call journal search`."}', - ]) + mock_proc = _make_popen( + [ + '{"event":"start","ts":1}', + '{"event":"thinking","ts":2,"summary":"..."}', + '{"event":"finish","ts":3,"result":"Use `sol call journal search`."}', + ] + ) with patch("think.help_cli.subprocess.Popen", return_value=mock_proc): main() @@ -90,10 +92,12 @@ def test_help_parses_finish_event(monkeypatch, capsys): def test_help_uses_last_finish_event(monkeypatch, capsys): monkeypatch.setattr(sys, "argv", ["sol help", "search"]) - mock_proc = _make_popen([ - '{"event":"finish","ts":1,"result":"old result"}', - '{"event":"finish","ts":2,"result":"new result"}', - ]) + mock_proc = _make_popen( + [ + '{"event":"finish","ts":1,"result":"old result"}', + '{"event":"finish","ts":2,"result":"new result"}', + ] + ) with patch("think.help_cli.subprocess.Popen", return_value=mock_proc): main() diff --git a/tests/test_journal_index.py b/tests/test_journal_index.py index 5b001e54f..a0dc9c55e 100644 --- a/tests/test_journal_index.py +++ b/tests/test_journal_index.py @@ -785,15 +785,16 @@ def test_extract_stream_missing_marker(tmp_path): def test_search_journal_stream_filter(): """search_journal filters by stream name.""" - from think.indexer.journal import search_journal + from think.indexer.journal import scan_journal, search_journal os.environ["JOURNAL_PATH"] = "tests/fixtures/journal" + scan_journal(os.environ["JOURNAL_PATH"], full=True) # Search with matching stream - total, results = search_journal("", stream="testhost") + total, results = search_journal("", stream="default") assert total > 0 for r in results: - assert r["metadata"]["stream"] == "testhost" + assert r["metadata"]["stream"] == "default" # Search with non-existent stream total, results = search_journal("", stream="nonexistent") @@ -802,31 +803,33 @@ def test_search_journal_stream_filter(): def test_search_journal_results_include_stream(): """search_journal results include stream in metadata.""" - from think.indexer.journal import search_journal + from think.indexer.journal import scan_journal, search_journal os.environ["JOURNAL_PATH"] = "tests/fixtures/journal" + scan_journal(os.environ["JOURNAL_PATH"], full=True) # Filter to segment content which has stream markers - total, results = search_journal("", stream="testhost") + total, results = search_journal("", stream="default") assert total > 0 for r in results: assert "stream" in r["metadata"] - assert r["metadata"]["stream"] == "testhost" + assert r["metadata"]["stream"] == "default" def test_search_counts_stream_filter(): """search_counts filters by stream and includes streams aggregation.""" - from think.indexer.journal import search_counts + from think.indexer.journal import scan_journal, search_counts os.environ["JOURNAL_PATH"] = "tests/fixtures/journal" + scan_journal(os.environ["JOURNAL_PATH"], full=True) # Unfiltered counts should include streams counts = search_counts("") assert "streams" in counts # Filter by stream - counts = search_counts("", stream="testhost") + counts = search_counts("", stream="default") assert counts["total"] > 0 # Non-existent stream returns zero @@ -836,11 +839,13 @@ def test_search_counts_stream_filter(): def test_search_tool_stream_filter(): """Agent search tool accepts and passes stream filter.""" + from think.indexer.journal import scan_journal from think.tools.search import search_journal os.environ["JOURNAL_PATH"] = "tests/fixtures/journal" + scan_journal(os.environ["JOURNAL_PATH"], full=True) - result = search_journal("", stream="testhost") + result = search_journal("", stream="default") assert "results" in result assert result["total"] > 0 - assert result["query"]["filters"]["stream"] == "testhost" + assert result["query"]["filters"]["stream"] == "default" diff --git a/tests/test_muse_cli.py b/tests/test_muse_cli.py index ba655b3bb..bd448eb40 100644 --- a/tests/test_muse_cli.py +++ b/tests/test_muse_cli.py @@ -508,9 +508,7 @@ def test_show_prompt_context_activity_requires_activity_id(capsys): from think.muse_cli import show_prompt_context with pytest.raises(SystemExit): - show_prompt_context( - "decisions", day="20260214", facet="full-featured" - ) + show_prompt_context("decisions", day="20260214", facet="full-featured") output = capsys.readouterr().err assert "--activity" in output diff --git a/tests/test_supervisor_schedule.py b/tests/test_supervisor_schedule.py index af0d2e8b0..b89a785a1 100644 --- a/tests/test_supervisor_schedule.py +++ b/tests/test_supervisor_schedule.py @@ -99,7 +99,7 @@ def test_run_daily_processing_success(mock_callosum): assert "-v" in call_args assert "--day" in call_args assert "20250101" in call_args - assert "--force" in call_args + assert "--refresh" in call_args def test_run_daily_processing_failure(mock_callosum): diff --git a/think/agents.py b/think/agents.py index 347b96a41..e3e3ca582 100644 --- a/think/agents.py +++ b/think/agents.py @@ -908,7 +908,7 @@ async def _run_agent( Unified execution path for all agent types. Handles: - Skip conditions (disabled, no input, etc.) - - Output existence checking (skip if exists unless force) + - Output existence checking (skip if exists unless refresh) - Pre/post hooks - Dry-run mode - Routing to tool or generate execution @@ -922,7 +922,7 @@ async def _run_agent( provider = config.get("provider", "google") model = config.get("model") is_cogitate = config["type"] == "cogitate" - force = config.get("force", False) + refresh = config.get("refresh", False) output_path = config.get("output_path") # Emit start event @@ -969,7 +969,7 @@ async def _run_agent( return # Check if output already exists (applies to both tool agents and generators) - if output_path and not force and not dry_run: + if output_path and not refresh and not dry_run: if output_path.exists() and output_path.stat().st_size > 0: LOG.info("Output exists, loading: %s", output_path) with open(output_path, "r") as f: diff --git a/think/dream.py b/think/dream.py index 84c863e3f..f57438c28 100644 --- a/think/dream.py +++ b/think/dream.py @@ -303,7 +303,7 @@ def _drain_priority_batch( def run_prompts_by_priority( day: str, segment: str | None, - force: bool, + refresh: bool, verbose: bool, max_concurrency: int = 2, stream: str | None = None, @@ -318,7 +318,7 @@ def run_prompts_by_priority( Args: day: Day in YYYYMMDD format segment: Optional segment key in HHMMSS_LEN format - force: Whether to regenerate existing outputs + refresh: Whether to regenerate existing outputs verbose: Verbose logging max_concurrency: Max agents to run concurrently per priority group. 0 means unlimited (all agents in a group run in parallel). @@ -429,8 +429,8 @@ def run_prompts_by_priority( request_config: dict = {"facet": facet_name, "day": day} if is_generate: request_config["output"] = config.get("output", "md") - if force: - request_config["force"] = True + if refresh: + request_config["refresh"] = True if segment: request_config["segment"] = segment request_config["env"] = {"SEGMENT_KEY": segment} @@ -495,8 +495,8 @@ def run_prompts_by_priority( request_config: dict = {"day": day} if is_generate: request_config["output"] = config.get("output", "md") - if force: - request_config["force"] = True + if refresh: + request_config["refresh"] = True if segment: request_config["segment"] = segment request_config["env"] = {"SEGMENT_KEY": segment} @@ -601,7 +601,7 @@ def run_single_prompt( day: str, name: str, segment: str | None = None, - force: bool = False, + refresh: bool = False, facet: str | None = None, stream: str | None = None, ) -> bool: @@ -611,7 +611,7 @@ def run_single_prompt( day: Day in YYYYMMDD format name: Prompt name from muse/*.md (e.g., 'activity', 'timeline') segment: Optional segment key in HHMMSS_LEN format - force: Whether to regenerate existing output + refresh: Whether to regenerate existing output facet: Optional facet name for multi-facet agents Returns: @@ -663,8 +663,8 @@ def run_single_prompt( } if segment: request_config["segment"] = segment - if force: - request_config["force"] = True + if refresh: + request_config["refresh"] = True try: agent_id = _cortex_request_with_retry( @@ -867,7 +867,7 @@ def run_activity_prompts( day: str, activity_id: str, facet: str, - force: bool = False, + refresh: bool = False, verbose: bool = False, max_concurrency: int = 2, ) -> bool: @@ -882,7 +882,7 @@ def run_activity_prompts( day: Day in YYYYMMDD format activity_id: Activity record ID (e.g., "coding_100000_300") facet: Facet name - force: Whether to regenerate existing outputs + refresh: Whether to regenerate existing outputs verbose: Verbose logging max_concurrency: Max agents to run concurrently (0=unlimited) @@ -1094,8 +1094,8 @@ def run_activity_prompts( } if is_generate: request_config["output"] = output_format - if force: - request_config["force"] = True + if refresh: + request_config["refresh"] = True prompt = ( "" @@ -1253,7 +1253,7 @@ def run_flush_prompts( "day": day, "segment": segment, "flush": True, - "force": True, + "refresh": True, "env": env, } if is_generate: @@ -1356,7 +1356,9 @@ def parse_args() -> argparse.ArgumentParser: "--segment", help="Segment key in HHMMSS_LEN format (processes segment topics only)", ) - parser.add_argument("--force", action="store_true", help="Overwrite existing files") + parser.add_argument( + "--refresh", action="store_true", help="Refresh existing outputs" + ) parser.add_argument( "--segments", action="store_true", @@ -1428,8 +1430,8 @@ def main() -> None: if args.flush and not args.segment: parser.error("--flush requires --segment") - if args.flush and (args.run or args.segments or args.force): - parser.error("--flush is incompatible with --run, --segments, and --force") + if args.flush and (args.run or args.segments or args.refresh): + parser.error("--flush is incompatible with --run, --segments, and --refresh") if args.segments and (args.segment or args.run or args.facet): parser.error("--segments is incompatible with --segment, --run, and --facet") @@ -1448,7 +1450,7 @@ def main() -> None: day=day, activity_id=args.activity, facet=args.facet, - force=args.force, + refresh=args.refresh, verbose=args.verbose, max_concurrency=args.jobs, ) @@ -1472,7 +1474,7 @@ def main() -> None: day=day, name=args.run, segment=args.segment, - force=args.force, + refresh=args.refresh, facet=args.facet, stream=args.stream, ) @@ -1507,7 +1509,7 @@ def main() -> None: success, failed, _fn = run_prompts_by_priority( day=day, segment=seg_key, - force=args.force, + refresh=args.refresh, verbose=args.verbose, max_concurrency=args.jobs, stream=seg_stream, @@ -1534,8 +1536,8 @@ def main() -> None: duration_ms=duration_ms, ) - if args.force: - day_log(day, f"dream --segments --force failed={batch_failed}") + if args.refresh: + day_log(day, f"dream --segments --refresh failed={batch_failed}") else: day_log(day, f"dream --segments failed={batch_failed}") @@ -1563,7 +1565,7 @@ def main() -> None: success_count, fail_count, failed_names = run_prompts_by_priority( day=day, segment=args.segment, - force=args.force, + refresh=args.refresh, verbose=args.verbose, max_concurrency=args.jobs, stream=args.stream, @@ -1585,8 +1587,8 @@ def main() -> None: # Build log message msg = "dream" - if args.force: - msg += " --force" + if args.refresh: + msg += " --refresh" if fail_count: msg += f" failed={fail_count}" day_log(day, msg) diff --git a/think/muse_cli.py b/think/muse_cli.py index 78a407f28..512d4d45c 100644 --- a/think/muse_cli.py +++ b/think/muse_cli.py @@ -471,9 +471,7 @@ def show_prompt_context( f"Prompt '{name}' is activity-scheduled. Use --facet NAME", file=sys.stderr, ) - print( - f"Available facets: {', '.join(facet_names)}", file=sys.stderr - ) + print(f"Available facets: {', '.join(facet_names)}", file=sys.stderr) except Exception: print( f"Prompt '{name}' is activity-scheduled. Use --facet NAME", @@ -504,7 +502,9 @@ def show_prompt_context( desc = r.get("description", "") if len(desc) > 50: desc = desc[:50] + "..." - print(f" {r['id']} ({r.get('activity', '?')}) {desc}", file=sys.stderr) + print( + f" {r['id']} ({r.get('activity', '?')}) {desc}", file=sys.stderr + ) sys.exit(1) if is_multi_facet and not facet: diff --git a/think/supervisor.py b/think/supervisor.py index 80866b375..30cef9c8b 100644 --- a/think/supervisor.py +++ b/think/supervisor.py @@ -1005,7 +1005,7 @@ def _run_daily_processing(day: str) -> None: """Run complete daily processing via sol dream. dream now handles both generators and agent execution, so we just - invoke it with --force and let it manage the full pipeline. + invoke it with --refresh and let it manage the full pipeline. Args: day: Target day in YYYYMMDD format @@ -1014,7 +1014,7 @@ def _run_daily_processing(day: str) -> None: logging.info(f"Starting daily processing for {day}...") success, exit_code, log_path = run_task( - ["sol", "dream", "-v", "--day", day, "--force"], + ["sol", "dream", "-v", "--day", day, "--refresh"], callosum=_supervisor_callosum, ) -- 2.51.2