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, )