gemcode 0.3.109__tar.gz → 0.3.110__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {gemcode-0.3.109/src/gemcode.egg-info → gemcode-0.3.110}/PKG-INFO +1 -1
- {gemcode-0.3.109 → gemcode-0.3.110}/pyproject.toml +1 -1
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/kaira_daemon.py +55 -5
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/session_runtime.py +3 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tui/scrollback.py +56 -0
- {gemcode-0.3.109 → gemcode-0.3.110/src/gemcode.egg-info}/PKG-INFO +1 -1
- {gemcode-0.3.109 → gemcode-0.3.110}/LICENSE +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/MANIFEST.in +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/README.md +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/setup.cfg +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/__init__.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/__main__.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/agent.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/audit.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/autocompact.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/autotune.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/callbacks.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/capability_routing.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/checkpoints.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/cli.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/compaction.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/computer_use/__init__.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/computer_use/browser_computer.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/config.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/context_budget.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/context_warning.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/credentials.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/curated_memory.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/dynamic_policy.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/evals/harness.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/hitl_session.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/hooks.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/ide_protocol.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/ide_stdio.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/intent_classifier.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/interactions.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/invoke.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/kaira_client.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/kaira_ipc.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/kaira_job_store.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/learning.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/limits.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/live_audio_engine.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/logging_config.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/mcp_loader.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/memory/__init__.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/memory/embedding_memory_service.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/memory/file_memory_service.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/modality_tools.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/model_errors.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/model_routing.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/multimodal_input.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/openapi_loader.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/org.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/output_styles.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/paths.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/permissions.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/plugins/__init__.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/plugins/terminal_hooks_plugin.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/plugins/tool_recovery_plugin.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/policy_profile.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/pricing.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/prompt_suggestions.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/query/__init__.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/query/config.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/query/deps.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/query/engine.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/query/stop_hooks.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/query/token_budget.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/query/transitions.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/query_sanitizer.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/refine.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/repl_commands.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/repl_slash.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/review_agent.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/rules.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/session_store.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/session_summariser.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/skills.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/slash_commands.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/thinking.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tool_prompt_manifest.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tool_registry.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tool_result_store.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/__init__.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/bash.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/browser.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/compress_memory.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/curated_memory.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/edit.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/filesystem.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/notebook.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/notes.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/org_tools.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/repo_map.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/search.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/shell.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/shell_gate.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/skills.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/subtask.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/tasks.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/think.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/todo.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/user_choice.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/veomem_tools.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/web.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools/web_search.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tools_inspector.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/trust.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tui/input_handler.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tui/spinner.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tui/welcome_banner.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/tui/welcome_rich.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/veomem_bridge.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/version.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/vertex.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/wal.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/web/__init__.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/web/sse_adapter.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/web/terminal_repl.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/web/web_sse_compat.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode/workspace_hints.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode.egg-info/SOURCES.txt +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode.egg-info/dependency_links.txt +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode.egg-info/entry_points.txt +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode.egg-info/requires.txt +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/src/gemcode.egg-info/top_level.txt +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_add_dir.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_agent_instruction.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_autocompact.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_capability_routing.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_checkpoint_diff_command.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_cli_init.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_compress_memory_tool.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_computer_use_permissions.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_context_budget.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_context_warning.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_credentials.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_eval_harness_layout.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_ide_stdio_attachments.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_interactive_permission_ask.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_kaira_scheduler.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_modality_tools.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_model_error_retry.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_model_errors.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_model_routing.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_multimodal_input.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_output_styles_and_rules.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_paths.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_permissions.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_prompt_suggestions.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_repl_commands.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_repl_slash.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_session_runtime_cache.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_skills.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_slash_commands.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_slash_completion_registry.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_thinking_config.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_token_budget.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_tool_context_circulation.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_tools.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_tools_inspector.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_web_sse_adapter.py +0 -0
- {gemcode-0.3.109 → gemcode-0.3.110}/tests/test_workspace_hints.py +0 -0
|
@@ -94,6 +94,22 @@ def _fmt_tool_result(resp: object) -> str:
|
|
|
94
94
|
return ""
|
|
95
95
|
|
|
96
96
|
|
|
97
|
+
def _should_stream_to_terminal() -> bool:
|
|
98
|
+
"""Stream live job output to the local terminal when interactive."""
|
|
99
|
+
try:
|
|
100
|
+
return bool(hasattr(sys.stdin, "isatty") and sys.stdin.isatty())
|
|
101
|
+
except Exception:
|
|
102
|
+
return False
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def _stream_print(s: str) -> None:
|
|
106
|
+
try:
|
|
107
|
+
sys.stdout.write(s)
|
|
108
|
+
sys.stdout.flush()
|
|
109
|
+
except Exception:
|
|
110
|
+
pass
|
|
111
|
+
|
|
112
|
+
|
|
97
113
|
async def _broadcast_text_delta(
|
|
98
114
|
*,
|
|
99
115
|
ipc: KairaIpcServer,
|
|
@@ -402,6 +418,9 @@ class KairaDaemon:
|
|
|
402
418
|
async def _stream_one_message(*, current_message: types.Content) -> tuple[list, str]:
|
|
403
419
|
emitted_text = ""
|
|
404
420
|
events: list = []
|
|
421
|
+
stream_live = _should_stream_to_terminal()
|
|
422
|
+
if stream_live:
|
|
423
|
+
_stream_print(f"\n[kaira {job.job_id}] started\n")
|
|
405
424
|
async for ev in runner.run_async(
|
|
406
425
|
user_id=self.user_id,
|
|
407
426
|
session_id=job.session_id,
|
|
@@ -409,6 +428,28 @@ class KairaDaemon:
|
|
|
409
428
|
**({"run_config": run_config} if run_config is not None else {}),
|
|
410
429
|
):
|
|
411
430
|
events.append(ev)
|
|
431
|
+
# Live terminal streaming (independent of IPC).
|
|
432
|
+
if stream_live:
|
|
433
|
+
try:
|
|
434
|
+
from gemcode.web.sse_adapter import extract_text_from_event
|
|
435
|
+
|
|
436
|
+
txt_live = extract_text_from_event(ev)
|
|
437
|
+
if txt_live:
|
|
438
|
+
if txt_live.startswith(emitted_text):
|
|
439
|
+
delta_live = txt_live[len(emitted_text) :]
|
|
440
|
+
else:
|
|
441
|
+
# Fallback: find common prefix.
|
|
442
|
+
common = 0
|
|
443
|
+
max_common = min(len(txt_live), len(emitted_text))
|
|
444
|
+
while common < max_common and txt_live[common] == emitted_text[common]:
|
|
445
|
+
common += 1
|
|
446
|
+
delta_live = txt_live[common:]
|
|
447
|
+
if delta_live:
|
|
448
|
+
_stream_print(delta_live)
|
|
449
|
+
emitted_text = txt_live
|
|
450
|
+
except Exception:
|
|
451
|
+
pass
|
|
452
|
+
|
|
412
453
|
if self._ipc is None:
|
|
413
454
|
continue
|
|
414
455
|
|
|
@@ -460,7 +501,7 @@ class KairaDaemon:
|
|
|
460
501
|
except Exception:
|
|
461
502
|
pass
|
|
462
503
|
|
|
463
|
-
# Text deltas
|
|
504
|
+
# Text deltas (IPC subscribers)
|
|
464
505
|
try:
|
|
465
506
|
from gemcode.web.sse_adapter import extract_text_from_event
|
|
466
507
|
|
|
@@ -602,8 +643,12 @@ class KairaDaemon:
|
|
|
602
643
|
session_id=session_id,
|
|
603
644
|
)
|
|
604
645
|
|
|
605
|
-
async def run_forever(self, *, session_id: str) -> None:
|
|
606
|
-
"""Start the scheduler and keep running until
|
|
646
|
+
async def run_forever(self, *, session_id: str, enable_stdin: bool = True) -> None:
|
|
647
|
+
"""Start the scheduler and keep running until stopped.
|
|
648
|
+
|
|
649
|
+
When enable_stdin=False, Kaira runs headless (IPC-only) and does not read
|
|
650
|
+
from stdin. This mode is used when embedding Kaira inside the GemCode TUI.
|
|
651
|
+
"""
|
|
607
652
|
|
|
608
653
|
# Start IPC server for two-way control + event streaming.
|
|
609
654
|
try:
|
|
@@ -623,11 +668,16 @@ class KairaDaemon:
|
|
|
623
668
|
print(f"[kaira] ipc disabled: {e}", file=sys.stderr, flush=True)
|
|
624
669
|
|
|
625
670
|
scheduler_task = asyncio.create_task(self._scheduler_loop())
|
|
626
|
-
stdin_task =
|
|
671
|
+
stdin_task = None
|
|
672
|
+
if enable_stdin:
|
|
673
|
+
stdin_task = asyncio.create_task(self._stdin_loop(session_id=session_id))
|
|
627
674
|
|
|
628
675
|
# Wait for either scheduler to stop (shouldn't happen) or stdin loop to end.
|
|
676
|
+
wait_set = {scheduler_task}
|
|
677
|
+
if stdin_task is not None:
|
|
678
|
+
wait_set.add(stdin_task)
|
|
629
679
|
done, pending = await asyncio.wait(
|
|
630
|
-
|
|
680
|
+
wait_set,
|
|
631
681
|
return_when=asyncio.FIRST_COMPLETED,
|
|
632
682
|
)
|
|
633
683
|
for p in pending:
|
|
@@ -474,9 +474,12 @@ def create_runner(cfg: GemCodeConfig, extra_tools: list | None = None) -> Runner
|
|
|
474
474
|
import sys
|
|
475
475
|
|
|
476
476
|
prompt_afc = os.environ.get("GEMCODE_AFC_PROMPT", "1").strip().lower() in ("1", "true", "yes", "on")
|
|
477
|
+
afc_default = (os.environ.get("GEMCODE_AFC_DEFAULT") or "").strip().lower()
|
|
477
478
|
if prompt_afc and hasattr(sys.stdin, "isatty") and sys.stdin.isatty():
|
|
478
479
|
tools_list = list(merged_extra_tools or [])
|
|
479
480
|
noncallable = [t for t in tools_list if not callable(t)]
|
|
481
|
+
if noncallable and getattr(cfg, "_afc_choice", None) not in ("all", "callables") and afc_default in ("all", "callables"):
|
|
482
|
+
object.__setattr__(cfg, "_afc_choice", afc_default)
|
|
480
483
|
if noncallable and getattr(cfg, "_afc_choice", None) not in ("all", "callables"):
|
|
481
484
|
print(
|
|
482
485
|
"\n[gemcode] AFC compatibility\n"
|
|
@@ -279,6 +279,50 @@ async def run_gemcode_scrollback_tui(
|
|
|
279
279
|
get_cfg=lambda: cfg,
|
|
280
280
|
)
|
|
281
281
|
|
|
282
|
+
# ── Optional: embed Kaira daemon in this TUI ─────────────────────────────
|
|
283
|
+
# This enables continuous background automation without requiring a second
|
|
284
|
+
# terminal. The TUI will also auto-subscribe to IPC events (below) so job
|
|
285
|
+
# output appears inline.
|
|
286
|
+
_embedded_kaira_task: list = [None] # asyncio.Task | None
|
|
287
|
+
|
|
288
|
+
def _embed_kaira_enabled() -> bool:
|
|
289
|
+
return os.environ.get("GEMCODE_TUI_WITH_KAIRA", "0").strip().lower() in (
|
|
290
|
+
"1",
|
|
291
|
+
"true",
|
|
292
|
+
"yes",
|
|
293
|
+
"on",
|
|
294
|
+
)
|
|
295
|
+
|
|
296
|
+
async def _start_embedded_kaira() -> None:
|
|
297
|
+
if not _embed_kaira_enabled():
|
|
298
|
+
return
|
|
299
|
+
# Avoid starting if a socket already exists (external daemon running).
|
|
300
|
+
sock = os.environ.get("GEMCODE_KAIRA_SOCKET") or str(cfg.project_root / _KAIRA_SOCKET_DEFAULT)
|
|
301
|
+
try:
|
|
302
|
+
from pathlib import Path as _Path
|
|
303
|
+
|
|
304
|
+
if _Path(sock).exists():
|
|
305
|
+
return
|
|
306
|
+
except Exception:
|
|
307
|
+
pass
|
|
308
|
+
try:
|
|
309
|
+
from gemcode.kaira_daemon import KairaDaemon
|
|
310
|
+
|
|
311
|
+
# Use this TUI's session id as the default session for stdin-less jobs.
|
|
312
|
+
daemon = KairaDaemon(cfg=cfg, concurrency=2, default_priority=0)
|
|
313
|
+
# Run headless: IPC-only. Jobs are enqueued via IPC (monitor scripts, org tools, etc.).
|
|
314
|
+
await daemon.run_forever(session_id=session_id, enable_stdin=False)
|
|
315
|
+
except asyncio.CancelledError:
|
|
316
|
+
return
|
|
317
|
+
except Exception:
|
|
318
|
+
return
|
|
319
|
+
|
|
320
|
+
try:
|
|
321
|
+
if _embed_kaira_enabled():
|
|
322
|
+
_embedded_kaira_task[0] = asyncio.create_task(_start_embedded_kaira())
|
|
323
|
+
except Exception:
|
|
324
|
+
_embedded_kaira_task[0] = None
|
|
325
|
+
|
|
282
326
|
# ── Kaira auto-connect (IPC subscribe) ───────────────────────────────────
|
|
283
327
|
# If a Kaira daemon is running for this project, subscribe to its updates and
|
|
284
328
|
# surface them in the same terminal UI. Also handle permission requests by
|
|
@@ -765,6 +809,12 @@ async def run_gemcode_scrollback_tui(
|
|
|
765
809
|
t.cancel()
|
|
766
810
|
except Exception:
|
|
767
811
|
pass
|
|
812
|
+
try:
|
|
813
|
+
t2 = _embedded_kaira_task[0]
|
|
814
|
+
if t2 is not None:
|
|
815
|
+
t2.cancel()
|
|
816
|
+
except Exception:
|
|
817
|
+
pass
|
|
768
818
|
try:
|
|
769
819
|
from gemcode.hooks import run_session_stop_hook
|
|
770
820
|
run_session_stop_hook(cfg.project_root, model=getattr(cfg, "model", "") or "")
|
|
@@ -781,6 +831,12 @@ async def run_gemcode_scrollback_tui(
|
|
|
781
831
|
t.cancel()
|
|
782
832
|
except Exception:
|
|
783
833
|
pass
|
|
834
|
+
try:
|
|
835
|
+
t2 = _embedded_kaira_task[0]
|
|
836
|
+
if t2 is not None:
|
|
837
|
+
t2.cancel()
|
|
838
|
+
except Exception:
|
|
839
|
+
pass
|
|
784
840
|
from gemcode.hooks import run_session_stop_hook
|
|
785
841
|
run_session_stop_hook(cfg.project_root, model=getattr(cfg, "model", "") or "")
|
|
786
842
|
except Exception:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|