diff --git a/pyproject.toml b/pyproject.toml index 1bfbbd0..daa96f2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -29,8 +29,8 @@ dependencies = [ # Pinned exactly: the CLI derives its flags and help text from these # clients, so one that moves changes the CLI's surface. Each release re-pins # deliberately, against the specs vendored in `src/unstract_cli/specs`. - "unstract-client==1.7.0", - "llmwhisperer-client==2.9.0", + "unstract-client==1.7.1", + "llmwhisperer-client==2.9.1", # Both clients pull this in, but the CLI imports its exception classes # directly to classify a failure, so it names the dependency itself. "requests>=2.32.3", diff --git a/src/unstract_cli/specs/docstudio.json b/src/unstract_cli/specs/docstudio.json index 7bd536c..ea8039b 100644 --- a/src/unstract_cli/specs/docstudio.json +++ b/src/unstract_cli/specs/docstudio.json @@ -65,6 +65,14 @@ "readOnly": true, "type": "string" }, + "owner_emails": { + "description": "Email of each owner, earliest first. Empty if none is a person.", + "items": { + "type": "string" + }, + "readOnly": true, + "type": "array" + }, "run_count": { "readOnly": true, "type": "integer" @@ -91,6 +99,7 @@ "is_owner", "last_5_run_statuses", "last_run_time", + "owner_emails", "run_count", "workflow", "workflow_name" @@ -230,10 +239,6 @@ "maximum": 300, "minimum": -1, "type": "integer" - }, - "use_file_history": { - "default": false, - "type": "boolean" } }, "type": "object" diff --git a/src/unstract_cli/specs/llmwhisperer.json b/src/unstract_cli/specs/llmwhisperer.json index bef1fdd..1cd64d2 100644 --- a/src/unstract_cli/specs/llmwhisperer.json +++ b/src/unstract_cli/specs/llmwhisperer.json @@ -1549,7 +1549,8 @@ "schema": { "default": 10.0, "type": "number" - } + }, + "x-internal": true }, { "in": "query", @@ -1585,7 +1586,8 @@ "schema": { "default": false, "type": "boolean" - } + }, + "x-internal": true }, { "in": "query", @@ -1662,7 +1664,8 @@ "schema": { "default": 0.0, "type": "number" - } + }, + "x-internal": true }, { "in": "query", @@ -1671,8 +1674,6 @@ "schema": { "default": "form", "enum": [ - "document_insights", - "excel", "form", "high_quality", "low_cost", @@ -1689,9 +1690,7 @@ "schema": { "default": "layout_preserving", "enum": [ - "dump-text", "layout_preserving", - "line-printer", "text" ], "type": "string" diff --git a/src/unstract_cli/specs/provenance.json b/src/unstract_cli/specs/provenance.json index 3a96802..7304379 100644 --- a/src/unstract_cli/specs/provenance.json +++ b/src/unstract_cli/specs/provenance.json @@ -1,16 +1,16 @@ { "docstudio.json": { - "client": "unstract-client==1.7.0", + "client": "unstract-client==1.7.1", "repo": "https://github.com/Zipstack/unstract", - "commit": "520b98d7acf5a6d138b24d9787bd788b89150b76", + "commit": "5d46c66ccff8ae1ac3c31a3c3d5d64206e329002", "path": "specs/docstudio-oss.json", - "sha256": "68a31eaf72e54daf8173ae3ef42e4174b257c93b1afc608114582a81be135bd1" + "sha256": "c0de3a14254600f436483561ebb737feac4023fdef2fd46d6abf15dcd2182ad9" }, "llmwhisperer.json": { - "client": "llmwhisperer-client==2.9.0", + "client": "llmwhisperer-client==2.9.1", "repo": "https://github.com/Zipstack/unstract-llm-whisperer", - "commit": "750f941ee229e12cc05d8bd85edaab6a337a8758", + "commit": "fa6cf651a594227f2249dfe0990f80f1ff780398", "path": "specs/llmwhisperer.json", - "sha256": "88ecc01e92443ba5ba6079db7f57cf3038f97670cb796f13c326268a3d79f366" + "sha256": "c015d035b9e06f58e80aabdb5190fbb582dc1b4b8ee48c3a6924fe4392edc650" } } diff --git a/tests/derived_flags.json b/tests/derived_flags.json index 1daff8b..0ce4b59 100644 --- a/tests/derived_flags.json +++ b/tests/derived_flags.json @@ -33,17 +33,6 @@ "choices": [], "short": null }, - "--derotate-threshold": { - "name": "derotate_threshold", - "type": "number", - "default": null, - "description": "The page rotation in degrees beyond which the page is straightened and re-read.", - "array": false, - "nullable": false, - "required": false, - "choices": [], - "short": null - }, "--file-name": { "name": "file_name", "type": "string", @@ -77,17 +66,6 @@ "choices": [], "short": null }, - "--ignore-vertical-text": { - "name": "ignore_vertical_text", - "type": "boolean", - "default": null, - "description": "Whether to drop vertically oriented text instead of extracting it.", - "array": false, - "nullable": false, - "required": false, - "choices": [], - "short": null - }, "--include-line-confidence": { "name": "include_line_confidence", "type": "boolean", @@ -169,17 +147,6 @@ "choices": [], "short": null }, - "--min-table-width": { - "name": "min_table_width", - "type": "number", - "default": null, - "description": "The minimum width a table must span, as a fraction of the page width, to be extracted as a table.", - "array": false, - "nullable": false, - "required": false, - "choices": [], - "short": null - }, "--mode": { "name": "mode", "type": "string", @@ -189,8 +156,6 @@ "nullable": false, "required": false, "choices": [ - "document_insights", - "excel", "form", "high_quality", "low_cost", @@ -208,9 +173,7 @@ "nullable": false, "required": false, "choices": [ - "dump-text", "layout_preserving", - "line-printer", "text" ], "short": null @@ -449,17 +412,6 @@ "required": false, "choices": [], "short": null - }, - "--use-file-history": { - "name": "use_file_history", - "type": "boolean", - "default": false, - "description": "Reuse a previous result for the same file.", - "array": false, - "nullable": false, - "required": false, - "choices": [], - "short": null } }, "docstudio:status": { diff --git a/tests/test_commands.py b/tests/test_commands.py index f29d432..4221e19 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -191,6 +191,34 @@ def test_the_v1_commands_are_registered(): assert set(tree["auth"]["commands"]) == {"login", "whoami"} +@pytest.mark.parametrize( + ("command", "flag"), + [ + (("whisper", "extract"), "--derotate-threshold"), + (("whisper", "extract"), "--min-table-width"), + (("whisper", "extract"), "--ignore-vertical-text"), + (("docstudio", "deployment", "run"), "--use-file-history"), + ], +) +def test_a_withdrawn_option_is_unknown_to_the_shipped_command(capsys, command, flag): + """The services stopped publishing these; a caller still passing one must + learn that before the request, not from a silently ignored setting.""" + code, out, _ = run(capsys, *command, "x.pdf", flag) + assert code == int(ExitCode.USAGE) + message = envelope(out)["error"]["message"] + assert "No such option" in message and flag in message + + +@pytest.mark.parametrize( + ("flag", "value"), + [("--output-mode", "line-printer"), ("--mode", "excel")], +) +def test_a_withdrawn_choice_is_refused_by_the_shipped_command(capsys, flag, value): + code, out, _ = run(capsys, "whisper", "extract", "x.pdf", flag, value) + assert code == int(ExitCode.USAGE) + assert f"'{value}' is not one of" in envelope(out)["error"]["message"] + + # --------------------------------------------------------------------------- # # whisper extract # --------------------------------------------------------------------------- # diff --git a/tests/test_discover.py b/tests/test_discover.py index 2d4b804..63b83e8 100644 --- a/tests/test_discover.py +++ b/tests/test_discover.py @@ -58,8 +58,6 @@ def test_full_carries_enough_to_build_a_call(capsys): assert params["source"]["kind"] == "argument" and params["source"]["required"] assert params["mode"]["choices"] == [ - "document_insights", - "excel", "form", "high_quality", "low_cost", diff --git a/tests/test_params.py b/tests/test_params.py index cc0c787..2bf44ad 100644 --- a/tests/test_params.py +++ b/tests/test_params.py @@ -273,7 +273,7 @@ def test_choices_come_from_the_spec_unless_the_overlay_narrows_them(): """A wrong value must fail before the request, not after -- and the list it is checked against is the service's own, not a copy that can fall behind.""" spec_declared = _by_name(operation_params("llmwhisperer", "extract"))["mode"] - assert "excel" in spec_declared.choices + assert "form" in spec_declared.choices assert click_option(spec_declared, {}).type.choices == spec_declared.choices option = click_option(spec_declared, {"mode": {"choices": ["form", "table"]}}) diff --git a/uv.lock b/uv.lock index 518002d..0057c00 100644 --- a/uv.lock +++ b/uv.lock @@ -172,7 +172,7 @@ wheels = [ [[package]] name = "llmwhisperer-client" -version = "2.9.0" +version = "2.9.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, @@ -180,9 +180,9 @@ dependencies = [ { name = "requests" }, { name = "tenacity" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/25/c7/d8c822ac12837073d07b9c4c3b4e3967ac6b6f8c91737899ca192e1f24fa/llmwhisperer_client-2.9.0.tar.gz", hash = "sha256:8db10ba2c3a9a8351f22bce809535489154bdc7531e7a54f7c04c7601b0cd784", size = 3317195, upload-time = "2026-09-01T10:15:39.042Z" } +sdist = { url = "https://files.pythonhosted.org/packages/62/8e/87d568d5ddf2c6494c11bedc7844e9ed150e90afe228f77867705bfd3d38/llmwhisperer_client-2.9.1.tar.gz", hash = "sha256:74dbced5a1a481ca5192c3d817a9f9e12bad4d9c3aaac64751ffb0e9b6182f35", size = 3319616, upload-time = "2026-09-18T10:56:06.901Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/7b/b192239d0b31e6979ba4d47336585de0fe437847d6839ff936bb9cb0310d/llmwhisperer_client-2.9.0-py3-none-any.whl", hash = "sha256:a2895053b21819fed2a6c85bc15ba05c74b883071b980360e32be537a285836a", size = 69257, upload-time = "2026-09-01T10:15:37.751Z" }, + { url = "https://files.pythonhosted.org/packages/aa/41/2f221e4ac210dd8a9307849cf0ac35ff87cdd8b344594524d15a52c8f115/llmwhisperer_client-2.9.1-py3-none-any.whl", hash = "sha256:9e9ad402f16562da4dad9d406e06e6c42c077bf8846670040f40e8605c5c82e4", size = 69186, upload-time = "2026-09-18T10:56:05.114Z" }, ] [[package]] @@ -396,19 +396,19 @@ dev = [ [package.metadata] requires-dist = [ { name = "click", specifier = ">=8.1,<9" }, - { name = "llmwhisperer-client", specifier = "==2.9.0" }, + { name = "llmwhisperer-client", specifier = "==2.9.1" }, { name = "pytest", marker = "extra == 'dev'", specifier = ">=8.0" }, { name = "pyyaml", marker = "extra == 'dev'", specifier = ">=6.0" }, { name = "requests", specifier = ">=2.32.3" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.6" }, { name = "tomli-w", specifier = ">=1.0" }, - { name = "unstract-client", specifier = "==1.7.0" }, + { name = "unstract-client", specifier = "==1.7.1" }, ] provides-extras = ["dev"] [[package]] name = "unstract-client" -version = "1.7.0" +version = "1.7.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "attrs" }, @@ -418,9 +418,9 @@ dependencies = [ { name = "rich" }, { name = "tenacity" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/d9/10/ef55a061b55b9ce5fc036a33d7f13ac8abf32d96c8a5d2f29db03248802e/unstract_client-1.7.0.tar.gz", hash = "sha256:39e989e2f9c999f9fe355cb91549cd228b3cc9c48ab4dceb65cd19dfdceb6c86", size = 222590, upload-time = "2026-09-10T12:59:42.268Z" } +sdist = { url = "https://files.pythonhosted.org/packages/1d/d0/d0a6704436baca70e5b261058c0cd9a3a4853556bf6ade9fe201eb3f4b88/unstract_client-1.7.1.tar.gz", hash = "sha256:d192295a8eba9f25268915e60cb0435683a1eb000eaf51bc4f87db0e6e9f1288", size = 222809, upload-time = "2026-09-18T10:56:05.187Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/92/c1d2f64061f7cb09a53f4a8336b34a9b45e7d5bd8f0af7388453fbc3e6e9/unstract_client-1.7.0-py3-none-any.whl", hash = "sha256:d56c5908b03156ac775e4cd9117d78aa39455a32805c49f4fc3ea77d39b6f542", size = 127958, upload-time = "2026-09-10T12:59:40.847Z" }, + { url = "https://files.pythonhosted.org/packages/d3/7b/10584cb0c1cefd075990c2dac0f5e1cdbe05aebc9de41c4ef55c6f73f936/unstract_client-1.7.1-py3-none-any.whl", hash = "sha256:82125d4fb5876fcd872595205d30ad6a1ba544a2d49ea1d3177910bc34877274", size = 127922, upload-time = "2026-09-18T10:56:03.928Z" }, ] [[package]]