ndi-cli 0.5.0__tar.gz → 0.7.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/PKG-INFO +6 -3
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/README.md +3 -1
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/pyproject.toml +6 -3
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/pyproject.toml.orig +4 -3
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/src/ndi_cli/__init__.py +1 -1
- ndi_cli-0.7.0/src/ndi_cli/_entrypoint.py +14 -0
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/src/ndi_cli/_output.py +8 -1
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/src/ndi_cli/_render.py +44 -0
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/src/ndi_cli/_workspace.py +23 -0
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/LICENSE +0 -0
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/src/ndi_cli/_cli.py +0 -0
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/src/ndi_cli/_config.py +0 -0
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/src/ndi_cli/_docops.py +0 -0
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/src/ndi_cli/_jobs.py +0 -0
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/src/ndi_cli/_local.py +0 -0
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/src/ndi_cli/_login.py +0 -0
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/src/ndi_cli/_sources.py +0 -0
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/src/ndi_cli/_tools.py +0 -0
- {ndi_cli-0.5.0 → ndi_cli-0.7.0}/src/ndi_cli/commands.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ndi-cli
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.7.0
|
|
4
4
|
Summary: NDI platform CLI: document operations, jobs, workspaces, and the agent workspace tools
|
|
5
5
|
Keywords: ndi,cli,document-intelligence,coding-agents
|
|
6
6
|
Author: Nace AI
|
|
@@ -16,7 +16,8 @@ Classifier: Programming Language :: Python :: 3.13
|
|
|
16
16
|
Classifier: Programming Language :: Python :: 3.14
|
|
17
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
18
18
|
Classifier: Typing :: Typed
|
|
19
|
-
Requires-Dist: ndi-sdk>=0.
|
|
19
|
+
Requires-Dist: ndi-sdk>=0.22,<1
|
|
20
|
+
Requires-Dist: truststore>=0.10.4,<1
|
|
20
21
|
Requires-Python: >=3.11
|
|
21
22
|
Project-URL: Homepage, https://ndi-api.nace.ai
|
|
22
23
|
Description-Content-Type: text/markdown
|
|
@@ -55,6 +56,7 @@ config location. Workspace-scoped verbs also take `--workspace ID`.
|
|
|
55
56
|
| `ndi files upload\|list\|get\|delete` | Workspace files (`--ingest` uploads then queues ingestion) |
|
|
56
57
|
| `ndi ingest` | Queue ingestion |
|
|
57
58
|
| `ndi deep-search QUERY` / `ndi fact-search QUERY` | Agentic / single-shot search |
|
|
59
|
+
| `ndi je-testing QUERY` | Journal-entry testing over a ledger package (`--path` to scope it, `--effort` for the level) |
|
|
58
60
|
| `ndi folder-metadata` / `file-metadata` / `read-file` / `ask-file` / `run-sql` / `hybrid-search` | Read-only workspace tools (the sandbox surface) |
|
|
59
61
|
|
|
60
62
|
## Sources
|
|
@@ -84,4 +86,5 @@ API failures exit 1. Usage / config errors exit 2. Schema-validation
|
|
|
84
86
|
failures also show up to five field constraints, each limited to 500
|
|
85
87
|
characters; request input and unrelated error-detail fields are omitted.
|
|
86
88
|
|
|
87
|
-
See
|
|
89
|
+
See the [CLI guide](https://docs.ndi.nace.ai/guides/cli) for the full command
|
|
90
|
+
reference. `SKILL.md` is the agent-facing guide to the six workspace tools.
|
|
@@ -32,6 +32,7 @@ config location. Workspace-scoped verbs also take `--workspace ID`.
|
|
|
32
32
|
| `ndi files upload\|list\|get\|delete` | Workspace files (`--ingest` uploads then queues ingestion) |
|
|
33
33
|
| `ndi ingest` | Queue ingestion |
|
|
34
34
|
| `ndi deep-search QUERY` / `ndi fact-search QUERY` | Agentic / single-shot search |
|
|
35
|
+
| `ndi je-testing QUERY` | Journal-entry testing over a ledger package (`--path` to scope it, `--effort` for the level) |
|
|
35
36
|
| `ndi folder-metadata` / `file-metadata` / `read-file` / `ask-file` / `run-sql` / `hybrid-search` | Read-only workspace tools (the sandbox surface) |
|
|
36
37
|
|
|
37
38
|
## Sources
|
|
@@ -61,4 +62,5 @@ API failures exit 1. Usage / config errors exit 2. Schema-validation
|
|
|
61
62
|
failures also show up to five field constraints, each limited to 500
|
|
62
63
|
characters; request input and unrelated error-detail fields are omitted.
|
|
63
64
|
|
|
64
|
-
See
|
|
65
|
+
See the [CLI guide](https://docs.ndi.nace.ai/guides/cli) for the full command
|
|
66
|
+
reference. `SKILL.md` is the agent-facing guide to the six workspace tools.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ndi-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.7.0"
|
|
4
4
|
description = "NDI platform CLI: document operations, jobs, workspaces, and the agent workspace tools"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "MIT"
|
|
@@ -23,7 +23,10 @@ classifiers = [
|
|
|
23
23
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
24
24
|
"Typing :: Typed",
|
|
25
25
|
]
|
|
26
|
-
dependencies = [
|
|
26
|
+
dependencies = [
|
|
27
|
+
"ndi-sdk>=0.22,<1",
|
|
28
|
+
"truststore>=0.10.4,<1",
|
|
29
|
+
]
|
|
27
30
|
|
|
28
31
|
[[project.authors]]
|
|
29
32
|
name = "Nace AI"
|
|
@@ -33,7 +36,7 @@ email = "engineering@nace.ai"
|
|
|
33
36
|
Homepage = "https://ndi-api.nace.ai"
|
|
34
37
|
|
|
35
38
|
[project.scripts]
|
|
36
|
-
ndi = "ndi_cli.
|
|
39
|
+
ndi = "ndi_cli._entrypoint:main"
|
|
37
40
|
|
|
38
41
|
[tool.uv.sources.ndi-sdk]
|
|
39
42
|
workspace = true
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "ndi-cli"
|
|
3
|
-
version = "0.
|
|
3
|
+
version = "0.7.0"
|
|
4
4
|
description = "NDI platform CLI: document operations, jobs, workspaces, and the agent workspace tools"
|
|
5
5
|
authors = [
|
|
6
6
|
{ name = "Nace AI", email = "engineering@nace.ai" }
|
|
@@ -27,14 +27,15 @@ classifiers = [
|
|
|
27
27
|
"Typing :: Typed",
|
|
28
28
|
]
|
|
29
29
|
dependencies = [
|
|
30
|
-
"ndi-sdk>=0.
|
|
30
|
+
"ndi-sdk>=0.22,<1",
|
|
31
|
+
"truststore>=0.10.4,<1",
|
|
31
32
|
]
|
|
32
33
|
|
|
33
34
|
[project.urls]
|
|
34
35
|
Homepage = "https://ndi-api.nace.ai"
|
|
35
36
|
|
|
36
37
|
[project.scripts]
|
|
37
|
-
ndi = "ndi_cli.
|
|
38
|
+
ndi = "ndi_cli._entrypoint:main"
|
|
38
39
|
|
|
39
40
|
[tool.uv.sources]
|
|
40
41
|
ndi-sdk = { workspace = true }
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"""Bootstrap the ``ndi`` executable with the operating system trust store."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import truststore
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def main(argv: list[str] | None = None) -> int:
|
|
9
|
+
"""Enable native certificate verification before loading the CLI and SDK."""
|
|
10
|
+
truststore.inject_into_ssl()
|
|
11
|
+
|
|
12
|
+
from ndi_cli._cli import main as cli_main # noqa: PLC0415
|
|
13
|
+
|
|
14
|
+
return cli_main(argv)
|
|
@@ -6,7 +6,7 @@ import sys
|
|
|
6
6
|
from collections.abc import Callable
|
|
7
7
|
from pathlib import Path
|
|
8
8
|
|
|
9
|
-
from ndi_sdk.models.jobs import IngestionResult, Job, ParseResult
|
|
9
|
+
from ndi_sdk.models.jobs import IngestionResult, JetResult, Job, ParseResult
|
|
10
10
|
|
|
11
11
|
OUTPUT_CHOICES = ("auto", "md", "json", "payload", "id")
|
|
12
12
|
|
|
@@ -108,6 +108,13 @@ def _content_failure(job: Job) -> int:
|
|
|
108
108
|
file=sys.stderr,
|
|
109
109
|
)
|
|
110
110
|
return 1
|
|
111
|
+
# A degraded JET run is the same shape: succeeded, but the procedure broke
|
|
112
|
+
# before it could finalize an answer, so `figures` is empty and only the
|
|
113
|
+
# working survives. `exhausted` and `partially_performed` stay zero — both
|
|
114
|
+
# are documented as successful partial answers, not failed work.
|
|
115
|
+
if isinstance(result, JetResult) and result.degraded:
|
|
116
|
+
print(f"error: journal-entry testing degraded: {result.degraded}", file=sys.stderr)
|
|
117
|
+
return 1
|
|
111
118
|
return 0
|
|
112
119
|
|
|
113
120
|
|
|
@@ -24,6 +24,7 @@ from ndi_sdk.models.jobs import (
|
|
|
24
24
|
GroundResult,
|
|
25
25
|
IngestionResult,
|
|
26
26
|
IntelligentSearchResult,
|
|
27
|
+
JetResult,
|
|
27
28
|
Job,
|
|
28
29
|
ParseResult,
|
|
29
30
|
SplitResult,
|
|
@@ -662,6 +663,49 @@ def search_job(job: Job) -> str:
|
|
|
662
663
|
return job_line(job)
|
|
663
664
|
|
|
664
665
|
|
|
666
|
+
def je_testing_job(job: Job) -> str:
|
|
667
|
+
"""The answer, then the numbers behind it — a JET result read at a glance.
|
|
668
|
+
|
|
669
|
+
Unlike :func:`search_job` this leads with ``figures``: the answer is prose a
|
|
670
|
+
person reads, and the figures are the same content a reviewer can check.
|
|
671
|
+
Each one names the receipt its numbers are readable out of, so
|
|
672
|
+
``ndi job <id> -o json`` is the next step rather than the only one.
|
|
673
|
+
"""
|
|
674
|
+
result = job.result
|
|
675
|
+
if not isinstance(result, JetResult):
|
|
676
|
+
return job_line(job)
|
|
677
|
+
lines: list[str] = []
|
|
678
|
+
if result.degraded:
|
|
679
|
+
lines.append(f"degraded: {result.degraded}")
|
|
680
|
+
if result.answer:
|
|
681
|
+
lines.append(result.answer.strip())
|
|
682
|
+
if result.population_statement:
|
|
683
|
+
lines.append(f"population: {result.population_statement}")
|
|
684
|
+
if result.figures:
|
|
685
|
+
lines.append(f"figures ({len(result.figures)}):")
|
|
686
|
+
for figure in result.figures:
|
|
687
|
+
if figure.cannot_be_performed:
|
|
688
|
+
lines.append(f" {figure.criterion}: not performed")
|
|
689
|
+
else:
|
|
690
|
+
value = f" | {figure.value}" if figure.value else ""
|
|
691
|
+
lines.append(f" {figure.criterion}: {figure.count}/{figure.population}{value}")
|
|
692
|
+
# The exception listing is the receipt worth opening: an unfiltered
|
|
693
|
+
# count points at every row, a listing points at the rows that failed.
|
|
694
|
+
receipt = figure.exception_listing_result_id or next(iter(figure.result_ids), None)
|
|
695
|
+
if receipt:
|
|
696
|
+
lines.append(f" receipt {receipt}")
|
|
697
|
+
for discrepancy in result.discrepancies:
|
|
698
|
+
lines.append(f"discrepancy: {discrepancy}")
|
|
699
|
+
lines.append(f"evidences ({len(result.evidences)}) | receipts ({len(result.sql_receipts)})")
|
|
700
|
+
if result.execution_status and result.execution_status != "performed":
|
|
701
|
+
lines.append(f"execution: {result.execution_status}")
|
|
702
|
+
if result.quality and result.quality.status != "clean":
|
|
703
|
+
lines.append(f"quality: {result.quality.status}")
|
|
704
|
+
if result.exhausted:
|
|
705
|
+
lines.append("exhausted: step budget ran out before the procedure finished")
|
|
706
|
+
return "\n".join(lines)
|
|
707
|
+
|
|
708
|
+
|
|
665
709
|
def _search_result(answer: str | None, clarification: str | None, evidences: list, *, receipts: int) -> str:
|
|
666
710
|
lines: list[str] = []
|
|
667
711
|
if clarification:
|
|
@@ -95,6 +95,17 @@ def add_parsers(sub: argparse._SubParsersAction, common: argparse.ArgumentParser
|
|
|
95
95
|
add_job_output_args(fact)
|
|
96
96
|
fact.set_defaults(run=_run_fact_search, family="workspace", needs_workspace=True, needs_client=True)
|
|
97
97
|
|
|
98
|
+
jet = sub.add_parser("je-testing", parents=[common], help="Run journal-entry testing over a ledger package.")
|
|
99
|
+
jet.add_argument("query")
|
|
100
|
+
jet.add_argument("--effort", choices=("low", "medium", "high"), default=None)
|
|
101
|
+
jet.add_argument("--prefix", default=None, dest="path_prefix")
|
|
102
|
+
jet.add_argument("--path", action="append", dest="paths", default=None, help="Scope to this file; repeatable.")
|
|
103
|
+
jet.add_argument("--context", default=None)
|
|
104
|
+
# No --session-id, for the reason deep-search omits it: a shell has nowhere
|
|
105
|
+
# to keep a thread. Omitting --effort leaves the deployment's own floor.
|
|
106
|
+
add_job_output_args(jet)
|
|
107
|
+
jet.set_defaults(run=_run_je_testing, family="workspace", needs_workspace=True, needs_client=True)
|
|
108
|
+
|
|
98
109
|
|
|
99
110
|
def _workspace_id(args: argparse.Namespace, fallback: str) -> str:
|
|
100
111
|
value = getattr(args, "workspace_id", None) or args.workspace or fallback
|
|
@@ -224,3 +235,15 @@ def _run_fact_search(client: NdiClient, workspace_id: str, args: argparse.Namesp
|
|
|
224
235
|
top_k=args.top_k,
|
|
225
236
|
)
|
|
226
237
|
return _finish_job(client, job, args, _render.search_job, "fact-search")
|
|
238
|
+
|
|
239
|
+
|
|
240
|
+
def _run_je_testing(client: NdiClient, workspace_id: str, args: argparse.Namespace) -> int:
|
|
241
|
+
job = client.search.je_testing(
|
|
242
|
+
workspace_id,
|
|
243
|
+
query=args.query,
|
|
244
|
+
context=args.context,
|
|
245
|
+
effort=args.effort,
|
|
246
|
+
path_prefix=args.path_prefix,
|
|
247
|
+
paths=args.paths,
|
|
248
|
+
)
|
|
249
|
+
return _finish_job(client, job, args, _render.je_testing_job, "je-testing")
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|