nodloop 0.7.0__tar.gz → 0.8.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.
- {nodloop-0.7.0 → nodloop-0.8.0}/PKG-INFO +2 -2
- {nodloop-0.7.0 → nodloop-0.8.0}/README.md +1 -1
- {nodloop-0.7.0 → nodloop-0.8.0}/pyproject.toml +1 -1
- {nodloop-0.7.0 → nodloop-0.8.0}/src/nodloop/client.py +10 -4
- {nodloop-0.7.0 → nodloop-0.8.0}/tests/test_client.py +13 -0
- {nodloop-0.7.0 → nodloop-0.8.0}/uv.lock +7 -7
- {nodloop-0.7.0 → nodloop-0.8.0}/.gitignore +0 -0
- {nodloop-0.7.0 → nodloop-0.8.0}/src/nodloop/__init__.py +0 -0
- {nodloop-0.7.0 → nodloop-0.8.0}/src/nodloop/binary.py +0 -0
- {nodloop-0.7.0 → nodloop-0.8.0}/src/nodloop/claude_agent.py +0 -0
- {nodloop-0.7.0 → nodloop-0.8.0}/src/nodloop/langchain.py +0 -0
- {nodloop-0.7.0 → nodloop-0.8.0}/src/nodloop/openai_agents.py +0 -0
- {nodloop-0.7.0 → nodloop-0.8.0}/tests/conftest.py +0 -0
- {nodloop-0.7.0 → nodloop-0.8.0}/tests/test_adapters.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: nodloop
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.8.0
|
|
4
4
|
Summary: Record AI runs and the verdicts people give on them, and hand the knowledge they approve to the next run in the same place
|
|
5
5
|
Project-URL: Homepage, https://github.com/jeon-jihyeon/nodloop
|
|
6
6
|
Project-URL: Repository, https://github.com/jeon-jihyeon/nodloop
|
|
@@ -54,7 +54,7 @@ From then on every `knowledge("support-bot", acme)` carries the item, and a run
|
|
|
54
54
|
| `record(producer, output, *, labels, applied, subject)` | the run id a verdict cites |
|
|
55
55
|
| `judge(run, verdict, reason, reason_code, edited, reviewer)` | nothing |
|
|
56
56
|
| `propose(kind, content, from_run, producer, labels, new_labels, item_id, veto)` | `Candidate` with `id`, `version`, `status` and `overlaps`, the current items of the same kind one run may carry with it |
|
|
57
|
-
| `approve(item_id, version, approver)` | `Approval` with `id`, `version`, `status`, `approver`, `veto`, `compaction_due` when one run would carry more than five items, and `export_error` and `folder_error` when a step after the approval failed |
|
|
57
|
+
| `approve(item_id, version, approver, labels=)` | Approves as proposed, or for the runs carrying `labels` when given, and `{}` for every run of the producer. `Approval` with `id`, `version`, `status`, `approver`, `veto`, `compaction_due` when one run would carry more than five items, and `export_error` and `folder_error` when a step after the approval failed |
|
|
58
58
|
| `check_call(tool, arguments, producer)` | `Decision` with `action` of allow, block or ask, `veto` and `reason` |
|
|
59
59
|
|
|
60
60
|
A tool that refuses, such as a proposal from a run nobody corrected, raises `ToolError` with the reason.
|
|
@@ -36,7 +36,7 @@ From then on every `knowledge("support-bot", acme)` carries the item, and a run
|
|
|
36
36
|
| `record(producer, output, *, labels, applied, subject)` | the run id a verdict cites |
|
|
37
37
|
| `judge(run, verdict, reason, reason_code, edited, reviewer)` | nothing |
|
|
38
38
|
| `propose(kind, content, from_run, producer, labels, new_labels, item_id, veto)` | `Candidate` with `id`, `version`, `status` and `overlaps`, the current items of the same kind one run may carry with it |
|
|
39
|
-
| `approve(item_id, version, approver)` | `Approval` with `id`, `version`, `status`, `approver`, `veto`, `compaction_due` when one run would carry more than five items, and `export_error` and `folder_error` when a step after the approval failed |
|
|
39
|
+
| `approve(item_id, version, approver, labels=)` | Approves as proposed, or for the runs carrying `labels` when given, and `{}` for every run of the producer. `Approval` with `id`, `version`, `status`, `approver`, `veto`, `compaction_due` when one run would carry more than five items, and `export_error` and `folder_error` when a step after the approval failed |
|
|
40
40
|
| `check_call(tool, arguments, producer)` | `Decision` with `action` of allow, block or ask, `veto` and `reason` |
|
|
41
41
|
|
|
42
42
|
A tool that refuses, such as a proposal from a run nobody corrected, raises `ToolError` with the reason.
|
|
@@ -17,7 +17,7 @@ from . import binary
|
|
|
17
17
|
__all__ = ["Approval", "Candidate", "Client", "Decision", "Item", "Knowledge", "ToolError"]
|
|
18
18
|
|
|
19
19
|
# The binary release the client fetches when no nodloop is installed
|
|
20
|
-
VERSION = "0.
|
|
20
|
+
VERSION = "0.8.0"
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
class ToolError(RuntimeError):
|
|
@@ -225,9 +225,15 @@ class Client:
|
|
|
225
225
|
answer = await self.call("propose", args)
|
|
226
226
|
return Candidate(answer["id"], answer["version"], answer["status"], answer.get("overlaps") or [])
|
|
227
227
|
|
|
228
|
-
async def approve(self, item_id: str, version: int, approver: str) -> Approval:
|
|
229
|
-
"""Approves a candidate on behalf of the named person
|
|
230
|
-
|
|
228
|
+
async def approve(self, item_id: str, version: int, approver: str, *, labels: dict[str, list[str]] | None = None) -> Approval:
|
|
229
|
+
"""Approves a candidate on behalf of the named person
|
|
230
|
+
|
|
231
|
+
labels approves it for the runs carrying them instead of the proposed scope and an empty mapping for every run of its producer
|
|
232
|
+
"""
|
|
233
|
+
args: dict[str, Any] = {"id": item_id, "version": version, "approver": approver}
|
|
234
|
+
if labels is not None:
|
|
235
|
+
args["scope"] = {"labels": labels}
|
|
236
|
+
answer = await self.call("approve", args)
|
|
231
237
|
return Approval(
|
|
232
238
|
answer["id"],
|
|
233
239
|
answer["version"],
|
|
@@ -96,3 +96,16 @@ async def test_approval_says_a_compaction_is_due(binary: str, records: str) -> N
|
|
|
96
96
|
|
|
97
97
|
assert [a.compaction_due for a in approvals] == [False] * 5 + [True]
|
|
98
98
|
assert all(a.folder_error == "" for a in approvals)
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
async def test_approve_in_picked_labels(binary: str, records: str) -> None:
|
|
102
|
+
async with Client(records, binary) as c:
|
|
103
|
+
run = await c.record("support-bot", "Here are the refund steps", labels=ACME)
|
|
104
|
+
await c.record("support-bot", "ok", labels={"tenant": ["globex"]})
|
|
105
|
+
await c.judge(run, "reject", reason="too long", reason_code="form")
|
|
106
|
+
proposed = await c.propose("judgment", "Answer in three lines", from_run=run)
|
|
107
|
+
approved = await c.approve(proposed.id, proposed.version, "ann", labels={})
|
|
108
|
+
globex = await c.knowledge("support-bot", {"tenant": ["globex"]})
|
|
109
|
+
|
|
110
|
+
assert approved.status == "approved"
|
|
111
|
+
assert [i.id for i in globex.items] == [proposed.id]
|
|
@@ -337,7 +337,7 @@ wheels = [
|
|
|
337
337
|
|
|
338
338
|
[[package]]
|
|
339
339
|
name = "claude-agent-sdk"
|
|
340
|
-
version = "0.2.
|
|
340
|
+
version = "0.2.162"
|
|
341
341
|
source = { registry = "https://pypi.org/simple" }
|
|
342
342
|
dependencies = [
|
|
343
343
|
{ name = "anyio" },
|
|
@@ -346,12 +346,12 @@ dependencies = [
|
|
|
346
346
|
{ name = "sniffio" },
|
|
347
347
|
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
|
348
348
|
]
|
|
349
|
-
sdist = { url = "https://files.pythonhosted.org/packages/
|
|
349
|
+
sdist = { url = "https://files.pythonhosted.org/packages/78/a3/d31886d0723593228797c96eb54d07a19e561931a2771ed40b4a105bedc9/claude_agent_sdk-0.2.162.tar.gz", hash = "sha256:e4cf92f04f934d3b87d42be9ecbeb75c1a3d487a8dc8a299f7fed1ad9d0b476f", size = 365167, upload-time = "2026-09-29T20:06:54.593Z" }
|
|
350
350
|
wheels = [
|
|
351
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
352
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
353
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
354
|
-
{ url = "https://files.pythonhosted.org/packages/
|
|
351
|
+
{ url = "https://files.pythonhosted.org/packages/6d/b6/ec37e32cb0782977e80cd00338f5073f150d6ecfa568e9fa1a1dd5c9eed3/claude_agent_sdk-0.2.162-py3-none-macosx_11_0_arm64.whl", hash = "sha256:a0d5ad6185a8bcaaff05f5648036e2484cab28bd1c2ccc474fc8969555b386f7", size = 92700771, upload-time = "2026-09-29T20:06:59.661Z" },
|
|
352
|
+
{ url = "https://files.pythonhosted.org/packages/92/c4/1165688243cbf90d3532f509ea65bc337c3ba7f8229e26d7297e00a6ec2b/claude_agent_sdk-0.2.162-py3-none-macosx_11_0_x86_64.whl", hash = "sha256:faab97b03f04f9c3deb58ad85a0410404d40b6efb5547c9defc4fa986642fced", size = 97130408, upload-time = "2026-09-29T20:07:06.243Z" },
|
|
353
|
+
{ url = "https://files.pythonhosted.org/packages/05/41/f0addb831c3aefbc02c811ef7415e89e889d1bc2ae976eb935c508c91c0d/claude_agent_sdk-0.2.162-py3-none-manylinux_2_17_aarch64.whl", hash = "sha256:332cfb5eb9190fc8de1ad427753417d7c345264e9d2bd2ffa312afcc2f5cf766", size = 102183342, upload-time = "2026-09-29T20:07:14.279Z" },
|
|
354
|
+
{ url = "https://files.pythonhosted.org/packages/d2/33/8a7acd75405d0cfde96c26219dbbac050aa23416ceefd5f62cf7aecfc22d/claude_agent_sdk-0.2.162-py3-none-manylinux_2_17_x86_64.whl", hash = "sha256:673598c9916f5f4d03ff49ab3128f856f0c6508135e8e258838fc3b6f7aafa49", size = 102525631, upload-time = "2026-09-29T20:07:23.411Z" },
|
|
355
355
|
]
|
|
356
356
|
|
|
357
357
|
[[package]]
|
|
@@ -899,7 +899,7 @@ wheels = [
|
|
|
899
899
|
|
|
900
900
|
[[package]]
|
|
901
901
|
name = "nodloop"
|
|
902
|
-
version = "0.
|
|
902
|
+
version = "0.8.0"
|
|
903
903
|
source = { editable = "." }
|
|
904
904
|
dependencies = [
|
|
905
905
|
{ name = "mcp" },
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|