feat: deriver custom instructions#609
Conversation
WalkthroughRaises Deriver max input tokens to 25,000, adds a deployable cap for reasoning.custom_instructions (2,000 tokens default), and wires that setting end-to-end: configuration files, settings model, schema validation, prompt token estimation and prompt construction, plus tests and docs. ChangesDeriver: custom instructions and token limits
Sequence Diagram(s)sequenceDiagram
participant Message as Message\n(with ReasoningConfiguration)
participant Config as Config Resolver\n(get_configuration)
participant Schema as Schema Validator\n(ReasoningConfiguration)
participant Deriver as Deriver\n(deriver.py)
participant TokenEst as Token Estimator\n(estimate_deriver_prompt_tokens)
participant Prompt as Prompt Generator\n(minimal_deriver_prompt)
participant LLM as LLM Call
Message->>Config: provide message with custom_instructions
Config->>Schema: validate custom_instructions\nagainst deployment cap
Schema-->>Config: validation result
Config->>Deriver: resolved config (includes custom_instructions)
Deriver->>TokenEst: estimate_deriver_prompt_tokens(custom_instructions)
TokenEst-->>Deriver: token count
Deriver->>Prompt: minimal_deriver_prompt(..., custom_instructions)
Prompt-->>Deriver: formatted prompt (may include CUSTOM INSTRUCTIONS)
Deriver->>LLM: honcho_llm_call(prompt)
LLM-->>Deriver: response
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~28 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
docs/v3/contributing/configuration.mdx (1)
298-326:⚠️ Potential issue | 🟡 MinorDocument the new
DERIVER_MAX_CUSTOM_INSTRUCTIONS_TOKENSsetting.
config.toml.exampleand.env.templateboth advertiseMAX_CUSTOM_INSTRUCTIONS_TOKENS, and the schema validator rejects non-blankreasoning.custom_instructionswhen this cap is unset (raises"DERIVER.MAX_CUSTOM_INSTRUCTIONS_TOKENS is not set…"). The contributing guide should mention it here so operators know they must opt in (max 2000) to enable custom instructions, and note that it must not exceedMAX_INPUT_TOKENS.📝 Suggested addition to the Deriver section
DERIVER_MAX_INPUT_TOKENS=25000 +# Opt-in cap for reasoning.custom_instructions (max 2000, must be <= MAX_INPUT_TOKENS). +# Unset means non-blank custom_instructions will be rejected at validation time. +# DERIVER_MAX_CUSTOM_INSTRUCTIONS_TOKENS=2000 # DERIVER_MODEL_CONFIG__THINKING_EFFORT=minimal🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/v3/contributing/configuration.mdx` around lines 298 - 326, Add documentation for the DERIVER_MAX_CUSTOM_INSTRUCTIONS_TOKENS env/config setting in the Deriver section to explain that operators must opt-in to enable non-blank reasoning.custom_instructions (the schema validator rejects it if this cap is unset), show an example env line (DERIVER_MAX_CUSTOM_INSTRUCTIONS_TOKENS=2000), state the allowed maximum (2000) and that the value must not exceed DERIVER_MAX_INPUT_TOKENS, and mention it corresponds to entries in config.toml.example and .env.template so maintainers know to keep those samples and the contributing guide in sync.
♻️ Duplicate comments (1)
src/schemas/configuration.py (1)
86-100:⚠️ Potential issue | 🟠 MajorValidator propagates a server-config error to API clients; see src/config.py comment on
effective_max_custom_instructions_tokens.
settings.DERIVER.effective_max_custom_instructions_tokensraisesValueErrorwhenMAX_CUSTOM_INSTRUCTIONS_TOKENSisNone. Pydantic will wrap that into a 422ValidationErrorwhose detail string is the internal config-path message (set [deriver].MAX_CUSTOM_INSTRUCTIONS_TOKENS in config.toml). This is the user-facing manifestation of the root-cause concern raised insrc/config.py; fixing it at the property (returnint | None) and guarding here —if max_tokens is None: raise ValueError("custom_instructions are not enabled on this deployment")— would produce a much better API error.Also note that because this validator reads the global
settingslazily, it's sensitive to test ordering and import-time settings construction; the existing tests work around this withmonkeypatch.setattr(settings.DERIVER, ...), which is fine but worth being aware of for future schema-construction outside request scope.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/schemas/configuration.py` around lines 86 - 100, The validator _validate_custom_instructions_budget must not propagate the internal config ValueError — fetch max_tokens via settings.DERIVER.effective_max_custom_instructions_tokens, guard for None and raise a clear API-facing ValueError like "custom_instructions are not enabled on this deployment" (do this before calling estimate_tokens), and only perform the token estimate and comparison if max_tokens is an int; this prevents the internal config error from being wrapped into a 422 and ensures a deterministic, testable behavior.
🧹 Nitpick comments (8)
.env.template (1)
115-116: Consider mirroring the explanatory comment fromconfig.toml.example.Optional nit: in
config.toml.examplethis key carries# Required for non-blank reasoning.custom_instructions; max supported value is 2000. Adding the same inline note here helps users understand that unsetting it disables non-blank custom instructions.📝 Suggested diff
-# DERIVER_MAX_CUSTOM_INSTRUCTIONS_TOKENS=2000 +# DERIVER_MAX_CUSTOM_INSTRUCTIONS_TOKENS=2000 # Required for non-blank reasoning.custom_instructions; max supported value is 2000🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.env.template around lines 115 - 116, Add an inline explanatory comment next to the DERIVER_MAX_INPUT_TOKENS and DERIVER_MAX_CUSTOM_INSTRUCTIONS_TOKENS entries in .env.template mirroring the wording from config.toml.example (e.g., note that DERIVER_MAX_CUSTOM_INSTRUCTIONS_TOKENS is "Required for non-blank reasoning.custom_instructions; max supported value is 2000" and that leaving it unset disables non-blank custom instructions) so users understand the setting's effect and max value; update the commented lines for DERIVER_MAX_CUSTOM_INSTRUCTIONS_TOKENS and optionally DERIVER_MAX_INPUT_TOKENS to include this guidance.tests/test_config.py (1)
39-43: Test name implies "defaults" but it exercises an explicit override.
test_deriver_defaults_allow_larger_custom_instruction_budgetreads as "with defaults, a larger budget is allowed", but the test passesMAX_CUSTOM_INSTRUCTIONS_TOKENS=2000explicitly — the default isNone. The actual assertion of interest is thatMAX_INPUT_TOKENSdefaults to25000(the other assertion is redundant withtest_effective_custom_instructions_tokens_uses_explicit_limit).♻️ Suggested rename / tightening
-def test_deriver_defaults_allow_larger_custom_instruction_budget() -> None: - settings = _make_deriver_settings(MAX_CUSTOM_INSTRUCTIONS_TOKENS=2000) - - assert settings.MAX_INPUT_TOKENS == 25000 - assert settings.effective_max_custom_instructions_tokens == 2000 +def test_deriver_default_max_input_tokens_is_25000() -> None: + settings = _make_deriver_settings() + + assert settings.MAX_INPUT_TOKENS == 25000🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/test_config.py` around lines 39 - 43, Rename or tighten the test so its name matches what it asserts: either remove the explicit override and call _make_deriver_settings() with default (no MAX_CUSTOM_INSTRUCTIONS_TOKENS) to verify settings.MAX_INPUT_TOKENS == 25000, or rename the test to reflect that it verifies an explicit override (e.g., test_deriver_explicit_custom_instruction_budget_allows_larger_value) and remove the redundant assertion on settings.effective_max_custom_instructions_tokens since test_effective_custom_instructions_tokens_uses_explicit_limit already covers that; update references to _make_deriver_settings, settings.MAX_INPUT_TOKENS and settings.effective_max_custom_instructions_tokens accordingly.tests/utils/test_config_helpers.py (2)
26-28:raising=Falseis unnecessary here and weakens the guard.
MAX_CUSTOM_INSTRUCTIONS_TOKENSis a declared field onDeriverSettings, so the attribute will always exist onsettings.DERIVER. Passingraising=Falsehides a would-be typo (e.g., renaming the field) that these tests would otherwise catch. Consider dropping it (same on Line 50).♻️ Proposed change
- monkeypatch.setattr( - settings.DERIVER, "MAX_CUSTOM_INSTRUCTIONS_TOKENS", 100, raising=False - ) + monkeypatch.setattr(settings.DERIVER, "MAX_CUSTOM_INSTRUCTIONS_TOKENS", 100)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/utils/test_config_helpers.py` around lines 26 - 28, Remove the unnecessary raising=False on the monkeypatch.setattr calls that modify settings.DERIVER attributes: ensure monkeypatch.setattr(settings.DERIVER, "MAX_CUSTOM_INSTRUCTIONS_TOKENS", 100) (and the analogous call around line 50) are called without raising=False so attribute existence is enforced; update both occurrences to omit the raising parameter to let tests fail if the DeriverSettings field is renamed or missing.
23-78: Coverage gap: no negative test for message-levelcustom_instructionsexceeding the cap.Both tests set
MAX_CUSTOM_INSTRUCTIONS_TOKENS=100and use short strings that easily fit. SinceMessageConfiguration→ReasoningConfiguration.validate_custom_instructionsis the user-facing enforcement point for this PR, it would be valuable to assert thatget_configuration(orMessageConfigurationconstruction) raises when the resolved/message-level custom_instructions blows the budget, and that it does not raise when the workspace-level string is within budget. The PR summary saystests/test_schema_validations.pycovers schema-level rejection, so this is an optional belt-and-suspenders addition at theget_configurationlayer.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/utils/test_config_helpers.py` around lines 23 - 78, Add a negative test that monkeypatches settings.DERIVER.MAX_CUSTOM_INSTRUCTIONS_TOKENS to a small value, then constructs a MessageConfiguration whose reasoning.custom_instructions exceeds that cap and assert that get_configuration (or MessageConfiguration construction) raises via ReasoningConfiguration.validate_custom_instructions; also include a control asserting that a workspace-level custom_instructions string that is within the same cap does not raise when passed to get_configuration. Reference MAX_CUSTOM_INSTRUCTIONS_TOKENS, MessageConfiguration, ReasoningConfiguration.validate_custom_instructions, and get_configuration to locate the relevant code paths.src/schemas/configuration.py (2)
153-160: Duplicated validator onResolvedReasoningConfigurationis redundant given upstream enforcement.
ResolvedReasoningConfigurationis only ever constructed from dicts that were themselves merged from already-validatedReasoningConfigurationinstances (seesrc/utils/config_helpers.py:get_configuration). Since_validate_custom_instructions_budgetis deterministic over the string, running it again on the resolved model just repeats the sameestimate_tokenscall on the deriver hot path. Not a correctness issue — I'd keep it only if you specifically want belt-and-suspenders againstResolvedConfiguration(**dict)being constructed from untrusted input elsewhere.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/schemas/configuration.py` around lines 153 - 160, The ResolvedReasoningConfiguration class currently re-runs _validate_custom_instructions_budget via the field validator method validate_custom_instructions, which is redundant because ResolvedReasoningConfiguration instances are constructed from already-validated ReasoningConfiguration dicts (see get_configuration). Remove the `@field_validator`("custom_instructions") method validate_custom_instructions from ResolvedReasoningConfiguration so the model only defines enabled and custom_instructions without re-invoking _validate_custom_instructions_budget; keep the helper _validate_custom_instructions_budget and the original validator on ReasoningConfiguration unchanged.
91-92: Whitespace-onlycustom_instructionsis returned verbatim — consider normalizing toNone.When
custom_instructions = " ", the validator returns the original whitespace string untouched. Downstream,_normalized_custom_instructionsinsrc/deriver/prompts.pycorrectly collapses that to no section, so there's no user-visible bug today. However, persisting a whitespace-only string in the workspace/session/message configuration is surprising and will fail any future exact-match comparisons to "no custom instructions set". Consider normalizing blank/whitespace toNoneat validation time for consistency.♻️ Proposed change
- if custom_instructions is None: - return None - if not custom_instructions.strip(): - return custom_instructions + if custom_instructions is None or not custom_instructions.strip(): + return None🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/schemas/configuration.py` around lines 91 - 92, The validator currently returns the original whitespace-only string when it hits the check "if not custom_instructions.strip(): return custom_instructions"; change this to return None instead so blank/whitespace-only custom_instructions are normalized to None at validation time (update the branch in the validator that inspects custom_instructions.strip()). Ensure callers that expect None (e.g., _normalized_custom_instructions in src/deriver/prompts.py) continue to work unchanged.src/deriver/prompts.py (1)
83-105: Token-estimation strategy is consistent with the existing pattern.Using empty
peer_id/messagesand letting the caller add those tokens separately matches howestimate_base_prompt_tokens()is intended to be used, and includingcustom_instructionsin the estimate here is correct because the caller cannot substitute it as a simple string concatenation (it adds theCUSTOM INSTRUCTIONS:header).One small concern:
estimate_minimal_deriver_prompt_tokens()is@cached, butestimate_deriver_prompt_tokens()re-renders the full prompt and re-tokenizes on every call whencustom_instructionsis non-empty. For the deriver hot path (called per message) this is likely fine, but if you want, the token count for a givencustom_instructionsstring could be cached too.Based on learnings: "the approach uses empty inputs to get the base prompt template token count via estimate_base_prompt_tokens(), then manually adds tokens for actual inputs (peer_card, working_representation, new_turns). This avoids double-counting wrapper overhead since the base prompt already includes template structure."
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/deriver/prompts.py` around lines 83 - 105, The per-call tokenization for non-empty custom instructions in estimate_deriver_prompt_tokens causes unnecessary work; cache the token count per normalized custom instructions string to avoid re-rendering/minimizing heat on the deriver hot path: normalize via _normalized_custom_instructions(custom_instructions) as you already do, then compute the prompt and estimate_tokens using minimal_deriver_prompt and estimate_tokens for that normalized string once and memoize it (e.g., add a small cached helper or apply `@cache` to a helper like _estimate_deriver_prompt_tokens_cached(normalized_custom_instructions) that calls minimal_deriver_prompt and estimate_tokens), while keeping the current fast-return to estimate_minimal_deriver_prompt_tokens() when normalized_custom_instructions is None.src/config.py (1)
771-778: Cross-field check is effectively unreachable given field bounds.
MAX_CUSTOM_INSTRUCTIONS_TOKENSis bounded byle=2000andMAX_INPUT_TOKENSis bounded bygeofREPRESENTATION_BATCH_MAX_TOKENS(ge=128) and below bygt=0. So this validator can only fire whenMAX_INPUT_TOKENSis set to something in the narrow range where it's belowMAX_CUSTOM_INSTRUCTIONS_TOKENS(≤2000), which is almost certainly a broken deployment for unrelated reasons. Keeping the check is fine (it's defensive), but the error message could tell the operator the real action — usually "raise MAX_INPUT_TOKENS" — rather than implying the custom-instructions budget is at fault.Nit only; happy to defer.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/config.py` around lines 771 - 778, The cross-field check in the validator block referencing MAX_CUSTOM_INSTRUCTIONS_TOKENS and MAX_INPUT_TOKENS should keep the guard but change the ValueError to direct operators to increase MAX_INPUT_TOKENS (since MAX_CUSTOM_INSTRUCTIONS_TOKENS is tightly bound by le=2000 and MAX_INPUT_TOKENS has lower bounds like REPRESENTATION_BATCH_MAX_TOKENS); update the error raised in that block to include both current values and a clear actionable suggestion such as "increase MAX_INPUT_TOKENS to at least X" or "raise MAX_INPUT_TOKENS" while still reporting the offending values (reference the variables MAX_CUSTOM_INSTRUCTIONS_TOKENS, MAX_INPUT_TOKENS, and REPRESENTATION_BATCH_MAX_TOKENS to locate the code).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@src/config.py`:
- Around line 781-788: The property effective_max_custom_instructions_tokens
should not raise a ValueError for a missing MAX_CUSTOM_INSTRUCTIONS_TOKENS
because that surfaces internal config paths to API clients; instead make the
property return None (i.e., keep its type as int | None) when
MAX_CUSTOM_INSTRUCTIONS_TOKENS is unset, and update the validators in
ReasoningConfiguration.validate_custom_instructions and
ResolvedReasoningConfiguration.validate_custom_instructions to explicitly check
for None and raise a user-facing validation error like "custom_instructions is
not enabled on this deployment" when a non-blank custom_instructions is
submitted; alternatively you can introduce a separate flag (e.g.,
CUSTOM_INSTRUCTIONS_ENABLED) and use that in the schema validators rather than
throwing from effective_max_custom_instructions_tokens.
---
Outside diff comments:
In `@docs/v3/contributing/configuration.mdx`:
- Around line 298-326: Add documentation for the
DERIVER_MAX_CUSTOM_INSTRUCTIONS_TOKENS env/config setting in the Deriver section
to explain that operators must opt-in to enable non-blank
reasoning.custom_instructions (the schema validator rejects it if this cap is
unset), show an example env line (DERIVER_MAX_CUSTOM_INSTRUCTIONS_TOKENS=2000),
state the allowed maximum (2000) and that the value must not exceed
DERIVER_MAX_INPUT_TOKENS, and mention it corresponds to entries in
config.toml.example and .env.template so maintainers know to keep those samples
and the contributing guide in sync.
---
Duplicate comments:
In `@src/schemas/configuration.py`:
- Around line 86-100: The validator _validate_custom_instructions_budget must
not propagate the internal config ValueError — fetch max_tokens via
settings.DERIVER.effective_max_custom_instructions_tokens, guard for None and
raise a clear API-facing ValueError like "custom_instructions are not enabled on
this deployment" (do this before calling estimate_tokens), and only perform the
token estimate and comparison if max_tokens is an int; this prevents the
internal config error from being wrapped into a 422 and ensures a deterministic,
testable behavior.
---
Nitpick comments:
In @.env.template:
- Around line 115-116: Add an inline explanatory comment next to the
DERIVER_MAX_INPUT_TOKENS and DERIVER_MAX_CUSTOM_INSTRUCTIONS_TOKENS entries in
.env.template mirroring the wording from config.toml.example (e.g., note that
DERIVER_MAX_CUSTOM_INSTRUCTIONS_TOKENS is "Required for non-blank
reasoning.custom_instructions; max supported value is 2000" and that leaving it
unset disables non-blank custom instructions) so users understand the setting's
effect and max value; update the commented lines for
DERIVER_MAX_CUSTOM_INSTRUCTIONS_TOKENS and optionally DERIVER_MAX_INPUT_TOKENS
to include this guidance.
In `@src/config.py`:
- Around line 771-778: The cross-field check in the validator block referencing
MAX_CUSTOM_INSTRUCTIONS_TOKENS and MAX_INPUT_TOKENS should keep the guard but
change the ValueError to direct operators to increase MAX_INPUT_TOKENS (since
MAX_CUSTOM_INSTRUCTIONS_TOKENS is tightly bound by le=2000 and MAX_INPUT_TOKENS
has lower bounds like REPRESENTATION_BATCH_MAX_TOKENS); update the error raised
in that block to include both current values and a clear actionable suggestion
such as "increase MAX_INPUT_TOKENS to at least X" or "raise MAX_INPUT_TOKENS"
while still reporting the offending values (reference the variables
MAX_CUSTOM_INSTRUCTIONS_TOKENS, MAX_INPUT_TOKENS, and
REPRESENTATION_BATCH_MAX_TOKENS to locate the code).
In `@src/deriver/prompts.py`:
- Around line 83-105: The per-call tokenization for non-empty custom
instructions in estimate_deriver_prompt_tokens causes unnecessary work; cache
the token count per normalized custom instructions string to avoid
re-rendering/minimizing heat on the deriver hot path: normalize via
_normalized_custom_instructions(custom_instructions) as you already do, then
compute the prompt and estimate_tokens using minimal_deriver_prompt and
estimate_tokens for that normalized string once and memoize it (e.g., add a
small cached helper or apply `@cache` to a helper like
_estimate_deriver_prompt_tokens_cached(normalized_custom_instructions) that
calls minimal_deriver_prompt and estimate_tokens), while keeping the current
fast-return to estimate_minimal_deriver_prompt_tokens() when
normalized_custom_instructions is None.
In `@src/schemas/configuration.py`:
- Around line 153-160: The ResolvedReasoningConfiguration class currently
re-runs _validate_custom_instructions_budget via the field validator method
validate_custom_instructions, which is redundant because
ResolvedReasoningConfiguration instances are constructed from already-validated
ReasoningConfiguration dicts (see get_configuration). Remove the
`@field_validator`("custom_instructions") method validate_custom_instructions from
ResolvedReasoningConfiguration so the model only defines enabled and
custom_instructions without re-invoking _validate_custom_instructions_budget;
keep the helper _validate_custom_instructions_budget and the original validator
on ReasoningConfiguration unchanged.
- Around line 91-92: The validator currently returns the original
whitespace-only string when it hits the check "if not
custom_instructions.strip(): return custom_instructions"; change this to return
None instead so blank/whitespace-only custom_instructions are normalized to None
at validation time (update the branch in the validator that inspects
custom_instructions.strip()). Ensure callers that expect None (e.g.,
_normalized_custom_instructions in src/deriver/prompts.py) continue to work
unchanged.
In `@tests/test_config.py`:
- Around line 39-43: Rename or tighten the test so its name matches what it
asserts: either remove the explicit override and call _make_deriver_settings()
with default (no MAX_CUSTOM_INSTRUCTIONS_TOKENS) to verify
settings.MAX_INPUT_TOKENS == 25000, or rename the test to reflect that it
verifies an explicit override (e.g.,
test_deriver_explicit_custom_instruction_budget_allows_larger_value) and remove
the redundant assertion on settings.effective_max_custom_instructions_tokens
since test_effective_custom_instructions_tokens_uses_explicit_limit already
covers that; update references to _make_deriver_settings,
settings.MAX_INPUT_TOKENS and settings.effective_max_custom_instructions_tokens
accordingly.
In `@tests/utils/test_config_helpers.py`:
- Around line 26-28: Remove the unnecessary raising=False on the
monkeypatch.setattr calls that modify settings.DERIVER attributes: ensure
monkeypatch.setattr(settings.DERIVER, "MAX_CUSTOM_INSTRUCTIONS_TOKENS", 100)
(and the analogous call around line 50) are called without raising=False so
attribute existence is enforced; update both occurrences to omit the raising
parameter to let tests fail if the DeriverSettings field is renamed or missing.
- Around line 23-78: Add a negative test that monkeypatches
settings.DERIVER.MAX_CUSTOM_INSTRUCTIONS_TOKENS to a small value, then
constructs a MessageConfiguration whose reasoning.custom_instructions exceeds
that cap and assert that get_configuration (or MessageConfiguration
construction) raises via ReasoningConfiguration.validate_custom_instructions;
also include a control asserting that a workspace-level custom_instructions
string that is within the same cap does not raise when passed to
get_configuration. Reference MAX_CUSTOM_INSTRUCTIONS_TOKENS,
MessageConfiguration, ReasoningConfiguration.validate_custom_instructions, and
get_configuration to locate the relevant code paths.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 32d2cf71-525a-497e-8924-ae4ee05a69b4
📒 Files selected for processing (13)
.env.templateconfig.toml.exampledocs/v3/contributing/configuration.mdxsrc/config.pysrc/deriver/deriver.pysrc/deriver/prompts.pysrc/schemas/configuration.pysrc/utils/config_helpers.pytests/deriver/test_deriver_processing.pytests/deriver/test_prompts.pytests/test_config.pytests/test_schema_validations.pytests/utils/test_config_helpers.py
There was a problem hiding this comment.
🧹 Nitpick comments (4)
tests/test_schema_validations.py (3)
230-245: Tighten the oversized-instructions test.This test only asserts that some error is raised at
loc == ("custom_instructions",), but Pydantic would also produce an error at that location for unrelated validation failures (e.g., a type error in the future). Consider also asserting that the message contains the expected "exceeds" text to distinguish it from the "not enabled" path covered by the previous test — otherwise both tests could pass even if the validator collapsed both branches into one.♻️ Proposed tightening
assert any( error["loc"] == ("custom_instructions",) + and "exceeds" in error["msg"] for error in exc_info.value.errors() )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/test_schema_validations.py` around lines 230 - 245, The test test_reasoning_configuration_rejects_oversized_custom_instructions should not only check the error location but also assert the error message indicates the size limit was exceeded; update the assertion that iterates exc_info.value.errors() to require both error["loc"] == ("custom_instructions",) and that the error["msg"] contains the expected substring (e.g., "exceeds" or "exceeds maximum") so the test specifically verifies the oversized-instructions branch of ReasoningConfiguration validation rather than any unrelated validation error.
214-216: Dropraising=Falseon the monkeypatch calls.
MAX_CUSTOM_INSTRUCTIONS_TOKENSis a declared field onDeriverSettings(seesrc/config.py:738), so the attribute always exists. Usingraising=Falsesilently swallowsAttributeError, which would mask a typo in the attribute name and turn a real test failure into a passing no-op. Prefer the default (raising=True) so the tests fail loudly if the setting is ever renamed.♻️ Proposed change
- monkeypatch.setattr( - settings.DERIVER, "MAX_CUSTOM_INSTRUCTIONS_TOKENS", None, raising=False - ) + monkeypatch.setattr( + settings.DERIVER, "MAX_CUSTOM_INSTRUCTIONS_TOKENS", None + )(apply the equivalent change at the three other call sites)
Also applies to: 233-235, 250-252, 280-282
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/test_schema_validations.py` around lines 214 - 216, Remove raising=False from the monkeypatch.setattr calls that target settings.DERIVER.MAX_CUSTOM_INSTRUCTIONS_TOKENS in tests/test_schema_validations.py so that monkeypatch will raise on missing attributes; specifically, update the monkeypatch.setattr invocations referencing settings.DERIVER and the attribute MAX_CUSTOM_INSTRUCTIONS_TOKENS (and the three equivalent call sites in the same file) to use the default raising=True by omitting the raising parameter.
221-228: Weak regression guard on line 228.The "not in" check targets the literal
"[deriver].MAX_CUSTOM_INSTRUCTIONS_TOKENS", but the current validator insrc/schemas/configuration.pynever emits that exact bracketed-prefix format in any branch — the "not enabled" branch doesn't reference the setting at all, and the "exceeds" branch usesDERIVER.MAX_CUSTOM_INSTRUCTIONS_TOKENS(no brackets). As written, this assertion will pass regardless of what leaks into the message, so it doesn't actually guard against settings-key leakage.Consider either removing it or broadening it to catch any form of the settings key (e.g., assert that
"MAX_CUSTOM_INSTRUCTIONS_TOKENS"does not appear in the "not enabled" message).♻️ Proposed change
- assert "[deriver].MAX_CUSTOM_INSTRUCTIONS_TOKENS" not in str(exc_info.value) + assert "MAX_CUSTOM_INSTRUCTIONS_TOKENS" not in str(exc_info.value)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/test_schema_validations.py` around lines 221 - 228, The regression guard is too specific and will always pass because the validator never emits the bracketed key "[deriver].MAX_CUSTOM_INSTRUCTIONS_TOKENS"; update the test in tests/test_schema_validations.py to assert against the broader token name instead of the bracketed form (e.g., assert "MAX_CUSTOM_INSTRUCTIONS_TOKENS" not in str(exc_info.value)) or remove the assertion entirely; target the same objects used in the test (errors and exc_info.value) so the "not enabled" branch in src/schemas/configuration.py is validated to not leak the settings key in any form.tests/utils/test_config_helpers.py (1)
23-74: Consider adding a session-over-workspace precedence test.The two tests cover "workspace only" and "message overrides all" cases, but not the intermediate "session overrides workspace" case (with no message configuration). Given that
get_configurationapplies overrides in a specific Workspace → Session → Message order insrc/utils/config_helpers.py, a dedicated test for session-level override would round out the precedence matrix and guard against regressions in the middle tier.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@tests/utils/test_config_helpers.py` around lines 23 - 74, Add a new unit test that asserts session-level reasoning.custom_instructions overrides workspace-level when no MessageConfiguration is provided: set monkeypatch for settings.DERIVER.MAX_CUSTOM_INSTRUCTIONS_TOKENS (as in other tests), create a workspace via _workspace(...) with reasoning.custom_instructions = "Use the workspace-specific guidance.", create a session via _session(...) with reasoning.custom_instructions = "Use the session-specific guidance.", call get_configuration(None, session, workspace) and assert configuration.reasoning.custom_instructions == "Use the session-specific guidance."; reference get_configuration, _workspace, _session, and ReasoningConfiguration to locate where to add the test.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@tests/test_schema_validations.py`:
- Around line 230-245: The test
test_reasoning_configuration_rejects_oversized_custom_instructions should not
only check the error location but also assert the error message indicates the
size limit was exceeded; update the assertion that iterates
exc_info.value.errors() to require both error["loc"] == ("custom_instructions",)
and that the error["msg"] contains the expected substring (e.g., "exceeds" or
"exceeds maximum") so the test specifically verifies the oversized-instructions
branch of ReasoningConfiguration validation rather than any unrelated validation
error.
- Around line 214-216: Remove raising=False from the monkeypatch.setattr calls
that target settings.DERIVER.MAX_CUSTOM_INSTRUCTIONS_TOKENS in
tests/test_schema_validations.py so that monkeypatch will raise on missing
attributes; specifically, update the monkeypatch.setattr invocations referencing
settings.DERIVER and the attribute MAX_CUSTOM_INSTRUCTIONS_TOKENS (and the three
equivalent call sites in the same file) to use the default raising=True by
omitting the raising parameter.
- Around line 221-228: The regression guard is too specific and will always pass
because the validator never emits the bracketed key
"[deriver].MAX_CUSTOM_INSTRUCTIONS_TOKENS"; update the test in
tests/test_schema_validations.py to assert against the broader token name
instead of the bracketed form (e.g., assert "MAX_CUSTOM_INSTRUCTIONS_TOKENS" not
in str(exc_info.value)) or remove the assertion entirely; target the same
objects used in the test (errors and exc_info.value) so the "not enabled" branch
in src/schemas/configuration.py is validated to not leak the settings key in any
form.
In `@tests/utils/test_config_helpers.py`:
- Around line 23-74: Add a new unit test that asserts session-level
reasoning.custom_instructions overrides workspace-level when no
MessageConfiguration is provided: set monkeypatch for
settings.DERIVER.MAX_CUSTOM_INSTRUCTIONS_TOKENS (as in other tests), create a
workspace via _workspace(...) with reasoning.custom_instructions = "Use the
workspace-specific guidance.", create a session via _session(...) with
reasoning.custom_instructions = "Use the session-specific guidance.", call
get_configuration(None, session, workspace) and assert
configuration.reasoning.custom_instructions == "Use the session-specific
guidance."; reference get_configuration, _workspace, _session, and
ReasoningConfiguration to locate where to add the test.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: b0829ed4-3ef2-458b-9da7-76e3d539af06
📒 Files selected for processing (6)
.env.templatedocs/v3/contributing/configuration.mdxsrc/schemas/configuration.pytests/test_config.pytests/test_schema_validations.pytests/utils/test_config_helpers.py
✅ Files skipped from review due to trivial changes (1)
- docs/v3/contributing/configuration.mdx
🚧 Files skipped from review as they are similar to previous changes (3)
- tests/test_config.py
- .env.template
- src/schemas/configuration.py
There was a problem hiding this comment.
🧹 Nitpick comments (1)
tests/test_config.py (1)
6-20: ⚡ Quick winUse snake_case parameter names in test helper.
Helper parameters should be snake_case to match project Python conventions.
Proposed change
def _make_deriver_settings( *, - MAX_INPUT_TOKENS: int = 25000, - MAX_CUSTOM_INSTRUCTIONS_TOKENS: int = 2000, - REPRESENTATION_BATCH_MAX_TOKENS: int = 1024, + max_input_tokens: int = 25000, + max_custom_instructions_tokens: int = 2000, + representation_batch_max_tokens: int = 1024, ) -> DeriverSettings: return DeriverSettings( MODEL_CONFIG=ConfiguredModelSettings( model="gpt-5.4-mini", transport="openai", ), - MAX_INPUT_TOKENS=MAX_INPUT_TOKENS, - MAX_CUSTOM_INSTRUCTIONS_TOKENS=MAX_CUSTOM_INSTRUCTIONS_TOKENS, - REPRESENTATION_BATCH_MAX_TOKENS=REPRESENTATION_BATCH_MAX_TOKENS, + MAX_INPUT_TOKENS=max_input_tokens, + MAX_CUSTOM_INSTRUCTIONS_TOKENS=max_custom_instructions_tokens, + REPRESENTATION_BATCH_MAX_TOKENS=representation_batch_max_tokens, )As per coding guidelines: "
**/*.py: Use snake_case for variables and functions; PascalCase for classes".🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@tests/test_config.py` around lines 6 - 20, The helper _make_deriver_settings currently uses Pascal/SCREAMING_STYLE parameter names; rename its parameters to snake_case (e.g., max_input_tokens, max_custom_instructions_tokens, representation_batch_max_tokens) and update the function body to pass those snake_case variables into DeriverSettings (mapping to MAX_INPUT_TOKENS, MAX_CUSTOM_INSTRUCTIONS_TOKENS, REPRESENTATION_BATCH_MAX_TOKENS) so callers and the test follow project Python naming conventions; also update any test calls to use the new snake_case argument names.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@tests/test_config.py`:
- Around line 6-20: The helper _make_deriver_settings currently uses
Pascal/SCREAMING_STYLE parameter names; rename its parameters to snake_case
(e.g., max_input_tokens, max_custom_instructions_tokens,
representation_batch_max_tokens) and update the function body to pass those
snake_case variables into DeriverSettings (mapping to MAX_INPUT_TOKENS,
MAX_CUSTOM_INSTRUCTIONS_TOKENS, REPRESENTATION_BATCH_MAX_TOKENS) so callers and
the test follow project Python naming conventions; also update any test calls to
use the new snake_case argument names.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 6ddd371c-8c4e-4e6d-98ec-f3c1eb48711d
📒 Files selected for processing (6)
.env.templateconfig.toml.examplesrc/config.pysrc/schemas/configuration.pytests/test_config.pytests/test_schema_validations.py
🚧 Files skipped from review as they are similar to previous changes (3)
- config.toml.example
- src/schemas/configuration.py
- tests/test_schema_validations.py
Sync fork with upstream through 9f26fdd (v3.0.2 → v3.0.9). No conflicts; local CLAUDE.md (GitNexus block) auto-merged. Notable: base_url threading to LLM clients (plastic-labs#643), configurable embeddings (plastic-labs#678), deriver custom instructions (plastic-labs#609). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary by CodeRabbit
New Features
Configuration
Behavior
Documentation
Tests