flock-core 0.5.11__py3-none-any.whl → 0.5.21__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/__init__.py +1 -1
- flock/agent/__init__.py +30 -0
- flock/agent/builder_helpers.py +192 -0
- flock/agent/builder_validator.py +169 -0
- flock/agent/component_lifecycle.py +325 -0
- flock/agent/context_resolver.py +141 -0
- flock/agent/mcp_integration.py +212 -0
- flock/agent/output_processor.py +304 -0
- flock/api/__init__.py +20 -0
- flock/{api_models.py → api/models.py} +0 -2
- flock/{service.py → api/service.py} +3 -3
- flock/cli.py +2 -2
- flock/components/__init__.py +41 -0
- flock/components/agent/__init__.py +22 -0
- flock/{components.py → components/agent/base.py} +4 -3
- flock/{utility/output_utility_component.py → components/agent/output_utility.py} +12 -7
- flock/components/orchestrator/__init__.py +22 -0
- flock/{orchestrator_component.py → components/orchestrator/base.py} +5 -293
- flock/components/orchestrator/circuit_breaker.py +95 -0
- flock/components/orchestrator/collection.py +143 -0
- flock/components/orchestrator/deduplication.py +78 -0
- flock/core/__init__.py +30 -0
- flock/core/agent.py +953 -0
- flock/{artifacts.py → core/artifacts.py} +1 -1
- flock/{context_provider.py → core/context_provider.py} +3 -3
- flock/core/orchestrator.py +1102 -0
- flock/{store.py → core/store.py} +99 -454
- flock/{subscription.py → core/subscription.py} +1 -1
- flock/dashboard/collector.py +5 -5
- flock/dashboard/events.py +1 -1
- flock/dashboard/graph_builder.py +7 -7
- flock/dashboard/routes/__init__.py +21 -0
- flock/dashboard/routes/control.py +327 -0
- flock/dashboard/routes/helpers.py +340 -0
- flock/dashboard/routes/themes.py +76 -0
- flock/dashboard/routes/traces.py +521 -0
- flock/dashboard/routes/websocket.py +108 -0
- flock/dashboard/service.py +43 -1316
- flock/engines/dspy/__init__.py +20 -0
- flock/engines/dspy/artifact_materializer.py +216 -0
- flock/engines/dspy/signature_builder.py +474 -0
- flock/engines/dspy/streaming_executor.py +812 -0
- flock/engines/dspy_engine.py +45 -1330
- flock/engines/examples/simple_batch_engine.py +2 -2
- flock/engines/streaming/__init__.py +3 -0
- flock/engines/streaming/sinks.py +489 -0
- flock/examples.py +7 -7
- flock/logging/logging.py +1 -16
- flock/models/__init__.py +10 -0
- flock/orchestrator/__init__.py +45 -0
- flock/{artifact_collector.py → orchestrator/artifact_collector.py} +3 -3
- flock/orchestrator/artifact_manager.py +168 -0
- flock/{batch_accumulator.py → orchestrator/batch_accumulator.py} +2 -2
- flock/orchestrator/component_runner.py +389 -0
- flock/orchestrator/context_builder.py +167 -0
- flock/{correlation_engine.py → orchestrator/correlation_engine.py} +2 -2
- flock/orchestrator/event_emitter.py +167 -0
- flock/orchestrator/initialization.py +184 -0
- flock/orchestrator/lifecycle_manager.py +226 -0
- flock/orchestrator/mcp_manager.py +202 -0
- flock/orchestrator/scheduler.py +189 -0
- flock/orchestrator/server_manager.py +234 -0
- flock/orchestrator/tracing.py +147 -0
- flock/storage/__init__.py +10 -0
- flock/storage/artifact_aggregator.py +158 -0
- flock/storage/in_memory/__init__.py +6 -0
- flock/storage/in_memory/artifact_filter.py +114 -0
- flock/storage/in_memory/history_aggregator.py +115 -0
- flock/storage/sqlite/__init__.py +10 -0
- flock/storage/sqlite/agent_history_queries.py +154 -0
- flock/storage/sqlite/consumption_loader.py +100 -0
- flock/storage/sqlite/query_builder.py +112 -0
- flock/storage/sqlite/query_params_builder.py +91 -0
- flock/storage/sqlite/schema_manager.py +168 -0
- flock/storage/sqlite/summary_queries.py +194 -0
- flock/utils/__init__.py +14 -0
- flock/utils/async_utils.py +67 -0
- flock/{runtime.py → utils/runtime.py} +3 -3
- flock/utils/time_utils.py +53 -0
- flock/utils/type_resolution.py +38 -0
- flock/{utilities.py → utils/utilities.py} +2 -2
- flock/utils/validation.py +57 -0
- flock/utils/visibility.py +79 -0
- flock/utils/visibility_utils.py +134 -0
- {flock_core-0.5.11.dist-info → flock_core-0.5.21.dist-info}/METADATA +19 -5
- {flock_core-0.5.11.dist-info → flock_core-0.5.21.dist-info}/RECORD +92 -34
- flock/agent.py +0 -1578
- flock/orchestrator.py +0 -1983
- /flock/{visibility.py → core/visibility.py} +0 -0
- /flock/{system_artifacts.py → models/system_artifacts.py} +0 -0
- /flock/{helper → utils}/cli_helper.py +0 -0
- {flock_core-0.5.11.dist-info → flock_core-0.5.21.dist-info}/WHEEL +0 -0
- {flock_core-0.5.11.dist-info → flock_core-0.5.21.dist-info}/entry_points.txt +0 -0
- {flock_core-0.5.11.dist-info → flock_core-0.5.21.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
"""Agent output processing - validation, filtering, and artifact creation.
|
|
2
|
+
|
|
3
|
+
Phase 4: Extracted from agent.py to eliminate C-rated complexity in _make_outputs_for_group.
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from __future__ import annotations
|
|
7
|
+
|
|
8
|
+
import logging
|
|
9
|
+
from typing import TYPE_CHECKING, Any
|
|
10
|
+
|
|
11
|
+
from flock.core.artifacts import Artifact
|
|
12
|
+
from flock.logging.logging import get_logger
|
|
13
|
+
from flock.registry import type_registry
|
|
14
|
+
from flock.utils.runtime import Context, EvalResult
|
|
15
|
+
from flock.utils.type_resolution import TypeResolutionHelper
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
if TYPE_CHECKING:
|
|
19
|
+
from flock.agent import AgentOutput, OutputGroup
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
logger = get_logger(__name__)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class OutputProcessor:
|
|
26
|
+
"""Handles agent output validation, filtering, and artifact creation.
|
|
27
|
+
|
|
28
|
+
This module encapsulates all output processing logic including:
|
|
29
|
+
- Engine contract validation (expected vs actual artifact counts)
|
|
30
|
+
- WHERE filtering (reduces artifacts based on predicates)
|
|
31
|
+
- VALIDATE checks (fail-fast on validation errors)
|
|
32
|
+
- Dynamic visibility resolution
|
|
33
|
+
- Artifact matching and payload extraction
|
|
34
|
+
"""
|
|
35
|
+
|
|
36
|
+
def __init__(self, agent_name: str):
|
|
37
|
+
"""Initialize OutputProcessor for a specific agent.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
agent_name: Name of the agent (for error messages and logging)
|
|
41
|
+
"""
|
|
42
|
+
self._agent_name = agent_name
|
|
43
|
+
self._logger = logging.getLogger(__name__)
|
|
44
|
+
|
|
45
|
+
async def make_outputs_for_group(
|
|
46
|
+
self,
|
|
47
|
+
ctx: Context,
|
|
48
|
+
result: EvalResult,
|
|
49
|
+
output_group: OutputGroup,
|
|
50
|
+
) -> list[Artifact]:
|
|
51
|
+
"""Phase 3/5: Validate, filter, and create artifacts for specific OutputGroup.
|
|
52
|
+
|
|
53
|
+
This function:
|
|
54
|
+
1. Validates that the engine fulfilled its contract (produced expected count)
|
|
55
|
+
2. Applies WHERE filtering (reduces artifacts, no error)
|
|
56
|
+
3. Applies VALIDATE checks (raises ValueError if validation fails)
|
|
57
|
+
4. Applies visibility (static or dynamic)
|
|
58
|
+
5. Creates final artifacts with agent metadata
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
ctx: Context for this group
|
|
62
|
+
result: EvalResult from engine for THIS group
|
|
63
|
+
output_group: OutputGroup defining expected outputs
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
List of artifacts matching this group's outputs
|
|
67
|
+
|
|
68
|
+
Raises:
|
|
69
|
+
ValueError: If engine violated contract or validation failed
|
|
70
|
+
"""
|
|
71
|
+
produced: list[Artifact] = []
|
|
72
|
+
|
|
73
|
+
for output_decl in output_group.outputs:
|
|
74
|
+
# 1. Find ALL matching artifacts for this type
|
|
75
|
+
expected_canonical = type_registry.resolve_name(output_decl.spec.type_name)
|
|
76
|
+
|
|
77
|
+
matching_artifacts: list[Artifact] = []
|
|
78
|
+
for artifact in result.artifacts:
|
|
79
|
+
artifact_canonical = TypeResolutionHelper.safe_resolve(
|
|
80
|
+
type_registry, artifact.type
|
|
81
|
+
)
|
|
82
|
+
if artifact_canonical == expected_canonical:
|
|
83
|
+
matching_artifacts.append(artifact)
|
|
84
|
+
|
|
85
|
+
# 2. STRICT VALIDATION: Engine must produce exactly what was promised
|
|
86
|
+
# (This happens BEFORE filtering so engine contract is validated first)
|
|
87
|
+
expected_count = output_decl.count
|
|
88
|
+
actual_count = len(matching_artifacts)
|
|
89
|
+
|
|
90
|
+
if actual_count != expected_count:
|
|
91
|
+
raise ValueError(
|
|
92
|
+
f"Engine contract violation in agent '{self._agent_name}': "
|
|
93
|
+
f"Expected {expected_count} artifact(s) of type '{output_decl.spec.type_name}', "
|
|
94
|
+
f"but engine produced {actual_count}. "
|
|
95
|
+
f"Check your engine implementation to ensure it generates the correct number of outputs."
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
# 3. Apply WHERE filtering (Phase 5)
|
|
99
|
+
# Filtering reduces the number of published artifacts (this is intentional)
|
|
100
|
+
# NOTE: Predicates expect Pydantic model instances, not dicts
|
|
101
|
+
model_cls = type_registry.resolve(output_decl.spec.type_name)
|
|
102
|
+
|
|
103
|
+
if output_decl.filter_predicate:
|
|
104
|
+
original_count = len(matching_artifacts)
|
|
105
|
+
filtered = []
|
|
106
|
+
for a in matching_artifacts:
|
|
107
|
+
# Reconstruct Pydantic model from payload dict
|
|
108
|
+
model_instance = model_cls(**a.payload)
|
|
109
|
+
if output_decl.filter_predicate(model_instance):
|
|
110
|
+
filtered.append(a)
|
|
111
|
+
matching_artifacts = filtered
|
|
112
|
+
logger.debug(
|
|
113
|
+
f"Agent {self._agent_name}: WHERE filter reduced artifacts from "
|
|
114
|
+
f"{original_count} to {len(matching_artifacts)} for type {output_decl.spec.type_name}"
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
# 4. Apply VALIDATE checks (Phase 5)
|
|
118
|
+
# Validation failures raise errors (fail-fast)
|
|
119
|
+
if output_decl.validate_predicate:
|
|
120
|
+
if callable(output_decl.validate_predicate):
|
|
121
|
+
# Single predicate
|
|
122
|
+
for artifact in matching_artifacts:
|
|
123
|
+
# Reconstruct Pydantic model from payload dict
|
|
124
|
+
model_instance = model_cls(**artifact.payload)
|
|
125
|
+
if not output_decl.validate_predicate(model_instance):
|
|
126
|
+
raise ValueError(
|
|
127
|
+
f"Validation failed for {output_decl.spec.type_name} "
|
|
128
|
+
f"in agent '{self._agent_name}'"
|
|
129
|
+
)
|
|
130
|
+
elif isinstance(output_decl.validate_predicate, list):
|
|
131
|
+
# List of (callable, error_msg) tuples
|
|
132
|
+
for artifact in matching_artifacts:
|
|
133
|
+
# Reconstruct Pydantic model from payload dict
|
|
134
|
+
model_instance = model_cls(**artifact.payload)
|
|
135
|
+
for check, error_msg in output_decl.validate_predicate:
|
|
136
|
+
if not check(model_instance):
|
|
137
|
+
raise ValueError(
|
|
138
|
+
f"{error_msg}: {output_decl.spec.type_name}"
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
# 5. Apply visibility and create artifacts (Phase 5)
|
|
142
|
+
for artifact_from_engine in matching_artifacts:
|
|
143
|
+
metadata = {
|
|
144
|
+
"correlation_id": ctx.correlation_id,
|
|
145
|
+
"artifact_id": artifact_from_engine.id, # Preserve engine's ID
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
# Determine visibility (static or dynamic)
|
|
149
|
+
visibility = output_decl.default_visibility
|
|
150
|
+
if callable(visibility):
|
|
151
|
+
# Dynamic visibility based on artifact content
|
|
152
|
+
# Reconstruct Pydantic model from payload dict
|
|
153
|
+
model_instance = model_cls(**artifact_from_engine.payload)
|
|
154
|
+
visibility = visibility(model_instance)
|
|
155
|
+
|
|
156
|
+
# Override metadata visibility
|
|
157
|
+
metadata["visibility"] = visibility
|
|
158
|
+
|
|
159
|
+
# Re-wrap the artifact with agent metadata
|
|
160
|
+
artifact = output_decl.apply(
|
|
161
|
+
artifact_from_engine.payload,
|
|
162
|
+
produced_by=self._agent_name,
|
|
163
|
+
metadata=metadata,
|
|
164
|
+
)
|
|
165
|
+
produced.append(artifact)
|
|
166
|
+
# Phase 6 SECURITY FIX: REMOVED publishing - orchestrator now handles it
|
|
167
|
+
# This fixes Vulnerability #2 (WRITE Bypass) - agents can no longer publish directly
|
|
168
|
+
# await ctx.board.publish(artifact)
|
|
169
|
+
|
|
170
|
+
return produced
|
|
171
|
+
|
|
172
|
+
async def make_outputs(
|
|
173
|
+
self, ctx: Context, result: EvalResult, output_groups: list[OutputGroup]
|
|
174
|
+
) -> list[Artifact]:
|
|
175
|
+
"""Output creation method for all output groups.
|
|
176
|
+
|
|
177
|
+
This method processes all output groups from a single engine evaluation.
|
|
178
|
+
|
|
179
|
+
Args:
|
|
180
|
+
ctx: Execution context
|
|
181
|
+
result: EvalResult from engine
|
|
182
|
+
output_groups: All output groups for the agent
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
List of produced artifacts
|
|
186
|
+
"""
|
|
187
|
+
if not output_groups:
|
|
188
|
+
# Utility agents may not publish anything
|
|
189
|
+
return list(result.artifacts)
|
|
190
|
+
|
|
191
|
+
produced: list[Artifact] = []
|
|
192
|
+
|
|
193
|
+
# For Phase 2: Iterate ALL output_groups (even though we only have 1 engine call)
|
|
194
|
+
# Phase 3 will modify this to call engine once PER group
|
|
195
|
+
for output_group in output_groups:
|
|
196
|
+
for output_decl in output_group.outputs:
|
|
197
|
+
# Phase 6: Find the matching artifact from engine result to preserve its ID
|
|
198
|
+
matching_artifact = self.find_matching_artifact(output_decl, result)
|
|
199
|
+
|
|
200
|
+
payload = self.select_payload(output_decl, result)
|
|
201
|
+
if payload is None:
|
|
202
|
+
continue
|
|
203
|
+
metadata = {
|
|
204
|
+
"correlation_id": ctx.correlation_id,
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
# Phase 6: Preserve artifact ID from engine (for streaming message preview)
|
|
208
|
+
if matching_artifact:
|
|
209
|
+
metadata["artifact_id"] = matching_artifact.id
|
|
210
|
+
|
|
211
|
+
artifact = output_decl.apply(
|
|
212
|
+
payload, produced_by=self._agent_name, metadata=metadata
|
|
213
|
+
)
|
|
214
|
+
produced.append(artifact)
|
|
215
|
+
# Phase 6: REMOVED publishing - orchestrator now handles it
|
|
216
|
+
# await ctx.board.publish(artifact)
|
|
217
|
+
|
|
218
|
+
return produced
|
|
219
|
+
|
|
220
|
+
def prepare_group_context(
|
|
221
|
+
self, ctx: Context, group_idx: int, output_group: OutputGroup
|
|
222
|
+
) -> Context:
|
|
223
|
+
"""Phase 3: Prepare context specific to this OutputGroup.
|
|
224
|
+
|
|
225
|
+
Creates a modified context for this group's engine call, potentially
|
|
226
|
+
with group-specific instructions or metadata.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
ctx: Base context
|
|
230
|
+
group_idx: Index of this group (0-based)
|
|
231
|
+
output_group: The OutputGroup being processed
|
|
232
|
+
|
|
233
|
+
Returns:
|
|
234
|
+
Context for this group (may be the same instance or modified)
|
|
235
|
+
"""
|
|
236
|
+
# For now, return the same context
|
|
237
|
+
# Phase 4 will add group-specific system prompts here
|
|
238
|
+
# Future: ctx.clone() and add group_description to system prompt
|
|
239
|
+
return ctx
|
|
240
|
+
|
|
241
|
+
def find_matching_artifact(
|
|
242
|
+
self, output_decl: AgentOutput, result: EvalResult
|
|
243
|
+
) -> Artifact | None:
|
|
244
|
+
"""Phase 6: Find artifact from engine result that matches this output declaration.
|
|
245
|
+
|
|
246
|
+
Returns the artifact object (with its ID) so we can preserve it when creating
|
|
247
|
+
the final published artifact. This ensures streaming events use the same ID.
|
|
248
|
+
|
|
249
|
+
Args:
|
|
250
|
+
output_decl: Output declaration to match
|
|
251
|
+
result: Engine result containing artifacts
|
|
252
|
+
|
|
253
|
+
Returns:
|
|
254
|
+
Matching artifact or None if not found
|
|
255
|
+
"""
|
|
256
|
+
if not result.artifacts:
|
|
257
|
+
return None
|
|
258
|
+
|
|
259
|
+
# Normalize the expected type name to canonical form
|
|
260
|
+
expected_canonical = type_registry.resolve_name(output_decl.spec.type_name)
|
|
261
|
+
|
|
262
|
+
for artifact in result.artifacts:
|
|
263
|
+
# Normalize artifact type name to canonical form for comparison
|
|
264
|
+
artifact_canonical = TypeResolutionHelper.safe_resolve(
|
|
265
|
+
type_registry, artifact.type
|
|
266
|
+
)
|
|
267
|
+
if artifact_canonical == expected_canonical:
|
|
268
|
+
return artifact
|
|
269
|
+
|
|
270
|
+
return None
|
|
271
|
+
|
|
272
|
+
def select_payload(
|
|
273
|
+
self, output_decl: AgentOutput, result: EvalResult
|
|
274
|
+
) -> dict[str, Any] | None:
|
|
275
|
+
"""Extract payload from engine result for output declaration.
|
|
276
|
+
|
|
277
|
+
Args:
|
|
278
|
+
output_decl: Output declaration defining expected type
|
|
279
|
+
result: Engine result containing artifacts
|
|
280
|
+
|
|
281
|
+
Returns:
|
|
282
|
+
Payload dict or None if not found
|
|
283
|
+
"""
|
|
284
|
+
# Normalize the expected type name to canonical form
|
|
285
|
+
expected_canonical = type_registry.resolve_name(output_decl.spec.type_name)
|
|
286
|
+
|
|
287
|
+
# Try to find payload in artifacts first
|
|
288
|
+
if result.artifacts:
|
|
289
|
+
for artifact in result.artifacts:
|
|
290
|
+
# Normalize artifact type name to canonical form for comparison
|
|
291
|
+
artifact_canonical = TypeResolutionHelper.safe_resolve(
|
|
292
|
+
type_registry, artifact.type
|
|
293
|
+
)
|
|
294
|
+
if artifact_canonical == expected_canonical:
|
|
295
|
+
return artifact.payload
|
|
296
|
+
|
|
297
|
+
# Fallback to state entries keyed by type name
|
|
298
|
+
maybe_data = result.state.get(output_decl.spec.type_name)
|
|
299
|
+
if isinstance(maybe_data, dict):
|
|
300
|
+
return maybe_data
|
|
301
|
+
return None
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
__all__ = ["OutputProcessor"]
|
flock/api/__init__.py
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"""HTTP API service layer for Flock.
|
|
2
|
+
|
|
3
|
+
This module contains HTTP service implementations and API models for
|
|
4
|
+
serving the Flock orchestrator over HTTP with REST endpoints.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from flock.api.models import (
|
|
8
|
+
ArtifactPublishRequest,
|
|
9
|
+
ArtifactPublishResponse,
|
|
10
|
+
CorrelationStatusResponse,
|
|
11
|
+
)
|
|
12
|
+
from flock.api.service import BlackboardHTTPService
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"ArtifactPublishRequest",
|
|
17
|
+
"ArtifactPublishResponse",
|
|
18
|
+
"BlackboardHTTPService",
|
|
19
|
+
"CorrelationStatusResponse",
|
|
20
|
+
]
|
|
@@ -6,9 +6,7 @@ This improves API documentation and enables SDK generation.
|
|
|
6
6
|
All models maintain 100% backwards compatibility with existing wire format.
|
|
7
7
|
"""
|
|
8
8
|
|
|
9
|
-
from datetime import datetime
|
|
10
9
|
from typing import Any, Literal
|
|
11
|
-
from uuid import UUID
|
|
12
10
|
|
|
13
11
|
from pydantic import BaseModel, Field
|
|
14
12
|
|
|
@@ -10,7 +10,7 @@ from uuid import UUID
|
|
|
10
10
|
from fastapi import FastAPI, HTTPException, Query
|
|
11
11
|
from fastapi.responses import PlainTextResponse
|
|
12
12
|
|
|
13
|
-
from flock.
|
|
13
|
+
from flock.api.models import (
|
|
14
14
|
Agent,
|
|
15
15
|
AgentListResponse,
|
|
16
16
|
AgentRunRequest,
|
|
@@ -24,12 +24,12 @@ from flock.api_models import (
|
|
|
24
24
|
HealthResponse,
|
|
25
25
|
ProducedArtifact,
|
|
26
26
|
)
|
|
27
|
+
from flock.core.store import ArtifactEnvelope, ConsumptionRecord, FilterConfig
|
|
27
28
|
from flock.registry import type_registry
|
|
28
|
-
from flock.store import ArtifactEnvelope, ConsumptionRecord, FilterConfig
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
if TYPE_CHECKING:
|
|
32
|
-
from flock.
|
|
32
|
+
from flock.core import Flock
|
|
33
33
|
|
|
34
34
|
|
|
35
35
|
class BlackboardHTTPService:
|
flock/cli.py
CHANGED
|
@@ -12,8 +12,8 @@ from typer.models import OptionInfo
|
|
|
12
12
|
|
|
13
13
|
# Lazy import: only import examples when CLI commands are invoked
|
|
14
14
|
# This prevents polluting type_registry on every package import
|
|
15
|
-
from flock.service import BlackboardHTTPService
|
|
16
|
-
from flock.store import SQLiteBlackboardStore
|
|
15
|
+
from flock.api.service import BlackboardHTTPService
|
|
16
|
+
from flock.core.store import SQLiteBlackboardStore
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
app = typer.Typer(help="Blackboard Agents CLI")
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""Component library for extending Flock agents and orchestrators."""
|
|
2
|
+
|
|
3
|
+
# Agent components
|
|
4
|
+
from flock.components.agent import (
|
|
5
|
+
AgentComponent,
|
|
6
|
+
AgentComponentConfig,
|
|
7
|
+
EngineComponent,
|
|
8
|
+
OutputUtilityComponent,
|
|
9
|
+
OutputUtilityConfig,
|
|
10
|
+
TracedModelMeta,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
# Orchestrator components
|
|
14
|
+
from flock.components.orchestrator import (
|
|
15
|
+
BuiltinCollectionComponent,
|
|
16
|
+
CircuitBreakerComponent,
|
|
17
|
+
CollectionResult,
|
|
18
|
+
DeduplicationComponent,
|
|
19
|
+
OrchestratorComponent,
|
|
20
|
+
OrchestratorComponentConfig,
|
|
21
|
+
ScheduleDecision,
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
# Agent components
|
|
27
|
+
"AgentComponent",
|
|
28
|
+
"AgentComponentConfig",
|
|
29
|
+
"EngineComponent",
|
|
30
|
+
"OutputUtilityComponent",
|
|
31
|
+
"OutputUtilityConfig",
|
|
32
|
+
"TracedModelMeta",
|
|
33
|
+
# Orchestrator components
|
|
34
|
+
"BuiltinCollectionComponent",
|
|
35
|
+
"CircuitBreakerComponent",
|
|
36
|
+
"CollectionResult",
|
|
37
|
+
"DeduplicationComponent",
|
|
38
|
+
"OrchestratorComponent",
|
|
39
|
+
"OrchestratorComponentConfig",
|
|
40
|
+
"ScheduleDecision",
|
|
41
|
+
]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Agent component library - Base classes and built-in components."""
|
|
2
|
+
|
|
3
|
+
from flock.components.agent.base import (
|
|
4
|
+
AgentComponent,
|
|
5
|
+
AgentComponentConfig,
|
|
6
|
+
EngineComponent,
|
|
7
|
+
TracedModelMeta,
|
|
8
|
+
)
|
|
9
|
+
from flock.components.agent.output_utility import (
|
|
10
|
+
OutputUtilityComponent,
|
|
11
|
+
OutputUtilityConfig,
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"AgentComponent",
|
|
17
|
+
"AgentComponentConfig",
|
|
18
|
+
"EngineComponent",
|
|
19
|
+
"OutputUtilityComponent",
|
|
20
|
+
"OutputUtilityConfig",
|
|
21
|
+
"TracedModelMeta",
|
|
22
|
+
]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"""Agent component
|
|
1
|
+
"""Agent component base classes and configuration."""
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
@@ -13,8 +13,8 @@ from flock.logging.auto_trace import AutoTracedMeta
|
|
|
13
13
|
|
|
14
14
|
if TYPE_CHECKING: # pragma: no cover - type checking only
|
|
15
15
|
from flock.agent import Agent, OutputGroup
|
|
16
|
-
from flock.artifacts import Artifact
|
|
17
|
-
from flock.runtime import Context, EvalInputs, EvalResult
|
|
16
|
+
from flock.core.artifacts import Artifact
|
|
17
|
+
from flock.utils.runtime import Context, EvalInputs, EvalResult
|
|
18
18
|
|
|
19
19
|
T = TypeVar("T", bound="AgentComponentConfig")
|
|
20
20
|
|
|
@@ -219,4 +219,5 @@ __all__ = [
|
|
|
219
219
|
"AgentComponent",
|
|
220
220
|
"AgentComponentConfig",
|
|
221
221
|
"EngineComponent",
|
|
222
|
+
"TracedModelMeta",
|
|
222
223
|
]
|
|
@@ -1,25 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
"""Output formatting and display functionality for agents using unified component architecture."""
|
|
1
|
+
"""Output formatting and display functionality for agents."""
|
|
3
2
|
|
|
4
3
|
import re
|
|
5
4
|
from typing import TYPE_CHECKING, Any
|
|
6
5
|
|
|
7
6
|
from pydantic import Field
|
|
8
7
|
|
|
9
|
-
from flock.components import AgentComponent, AgentComponentConfig
|
|
8
|
+
from flock.components.agent.base import AgentComponent, AgentComponentConfig
|
|
10
9
|
from flock.logging.formatters.themed_formatter import (
|
|
11
10
|
ThemedAgentResultFormatter,
|
|
12
11
|
)
|
|
13
12
|
from flock.logging.formatters.themes import OutputTheme
|
|
14
13
|
from flock.logging.logging import get_logger
|
|
15
|
-
from flock.runtime import Context, EvalInputs, EvalResult
|
|
14
|
+
from flock.utils.runtime import Context, EvalInputs, EvalResult
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
if TYPE_CHECKING: # pragma: no cover - type checking only
|
|
19
|
-
from flock.
|
|
18
|
+
from flock.core import Agent
|
|
20
19
|
|
|
21
20
|
|
|
22
|
-
logger = get_logger("components.
|
|
21
|
+
logger = get_logger("components.agent.output_utility")
|
|
23
22
|
|
|
24
23
|
|
|
25
24
|
class OutputUtilityConfig(AgentComponentConfig):
|
|
@@ -188,7 +187,7 @@ class OutputUtilityComponent(AgentComponent):
|
|
|
188
187
|
if ctx:
|
|
189
188
|
import asyncio
|
|
190
189
|
|
|
191
|
-
from flock.
|
|
190
|
+
from flock.core import Agent
|
|
192
191
|
|
|
193
192
|
# Wait until no streams are active
|
|
194
193
|
max_wait = 30 # seconds
|
|
@@ -244,3 +243,9 @@ class OutputUtilityComponent(AgentComponent):
|
|
|
244
243
|
def add_custom_formatter(self, key: str, formatter_name: str) -> None:
|
|
245
244
|
"""Add a custom formatter for a specific output key."""
|
|
246
245
|
self.config.custom_formatters[key] = formatter_name
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
__all__ = [
|
|
249
|
+
"OutputUtilityComponent",
|
|
250
|
+
"OutputUtilityConfig",
|
|
251
|
+
]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Orchestrator component library - Base classes and built-in components."""
|
|
2
|
+
|
|
3
|
+
from flock.components.orchestrator.base import (
|
|
4
|
+
CollectionResult,
|
|
5
|
+
OrchestratorComponent,
|
|
6
|
+
OrchestratorComponentConfig,
|
|
7
|
+
ScheduleDecision,
|
|
8
|
+
)
|
|
9
|
+
from flock.components.orchestrator.circuit_breaker import CircuitBreakerComponent
|
|
10
|
+
from flock.components.orchestrator.collection import BuiltinCollectionComponent
|
|
11
|
+
from flock.components.orchestrator.deduplication import DeduplicationComponent
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
__all__ = [
|
|
15
|
+
"BuiltinCollectionComponent",
|
|
16
|
+
"CircuitBreakerComponent",
|
|
17
|
+
"CollectionResult",
|
|
18
|
+
"DeduplicationComponent",
|
|
19
|
+
"OrchestratorComponent",
|
|
20
|
+
"OrchestratorComponentConfig",
|
|
21
|
+
"ScheduleDecision",
|
|
22
|
+
]
|