stata-code 0.6.4__tar.gz → 0.6.5__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 (57) hide show
  1. {stata_code-0.6.4 → stata_code-0.6.5}/CHANGELOG.md +10 -0
  2. {stata_code-0.6.4 → stata_code-0.6.5}/PKG-INFO +14 -1
  3. {stata_code-0.6.4 → stata_code-0.6.5}/README.md +13 -0
  4. {stata_code-0.6.4 → stata_code-0.6.5}/pyproject.toml +1 -1
  5. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/__init__.py +1 -1
  6. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/mcp/server.py +1 -21
  7. {stata_code-0.6.4 → stata_code-0.6.5}/tests/test_mcp.py +18 -15
  8. {stata_code-0.6.4 → stata_code-0.6.5}/.gitignore +0 -0
  9. {stata_code-0.6.4 → stata_code-0.6.5}/LICENSE +0 -0
  10. {stata_code-0.6.4 → stata_code-0.6.5}/LICENSE-POLICY.md +0 -0
  11. {stata_code-0.6.4 → stata_code-0.6.5}/PUBLISHING.md +0 -0
  12. {stata_code-0.6.4 → stata_code-0.6.5}/SCHEMA.md +0 -0
  13. {stata_code-0.6.4 → stata_code-0.6.5}/docs/design/hard_timeout.md +0 -0
  14. {stata_code-0.6.4 → stata_code-0.6.5}/examples/01-basic-regression.md +0 -0
  15. {stata_code-0.6.4 → stata_code-0.6.5}/examples/02-did-card-krueger.md +0 -0
  16. {stata_code-0.6.4 → stata_code-0.6.5}/examples/03-graphs.md +0 -0
  17. {stata_code-0.6.4 → stata_code-0.6.5}/examples/04-multi-session.md +0 -0
  18. {stata_code-0.6.4 → stata_code-0.6.5}/examples/05-large-matrix.md +0 -0
  19. {stata_code-0.6.4 → stata_code-0.6.5}/examples/README.md +0 -0
  20. {stata_code-0.6.4 → stata_code-0.6.5}/schema/run_result.schema.json +0 -0
  21. {stata_code-0.6.4 → stata_code-0.6.5}/scripts/check_versions.py +0 -0
  22. {stata_code-0.6.4 → stata_code-0.6.5}/scripts/export_schema.py +0 -0
  23. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/core/__init__.py +0 -0
  24. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/core/_pool.py +0 -0
  25. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/core/_refs.py +0 -0
  26. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/core/_runtime.py +0 -0
  27. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/core/errors.py +0 -0
  28. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/core/log_artifacts.py +0 -0
  29. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/core/notebook.py +0 -0
  30. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/core/run_index.py +0 -0
  31. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/core/runner.py +0 -0
  32. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/core/schema.py +0 -0
  33. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/kernel/__init__.py +0 -0
  34. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/kernel/__main__.py +0 -0
  35. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/kernel/assets/logo-32x32.png +0 -0
  36. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/kernel/assets/logo-64x64.png +0 -0
  37. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/kernel/assets/logo-svg.svg +0 -0
  38. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/kernel/kernel.py +0 -0
  39. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/mcp/__init__.py +0 -0
  40. {stata_code-0.6.4 → stata_code-0.6.5}/stata_code/mcp/__main__.py +0 -0
  41. {stata_code-0.6.4 → stata_code-0.6.5}/tests/__init__.py +0 -0
  42. {stata_code-0.6.4 → stata_code-0.6.5}/tests/conftest.py +0 -0
  43. {stata_code-0.6.4 → stata_code-0.6.5}/tests/fixtures/.gitkeep +0 -0
  44. {stata_code-0.6.4 → stata_code-0.6.5}/tests/test_cancel.py +0 -0
  45. {stata_code-0.6.4 → stata_code-0.6.5}/tests/test_errors.py +0 -0
  46. {stata_code-0.6.4 → stata_code-0.6.5}/tests/test_kernel.py +0 -0
  47. {stata_code-0.6.4 → stata_code-0.6.5}/tests/test_log_artifacts.py +0 -0
  48. {stata_code-0.6.4 → stata_code-0.6.5}/tests/test_mcp_stdio.py +0 -0
  49. {stata_code-0.6.4 → stata_code-0.6.5}/tests/test_notebook.py +0 -0
  50. {stata_code-0.6.4 → stata_code-0.6.5}/tests/test_notebook_phase2.py +0 -0
  51. {stata_code-0.6.4 → stata_code-0.6.5}/tests/test_pool.py +0 -0
  52. {stata_code-0.6.4 → stata_code-0.6.5}/tests/test_public_api.py +0 -0
  53. {stata_code-0.6.4 → stata_code-0.6.5}/tests/test_run_index.py +0 -0
  54. {stata_code-0.6.4 → stata_code-0.6.5}/tests/test_runner.py +0 -0
  55. {stata_code-0.6.4 → stata_code-0.6.5}/tests/test_runtime_discovery.py +0 -0
  56. {stata_code-0.6.4 → stata_code-0.6.5}/tests/test_schema.py +0 -0
  57. {stata_code-0.6.4 → stata_code-0.6.5}/tests/test_schema_artifact.py +0 -0
@@ -6,6 +6,16 @@ to semver-major.minor for the result schema (see `SCHEMA.md` §6).
6
6
 
7
7
  ## Unreleased
8
8
 
9
+ ## 0.6.5 — 2026-05-22
10
+
11
+ ### Fixed
12
+
13
+ - **OpenAI tool-schema compatibility.** `notebook_locate` and
14
+ `notebook_insert_cell` no longer advertise top-level `oneOf` constraints in
15
+ their MCP input schemas. OpenAI rejects those schemas during tool
16
+ registration, while the server-side runtime guards still enforce the
17
+ "exactly one query/anchor" rules.
18
+
9
19
  ## 0.6.4 — 2026-05-21
10
20
 
11
21
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: stata-code
3
- Version: 0.6.4
3
+ Version: 0.6.5
4
4
  Summary: Agent-native Stata bridge — one core, multiple frontends (MCP, Jupyter, VSCode)
5
5
  Project-URL: Homepage, https://github.com/brycewang-stanford/stata-code
6
6
  Project-URL: Repository, https://github.com/brycewang-stanford/stata-code
@@ -263,6 +263,19 @@ When `stata-code-mcp` lives inside a project virtualenv (recommended for reprodu
263
263
 
264
264
  For `uvx`-only setups, set `"command": "uvx"` and `"args": ["--from", "stata-code", "stata-code-mcp"]`.
265
265
 
266
+ #### MCP troubleshooting
267
+
268
+ If `stata_run` reports `adapter_crash` with `worker emitted non-JSON: '\n'`,
269
+ upgrade to `stata-code>=0.6.4`, then restart the MCP client so it launches a
270
+ fresh server process. Also check that the client is resolving the expected
271
+ `stata-code-mcp` binary; project virtualenv installs should use the absolute
272
+ `.venv/bin/stata-code-mcp` path instead of relying on a global `PATH` entry.
273
+
274
+ If an OpenAI-backed client reports `API Error: 400 Invalid schema for function
275
+ 'mcp__stata-code__notebook_insert_cell'` and mentions a top-level `oneOf`,
276
+ upgrade to `stata-code>=0.6.5`, then restart the MCP client. Older server
277
+ processes keep advertising the stale schema until they are restarted.
278
+
266
279
  The MCP server registers 15 tools:
267
280
 
268
281
  | Tool | Purpose |
@@ -224,6 +224,19 @@ When `stata-code-mcp` lives inside a project virtualenv (recommended for reprodu
224
224
 
225
225
  For `uvx`-only setups, set `"command": "uvx"` and `"args": ["--from", "stata-code", "stata-code-mcp"]`.
226
226
 
227
+ #### MCP troubleshooting
228
+
229
+ If `stata_run` reports `adapter_crash` with `worker emitted non-JSON: '\n'`,
230
+ upgrade to `stata-code>=0.6.4`, then restart the MCP client so it launches a
231
+ fresh server process. Also check that the client is resolving the expected
232
+ `stata-code-mcp` binary; project virtualenv installs should use the absolute
233
+ `.venv/bin/stata-code-mcp` path instead of relying on a global `PATH` entry.
234
+
235
+ If an OpenAI-backed client reports `API Error: 400 Invalid schema for function
236
+ 'mcp__stata-code__notebook_insert_cell'` and mentions a top-level `oneOf`,
237
+ upgrade to `stata-code>=0.6.5`, then restart the MCP client. Older server
238
+ processes keep advertising the stale schema until they are restarted.
239
+
227
240
  The MCP server registers 15 tools:
228
241
 
229
242
  | Tool | Purpose |
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "stata-code"
7
- version = "0.6.4"
7
+ version = "0.6.5"
8
8
  description = "Agent-native Stata bridge — one core, multiple frontends (MCP, Jupyter, VSCode)"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -174,7 +174,7 @@ def is_available() -> bool:
174
174
  return True
175
175
 
176
176
 
177
- __version__ = "0.6.4"
177
+ __version__ = "0.6.5"
178
178
 
179
179
  __all__ = [
180
180
  # Primary entry points
@@ -95,7 +95,7 @@ from stata_code.core.runner import (
95
95
  )
96
96
  from stata_code.core.schema import RunResult
97
97
 
98
- __version__ = "0.6.4"
98
+ __version__ = "0.6.5"
99
99
 
100
100
  SERVER_INSTRUCTIONS = (
101
101
  "Use stata-code for running and inspecting Stata code. Prefer structuredContent "
@@ -894,15 +894,6 @@ def _tool_definitions() -> list[Tool]:
894
894
  },
895
895
  },
896
896
  "required": ["path"],
897
- # Schema-level expression of the "exactly one of snippet /
898
- # regex / error_text" rule. The runtime guard in
899
- # notebook.locate_cells still enforces this for clients that
900
- # don't validate inputs against the schema.
901
- "oneOf": [
902
- {"required": ["snippet"]},
903
- {"required": ["regex"]},
904
- {"required": ["error_text"]},
905
- ],
906
897
  },
907
898
  outputSchema=_NOTEBOOK_LOCATE_OUTPUT_SCHEMA,
908
899
  annotations=ToolAnnotations(
@@ -989,17 +980,6 @@ def _tool_definitions() -> list[Tool]:
989
980
  "at_end": {"type": "boolean"},
990
981
  },
991
982
  "required": ["path", "source"],
992
- # Exactly one anchor must be present. Booleans for
993
- # at_start/at_end must additionally be `true` to count as
994
- # "specified" — the JSON Schema below treats them as
995
- # required-presence; the runtime guard in
996
- # notebook.insert_cell additionally rejects the false-y form.
997
- "oneOf": [
998
- {"required": ["after_cell_id"]},
999
- {"required": ["before_cell_id"]},
1000
- {"required": ["at_start"]},
1001
- {"required": ["at_end"]},
1002
- ],
1003
983
  },
1004
984
  outputSchema=_NOTEBOOK_INSERT_OUTPUT_SCHEMA,
1005
985
  annotations=ToolAnnotations(
@@ -87,30 +87,33 @@ class TestToolRegistry:
87
87
  assert gg.annotations is not None
88
88
  assert gg.annotations.readOnlyHint is True
89
89
 
90
- def test_notebook_locate_schema_oneof(self):
90
+ def test_tool_input_schemas_avoid_openai_forbidden_top_level_keywords(self):
91
+ from stata_code.mcp.server import _tool_definitions
92
+
93
+ forbidden = {"oneOf", "anyOf", "allOf", "enum", "not"}
94
+ for tool in _tool_definitions():
95
+ schema = tool.inputSchema
96
+ assert schema is not None
97
+ assert schema.get("type") == "object"
98
+ assert forbidden.isdisjoint(schema), tool.name
99
+
100
+ def test_notebook_locate_schema_keeps_query_fields_optional(self):
91
101
  from stata_code.mcp.server import _tool_definitions
92
102
 
93
103
  loc = next(t for t in _tool_definitions() if t.name == "notebook_locate")
94
104
  schema = loc.inputSchema
95
- assert "oneOf" in schema
96
- required_sets = [tuple(sorted(o.get("required", []))) for o in schema["oneOf"]]
97
- assert ("snippet",) in required_sets
98
- assert ("regex",) in required_sets
99
- assert ("error_text",) in required_sets
105
+ assert schema["required"] == ["path"]
106
+ assert {"snippet", "regex", "error_text"} <= set(schema["properties"])
100
107
 
101
- def test_notebook_insert_cell_schema_oneof(self):
108
+ def test_notebook_insert_cell_schema_keeps_anchor_fields_optional(self):
102
109
  from stata_code.mcp.server import _tool_definitions
103
110
 
104
111
  ins = next(t for t in _tool_definitions() if t.name == "notebook_insert_cell")
105
112
  schema = ins.inputSchema
106
- assert "oneOf" in schema
107
- anchors = {tuple(sorted(o.get("required", []))) for o in schema["oneOf"]}
108
- assert anchors == {
109
- ("after_cell_id",),
110
- ("before_cell_id",),
111
- ("at_start",),
112
- ("at_end",),
113
- }
113
+ assert schema["required"] == ["path", "source"]
114
+ assert {"after_cell_id", "before_cell_id", "at_start", "at_end"} <= set(
115
+ schema["properties"]
116
+ )
114
117
 
115
118
  def test_resource_templates_include_ref_shapes(self):
116
119
  from stata_code.mcp.server import _resource_templates
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes