@pentatonic-ai/ai-agent-sdk 0.8.1 → 0.8.2

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pentatonic-ai/ai-agent-sdk",
3
- "version": "0.8.1",
3
+ "version": "0.8.2",
4
4
  "description": "TES SDK — LLM observability and lifecycle tracking via Pentatonic Thing Event System. Track token usage, tool calls, and conversations. Manage things through event-sourced lifecycle stages with AI enrichment and vector search.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -416,8 +416,14 @@ async def health():
416
416
  "engine": "pentatonic-memory-engine",
417
417
  "layers": {},
418
418
  }
419
- # NV-Embed exposes /health alongside /v1/embeddings.
420
- nv_embed_health = NV_EMBED_URL.replace("/v1/embeddings", "/health")
419
+ # NV-Embed (or the upstream gateway) exposes /health at the host root.
420
+ # Use urlparse so we swap *just* the path component instead of doing a
421
+ # string replace — that breaks the moment NV_EMBED_URL is /v1/embed,
422
+ # /v1/embeddings, or bare-host. The probe is informational only; gateways
423
+ # that return non-200 on root-/health don't block engine operation.
424
+ from urllib.parse import urlparse, urlunparse
425
+ _u = urlparse(NV_EMBED_URL)
426
+ nv_embed_health = urlunparse((_u.scheme, _u.netloc, "/health", "", "", ""))
421
427
 
422
428
  import asyncio
423
429
  l2_v, l4_v, l5_v, l6_v, nv_v, l3_v = await asyncio.gather(
@@ -0,0 +1,48 @@
1
+ """Regression test for the nv_embed /health probe URL construction.
2
+
3
+ Before v0.8.1 the probe was built via str.replace("/v1/embeddings", "/health"),
4
+ which silently produced the wrong URL when NV_EMBED_URL was anything other
5
+ than ".../v1/embeddings" (e.g. /v1/embed for the Pentatonic AI Gateway, or
6
+ a bare host). The probe would end up GET-ing the embed endpoint itself and
7
+ the gateway would return 401 — making /health falsely report a degraded
8
+ nv_embed layer even when embeddings worked fine.
9
+
10
+ The fix replaces the substring replace with a urlparse-based path swap.
11
+ """
12
+
13
+ from urllib.parse import urlparse, urlunparse
14
+
15
+
16
+ def probe_url(nv_embed_url: str) -> str:
17
+ """Re-implementation of the probe URL builder from compat/server.py.
18
+ Kept tiny + isolated so it can be unit-tested without booting FastAPI."""
19
+ u = urlparse(nv_embed_url)
20
+ return urlunparse((u.scheme, u.netloc, "/health", "", "", ""))
21
+
22
+
23
+ def test_probe_with_v1_embeddings_path():
24
+ assert probe_url("https://nv-embed:8041/v1/embeddings") == "https://nv-embed:8041/health"
25
+
26
+
27
+ def test_probe_with_v1_embed_path():
28
+ """The bug case — gateway moved to /v1/embed and old replace() left URL untouched."""
29
+ assert probe_url("https://lambda-gateway.pentatonic.com/v1/embed") == (
30
+ "https://lambda-gateway.pentatonic.com/health"
31
+ )
32
+
33
+
34
+ def test_probe_with_bare_host():
35
+ """No path at all — provider supplies path_default, but probe just wants /health."""
36
+ assert probe_url("https://lambda-gateway.pentatonic.com") == (
37
+ "https://lambda-gateway.pentatonic.com/health"
38
+ )
39
+
40
+
41
+ def test_probe_strips_query_and_fragment():
42
+ assert probe_url("https://gw.example.com/v1/embeddings?token=x#frag") == (
43
+ "https://gw.example.com/health"
44
+ )
45
+
46
+
47
+ def test_probe_preserves_port():
48
+ assert probe_url("http://nv-embed:8041/v1/embeddings") == "http://nv-embed:8041/health"