keystone-cli 0.1.9__tar.gz → 0.1.10__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 (86) hide show
  1. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/PKG-INFO +1 -1
  2. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/pyproject.toml +2 -2
  3. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/commands/agent.py +20 -1
  4. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli.egg-info/PKG-INFO +1 -1
  5. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_deploy.py +38 -0
  6. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/setup.cfg +0 -0
  7. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/__init__.py +0 -0
  8. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/__main__.py +0 -0
  9. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/_build_env.py +0 -0
  10. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/_version.py +0 -0
  11. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/auth/__init__.py +0 -0
  12. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/auth/device_flow.py +0 -0
  13. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/auth/token_store.py +0 -0
  14. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/commands/__init__.py +0 -0
  15. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/commands/dev.py +0 -0
  16. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/commands/login.py +0 -0
  17. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/commands/workspace.py +0 -0
  18. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/devloop.py +0 -0
  19. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/platform_client.py +0 -0
  20. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/runner.py +0 -0
  21. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/scaffold.py +0 -0
  22. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/blank/README.md.tmpl +0 -0
  23. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/blank/agent.yaml.tmpl +0 -0
  24. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/blank/env.tmpl +0 -0
  25. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/blank/gitignore.tmpl +0 -0
  26. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/blank/pkg/__init__.py.tmpl +0 -0
  27. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/blank/pkg/graph.py.tmpl +0 -0
  28. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/blank/pyproject.toml.tmpl +0 -0
  29. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/hitl/README.md.tmpl +0 -0
  30. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/hitl/agent.yaml.tmpl +0 -0
  31. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/hitl/env.tmpl +0 -0
  32. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/hitl/gitignore.tmpl +0 -0
  33. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/hitl/pkg/__init__.py.tmpl +0 -0
  34. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/hitl/pkg/graph.py.tmpl +0 -0
  35. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/hitl/pyproject.toml.tmpl +0 -0
  36. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/llm/README.md.tmpl +0 -0
  37. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/llm/agent.yaml.tmpl +0 -0
  38. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/llm/env.tmpl +0 -0
  39. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/llm/gitignore.tmpl +0 -0
  40. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/llm/pkg/__init__.py.tmpl +0 -0
  41. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/llm/pkg/graph.py.tmpl +0 -0
  42. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/llm/pyproject.toml.tmpl +0 -0
  43. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/memory/README.md.tmpl +0 -0
  44. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/memory/agent.yaml.tmpl +0 -0
  45. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/memory/env.tmpl +0 -0
  46. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/memory/gitignore.tmpl +0 -0
  47. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/memory/pkg/__init__.py.tmpl +0 -0
  48. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/memory/pkg/graph.py.tmpl +0 -0
  49. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/memory/pyproject.toml.tmpl +0 -0
  50. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/rag-qa/README.md.tmpl +0 -0
  51. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/rag-qa/agent.yaml.tmpl +0 -0
  52. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/rag-qa/env.tmpl +0 -0
  53. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/rag-qa/gitignore.tmpl +0 -0
  54. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/rag-qa/pkg/__init__.py.tmpl +0 -0
  55. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/rag-qa/pkg/graph.py.tmpl +0 -0
  56. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/rag-qa/pyproject.toml.tmpl +0 -0
  57. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/tool-agent/README.md.tmpl +0 -0
  58. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/tool-agent/agent.yaml.tmpl +0 -0
  59. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/tool-agent/env.tmpl +0 -0
  60. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/tool-agent/gitignore.tmpl +0 -0
  61. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/tool-agent/pkg/__init__.py.tmpl +0 -0
  62. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/tool-agent/pkg/graph.py.tmpl +0 -0
  63. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli/templates/tool-agent/pyproject.toml.tmpl +0 -0
  64. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli.egg-info/SOURCES.txt +0 -0
  65. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli.egg-info/dependency_links.txt +0 -0
  66. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli.egg-info/entry_points.txt +0 -0
  67. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli.egg-info/requires.txt +0 -0
  68. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/src/keystone_cli.egg-info/top_level.txt +0 -0
  69. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_agent.py +0 -0
  70. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_auth.py +0 -0
  71. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_build_progress.py +0 -0
  72. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_ci_token.py +0 -0
  73. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_dev.py +0 -0
  74. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_init.py +0 -0
  75. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_invoke.py +0 -0
  76. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_login_command.py +0 -0
  77. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_offline.py +0 -0
  78. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_platform_client.py +0 -0
  79. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_publish.py +0 -0
  80. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_retire_delete.py +0 -0
  81. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_runs.py +0 -0
  82. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_status.py +0 -0
  83. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_threads.py +0 -0
  84. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_traces.py +0 -0
  85. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_version.py +0 -0
  86. {keystone_cli-0.1.9 → keystone_cli-0.1.10}/tests/test_workspace.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: keystone-cli
3
- Version: 0.1.9
3
+ Version: 0.1.10
4
4
  Summary: Keystone pro-code agent CLI — author, validate, and run agents locally, then deploy and invoke them on the Keystone platform.
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: keystone-agent-sdk<0.4,>=0.3
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "keystone-cli"
7
- version = "0.1.9"
7
+ version = "0.1.10"
8
8
  description = "Keystone pro-code agent CLI — author, validate, and run agents locally, then deploy and invoke them on the Keystone platform."
9
9
  requires-python = ">=3.12"
10
10
  dependencies = [
@@ -45,7 +45,7 @@ where = ["src"]
45
45
  keystone_cli = ["templates/*/*.tmpl", "templates/*/pkg/*.tmpl"]
46
46
 
47
47
  [tool.ruff]
48
- target-version = "py312"
48
+ target-version = "0.1.10"
49
49
  line-length = 120
50
50
 
51
51
  [tool.ruff.lint]
@@ -1287,6 +1287,12 @@ def _warm_up_until_ready(gw_base: str, headers: dict[str, str], agent: str, *, t
1287
1287
  ``502 GW_UPSTREAM_UNAVAILABLE`` past the deadline means it never came up (most often a boot crash
1288
1288
  — CrashLoopBackOff / CreateContainerError). Exits 1 with the reason on timeout."""
1289
1289
  url = f"{gw_base}/api/agent-service/v1/agents/{agent}/runs"
1290
+ # The gateway requires X-Correlation-ID on every proxied request (agent-gateway identity.py); the
1291
+ # edge injects X-Entity-ID/X-User-ID from the JWT but NOT the correlation id — the caller sets it,
1292
+ # like every other data-plane call (invoke / runs). Reusing the publish headers alone omitted it,
1293
+ # so the probe got 400 GW_MISSING_CORRELATION_ID, which the loop below mistook for "still warming"
1294
+ # and waited out to the deadline → a false "did not become Running".
1295
+ headers = {**headers, "X-Correlation-ID": str(uuid.uuid4())}
1290
1296
  deadline = time.monotonic() + timeout_s
1291
1297
  progress = _BuildProgress(sys.stdout.isatty(), label="Warming up ", noun="warm")
1292
1298
  last = "starting"
@@ -1311,7 +1317,20 @@ def _warm_up_until_ready(gw_base: str, headers: dict[str, str], agent: str, *, t
1311
1317
  last = "upstream unavailable"
1312
1318
  progress.tick("upstream unavailable")
1313
1319
  time.sleep(5)
1314
- else: # e.g. route not learned yet right after publish — keep waiting briefly
1320
+ elif resp.status_code == 400:
1321
+ # A rejected request (missing / invalid header) never turns into a 200 by waiting —
1322
+ # fail fast and name it, so it is not mistaken for a boot crash or silently waited out.
1323
+ progress.close()
1324
+ typer.secho(f"✗ warm-up probe rejected: HTTP 400 {resp.text[:200]}", fg=typer.colors.RED)
1325
+ typer.secho(
1326
+ " This is a gateway request-validation error, not a pod boot failure — the "
1327
+ "published version is likely serving. Verify with `keystone agent status` / "
1328
+ "`keystone agent invoke`; if it persists, the agent-service edge is dropping an "
1329
+ "identity header.",
1330
+ fg=typer.colors.RED,
1331
+ )
1332
+ raise typer.Exit(1)
1333
+ else: # e.g. 404 route not learned yet / 403 authz still propagating — keep waiting briefly
1315
1334
  last = f"HTTP {resp.status_code}"
1316
1335
  progress.tick(last)
1317
1336
  time.sleep(5)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: keystone-cli
3
- Version: 0.1.9
3
+ Version: 0.1.10
4
4
  Summary: Keystone pro-code agent CLI — author, validate, and run agents locally, then deploy and invoke them on the Keystone platform.
5
5
  Requires-Python: >=3.12
6
6
  Requires-Dist: keystone-agent-sdk<0.4,>=0.3
@@ -237,6 +237,44 @@ def test_deploy_publish_wait_fails_when_pod_never_ready(monkeypatch, project) ->
237
237
  assert "crashes at startup" in result.output # points the dev at the likely cause
238
238
 
239
239
 
240
+ def test_deploy_publish_wait_sends_correlation_id_and_fails_fast_on_400(monkeypatch, project) -> None:
241
+ # The warm-up probe MUST send X-Correlation-ID (the gateway requires it and the edge does not
242
+ # inject it — Kong only projects entity/user from the JWT). And a 400 must fail FAST with a
243
+ # request-validation message, not be mistaken for "still warming" and waited out to the deadline.
244
+ monkeypatch.setattr("keystone_cli.commands.agent.df.get_access_token", lambda *_a, **_k: "tok")
245
+ monkeypatch.setattr("keystone_cli.commands.agent.time.sleep", lambda *_a: None)
246
+
247
+ seen: dict[str, str | None] = {"corr": None}
248
+
249
+ def handler(req: httpx.Request) -> httpx.Response:
250
+ p = req.url.path
251
+ if p == "/api/agent-hub/v1/bundles":
252
+ return httpx.Response(202, json={"version_id": "v1id", "version": "v1", "status": "building"})
253
+ if p == "/api/agent-hub/v1/agents":
254
+ return httpx.Response(200, json={"data": [{"id": "a1", "name": "rag-qa"}], "meta": {}})
255
+ if p == "/api/agent-hub/v1/agents/a1/versions/v1id":
256
+ return httpx.Response(200, json={"data": {"id": "v1id", "version": "v1", "status": "staged"}})
257
+ if p.endswith("/v1id/publish"):
258
+ return httpx.Response(200, json={"data": {"version": "v1", "status": "live"}})
259
+ if p == "/api/agent-service/v1/agents/rag-qa/runs":
260
+ seen["corr"] = req.headers.get("x-correlation-id")
261
+ return httpx.Response(
262
+ 400, json={"error": {"code": "GW_MISSING_ENTITY", "message": "missing required header x-entity-id"}}
263
+ )
264
+ return httpx.Response(404, text=p)
265
+
266
+ _mock_httpx(monkeypatch, handler)
267
+ result = runner.invoke(
268
+ app,
269
+ ["agent", "deploy", str(project), "--api-base", "https://api", "--workspace-id", WS, "--publish", "--wait"],
270
+ )
271
+ assert result.exit_code == 1, result.output
272
+ assert seen["corr"], "warm-up probe must send X-Correlation-ID"
273
+ assert "warm-up probe rejected" in result.output
274
+ assert "not a pod boot failure" in result.output
275
+ assert "did not become Running" not in result.output # a 400 is not the boot-crash timeout path
276
+
277
+
240
278
  def test_deploy_wait_without_publish_is_a_noop(monkeypatch, project) -> None:
241
279
  monkeypatch.setattr("keystone_cli.commands.agent.df.get_access_token", lambda *_a, **_k: "tok")
242
280
  called: dict[str, bool] = {"warmed": False}
File without changes