flock-core 0.5.9__py3-none-any.whl → 0.5.11__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/agent.py +149 -62
- flock/api/themes.py +6 -2
- flock/api_models.py +285 -0
- flock/artifact_collector.py +6 -3
- flock/batch_accumulator.py +3 -1
- flock/cli.py +3 -1
- flock/components.py +45 -56
- flock/context_provider.py +531 -0
- flock/correlation_engine.py +8 -4
- flock/dashboard/collector.py +48 -29
- flock/dashboard/events.py +10 -4
- flock/dashboard/launcher.py +3 -1
- flock/dashboard/models/graph.py +9 -3
- flock/dashboard/service.py +187 -93
- flock/dashboard/websocket.py +17 -4
- flock/engines/dspy_engine.py +174 -98
- flock/engines/examples/simple_batch_engine.py +9 -3
- flock/examples.py +6 -2
- flock/frontend/src/services/indexeddb.test.ts +4 -4
- flock/frontend/src/services/indexeddb.ts +1 -1
- flock/helper/cli_helper.py +14 -1
- flock/logging/auto_trace.py +6 -1
- flock/logging/formatters/enum_builder.py +3 -1
- flock/logging/formatters/theme_builder.py +32 -17
- flock/logging/formatters/themed_formatter.py +38 -22
- flock/logging/logging.py +21 -7
- flock/logging/telemetry.py +9 -3
- flock/logging/telemetry_exporter/duckdb_exporter.py +27 -25
- flock/logging/trace_and_logged.py +14 -5
- flock/mcp/__init__.py +3 -6
- flock/mcp/client.py +49 -19
- flock/mcp/config.py +12 -6
- flock/mcp/manager.py +6 -2
- flock/mcp/servers/sse/flock_sse_server.py +9 -3
- flock/mcp/servers/streamable_http/flock_streamable_http_server.py +6 -2
- flock/mcp/tool.py +18 -6
- flock/mcp/types/handlers.py +3 -1
- flock/mcp/types/types.py +9 -3
- flock/orchestrator.py +449 -58
- flock/orchestrator_component.py +15 -5
- flock/patches/dspy_streaming_patch.py +12 -4
- flock/registry.py +9 -3
- flock/runtime.py +69 -18
- flock/service.py +135 -64
- flock/store.py +29 -10
- flock/subscription.py +6 -4
- flock/system_artifacts.py +33 -0
- flock/utilities.py +41 -13
- flock/utility/output_utility_component.py +31 -11
- {flock_core-0.5.9.dist-info → flock_core-0.5.11.dist-info}/METADATA +150 -26
- {flock_core-0.5.9.dist-info → flock_core-0.5.11.dist-info}/RECORD +54 -51
- {flock_core-0.5.9.dist-info → flock_core-0.5.11.dist-info}/WHEEL +0 -0
- {flock_core-0.5.9.dist-info → flock_core-0.5.11.dist-info}/entry_points.txt +0 -0
- {flock_core-0.5.9.dist-info → flock_core-0.5.11.dist-info}/licenses/LICENSE +0 -0
flock/dashboard/collector.py
CHANGED
|
@@ -54,7 +54,9 @@ class RunRecord:
|
|
|
54
54
|
error_message: str | None = None
|
|
55
55
|
|
|
56
56
|
def to_graph_run(self) -> GraphRun:
|
|
57
|
-
status =
|
|
57
|
+
status = (
|
|
58
|
+
self.status if self.status in {"active", "completed", "error"} else "active"
|
|
59
|
+
)
|
|
58
60
|
return GraphRun(
|
|
59
61
|
run_id=self.run_id,
|
|
60
62
|
agent_name=self.agent_name,
|
|
@@ -102,7 +104,10 @@ class DashboardEventCollector(AgentComponent):
|
|
|
102
104
|
|
|
103
105
|
# Use PrivateAttr for non-Pydantic fields (AgentComponent extends BaseModel)
|
|
104
106
|
_events: deque[
|
|
105
|
-
AgentActivatedEvent
|
|
107
|
+
AgentActivatedEvent
|
|
108
|
+
| MessagePublishedEvent
|
|
109
|
+
| AgentCompletedEvent
|
|
110
|
+
| AgentErrorEvent
|
|
106
111
|
] = PrivateAttr(default=None)
|
|
107
112
|
|
|
108
113
|
# Track run start times for duration calculation
|
|
@@ -114,7 +119,9 @@ class DashboardEventCollector(AgentComponent):
|
|
|
114
119
|
# Graph assembly helpers
|
|
115
120
|
_graph_lock: asyncio.Lock = PrivateAttr(default_factory=asyncio.Lock)
|
|
116
121
|
_run_registry: dict[str, RunRecord] = PrivateAttr(default_factory=dict)
|
|
117
|
-
_artifact_consumers: dict[str, set[str]] = PrivateAttr(
|
|
122
|
+
_artifact_consumers: dict[str, set[str]] = PrivateAttr(
|
|
123
|
+
default_factory=lambda: defaultdict(set)
|
|
124
|
+
)
|
|
118
125
|
_agent_status: dict[str, str] = PrivateAttr(default_factory=dict)
|
|
119
126
|
_agent_snapshots: dict[str, AgentSnapshot] = PrivateAttr(default_factory=dict)
|
|
120
127
|
|
|
@@ -185,13 +192,15 @@ class DashboardEventCollector(AgentComponent):
|
|
|
185
192
|
await self._update_agent_snapshot_locked(agent)
|
|
186
193
|
|
|
187
194
|
# Build subscription info from agent's subscriptions
|
|
188
|
-
subscription_info = SubscriptionInfo(from_agents=[],
|
|
195
|
+
subscription_info = SubscriptionInfo(from_agents=[], tags=[], mode="both")
|
|
189
196
|
|
|
190
197
|
if agent.subscriptions:
|
|
191
198
|
# Get first subscription's config (agents typically have one)
|
|
192
199
|
sub = agent.subscriptions[0]
|
|
193
|
-
subscription_info.from_agents =
|
|
194
|
-
|
|
200
|
+
subscription_info.from_agents = (
|
|
201
|
+
list(sub.from_agents) if sub.from_agents else []
|
|
202
|
+
)
|
|
203
|
+
subscription_info.tags = list(sub.tags) if sub.tags else []
|
|
195
204
|
subscription_info.mode = sub.mode
|
|
196
205
|
|
|
197
206
|
# Create and store event
|
|
@@ -210,7 +219,9 @@ class DashboardEventCollector(AgentComponent):
|
|
|
210
219
|
)
|
|
211
220
|
|
|
212
221
|
self._events.append(event)
|
|
213
|
-
logger.info(
|
|
222
|
+
logger.info(
|
|
223
|
+
f"Agent activated: {agent.name} (correlation_id={event.correlation_id})"
|
|
224
|
+
)
|
|
214
225
|
|
|
215
226
|
# Broadcast via WebSocket if manager is configured
|
|
216
227
|
if self._websocket_manager:
|
|
@@ -220,7 +231,9 @@ class DashboardEventCollector(AgentComponent):
|
|
|
220
231
|
|
|
221
232
|
return inputs
|
|
222
233
|
|
|
223
|
-
async def on_post_publish(
|
|
234
|
+
async def on_post_publish(
|
|
235
|
+
self, agent: "Agent", ctx: Context, artifact: "Artifact"
|
|
236
|
+
) -> None:
|
|
224
237
|
"""Emit message_published event when artifact is published.
|
|
225
238
|
|
|
226
239
|
Args:
|
|
@@ -391,7 +404,9 @@ class DashboardEventCollector(AgentComponent):
|
|
|
391
404
|
}
|
|
392
405
|
runs = [record.to_graph_run() for record in self._run_registry.values()]
|
|
393
406
|
agent_status = dict(self._agent_status)
|
|
394
|
-
return GraphState(
|
|
407
|
+
return GraphState(
|
|
408
|
+
consumptions=consumptions, runs=runs, agent_status=agent_status
|
|
409
|
+
)
|
|
395
410
|
|
|
396
411
|
async def snapshot_agent_registry(self) -> dict[str, AgentSnapshot]:
|
|
397
412
|
"""Return a snapshot of all known agents (active and inactive)."""
|
|
@@ -456,21 +471,17 @@ class DashboardEventCollector(AgentComponent):
|
|
|
456
471
|
async def _update_agent_snapshot_locked(self, agent: "Agent") -> None:
|
|
457
472
|
now = datetime.now(UTC)
|
|
458
473
|
description = agent.description or ""
|
|
459
|
-
subscriptions = sorted(
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
if getattr(output, "spec", None) is not None
|
|
471
|
-
and getattr(output.spec, "type_name", "")
|
|
472
|
-
}
|
|
473
|
-
)
|
|
474
|
+
subscriptions = sorted({
|
|
475
|
+
type_name
|
|
476
|
+
for subscription in getattr(agent, "subscriptions", [])
|
|
477
|
+
for type_name in getattr(subscription, "type_names", [])
|
|
478
|
+
})
|
|
479
|
+
output_types = sorted({
|
|
480
|
+
output.spec.type_name
|
|
481
|
+
for output in getattr(agent, "outputs", [])
|
|
482
|
+
if getattr(output, "spec", None) is not None
|
|
483
|
+
and getattr(output.spec, "type_name", "")
|
|
484
|
+
})
|
|
474
485
|
labels = sorted(agent.labels)
|
|
475
486
|
|
|
476
487
|
signature_payload = {
|
|
@@ -519,7 +530,9 @@ class DashboardEventCollector(AgentComponent):
|
|
|
519
530
|
first_seen=snapshot.first_seen,
|
|
520
531
|
last_seen=snapshot.last_seen,
|
|
521
532
|
signature=snapshot.signature,
|
|
522
|
-
logic_operations=[
|
|
533
|
+
logic_operations=[
|
|
534
|
+
dict(op) for op in snapshot.logic_operations
|
|
535
|
+
], # Phase 1.2
|
|
523
536
|
)
|
|
524
537
|
|
|
525
538
|
def _snapshot_to_record(self, snapshot: AgentSnapshot) -> AgentSnapshotRecord:
|
|
@@ -545,19 +558,25 @@ class DashboardEventCollector(AgentComponent):
|
|
|
545
558
|
"""
|
|
546
559
|
# Get visibility kind from class name, stripping "Visibility" suffix
|
|
547
560
|
class_name = type(visibility).__name__
|
|
548
|
-
kind = class_name
|
|
561
|
+
kind = class_name.removesuffix("Visibility")
|
|
549
562
|
|
|
550
563
|
spec = VisibilitySpec(kind=kind)
|
|
551
564
|
|
|
552
565
|
# Extract type-specific fields
|
|
553
566
|
if kind == "Private":
|
|
554
|
-
spec.agents =
|
|
567
|
+
spec.agents = (
|
|
568
|
+
list(visibility.agents) if hasattr(visibility, "agents") else []
|
|
569
|
+
)
|
|
555
570
|
elif kind == "Labelled":
|
|
556
571
|
spec.required_labels = (
|
|
557
|
-
list(visibility.required_labels)
|
|
572
|
+
list(visibility.required_labels)
|
|
573
|
+
if hasattr(visibility, "required_labels")
|
|
574
|
+
else []
|
|
558
575
|
)
|
|
559
576
|
elif kind == "Tenant":
|
|
560
|
-
spec.tenant_id =
|
|
577
|
+
spec.tenant_id = (
|
|
578
|
+
visibility.tenant_id if hasattr(visibility, "tenant_id") else None
|
|
579
|
+
)
|
|
561
580
|
|
|
562
581
|
return spec
|
|
563
582
|
|
flock/dashboard/events.py
CHANGED
|
@@ -14,7 +14,7 @@ class SubscriptionInfo(BaseModel):
|
|
|
14
14
|
"""Subscription configuration for an agent."""
|
|
15
15
|
|
|
16
16
|
from_agents: list[str] = Field(default_factory=list)
|
|
17
|
-
|
|
17
|
+
tags: list[str] = Field(default_factory=list)
|
|
18
18
|
mode: str = "both" # "both" | "events" | "direct"
|
|
19
19
|
|
|
20
20
|
|
|
@@ -123,8 +123,12 @@ class StreamingOutputEvent(BaseModel):
|
|
|
123
123
|
is_final: bool = False # True when agent completes this output stream
|
|
124
124
|
|
|
125
125
|
# Artifact tracking (Phase 6: for message streaming preview)
|
|
126
|
-
artifact_id: str | None =
|
|
127
|
-
|
|
126
|
+
artifact_id: str | None = (
|
|
127
|
+
None # Pre-generated artifact ID for streaming message nodes
|
|
128
|
+
)
|
|
129
|
+
artifact_type: str | None = (
|
|
130
|
+
None # Artifact type name (e.g., "__main__.BookOutline")
|
|
131
|
+
)
|
|
128
132
|
|
|
129
133
|
|
|
130
134
|
class AgentCompletedEvent(BaseModel):
|
|
@@ -149,7 +153,9 @@ class AgentCompletedEvent(BaseModel):
|
|
|
149
153
|
artifacts_produced: list[str] = Field(default_factory=list) # [artifact_id]
|
|
150
154
|
|
|
151
155
|
# Metrics and state
|
|
152
|
-
metrics: dict[str, Any] = Field(
|
|
156
|
+
metrics: dict[str, Any] = Field(
|
|
157
|
+
default_factory=dict
|
|
158
|
+
) # {"tokens_used": 1234, "cost": 0.05}
|
|
153
159
|
final_state: dict[str, Any] = Field(default_factory=dict) # Context.state snapshot
|
|
154
160
|
|
|
155
161
|
|
flock/dashboard/launcher.py
CHANGED
|
@@ -94,7 +94,9 @@ class DashboardLauncher:
|
|
|
94
94
|
|
|
95
95
|
def _start_dev_server(self) -> None:
|
|
96
96
|
"""Start npm dev server for hot-reload development."""
|
|
97
|
-
print(
|
|
97
|
+
print(
|
|
98
|
+
f"[Dashboard] Starting dev server (DASHBOARD_DEV=1) on port {self.port}..."
|
|
99
|
+
)
|
|
98
100
|
|
|
99
101
|
try:
|
|
100
102
|
self._npm_process = subprocess.Popen(
|
flock/dashboard/models/graph.py
CHANGED
|
@@ -104,7 +104,9 @@ class GraphStatistics(BaseModel):
|
|
|
104
104
|
consumed_by_agent: dict[str, GraphAgentMetrics] = Field(
|
|
105
105
|
default_factory=dict, alias="consumedByAgent"
|
|
106
106
|
)
|
|
107
|
-
artifact_summary: dict[str, Any] = Field(
|
|
107
|
+
artifact_summary: dict[str, Any] = Field(
|
|
108
|
+
default_factory=dict, alias="artifactSummary"
|
|
109
|
+
)
|
|
108
110
|
|
|
109
111
|
|
|
110
112
|
class GraphArtifact(BaseModel):
|
|
@@ -128,8 +130,12 @@ class GraphRun(BaseModel):
|
|
|
128
130
|
agent_name: str = Field(alias="agentName")
|
|
129
131
|
correlation_id: str | None = Field(default=None, alias="correlationId")
|
|
130
132
|
status: Literal["active", "completed", "error"] = "active"
|
|
131
|
-
consumed_artifacts: list[str] = Field(
|
|
132
|
-
|
|
133
|
+
consumed_artifacts: list[str] = Field(
|
|
134
|
+
default_factory=list, alias="consumedArtifacts"
|
|
135
|
+
)
|
|
136
|
+
produced_artifacts: list[str] = Field(
|
|
137
|
+
default_factory=list, alias="producedArtifacts"
|
|
138
|
+
)
|
|
133
139
|
duration_ms: float | None = Field(default=None, alias="durationMs")
|
|
134
140
|
started_at: datetime | None = Field(default=None, alias="startedAt")
|
|
135
141
|
completed_at: datetime | None = Field(default=None, alias="completedAt")
|