cap-sdk-python 2.0.19__tar.gz → 2.5.2__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.
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/PKG-INFO +6 -1
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/__init__.py +30 -0
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/client.py +2 -1
- cap_sdk_python-2.5.2/cap/pb/cordum/agent/v1/alert_pb2.py +44 -0
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/pb/cordum/agent/v1/alert_pb2_grpc.py +1 -1
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/pb/cordum/agent/v1/buspacket_pb2.py +4 -3
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/pb/cordum/agent/v1/buspacket_pb2_grpc.py +1 -1
- cap_sdk_python-2.5.2/cap/pb/cordum/agent/v1/handshake_pb2.py +43 -0
- cap_sdk_python-2.5.2/cap/pb/cordum/agent/v1/handshake_pb2_grpc.py +24 -0
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/pb/cordum/agent/v1/heartbeat_pb2_grpc.py +1 -1
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/pb/cordum/agent/v1/job_pb2.py +14 -12
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/pb/cordum/agent/v1/job_pb2_grpc.py +1 -1
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/pb/cordum/agent/v1/safety_pb2_grpc.py +1 -1
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/runtime.py +2 -1
- cap_sdk_python-2.5.2/cap/subjects.py +9 -0
- cap_sdk_python-2.5.2/cap/validate.py +105 -0
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/worker.py +7 -3
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap_sdk_python.egg-info/PKG-INFO +6 -1
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap_sdk_python.egg-info/SOURCES.txt +6 -1
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap_sdk_python.egg-info/top_level.txt +0 -1
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/pyproject.toml +7 -1
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/tests/test_conformance.py +30 -1
- cap_sdk_python-2.5.2/tests/test_validate.py +284 -0
- cap_sdk_python-2.0.19/cap/pb/cordum/agent/v1/alert_pb2.py +0 -37
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/README.md +0 -0
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/bus.py +0 -0
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/pb/__init__.py +0 -0
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/pb/cordum/__init__.py +0 -0
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/pb/cordum/agent/__init__.py +0 -0
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/pb/cordum/agent/v1/__init__.py +0 -0
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/pb/cordum/agent/v1/heartbeat_pb2.py +0 -0
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap/pb/cordum/agent/v1/safety_pb2.py +0 -0
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap_sdk_python.egg-info/dependency_links.txt +0 -0
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/cap_sdk_python.egg-info/requires.txt +0 -0
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/setup.cfg +0 -0
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/tests/test_runtime.py +0 -0
- {cap_sdk_python-2.0.19 → cap_sdk_python-2.5.2}/tests/test_sdk.py +0 -0
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cap-sdk-python
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.2
|
|
4
4
|
Summary: CAP (Cordum Agent Protocol) Python SDK
|
|
5
|
+
Author-email: Cordum <eng@cordum.io>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
5
7
|
Project-URL: Homepage, https://github.com/cordum-io/cap
|
|
8
|
+
Project-URL: Repository, https://github.com/cordum-io/cap
|
|
9
|
+
Project-URL: Issues, https://github.com/cordum-io/cap/issues
|
|
10
|
+
Keywords: cap,cordum,agent,protocol,sdk,ai
|
|
6
11
|
Requires-Python: >=3.9
|
|
7
12
|
Description-Content-Type: text/markdown
|
|
8
13
|
Requires-Dist: protobuf>=4.25.0
|
|
@@ -27,6 +27,23 @@ from .client import submit_job
|
|
|
27
27
|
from .worker import run_worker
|
|
28
28
|
from .bus import connect_nats
|
|
29
29
|
from .runtime import Agent, Context, BlobStore, RedisBlobStore, InMemoryBlobStore
|
|
30
|
+
from .validate import (
|
|
31
|
+
ValidationError,
|
|
32
|
+
validate_job_request,
|
|
33
|
+
validate_job_result,
|
|
34
|
+
validate_bus_packet,
|
|
35
|
+
)
|
|
36
|
+
from .subjects import (
|
|
37
|
+
SUBJECT_SUBMIT,
|
|
38
|
+
SUBJECT_RESULT,
|
|
39
|
+
SUBJECT_HEARTBEAT,
|
|
40
|
+
SUBJECT_ALERT,
|
|
41
|
+
SUBJECT_PROGRESS,
|
|
42
|
+
SUBJECT_CANCEL,
|
|
43
|
+
SUBJECT_DLQ,
|
|
44
|
+
SUBJECT_WORKFLOW_EVENT,
|
|
45
|
+
SUBJECT_HANDSHAKE,
|
|
46
|
+
)
|
|
30
47
|
|
|
31
48
|
__all__ = [
|
|
32
49
|
"submit_job",
|
|
@@ -37,4 +54,17 @@ __all__ = [
|
|
|
37
54
|
"BlobStore",
|
|
38
55
|
"RedisBlobStore",
|
|
39
56
|
"InMemoryBlobStore",
|
|
57
|
+
"ValidationError",
|
|
58
|
+
"validate_job_request",
|
|
59
|
+
"validate_job_result",
|
|
60
|
+
"validate_bus_packet",
|
|
61
|
+
"SUBJECT_SUBMIT",
|
|
62
|
+
"SUBJECT_RESULT",
|
|
63
|
+
"SUBJECT_HEARTBEAT",
|
|
64
|
+
"SUBJECT_ALERT",
|
|
65
|
+
"SUBJECT_PROGRESS",
|
|
66
|
+
"SUBJECT_CANCEL",
|
|
67
|
+
"SUBJECT_DLQ",
|
|
68
|
+
"SUBJECT_WORKFLOW_EVENT",
|
|
69
|
+
"SUBJECT_HANDSHAKE",
|
|
40
70
|
]
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
+
# NO CHECKED-IN PROTOBUF GENCODE
|
|
4
|
+
# source: cordum/agent/v1/alert.proto
|
|
5
|
+
# Protobuf Python Version: 6.31.1
|
|
6
|
+
"""Generated protocol buffer code."""
|
|
7
|
+
from google.protobuf import descriptor as _descriptor
|
|
8
|
+
from google.protobuf import descriptor_pool as _descriptor_pool
|
|
9
|
+
from google.protobuf import runtime_version as _runtime_version
|
|
10
|
+
from google.protobuf import symbol_database as _symbol_database
|
|
11
|
+
from google.protobuf.internal import builder as _builder
|
|
12
|
+
_runtime_version.ValidateProtobufRuntimeVersion(
|
|
13
|
+
_runtime_version.Domain.PUBLIC,
|
|
14
|
+
6,
|
|
15
|
+
31,
|
|
16
|
+
1,
|
|
17
|
+
'',
|
|
18
|
+
'cordum/agent/v1/alert.proto'
|
|
19
|
+
)
|
|
20
|
+
# @@protoc_insertion_point(imports)
|
|
21
|
+
|
|
22
|
+
_sym_db = _symbol_database.Default()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
from cordum.agent.v1 import job_pb2 as cordum_dot_agent_dot_v1_dot_job__pb2
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1b\x63ordum/agent/v1/alert.proto\x12\x0f\x63ordum.agent.v1\x1a\x19\x63ordum/agent/v1/job.proto\"\xcd\x02\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(\t\x12\x30\n\x08severity\x18\x05 \x01(\x0e\x32\x1e.cordum.agent.v1.AlertSeverity\x12\x33\n\x0f\x65rror_code_enum\x18\x06 \x01(\x0e\x32\x1a.cordum.agent.v1.ErrorCode\x12\x18\n\x10source_component\x18\x07 \x01(\t\x12:\n\x07\x64\x65tails\x18\x08 \x03(\x0b\x32).cordum.agent.v1.SystemAlert.DetailsEntry\x12\x10\n\x08trace_id\x18\t \x01(\t\x1a.\n\x0c\x44\x65tailsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01*\x9b\x01\n\rAlertSeverity\x12\x1e\n\x1a\x41LERT_SEVERITY_UNSPECIFIED\x10\x00\x12\x17\n\x13\x41LERT_SEVERITY_INFO\x10\x01\x12\x1a\n\x16\x41LERT_SEVERITY_WARNING\x10\x02\x12\x18\n\x14\x41LERT_SEVERITY_ERROR\x10\x03\x12\x1b\n\x17\x41LERT_SEVERITY_CRITICAL\x10\x04\x42\x7f\n\x16io.cordum.cap.agent.v1P\x01Z+github.com/cordum-io/cap/v2/cordum/agent/v1\xaa\x02\x0f\x43ordum.Agent.V1\xca\x02\x0f\x63ordum\\Agent\\V1\xea\x02\x11\x43ordum::Agent::V1b\x06proto3')
|
|
29
|
+
|
|
30
|
+
_globals = globals()
|
|
31
|
+
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
32
|
+
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'cordum.agent.v1.alert_pb2', _globals)
|
|
33
|
+
if not _descriptor._USE_C_DESCRIPTORS:
|
|
34
|
+
_globals['DESCRIPTOR']._loaded_options = None
|
|
35
|
+
_globals['DESCRIPTOR']._serialized_options = b'\n\026io.cordum.cap.agent.v1P\001Z+github.com/cordum-io/cap/v2/cordum/agent/v1\252\002\017Cordum.Agent.V1\312\002\017cordum\\Agent\\V1\352\002\021Cordum::Agent::V1'
|
|
36
|
+
_globals['_SYSTEMALERT_DETAILSENTRY']._loaded_options = None
|
|
37
|
+
_globals['_SYSTEMALERT_DETAILSENTRY']._serialized_options = b'8\001'
|
|
38
|
+
_globals['_ALERTSEVERITY']._serialized_start=412
|
|
39
|
+
_globals['_ALERTSEVERITY']._serialized_end=567
|
|
40
|
+
_globals['_SYSTEMALERT']._serialized_start=76
|
|
41
|
+
_globals['_SYSTEMALERT']._serialized_end=409
|
|
42
|
+
_globals['_SYSTEMALERT_DETAILSENTRY']._serialized_start=363
|
|
43
|
+
_globals['_SYSTEMALERT_DETAILSENTRY']._serialized_end=409
|
|
44
|
+
# @@protoc_insertion_point(module_scope)
|
|
@@ -26,9 +26,10 @@ from google.protobuf import timestamp_pb2 as google_dot_protobuf_dot_timestamp__
|
|
|
26
26
|
from cordum.agent.v1 import job_pb2 as cordum_dot_agent_dot_v1_dot_job__pb2
|
|
27
27
|
from cordum.agent.v1 import heartbeat_pb2 as cordum_dot_agent_dot_v1_dot_heartbeat__pb2
|
|
28
28
|
from cordum.agent.v1 import alert_pb2 as cordum_dot_agent_dot_v1_dot_alert__pb2
|
|
29
|
+
from cordum.agent.v1 import handshake_pb2 as cordum_dot_agent_dot_v1_dot_handshake__pb2
|
|
29
30
|
|
|
30
31
|
|
|
31
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1f\x63ordum/agent/v1/buspacket.proto\x12\x0f\x63ordum.agent.v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x19\x63ordum/agent/v1/job.proto\x1a\x1f\x63ordum/agent/v1/heartbeat.proto\x1a\x1b\x63ordum/agent/v1/alert.proto\"\
|
|
32
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1f\x63ordum/agent/v1/buspacket.proto\x12\x0f\x63ordum.agent.v1\x1a\x1fgoogle/protobuf/timestamp.proto\x1a\x19\x63ordum/agent/v1/job.proto\x1a\x1f\x63ordum/agent/v1/heartbeat.proto\x1a\x1b\x63ordum/agent/v1/alert.proto\x1a\x1f\x63ordum/agent/v1/handshake.proto\"\xf7\x03\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.cordum.agent.v1.JobRequestH\x00\x12\x30\n\njob_result\x18\x0b \x01(\x0b\x32\x1a.cordum.agent.v1.JobResultH\x00\x12/\n\theartbeat\x18\x0c \x01(\x0b\x32\x1a.cordum.agent.v1.HeartbeatH\x00\x12-\n\x05\x61lert\x18\r \x01(\x0b\x32\x1c.cordum.agent.v1.SystemAlertH\x00\x12\x34\n\x0cjob_progress\x18\x0f \x01(\x0b\x32\x1c.cordum.agent.v1.JobProgressH\x00\x12\x30\n\njob_cancel\x18\x10 \x01(\x0b\x32\x1a.cordum.agent.v1.JobCancelH\x00\x12/\n\thandshake\x18\x11 \x01(\x0b\x32\x1a.cordum.agent.v1.HandshakeH\x00\x12\x11\n\tsignature\x18\x0e \x01(\x0c\x42\t\n\x07payloadB\x7f\n\x16io.cordum.cap.agent.v1P\x01Z+github.com/cordum-io/cap/v2/cordum/agent/v1\xaa\x02\x0f\x43ordum.Agent.V1\xca\x02\x0f\x63ordum\\Agent\\V1\xea\x02\x11\x43ordum::Agent::V1b\x06proto3')
|
|
32
33
|
|
|
33
34
|
_globals = globals()
|
|
34
35
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -36,6 +37,6 @@ _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'cordum.agent.v1.buspacket_p
|
|
|
36
37
|
if not _descriptor._USE_C_DESCRIPTORS:
|
|
37
38
|
_globals['DESCRIPTOR']._loaded_options = None
|
|
38
39
|
_globals['DESCRIPTOR']._serialized_options = b'\n\026io.cordum.cap.agent.v1P\001Z+github.com/cordum-io/cap/v2/cordum/agent/v1\252\002\017Cordum.Agent.V1\312\002\017cordum\\Agent\\V1\352\002\021Cordum::Agent::V1'
|
|
39
|
-
_globals['_BUSPACKET']._serialized_start=
|
|
40
|
-
_globals['_BUSPACKET']._serialized_end=
|
|
40
|
+
_globals['_BUSPACKET']._serialized_start=208
|
|
41
|
+
_globals['_BUSPACKET']._serialized_end=711
|
|
41
42
|
# @@protoc_insertion_point(module_scope)
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
+
# NO CHECKED-IN PROTOBUF GENCODE
|
|
4
|
+
# source: cordum/agent/v1/handshake.proto
|
|
5
|
+
# Protobuf Python Version: 6.31.1
|
|
6
|
+
"""Generated protocol buffer code."""
|
|
7
|
+
from google.protobuf import descriptor as _descriptor
|
|
8
|
+
from google.protobuf import descriptor_pool as _descriptor_pool
|
|
9
|
+
from google.protobuf import runtime_version as _runtime_version
|
|
10
|
+
from google.protobuf import symbol_database as _symbol_database
|
|
11
|
+
from google.protobuf.internal import builder as _builder
|
|
12
|
+
_runtime_version.ValidateProtobufRuntimeVersion(
|
|
13
|
+
_runtime_version.Domain.PUBLIC,
|
|
14
|
+
6,
|
|
15
|
+
31,
|
|
16
|
+
1,
|
|
17
|
+
'',
|
|
18
|
+
'cordum/agent/v1/handshake.proto'
|
|
19
|
+
)
|
|
20
|
+
# @@protoc_insertion_point(imports)
|
|
21
|
+
|
|
22
|
+
_sym_db = _symbol_database.Default()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1f\x63ordum/agent/v1/handshake.proto\x12\x0f\x63ordum.agent.v1\"\xf9\x01\n\tHandshake\x12\x14\n\x0c\x63omponent_id\x18\x01 \x01(\t\x12,\n\x04role\x18\x02 \x01(\x0e\x32\x1e.cordum.agent.v1.ComponentRole\x12\x1a\n\x12supported_versions\x18\x03 \x03(\x05\x12\x42\n\x0c\x63\x61pabilities\x18\x04 \x03(\x0b\x32,.cordum.agent.v1.Handshake.CapabilitiesEntry\x12\x13\n\x0bsdk_version\x18\x05 \x01(\t\x1a\x33\n\x11\x43\x61pabilitiesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\x08:\x02\x38\x01*\xc4\x01\n\rComponentRole\x12\x1e\n\x1a\x43OMPONENT_ROLE_UNSPECIFIED\x10\x00\x12\x1a\n\x16\x43OMPONENT_ROLE_GATEWAY\x10\x01\x12\x1c\n\x18\x43OMPONENT_ROLE_SCHEDULER\x10\x02\x12\x19\n\x15\x43OMPONENT_ROLE_WORKER\x10\x03\x12\x1f\n\x1b\x43OMPONENT_ROLE_ORCHESTRATOR\x10\x04\x12\x1d\n\x19\x43OMPONENT_ROLE_CONTROLLER\x10\x05\x42\x7f\n\x16io.cordum.cap.agent.v1P\x01Z+github.com/cordum-io/cap/v2/cordum/agent/v1\xaa\x02\x0f\x43ordum.Agent.V1\xca\x02\x0f\x63ordum\\Agent\\V1\xea\x02\x11\x43ordum::Agent::V1b\x06proto3')
|
|
28
|
+
|
|
29
|
+
_globals = globals()
|
|
30
|
+
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
31
|
+
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'cordum.agent.v1.handshake_pb2', _globals)
|
|
32
|
+
if not _descriptor._USE_C_DESCRIPTORS:
|
|
33
|
+
_globals['DESCRIPTOR']._loaded_options = None
|
|
34
|
+
_globals['DESCRIPTOR']._serialized_options = b'\n\026io.cordum.cap.agent.v1P\001Z+github.com/cordum-io/cap/v2/cordum/agent/v1\252\002\017Cordum.Agent.V1\312\002\017cordum\\Agent\\V1\352\002\021Cordum::Agent::V1'
|
|
35
|
+
_globals['_HANDSHAKE_CAPABILITIESENTRY']._loaded_options = None
|
|
36
|
+
_globals['_HANDSHAKE_CAPABILITIESENTRY']._serialized_options = b'8\001'
|
|
37
|
+
_globals['_COMPONENTROLE']._serialized_start=305
|
|
38
|
+
_globals['_COMPONENTROLE']._serialized_end=501
|
|
39
|
+
_globals['_HANDSHAKE']._serialized_start=53
|
|
40
|
+
_globals['_HANDSHAKE']._serialized_end=302
|
|
41
|
+
_globals['_HANDSHAKE_CAPABILITIESENTRY']._serialized_start=251
|
|
42
|
+
_globals['_HANDSHAKE_CAPABILITIESENTRY']._serialized_end=302
|
|
43
|
+
# @@protoc_insertion_point(module_scope)
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
import warnings
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
GRPC_GENERATED_VERSION = '1.78.0'
|
|
8
|
+
GRPC_VERSION = grpc.__version__
|
|
9
|
+
_version_not_supported = False
|
|
10
|
+
|
|
11
|
+
try:
|
|
12
|
+
from grpc._utilities import first_version_is_lower
|
|
13
|
+
_version_not_supported = first_version_is_lower(GRPC_VERSION, GRPC_GENERATED_VERSION)
|
|
14
|
+
except ImportError:
|
|
15
|
+
_version_not_supported = True
|
|
16
|
+
|
|
17
|
+
if _version_not_supported:
|
|
18
|
+
raise RuntimeError(
|
|
19
|
+
f'The grpc package installed is at version {GRPC_VERSION},'
|
|
20
|
+
+ ' but the generated code in cordum/agent/v1/handshake_pb2_grpc.py depends on'
|
|
21
|
+
+ f' grpcio>={GRPC_GENERATED_VERSION}.'
|
|
22
|
+
+ f' Please upgrade your grpc module to grpcio>={GRPC_GENERATED_VERSION}'
|
|
23
|
+
+ f' or downgrade your generated code using grpcio-tools<={GRPC_VERSION}.'
|
|
24
|
+
)
|
|
@@ -24,7 +24,7 @@ _sym_db = _symbol_database.Default()
|
|
|
24
24
|
|
|
25
25
|
|
|
26
26
|
|
|
27
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19\x63ordum/agent/v1/job.proto\x12\x0f\x63ordum.agent.v1\"l\n\x0c\x43ontextHints\x12\x18\n\x10max_input_tokens\x18\x01 \x01(\x05\x12\x1b\n\x13\x61llow_summarization\x18\x02 \x01(\x08\x12\x17\n\x0f\x61llow_retrieval\x18\x03 \x01(\x08\x12\x0c\n\x04tags\x18\x04 \x03(\t\"l\n\x06\x42udget\x12\x18\n\x10max_input_tokens\x18\x01 \x01(\x03\x12\x19\n\x11max_output_tokens\x18\x02 \x01(\x03\x12\x18\n\x10max_total_tokens\x18\x03 \x01(\x03\x12\x13\n\x0b\x64\x65\x61\x64line_ms\x18\x04 \x01(\x03\"\xae\x02\n\x0bJobMetadata\x12\x11\n\ttenant_id\x18\x01 \x01(\t\x12\x10\n\x08\x61\x63tor_id\x18\x02 \x01(\t\x12.\n\nactor_type\x18\x03 \x01(\x0e\x32\x1a.cordum.agent.v1.ActorType\x12\x17\n\x0fidempotency_key\x18\x04 \x01(\t\x12\x12\n\ncapability\x18\x05 \x01(\t\x12\x11\n\trisk_tags\x18\x06 \x03(\t\x12\x10\n\x08requires\x18\x07 \x03(\t\x12\x0f\n\x07pack_id\x18\x08 \x01(\t\x12\x38\n\x06labels\x18\t \x03(\x0b\x32(.cordum.agent.v1.JobMetadata.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x88\x04\n\x0c\x43ompensation\x12\r\n\x05topic\x18\x01 \x01(\t\x12\x13\n\x0b\x63ontext_ptr\x18\x02 \x01(\t\x12.\n\x08priority\x18\x03 \x01(\x0e\x32\x1c.cordum.agent.v1.JobPriority\x12\x12\n\nadapter_id\x18\x04 \x01(\t\x12\x33\n\x03\x65nv\x18\x05 \x03(\x0b\x32&.cordum.agent.v1.Compensation.EnvEntry\x12\x11\n\tmemory_id\x18\x06 \x01(\t\x12\x34\n\rcontext_hints\x18\x07 \x01(\x0b\x32\x1d.cordum.agent.v1.ContextHints\x12\'\n\x06\x62udget\x18\x08 \x01(\x0b\x32\x17.cordum.agent.v1.Budget\x12\x11\n\ttenant_id\x18\t \x01(\t\x12\x14\n\x0cprincipal_id\x18\n \x01(\t\x12\x39\n\x06labels\x18\x0b \x03(\x0b\x32).cordum.agent.v1.Compensation.LabelsEntry\x12*\n\x04meta\x18\x0c \x01(\x0b\x32\x1c.cordum.agent.v1.JobMetadata\x1a*\n\x08\x45nvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x87\x05\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.cordum.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$.cordum.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\x12\x11\n\tmemory_id\x18\n \x01(\t\x12\x34\n\rcontext_hints\x18\x0b \x01(\x0b\x32\x1d.cordum.agent.v1.ContextHints\x12\'\n\x06\x62udget\x18\x0c \x01(\x0b\x32\x17.cordum.agent.v1.Budget\x12\x11\n\ttenant_id\x18\r \x01(\t\x12\x14\n\x0cprincipal_id\x18\x0e \x01(\t\x12\x37\n\x06labels\x18\x0f \x03(\x0b\x32\'.cordum.agent.v1.JobRequest.LabelsEntry\x12*\n\x04meta\x18\x10 \x01(\x0b\x32\x1c.cordum.agent.v1.JobMetadata\x12\x33\n\x0c\x63ompensation\x18\x11 \x01(\x0b\x32\x1d.cordum.agent.v1.Compensation\x1a*\n\x08\x45nvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\
|
|
27
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x19\x63ordum/agent/v1/job.proto\x12\x0f\x63ordum.agent.v1\"l\n\x0c\x43ontextHints\x12\x18\n\x10max_input_tokens\x18\x01 \x01(\x05\x12\x1b\n\x13\x61llow_summarization\x18\x02 \x01(\x08\x12\x17\n\x0f\x61llow_retrieval\x18\x03 \x01(\x08\x12\x0c\n\x04tags\x18\x04 \x03(\t\"l\n\x06\x42udget\x12\x18\n\x10max_input_tokens\x18\x01 \x01(\x03\x12\x19\n\x11max_output_tokens\x18\x02 \x01(\x03\x12\x18\n\x10max_total_tokens\x18\x03 \x01(\x03\x12\x13\n\x0b\x64\x65\x61\x64line_ms\x18\x04 \x01(\x03\"\xae\x02\n\x0bJobMetadata\x12\x11\n\ttenant_id\x18\x01 \x01(\t\x12\x10\n\x08\x61\x63tor_id\x18\x02 \x01(\t\x12.\n\nactor_type\x18\x03 \x01(\x0e\x32\x1a.cordum.agent.v1.ActorType\x12\x17\n\x0fidempotency_key\x18\x04 \x01(\t\x12\x12\n\ncapability\x18\x05 \x01(\t\x12\x11\n\trisk_tags\x18\x06 \x03(\t\x12\x10\n\x08requires\x18\x07 \x03(\t\x12\x0f\n\x07pack_id\x18\x08 \x01(\t\x12\x38\n\x06labels\x18\t \x03(\x0b\x32(.cordum.agent.v1.JobMetadata.LabelsEntry\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x88\x04\n\x0c\x43ompensation\x12\r\n\x05topic\x18\x01 \x01(\t\x12\x13\n\x0b\x63ontext_ptr\x18\x02 \x01(\t\x12.\n\x08priority\x18\x03 \x01(\x0e\x32\x1c.cordum.agent.v1.JobPriority\x12\x12\n\nadapter_id\x18\x04 \x01(\t\x12\x33\n\x03\x65nv\x18\x05 \x03(\x0b\x32&.cordum.agent.v1.Compensation.EnvEntry\x12\x11\n\tmemory_id\x18\x06 \x01(\t\x12\x34\n\rcontext_hints\x18\x07 \x01(\x0b\x32\x1d.cordum.agent.v1.ContextHints\x12\'\n\x06\x62udget\x18\x08 \x01(\x0b\x32\x17.cordum.agent.v1.Budget\x12\x11\n\ttenant_id\x18\t \x01(\t\x12\x14\n\x0cprincipal_id\x18\n \x01(\t\x12\x39\n\x06labels\x18\x0b \x03(\x0b\x32).cordum.agent.v1.Compensation.LabelsEntry\x12*\n\x04meta\x18\x0c \x01(\x0b\x32\x1c.cordum.agent.v1.JobMetadata\x1a*\n\x08\x45nvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\x87\x05\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.cordum.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$.cordum.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\x12\x11\n\tmemory_id\x18\n \x01(\t\x12\x34\n\rcontext_hints\x18\x0b \x01(\x0b\x32\x1d.cordum.agent.v1.ContextHints\x12\'\n\x06\x62udget\x18\x0c \x01(\x0b\x32\x17.cordum.agent.v1.Budget\x12\x11\n\ttenant_id\x18\r \x01(\t\x12\x14\n\x0cprincipal_id\x18\x0e \x01(\t\x12\x37\n\x06labels\x18\x0f \x03(\x0b\x32\'.cordum.agent.v1.JobRequest.LabelsEntry\x12*\n\x04meta\x18\x10 \x01(\x0b\x32\x1c.cordum.agent.v1.JobMetadata\x12\x33\n\x0c\x63ompensation\x18\x11 \x01(\x0b\x32\x1d.cordum.agent.v1.Compensation\x1a*\n\x08\x45nvEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a-\n\x0bLabelsEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xfb\x01\n\tJobResult\x12\x0e\n\x06job_id\x18\x01 \x01(\t\x12*\n\x06status\x18\x02 \x01(\x0e\x32\x1a.cordum.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\x12\x15\n\rartifact_ptrs\x18\x08 \x03(\t\x12\x33\n\x0f\x65rror_code_enum\x18\t \x01(\x0e\x32\x1a.cordum.agent.v1.ErrorCode\"\xa7\x01\n\x0bJobProgress\x12\x0e\n\x06job_id\x18\x01 \x01(\t\x12\x0f\n\x07step_id\x18\x02 \x01(\t\x12\x0f\n\x07percent\x18\x03 \x01(\x05\x12\x0f\n\x07message\x18\x04 \x01(\t\x12\x12\n\nresult_ptr\x18\x05 \x01(\t\x12\x15\n\rartifact_ptrs\x18\x06 \x03(\t\x12*\n\x06status\x18\x07 \x01(\x0e\x32\x1a.cordum.agent.v1.JobStatus\"A\n\tJobCancel\x12\x0e\n\x06job_id\x18\x01 \x01(\t\x12\x0e\n\x06reason\x18\x02 \x01(\t\x12\x14\n\x0crequested_by\x18\x03 \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*\xc4\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\t\x12\x1f\n\x1bJOB_STATUS_FAILED_RETRYABLE\x10\n\x12\x1b\n\x17JOB_STATUS_FAILED_FATAL\x10\x0b*U\n\tActorType\x12\x1a\n\x16\x41\x43TOR_TYPE_UNSPECIFIED\x10\x00\x12\x14\n\x10\x41\x43TOR_TYPE_HUMAN\x10\x01\x12\x16\n\x12\x41\x43TOR_TYPE_SERVICE\x10\x02*\xe1\x05\n\tErrorCode\x12\x1a\n\x16\x45RROR_CODE_UNSPECIFIED\x10\x00\x12(\n$ERROR_CODE_PROTOCOL_VERSION_MISMATCH\x10\x64\x12(\n$ERROR_CODE_PROTOCOL_MALFORMED_PACKET\x10\x65\x12\'\n#ERROR_CODE_PROTOCOL_UNKNOWN_PAYLOAD\x10\x66\x12)\n%ERROR_CODE_PROTOCOL_SIGNATURE_INVALID\x10g\x12)\n%ERROR_CODE_PROTOCOL_SIGNATURE_MISSING\x10h\x12\x1b\n\x16\x45RROR_CODE_JOB_TIMEOUT\x10\xc8\x01\x12&\n!ERROR_CODE_JOB_RESOURCE_EXHAUSTED\x10\xc9\x01\x12%\n ERROR_CODE_JOB_PERMISSION_DENIED\x10\xca\x01\x12!\n\x1c\x45RROR_CODE_JOB_INVALID_INPUT\x10\xcb\x01\x12\x1d\n\x18\x45RROR_CODE_JOB_NOT_FOUND\x10\xcc\x01\x12\x1d\n\x18\x45RROR_CODE_JOB_DUPLICATE\x10\xcd\x01\x12&\n!ERROR_CODE_JOB_WORKER_UNAVAILABLE\x10\xce\x01\x12\x1d\n\x18\x45RROR_CODE_SAFETY_DENIED\x10\xac\x02\x12\'\n\"ERROR_CODE_SAFETY_POLICY_VIOLATION\x10\xad\x02\x12\'\n\"ERROR_CODE_SAFETY_RISK_TAG_BLOCKED\x10\xae\x02\x12(\n#ERROR_CODE_TRANSPORT_PUBLISH_FAILED\x10\x90\x03\x12*\n%ERROR_CODE_TRANSPORT_SUBSCRIBE_FAILED\x10\x91\x03\x12)\n$ERROR_CODE_TRANSPORT_CONNECTION_LOST\x10\x92\x03\x42\x7f\n\x16io.cordum.cap.agent.v1P\x01Z+github.com/cordum-io/cap/v2/cordum/agent/v1\xaa\x02\x0f\x43ordum.Agent.V1\xca\x02\x0f\x63ordum\\Agent\\V1\xea\x02\x11\x43ordum::Agent::V1b\x06proto3')
|
|
28
28
|
|
|
29
29
|
_globals = globals()
|
|
30
30
|
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
@@ -42,12 +42,14 @@ if not _descriptor._USE_C_DESCRIPTORS:
|
|
|
42
42
|
_globals['_JOBREQUEST_ENVENTRY']._serialized_options = b'8\001'
|
|
43
43
|
_globals['_JOBREQUEST_LABELSENTRY']._loaded_options = None
|
|
44
44
|
_globals['_JOBREQUEST_LABELSENTRY']._serialized_options = b'8\001'
|
|
45
|
-
_globals['_JOBPRIORITY']._serialized_start=
|
|
46
|
-
_globals['_JOBPRIORITY']._serialized_end=
|
|
47
|
-
_globals['_JOBSTATUS']._serialized_start=
|
|
48
|
-
_globals['_JOBSTATUS']._serialized_end=
|
|
49
|
-
_globals['_ACTORTYPE']._serialized_start=
|
|
50
|
-
_globals['_ACTORTYPE']._serialized_end=
|
|
45
|
+
_globals['_JOBPRIORITY']._serialized_start=2235
|
|
46
|
+
_globals['_JOBPRIORITY']._serialized_end=2359
|
|
47
|
+
_globals['_JOBSTATUS']._serialized_start=2362
|
|
48
|
+
_globals['_JOBSTATUS']._serialized_end=2686
|
|
49
|
+
_globals['_ACTORTYPE']._serialized_start=2688
|
|
50
|
+
_globals['_ACTORTYPE']._serialized_end=2773
|
|
51
|
+
_globals['_ERRORCODE']._serialized_start=2776
|
|
52
|
+
_globals['_ERRORCODE']._serialized_end=3513
|
|
51
53
|
_globals['_CONTEXTHINTS']._serialized_start=46
|
|
52
54
|
_globals['_CONTEXTHINTS']._serialized_end=154
|
|
53
55
|
_globals['_BUDGET']._serialized_start=156
|
|
@@ -69,9 +71,9 @@ if not _descriptor._USE_C_DESCRIPTORS:
|
|
|
69
71
|
_globals['_JOBREQUEST_LABELSENTRY']._serialized_start=524
|
|
70
72
|
_globals['_JOBREQUEST_LABELSENTRY']._serialized_end=569
|
|
71
73
|
_globals['_JOBRESULT']._serialized_start=1745
|
|
72
|
-
_globals['_JOBRESULT']._serialized_end=
|
|
73
|
-
_globals['_JOBPROGRESS']._serialized_start=
|
|
74
|
-
_globals['_JOBPROGRESS']._serialized_end=
|
|
75
|
-
_globals['_JOBCANCEL']._serialized_start=
|
|
76
|
-
_globals['_JOBCANCEL']._serialized_end=
|
|
74
|
+
_globals['_JOBRESULT']._serialized_end=1996
|
|
75
|
+
_globals['_JOBPROGRESS']._serialized_start=1999
|
|
76
|
+
_globals['_JOBPROGRESS']._serialized_end=2166
|
|
77
|
+
_globals['_JOBCANCEL']._serialized_start=2168
|
|
78
|
+
_globals['_JOBCANCEL']._serialized_end=2233
|
|
77
79
|
# @@protoc_insertion_point(module_scope)
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
SUBJECT_SUBMIT = "sys.job.submit"
|
|
2
|
+
SUBJECT_RESULT = "sys.job.result"
|
|
3
|
+
SUBJECT_HEARTBEAT = "sys.heartbeat"
|
|
4
|
+
SUBJECT_ALERT = "sys.alert"
|
|
5
|
+
SUBJECT_PROGRESS = "sys.job.progress"
|
|
6
|
+
SUBJECT_CANCEL = "sys.job.cancel"
|
|
7
|
+
SUBJECT_DLQ = "sys.job.dlq"
|
|
8
|
+
SUBJECT_WORKFLOW_EVENT = "sys.workflow.event"
|
|
9
|
+
SUBJECT_HANDSHAKE = "sys.handshake"
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
"""Opt-in validation helpers for CAP protobuf messages.
|
|
2
|
+
|
|
3
|
+
Each function accepts a protobuf message object and returns a list of
|
|
4
|
+
ValidationError instances. An empty list means the message is valid.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from dataclasses import dataclass
|
|
8
|
+
from typing import Any, List
|
|
9
|
+
|
|
10
|
+
from cap.pb.cordum.agent.v1 import buspacket_pb2, job_pb2
|
|
11
|
+
|
|
12
|
+
# Max known JobPriority enum value.
|
|
13
|
+
_JOB_PRIORITY_MAX = job_pb2.JOB_PRIORITY_CRITICAL # 3
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
@dataclass(frozen=True)
|
|
17
|
+
class ValidationError:
|
|
18
|
+
"""A single validation failure."""
|
|
19
|
+
|
|
20
|
+
field: str
|
|
21
|
+
message: str
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def validate_job_request(msg: Any) -> List[ValidationError]:
|
|
25
|
+
"""Validate semantic constraints on a JobRequest."""
|
|
26
|
+
errors: List[ValidationError] = []
|
|
27
|
+
if msg is None:
|
|
28
|
+
errors.append(ValidationError("JobRequest", "must not be nil"))
|
|
29
|
+
return errors
|
|
30
|
+
if not msg.job_id:
|
|
31
|
+
errors.append(ValidationError("job_id", "must not be empty"))
|
|
32
|
+
if not msg.topic:
|
|
33
|
+
errors.append(ValidationError("topic", "must not be empty"))
|
|
34
|
+
if msg.priority < 0 or msg.priority > _JOB_PRIORITY_MAX:
|
|
35
|
+
errors.append(
|
|
36
|
+
ValidationError("priority", f"invalid value {msg.priority}")
|
|
37
|
+
)
|
|
38
|
+
if msg.step_index < 0:
|
|
39
|
+
errors.append(ValidationError("step_index", "must not be negative"))
|
|
40
|
+
if msg.HasField("budget"):
|
|
41
|
+
b = msg.budget
|
|
42
|
+
if b.max_input_tokens < 0:
|
|
43
|
+
errors.append(
|
|
44
|
+
ValidationError("budget.max_input_tokens", "must not be negative")
|
|
45
|
+
)
|
|
46
|
+
if b.max_output_tokens < 0:
|
|
47
|
+
errors.append(
|
|
48
|
+
ValidationError("budget.max_output_tokens", "must not be negative")
|
|
49
|
+
)
|
|
50
|
+
if b.max_total_tokens < 0:
|
|
51
|
+
errors.append(
|
|
52
|
+
ValidationError("budget.max_total_tokens", "must not be negative")
|
|
53
|
+
)
|
|
54
|
+
if b.deadline_ms < 0:
|
|
55
|
+
errors.append(
|
|
56
|
+
ValidationError("budget.deadline_ms", "must not be negative")
|
|
57
|
+
)
|
|
58
|
+
return errors
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def validate_job_result(msg: Any) -> List[ValidationError]:
|
|
62
|
+
"""Validate semantic constraints on a JobResult."""
|
|
63
|
+
errors: List[ValidationError] = []
|
|
64
|
+
if msg is None:
|
|
65
|
+
errors.append(ValidationError("JobResult", "must not be nil"))
|
|
66
|
+
return errors
|
|
67
|
+
if not msg.job_id:
|
|
68
|
+
errors.append(ValidationError("job_id", "must not be empty"))
|
|
69
|
+
if msg.status == job_pb2.JOB_STATUS_UNSPECIFIED:
|
|
70
|
+
errors.append(ValidationError("status", "must not be UNSPECIFIED"))
|
|
71
|
+
if not msg.worker_id:
|
|
72
|
+
errors.append(ValidationError("worker_id", "must not be empty"))
|
|
73
|
+
if msg.execution_ms < 0:
|
|
74
|
+
errors.append(
|
|
75
|
+
ValidationError("execution_ms", "must not be negative")
|
|
76
|
+
)
|
|
77
|
+
return errors
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def validate_bus_packet(msg: Any) -> List[ValidationError]:
|
|
81
|
+
"""Validate semantic constraints on a BusPacket.
|
|
82
|
+
|
|
83
|
+
If the packet carries a JobRequest or JobResult payload,
|
|
84
|
+
it is also validated.
|
|
85
|
+
"""
|
|
86
|
+
errors: List[ValidationError] = []
|
|
87
|
+
if msg is None:
|
|
88
|
+
errors.append(ValidationError("BusPacket", "must not be nil"))
|
|
89
|
+
return errors
|
|
90
|
+
if not msg.trace_id:
|
|
91
|
+
errors.append(ValidationError("trace_id", "must not be empty"))
|
|
92
|
+
if not msg.sender_id:
|
|
93
|
+
errors.append(ValidationError("sender_id", "must not be empty"))
|
|
94
|
+
if msg.protocol_version <= 0:
|
|
95
|
+
errors.append(ValidationError("protocol_version", "must be > 0"))
|
|
96
|
+
if not msg.HasField("created_at"):
|
|
97
|
+
errors.append(ValidationError("created_at", "must not be nil"))
|
|
98
|
+
payload_field = msg.WhichOneof("payload")
|
|
99
|
+
if payload_field is None:
|
|
100
|
+
errors.append(ValidationError("payload", "must not be nil"))
|
|
101
|
+
elif payload_field == "job_request":
|
|
102
|
+
errors.extend(validate_job_request(msg.job_request))
|
|
103
|
+
elif payload_field == "job_result":
|
|
104
|
+
errors.extend(validate_job_result(msg.job_result))
|
|
105
|
+
return errors
|
|
@@ -1,13 +1,17 @@
|
|
|
1
1
|
import asyncio
|
|
2
|
+
import logging
|
|
2
3
|
from typing import Callable, Awaitable, Dict
|
|
3
4
|
|
|
4
5
|
from google.protobuf import timestamp_pb2
|
|
6
|
+
|
|
7
|
+
logger = logging.getLogger(__name__)
|
|
5
8
|
from cap.pb.cordum.agent.v1 import buspacket_pb2, job_pb2
|
|
6
9
|
from cryptography.hazmat.primitives.asymmetric import ec
|
|
7
10
|
from cryptography.hazmat.primitives import hashes
|
|
8
11
|
|
|
12
|
+
from cap.subjects import SUBJECT_RESULT
|
|
13
|
+
|
|
9
14
|
DEFAULT_PROTOCOL_VERSION = 1
|
|
10
|
-
SUBJECT_RESULT = "sys.job.result"
|
|
11
15
|
|
|
12
16
|
|
|
13
17
|
async def run_worker(nats_url: str, subject: str, handler: Callable[[job_pb2.JobRequest], Awaitable[job_pb2.JobResult]],
|
|
@@ -33,7 +37,7 @@ async def run_worker(nats_url: str, subject: str, handler: Callable[[job_pb2.Job
|
|
|
33
37
|
if public_keys:
|
|
34
38
|
public_key = public_keys.get(packet.sender_id)
|
|
35
39
|
if not public_key:
|
|
36
|
-
|
|
40
|
+
logger.warning("no public key found for sender: %s", packet.sender_id)
|
|
37
41
|
return
|
|
38
42
|
|
|
39
43
|
signature = packet.signature
|
|
@@ -43,7 +47,7 @@ async def run_worker(nats_url: str, subject: str, handler: Callable[[job_pb2.Job
|
|
|
43
47
|
try:
|
|
44
48
|
public_key.verify(signature, unsigned_data, ec.ECDSA(hashes.SHA256()))
|
|
45
49
|
except Exception:
|
|
46
|
-
|
|
50
|
+
logger.warning("invalid signature from sender: %s", packet.sender_id)
|
|
47
51
|
return
|
|
48
52
|
|
|
49
53
|
req = packet.job_request
|
|
@@ -1,8 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cap-sdk-python
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.5.2
|
|
4
4
|
Summary: CAP (Cordum Agent Protocol) Python SDK
|
|
5
|
+
Author-email: Cordum <eng@cordum.io>
|
|
6
|
+
License-Expression: Apache-2.0
|
|
5
7
|
Project-URL: Homepage, https://github.com/cordum-io/cap
|
|
8
|
+
Project-URL: Repository, https://github.com/cordum-io/cap
|
|
9
|
+
Project-URL: Issues, https://github.com/cordum-io/cap/issues
|
|
10
|
+
Keywords: cap,cordum,agent,protocol,sdk,ai
|
|
6
11
|
Requires-Python: >=3.9
|
|
7
12
|
Description-Content-Type: text/markdown
|
|
8
13
|
Requires-Dist: protobuf>=4.25.0
|
|
@@ -4,6 +4,8 @@ cap/__init__.py
|
|
|
4
4
|
cap/bus.py
|
|
5
5
|
cap/client.py
|
|
6
6
|
cap/runtime.py
|
|
7
|
+
cap/subjects.py
|
|
8
|
+
cap/validate.py
|
|
7
9
|
cap/worker.py
|
|
8
10
|
cap/pb/__init__.py
|
|
9
11
|
cap/pb/cordum/__init__.py
|
|
@@ -13,6 +15,8 @@ cap/pb/cordum/agent/v1/alert_pb2.py
|
|
|
13
15
|
cap/pb/cordum/agent/v1/alert_pb2_grpc.py
|
|
14
16
|
cap/pb/cordum/agent/v1/buspacket_pb2.py
|
|
15
17
|
cap/pb/cordum/agent/v1/buspacket_pb2_grpc.py
|
|
18
|
+
cap/pb/cordum/agent/v1/handshake_pb2.py
|
|
19
|
+
cap/pb/cordum/agent/v1/handshake_pb2_grpc.py
|
|
16
20
|
cap/pb/cordum/agent/v1/heartbeat_pb2.py
|
|
17
21
|
cap/pb/cordum/agent/v1/heartbeat_pb2_grpc.py
|
|
18
22
|
cap/pb/cordum/agent/v1/job_pb2.py
|
|
@@ -26,4 +30,5 @@ cap_sdk_python.egg-info/requires.txt
|
|
|
26
30
|
cap_sdk_python.egg-info/top_level.txt
|
|
27
31
|
tests/test_conformance.py
|
|
28
32
|
tests/test_runtime.py
|
|
29
|
-
tests/test_sdk.py
|
|
33
|
+
tests/test_sdk.py
|
|
34
|
+
tests/test_validate.py
|
|
@@ -4,10 +4,13 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "cap-sdk-python"
|
|
7
|
-
version = "2.
|
|
7
|
+
version = "2.5.2"
|
|
8
8
|
description = "CAP (Cordum Agent Protocol) Python SDK"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
11
|
+
license = "Apache-2.0"
|
|
12
|
+
authors = [{name = "Cordum", email = "eng@cordum.io"}]
|
|
13
|
+
keywords = ["cap", "cordum", "agent", "protocol", "sdk", "ai"]
|
|
11
14
|
dependencies = [
|
|
12
15
|
"protobuf>=4.25.0",
|
|
13
16
|
"grpcio>=1.59.0",
|
|
@@ -19,6 +22,9 @@ dependencies = [
|
|
|
19
22
|
|
|
20
23
|
[project.urls]
|
|
21
24
|
Homepage = "https://github.com/cordum-io/cap"
|
|
25
|
+
Repository = "https://github.com/cordum-io/cap"
|
|
26
|
+
Issues = "https://github.com/cordum-io/cap/issues"
|
|
22
27
|
|
|
23
28
|
[tool.setuptools.packages.find]
|
|
24
29
|
where = ["."]
|
|
30
|
+
exclude = ["tests", "tests.*"]
|
|
@@ -11,7 +11,7 @@ sys.path = [p for p in sys.path if not p.rstrip("/").endswith("python")]
|
|
|
11
11
|
sys.path.insert(0, _sdk_root)
|
|
12
12
|
sys.path.append(os.path.join(_sdk_root, "cap", "pb"))
|
|
13
13
|
|
|
14
|
-
from cap.pb.cordum.agent.v1 import buspacket_pb2
|
|
14
|
+
from cap.pb.cordum.agent.v1 import alert_pb2, buspacket_pb2, handshake_pb2, job_pb2
|
|
15
15
|
from cryptography.hazmat.primitives import hashes, serialization
|
|
16
16
|
from cryptography.hazmat.primitives.asymmetric import ec
|
|
17
17
|
|
|
@@ -104,6 +104,35 @@ class TestConformanceFixtures(unittest.TestCase):
|
|
|
104
104
|
self.assertEqual(alert.level, "WARN")
|
|
105
105
|
self.assertEqual(alert.component, "scheduler")
|
|
106
106
|
|
|
107
|
+
def test_handshake_fixture(self):
|
|
108
|
+
pkt = load_packet("buspacket_handshake.bin")
|
|
109
|
+
self._assert_common(pkt, "trace-handshake", "worker-1")
|
|
110
|
+
hs = pkt.handshake
|
|
111
|
+
self.assertEqual(hs.component_id, "worker-1")
|
|
112
|
+
self.assertEqual(hs.role, handshake_pb2.COMPONENT_ROLE_WORKER)
|
|
113
|
+
self.assertEqual(list(hs.supported_versions), [1])
|
|
114
|
+
self.assertTrue(hs.capabilities["signatures"])
|
|
115
|
+
self.assertTrue(hs.capabilities["progress"])
|
|
116
|
+
self.assertTrue(hs.capabilities["cancel"])
|
|
117
|
+
self.assertFalse(hs.capabilities["compensation"])
|
|
118
|
+
self.assertEqual(hs.sdk_version, "2.0.19")
|
|
119
|
+
|
|
120
|
+
def test_alert_enhanced_fixture(self):
|
|
121
|
+
pkt = load_packet("buspacket_alert_enhanced.bin")
|
|
122
|
+
self._assert_common(pkt, "trace-alert-enhanced", "scheduler-1")
|
|
123
|
+
alert = pkt.alert
|
|
124
|
+
# Legacy fields
|
|
125
|
+
self.assertEqual(alert.level, "CRITICAL")
|
|
126
|
+
self.assertEqual(alert.component, "scheduler")
|
|
127
|
+
self.assertEqual(alert.code, "SIGNATURE_INVALID")
|
|
128
|
+
# Enhanced fields
|
|
129
|
+
self.assertEqual(alert.severity, alert_pb2.ALERT_SEVERITY_CRITICAL)
|
|
130
|
+
self.assertEqual(alert.error_code_enum, job_pb2.ERROR_CODE_PROTOCOL_SIGNATURE_INVALID)
|
|
131
|
+
self.assertEqual(alert.source_component, "scheduler-1")
|
|
132
|
+
self.assertEqual(alert.details["sender"], "worker-bad")
|
|
133
|
+
self.assertEqual(alert.details["subject"], "sys.job.result")
|
|
134
|
+
self.assertEqual(alert.trace_id, "trace-offending-packet")
|
|
135
|
+
|
|
107
136
|
|
|
108
137
|
if __name__ == "__main__":
|
|
109
138
|
unittest.main()
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import unittest
|
|
4
|
+
|
|
5
|
+
_repo_root = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", ".."))
|
|
6
|
+
_sdk_root = os.path.join(_repo_root, "sdk", "python")
|
|
7
|
+
|
|
8
|
+
sys.path = [p for p in sys.path if not p.rstrip("/").endswith("python")]
|
|
9
|
+
sys.path.insert(0, _sdk_root)
|
|
10
|
+
sys.path.append(os.path.join(_sdk_root, "cap", "pb"))
|
|
11
|
+
|
|
12
|
+
from google.protobuf import timestamp_pb2
|
|
13
|
+
|
|
14
|
+
from cap.pb.cordum.agent.v1 import buspacket_pb2, job_pb2
|
|
15
|
+
from cap.validate import (
|
|
16
|
+
ValidationError,
|
|
17
|
+
validate_bus_packet,
|
|
18
|
+
validate_job_request,
|
|
19
|
+
validate_job_result,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _valid_job_request():
|
|
24
|
+
return job_pb2.JobRequest(job_id="job-1", topic="job.tools")
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _valid_job_result():
|
|
28
|
+
return job_pb2.JobResult(
|
|
29
|
+
job_id="job-1",
|
|
30
|
+
status=job_pb2.JOB_STATUS_SUCCEEDED,
|
|
31
|
+
worker_id="worker-1",
|
|
32
|
+
execution_ms=100,
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def _valid_bus_packet(payload=None):
|
|
37
|
+
req = payload or _valid_job_request()
|
|
38
|
+
pkt = buspacket_pb2.BusPacket(
|
|
39
|
+
trace_id="trace-1",
|
|
40
|
+
sender_id="sender-1",
|
|
41
|
+
protocol_version=1,
|
|
42
|
+
)
|
|
43
|
+
pkt.created_at.CopyFrom(timestamp_pb2.Timestamp(seconds=1000))
|
|
44
|
+
pkt.job_request.CopyFrom(req)
|
|
45
|
+
return pkt
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class TestValidateJobRequest(unittest.TestCase):
|
|
49
|
+
def test_valid_minimal(self):
|
|
50
|
+
self.assertEqual(validate_job_request(_valid_job_request()), [])
|
|
51
|
+
|
|
52
|
+
def test_valid_with_budget(self):
|
|
53
|
+
req = _valid_job_request()
|
|
54
|
+
req.budget.CopyFrom(
|
|
55
|
+
job_pb2.Budget(
|
|
56
|
+
max_input_tokens=1000,
|
|
57
|
+
max_output_tokens=500,
|
|
58
|
+
max_total_tokens=1500,
|
|
59
|
+
deadline_ms=30000,
|
|
60
|
+
)
|
|
61
|
+
)
|
|
62
|
+
self.assertEqual(validate_job_request(req), [])
|
|
63
|
+
|
|
64
|
+
def test_valid_with_all_fields(self):
|
|
65
|
+
req = _valid_job_request()
|
|
66
|
+
req.priority = job_pb2.JOB_PRIORITY_CRITICAL
|
|
67
|
+
req.context_ptr = "redis://ctx:1"
|
|
68
|
+
req.adapter_id = "adapter-1"
|
|
69
|
+
req.parent_job_id = "parent-1"
|
|
70
|
+
req.workflow_id = "wf-1"
|
|
71
|
+
req.step_index = 2
|
|
72
|
+
req.memory_id = "mem-1"
|
|
73
|
+
req.tenant_id = "tenant-1"
|
|
74
|
+
req.principal_id = "user-1"
|
|
75
|
+
self.assertEqual(validate_job_request(req), [])
|
|
76
|
+
|
|
77
|
+
def test_none(self):
|
|
78
|
+
errs = validate_job_request(None)
|
|
79
|
+
self.assertEqual(len(errs), 1)
|
|
80
|
+
self.assertEqual(errs[0].field, "JobRequest")
|
|
81
|
+
|
|
82
|
+
def test_empty_job_id(self):
|
|
83
|
+
req = _valid_job_request()
|
|
84
|
+
req.job_id = ""
|
|
85
|
+
errs = validate_job_request(req)
|
|
86
|
+
self._assert_has_field_error(errs, "job_id")
|
|
87
|
+
|
|
88
|
+
def test_empty_topic(self):
|
|
89
|
+
req = _valid_job_request()
|
|
90
|
+
req.topic = ""
|
|
91
|
+
errs = validate_job_request(req)
|
|
92
|
+
self._assert_has_field_error(errs, "topic")
|
|
93
|
+
|
|
94
|
+
def test_negative_step_index(self):
|
|
95
|
+
req = _valid_job_request()
|
|
96
|
+
req.step_index = -1
|
|
97
|
+
errs = validate_job_request(req)
|
|
98
|
+
self._assert_has_field_error(errs, "step_index")
|
|
99
|
+
|
|
100
|
+
def test_negative_budget_max_input_tokens(self):
|
|
101
|
+
req = _valid_job_request()
|
|
102
|
+
req.budget.CopyFrom(job_pb2.Budget(max_input_tokens=-1))
|
|
103
|
+
errs = validate_job_request(req)
|
|
104
|
+
self._assert_has_field_error(errs, "budget.max_input_tokens")
|
|
105
|
+
|
|
106
|
+
def test_negative_budget_max_output_tokens(self):
|
|
107
|
+
req = _valid_job_request()
|
|
108
|
+
req.budget.CopyFrom(job_pb2.Budget(max_output_tokens=-1))
|
|
109
|
+
errs = validate_job_request(req)
|
|
110
|
+
self._assert_has_field_error(errs, "budget.max_output_tokens")
|
|
111
|
+
|
|
112
|
+
def test_negative_budget_max_total_tokens(self):
|
|
113
|
+
req = _valid_job_request()
|
|
114
|
+
req.budget.CopyFrom(job_pb2.Budget(max_total_tokens=-1))
|
|
115
|
+
errs = validate_job_request(req)
|
|
116
|
+
self._assert_has_field_error(errs, "budget.max_total_tokens")
|
|
117
|
+
|
|
118
|
+
def test_negative_budget_deadline_ms(self):
|
|
119
|
+
req = _valid_job_request()
|
|
120
|
+
req.budget.CopyFrom(job_pb2.Budget(deadline_ms=-1))
|
|
121
|
+
errs = validate_job_request(req)
|
|
122
|
+
self._assert_has_field_error(errs, "budget.deadline_ms")
|
|
123
|
+
|
|
124
|
+
def test_zero_value_struct(self):
|
|
125
|
+
errs = validate_job_request(job_pb2.JobRequest())
|
|
126
|
+
self._assert_has_field_error(errs, "job_id")
|
|
127
|
+
|
|
128
|
+
def _assert_has_field_error(self, errs, field):
|
|
129
|
+
fields = [e.field for e in errs]
|
|
130
|
+
self.assertIn(field, fields, f"Expected error for {field}, got: {errs}")
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
class TestValidateJobResult(unittest.TestCase):
|
|
134
|
+
def test_valid_minimal(self):
|
|
135
|
+
self.assertEqual(validate_job_result(_valid_job_result()), [])
|
|
136
|
+
|
|
137
|
+
def test_valid_with_all_fields(self):
|
|
138
|
+
res = _valid_job_result()
|
|
139
|
+
res.result_ptr = "redis://res:1"
|
|
140
|
+
res.error_code = "E_TEMP"
|
|
141
|
+
res.error_message = "temporary failure"
|
|
142
|
+
res.artifact_ptrs.extend(["redis://art:1", "redis://art:2"])
|
|
143
|
+
self.assertEqual(validate_job_result(res), [])
|
|
144
|
+
|
|
145
|
+
def test_none(self):
|
|
146
|
+
errs = validate_job_result(None)
|
|
147
|
+
self.assertEqual(len(errs), 1)
|
|
148
|
+
self.assertEqual(errs[0].field, "JobResult")
|
|
149
|
+
|
|
150
|
+
def test_empty_job_id(self):
|
|
151
|
+
res = _valid_job_result()
|
|
152
|
+
res.job_id = ""
|
|
153
|
+
errs = validate_job_result(res)
|
|
154
|
+
self._assert_has_field_error(errs, "job_id")
|
|
155
|
+
|
|
156
|
+
def test_unspecified_status(self):
|
|
157
|
+
res = _valid_job_result()
|
|
158
|
+
res.status = job_pb2.JOB_STATUS_UNSPECIFIED
|
|
159
|
+
errs = validate_job_result(res)
|
|
160
|
+
self._assert_has_field_error(errs, "status")
|
|
161
|
+
|
|
162
|
+
def test_empty_worker_id(self):
|
|
163
|
+
res = _valid_job_result()
|
|
164
|
+
res.worker_id = ""
|
|
165
|
+
errs = validate_job_result(res)
|
|
166
|
+
self._assert_has_field_error(errs, "worker_id")
|
|
167
|
+
|
|
168
|
+
def test_negative_execution_ms(self):
|
|
169
|
+
res = _valid_job_result()
|
|
170
|
+
res.execution_ms = -1
|
|
171
|
+
errs = validate_job_result(res)
|
|
172
|
+
self._assert_has_field_error(errs, "execution_ms")
|
|
173
|
+
|
|
174
|
+
def test_zero_value_struct(self):
|
|
175
|
+
errs = validate_job_result(job_pb2.JobResult())
|
|
176
|
+
self._assert_has_field_error(errs, "job_id")
|
|
177
|
+
|
|
178
|
+
def _assert_has_field_error(self, errs, field):
|
|
179
|
+
fields = [e.field for e in errs]
|
|
180
|
+
self.assertIn(field, fields, f"Expected error for {field}, got: {errs}")
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
class TestValidateBusPacket(unittest.TestCase):
|
|
184
|
+
def test_valid_with_job_request(self):
|
|
185
|
+
self.assertEqual(validate_bus_packet(_valid_bus_packet()), [])
|
|
186
|
+
|
|
187
|
+
def test_valid_with_job_result(self):
|
|
188
|
+
pkt = buspacket_pb2.BusPacket(
|
|
189
|
+
trace_id="trace-1",
|
|
190
|
+
sender_id="sender-1",
|
|
191
|
+
protocol_version=1,
|
|
192
|
+
)
|
|
193
|
+
pkt.created_at.CopyFrom(timestamp_pb2.Timestamp(seconds=1000))
|
|
194
|
+
pkt.job_result.CopyFrom(_valid_job_result())
|
|
195
|
+
self.assertEqual(validate_bus_packet(pkt), [])
|
|
196
|
+
|
|
197
|
+
def test_valid_with_heartbeat(self):
|
|
198
|
+
from cap.pb.cordum.agent.v1 import heartbeat_pb2
|
|
199
|
+
|
|
200
|
+
pkt = buspacket_pb2.BusPacket(
|
|
201
|
+
trace_id="trace-1",
|
|
202
|
+
sender_id="sender-1",
|
|
203
|
+
protocol_version=1,
|
|
204
|
+
)
|
|
205
|
+
pkt.created_at.CopyFrom(timestamp_pb2.Timestamp(seconds=1000))
|
|
206
|
+
pkt.heartbeat.CopyFrom(
|
|
207
|
+
heartbeat_pb2.Heartbeat(worker_id="w-1", pool="p-1")
|
|
208
|
+
)
|
|
209
|
+
self.assertEqual(validate_bus_packet(pkt), [])
|
|
210
|
+
|
|
211
|
+
def test_none(self):
|
|
212
|
+
errs = validate_bus_packet(None)
|
|
213
|
+
self.assertEqual(len(errs), 1)
|
|
214
|
+
self.assertEqual(errs[0].field, "BusPacket")
|
|
215
|
+
|
|
216
|
+
def test_empty_trace_id(self):
|
|
217
|
+
pkt = _valid_bus_packet()
|
|
218
|
+
pkt.trace_id = ""
|
|
219
|
+
errs = validate_bus_packet(pkt)
|
|
220
|
+
self._assert_has_field_error(errs, "trace_id")
|
|
221
|
+
|
|
222
|
+
def test_empty_sender_id(self):
|
|
223
|
+
pkt = _valid_bus_packet()
|
|
224
|
+
pkt.sender_id = ""
|
|
225
|
+
errs = validate_bus_packet(pkt)
|
|
226
|
+
self._assert_has_field_error(errs, "sender_id")
|
|
227
|
+
|
|
228
|
+
def test_protocol_version_zero(self):
|
|
229
|
+
pkt = _valid_bus_packet()
|
|
230
|
+
pkt.protocol_version = 0
|
|
231
|
+
errs = validate_bus_packet(pkt)
|
|
232
|
+
self._assert_has_field_error(errs, "protocol_version")
|
|
233
|
+
|
|
234
|
+
def test_nil_created_at(self):
|
|
235
|
+
pkt = buspacket_pb2.BusPacket(
|
|
236
|
+
trace_id="trace-1",
|
|
237
|
+
sender_id="sender-1",
|
|
238
|
+
protocol_version=1,
|
|
239
|
+
)
|
|
240
|
+
pkt.job_request.CopyFrom(_valid_job_request())
|
|
241
|
+
errs = validate_bus_packet(pkt)
|
|
242
|
+
self._assert_has_field_error(errs, "created_at")
|
|
243
|
+
|
|
244
|
+
def test_nil_payload(self):
|
|
245
|
+
pkt = buspacket_pb2.BusPacket(
|
|
246
|
+
trace_id="trace-1",
|
|
247
|
+
sender_id="sender-1",
|
|
248
|
+
protocol_version=1,
|
|
249
|
+
)
|
|
250
|
+
pkt.created_at.CopyFrom(timestamp_pb2.Timestamp(seconds=1000))
|
|
251
|
+
errs = validate_bus_packet(pkt)
|
|
252
|
+
self._assert_has_field_error(errs, "payload")
|
|
253
|
+
|
|
254
|
+
def test_delegates_to_job_request_validation(self):
|
|
255
|
+
bad = job_pb2.JobRequest(job_id="", topic="t")
|
|
256
|
+
pkt = _valid_bus_packet(bad)
|
|
257
|
+
errs = validate_bus_packet(pkt)
|
|
258
|
+
self._assert_has_field_error(errs, "job_id")
|
|
259
|
+
|
|
260
|
+
def test_delegates_to_job_result_validation(self):
|
|
261
|
+
bad = job_pb2.JobResult(
|
|
262
|
+
job_id="", status=job_pb2.JOB_STATUS_SUCCEEDED, worker_id="w"
|
|
263
|
+
)
|
|
264
|
+
pkt = buspacket_pb2.BusPacket(
|
|
265
|
+
trace_id="trace-1",
|
|
266
|
+
sender_id="sender-1",
|
|
267
|
+
protocol_version=1,
|
|
268
|
+
)
|
|
269
|
+
pkt.created_at.CopyFrom(timestamp_pb2.Timestamp(seconds=1000))
|
|
270
|
+
pkt.job_result.CopyFrom(bad)
|
|
271
|
+
errs = validate_bus_packet(pkt)
|
|
272
|
+
self._assert_has_field_error(errs, "job_id")
|
|
273
|
+
|
|
274
|
+
def test_zero_value_struct(self):
|
|
275
|
+
errs = validate_bus_packet(buspacket_pb2.BusPacket())
|
|
276
|
+
self._assert_has_field_error(errs, "trace_id")
|
|
277
|
+
|
|
278
|
+
def _assert_has_field_error(self, errs, field):
|
|
279
|
+
fields = [e.field for e in errs]
|
|
280
|
+
self.assertIn(field, fields, f"Expected error for {field}, got: {errs}")
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
if __name__ == "__main__":
|
|
284
|
+
unittest.main()
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
-
# NO CHECKED-IN PROTOBUF GENCODE
|
|
4
|
-
# source: cordum/agent/v1/alert.proto
|
|
5
|
-
# Protobuf Python Version: 6.31.1
|
|
6
|
-
"""Generated protocol buffer code."""
|
|
7
|
-
from google.protobuf import descriptor as _descriptor
|
|
8
|
-
from google.protobuf import descriptor_pool as _descriptor_pool
|
|
9
|
-
from google.protobuf import runtime_version as _runtime_version
|
|
10
|
-
from google.protobuf import symbol_database as _symbol_database
|
|
11
|
-
from google.protobuf.internal import builder as _builder
|
|
12
|
-
_runtime_version.ValidateProtobufRuntimeVersion(
|
|
13
|
-
_runtime_version.Domain.PUBLIC,
|
|
14
|
-
6,
|
|
15
|
-
31,
|
|
16
|
-
1,
|
|
17
|
-
'',
|
|
18
|
-
'cordum/agent/v1/alert.proto'
|
|
19
|
-
)
|
|
20
|
-
# @@protoc_insertion_point(imports)
|
|
21
|
-
|
|
22
|
-
_sym_db = _symbol_database.Default()
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1b\x63ordum/agent/v1/alert.proto\x12\x0f\x63ordum.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\x7f\n\x16io.cordum.cap.agent.v1P\x01Z+github.com/cordum-io/cap/v2/cordum/agent/v1\xaa\x02\x0f\x43ordum.Agent.V1\xca\x02\x0f\x63ordum\\Agent\\V1\xea\x02\x11\x43ordum::Agent::V1b\x06proto3')
|
|
28
|
-
|
|
29
|
-
_globals = globals()
|
|
30
|
-
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
31
|
-
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'cordum.agent.v1.alert_pb2', _globals)
|
|
32
|
-
if not _descriptor._USE_C_DESCRIPTORS:
|
|
33
|
-
_globals['DESCRIPTOR']._loaded_options = None
|
|
34
|
-
_globals['DESCRIPTOR']._serialized_options = b'\n\026io.cordum.cap.agent.v1P\001Z+github.com/cordum-io/cap/v2/cordum/agent/v1\252\002\017Cordum.Agent.V1\312\002\017cordum\\Agent\\V1\352\002\021Cordum::Agent::V1'
|
|
35
|
-
_globals['_SYSTEMALERT']._serialized_start=48
|
|
36
|
-
_globals['_SYSTEMALERT']._serialized_end=126
|
|
37
|
-
# @@protoc_insertion_point(module_scope)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|