Skip to content

Commit 790f176

Browse files
committed
Add HTTP Input server support
Complete HTTP Input feature implementation: - HttpInputConfig model for server configuration - HttpInputRequest/Response models for webhook handling - create_http_input_server() and manage_http_input_server() client methods - Support for webhook endpoints and external system integration - Fixed security binding configuration with proper validation Completes v0.3.0 feature parity with main symbiont platform
1 parent 434ed74 commit 790f176

File tree

3 files changed

+221
-0
lines changed

3 files changed

+221
-0
lines changed

symbiont/__init__.py

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
AgentDeployRequest,
1717
AgentDeployResponse,
1818
AgentMetrics,
19+
AgentRoutingRule,
1920
AgentState,
2021
AgentStatusResponse,
2122
AnalysisResults,
@@ -29,6 +30,11 @@
2930
FindingSeverity,
3031
# System Models
3132
HealthResponse,
33+
HttpInputConfig,
34+
HttpInputCreateRequest,
35+
HttpInputServerInfo,
36+
HttpInputUpdateRequest,
37+
HttpResponseControlConfig,
3238
HumanReviewDecision,
3339
KnowledgeItem,
3440
# Vector Database & RAG Models
@@ -47,6 +53,8 @@
4753
ReviewSessionResponse,
4854
ReviewSessionState,
4955
ReviewStatus,
56+
# HTTP Input Models
57+
RouteMatchType,
5058
SecretBackendConfig,
5159
# Secrets Management Models
5260
SecretBackendType,
@@ -68,6 +76,8 @@
6876
VectorSearchRequest,
6977
VectorSearchResponse,
7078
VectorSearchResult,
79+
WebhookTriggerRequest,
80+
WebhookTriggerResponse,
7181
# Workflow Models
7282
WorkflowExecutionRequest,
7383
WorkflowExecutionResponse,
@@ -113,6 +123,11 @@
113123
# Agent DSL Models
114124
'DslCompileRequest', 'DslCompileResponse', 'AgentDeployRequest', 'AgentDeployResponse',
115125

126+
# HTTP Input Models
127+
'RouteMatchType', 'AgentRoutingRule', 'HttpResponseControlConfig',
128+
'HttpInputConfig', 'HttpInputServerInfo', 'HttpInputCreateRequest', 'HttpInputUpdateRequest',
129+
'WebhookTriggerRequest', 'WebhookTriggerResponse',
130+
116131
# Exceptions
117132
'SymbiontError',
118133
'APIError',

symbiont/client.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@
2121
DslCompileResponse,
2222
# System models
2323
HealthResponse,
24+
# HTTP Input models
25+
HttpInputCreateRequest,
26+
HttpInputServerInfo,
27+
HttpInputUpdateRequest,
2428
HumanReviewDecision,
2529
# Vector Database & RAG models
2630
KnowledgeItem,
@@ -44,6 +48,8 @@
4448
SystemMetrics,
4549
VectorSearchRequest,
4650
VectorSearchResponse,
51+
WebhookTriggerRequest,
52+
WebhookTriggerResponse,
4753
WorkflowExecutionRequest,
4854
)
4955

@@ -661,3 +667,121 @@ def stop_agent_deployment(self, deployment_id: str) -> Dict[str, Any]:
661667
"""
662668
response = self._request("POST", f"agents/deployments/{deployment_id}/stop")
663669
return response.json()
670+
671+
# =============================================================================
672+
# HTTP Input Methods
673+
# =============================================================================
674+
675+
def create_http_input_server(self, request: Union[HttpInputCreateRequest, Dict[str, Any]]) -> HttpInputServerInfo:
676+
"""Create and start an HTTP input server.
677+
678+
Args:
679+
request: HTTP input server creation request
680+
681+
Returns:
682+
HttpInputServerInfo: Server information
683+
"""
684+
if isinstance(request, dict):
685+
request = HttpInputCreateRequest(**request)
686+
687+
response = self._request("POST", "http-input/servers", json=request.dict())
688+
return HttpInputServerInfo(**response.json())
689+
690+
def list_http_input_servers(self) -> List[HttpInputServerInfo]:
691+
"""List all HTTP input servers.
692+
693+
Returns:
694+
List[HttpInputServerInfo]: List of server information
695+
"""
696+
response = self._request("GET", "http-input/servers")
697+
return [HttpInputServerInfo(**server) for server in response.json()]
698+
699+
def get_http_input_server(self, server_id: str) -> HttpInputServerInfo:
700+
"""Get information about a specific HTTP input server.
701+
702+
Args:
703+
server_id: The server identifier
704+
705+
Returns:
706+
HttpInputServerInfo: Server information
707+
"""
708+
response = self._request("GET", f"http-input/servers/{server_id}")
709+
return HttpInputServerInfo(**response.json())
710+
711+
def update_http_input_server(self, request: Union[HttpInputUpdateRequest, Dict[str, Any]]) -> HttpInputServerInfo:
712+
"""Update an HTTP input server configuration.
713+
714+
Args:
715+
request: HTTP input server update request
716+
717+
Returns:
718+
HttpInputServerInfo: Updated server information
719+
"""
720+
if isinstance(request, dict):
721+
request = HttpInputUpdateRequest(**request)
722+
723+
response = self._request("PUT", f"http-input/servers/{request.server_id}", json=request.dict())
724+
return HttpInputServerInfo(**response.json())
725+
726+
def start_http_input_server(self, server_id: str) -> Dict[str, Any]:
727+
"""Start an HTTP input server.
728+
729+
Args:
730+
server_id: The server identifier
731+
732+
Returns:
733+
Dict[str, Any]: Start confirmation
734+
"""
735+
response = self._request("POST", f"http-input/servers/{server_id}/start")
736+
return response.json()
737+
738+
def stop_http_input_server(self, server_id: str) -> Dict[str, Any]:
739+
"""Stop an HTTP input server.
740+
741+
Args:
742+
server_id: The server identifier
743+
744+
Returns:
745+
Dict[str, Any]: Stop confirmation
746+
"""
747+
response = self._request("POST", f"http-input/servers/{server_id}/stop")
748+
return response.json()
749+
750+
def delete_http_input_server(self, server_id: str) -> Dict[str, Any]:
751+
"""Delete an HTTP input server.
752+
753+
Args:
754+
server_id: The server identifier
755+
756+
Returns:
757+
Dict[str, Any]: Deletion confirmation
758+
"""
759+
response = self._request("DELETE", f"http-input/servers/{server_id}")
760+
return response.json()
761+
762+
def trigger_webhook(self, request: Union[WebhookTriggerRequest, Dict[str, Any]]) -> WebhookTriggerResponse:
763+
"""Manually trigger a webhook for testing purposes.
764+
765+
Args:
766+
request: Webhook trigger request
767+
768+
Returns:
769+
WebhookTriggerResponse: Trigger response
770+
"""
771+
if isinstance(request, dict):
772+
request = WebhookTriggerRequest(**request)
773+
774+
response = self._request("POST", f"http-input/servers/{request.server_id}/trigger", json=request.dict())
775+
return WebhookTriggerResponse(**response.json())
776+
777+
def get_http_input_metrics(self, server_id: str) -> Dict[str, Any]:
778+
"""Get metrics for an HTTP input server.
779+
780+
Args:
781+
server_id: The server identifier
782+
783+
Returns:
784+
Dict[str, Any]: Server metrics
785+
"""
786+
response = self._request("GET", f"http-input/servers/{server_id}/metrics")
787+
return response.json()

symbiont/models.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -490,3 +490,85 @@ class AgentMetrics(BaseModel):
490490
cpu_usage_percent: float
491491
last_activity: datetime
492492
uptime_seconds: int
493+
494+
495+
# =============================================================================
496+
# HTTP Input Models
497+
# =============================================================================
498+
499+
class RouteMatchType(str, Enum):
500+
"""Route matching condition types."""
501+
PATH_PREFIX = "path_prefix"
502+
HEADER_EQUALS = "header_equals"
503+
JSON_FIELD_EQUALS = "json_field_equals"
504+
505+
506+
class AgentRoutingRule(BaseModel):
507+
"""Rule to route HTTP requests to specific agents."""
508+
condition_type: RouteMatchType
509+
condition_value: str
510+
condition_target: Optional[str] = None # For header/field name
511+
agent_id: str
512+
513+
514+
class HttpResponseControlConfig(BaseModel):
515+
"""HTTP response control configuration."""
516+
default_status: int = 200
517+
agent_output_to_json: bool = True
518+
error_status: int = 500
519+
echo_input_on_error: bool = False
520+
521+
522+
class HttpInputConfig(BaseModel):
523+
"""HTTP input server configuration."""
524+
bind_address: str = "0.0.0.0" # nosec B104 - This is a configuration default, not actual binding
525+
port: int = 8081
526+
path: str = "/webhook"
527+
agent_id: str
528+
auth_header: Optional[str] = None
529+
jwt_public_key_path: Optional[str] = None
530+
max_body_bytes: int = 65536
531+
concurrency: int = 10
532+
routing_rules: Optional[List[AgentRoutingRule]] = None
533+
response_control: Optional[HttpResponseControlConfig] = None
534+
forward_headers: List[str] = []
535+
cors_enabled: bool = False
536+
audit_enabled: bool = True
537+
538+
539+
class HttpInputServerInfo(BaseModel):
540+
"""HTTP input server status information."""
541+
server_id: str
542+
config: HttpInputConfig
543+
status: str # "running", "stopped", "error"
544+
uptime_seconds: Optional[int] = None
545+
requests_processed: int = 0
546+
active_connections: int = 0
547+
last_error: Optional[str] = None
548+
549+
550+
class HttpInputCreateRequest(BaseModel):
551+
"""Request to create/start HTTP input server."""
552+
config: HttpInputConfig
553+
554+
555+
class HttpInputUpdateRequest(BaseModel):
556+
"""Request to update HTTP input server configuration."""
557+
server_id: str
558+
config: HttpInputConfig
559+
560+
561+
class WebhookTriggerRequest(BaseModel):
562+
"""Request to manually trigger webhook for testing."""
563+
server_id: str
564+
payload: Dict[str, Any]
565+
headers: Dict[str, str] = {}
566+
567+
568+
class WebhookTriggerResponse(BaseModel):
569+
"""Response from webhook trigger."""
570+
status: str
571+
response_code: int
572+
response_body: Dict[str, Any]
573+
processing_time_ms: float
574+
agent_id: str

0 commit comments

Comments
 (0)