Support :ai off to disconnect and :ai to reconnect the agent (#167) - #180
Conversation
Ctrl+A only toggles panel visibility — there was no in-session way to actually turn the runtime off short of editing config.yaml and restarting. - :ai off releases the live provider (background aclose via the same close-task machinery the :ai rebuild uses), empties the wiring's provider box so teardown/rebuild never touch the dead provider, sets the runtime to None (status bar flips to 'AI off'), disables prompt submission, and shows a reconnect hint — the transcript stays. - Session-only: agent.enabled and persisted settings are untouched, so bare :ai reopens the wizard with the current settings and _apply_agent_settings reconnects (input re-enabled, 'AI on'). - Refused while a turn runs (never cancels midway); idempotent when already off. - New KorvidApp ctor param disconnect_agent, wired from _build_agent_wiring's new _make_disconnect_agent closure. Closes #167 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
APPROVE — 이슈 #167 :ai off 세션 단위 연결 해제, 깔끔한 구현입니다.
확인한 사항:
_make_disconnect_agent: provider box를 먼저 비운 뒤 백그라운드aclose— teardown 가드나 이후 rebuild가 죽은 provider를 만질 수 없고, 이미 off일 때 멱등. 기존_close_provider_in_background/close_tasks 기계를 재사용해 reap 경로도 동일합니다._handle_agent_off의 busy-turn 거부(_agent_taskdone 검사)가 interrupt-and-submit 드레인과 안전하게 맞물립니다:_agent_replacement는 task가 살아있는(취소 중 포함) 동안에만 존재하고 그동안:ai off는 거부되므로, off 이후 드레인 콜백이 죽은 runtime으로_start_agent_turn을 호출해 패널을 영구 running 상태로 만드는 경로가 구조적으로 없습니다 (head에서_drain_agent_replacement/action_interrupt_agent직접 확인).- 영속 설정 무변경 · transcript 보존 ·
Ctrl+A순수 가시성 토글 유지 모두 실질 테스트로 고정 (assert not runtime.calls,closed == [True]등 비공허). - 재연결 경로:
_apply_agent_settings가agent_input.disabled = False로 hint가 걸어둔 비활성화를 항상 해제하는 것 확인. 위저드를 열었다 취소하면 입력이 계속 비활성인데, 여전히 off 상태이므로 올바른 동작입니다.
Suggestions (advisory):
_handle_agent_off의 멱등 검사self._agent_runtime is None은 "한 번도 설정 안 된" 상태와 "off한" 상태를 구분하지 않아, 미설정 상태에서:ai off를 치면 setup 안내 대신 "Agent is already off"가 나옵니다._agent_configurator/설정 존재 여부로 분기해:ai안내를 주면 약간 더 친절합니다.show_setup_hint와show_reconnect_hint가 같은 disable+hint 패턴을 반복하므로, 셋째 상태가 생기면 공통 helper로 뽑을 만합니다.
APPROVE
There was a problem hiding this comment.
Pull request overview
Adds session-only agent disconnection through :ai off, while preserving configuration for reconnection.
Changes:
- Adds runtime disconnect handling and provider cleanup.
- Updates agent panel status, input state, and reconnect messaging.
- Adds documentation and UI/wiring tests.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
src/korvid/__main__.py |
Wires provider disconnection and cleanup. |
src/korvid/ui/app.py |
Handles :ai off and runtime state. |
src/korvid/ui/widgets/agent_panel.py |
Adds the disconnected-state hint. |
tests/test_main_wiring.py |
Tests provider release wiring. |
tests/ui/test_agent_off.py |
Tests disconnect and reconnect behavior. |
docs/agent.md |
Documents runtime and visibility controls. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
…erves transcript after :ai off - AgentSetupScreen takes current_settings: the provider option is pre-highlighted, the endpoint/API-key-env inputs and model default start from the kept values when the same provider is chosen — reconnecting is confirm-through, not re-entry. - action_toggle_agent distinguishes disconnected-from-configured (_agent_disconnected, set by :ai off, cleared on reconnect) from never-configured: reopening the panel shows the reconnect hint and keeps the conversation instead of the setup wipe. The hint is idempotent across repeated toggles. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 7 out of 7 changed files in this pull request and generated no new comments.
Suppressed comments (2)
src/korvid/ui/widgets/agent_setup_screen.py:133
- The retained Azure authentication method is not restored. Even when
current_settings.auth_method == "entra", selecting the pre-highlighted Azure provider resets the auth list to index 0 (api_key), so confirming through changes the auth flow and asks for an API-key variable instead of reconnecting with Entra. Pre-highlight the auth choice from the matching current settings when the Azure auth step opens, and cover the Azure/Entra reconnect path.
if self._current_settings is not None:
providers = list(_DEFAULTS)
if self._current_settings.provider in providers:
provider_list.highlighted = providers.index(self._current_settings.provider)
src/korvid/ui/widgets/agent_setup_screen.py:133
- This exact membership check loses valid configured providers supported by
providers/registry.py:23-32and documented indocs/agent.md:130-152(for examplegithub,anthropic,vllm,openai, or differently cased names). Those runtimes can be active before:ai off, but bare:aithen leaves the wizard on the first GitHub Copilot option; the later exact provider checks also fail to prefill endpoint/model/credentials. Normalize registry aliases to the wizard's canonical provider before highlighting and comparing retained settings.
This issue also appears on line 130 of the same file.
if self._current_settings is not None:
providers = list(_DEFAULTS)
if self._current_settings.provider in providers:
provider_list.highlighted = providers.index(self._current_settings.provider)
… alias normalization - The Azure auth step pre-highlights the retained method: a confirm-through reconnect keeps Entra instead of silently switching to api_key. - Registry provider aliases (openai, vllm, github, anthropic, claude) normalize onto the wizard's openai-compat entry, so settings configured under an alias still pre-highlight the provider and prefill endpoint/key-env/model. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated no new comments.
Suppressed comments (1)
src/korvid/ui/widgets/agent_setup_screen.py:196
- Auth retention is limited to Azure/Entra. OpenAI-compatible providers validly support
auth_method="none"(for example, a local vLLM endpoint; seeproviders/registry.py:125-140), but confirming the preselected provider resets it toapi_key, prompts for a nonexistent key env, and prevents reconnecting. Preserve the retained auth method whenever the canonical provider matches.
if (
self._current_canonical == "azure"
and current is not None
and current.auth_method == "entra"
):
There was a problem hiding this comment.
재리뷰 (신규 커밋 2건) — 이전 리뷰의 Suggestion 두 건을 정확히 반영했습니다.
-
_agent_disconnected플래그로 never-configured와 :ai off 상태를 분리:action_toggle_agent가 off 상태에서 reconnect hint를 보여 setup wipe로 대화가 지워지던 경로가 사라졌고,show_reconnect_hint가 마지막 ChatEntry의 raw 비교로 멱등이라 토글 반복 시 힌트가 쌓이지 않습니다._apply_agent_settings에서 플래그 해제도 확인. Ctrl+A 토글 왕복 + 힌트 1회 카운트 테스트가 실질적입니다. -
위저드 prefill:
current_settings주입으로 provider 사전 하이라이트, 같은 provider일 때 endpoint/api_key_env/model이 기본값 대신 보존값에서 시작 — confirm-through reconnect가 됩니다. Azure Entra 사전 하이라이트로 조용한 api_key 전환도 차단, registry alias(openai/vllm/github/anthropic/claude)→openai-compat 정규화도 테스트로 고정.
Suggestions (advisory):
_OPENAI_COMPAT_ALIASES는 providers/registry.py의 alias 목록과 수동 동기화됩니다. registry에 alias가 추가되면 여기서 조용히 빠져 prefill이 무시됩니다. registry에서 alias 집합을 import하거나 drift 계약 테스트를 권장.- Azure auth 사전 하이라이트의
auth_list.highlighted = 1은 옵션 순서(api_key=0, entra=1) 하드코딩입니다. 테스트가 prompt 문자열로 고정하고 있어 당장은 안전하지만, 옵션 목록에서 index를 조회하는 편이 견고합니다.
APPROVE
… matching provider A no-auth OpenAI-compatible endpoint (local vLLM) was reset to api_key on confirm-through and prompted for a nonexistent key env. The retained auth method now survives whenever the canonical provider matches. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
재리뷰 (신규 커밋 1건) — confirm-through 재연결 시 유지된 auth_method 보존 수정 확인.
- 로컬 vLLM 같은 no-auth OpenAI 호환 엔드포인트가 provider 기본값
api_key로 리셋되어 존재하지 않는 key env를 묻던 문제를, 기존 base_url/model prefill과 동일한 가드 패턴(current is not None and self._current_canonical == self._provider and current.auth_method)으로 해결 — canonical 일치 조건 덕분에 다른 provider로 갈아탈 때 이전 auth가 새 provider에 새는 일이 없습니다. - azure 분기는 기존 entra pre-highlight 경로가 별도로 유지되어 이번 가드와 충돌 없음.
- 테스트
test_reconnect_preserves_a_no_auth_method는_auth_method == "none"과 key-env 입력 미표시를 모두 단언해 비공허합니다.
지적사항 없음. APPROVE
Closes #167
Once configured, the agent runtime stayed
AI onfor the process lifetime:Ctrl+Aonly hides the chat panel, and actually turning the agent off required editing~/.config/korvid/config.yamland restarting.What changed
:ai offdisconnects the runtime for the current session:aclosethrough the same close-task machinery the:airebuild uses), and the wiring's provider box is emptied so teardown and a later rebuild never touch the dead provider (_make_disconnect_agentin the composition root, handed to the app as a newdisconnect_agentctor param).AI offimmediately; prompt submission is disabled; a dimagent off — run :ai to reconnecthint is appended — the conversation transcript is never erased.agent.enabledand all persisted settings (provider, model, profile, credentials) are untouched.Ctrl+X's job, not a state command's); idempotent when already off.Bare
:aiafter:ai offopens the setup wizard with the kept settings; applying them rebuilds the runtime — status returns toAI on, the input re-enables and refocuses.Ctrl+Aremains a pure visibility toggle.Tests
tests/ui/test_agent_off.py(7): disconnect + status flip + provider release, input disabled + hint, transcript preserved, idempotent when off, busy-turn refusal, reconnect restoresAI on/input, Ctrl+A never touches runtime state.tests/test_main_wiring.py::test_disconnect_agent_releases_the_provider: the closure empties the box and closes the provider in the background; idempotent.Docs:
docs/agent.mdgains "Turning the agent off and on" distinguishingCtrl+A(visibility) from:ai off(runtime state).Full gate green: ruff, mypy --strict, 3098 passed, tach.