cap-sdk-python 0.1.0__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 (27) hide show
  1. cap_sdk_python-0.1.0/PKG-INFO +59 -0
  2. cap_sdk_python-0.1.0/README.md +48 -0
  3. cap_sdk_python-0.1.0/cap/__init__.py +5 -0
  4. cap_sdk_python-0.1.0/cap/bus.py +31 -0
  5. cap_sdk_python-0.1.0/cap/client.py +18 -0
  6. cap_sdk_python-0.1.0/cap/pb/__init__.py +0 -0
  7. cap_sdk_python-0.1.0/cap/pb/cortex/__init__.py +0 -0
  8. cap_sdk_python-0.1.0/cap/pb/cortex/agent/__init__.py +0 -0
  9. cap_sdk_python-0.1.0/cap/pb/cortex/agent/v1/__init__.py +0 -0
  10. cap_sdk_python-0.1.0/cap/pb/cortex/agent/v1/alert_pb2.py +27 -0
  11. cap_sdk_python-0.1.0/cap/pb/cortex/agent/v1/alert_pb2_grpc.py +4 -0
  12. cap_sdk_python-0.1.0/cap/pb/cortex/agent/v1/buspacket_pb2.py +31 -0
  13. cap_sdk_python-0.1.0/cap/pb/cortex/agent/v1/buspacket_pb2_grpc.py +4 -0
  14. cap_sdk_python-0.1.0/cap/pb/cortex/agent/v1/heartbeat_pb2.py +27 -0
  15. cap_sdk_python-0.1.0/cap/pb/cortex/agent/v1/heartbeat_pb2_grpc.py +4 -0
  16. cap_sdk_python-0.1.0/cap/pb/cortex/agent/v1/job_pb2.py +37 -0
  17. cap_sdk_python-0.1.0/cap/pb/cortex/agent/v1/job_pb2_grpc.py +4 -0
  18. cap_sdk_python-0.1.0/cap/pb/cortex/agent/v1/safety_pb2.py +34 -0
  19. cap_sdk_python-0.1.0/cap/pb/cortex/agent/v1/safety_pb2_grpc.py +69 -0
  20. cap_sdk_python-0.1.0/cap/worker.py +45 -0
  21. cap_sdk_python-0.1.0/cap_sdk_python.egg-info/PKG-INFO +59 -0
  22. cap_sdk_python-0.1.0/cap_sdk_python.egg-info/SOURCES.txt +25 -0
  23. cap_sdk_python-0.1.0/cap_sdk_python.egg-info/dependency_links.txt +1 -0
  24. cap_sdk_python-0.1.0/cap_sdk_python.egg-info/requires.txt +3 -0
  25. cap_sdk_python-0.1.0/cap_sdk_python.egg-info/top_level.txt +2 -0
  26. cap_sdk_python-0.1.0/pyproject.toml +21 -0
  27. cap_sdk_python-0.1.0/setup.cfg +4 -0
@@ -0,0 +1,59 @@
1
+ Metadata-Version: 2.4
2
+ Name: cap-sdk-python
3
+ Version: 0.1.0
4
+ Summary: CAP (Cortex Agent Protocol) Python SDK
5
+ Project-URL: Homepage, https://github.com/coretexos/cap
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: protobuf>=4.25.0
9
+ Requires-Dist: grpcio>=1.59.0
10
+ Requires-Dist: nats-py>=2.6.0
11
+
12
+ # CAP Python SDK
13
+
14
+ Asyncio-first SDK with NATS helpers for CAP workers and clients.
15
+
16
+ ## Quick Start
17
+ 1. Generate protobuf stubs into this SDK (one-time per proto change):
18
+ ```bash
19
+ python -m grpc_tools.protoc \
20
+ -I../../proto \
21
+ --python_out=./cap/pb \
22
+ --grpc_python_out=./cap/pb \
23
+ ../../proto/cortex/agent/v1/*.proto
24
+ ```
25
+ (Or run `./tools/make_protos.sh` from repo root and copy `generated/python` into `sdk/python/cap/pb`.)
26
+
27
+ 2. Install:
28
+ ```bash
29
+ pip install -e .
30
+ ```
31
+
32
+ 3. Run a worker:
33
+ ```python
34
+ import asyncio
35
+ from cap import worker
36
+ from cap.pb.cortex.agent.v1 import job_pb2
37
+
38
+ async def handle(req: job_pb2.JobRequest):
39
+ return job_pb2.JobResult(
40
+ job_id=req.job_id,
41
+ status=job_pb2.JOB_STATUS_SUCCEEDED,
42
+ result_ptr=f"redis://res/{req.job_id}",
43
+ worker_id="worker-echo-1",
44
+ )
45
+
46
+ asyncio.run(worker.run_worker("nats://127.0.0.1:4222", "job.echo", handle))
47
+ ```
48
+
49
+ ## Files
50
+ - `cap/bus.py` — NATS connector.
51
+ - `cap/worker.py` — worker skeleton with handler hook.
52
+ - `cap/client.py` — publish JobRequest to `sys.job.submit`.
53
+ - `cap/pb/` — protobuf stubs (generated).
54
+
55
+ ## Defaults
56
+ - Subjects: `sys.job.submit`, `sys.job.result`, `sys.heartbeat`.
57
+ - Protocol version: `1`.
58
+
59
+ Swap out `cap.bus` if you need a different transport.
@@ -0,0 +1,48 @@
1
+ # CAP Python SDK
2
+
3
+ Asyncio-first SDK with NATS helpers for CAP workers and clients.
4
+
5
+ ## Quick Start
6
+ 1. Generate protobuf stubs into this SDK (one-time per proto change):
7
+ ```bash
8
+ python -m grpc_tools.protoc \
9
+ -I../../proto \
10
+ --python_out=./cap/pb \
11
+ --grpc_python_out=./cap/pb \
12
+ ../../proto/cortex/agent/v1/*.proto
13
+ ```
14
+ (Or run `./tools/make_protos.sh` from repo root and copy `generated/python` into `sdk/python/cap/pb`.)
15
+
16
+ 2. Install:
17
+ ```bash
18
+ pip install -e .
19
+ ```
20
+
21
+ 3. Run a worker:
22
+ ```python
23
+ import asyncio
24
+ from cap import worker
25
+ from cap.pb.cortex.agent.v1 import job_pb2
26
+
27
+ async def handle(req: job_pb2.JobRequest):
28
+ return job_pb2.JobResult(
29
+ job_id=req.job_id,
30
+ status=job_pb2.JOB_STATUS_SUCCEEDED,
31
+ result_ptr=f"redis://res/{req.job_id}",
32
+ worker_id="worker-echo-1",
33
+ )
34
+
35
+ asyncio.run(worker.run_worker("nats://127.0.0.1:4222", "job.echo", handle))
36
+ ```
37
+
38
+ ## Files
39
+ - `cap/bus.py` — NATS connector.
40
+ - `cap/worker.py` — worker skeleton with handler hook.
41
+ - `cap/client.py` — publish JobRequest to `sys.job.submit`.
42
+ - `cap/pb/` — protobuf stubs (generated).
43
+
44
+ ## Defaults
45
+ - Subjects: `sys.job.submit`, `sys.job.result`, `sys.heartbeat`.
46
+ - Protocol version: `1`.
47
+
48
+ Swap out `cap.bus` if you need a different transport.
@@ -0,0 +1,5 @@
1
+ from .client import submit_job
2
+ from .worker import run_worker
3
+ from .bus import connect_nats
4
+
5
+ __all__ = ["submit_job", "run_worker", "connect_nats"]
@@ -0,0 +1,31 @@
1
+ import asyncio
2
+ from typing import Optional
3
+
4
+ import nats
5
+
6
+
7
+ class NATSConfig:
8
+ def __init__(
9
+ self,
10
+ url: str,
11
+ token: Optional[str] = None,
12
+ username: Optional[str] = None,
13
+ password: Optional[str] = None,
14
+ name: str = "cap-sdk-python",
15
+ ):
16
+ self.url = url
17
+ self.token = token
18
+ self.username = username
19
+ self.password = password
20
+ self.name = name
21
+
22
+
23
+ async def connect_nats(cfg: NATSConfig):
24
+ opts = {"servers": cfg.url, "name": cfg.name}
25
+ if cfg.token:
26
+ opts["token"] = cfg.token
27
+ if cfg.username:
28
+ opts["user"] = cfg.username
29
+ if cfg.password:
30
+ opts["password"] = cfg.password
31
+ return await nats.connect(**opts)
@@ -0,0 +1,18 @@
1
+ from google.protobuf import timestamp_pb2
2
+ from cap.pb.cortex.agent.v1 import buspacket_pb2
3
+
4
+
5
+ DEFAULT_PROTOCOL_VERSION = 1
6
+ SUBJECT_SUBMIT = "sys.job.submit"
7
+
8
+
9
+ async def submit_job(nc, job_request, trace_id: str, sender_id: str):
10
+ ts = timestamp_pb2.Timestamp()
11
+ ts.GetCurrentTime()
12
+ packet = buspacket_pb2.BusPacket()
13
+ packet.trace_id = trace_id
14
+ packet.sender_id = sender_id
15
+ packet.created_at.CopyFrom(ts)
16
+ packet.protocol_version = DEFAULT_PROTOCOL_VERSION
17
+ packet.job_request.CopyFrom(job_request)
18
+ await nc.publish(SUBJECT_SUBMIT, packet.SerializeToString())
File without changes
File without changes
File without changes
@@ -0,0 +1,27 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: cortex/agent/v1/alert.proto
4
+ # Protobuf Python Version: 4.25.1
5
+ """Generated protocol buffer code."""
6
+ from google.protobuf import descriptor as _descriptor
7
+ from google.protobuf import descriptor_pool as _descriptor_pool
8
+ from google.protobuf import symbol_database as _symbol_database
9
+ from google.protobuf.internal import builder as _builder
10
+ # @@protoc_insertion_point(imports)
11
+
12
+ _sym_db = _symbol_database.Default()
13
+
14
+
15
+
16
+
17
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1b\x63ortex/agent/v1/alert.proto\x12\x0f\x63ortex.agent.v1\"N\n\x0bSystemAlert\x12\r\n\x05level\x18\x01 \x01(\t\x12\x0f\n\x07message\x18\x02 \x01(\t\x12\x11\n\tcomponent\x18\x03 \x01(\t\x12\x0c\n\x04\x63ode\x18\x04 \x01(\tB|\n\x16\x61i.cortex.cap.agent.v1P\x01Z(github.com/coretexos/cap/cortex/agent/v1\xaa\x02\x0f\x43ortex.Agent.V1\xca\x02\x0f\x43ortex\\Agent\\V1\xea\x02\x11\x43ortex::Agent::V1b\x06proto3')
18
+
19
+ _globals = globals()
20
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
21
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'cortex.agent.v1.alert_pb2', _globals)
22
+ if _descriptor._USE_C_DESCRIPTORS == False:
23
+ _globals['DESCRIPTOR']._options = None
24
+ _globals['DESCRIPTOR']._serialized_options = b'\n\026ai.cortex.cap.agent.v1P\001Z(github.com/coretexos/cap/cortex/agent/v1\252\002\017Cortex.Agent.V1\312\002\017Cortex\\Agent\\V1\352\002\021Cortex::Agent::V1'
25
+ _globals['_SYSTEMALERT']._serialized_start=48
26
+ _globals['_SYSTEMALERT']._serialized_end=126
27
+ # @@protoc_insertion_point(module_scope)
@@ -0,0 +1,4 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+
@@ -0,0 +1,31 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: cortex/agent/v1/buspacket.proto
4
+ # Protobuf Python Version: 4.25.1
5
+ """Generated protocol buffer code."""
6
+ from google.protobuf import descriptor as _descriptor
7
+ from google.protobuf import descriptor_pool as _descriptor_pool
8
+ from google.protobuf import symbol_database as _symbol_database
9
+ from google.protobuf.internal import builder as _builder
10
+ # @@protoc_insertion_point(imports)
11
+
12
+ _sym_db = _symbol_database.Default()
13
+
14
+
15
+ from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__pb2
16
+ from cortex.agent.v1 import job_pb2 as cortex_dot_agent_dot_v1_dot_job__pb2
17
+ from cortex.agent.v1 import heartbeat_pb2 as cortex_dot_agent_dot_v1_dot_heartbeat__pb2
18
+ from cortex.agent.v1 import alert_pb2 as cortex_dot_agent_dot_v1_dot_alert__pb2
19
+
20
+
21
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1f\x63ortex/agent/v1/buspacket.proto\x12\x0f\x63ortex.agent.v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x19\x63ortex/agent/v1/job.proto\x1a\x1f\x63ortex/agent/v1/heartbeat.proto\x1a\x1b\x63ortex/agent/v1/alert.proto\"\xcb\x02\n\tBusPacket\x12\x10\n\x08trace_id\x18\x01 \x01(\t\x12\x11\n\tsender_id\x18\x02 \x01(\t\x12.\n\ncreated_at\x18\x03 \x01(\x0b\x32\x1a.google.protobuf.Timestamp\x12\x18\n\x10protocol_version\x18\x04 \x01(\x05\x12\x32\n\x0bjob_request\x18\n \x01(\x0b\x32\x1b.cortex.agent.v1.JobRequestH\x00\x12\x30\n\njob_result\x18\x0b \x01(\x0b\x32\x1a.cortex.agent.v1.JobResultH\x00\x12/\n\theartbeat\x18\x0c \x01(\x0b\x32\x1a.cortex.agent.v1.HeartbeatH\x00\x12-\n\x05\x61lert\x18\r \x01(\x0b\x32\x1c.cortex.agent.v1.SystemAlertH\x00\x42\t\n\x07payloadB|\n\x16\x61i.cortex.cap.agent.v1P\x01Z(github.com/coretexos/cap/cortex/agent/v1\xaa\x02\x0f\x43ortex.Agent.V1\xca\x02\x0f\x43ortex\\Agent\\V1\xea\x02\x11\x43ortex::Agent::V1b\x06proto3')
22
+
23
+ _globals = globals()
24
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
25
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'cortex.agent.v1.buspacket_pb2', _globals)
26
+ if _descriptor._USE_C_DESCRIPTORS == False:
27
+ _globals['DESCRIPTOR']._options = None
28
+ _globals['DESCRIPTOR']._serialized_options = b'\n\026ai.cortex.cap.agent.v1P\001Z(github.com/coretexos/cap/cortex/agent/v1\252\002\017Cortex.Agent.V1\312\002\017Cortex\\Agent\\V1\352\002\021Cortex::Agent::V1'
29
+ _globals['_BUSPACKET']._serialized_start=175
30
+ _globals['_BUSPACKET']._serialized_end=506
31
+ # @@protoc_insertion_point(module_scope)
@@ -0,0 +1,4 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+
@@ -0,0 +1,27 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: cortex/agent/v1/heartbeat.proto
4
+ # Protobuf Python Version: 4.25.1
5
+ """Generated protocol buffer code."""
6
+ from google.protobuf import descriptor as _descriptor
7
+ from google.protobuf import descriptor_pool as _descriptor_pool
8
+ from google.protobuf import symbol_database as _symbol_database
9
+ from google.protobuf.internal import builder as _builder
10
+ # @@protoc_insertion_point(imports)
11
+
12
+ _sym_db = _symbol_database.Default()
13
+
14
+
15
+
16
+
17
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1f\x63ortex/agent/v1/heartbeat.proto\x12\x0f\x63ortex.agent.v1\"\xbb\x01\n\tHeartbeat\x12\x11\n\tworker_id\x18\x01 \x01(\t\x12\x0e\n\x06region\x18\x02 \x01(\t\x12\x0c\n\x04type\x18\x03 \x01(\t\x12\x10\n\x08\x63pu_load\x18\x04 \x01(\x02\x12\x17\n\x0fgpu_utilization\x18\x05 \x01(\x02\x12\x13\n\x0b\x61\x63tive_jobs\x18\x06 \x01(\x05\x12\x14\n\x0c\x63\x61pabilities\x18\x07 \x03(\t\x12\x0c\n\x04pool\x18\x0b \x01(\t\x12\x19\n\x11max_parallel_jobs\x18\x0c \x01(\x05\x42|\n\x16\x61i.cortex.cap.agent.v1P\x01Z(github.com/coretexos/cap/cortex/agent/v1\xaa\x02\x0f\x43ortex.Agent.V1\xca\x02\x0f\x43ortex\\Agent\\V1\xea\x02\x11\x43ortex::Agent::V1b\x06proto3')
18
+
19
+ _globals = globals()
20
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
21
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'cortex.agent.v1.heartbeat_pb2', _globals)
22
+ if _descriptor._USE_C_DESCRIPTORS == False:
23
+ _globals['DESCRIPTOR']._options = None
24
+ _globals['DESCRIPTOR']._serialized_options = b'\n\026ai.cortex.cap.agent.v1P\001Z(github.com/coretexos/cap/cortex/agent/v1\252\002\017Cortex.Agent.V1\312\002\017Cortex\\Agent\\V1\352\002\021Cortex::Agent::V1'
25
+ _globals['_HEARTBEAT']._serialized_start=53
26
+ _globals['_HEARTBEAT']._serialized_end=240
27
+ # @@protoc_insertion_point(module_scope)
@@ -0,0 +1,4 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+
@@ -0,0 +1,37 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: cortex/agent/v1/job.proto
4
+ # Protobuf Python Version: 4.25.1
5
+ """Generated protocol buffer code."""
6
+ from google.protobuf import descriptor as _descriptor
7
+ from google.protobuf import descriptor_pool as _descriptor_pool
8
+ from google.protobuf import symbol_database as _symbol_database
9
+ from google.protobuf.internal import builder as _builder
10
+ # @@protoc_insertion_point(imports)
11
+
12
+ _sym_db = _symbol_database.Default()
13
+
14
+
15
+
16
+
17
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19\x63ortex/agent/v1/job.proto\x12\x0f\x63ortex.agent.v1\"\xa3\x02\n\nJobRequest\x12\x0e\n\x06job_id\x18\x01 \x01(\t\x12\r\n\x05topic\x18\x02 \x01(\t\x12.\n\x08priority\x18\x03 \x01(\x0e\x32\x1c.cortex.agent.v1.JobPriority\x12\x13\n\x0b\x63ontext_ptr\x18\x04 \x01(\t\x12\x12\n\nadapter_id\x18\x05 \x01(\t\x12\x31\n\x03\x65nv\x18\x06 \x03(\x0b\x32$.cortex.agent.v1.JobRequest.EnvEntry\x12\x15\n\rparent_job_id\x18\x07 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x08 \x01(\t\x12\x12\n\nstep_index\x18\t \x01(\x05\x1a*\n\x08\x45nvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xaf\x01\n\tJobResult\x12\x0e\n\x06job_id\x18\x01 \x01(\t\x12*\n\x06status\x18\x02 \x01(\x0e\x32\x1a.cortex.agent.v1.JobStatus\x12\x12\n\nresult_ptr\x18\x03 \x01(\t\x12\x11\n\tworker_id\x18\x04 \x01(\t\x12\x14\n\x0c\x65xecution_ms\x18\x05 \x01(\x03\x12\x12\n\nerror_code\x18\x06 \x01(\t\x12\x15\n\rerror_message\x18\x07 \x01(\t*|\n\x0bJobPriority\x12\x1c\n\x18JOB_PRIORITY_UNSPECIFIED\x10\x00\x12\x1c\n\x18JOB_PRIORITY_INTERACTIVE\x10\x01\x12\x16\n\x12JOB_PRIORITY_BATCH\x10\x02\x12\x19\n\x15JOB_PRIORITY_CRITICAL\x10\x03*\x86\x02\n\tJobStatus\x12\x1a\n\x16JOB_STATUS_UNSPECIFIED\x10\x00\x12\x16\n\x12JOB_STATUS_PENDING\x10\x01\x12\x18\n\x14JOB_STATUS_SCHEDULED\x10\x02\x12\x19\n\x15JOB_STATUS_DISPATCHED\x10\x03\x12\x16\n\x12JOB_STATUS_RUNNING\x10\x04\x12\x18\n\x14JOB_STATUS_SUCCEEDED\x10\x05\x12\x15\n\x11JOB_STATUS_FAILED\x10\x06\x12\x18\n\x14JOB_STATUS_CANCELLED\x10\x07\x12\x15\n\x11JOB_STATUS_DENIED\x10\x08\x12\x16\n\x12JOB_STATUS_TIMEOUT\x10\tB|\n\x16\x61i.cortex.cap.agent.v1P\x01Z(github.com/coretexos/cap/cortex/agent/v1\xaa\x02\x0f\x43ortex.Agent.V1\xca\x02\x0f\x43ortex\\Agent\\V1\xea\x02\x11\x43ortex::Agent::V1b\x06proto3')
18
+
19
+ _globals = globals()
20
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
21
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'cortex.agent.v1.job_pb2', _globals)
22
+ if _descriptor._USE_C_DESCRIPTORS == False:
23
+ _globals['DESCRIPTOR']._options = None
24
+ _globals['DESCRIPTOR']._serialized_options = b'\n\026ai.cortex.cap.agent.v1P\001Z(github.com/coretexos/cap/cortex/agent/v1\252\002\017Cortex.Agent.V1\312\002\017Cortex\\Agent\\V1\352\002\021Cortex::Agent::V1'
25
+ _globals['_JOBREQUEST_ENVENTRY']._options = None
26
+ _globals['_JOBREQUEST_ENVENTRY']._serialized_options = b'8\001'
27
+ _globals['_JOBPRIORITY']._serialized_start=518
28
+ _globals['_JOBPRIORITY']._serialized_end=642
29
+ _globals['_JOBSTATUS']._serialized_start=645
30
+ _globals['_JOBSTATUS']._serialized_end=907
31
+ _globals['_JOBREQUEST']._serialized_start=47
32
+ _globals['_JOBREQUEST']._serialized_end=338
33
+ _globals['_JOBREQUEST_ENVENTRY']._serialized_start=296
34
+ _globals['_JOBREQUEST_ENVENTRY']._serialized_end=338
35
+ _globals['_JOBRESULT']._serialized_start=341
36
+ _globals['_JOBRESULT']._serialized_end=516
37
+ # @@protoc_insertion_point(module_scope)
@@ -0,0 +1,4 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+
@@ -0,0 +1,34 @@
1
+ # -*- coding: utf-8 -*-
2
+ # Generated by the protocol buffer compiler. DO NOT EDIT!
3
+ # source: cortex/agent/v1/safety.proto
4
+ # Protobuf Python Version: 4.25.1
5
+ """Generated protocol buffer code."""
6
+ from google.protobuf import descriptor as _descriptor
7
+ from google.protobuf import descriptor_pool as _descriptor_pool
8
+ from google.protobuf import symbol_database as _symbol_database
9
+ from google.protobuf.internal import builder as _builder
10
+ # @@protoc_insertion_point(imports)
11
+
12
+ _sym_db = _symbol_database.Default()
13
+
14
+
15
+ from cortex.agent.v1 import job_pb2 as cortex_dot_agent_dot_v1_dot_job__pb2
16
+
17
+
18
+ DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1c\x63ortex/agent/v1/safety.proto\x12\x0f\x63ortex.agent.v1\x1a\x19\x63ortex/agent/v1/job.proto\"\x8b\x01\n\x12PolicyCheckRequest\x12\x0e\n\x06job_id\x18\x01 \x01(\t\x12\r\n\x05topic\x18\x02 \x01(\t\x12\x0e\n\x06tenant\x18\x03 \x01(\t\x12.\n\x08priority\x18\x04 \x01(\x0e\x32\x1c.cortex.agent.v1.JobPriority\x12\x16\n\x0e\x65stimated_cost\x18\x05 \x01(\x01\"t\n\x13PolicyCheckResponse\x12/\n\x08\x64\x65\x63ision\x18\x01 \x01(\x0e\x32\x1d.cortex.agent.v1.DecisionType\x12\x0e\n\x06reason\x18\x02 \x01(\t\x12\x1c\n\x14redacted_context_ptr\x18\x03 \x01(\t*\x9b\x01\n\x0c\x44\x65\x63isionType\x12\x1d\n\x19\x44\x45\x43ISION_TYPE_UNSPECIFIED\x10\x00\x12\x17\n\x13\x44\x45\x43ISION_TYPE_ALLOW\x10\x01\x12\x16\n\x12\x44\x45\x43ISION_TYPE_DENY\x10\x02\x12\x1f\n\x1b\x44\x45\x43ISION_TYPE_REQUIRE_HUMAN\x10\x03\x12\x1a\n\x16\x44\x45\x43ISION_TYPE_THROTTLE\x10\x04\x32\x62\n\x0cSafetyKernel\x12R\n\x05\x43heck\x12#.cortex.agent.v1.PolicyCheckRequest\x1a$.cortex.agent.v1.PolicyCheckResponseB|\n\x16\x61i.cortex.cap.agent.v1P\x01Z(github.com/coretexos/cap/cortex/agent/v1\xaa\x02\x0f\x43ortex.Agent.V1\xca\x02\x0f\x43ortex\\Agent\\V1\xea\x02\x11\x43ortex::Agent::V1b\x06proto3')
19
+
20
+ _globals = globals()
21
+ _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
22
+ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'cortex.agent.v1.safety_pb2', _globals)
23
+ if _descriptor._USE_C_DESCRIPTORS == False:
24
+ _globals['DESCRIPTOR']._options = None
25
+ _globals['DESCRIPTOR']._serialized_options = b'\n\026ai.cortex.cap.agent.v1P\001Z(github.com/coretexos/cap/cortex/agent/v1\252\002\017Cortex.Agent.V1\312\002\017Cortex\\Agent\\V1\352\002\021Cortex::Agent::V1'
26
+ _globals['_DECISIONTYPE']._serialized_start=337
27
+ _globals['_DECISIONTYPE']._serialized_end=492
28
+ _globals['_POLICYCHECKREQUEST']._serialized_start=77
29
+ _globals['_POLICYCHECKREQUEST']._serialized_end=216
30
+ _globals['_POLICYCHECKRESPONSE']._serialized_start=218
31
+ _globals['_POLICYCHECKRESPONSE']._serialized_end=334
32
+ _globals['_SAFETYKERNEL']._serialized_start=494
33
+ _globals['_SAFETYKERNEL']._serialized_end=592
34
+ # @@protoc_insertion_point(module_scope)
@@ -0,0 +1,69 @@
1
+ # Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
2
+ """Client and server classes corresponding to protobuf-defined services."""
3
+ import grpc
4
+
5
+ from cortex.agent.v1 import safety_pb2 as cortex_dot_agent_dot_v1_dot_safety__pb2
6
+
7
+
8
+ class SafetyKernelStub(object):
9
+ """SafetyKernel defines the policy decision service.
10
+ """
11
+
12
+ def __init__(self, channel):
13
+ """Constructor.
14
+
15
+ Args:
16
+ channel: A grpc.Channel.
17
+ """
18
+ self.Check = channel.unary_unary(
19
+ '/cortex.agent.v1.SafetyKernel/Check',
20
+ request_serializer=cortex_dot_agent_dot_v1_dot_safety__pb2.PolicyCheckRequest.SerializeToString,
21
+ response_deserializer=cortex_dot_agent_dot_v1_dot_safety__pb2.PolicyCheckResponse.FromString,
22
+ )
23
+
24
+
25
+ class SafetyKernelServicer(object):
26
+ """SafetyKernel defines the policy decision service.
27
+ """
28
+
29
+ def Check(self, request, context):
30
+ """Missing associated documentation comment in .proto file."""
31
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
32
+ context.set_details('Method not implemented!')
33
+ raise NotImplementedError('Method not implemented!')
34
+
35
+
36
+ def add_SafetyKernelServicer_to_server(servicer, server):
37
+ rpc_method_handlers = {
38
+ 'Check': grpc.unary_unary_rpc_method_handler(
39
+ servicer.Check,
40
+ request_deserializer=cortex_dot_agent_dot_v1_dot_safety__pb2.PolicyCheckRequest.FromString,
41
+ response_serializer=cortex_dot_agent_dot_v1_dot_safety__pb2.PolicyCheckResponse.SerializeToString,
42
+ ),
43
+ }
44
+ generic_handler = grpc.method_handlers_generic_handler(
45
+ 'cortex.agent.v1.SafetyKernel', rpc_method_handlers)
46
+ server.add_generic_rpc_handlers((generic_handler,))
47
+
48
+
49
+ # This class is part of an EXPERIMENTAL API.
50
+ class SafetyKernel(object):
51
+ """SafetyKernel defines the policy decision service.
52
+ """
53
+
54
+ @staticmethod
55
+ def Check(request,
56
+ target,
57
+ options=(),
58
+ channel_credentials=None,
59
+ call_credentials=None,
60
+ insecure=False,
61
+ compression=None,
62
+ wait_for_ready=None,
63
+ timeout=None,
64
+ metadata=None):
65
+ return grpc.experimental.unary_unary(request, target, '/cortex.agent.v1.SafetyKernel/Check',
66
+ cortex_dot_agent_dot_v1_dot_safety__pb2.PolicyCheckRequest.SerializeToString,
67
+ cortex_dot_agent_dot_v1_dot_safety__pb2.PolicyCheckResponse.FromString,
68
+ options, channel_credentials,
69
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
@@ -0,0 +1,45 @@
1
+ import asyncio
2
+ from typing import Callable, Awaitable
3
+
4
+ from google.protobuf import timestamp_pb2
5
+ from cap.pb.cortex.agent.v1 import buspacket_pb2, job_pb2
6
+
7
+ DEFAULT_PROTOCOL_VERSION = 1
8
+ SUBJECT_RESULT = "sys.job.result"
9
+
10
+
11
+ async def run_worker(nats_url: str, subject: str, handler: Callable[[job_pb2.JobRequest], Awaitable[job_pb2.JobResult]]):
12
+ import nats
13
+
14
+ nc = await nats.connect(servers=nats_url, name="cap-worker")
15
+
16
+ async def on_msg(msg):
17
+ packet = buspacket_pb2.BusPacket()
18
+ packet.ParseFromString(msg.data)
19
+ req = packet.job_request
20
+ if not req.job_id:
21
+ return
22
+ try:
23
+ res = await handler(req)
24
+ except Exception as exc: # noqa: BLE001
25
+ res = job_pb2.JobResult(
26
+ job_id=req.job_id,
27
+ status=job_pb2.JOB_STATUS_FAILED,
28
+ error_message=str(exc),
29
+ )
30
+ ts = timestamp_pb2.Timestamp()
31
+ ts.GetCurrentTime()
32
+ out = buspacket_pb2.BusPacket()
33
+ out.trace_id = packet.trace_id
34
+ out.sender_id = "cap-worker"
35
+ out.protocol_version = DEFAULT_PROTOCOL_VERSION
36
+ out.created_at.CopyFrom(ts)
37
+ out.job_result.CopyFrom(res)
38
+ await nc.publish(SUBJECT_RESULT, out.SerializeToString())
39
+
40
+ await nc.subscribe(subject, queue=subject, cb=on_msg)
41
+ try:
42
+ while True:
43
+ await asyncio.sleep(1)
44
+ finally:
45
+ await nc.drain()
@@ -0,0 +1,59 @@
1
+ Metadata-Version: 2.4
2
+ Name: cap-sdk-python
3
+ Version: 0.1.0
4
+ Summary: CAP (Cortex Agent Protocol) Python SDK
5
+ Project-URL: Homepage, https://github.com/coretexos/cap
6
+ Requires-Python: >=3.9
7
+ Description-Content-Type: text/markdown
8
+ Requires-Dist: protobuf>=4.25.0
9
+ Requires-Dist: grpcio>=1.59.0
10
+ Requires-Dist: nats-py>=2.6.0
11
+
12
+ # CAP Python SDK
13
+
14
+ Asyncio-first SDK with NATS helpers for CAP workers and clients.
15
+
16
+ ## Quick Start
17
+ 1. Generate protobuf stubs into this SDK (one-time per proto change):
18
+ ```bash
19
+ python -m grpc_tools.protoc \
20
+ -I../../proto \
21
+ --python_out=./cap/pb \
22
+ --grpc_python_out=./cap/pb \
23
+ ../../proto/cortex/agent/v1/*.proto
24
+ ```
25
+ (Or run `./tools/make_protos.sh` from repo root and copy `generated/python` into `sdk/python/cap/pb`.)
26
+
27
+ 2. Install:
28
+ ```bash
29
+ pip install -e .
30
+ ```
31
+
32
+ 3. Run a worker:
33
+ ```python
34
+ import asyncio
35
+ from cap import worker
36
+ from cap.pb.cortex.agent.v1 import job_pb2
37
+
38
+ async def handle(req: job_pb2.JobRequest):
39
+ return job_pb2.JobResult(
40
+ job_id=req.job_id,
41
+ status=job_pb2.JOB_STATUS_SUCCEEDED,
42
+ result_ptr=f"redis://res/{req.job_id}",
43
+ worker_id="worker-echo-1",
44
+ )
45
+
46
+ asyncio.run(worker.run_worker("nats://127.0.0.1:4222", "job.echo", handle))
47
+ ```
48
+
49
+ ## Files
50
+ - `cap/bus.py` — NATS connector.
51
+ - `cap/worker.py` — worker skeleton with handler hook.
52
+ - `cap/client.py` — publish JobRequest to `sys.job.submit`.
53
+ - `cap/pb/` — protobuf stubs (generated).
54
+
55
+ ## Defaults
56
+ - Subjects: `sys.job.submit`, `sys.job.result`, `sys.heartbeat`.
57
+ - Protocol version: `1`.
58
+
59
+ Swap out `cap.bus` if you need a different transport.
@@ -0,0 +1,25 @@
1
+ README.md
2
+ pyproject.toml
3
+ cap/__init__.py
4
+ cap/bus.py
5
+ cap/client.py
6
+ cap/worker.py
7
+ cap/pb/__init__.py
8
+ cap/pb/cortex/__init__.py
9
+ cap/pb/cortex/agent/__init__.py
10
+ cap/pb/cortex/agent/v1/__init__.py
11
+ cap/pb/cortex/agent/v1/alert_pb2.py
12
+ cap/pb/cortex/agent/v1/alert_pb2_grpc.py
13
+ cap/pb/cortex/agent/v1/buspacket_pb2.py
14
+ cap/pb/cortex/agent/v1/buspacket_pb2_grpc.py
15
+ cap/pb/cortex/agent/v1/heartbeat_pb2.py
16
+ cap/pb/cortex/agent/v1/heartbeat_pb2_grpc.py
17
+ cap/pb/cortex/agent/v1/job_pb2.py
18
+ cap/pb/cortex/agent/v1/job_pb2_grpc.py
19
+ cap/pb/cortex/agent/v1/safety_pb2.py
20
+ cap/pb/cortex/agent/v1/safety_pb2_grpc.py
21
+ cap_sdk_python.egg-info/PKG-INFO
22
+ cap_sdk_python.egg-info/SOURCES.txt
23
+ cap_sdk_python.egg-info/dependency_links.txt
24
+ cap_sdk_python.egg-info/requires.txt
25
+ cap_sdk_python.egg-info/top_level.txt
@@ -0,0 +1,3 @@
1
+ protobuf>=4.25.0
2
+ grpcio>=1.59.0
3
+ nats-py>=2.6.0
@@ -0,0 +1,21 @@
1
+ [build-system]
2
+ requires = ["setuptools>=61.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "cap-sdk-python"
7
+ version = "0.1.0"
8
+ description = "CAP (Cortex Agent Protocol) Python SDK"
9
+ readme = "README.md"
10
+ requires-python = ">=3.9"
11
+ dependencies = [
12
+ "protobuf>=4.25.0",
13
+ "grpcio>=1.59.0",
14
+ "nats-py>=2.6.0",
15
+ ]
16
+
17
+ [project.urls]
18
+ Homepage = "https://github.com/coretexos/cap"
19
+
20
+ [tool.setuptools.packages.find]
21
+ where = ["."]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+