Repository navigation
Installer and init: no default model, a model check, and next steps (Lane A) - #4
Merged
Merged
Conversation
hindsight.model_probe(settings, timeout=60) builds Hindsight's LLMProvider in this process, like document_compiler, and sends one tiny request through retain's strict structured-output path, then a reflect-style named tool call that only warns. Failures become a stable cause (key rejected, model not found, no structured output, rate limited, endpoint unreachable) with a sentence and a fix command; provider text is never returned, printed or logged. A 429 is retried once, and the provider SDK imports and Hindsight's config load happen before the timeout starts.
- A terminal gets a provider menu with nothing preselected (Anthropic, OpenAI, Gemini, OpenRouter, a local model server, another OpenAI-compatible endpoint); Enter asks again. Anthropic suggests claude-sonnet-5, the local choice suggests http://127.0.0.1:11434/v1, the others link to the model list. - Without a terminal, init needs an explicit provider and model and stops with provider_required or model_required naming LIFECONTEXT_PROVIDER and LIFECONTEXT_MODEL. The DEFAULT_PROVIDER fallback is gone. - init and llm set refuse claude-sonnet-5-5, claude-opus-5-5, claude-fable-5-1 and claude-mythos-5-1 with provider anthropic and say why; behind openai_compatible they only warn. A config that already names one is kept, and doctor warns. - init creates Journal/Inbox (0700) and reports two lists: next_steps for people and setup_steps for a source install. - Interactive init runs the model probe and reports model_probe; preflight --model-probe runs only the probe (exit 0 or 3), and doctor --model-probe adds it to the diagnostics.
- The endpoint questions become the same provider menu as lifecontext init, with nothing preselected; the CLIProxyAPI sentence, the 8317 default, the 'default: 1.2.0' text and the --help defaults are gone. Anthropic refuses the four Claude models that refuse forced tool choice. - After configure, also on a re-run that keeps the config, the installer runs lifecontext preflight --model-probe, prints the cause and the command that fixes it, carries on with the service, skills and doctor, and exits 3 at the end. --skip-model-probe or LIFECONTEXT_SKIP_MODEL_PROBE=1 skip it. - The interactive installer asks whether to turn notes in Journal/Inbox into journal entries and then installs the service with --capture; unattended runs do so with LIFECONTEXT_CAPTURE=1, and a re-run keeps an installed capture timer. - The installer ends with init's three next steps for people. - tests: the wheel name comes from LIFECONTEXT_RELEASE; the prompt tests follow the menu; the menu, refused models and model-list links are checked against lifecontext init.
With no default model, running init on the first start without LIFECONTEXT_PROVIDER and LIFECONTEXT_MODEL would fail and, under restart: unless-stopped, loop. The entrypoint now names the missing variable, says how to set it up, and waits for ~/.lifeweave/config.yaml (docker stop ends the wait). The compose.yaml example sets LIFECONTEXT_PROVIDER=anthropic next to the model.
From review: - Both checks share one deadline; the reflect check is skipped when less than five seconds are left, so the probe takes at most a minute after the SDK imports. - Any OSError and aiohttp connection error count as unreachable, so a google-genai DNS failure or disconnect is no longer reported as failed. - A 429 whose retry runs out of time stays rate_limited. - A 400 or 404 that names an unsupported structured-output feature (OpenRouter answers with 404; Gemini says JSON mode or function calling) is structured_output_unsupported, not model_not_found. - For a provider's own endpoint the unreachable fix suggests the network, not --base-url. - Gemini gets retain's output cap, since its thinking tokens count toward it.
- init and install.sh: a menu choice decides the base URL, so a LIFECONTEXT_BASE_URL left in the environment no longer attaches a URL to Anthropic, OpenAI, Gemini or OpenRouter; for choices 5 and 6 it is only the suggestion. - provider_required and model_required name both variables and both flags; llm set says to add --model. Interactive init asks again for a refused model, saying why. The refusal now says what is true for Anthropic: strict structured output there is a forced tool call. - Docker: after the wait, a mounted key secret is stored, and without one the entrypoint also waits for init to store the key. An init failure (for example a refused model) shows init's message and waits instead of exiting into a restart loop. - install.sh: the ending and the service command are functions, with tests for exit codes, output order, the re-run init and keeping capture.
Member
Author
|
@codex review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: be0fff3376
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
…t one With provider and model set but no key secret, or an empty key file, init succeeded with no key, serve failed on missing credentials, and every restart did the same: the restart loop the wait was meant to remove. Before serve, on every start, the entrypoint now checks that a key is stored (or that the endpoint needs none), says why not, and waits. A key file that gets content meanwhile is stored as soon as it does. An empty key file counts as no key; a keyless loopback openai_compatible endpoint still serves at once.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Lane A of the v1.2.0 P0 plan (
plan/RELEASE_1_2_0_P0.md, "Lane A", items 1 to 7): the installer andinitno longer default to a model, the first run proves the model works, and the installer ends with three next steps.What changed
1. Provider menu with no preselection (
install.shchoose_provider,initialize.provider_menu). Both show exactly:Enter without a choice asks again (three tries). Choice 1 suggests
claude-sonnet-5("claude-haiku-5-5 costs less"); 2 to 4 link to the provider's model list; 5 suggestshttp://127.0.0.1:11434/v1; 6 asks for the API root. The CLIProxyAPI sentence, the 8317 default, "default: 1.2.0" and the--helpdefaults are gone;grep -rn "8317\|CLIProxyAPI" install.sh src/ docker/finds nothing. A test compares the two menus.2. Unattended runs need explicit choices.
init --non-interactivewithout a provider or model stops withprovider_required/model_required. The JSON error now carries amessagenaming both variables and both flags.DEFAULT_PROVIDERis gone.--forceandllm setstill keep the provider and model already inconfig.yaml. A menu choice decides the base URL, so a leftoverLIFECONTEXT_BASE_URLcan't attach a URL to Anthropic, OpenAI, Gemini or OpenRouter.The Docker entrypoint logs which variable is missing and waits instead of exiting into a restart loop. It waits for
~/.lifeweave/config.yaml, then for a key (a mounted secret is stored after the wait), anddocker stopends the wait. Aninitfailure such as a refused model showsinit's message and waits the same way. Thecompose.yamlexample setsLIFECONTEXT_PROVIDER=anthropic.3. Four Claude models refused with
anthropic. These areclaude-sonnet-5-5,claude-opus-5-5,claude-fable-5-1andclaude-mythos-5-1.init,llm setand the installer's model prompt refuse them withmodel_unsupported; interactive prompts ask again and say why. Behindopenai_compatiblethey only warn. An existing config that names one is kept, anddoctorwarns (model_rejects_forced_tool_use).The message differs from the plan's on purpose. The plan says "retain uses strict structured output and reflect forces a named tool". But Hindsight 0.9.2's Anthropic adapter sends no
tool_choiceon tool calls (anthropic_llm.py:507-512), so on Anthropic only retain forces a tool. The message now reads: "… its retain step uses strict structured output, which on Anthropic is a forced tool call, and these models refuse a forced tool choice. Use claude-sonnet-5 or claude-haiku-5-5 (it costs less)." I sent the same correction to Lane B, whose docs quote the plan's sentence.4. Model probe.
hindsight.model_probe(settings, timeout=60)sits next todocument_compiler(). It buildsLLMProviderin-process and callscall(response_format=<tiny model>, strict_schema=True, max_completion_tokens=1024, max_retries=0, skip_validation=True, scope="retain_extract_facts"). A reflect-stylecall_with_tools(tool_choice=LLMToolChoice.named(...))check follows and only warns.key_rejected,model_not_found,structured_output_unsupported,rate_limited(after one retry),unreachable, pluskey_missing,invalid_configandfailed. Each comes with a sentence and a fix command.structured_output_unsupported(OpenRouter answers with 404). AnyOSErroror aiohttp connection error counts asunreachable, which covers google-genai.hindsight_api,openai,anthropic,httpxandgoogle_genailoggers are silenced during the probe.run_init(). Interactiveinitreportsmodel_probeas its own field.lifecontext preflight --model-proberuns only the probe, without the engine: it prints{"model_probe": …}and exits 0 or 3.doctor --model-probeadds it to the diagnostics (model_probe_failedis a problem).configure, also on a re-run, prints the cause and the fix, carries on, and exits 3 at the end.--skip-model-probeorLIFECONTEXT_SKIP_MODEL_PROBE=1skip it. Docker never probes.5.
Journal/Inbox.initcreates it (0700). The interactive installer asks "Turn notes you put in Journal/Inbox into journal entries automatically? [Y/n]" and installs the service with--captureon yes. Unattended runs do so only withLIFECONTEXT_CAPTURE=1. A re-run does not ask, and passes--capturewhen the capture timer or agent is already installed.6. Two lists from
init.next_stepsis for people;setup_stepsis the old operational list, for source installs. The installer prints onlynext_steps, at the very end. A re-run now also runsinit --non-interactiveagainst the kept config: it changes no settings, createsJournal/Inboxfor upgraded installs, and names the steps.7. Tests. The wheel name comes from
LIFECONTEXT_RELEASE. The pseudo-terminal prompt tests follow the menu. Newtest_model_probe.pyruns a fake OpenAI-compatible and Anthropic endpoint on loopback, covers one case per cause, and checks that no provider text or key reaches the result, stdout, stderr or log records. Newtest_docker_entrypoint.pycovers the waiting path.Strings other lanes depend on
qualify.ymlcase. The installer exits 3 and its last lines are:Findings worth knowing
tool_choiceoncall_with_tools. So withanthropic, only retain's strict path actually forces a tool, and the reflect check is a plain tool call. The OpenAI-compatible adapter turns a named choice into"required"with only that tool. This is why the refusal text changed (item 3).LLMProviderimports every provider SDK, and the first call loads Hindsight's server config, which imports torch. The probe does both before its 60-second clock starts. On the dev host this costs about 90 s the first time; on CI runners it costs a few seconds.Review and testing
Review. An independent review found no blockers and no leaks: provider text and keys reach no output, log or JSON. Its two major findings were both about the probe: each check had its own 60 s, and google-genai network errors came back as
failed. Its minor findings covered:tool_choice;LIFECONTEXT_BASE_URL;initfailures;All of them are fixed in the last two commits. I kept one nit: the failure output ends with "Then check it again with: lifecontext preflight --model-probe" after the fix line. Lane D confirmed its check expects exactly that.
The review also found gaps in the tests. These now have tests:
init;--captureon a re-run;inithandler;Tests. On the dev host I ran targeted modules only; CI runs the full suite on this branch. All pass:
test_init+test_llmtest_doctor+test_backup+test_cli_preflighttest_install_scripttest_model_probetest_docker_entrypointRuff 0.16.10 reports no new findings compared with
9bfb70d; the ruff job is non-blocking and fails onmaintoo. CI was green on23700e8, before the review fixes.Not covered here: the two
qualify.ymlinstaller cases (Lane D adds them) and a real clean install (that runs inqualify.yml, never on the dev host).CHANGELOG entry (for Lane D to add)