dispatch_agents 0.9.0__py3-none-any.whl
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.
- agentservice/__init__.py +0 -0
- agentservice/py.typed +0 -0
- agentservice/v1/__init__.py +0 -0
- agentservice/v1/message_pb2.py +41 -0
- agentservice/v1/message_pb2.pyi +22 -0
- agentservice/v1/message_pb2_grpc.py +4 -0
- agentservice/v1/request_response_pb2.py +46 -0
- agentservice/v1/request_response_pb2.pyi +54 -0
- agentservice/v1/request_response_pb2_grpc.py +4 -0
- agentservice/v1/service_pb2.py +43 -0
- agentservice/v1/service_pb2.pyi +6 -0
- agentservice/v1/service_pb2_grpc.py +129 -0
- dispatch_agents/__init__.py +281 -0
- dispatch_agents/agent_service.py +135 -0
- dispatch_agents/config.py +490 -0
- dispatch_agents/contrib/__init__.py +1 -0
- dispatch_agents/contrib/claude/__init__.py +246 -0
- dispatch_agents/contrib/openai/__init__.py +167 -0
- dispatch_agents/events.py +986 -0
- dispatch_agents/grpc_server.py +565 -0
- dispatch_agents/instrument.py +217 -0
- dispatch_agents/integrations/__init__.py +1 -0
- dispatch_agents/integrations/github/README.md +9 -0
- dispatch_agents/integrations/github/__init__.py +4268 -0
- dispatch_agents/invocation.py +25 -0
- dispatch_agents/llm.py +1017 -0
- dispatch_agents/llm_langchain.py +394 -0
- dispatch_agents/logging_config.py +133 -0
- dispatch_agents/mcp.py +266 -0
- dispatch_agents/memory.py +264 -0
- dispatch_agents/models.py +748 -0
- dispatch_agents/proxy/__init__.py +6 -0
- dispatch_agents/proxy/server.py +1137 -0
- dispatch_agents/proxy/sse_utils.py +76 -0
- dispatch_agents/py.typed +0 -0
- dispatch_agents/resources.py +68 -0
- dispatch_agents/version.py +19 -0
- dispatch_agents-0.9.0.dist-info/METADATA +20 -0
- dispatch_agents-0.9.0.dist-info/RECORD +43 -0
- dispatch_agents-0.9.0.dist-info/WHEEL +4 -0
- dispatch_agents-0.9.0.dist-info/licenses/LICENSE +191 -0
- dispatch_agents-0.9.0.dist-info/licenses/LICENSE-3rdparty.csv +12 -0
- dispatch_agents-0.9.0.dist-info/licenses/NOTICE +5 -0
agentservice/__init__.py
ADDED
|
File without changes
|
agentservice/py.typed
ADDED
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
+
# NO CHECKED-IN PROTOBUF GENCODE
|
|
4
|
+
# source: agentservice/v1/message.proto
|
|
5
|
+
# Protobuf Python Version: 6.33.5
|
|
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
|
+
33,
|
|
16
|
+
5,
|
|
17
|
+
'',
|
|
18
|
+
'agentservice/v1/message.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\x1d\x61gentservice/v1/message.proto\x12\x0f\x61gentservice.v1\"\x9e\x01\n\x07Payload\x12\x42\n\x08metadata\x18\x01 \x03(\x0b\x32&.agentservice.v1.Payload.MetadataEntryR\x08metadata\x12\x12\n\x04\x64\x61ta\x18\x02 \x01(\x0cR\x04\x64\x61ta\x1a;\n\rMetadataEntry\x12\x10\n\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n\x05value\x18\x02 \x01(\x0cR\x05value:\x02\x38\x01\x42\x80\x01\n\x13\x63om.agentservice.v1B\x0cMessageProtoP\x01\xa2\x02\x03\x41XX\xaa\x02\x0f\x41gentservice.V1\xca\x02\x0f\x41gentservice\\V1\xe2\x02\x1b\x41gentservice\\V1\\GPBMetadata\xea\x02\x10\x41gentservice::V1b\x06proto3')
|
|
28
|
+
|
|
29
|
+
_globals = globals()
|
|
30
|
+
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
31
|
+
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'agentservice.v1.message_pb2', _globals)
|
|
32
|
+
if not _descriptor._USE_C_DESCRIPTORS:
|
|
33
|
+
_globals['DESCRIPTOR']._loaded_options = None
|
|
34
|
+
_globals['DESCRIPTOR']._serialized_options = b'\n\023com.agentservice.v1B\014MessageProtoP\001\242\002\003AXX\252\002\017Agentservice.V1\312\002\017Agentservice\\V1\342\002\033Agentservice\\V1\\GPBMetadata\352\002\020Agentservice::V1'
|
|
35
|
+
_globals['_PAYLOAD_METADATAENTRY']._loaded_options = None
|
|
36
|
+
_globals['_PAYLOAD_METADATAENTRY']._serialized_options = b'8\001'
|
|
37
|
+
_globals['_PAYLOAD']._serialized_start=51
|
|
38
|
+
_globals['_PAYLOAD']._serialized_end=209
|
|
39
|
+
_globals['_PAYLOAD_METADATAENTRY']._serialized_start=150
|
|
40
|
+
_globals['_PAYLOAD_METADATAENTRY']._serialized_end=209
|
|
41
|
+
# @@protoc_insertion_point(module_scope)
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from google.protobuf.internal import containers as _containers
|
|
2
|
+
from google.protobuf import descriptor as _descriptor
|
|
3
|
+
from google.protobuf import message as _message
|
|
4
|
+
from collections.abc import Mapping as _Mapping
|
|
5
|
+
from typing import ClassVar as _ClassVar, Optional as _Optional
|
|
6
|
+
|
|
7
|
+
DESCRIPTOR: _descriptor.FileDescriptor
|
|
8
|
+
|
|
9
|
+
class Payload(_message.Message):
|
|
10
|
+
__slots__ = ("metadata", "data")
|
|
11
|
+
class MetadataEntry(_message.Message):
|
|
12
|
+
__slots__ = ("key", "value")
|
|
13
|
+
KEY_FIELD_NUMBER: _ClassVar[int]
|
|
14
|
+
VALUE_FIELD_NUMBER: _ClassVar[int]
|
|
15
|
+
key: str
|
|
16
|
+
value: bytes
|
|
17
|
+
def __init__(self, key: _Optional[str] = ..., value: _Optional[bytes] = ...) -> None: ...
|
|
18
|
+
METADATA_FIELD_NUMBER: _ClassVar[int]
|
|
19
|
+
DATA_FIELD_NUMBER: _ClassVar[int]
|
|
20
|
+
metadata: _containers.ScalarMap[str, bytes]
|
|
21
|
+
data: bytes
|
|
22
|
+
def __init__(self, metadata: _Optional[_Mapping[str, bytes]] = ..., data: _Optional[bytes] = ...) -> None: ...
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
|
3
|
+
# NO CHECKED-IN PROTOBUF GENCODE
|
|
4
|
+
# source: agentservice/v1/request_response.proto
|
|
5
|
+
# Protobuf Python Version: 6.33.5
|
|
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
|
+
33,
|
|
16
|
+
5,
|
|
17
|
+
'',
|
|
18
|
+
'agentservice/v1/request_response.proto'
|
|
19
|
+
)
|
|
20
|
+
# @@protoc_insertion_point(imports)
|
|
21
|
+
|
|
22
|
+
_sym_db = _symbol_database.Default()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
from agentservice.v1 import message_pb2 as agentservice_dot_v1_dot_message__pb2
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n&agentservice/v1/request_response.proto\x12\x0f\x61gentservice.v1\x1a\x1d\x61gentservice/v1/message.proto\"\xde\x01\n\rInvokeRequest\x12#\n\rfunction_name\x18\x01 \x01(\tR\x0c\x66unctionName\x12\x32\n\x07payload\x18\x02 \x01(\x0b\x32\x18.agentservice.v1.PayloadR\x07payload\x12\x10\n\x03uid\x18\x03 \x01(\tR\x03uid\x12\x19\n\x08trace_id\x18\x04 \x01(\tR\x07traceId\x12\x0e\n\x02ts\x18\x06 \x01(\tR\x02ts\x12\x14\n\x05topic\x18\x07 \x01(\tR\x05topic\x12!\n\x0cmessage_type\x18\x08 \x01(\tR\x0bmessageType\"]\n\x0eInvokeResponse\x12\x30\n\x06result\x18\x01 \x01(\x0b\x32\x18.agentservice.v1.PayloadR\x06result\x12\x19\n\x08is_error\x18\x02 \x01(\x08R\x07isError\"\x14\n\x12HealthCheckRequest\"\xf3\x01\n\x13HealthCheckResponse\x12J\n\x06status\x18\x01 \x01(\x0e\x32\x32.agentservice.v1.HealthCheckResponse.ServingStatusR\x06status\"\x8f\x01\n\rServingStatus\x12\x1e\n\x1aSERVING_STATUS_UNSPECIFIED\x10\x00\x12\x1a\n\x16SERVING_STATUS_SERVING\x10\x01\x12\x1e\n\x1aSERVING_STATUS_NOT_SERVING\x10\x02\x12\"\n\x1eSERVING_STATUS_SERVICE_UNKNOWN\x10\x03\x42\x88\x01\n\x13\x63om.agentservice.v1B\x14RequestResponseProtoP\x01\xa2\x02\x03\x41XX\xaa\x02\x0f\x41gentservice.V1\xca\x02\x0f\x41gentservice\\V1\xe2\x02\x1b\x41gentservice\\V1\\GPBMetadata\xea\x02\x10\x41gentservice::V1b\x06proto3')
|
|
29
|
+
|
|
30
|
+
_globals = globals()
|
|
31
|
+
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
32
|
+
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'agentservice.v1.request_response_pb2', _globals)
|
|
33
|
+
if not _descriptor._USE_C_DESCRIPTORS:
|
|
34
|
+
_globals['DESCRIPTOR']._loaded_options = None
|
|
35
|
+
_globals['DESCRIPTOR']._serialized_options = b'\n\023com.agentservice.v1B\024RequestResponseProtoP\001\242\002\003AXX\252\002\017Agentservice.V1\312\002\017Agentservice\\V1\342\002\033Agentservice\\V1\\GPBMetadata\352\002\020Agentservice::V1'
|
|
36
|
+
_globals['_INVOKEREQUEST']._serialized_start=91
|
|
37
|
+
_globals['_INVOKEREQUEST']._serialized_end=313
|
|
38
|
+
_globals['_INVOKERESPONSE']._serialized_start=315
|
|
39
|
+
_globals['_INVOKERESPONSE']._serialized_end=408
|
|
40
|
+
_globals['_HEALTHCHECKREQUEST']._serialized_start=410
|
|
41
|
+
_globals['_HEALTHCHECKREQUEST']._serialized_end=430
|
|
42
|
+
_globals['_HEALTHCHECKRESPONSE']._serialized_start=433
|
|
43
|
+
_globals['_HEALTHCHECKRESPONSE']._serialized_end=676
|
|
44
|
+
_globals['_HEALTHCHECKRESPONSE_SERVINGSTATUS']._serialized_start=533
|
|
45
|
+
_globals['_HEALTHCHECKRESPONSE_SERVINGSTATUS']._serialized_end=676
|
|
46
|
+
# @@protoc_insertion_point(module_scope)
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
from agentservice.v1 import message_pb2 as _message_pb2
|
|
2
|
+
from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper
|
|
3
|
+
from google.protobuf import descriptor as _descriptor
|
|
4
|
+
from google.protobuf import message as _message
|
|
5
|
+
from collections.abc import Mapping as _Mapping
|
|
6
|
+
from typing import ClassVar as _ClassVar, Optional as _Optional, Union as _Union
|
|
7
|
+
|
|
8
|
+
DESCRIPTOR: _descriptor.FileDescriptor
|
|
9
|
+
|
|
10
|
+
class InvokeRequest(_message.Message):
|
|
11
|
+
__slots__ = ("function_name", "payload", "uid", "trace_id", "ts", "topic", "message_type")
|
|
12
|
+
FUNCTION_NAME_FIELD_NUMBER: _ClassVar[int]
|
|
13
|
+
PAYLOAD_FIELD_NUMBER: _ClassVar[int]
|
|
14
|
+
UID_FIELD_NUMBER: _ClassVar[int]
|
|
15
|
+
TRACE_ID_FIELD_NUMBER: _ClassVar[int]
|
|
16
|
+
TS_FIELD_NUMBER: _ClassVar[int]
|
|
17
|
+
TOPIC_FIELD_NUMBER: _ClassVar[int]
|
|
18
|
+
MESSAGE_TYPE_FIELD_NUMBER: _ClassVar[int]
|
|
19
|
+
function_name: str
|
|
20
|
+
payload: _message_pb2.Payload
|
|
21
|
+
uid: str
|
|
22
|
+
trace_id: str
|
|
23
|
+
ts: str
|
|
24
|
+
topic: str
|
|
25
|
+
message_type: str
|
|
26
|
+
def __init__(self, function_name: _Optional[str] = ..., payload: _Optional[_Union[_message_pb2.Payload, _Mapping]] = ..., uid: _Optional[str] = ..., trace_id: _Optional[str] = ..., ts: _Optional[str] = ..., topic: _Optional[str] = ..., message_type: _Optional[str] = ...) -> None: ...
|
|
27
|
+
|
|
28
|
+
class InvokeResponse(_message.Message):
|
|
29
|
+
__slots__ = ("result", "is_error")
|
|
30
|
+
RESULT_FIELD_NUMBER: _ClassVar[int]
|
|
31
|
+
IS_ERROR_FIELD_NUMBER: _ClassVar[int]
|
|
32
|
+
result: _message_pb2.Payload
|
|
33
|
+
is_error: bool
|
|
34
|
+
def __init__(self, result: _Optional[_Union[_message_pb2.Payload, _Mapping]] = ..., is_error: _Optional[bool] = ...) -> None: ...
|
|
35
|
+
|
|
36
|
+
class HealthCheckRequest(_message.Message):
|
|
37
|
+
__slots__ = ()
|
|
38
|
+
def __init__(self) -> None: ...
|
|
39
|
+
|
|
40
|
+
class HealthCheckResponse(_message.Message):
|
|
41
|
+
__slots__ = ("status",)
|
|
42
|
+
class ServingStatus(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):
|
|
43
|
+
__slots__ = ()
|
|
44
|
+
SERVING_STATUS_UNSPECIFIED: _ClassVar[HealthCheckResponse.ServingStatus]
|
|
45
|
+
SERVING_STATUS_SERVING: _ClassVar[HealthCheckResponse.ServingStatus]
|
|
46
|
+
SERVING_STATUS_NOT_SERVING: _ClassVar[HealthCheckResponse.ServingStatus]
|
|
47
|
+
SERVING_STATUS_SERVICE_UNKNOWN: _ClassVar[HealthCheckResponse.ServingStatus]
|
|
48
|
+
SERVING_STATUS_UNSPECIFIED: HealthCheckResponse.ServingStatus
|
|
49
|
+
SERVING_STATUS_SERVING: HealthCheckResponse.ServingStatus
|
|
50
|
+
SERVING_STATUS_NOT_SERVING: HealthCheckResponse.ServingStatus
|
|
51
|
+
SERVING_STATUS_SERVICE_UNKNOWN: HealthCheckResponse.ServingStatus
|
|
52
|
+
STATUS_FIELD_NUMBER: _ClassVar[int]
|
|
53
|
+
status: HealthCheckResponse.ServingStatus
|
|
54
|
+
def __init__(self, status: _Optional[_Union[HealthCheckResponse.ServingStatus, str]] = ...) -> None: ...
|
|
@@ -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: agentservice/v1/service.proto
|
|
5
|
+
# Protobuf Python Version: 6.33.5
|
|
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
|
+
33,
|
|
16
|
+
5,
|
|
17
|
+
'',
|
|
18
|
+
'agentservice/v1/service.proto'
|
|
19
|
+
)
|
|
20
|
+
# @@protoc_insertion_point(imports)
|
|
21
|
+
|
|
22
|
+
_sym_db = _symbol_database.Default()
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
from agentservice.v1 import request_response_pb2 as agentservice_dot_v1_dot_request__response__pb2
|
|
26
|
+
from google.api import annotations_pb2 as google_dot_api_dot_annotations__pb2
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x1d\x61gentservice/v1/service.proto\x12\x0f\x61gentservice.v1\x1a&agentservice/v1/request_response.proto\x1a\x1cgoogle/api/annotations.proto2\xf2\x01\n\x0c\x41gentService\x12j\n\x06Invoke\x12\x1e.agentservice.v1.InvokeRequest\x1a\x1f.agentservice.v1.InvokeResponse\"\x1f\x82\xd3\xe4\x93\x02\x19\"\x14/api/v1/agent/invoke:\x01*\x12v\n\x0bHealthCheck\x12#.agentservice.v1.HealthCheckRequest\x1a$.agentservice.v1.HealthCheckResponse\"\x1c\x82\xd3\xe4\x93\x02\x16\x12\x14/api/v1/agent/healthB\x80\x01\n\x13\x63om.agentservice.v1B\x0cServiceProtoP\x01\xa2\x02\x03\x41XX\xaa\x02\x0f\x41gentservice.V1\xca\x02\x0f\x41gentservice\\V1\xe2\x02\x1b\x41gentservice\\V1\\GPBMetadata\xea\x02\x10\x41gentservice::V1b\x06proto3')
|
|
30
|
+
|
|
31
|
+
_globals = globals()
|
|
32
|
+
_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
|
|
33
|
+
_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'agentservice.v1.service_pb2', _globals)
|
|
34
|
+
if not _descriptor._USE_C_DESCRIPTORS:
|
|
35
|
+
_globals['DESCRIPTOR']._loaded_options = None
|
|
36
|
+
_globals['DESCRIPTOR']._serialized_options = b'\n\023com.agentservice.v1B\014ServiceProtoP\001\242\002\003AXX\252\002\017Agentservice.V1\312\002\017Agentservice\\V1\342\002\033Agentservice\\V1\\GPBMetadata\352\002\020Agentservice::V1'
|
|
37
|
+
_globals['_AGENTSERVICE'].methods_by_name['Invoke']._loaded_options = None
|
|
38
|
+
_globals['_AGENTSERVICE'].methods_by_name['Invoke']._serialized_options = b'\202\323\344\223\002\031\"\024/api/v1/agent/invoke:\001*'
|
|
39
|
+
_globals['_AGENTSERVICE'].methods_by_name['HealthCheck']._loaded_options = None
|
|
40
|
+
_globals['_AGENTSERVICE'].methods_by_name['HealthCheck']._serialized_options = b'\202\323\344\223\002\026\022\024/api/v1/agent/health'
|
|
41
|
+
_globals['_AGENTSERVICE']._serialized_start=121
|
|
42
|
+
_globals['_AGENTSERVICE']._serialized_end=363
|
|
43
|
+
# @@protoc_insertion_point(module_scope)
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
from agentservice.v1 import request_response_pb2 as _request_response_pb2
|
|
2
|
+
from google.api import annotations_pb2 as _annotations_pb2
|
|
3
|
+
from google.protobuf import descriptor as _descriptor
|
|
4
|
+
from typing import ClassVar as _ClassVar
|
|
5
|
+
|
|
6
|
+
DESCRIPTOR: _descriptor.FileDescriptor
|
|
@@ -0,0 +1,129 @@
|
|
|
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 agentservice.v1 import request_response_pb2 as agentservice_dot_v1_dot_request__response__pb2
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AgentServiceStub(object):
|
|
9
|
+
"""AgentService provides a simple RPC interface that mirrors the agent_sidecar
|
|
10
|
+
temporal worker's activity API for invoking agents and awaiting results.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, channel):
|
|
14
|
+
"""Constructor.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
channel: A grpc.Channel.
|
|
18
|
+
"""
|
|
19
|
+
self.Invoke = channel.unary_unary(
|
|
20
|
+
'/agentservice.v1.AgentService/Invoke',
|
|
21
|
+
request_serializer=agentservice_dot_v1_dot_request__response__pb2.InvokeRequest.SerializeToString,
|
|
22
|
+
response_deserializer=agentservice_dot_v1_dot_request__response__pb2.InvokeResponse.FromString,
|
|
23
|
+
_registered_method=True)
|
|
24
|
+
self.HealthCheck = channel.unary_unary(
|
|
25
|
+
'/agentservice.v1.AgentService/HealthCheck',
|
|
26
|
+
request_serializer=agentservice_dot_v1_dot_request__response__pb2.HealthCheckRequest.SerializeToString,
|
|
27
|
+
response_deserializer=agentservice_dot_v1_dot_request__response__pb2.HealthCheckResponse.FromString,
|
|
28
|
+
_registered_method=True)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class AgentServiceServicer(object):
|
|
32
|
+
"""AgentService provides a simple RPC interface that mirrors the agent_sidecar
|
|
33
|
+
temporal worker's activity API for invoking agents and awaiting results.
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def Invoke(self, request, context):
|
|
37
|
+
"""Invoke invokes an agent and waits for the result.
|
|
38
|
+
This mirrors the temporal activity API used by the agent_sidecar worker.
|
|
39
|
+
"""
|
|
40
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
41
|
+
context.set_details('Method not implemented!')
|
|
42
|
+
raise NotImplementedError('Method not implemented!')
|
|
43
|
+
|
|
44
|
+
def HealthCheck(self, request, context):
|
|
45
|
+
"""Check performs a health check on the agent.
|
|
46
|
+
"""
|
|
47
|
+
context.set_code(grpc.StatusCode.UNIMPLEMENTED)
|
|
48
|
+
context.set_details('Method not implemented!')
|
|
49
|
+
raise NotImplementedError('Method not implemented!')
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def add_AgentServiceServicer_to_server(servicer, server):
|
|
53
|
+
rpc_method_handlers = {
|
|
54
|
+
'Invoke': grpc.unary_unary_rpc_method_handler(
|
|
55
|
+
servicer.Invoke,
|
|
56
|
+
request_deserializer=agentservice_dot_v1_dot_request__response__pb2.InvokeRequest.FromString,
|
|
57
|
+
response_serializer=agentservice_dot_v1_dot_request__response__pb2.InvokeResponse.SerializeToString,
|
|
58
|
+
),
|
|
59
|
+
'HealthCheck': grpc.unary_unary_rpc_method_handler(
|
|
60
|
+
servicer.HealthCheck,
|
|
61
|
+
request_deserializer=agentservice_dot_v1_dot_request__response__pb2.HealthCheckRequest.FromString,
|
|
62
|
+
response_serializer=agentservice_dot_v1_dot_request__response__pb2.HealthCheckResponse.SerializeToString,
|
|
63
|
+
),
|
|
64
|
+
}
|
|
65
|
+
generic_handler = grpc.method_handlers_generic_handler(
|
|
66
|
+
'agentservice.v1.AgentService', rpc_method_handlers)
|
|
67
|
+
server.add_generic_rpc_handlers((generic_handler,))
|
|
68
|
+
server.add_registered_method_handlers('agentservice.v1.AgentService', rpc_method_handlers)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# This class is part of an EXPERIMENTAL API.
|
|
72
|
+
class AgentService(object):
|
|
73
|
+
"""AgentService provides a simple RPC interface that mirrors the agent_sidecar
|
|
74
|
+
temporal worker's activity API for invoking agents and awaiting results.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
@staticmethod
|
|
78
|
+
def Invoke(request,
|
|
79
|
+
target,
|
|
80
|
+
options=(),
|
|
81
|
+
channel_credentials=None,
|
|
82
|
+
call_credentials=None,
|
|
83
|
+
insecure=False,
|
|
84
|
+
compression=None,
|
|
85
|
+
wait_for_ready=None,
|
|
86
|
+
timeout=None,
|
|
87
|
+
metadata=None):
|
|
88
|
+
return grpc.experimental.unary_unary(
|
|
89
|
+
request,
|
|
90
|
+
target,
|
|
91
|
+
'/agentservice.v1.AgentService/Invoke',
|
|
92
|
+
agentservice_dot_v1_dot_request__response__pb2.InvokeRequest.SerializeToString,
|
|
93
|
+
agentservice_dot_v1_dot_request__response__pb2.InvokeResponse.FromString,
|
|
94
|
+
options,
|
|
95
|
+
channel_credentials,
|
|
96
|
+
insecure,
|
|
97
|
+
call_credentials,
|
|
98
|
+
compression,
|
|
99
|
+
wait_for_ready,
|
|
100
|
+
timeout,
|
|
101
|
+
metadata,
|
|
102
|
+
_registered_method=True)
|
|
103
|
+
|
|
104
|
+
@staticmethod
|
|
105
|
+
def HealthCheck(request,
|
|
106
|
+
target,
|
|
107
|
+
options=(),
|
|
108
|
+
channel_credentials=None,
|
|
109
|
+
call_credentials=None,
|
|
110
|
+
insecure=False,
|
|
111
|
+
compression=None,
|
|
112
|
+
wait_for_ready=None,
|
|
113
|
+
timeout=None,
|
|
114
|
+
metadata=None):
|
|
115
|
+
return grpc.experimental.unary_unary(
|
|
116
|
+
request,
|
|
117
|
+
target,
|
|
118
|
+
'/agentservice.v1.AgentService/HealthCheck',
|
|
119
|
+
agentservice_dot_v1_dot_request__response__pb2.HealthCheckRequest.SerializeToString,
|
|
120
|
+
agentservice_dot_v1_dot_request__response__pb2.HealthCheckResponse.FromString,
|
|
121
|
+
options,
|
|
122
|
+
channel_credentials,
|
|
123
|
+
insecure,
|
|
124
|
+
call_credentials,
|
|
125
|
+
compression,
|
|
126
|
+
wait_for_ready,
|
|
127
|
+
timeout,
|
|
128
|
+
metadata,
|
|
129
|
+
_registered_method=True)
|
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import tempfile
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
# Add SDK root to Python path so generated protobuf files can import
|
|
7
|
+
# using their package structure (e.g., "from agentservice.v1 import ...")
|
|
8
|
+
_sdk_root = str(Path(__file__).parent.parent)
|
|
9
|
+
if _sdk_root not in sys.path:
|
|
10
|
+
sys.path.insert(0, _sdk_root)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def get_data_dir() -> Path:
|
|
14
|
+
"""Get the data directory for persistent storage.
|
|
15
|
+
|
|
16
|
+
In production, this returns /data (EFS mount point).
|
|
17
|
+
In local dev mode (`dispatch agent dev`), this returns the mock data directory
|
|
18
|
+
set by DISPATCH_DEV_DATA_DIR environment variable.
|
|
19
|
+
|
|
20
|
+
Returns:
|
|
21
|
+
Path to the data directory
|
|
22
|
+
|
|
23
|
+
Example:
|
|
24
|
+
from dispatch_agents import get_data_dir
|
|
25
|
+
|
|
26
|
+
DATA_DIR = get_data_dir()
|
|
27
|
+
my_file = DATA_DIR / "myfile.txt"
|
|
28
|
+
my_file.write_text("hello")
|
|
29
|
+
"""
|
|
30
|
+
dev_data_dir = os.environ.get("DISPATCH_DEV_DATA_DIR")
|
|
31
|
+
if dev_data_dir:
|
|
32
|
+
# In dev mode, use the mock data directory
|
|
33
|
+
return Path(dev_data_dir) / "data"
|
|
34
|
+
# In production, use the EFS mount at /data
|
|
35
|
+
return Path("/data")
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# =============================================================================
|
|
39
|
+
# Dev Mode Audit Hook - Restricts writes to allowed directories
|
|
40
|
+
# =============================================================================
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
class DisallowedWriteError(Exception):
|
|
44
|
+
"""Raised when an agent attempts to write outside allowed directories in dev mode."""
|
|
45
|
+
|
|
46
|
+
pass
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
_audit_hook_blocked: set[str] = set() # Track blocked paths to avoid duplicate errors
|
|
50
|
+
_audit_hook_allowed_prefixes: list[str] = [] # Computed once at startup
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
def _init_allowed_prefixes() -> list[str]:
|
|
54
|
+
"""Compute the list of allowed write prefixes for dev mode.
|
|
55
|
+
|
|
56
|
+
Allowed locations:
|
|
57
|
+
1. get_data_dir() - the mock data directory
|
|
58
|
+
2. /tmp - temporary files (and system temp directory)
|
|
59
|
+
3. Agent folder - where the agent code lives (derived from DISPATCH_DEV_DATA_DIR)
|
|
60
|
+
|
|
61
|
+
All paths are resolved to their canonical form to handle symlinks
|
|
62
|
+
(e.g., macOS /var -> /private/var).
|
|
63
|
+
"""
|
|
64
|
+
allowed = []
|
|
65
|
+
|
|
66
|
+
def resolve_path(p: str) -> str:
|
|
67
|
+
"""Resolve path to canonical form, handling symlinks."""
|
|
68
|
+
try:
|
|
69
|
+
return str(Path(p).resolve())
|
|
70
|
+
except (OSError, ValueError):
|
|
71
|
+
return p
|
|
72
|
+
|
|
73
|
+
# 1. The data directory from get_data_dir()
|
|
74
|
+
allowed.append(resolve_path(str(get_data_dir())))
|
|
75
|
+
|
|
76
|
+
# 2. Temp directories - include both standard paths and the system's actual temp
|
|
77
|
+
# Resolve all paths to handle macOS symlinks (/var -> /private/var)
|
|
78
|
+
allowed.append(resolve_path("/tmp"))
|
|
79
|
+
allowed.append(resolve_path("/var/tmp"))
|
|
80
|
+
# macOS temp dirs (may be redundant after resolution, but included for safety)
|
|
81
|
+
allowed.append(resolve_path("/private/tmp"))
|
|
82
|
+
allowed.append(resolve_path("/private/var/tmp"))
|
|
83
|
+
# System temp directory (handles macOS /var/folders/... and other platforms)
|
|
84
|
+
allowed.append(resolve_path(tempfile.gettempdir()))
|
|
85
|
+
|
|
86
|
+
# 3. Agent folder - DISPATCH_DEV_DATA_DIR is {agent_path}/.dispatch/dev-data
|
|
87
|
+
dev_data_dir = os.environ.get("DISPATCH_DEV_DATA_DIR", "")
|
|
88
|
+
if dev_data_dir:
|
|
89
|
+
# Go up two levels: dev-data -> .dispatch -> agent_folder
|
|
90
|
+
agent_folder = str(Path(dev_data_dir).parent.parent)
|
|
91
|
+
allowed.append(resolve_path(agent_folder))
|
|
92
|
+
|
|
93
|
+
return allowed
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def _dev_mode_audit_hook(event: str, args: tuple) -> None:
|
|
97
|
+
"""Block file operations that target paths outside allowed directories.
|
|
98
|
+
|
|
99
|
+
In dev mode, agents should only write to:
|
|
100
|
+
- get_data_dir() (mock persistent storage)
|
|
101
|
+
- /tmp (temporary files)
|
|
102
|
+
- The agent's own folder
|
|
103
|
+
|
|
104
|
+
This protects the developer's machine from accidental writes to arbitrary locations.
|
|
105
|
+
Use --allow-arbitrary-writes flag or DISPATCH_ALLOW_ARBITRARY_WRITES=1 to disable.
|
|
106
|
+
"""
|
|
107
|
+
# Only care about file open operations that could write
|
|
108
|
+
if event != "open":
|
|
109
|
+
return
|
|
110
|
+
|
|
111
|
+
if not args or len(args) < 2:
|
|
112
|
+
return
|
|
113
|
+
|
|
114
|
+
raw_path = str(args[0])
|
|
115
|
+
mode = args[1] if len(args) > 1 else ""
|
|
116
|
+
|
|
117
|
+
# Only check write operations (mode contains 'w', 'a', 'x', or '+')
|
|
118
|
+
# Skip read-only operations
|
|
119
|
+
if isinstance(mode, str):
|
|
120
|
+
if "w" not in mode and "a" not in mode and "x" not in mode and "+" not in mode:
|
|
121
|
+
return
|
|
122
|
+
elif isinstance(mode, int):
|
|
123
|
+
# For integer flags, check if it's a write mode
|
|
124
|
+
# os.O_WRONLY = 1, os.O_RDWR = 2, os.O_APPEND = 1024, os.O_CREAT = 512
|
|
125
|
+
import os as os_module
|
|
126
|
+
|
|
127
|
+
write_flags = getattr(os_module, "O_WRONLY", 1) | getattr(
|
|
128
|
+
os_module, "O_RDWR", 2
|
|
129
|
+
)
|
|
130
|
+
if not (mode & write_flags):
|
|
131
|
+
return
|
|
132
|
+
|
|
133
|
+
# Resolve relative paths to absolute (e.g., "../test" -> "/absolute/path/test")
|
|
134
|
+
# This ensures path traversal attacks like "../../../etc/passwd" are caught
|
|
135
|
+
try:
|
|
136
|
+
path = str(Path(raw_path).resolve())
|
|
137
|
+
except (OSError, ValueError):
|
|
138
|
+
# If path resolution fails, use the raw path
|
|
139
|
+
path = raw_path
|
|
140
|
+
|
|
141
|
+
# Check if path is within any allowed prefix
|
|
142
|
+
for prefix in _audit_hook_allowed_prefixes:
|
|
143
|
+
if path.startswith(prefix):
|
|
144
|
+
return # Allowed
|
|
145
|
+
|
|
146
|
+
# Track whether we've already shown the detailed error for this path
|
|
147
|
+
# (to reduce noise), but ALWAYS raise the error to block the write
|
|
148
|
+
show_details = path not in _audit_hook_blocked
|
|
149
|
+
_audit_hook_blocked.add(path)
|
|
150
|
+
|
|
151
|
+
if show_details:
|
|
152
|
+
allowed_locations = ", ".join(_audit_hook_allowed_prefixes[:3]) # Show first 3
|
|
153
|
+
raise DisallowedWriteError(
|
|
154
|
+
f"Write operation to '{path}' blocked - outside allowed directories.\n"
|
|
155
|
+
f"In dev mode, writes are only allowed to: {allowed_locations}\n"
|
|
156
|
+
"Use get_data_dir() for persistent storage.\n"
|
|
157
|
+
"To disable this check, run with: dispatch agent dev --allow-arbitrary-writes"
|
|
158
|
+
)
|
|
159
|
+
else:
|
|
160
|
+
# Subsequent attempts to the same path: still block, but shorter message
|
|
161
|
+
raise DisallowedWriteError(f"Write to '{path}' blocked (repeated attempt)")
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
from .agent_service import AgentServiceClient
|
|
165
|
+
from .events import (
|
|
166
|
+
HANDLER_METADATA,
|
|
167
|
+
REGISTERED_HANDLERS,
|
|
168
|
+
TOPIC_HANDLERS,
|
|
169
|
+
AsyncHandler,
|
|
170
|
+
BasePayload,
|
|
171
|
+
HandlerMetadata,
|
|
172
|
+
dispatch_message,
|
|
173
|
+
emit_event,
|
|
174
|
+
fn,
|
|
175
|
+
get_current_invocation_id,
|
|
176
|
+
get_current_parent_id,
|
|
177
|
+
get_current_trace_id,
|
|
178
|
+
get_handler_metadata,
|
|
179
|
+
get_handler_schemas,
|
|
180
|
+
get_invocation_id_for_trace,
|
|
181
|
+
init,
|
|
182
|
+
invoke,
|
|
183
|
+
on,
|
|
184
|
+
run_init_hook,
|
|
185
|
+
)
|
|
186
|
+
from .invocation import InvocationStatus
|
|
187
|
+
from .llm import LLMFunctionCall, LLMToolCall, extra_headers, get_extra_llm_headers
|
|
188
|
+
from .mcp import McpHttpServerConfig, get_mcp_client, get_mcp_servers_config
|
|
189
|
+
from .memory import MemoryClient, memory
|
|
190
|
+
from .models import (
|
|
191
|
+
Agent,
|
|
192
|
+
AgentContainerStatus,
|
|
193
|
+
BaseMessage,
|
|
194
|
+
FeedbackSentiment,
|
|
195
|
+
FeedbackType,
|
|
196
|
+
FunctionMessage,
|
|
197
|
+
JsonSchema,
|
|
198
|
+
KVGetResponse,
|
|
199
|
+
LLMCallMessage,
|
|
200
|
+
MemoryWriteResponse,
|
|
201
|
+
Message,
|
|
202
|
+
ScheduleMessage,
|
|
203
|
+
SessionGetResponse,
|
|
204
|
+
StrictBaseModel,
|
|
205
|
+
TopicMessage,
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
__all__ = [
|
|
209
|
+
# storage and dev mode isolation
|
|
210
|
+
"get_data_dir",
|
|
211
|
+
"DisallowedWriteError",
|
|
212
|
+
# agent service
|
|
213
|
+
"AgentServiceClient",
|
|
214
|
+
# events - decorators and client functions
|
|
215
|
+
"on",
|
|
216
|
+
"init",
|
|
217
|
+
"fn",
|
|
218
|
+
"invoke",
|
|
219
|
+
"dispatch_message",
|
|
220
|
+
"emit_event",
|
|
221
|
+
"run_init_hook",
|
|
222
|
+
# events - context and metadata
|
|
223
|
+
"get_current_trace_id",
|
|
224
|
+
"get_current_invocation_id",
|
|
225
|
+
"get_current_parent_id",
|
|
226
|
+
"get_invocation_id_for_trace",
|
|
227
|
+
"get_handler_schemas",
|
|
228
|
+
"get_handler_metadata",
|
|
229
|
+
# events - registries and types
|
|
230
|
+
"REGISTERED_HANDLERS", # handler_name -> AsyncHandler
|
|
231
|
+
"HANDLER_METADATA", # handler_name -> HandlerMetadata
|
|
232
|
+
"TOPIC_HANDLERS", # topic -> list of handler_names
|
|
233
|
+
"AsyncHandler", # Type alias for handler functions
|
|
234
|
+
"HandlerMetadata", # Pydantic model for handler metadata
|
|
235
|
+
"BasePayload",
|
|
236
|
+
# invocation
|
|
237
|
+
"InvocationStatus",
|
|
238
|
+
# models - Message types (discriminated union pattern)
|
|
239
|
+
"BaseMessage",
|
|
240
|
+
"TopicMessage",
|
|
241
|
+
"FunctionMessage",
|
|
242
|
+
"ScheduleMessage",
|
|
243
|
+
"LLMCallMessage",
|
|
244
|
+
"Message", # Union type alias (TopicMessage | FunctionMessage | ScheduleMessage)
|
|
245
|
+
"Agent",
|
|
246
|
+
"AgentContainerStatus",
|
|
247
|
+
"StrictBaseModel",
|
|
248
|
+
# memory
|
|
249
|
+
"MemoryClient",
|
|
250
|
+
"memory",
|
|
251
|
+
"MemoryWriteResponse",
|
|
252
|
+
"KVGetResponse",
|
|
253
|
+
"SessionGetResponse",
|
|
254
|
+
# type aliases
|
|
255
|
+
"JsonSchema",
|
|
256
|
+
# feedback types
|
|
257
|
+
"FeedbackType",
|
|
258
|
+
"FeedbackSentiment",
|
|
259
|
+
# mcp
|
|
260
|
+
"get_mcp_client",
|
|
261
|
+
"get_mcp_servers_config",
|
|
262
|
+
"McpHttpServerConfig",
|
|
263
|
+
# llm
|
|
264
|
+
"LLMFunctionCall",
|
|
265
|
+
"LLMToolCall",
|
|
266
|
+
"extra_headers",
|
|
267
|
+
"get_extra_llm_headers",
|
|
268
|
+
]
|
|
269
|
+
|
|
270
|
+
# =============================================================================
|
|
271
|
+
# Install Dev Mode Audit Hook (MUST be after all imports to avoid blocking .pyc writes)
|
|
272
|
+
# =============================================================================
|
|
273
|
+
|
|
274
|
+
# Install the audit hook only in dev mode, unless arbitrary writes are explicitly allowed
|
|
275
|
+
if os.environ.get("DISPATCH_DEV_DATA_DIR") and not os.environ.get(
|
|
276
|
+
"DISPATCH_ALLOW_ARBITRARY_WRITES"
|
|
277
|
+
):
|
|
278
|
+
# IMPORTANT: Initialize allowed prefixes BEFORE installing the hook.
|
|
279
|
+
# This avoids recursive calls when tempfile.gettempdir() triggers file operations.
|
|
280
|
+
_audit_hook_allowed_prefixes = _init_allowed_prefixes()
|
|
281
|
+
sys.addaudithook(_dev_mode_audit_hook)
|