hexel-sdk 0.1.0

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. package/LICENSE +21 -0
  2. package/Makefile +28 -0
  3. package/README.md +123 -0
  4. package/dist/_internal/auth.d.ts +17 -0
  5. package/dist/_internal/auth.d.ts.map +1 -0
  6. package/dist/_internal/auth.js +50 -0
  7. package/dist/_internal/auth.js.map +1 -0
  8. package/dist/_internal/client.d.ts +15 -0
  9. package/dist/_internal/client.d.ts.map +1 -0
  10. package/dist/_internal/client.js +22 -0
  11. package/dist/_internal/client.js.map +1 -0
  12. package/dist/_internal/http.d.ts +15 -0
  13. package/dist/_internal/http.d.ts.map +1 -0
  14. package/dist/_internal/http.js +59 -0
  15. package/dist/_internal/http.js.map +1 -0
  16. package/dist/compute/agent.d.ts +18 -0
  17. package/dist/compute/agent.d.ts.map +1 -0
  18. package/dist/compute/agent.js +40 -0
  19. package/dist/compute/agent.js.map +1 -0
  20. package/dist/compute/index.d.ts +13 -0
  21. package/dist/compute/index.d.ts.map +1 -0
  22. package/dist/compute/index.js +36 -0
  23. package/dist/compute/index.js.map +1 -0
  24. package/dist/compute/instance.d.ts +18 -0
  25. package/dist/compute/instance.d.ts.map +1 -0
  26. package/dist/compute/instance.js +40 -0
  27. package/dist/compute/instance.js.map +1 -0
  28. package/dist/compute/sandbox.d.ts +20 -0
  29. package/dist/compute/sandbox.d.ts.map +1 -0
  30. package/dist/compute/sandbox.js +44 -0
  31. package/dist/compute/sandbox.js.map +1 -0
  32. package/dist/compute/types.d.ts +272 -0
  33. package/dist/compute/types.d.ts.map +1 -0
  34. package/dist/compute/types.js +4 -0
  35. package/dist/compute/types.js.map +1 -0
  36. package/dist/index.d.ts +4 -0
  37. package/dist/index.d.ts.map +1 -0
  38. package/dist/index.js +23 -0
  39. package/dist/index.js.map +1 -0
  40. package/generator/generate.py +180 -0
  41. package/generator/ir.json +1545 -0
  42. package/generator/overrides.json +66 -0
  43. package/generator/parser.py +180 -0
  44. package/package.json +21 -0
  45. package/specs/agent-registry-api.json +1 -0
  46. package/specs/agentd-api.json +1364 -0
  47. package/specs/compute-api.json +1 -0
  48. package/src/_internal/auth.ts +56 -0
  49. package/src/_internal/client.ts +33 -0
  50. package/src/_internal/http.ts +61 -0
  51. package/src/compute/agent.ts +41 -0
  52. package/src/compute/index.ts +20 -0
  53. package/src/compute/instance.ts +41 -0
  54. package/src/compute/sandbox.ts +46 -0
  55. package/src/compute/types.ts +310 -0
  56. package/src/index.ts +3 -0
  57. package/tsconfig.json +17 -0
@@ -0,0 +1,66 @@
1
+ {
2
+ "services": {
3
+ "sandbox": {
4
+ "description": "Isolated execution environments",
5
+ "endpoints": {
6
+ "POST /compute/v1/vms/allocate": "create",
7
+ "GET /compute/v1/vms": "list",
8
+ "GET /compute/v1/vms/{id}": "get",
9
+ "DELETE /compute/v1/vms/{id}": "delete",
10
+ "POST /compute/v1/vms/{id}/release": "release",
11
+ "POST /compute/v1/vms/{id}/renew": "renew",
12
+ "POST /compute/v1/vms/{id}/execute": "execute"
13
+ }
14
+ },
15
+ "agent": {
16
+ "description": "Agent registry — register and manage agent images",
17
+ "endpoints": {
18
+ "POST /registry/v1/agents": "register",
19
+ "GET /registry/v1/agents": "list",
20
+ "GET /registry/v1/agents/{id}": "get",
21
+ "PUT /registry/v1/agents/{id}": "update",
22
+ "DELETE /registry/v1/agents/{id}": "delete",
23
+ "GET /registry/v1/agents/search": "search"
24
+ }
25
+ },
26
+ "instance": {
27
+ "description": "Agent deployments — deploy agents and manage instances",
28
+ "endpoints": {
29
+ "POST /compute/v1/agents/{agent_id}/deploy": "deploy",
30
+ "GET /compute/v1/deployments": "list",
31
+ "GET /compute/v1/deployments/{deployment_id}": "get",
32
+ "DELETE /compute/v1/deployments/{deployment_id}": "delete",
33
+ "POST /compute/v1/deployments/{deployment_id}/stop": "stop",
34
+ "POST /compute/v1/deployments/{deployment_id}/redeploy": "redeploy"
35
+ }
36
+ }
37
+ },
38
+ "exclude_paths": [
39
+ "/internal/",
40
+ "/compute/v1/pool/",
41
+ "/compute/v1/access/",
42
+ "/compute/v1/skills",
43
+ "/compute/v1/usage",
44
+ "/compute/v1/vms/{id}/r/",
45
+ "/compute/v1/vms/{id}/endpoint"
46
+ ],
47
+ "type_renames": {
48
+ "models.AllocateRequest": "CreateSandboxRequest",
49
+ "models.AllocateResponse": "SandboxResponse",
50
+ "models.AgentVM": "SandboxInfo",
51
+ "models.Agent": "InstanceInfo",
52
+ "models.ReleaseRequest": "ReleaseRequest",
53
+ "models.RenewRequest": "RenewRequest",
54
+ "registryclient.Agent": "AgentInfo"
55
+ },
56
+ "websocket": {
57
+ "sandbox": {
58
+ "url_field": "ws_url",
59
+ "methods": {
60
+ "execute": {"type": "execute", "fields": ["code", "language"]},
61
+ "command": {"type": "command", "fields": ["command"]}
62
+ },
63
+ "terminal_events": ["done", "execution_complete", "error"]
64
+ }
65
+ }
66
+ }
@@ -0,0 +1,180 @@
1
+ """
2
+ Spec parser — reads OpenAPI specs + overrides → produces IR (intermediate representation).
3
+
4
+ The IR is a clean, normalized model that the code generator reads.
5
+ """
6
+ import json
7
+ import re
8
+ from pathlib import Path
9
+
10
+
11
+ def load_spec(path: str) -> dict:
12
+ with open(path) as f:
13
+ return json.load(f)
14
+
15
+
16
+ def resolve_ref(spec: dict, ref: str) -> dict:
17
+ """Resolve a $ref like #/components/schemas/models.Agent"""
18
+ parts = ref.lstrip("#/").split("/")
19
+ node = spec
20
+ for p in parts:
21
+ node = node.get(p, {})
22
+ return node
23
+
24
+
25
+ def extract_schema_fields(spec: dict, schema: dict) -> list[dict]:
26
+ """Extract fields from a schema, resolving $ref."""
27
+ if "$ref" in schema:
28
+ schema = resolve_ref(spec, schema["$ref"])
29
+ props = schema.get("properties", {})
30
+ required = set(schema.get("required", []))
31
+ fields = []
32
+ for name, prop in props.items():
33
+ typ = prop.get("type", "any")
34
+ if "$ref" in prop:
35
+ typ = prop["$ref"].split("/")[-1]
36
+ if typ == "array" and "items" in prop:
37
+ item_type = prop["items"].get("type", "any")
38
+ if "$ref" in prop["items"]:
39
+ item_type = prop["items"]["$ref"].split("/")[-1]
40
+ typ = f"list[{item_type}]"
41
+ if prop.get("additionalProperties") and isinstance(prop["additionalProperties"], dict):
42
+ val_type = prop["additionalProperties"].get("type", "any")
43
+ typ = f"dict[str, {val_type}]"
44
+ elif prop.get("additionalProperties") is True:
45
+ typ = "dict"
46
+ fields.append({
47
+ "name": name,
48
+ "type": typ,
49
+ "required": name in required,
50
+ "description": prop.get("description", ""),
51
+ })
52
+ return fields
53
+
54
+
55
+ def parse_path_params(path: str) -> list[str]:
56
+ """Extract path parameters like {id}, {agent_id}."""
57
+ return re.findall(r"\{(\w+)\}", path)
58
+
59
+
60
+ def build_ir(specs: dict[str, dict], overrides: dict) -> dict:
61
+ """
62
+ Build IR from multiple OpenAPI specs + overrides.
63
+
64
+ specs: {"compute": spec_dict, "registry": spec_dict, "agentd": spec_dict}
65
+ overrides: the overrides.json content
66
+ """
67
+ ir = {
68
+ "services": {},
69
+ "types": {},
70
+ }
71
+
72
+ # Collect all schemas from all specs
73
+ for spec_name, spec in specs.items():
74
+ for schema_name, schema_def in spec.get("components", {}).get("schemas", {}).items():
75
+ type_name = overrides.get("type_renames", {}).get(schema_name, schema_name)
76
+ # Clean up Go-style names
77
+ type_name = type_name.replace("models.", "").replace("iamclient.", "").replace("registryclient.", "")
78
+ ir["types"][type_name] = {
79
+ "original": schema_name,
80
+ "fields": extract_schema_fields(spec, schema_def),
81
+ }
82
+
83
+ # Build services from overrides
84
+ exclude = overrides.get("exclude_paths", [])
85
+ for service_name, service_def in overrides.get("services", {}).items():
86
+ methods = {}
87
+ for endpoint_key, method_name in service_def.get("endpoints", {}).items():
88
+ # Parse "POST /compute/v1/vms/allocate"
89
+ parts = endpoint_key.split(" ", 1)
90
+ http_method = parts[0]
91
+ path = parts[1]
92
+
93
+ # Find this endpoint in any spec
94
+ endpoint_spec = None
95
+ source_spec = None
96
+ for spec_name, spec in specs.items():
97
+ if path in spec.get("paths", {}):
98
+ ep = spec["paths"][path].get(http_method.lower(), {})
99
+ if ep:
100
+ endpoint_spec = ep
101
+ source_spec = spec
102
+ break
103
+
104
+ if not endpoint_spec:
105
+ continue
106
+
107
+ # Extract request/response types
108
+ request_type = None
109
+ request_body = endpoint_spec.get("requestBody", {})
110
+ if request_body:
111
+ content = request_body.get("content", {}).get("application/json", {})
112
+ schema = content.get("schema", {})
113
+ if "$ref" in schema:
114
+ request_type = schema["$ref"].split("/")[-1]
115
+ request_type = overrides.get("type_renames", {}).get(request_type, request_type)
116
+ request_type = request_type.replace("models.", "")
117
+
118
+ response_type = None
119
+ resp_200 = endpoint_spec.get("responses", {}).get("200", endpoint_spec.get("responses", {}).get("201", {}))
120
+ if resp_200:
121
+ content = resp_200.get("content", {}).get("application/json", {})
122
+ schema = content.get("schema", {})
123
+ if "$ref" in schema:
124
+ response_type = schema["$ref"].split("/")[-1]
125
+ response_type = overrides.get("type_renames", {}).get(response_type, response_type)
126
+ response_type = response_type.replace("models.", "")
127
+ elif schema.get("type") == "array":
128
+ items = schema.get("items", {})
129
+ if "$ref" in items:
130
+ item_type = items["$ref"].split("/")[-1].replace("models.", "")
131
+ response_type = f"list[{item_type}]"
132
+
133
+ path_params = parse_path_params(path)
134
+
135
+ methods[method_name] = {
136
+ "http_method": http_method,
137
+ "path": path,
138
+ "path_params": path_params,
139
+ "request_type": request_type,
140
+ "response_type": response_type,
141
+ "description": endpoint_spec.get("description", endpoint_spec.get("summary", "")),
142
+ "tags": endpoint_spec.get("tags", []),
143
+ }
144
+
145
+ ir["services"][service_name] = {
146
+ "description": service_def.get("description", ""),
147
+ "methods": methods,
148
+ }
149
+
150
+ # Add WebSocket info
151
+ ir["websocket"] = overrides.get("websocket", {})
152
+
153
+ return ir
154
+
155
+
156
+ def build_from_files(specs_dir: str, overrides_path: str) -> dict:
157
+ """Convenience: load specs from directory + overrides file → IR."""
158
+ specs_dir = Path(specs_dir)
159
+ specs = {}
160
+
161
+ spec_map = {
162
+ "compute-api.json": "compute",
163
+ "agent-registry-api.json": "registry",
164
+ "agentd-api.json": "agentd",
165
+ }
166
+
167
+ for filename, key in spec_map.items():
168
+ path = specs_dir / filename
169
+ if path.exists():
170
+ specs[key] = load_spec(str(path))
171
+
172
+ with open(overrides_path) as f:
173
+ overrides = json.load(f)
174
+
175
+ return build_ir(specs, overrides)
176
+
177
+
178
+ if __name__ == "__main__":
179
+ ir = build_from_files("specs", "generator/overrides.json")
180
+ print(json.dumps(ir, indent=2))
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "hexel-sdk",
3
+ "version": "0.1.0",
4
+ "description": "Hexel SDK — deploy and run AI agents",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "scripts": {
8
+ "build": "tsc",
9
+ "generate": "npx ts-node generator/generate.ts",
10
+ "check": "tsc --noEmit",
11
+ "test": "vitest run"
12
+ },
13
+ "keywords": ["ai", "agents", "compute", "hexel", "sandbox"],
14
+ "license": "MIT",
15
+ "dependencies": {},
16
+ "devDependencies": {
17
+ "typescript": "^5.5.0",
18
+ "ts-node": "^10.9.0",
19
+ "@types/node": "^20.0.0"
20
+ }
21
+ }
@@ -0,0 +1 @@
1
+ {"components":{"schemas":{"models.Agent":{"properties":{"allowed_org_ids":{"items":{"type":"string"},"type":"array"},"author":{"type":"string"},"capabilities":{"items":{"type":"string"},"type":"array"},"created_at":{"type":"string"},"description":{"type":"string"},"endpoint":{"type":"string"},"id":{"type":"string"},"image":{"type":"string"},"image_pull_secret":{"$ref":"#/components/schemas/models.ImagePullSecret"},"manifest":{"$ref":"#/components/schemas/models.AgentManifest"},"metadata":{"additionalProperties":{"type":"string"},"type":"object"},"name":{"type":"string"},"org_id":{"type":"string"},"public_key":{"type":"string"},"state":{"description":"registered, deploying, running, active, idle, sleeping, stopped, failed","type":"string"},"updated_at":{"type":"string"},"version":{"type":"string"},"visibility":{"description":"private, public","type":"string"}},"type":"object"},"models.AgentManifest":{"properties":{"authentication":{"additionalProperties":true,"type":"object"},"capabilities":{"additionalProperties":true,"type":"object"},"description":{"type":"string"},"input_schema":{"additionalProperties":true,"type":"object"},"name":{"type":"string"},"output_schema":{"additionalProperties":true,"type":"object"},"runtime":{"additionalProperties":true,"type":"object"},"skills":{"items":{"$ref":"#/components/schemas/models.ManifestSkill"},"type":"array"},"url":{"type":"string"},"version":{"type":"string"}},"type":"object"},"models.AgentResponse":{"properties":{"agent":{"$ref":"#/components/schemas/models.Agent"}},"type":"object"},"models.AgentsListResponse":{"properties":{"agents":{"items":{"$ref":"#/components/schemas/models.Agent"},"type":"array"},"total":{"type":"integer"}},"type":"object"},"models.CreateAgentRequest":{"properties":{"author":{"type":"string"},"capabilities":{"items":{"type":"string"},"type":"array"},"description":{"type":"string"},"endpoint":{"type":"string"},"image":{"type":"string"},"image_pull_secret":{"$ref":"#/components/schemas/models.ImagePullSecret"},"manifest":{"$ref":"#/components/schemas/models.AgentManifest"},"metadata":{"additionalProperties":{"type":"string"},"type":"object"},"name":{"type":"string"},"org_id":{"type":"string"},"version":{"type":"string"}},"required":["image","name","org_id"],"type":"object"},"models.CreateToolRequest":{"properties":{"category":{"type":"string"},"description":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"type":"object"},"models.ErrorResponse":{"properties":{"error":{"type":"string"},"message":{"type":"string"}},"type":"object"},"models.ImagePullSecret":{"properties":{"password":{"type":"string"},"registry":{"type":"string"},"username":{"type":"string"}},"type":"object"},"models.ManifestSkill":{"properties":{"id":{"type":"string"},"inputModes":{"items":{"type":"string"},"type":"array"},"outputModes":{"items":{"type":"string"},"type":"array"}},"type":"object"},"models.Tool":{"properties":{"category":{"type":"string"},"created_at":{"type":"string"},"description":{"type":"string"},"id":{"type":"string"},"name":{"type":"string"}},"type":"object"},"models.ToolResponse":{"properties":{"tool":{"$ref":"#/components/schemas/models.Tool"}},"type":"object"},"models.ToolsListResponse":{"properties":{"tools":{"items":{"$ref":"#/components/schemas/models.Tool"},"type":"array"},"total":{"type":"integer"}},"type":"object"},"models.UpdateAgentRequest":{"properties":{"capabilities":{"items":{"type":"string"},"type":"array"},"description":{"type":"string"},"endpoint":{"type":"string"},"image":{"type":"string"},"manifest":{"$ref":"#/components/schemas/models.AgentManifest"},"metadata":{"additionalProperties":{"type":"string"},"type":"object"},"name":{"type":"string"},"public_key":{"type":"string"},"state":{"type":"string"},"version":{"type":"string"}},"type":"object"}},"securitySchemes":{"BearerAuth":{"in":"header","name":"Authorization","type":"apiKey"}}},"info":{"contact":{},"description":"Independent agent catalog service for Compute and Orchestrator platforms","title":"Agent Registry API","version":"1.0"},"openapi":"3.0.1","paths":{"/registry/v1/agents":{"get":{"description":"List agents with optional filters","parameters":[{"description":"Filter by author","in":"query","name":"author","schema":{"type":"string"}},{"description":"Filter by status","in":"query","name":"status","schema":{"type":"string"}},{"description":"Limit","in":"query","name":"limit","schema":{"default":20,"type":"integer"}},{"description":"Offset","in":"query","name":"offset","schema":{"default":0,"type":"integer"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.AgentsListResponse"}}},"description":"OK"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}},"description":"Internal Server Error"}},"summary":"List agents","tags":["agents"]},"post":{"description":"Register a new agent in the catalog","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.CreateAgentRequest"}}},"description":"Agent details","required":true,"x-originalParamName":"request"},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.AgentResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}},"description":"Bad Request"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}},"description":"Conflict"}},"summary":"Create agent","tags":["agents"]}},"/registry/v1/agents/search":{"get":{"description":"Find agents matching given capabilities","parameters":[{"description":"Comma-separated capabilities","in":"query","name":"capabilities","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.AgentsListResponse"}}},"description":"OK"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}},"description":"Bad Request"}},"summary":"Search agents by capabilities","tags":["agents"]}},"/registry/v1/agents/{id}":{"delete":{"description":"Delete agent by ID","parameters":[{"description":"Agent ID","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"No Content"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}},"description":"Not Found"}},"summary":"Delete agent","tags":["agents"]},"get":{"description":"Get agent by ID","parameters":[{"description":"Agent ID","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.AgentResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}},"description":"Not Found"}},"summary":"Get agent","tags":["agents"]},"put":{"description":"Update agent fields","parameters":[{"description":"Agent ID","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.UpdateAgentRequest"}}},"description":"Fields to update","required":true,"x-originalParamName":"request"},"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.AgentResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}},"description":"Not Found"}},"summary":"Update agent","tags":["agents"]}},"/registry/v1/agents/{id}/public-key":{"get":{"description":"Returns the Ed25519 public key for A2A signature verification","parameters":[{"description":"Agent ID","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}},"description":"Not Found"}},"summary":"Get agent public key","tags":["agents"]}},"/registry/v1/tools":{"get":{"description":"List all tools with optional category filter","parameters":[{"description":"Filter by category","in":"query","name":"category","schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ToolsListResponse"}}},"description":"OK"},"500":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}},"description":"Internal Server Error"}},"summary":"List tools","tags":["tools"]},"post":{"description":"Register a new tool in the catalog","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.CreateToolRequest"}}},"description":"Tool details","required":true,"x-originalParamName":"request"},"responses":{"201":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ToolResponse"}}},"description":"Created"},"400":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}},"description":"Bad Request"},"409":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}},"description":"Conflict"}},"summary":"Create tool","tags":["tools"]}},"/registry/v1/tools/{id}":{"get":{"description":"Get tool by ID","parameters":[{"description":"Tool ID","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ToolResponse"}}},"description":"OK"},"404":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/models.ErrorResponse"}}},"description":"Not Found"}},"summary":"Get tool","tags":["tools"]}}},"servers":[{"url":"https://api.hexelstudio.com/"}]}