flock-core 0.3.3__py3-none-any.whl → 0.3.4__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.

Potentially problematic release.


This version of flock-core might be problematic. Click here for more details.

flock/core/__init__.py CHANGED
@@ -2,12 +2,14 @@
2
2
 
3
3
  from flock.core.flock import Flock
4
4
  from flock.core.flock_agent import FlockAgent
5
+ from flock.core.flock_api import FlockAPI
5
6
  from flock.core.flock_evaluator import FlockEvaluator, FlockEvaluatorConfig
6
7
  from flock.core.flock_factory import FlockFactory
7
8
  from flock.core.flock_module import FlockModule, FlockModuleConfig
8
9
 
9
10
  __all__ = [
10
11
  "Flock",
12
+ "FlockAPI",
11
13
  "FlockAgent",
12
14
  "FlockEvaluator",
13
15
  "FlockEvaluatorConfig",
flock/core/flock.py CHANGED
@@ -379,6 +379,8 @@ class Flock:
379
379
  Exception: For any other errors encountered during execution.
380
380
  """
381
381
  with tracer.start_as_current_span("run_async") as span:
382
+ if isinstance(start_agent, str):
383
+ start_agent = self.registry.get_agent(start_agent)
382
384
  span.set_attribute(
383
385
  "start_agent",
384
386
  start_agent.name
@@ -0,0 +1,215 @@
1
+ """REST API server for Flock."""
2
+
3
+ import uuid
4
+ from datetime import datetime
5
+ from typing import Any
6
+
7
+ import uvicorn
8
+ from fastapi import BackgroundTasks, FastAPI, HTTPException
9
+ from pydantic import BaseModel, Field
10
+
11
+ from flock.core.flock import Flock
12
+ from flock.core.logging.logging import get_logger
13
+
14
+ logger = get_logger("api")
15
+
16
+
17
+ class FlockAPIRequest(BaseModel):
18
+ """Request model for running an agent."""
19
+
20
+ agent_name: str = Field(..., description="Name of the agent to run")
21
+ inputs: dict[str, Any] = Field(
22
+ default_factory=dict, description="Input data for the agent"
23
+ )
24
+ async_run: bool = Field(
25
+ default=False, description="Whether to run asynchronously"
26
+ )
27
+
28
+
29
+ class FlockAPIResponse(BaseModel):
30
+ """Response model for run requests."""
31
+
32
+ run_id: str = Field(..., description="Unique ID for this run")
33
+ status: str = Field(..., description="Status of the run")
34
+ result: dict[str, Any] | None = Field(
35
+ None, description="Run result if completed"
36
+ )
37
+ started_at: datetime = Field(..., description="When the run started")
38
+ completed_at: datetime | None = Field(
39
+ None, description="When the run completed"
40
+ )
41
+ error: str | None = Field(None, description="Error message if failed")
42
+
43
+
44
+ class FlockAPI:
45
+ """REST API server for Flock.
46
+
47
+ Provides HTTP endpoints for:
48
+ - Running agents
49
+ - Checking run status
50
+ - Getting run results
51
+ """
52
+
53
+ def __init__(self, flock: Flock):
54
+ self.flock = flock
55
+ self.app = FastAPI(title="Flock API")
56
+ self.runs: dict[str, FlockAPIResponse] = {}
57
+
58
+ # Register routes
59
+ self._setup_routes()
60
+
61
+ def _setup_routes(self):
62
+ """Set up API routes."""
63
+
64
+ @self.app.post("/run/flock", response_model=FlockAPIResponse)
65
+ async def run_flock(
66
+ request: FlockAPIRequest, background_tasks: BackgroundTasks
67
+ ):
68
+ """Run an agent with the provided inputs."""
69
+ try:
70
+ # Generate run ID
71
+ run_id = str(uuid.uuid4())
72
+
73
+ # Create initial response
74
+ response = FlockAPIResponse(
75
+ run_id=run_id, status="starting", started_at=datetime.now()
76
+ )
77
+ self.runs[run_id] = response
78
+
79
+ if request.async_run:
80
+ # Start run in background
81
+ background_tasks.add_task(
82
+ self._run_flock,
83
+ run_id,
84
+ request.agent_name,
85
+ request.inputs,
86
+ )
87
+ response.status = "running"
88
+ else:
89
+ # Run synchronously
90
+ await self._run_flock(
91
+ run_id, request.agent_name, request.inputs
92
+ )
93
+
94
+ return self.runs[run_id]
95
+
96
+ except Exception as e:
97
+ logger.error(f"Error starting run: {e!s}")
98
+ raise HTTPException(status_code=500, detail=str(e))
99
+
100
+ @self.app.post("/run/agent", response_model=FlockAPIResponse)
101
+ async def run_agent(
102
+ request: FlockAPIRequest, background_tasks: BackgroundTasks
103
+ ):
104
+ """Run an agent with the provided inputs."""
105
+ try:
106
+ # Generate run ID
107
+ run_id = str(uuid.uuid4())
108
+
109
+ # Create initial response
110
+ response = FlockAPIResponse(
111
+ run_id=run_id, status="starting", started_at=datetime.now()
112
+ )
113
+ self.runs[run_id] = response
114
+
115
+ if request.async_run:
116
+ # Start run in background
117
+ background_tasks.add_task(
118
+ self._run_agent,
119
+ run_id,
120
+ request.agent_name,
121
+ request.inputs,
122
+ )
123
+ response.status = "running"
124
+ else:
125
+ # Run synchronously
126
+ await self._run_agent(
127
+ run_id, request.agent_name, request.inputs
128
+ )
129
+
130
+ return self.runs[run_id]
131
+
132
+ except Exception as e:
133
+ logger.error(f"Error starting run: {e!s}")
134
+ raise HTTPException(status_code=500, detail=str(e))
135
+
136
+ @self.app.get("/run/{run_id}", response_model=FlockAPIResponse)
137
+ async def get_run_status(run_id: str):
138
+ """Get the status of a run."""
139
+ if run_id not in self.runs:
140
+ raise HTTPException(status_code=404, detail="Run not found")
141
+ return self.runs[run_id]
142
+
143
+ @self.app.get("/agents")
144
+ async def list_agents():
145
+ """List all available agents."""
146
+ return {
147
+ "agents": [
148
+ {
149
+ "name": agent.name,
150
+ "description": agent.description,
151
+ "input_schema": agent.input,
152
+ "output_schema": agent.output,
153
+ "hand_off": agent.hand_off,
154
+ }
155
+ for agent in self.flock.agents.values()
156
+ ]
157
+ }
158
+
159
+ async def _run_agent(
160
+ self, run_id: str, agent_name: str, inputs: dict[str, Any]
161
+ ):
162
+ """Execute an agent run."""
163
+ try:
164
+ # Get the agent
165
+ if agent_name not in self.flock.agents:
166
+ raise ValueError(f"Agent '{agent_name}' not found")
167
+
168
+ agent = self.flock.agents[agent_name]
169
+
170
+ # Run the agent
171
+ result = await agent.run_async(inputs)
172
+
173
+ # Update run status
174
+ self.runs[run_id].status = "completed"
175
+ self.runs[run_id].result = result
176
+ self.runs[run_id].completed_at = datetime.now()
177
+
178
+ except Exception as e:
179
+ logger.error(f"Error in run {run_id}: {e!s}")
180
+ self.runs[run_id].status = "failed"
181
+ self.runs[run_id].error = str(e)
182
+ self.runs[run_id].completed_at = datetime.now()
183
+
184
+ async def _run_flock(
185
+ self, run_id: str, agent_name: str, inputs: dict[str, Any]
186
+ ):
187
+ """Execute an agent run."""
188
+ try:
189
+ # Get the agent
190
+ if agent_name not in self.flock.agents:
191
+ raise ValueError(f"Agent '{agent_name}' not found")
192
+
193
+ result = await self.flock.run_async(
194
+ start_agent=agent_name, input=inputs
195
+ )
196
+
197
+ # Update run status
198
+ self.runs[run_id].status = "completed"
199
+ self.runs[run_id].result = result
200
+ self.runs[run_id].completed_at = datetime.now()
201
+
202
+ except Exception as e:
203
+ logger.error(f"Error in run {run_id}: {e!s}")
204
+ self.runs[run_id].status = "failed"
205
+ self.runs[run_id].error = str(e)
206
+ self.runs[run_id].completed_at = datetime.now()
207
+
208
+ def start(self, host: str = "0.0.0.0", port: int = 8344):
209
+ """Start the API server."""
210
+ uvicorn.run(self.app, host=host, port=port)
211
+
212
+ async def stop(self):
213
+ """Stop the API server."""
214
+ # Cleanup if needed
215
+ pass
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: flock-core
3
- Version: 0.3.3
3
+ Version: 0.3.4
4
4
  Summary: Declarative LLM Orchestration at Scale
5
5
  Author-email: Andre Ratzenberger <andre.ratzenberger@whiteduck.de>
6
6
  License-File: LICENSE
@@ -12,6 +12,7 @@ Requires-Dist: cloudpickle>=3.1.1
12
12
  Requires-Dist: devtools>=0.12.2
13
13
  Requires-Dist: dspy==2.5.42
14
14
  Requires-Dist: duckduckgo-search>=7.3.2
15
+ Requires-Dist: fastapi>=0.115.8
15
16
  Requires-Dist: httpx>=0.28.1
16
17
  Requires-Dist: loguru>=0.7.3
17
18
  Requires-Dist: matplotlib>=3.10.0
@@ -9,9 +9,10 @@ flock/cli/load_flock.py,sha256=3JdECvt5X7uyOG2vZS3-Zk5C5SI_84_QZjcsB3oJmfA,932
9
9
  flock/cli/load_release_notes.py,sha256=qFcgUrMddAE_TP6x1P-6ZywTUjTknfhTDW5LTxtg1yk,599
10
10
  flock/cli/settings.py,sha256=DkeLUlrb7rGx3nZ04aADU9HXXu5mZTf_DBwT0xhzIv4,7
11
11
  flock/cli/assets/release_notes.md,sha256=K-upUm5vuUuRSSU2FkMdgDfai_YlDk_vTCp0s4s2WO0,3419
12
- flock/core/__init__.py,sha256=ZTp6qNY-kNH_Xn0xFfCAYceYqWFdahXYMm5wWPb30Go,501
13
- flock/core/flock.py,sha256=4Kcnw39YiPRND6U8TWLZ0LyjNTykIk56VPruUEGwBrk,19116
12
+ flock/core/__init__.py,sha256=mPlvKc0SxC2qCvSlgYeP_7EyV8ptmdn24NO8mlQoCSo,559
13
+ flock/core/flock.py,sha256=1LPMblsvT90Na35LXx0w3Us66yIaTzsokL7lF5fsVX8,19228
14
14
  flock/core/flock_agent.py,sha256=RzKX0GRrRJz16YbQFheMo8TqJPXOZSHWNloTbp35zwI,12229
15
+ flock/core/flock_api.py,sha256=SKQVKgFCaNCqHtwvIcksnpqG6ajHodVhs3oaKUw-d8c,7192
15
16
  flock/core/flock_evaluator.py,sha256=j7riJj_KsWoBnKmLiGp-U0CRhxDyJbgEdLGN26tfKm8,1588
16
17
  flock/core/flock_factory.py,sha256=vyDq0eyFT4MyE_n2JyNU7YaFx2ljmjSDmZ07OIsmIOE,2694
17
18
  flock/core/flock_module.py,sha256=VWFlBiY2RHZLTlGYfcchuT41M3m_JrZcmzw07u7KayM,2581
@@ -395,8 +396,8 @@ flock/workflow/activities.py,sha256=2zcYyDoCuYs9oQbnhLjCzBUdEi7d5IEIemKJ7TV_B8w,
395
396
  flock/workflow/agent_activities.py,sha256=NhBZscflEf2IMfSRa_pBM_TRP7uVEF_O0ROvWZ33eDc,963
396
397
  flock/workflow/temporal_setup.py,sha256=VWBgmBgfTBjwM5ruS_dVpA5AVxx6EZ7oFPGw4j3m0l0,1091
397
398
  flock/workflow/workflow.py,sha256=I9MryXW_bqYVTHx-nl2epbTqeRy27CAWHHA7ZZA0nAk,1696
398
- flock_core-0.3.3.dist-info/METADATA,sha256=DmDTXx-eJoRlsZbhPGsyX-OEBZ16ahgDPFKb5N0YFBk,20431
399
- flock_core-0.3.3.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
400
- flock_core-0.3.3.dist-info/entry_points.txt,sha256=rWaS5KSpkTmWySURGFZk6PhbJ87TmvcFQDi2uzjlagQ,37
401
- flock_core-0.3.3.dist-info/licenses/LICENSE,sha256=iYEqWy0wjULzM9GAERaybP4LBiPeu7Z1NEliLUdJKSc,1072
402
- flock_core-0.3.3.dist-info/RECORD,,
399
+ flock_core-0.3.4.dist-info/METADATA,sha256=o10aq5iiMQPy1xhMv89xMcspa5pgX2c3lHZghImgWjo,20463
400
+ flock_core-0.3.4.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
401
+ flock_core-0.3.4.dist-info/entry_points.txt,sha256=rWaS5KSpkTmWySURGFZk6PhbJ87TmvcFQDi2uzjlagQ,37
402
+ flock_core-0.3.4.dist-info/licenses/LICENSE,sha256=iYEqWy0wjULzM9GAERaybP4LBiPeu7Z1NEliLUdJKSc,1072
403
+ flock_core-0.3.4.dist-info/RECORD,,