ctxprotocol 0.19.0__tar.gz → 0.19.1__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.
Files changed (54) hide show
  1. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/CHANGELOG.md +4 -0
  2. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/PKG-INFO +1 -1
  3. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/__init__.py +1 -1
  4. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/client/resources/query.py +4 -2
  5. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/pyproject.toml +1 -1
  6. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/tests/test_query.py +33 -4
  7. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/uv.lock +1 -1
  8. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/.codexignore +0 -0
  9. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/.gitignore +0 -0
  10. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/README.md +0 -0
  11. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/auth/__init__.py +0 -0
  12. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/client/__init__.py +0 -0
  13. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/client/client.py +0 -0
  14. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/client/resources/__init__.py +0 -0
  15. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/client/resources/developer.py +0 -0
  16. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/client/resources/discovery.py +0 -0
  17. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/client/resources/tools.py +0 -0
  18. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/client/types.py +0 -0
  19. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/context/__init__.py +0 -0
  20. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/context/hyperliquid.py +0 -0
  21. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/context/polymarket.py +0 -0
  22. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/context/wallet.py +0 -0
  23. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/contrib/__init__.py +0 -0
  24. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/contrib/search/__init__.py +0 -0
  25. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/contrib/search/core.py +0 -0
  26. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/contrib/search/trace.py +0 -0
  27. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/contrib/search/types.py +0 -0
  28. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/contrib/search/validation.py +0 -0
  29. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/handshake/__init__.py +0 -0
  30. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/ctxprotocol/py.typed +0 -0
  31. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/docs/README.md +0 -0
  32. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/examples/client/execute_client.py +0 -0
  33. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/examples/client/polymarket_query_trace_validation.py +0 -0
  34. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/examples/client/query_client.py +0 -0
  35. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/examples/client/test_favorites_only.py +0 -0
  36. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/examples/client/test_get_tool.py +0 -0
  37. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/examples/client/two_surfaces_client.py +0 -0
  38. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/examples/client/validation/generate_contributor_search_validation_artifacts.py +0 -0
  39. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/examples/client/validation/named-regression-iran-boots-on-ground.json +0 -0
  40. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/examples/client/validation/named-regression-supreme-court-tariffs.json +0 -0
  41. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/examples/client/validation/shared-capability-miss-unsupported-venue.json +0 -0
  42. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/examples/client/validation/shared-generic-overlap-best-match.json +0 -0
  43. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/examples/client/validation/shared-still-ambiguous-shortlist.json +0 -0
  44. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/examples/server/hummingbot-contributor/README.md +0 -0
  45. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/examples/server/hummingbot-contributor/env.example +0 -0
  46. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/examples/server/hummingbot-contributor/requirements.txt +0 -0
  47. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/examples/server/hummingbot-contributor/server.py +0 -0
  48. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/polymarket-query-trace-results-py.json +0 -0
  49. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/tests/__init__.py +0 -0
  50. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/tests/contrib_search_validation_cases.py +0 -0
  51. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/tests/test_client.py +0 -0
  52. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/tests/test_contrib_search.py +0 -0
  53. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/tests/test_discovery.py +0 -0
  54. {ctxprotocol-0.19.0 → ctxprotocol-0.19.1}/tests/test_tools.py +0 -0
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.19.1
4
+
5
+ - Fixed `client.query.start()` returning `400 "Invalid query job request"` when called without explicit `tools`. The request body builder now omits optional fields (notably `tools`) when unset instead of serializing them as JSON `null`; the durable jobs endpoint's Zod schema rejects `null` for optional fields. `client.query.run()` and `client.query.stream()` were not failing (the `/api/v1/query` endpoint tolerates `null`), but are now consistent with the TS SDK and MCP behavior.
6
+
3
7
  ## 0.19.0
4
8
 
5
9
  - Fixed `client.query.run()`/`client.query.stream()` raising a `ValidationError` on queries that returned a rendered image artifact (e.g. server-rendered chart PNGs). `computedArtifacts` now accepts both `chart` (structured spec + data) and `image` (hosted URL) variants.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ctxprotocol
3
- Version: 0.19.0
3
+ Version: 0.19.1
4
4
  Summary: Official Python SDK for the Context Protocol - Discover and execute AI tools programmatically
5
5
  Project-URL: Homepage, https://ctxprotocol.com
6
6
  Project-URL: Documentation, https://docs.ctxprotocol.com
@@ -31,7 +31,7 @@ Example:
31
31
  For more information, visit: https://ctxprotocol.com
32
32
  """
33
33
 
34
- __version__ = "0.19.0"
34
+ __version__ = "0.19.1"
35
35
 
36
36
  # Re-export everything from client module
37
37
  from ctxprotocol.client import (
@@ -62,8 +62,9 @@ class Query:
62
62
  ) -> dict[str, Any]:
63
63
  request_body: dict[str, Any] = {
64
64
  "query": query,
65
- "tools": tools,
66
65
  }
66
+ if tools is not None:
67
+ request_body["tools"] = tools
67
68
  if stream is not None:
68
69
  request_body["stream"] = stream
69
70
  if resume_from is not None:
@@ -443,9 +444,10 @@ class Query:
443
444
  """
444
445
  request_body: dict[str, Any] = {
445
446
  "query": query,
446
- "tools": tools,
447
447
  "stream": True,
448
448
  }
449
+ if tools is not None:
450
+ request_body["tools"] = tools
449
451
  if resume_from is not None:
450
452
  request_body["resumeFrom"] = (
451
453
  resume_from.model_dump(by_alias=True, exclude_none=True)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "ctxprotocol"
7
- version = "0.19.0"
7
+ version = "0.19.1"
8
8
  description = "Official Python SDK for the Context Protocol - Discover and execute AI tools programmatically"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -420,7 +420,6 @@ class TestQueryRun:
420
420
  method="POST",
421
421
  json_body={
422
422
  "query": "What are the top whale movements?",
423
- "tools": None,
424
423
  "stream": True,
425
424
  },
426
425
  extra_headers=None,
@@ -480,7 +479,6 @@ class TestQueryRun:
480
479
  method="POST",
481
480
  json_body={
482
481
  "query": "Analyze whale activity",
483
- "tools": None,
484
482
  "stream": True,
485
483
  "agentModelId": "kimi-k2.6-model",
486
484
  "responseShape": "answer_with_evidence",
@@ -1091,7 +1089,6 @@ class TestQueryStream:
1091
1089
  method="POST",
1092
1090
  json_body={
1093
1091
  "query": "What are whale movements?",
1094
- "tools": None,
1095
1092
  "stream": True,
1096
1093
  },
1097
1094
  extra_headers=None,
@@ -1534,7 +1531,6 @@ class TestQueryJobs:
1534
1531
  method="POST",
1535
1532
  json_body={
1536
1533
  "query": "long query",
1537
- "tools": None,
1538
1534
  "stream": False,
1539
1535
  "responseShape": "evidence_only",
1540
1536
  "includeDataUrl": True,
@@ -1544,6 +1540,39 @@ class TestQueryJobs:
1544
1540
  },
1545
1541
  )
1546
1542
 
1543
+ async def test_start_omits_null_optional_fields(self) -> None:
1544
+ """Regression: optional fields must be absent (not JSON null) in the job body.
1545
+
1546
+ The /api/v1/query/jobs endpoint validates the body with a Zod schema whose
1547
+ optional fields accept `undefined`/absent but reject `null`. Sending
1548
+ `"tools": null` (as the SDK previously did) made query.start() 400 with
1549
+ "Invalid query job request". Optional fields must be omitted when unset,
1550
+ matching the TS SDK (JSON.stringify drops undefined keys).
1551
+ """
1552
+ client = ContextClient(api_key="ctx_test_key_1234567890abcdef12345678")
1553
+ payload = {
1554
+ "status": "running",
1555
+ "jobId": "11111111-1111-4111-8111-111111111111",
1556
+ "pollingTool": "context_query_status",
1557
+ "message": "running",
1558
+ "progress": None,
1559
+ "querySession": None,
1560
+ "createdAt": "2026-06-14T00:00:00.000Z",
1561
+ "updatedAt": "2026-06-14T00:00:00.000Z",
1562
+ }
1563
+
1564
+ with patch.object(client, "fetch", new_callable=AsyncMock) as mock_fetch:
1565
+ mock_fetch.return_value = payload
1566
+ await client.query.start(query="long query")
1567
+
1568
+ body = mock_fetch.call_args.kwargs["json_body"]
1569
+ # No optional field may serialize to JSON null.
1570
+ assert all(value is not None for value in body.values()), body
1571
+ # tools specifically must be omitted when not supplied (was the 400 trigger).
1572
+ assert "tools" not in body, body
1573
+ # query is always present and non-null.
1574
+ assert body["query"] == "long query"
1575
+
1547
1576
  async def test_get_status_fetches_query_job(self) -> None:
1548
1577
  client = ContextClient(api_key="ctx_test_key_1234567890abcdef12345678")
1549
1578
  payload = {
@@ -205,7 +205,7 @@ wheels = [
205
205
 
206
206
  [[package]]
207
207
  name = "ctxprotocol"
208
- version = "0.19.0"
208
+ version = "0.19.1"
209
209
  source = { editable = "." }
210
210
  dependencies = [
211
211
  { name = "cryptography" },
File without changes
File without changes
File without changes