UN-3987 [FIX] Send LLMWhisperer V2 params under the correct names - #2236
UN-3987 [FIX] Send LLMWhisperer V2 params under the correct names#2236chandrasekharan-zipstack wants to merge 8 commits into
Conversation
0b28344 to
151b688
Compare
The adapter read the line splitter strategy under `line_spitter_strategy` while its JSON schema stores it as `line_splitter_strategy`, so the user's choice never applied. The same misspelling was also passed to the client, which forwarded a query param the service does not read. The page separator keeps its misspelled config key since existing adapter configs are stored under it, but is now sent under the client's corrected kwarg. Both need llmwhisperer-client 2.8.0 or newer. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dra3Xevzb5oYtMz9fhj8iG
Without it, usage reports record the service default for every Unstract-originated extraction, leaving no way to cross reference a row back to a document. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dra3Xevzb5oYtMz9fhj8iG
151b688 to
8b74d6f
Compare
|
|
| Filename | Overview |
|---|---|
| docker/scripts/uv-lock-gen/uv-lock.sh | Adds missing projects to lock automation, but direct-only dependency detection leaves transitive consumer locks susceptible to recurrence. |
| unstract/sdk1/pyproject.toml | Raises the LLMWhisperer client requirement to the released 2.8.1 version. |
| unstract/sdk1/src/unstract/sdk1/adapters/x2text/llm_whisperer_v2/src/helper.py | Sends corrected parameter names, validates strategies, and attaches the input basename. |
| unstract/sdk1/tests/test_llm_whisperer_v2_params.py | Covers supported and invalid splitter strategies plus legacy page-separator configuration. |
| unstract/connectors/uv.lock | Currently resolves llmwhisperer-client 2.8.1, while also demonstrating that this transitive consumer lock depends on sdk1 metadata. |
Flowchart
%%{init: {'theme': 'neutral'}}%%
flowchart LR
SDK["sdk1 dependency changes"] --> FS["filesystem directly depends on sdk1"]
FS --> CONN["connectors transitively consumes sdk1"]
SCRIPT["lock automation"] --> DIRECT["checks connectors + direct dependencies"]
DIRECT --> FS
DIRECT -. "does not recurse" .-> SDK
CONN --> STALE["connectors lock may remain stale"]
Prompt To Fix All With AI
### Issue 1
docker/scripts/uv-lock-gen/uv-lock.sh:110-112
**Transitive lock updates remain stale**
When a future `unstract/sdk1` dependency changes while `unstract/connectors` and its direct `unstract-filesystem` dependency remain unchanged, `has_dependency_changes` stops after inspecting the direct dependency and skips the connectors lock, causing `uv lock --check` or frozen installation to fail against its stale sdk1 dependency graph.
---
For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.Reviews (4): Last reviewed commit: "Merge branch 'main' into UN-3987-fix-lin..." | Re-trigger Greptile
…mers The uv-lock bot only checks a directory's own pyproject and its immediate local path dependencies, so an sdk1-only dependency bump left five lockfiles pinning the pre-2.8.0 client with a stale `>=2.6.2` specifier. `uv sync --locked` rejected those directories. Adds sdk1, tool-registry and workflow-execution to the bot's directory list so a future sdk1 bump relocks them without a manual pass. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVoa8BMCNnhdkATd7A9U4J
…service accepts The setting has never reached the service, so stored values were never validated and the JSON schema accepted free text. Now that the value is actually sent, anything outside left-priority / mid-priority / right-priority makes the service reject the extraction with a 400. Adds the enum to the schema so the field renders as a dropdown, and falls back to the default with a warning when an existing config holds an unsupported value. The fallback preserves what those configs resolve to today, and the warning surfaces how many are affected without decrypting stored metadata. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVoa8BMCNnhdkATd7A9U4J
2.8.1 sends the page separator under both the corrected and the legacy query key, so the adapter no longer depends on the LLMWhisperer service being new enough to read the corrected one. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVoa8BMCNnhdkATd7A9U4J
Unstract test resultsPer-group results
Critical paths
|
has_dependency_changes only walked one level of [tool.uv.sources], so a change to unstract/sdk1 relocked unstract/filesystem (a direct dependant) but not unstract/connectors, which reaches sdk1 through it. That is why the root and connectors locks were already stale at llmwhisperer-client 2.7.0 before this branch existed. Read the resolved graph out of each uv.lock instead: uv has already computed the closure there, so no recursion is needed. The pyproject is still read so a dependency added but not yet locked is not missed. Against this branch's sdk1 change, the old walk skips '.' and unstract/connectors; the new one selects both. Also cover unstract/tool-sandbox and tool-sidecar, the two remaining directories with a uv.lock that the bot never visited. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EVoa8BMCNnhdkATd7A9U4J
|



What
The LLMWhisperer V2 adapter's line splitter strategy setting has never been applied. Two breaks stacked:
line_splitter_strategy, butWhispererConfig.LINE_SPLITTER_STRATEGYwas"line_spitter_strategy", soconfig.get()never matched and theleft-prioritydefault was always used.whisper()kwarg, so the client sent query paramline_spitter_strategy, which the service does not read and Flask drops silently.Fixing either alone changes nothing.
Changes
LINE_SPLITTER_STRATEGYis now"line_splitter_strategy"— matches the schema key and the wire param.WhispererConfiggainsPAGE_SEPARATOR_PARAMandFILE_NAMEfor the client kwarg names.page_seperatorstays as the config key (existing adapter configs in the DB are stored under it, no migration needed) but is now sent aspage_separator.file_nameis now sent, set to the basename of the file being extracted. Previously the adapter never sent it, so every Unstract-originated row in LLMWhisperer usage reports showed the service default. Separate commit if you'd rather drop it.llmwhisperer-clientpinned to>=2.8.0.Blocked on the client release
>=2.8.0does not exist yet — it is the release that carries Zipstack/llm-whisperer-python-client#34, which adds the correctly-namedline_splitter_strategy,page_separatorandfile_namekwargs. On an older client these kwargs raiseTypeError, so this must not merge before that release. Draft until then. On un-drafting: confirm the actual version number and regenerate the lockfiles.Ordering: unstract-llm-whisperer#721 (service accepts
page_separator) → llm-whisperer-python-client#34 release → this PR.Behaviour change to expect
The service validates the strategy and returns
400for anything outsideleft-priority/right-priority/mid-priority. Previously an out-of-range value was silently ignored, so a bad stored value becomes a hard error once the value actually arrives.Users who never touched the setting are unaffected — adapter, client and service all default to
left-priority.Verification
tests/test_llm_whisperer_v2_params.py— 2 tests, both pass: the strategy is read from the schema key, and the page separator is read from the legacy config key but emitted under the corrected kwarg.Not verified end to end: the extraction-output change needs the client release and a run against a deployed service.
Jira: UN-3987, LW-406
🤖 Generated with Claude Code
https://claude.ai/code/session_01Dra3Xevzb5oYtMz9fhj8iG