flock-core 0.1.1__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.

Files changed (48) hide show
  1. flock/__init__.py +4 -0
  2. flock/agents/__init__.py +3 -0
  3. flock/agents/batch_agent.py +175 -0
  4. flock/agents/declarative_agent.py +166 -0
  5. flock/agents/loop_agent.py +178 -0
  6. flock/agents/trigger_agent.py +191 -0
  7. flock/agents/user_agent.py +230 -0
  8. flock/app/components/__init__.py +14 -0
  9. flock/app/components/charts/agent_workflow.py +14 -0
  10. flock/app/components/charts/core_architecture.py +14 -0
  11. flock/app/components/charts/tool_system.py +14 -0
  12. flock/app/components/history_grid.py +168 -0
  13. flock/app/components/history_grid_alt.py +189 -0
  14. flock/app/components/sidebar.py +19 -0
  15. flock/app/components/theme.py +9 -0
  16. flock/app/components/util.py +18 -0
  17. flock/app/hive_app.py +118 -0
  18. flock/app/html/d3.html +179 -0
  19. flock/app/modules/__init__.py +12 -0
  20. flock/app/modules/about.py +17 -0
  21. flock/app/modules/agent_detail.py +70 -0
  22. flock/app/modules/agent_list.py +59 -0
  23. flock/app/modules/playground.py +322 -0
  24. flock/app/modules/settings.py +96 -0
  25. flock/core/__init__.py +7 -0
  26. flock/core/agent.py +150 -0
  27. flock/core/agent_registry.py +162 -0
  28. flock/core/config/declarative_agent_config.py +0 -0
  29. flock/core/context.py +279 -0
  30. flock/core/context_vars.py +6 -0
  31. flock/core/flock.py +208 -0
  32. flock/core/handoff/handoff_base.py +12 -0
  33. flock/core/logging/__init__.py +18 -0
  34. flock/core/logging/error_handler.py +84 -0
  35. flock/core/logging/formatters.py +122 -0
  36. flock/core/logging/handlers.py +117 -0
  37. flock/core/logging/logger.py +107 -0
  38. flock/core/serializable.py +206 -0
  39. flock/core/tools/basic_tools.py +98 -0
  40. flock/workflow/activities.py +115 -0
  41. flock/workflow/agent_activities.py +26 -0
  42. flock/workflow/temporal_setup.py +37 -0
  43. flock/workflow/workflow.py +53 -0
  44. flock_core-0.1.1.dist-info/METADATA +449 -0
  45. flock_core-0.1.1.dist-info/RECORD +48 -0
  46. flock_core-0.1.1.dist-info/WHEEL +4 -0
  47. flock_core-0.1.1.dist-info/entry_points.txt +2 -0
  48. flock_core-0.1.1.dist-info/licenses/LICENSE +21 -0
@@ -0,0 +1,12 @@
1
+ from .agent_detail import AgentDetailView
2
+ from .agent_list import AgentContent, agent_data
3
+ from .playground import Playground
4
+ from .settings import Settings
5
+
6
+ __all__ = [
7
+ "AgentContent",
8
+ "AgentDetailView",
9
+ "Playground",
10
+ "Settings",
11
+ "agent_data",
12
+ ]
@@ -0,0 +1,17 @@
1
+ from fasthtml.common import *
2
+ from fasthtml.svg import *
3
+ from monsterui.all import *
4
+
5
+ from flock.app.components import CoreArchitectureChart
6
+
7
+
8
+ def AboutPage():
9
+ return Div(cls="flex flex-col", uk_filter="target: .js-filter")(
10
+ Div(cls="flex px-4 py-2 ")(
11
+ H3("About & Help"),
12
+ ),
13
+ Div(
14
+ Div(cls="p-4")(CoreArchitectureChart()),
15
+ cls="w-[1200px]",
16
+ ),
17
+ )
@@ -0,0 +1,70 @@
1
+ from fasthtml.common import *
2
+ from fasthtml.svg import *
3
+ from monsterui.all import *
4
+
5
+ from flock.app.components import HistoryGrid
6
+ from flock.app.components.util import IconNav, IconNavItem, format_date
7
+
8
+ ##############################
9
+ # Agents
10
+ ##############################
11
+
12
+
13
+ def AgentDetailView(agent):
14
+ action_icons = [("copy", "Duplicate"), ("pencil", "Edit"), ("cloud-upload", "Deploy")]
15
+ status_items = ["Toggle Production", "Arcflock", "Add Label", "Monitor Usage"]
16
+
17
+ return Div(cls="flex flex-col")(
18
+ Div(cls="flex h-14 flex-none items-center border-b border-border p-2")(
19
+ DivFullySpaced(
20
+ DivLAligned(
21
+ IconNav(*IconNavItem(*action_icons)),
22
+ IconNav(Li(A(UkIcon("activity"), uk_tooltip="Metrics")), cls="pl-2"),
23
+ cls="gap-x-2 divide-x divide-border",
24
+ ),
25
+ IconNav(
26
+ *IconNavItem(("trash", "Delete"), ("code", "View JSON")),
27
+ Li(A(UkIcon("ellipsis-vertical", button=True))),
28
+ DropDownNavContainer(*map(lambda x: Li(A(x)), status_items)),
29
+ ),
30
+ )
31
+ ),
32
+ Div(cls="flex-1")(
33
+ DivLAligned(
34
+ DivLAligned(
35
+ Span(UkIcon(agent["icon"]), cls="flex h-10 w-10 items-center justify-center rounded-full bg-muted"),
36
+ Div(cls="grid gap-1")(
37
+ Div(agent["title"], cls=TextT.bold),
38
+ Div(agent["name"], cls="text-xs"),
39
+ # DivLAligned("Type:", agent["type"], cls=TextT.sm),
40
+ ),
41
+ cls="gap-4 text-sm",
42
+ ),
43
+ Div(format_date(agent["created_at"]), cls=TextFont.muted_sm),
44
+ cls="p-4",
45
+ ),
46
+ Div(cls="flex-1 space-y-4 border-t border-border p-4 text-sm")(
47
+ P(agent["description"]),
48
+ Dl(cls="grid grid-cols-2 gap-4")(
49
+ DivLAligned(
50
+ Dt("Production Ready", cls=TextT.muted), Dd("✅" if agent["production_ready"] else "❌")
51
+ ),
52
+ DivLAligned(Dt("Last Updated", cls=TextT.muted), Dd(format_date(agent["last_updated"]))),
53
+ DivLAligned(Dt("Input Schema", cls=TextT.muted), Dd(agent["input"], cls="font-mono text-xs")),
54
+ DivLAligned(Dt("Output Schema", cls=TextT.muted), Dd(agent["output"], cls="font-mono text-xs")),
55
+ ),
56
+ ),
57
+ ),
58
+ Div(cls="flex-none space-y-4 border-t border-border p-4")(
59
+ DivFullySpaced(
60
+ HistoryGrid(reduced=True),
61
+ ),
62
+ ),
63
+ Div(cls="flex-none space-y-4 border-t border-border p-4")(
64
+ DivFullySpaced(
65
+ LabelSwitch("Monitoring Enabled", id="monitoring"),
66
+ Button("Export Configuration", cls=ButtonT.secondary),
67
+ Button("Run Agent", cls=ButtonT.primary),
68
+ ),
69
+ ),
70
+ )
@@ -0,0 +1,59 @@
1
+ import json
2
+ import pathlib
3
+
4
+ from fasthtml.common import *
5
+ from fasthtml.svg import *
6
+ from monsterui.all import *
7
+
8
+ from flock.app.components.util import format_date
9
+
10
+ agent_data = json.load(open(pathlib.Path("data/mock.json")))
11
+
12
+
13
+ def AgentItem(agent):
14
+ cls_base = "space-y-4 relative rounded-lg border border-border p-3 text-sm hover:bg-primary"
15
+ cls = f"{cls_base} {'bg-muted' if agent == agent_data[0] else ''} {'tag-unread' if not agent['production_ready'] else 'tag-mail'}"
16
+
17
+ return Li(cls=cls)(
18
+ DivFullySpaced(
19
+ DivLAligned(
20
+ Span(UkIcon(agent["icon"]), cls="flex h-10 w-10 items-center justify-center"),
21
+ Div(agent["title"], cls="font-semibold"),
22
+ Span(cls="flex h-2 w-2 rounded-full bg-green-600") if agent["production_ready"] else "",
23
+ ),
24
+ Div(format_date(agent["created_at"]), cls="text-xs"),
25
+ cls="mb-4",
26
+ ),
27
+ A(agent["name"], cls=TextFont.bold_sm, href=f"#agent-{agent['id']}"),
28
+ Div(agent["description"][:100] + "...", cls=TextFont.muted_sm),
29
+ DivLAligned(*[
30
+ A(label, cls=f"uk-label relative z-10 {'uk-label-primary' if label == 'analysis' else ''}", href="#")
31
+ for label in agent["labels"]
32
+ ]),
33
+ )
34
+
35
+
36
+ def AgentList(agents):
37
+ return Ul(cls="js-filter space-y-4 p-4 pt-0")(*[AgentItem(agent) for agent in agents])
38
+
39
+
40
+ def AgentContent():
41
+ return Div(cls="flex flex-col", uk_filter="target: .js-filter")(
42
+ Div(cls="flex px-4 py-2 ")(
43
+ H3("Agents"),
44
+ TabContainer(
45
+ Li(A("All Agents", href="#", role="button"), cls="uk-active", uk_filter_control="filter: .tag-mail"),
46
+ Li(A("Production Ready", href="#", role="button"), uk_filter_control="filter: .tag-unread"),
47
+ alt=True,
48
+ cls="ml-auto max-w-80",
49
+ ),
50
+ ),
51
+ Div(cls="flex flex-1 flex-col")(
52
+ Div(cls="p-4")(
53
+ Div(cls="uk-inline w-full")(
54
+ Span(cls="uk-form-icon text-muted-foreground")(UkIcon("search")), Input(placeholder="Search")
55
+ )
56
+ ),
57
+ Div(cls="flex-1 overflow-y-auto max-h-[800px]")(AgentList(agent_data)),
58
+ ),
59
+ )
@@ -0,0 +1,322 @@
1
+ from fasthtml.common import *
2
+ from fasthtml.svg import *
3
+ from monsterui.all import *
4
+
5
+ CODE = """
6
+ var pixelSize = 16
7
+ import 'https://cdn.interactjs.io/v1.9.20/auto-start/index.js'
8
+ import 'https://cdn.interactjs.io/v1.9.20/actions/drag/index.js'
9
+ import 'https://cdn.interactjs.io/v1.9.20/actions/resize/index.js'
10
+ import 'https://cdn.interactjs.io/v1.9.20/modifiers/index.js'
11
+ import 'https://cdn.interactjs.io/v1.9.20/dev-tools/index.js'
12
+ import interact from 'https://cdn.interactjs.io/v1.9.20/interactjs/index.js'
13
+
14
+ interact('.rainbow-pixel-canvas')
15
+ .draggable({
16
+ max: Infinity,
17
+ maxPerElement: Infinity,
18
+ origin: 'self',
19
+ modifiers: [
20
+ interact.modifiers.snap({
21
+ // snap to the corners of a grid
22
+ targets: [
23
+ interact.snappers.grid({ x: pixelSize, y: pixelSize })
24
+ ]
25
+ })
26
+ ],
27
+ listeners: {
28
+ // draw colored squares on move
29
+ move: function (event) {
30
+ var context = event.target.getContext('2d')
31
+ // calculate the angle of the drag direction
32
+ var dragAngle = 180 * Math.atan2(event.dx, event.dy) / Math.PI
33
+
34
+ // set color based on drag angle and speed
35
+ context.fillStyle =
36
+ 'hsl(' +
37
+ dragAngle +
38
+ ', 86%, ' +
39
+ (30 + Math.min(event.speed / 1000, 1) * 50) +
40
+ '%)'
41
+
42
+ // draw squares
43
+ context.fillRect(
44
+ event.pageX - pixelSize / 2,
45
+ event.pageY - pixelSize / 2,
46
+ pixelSize,
47
+ pixelSize
48
+ )
49
+ }
50
+ }
51
+ })
52
+ // clear the canvas on doubletap
53
+ .on('doubletap', function (event) {
54
+ var context = event.target.getContext('2d')
55
+
56
+ context.clearRect(0, 0, context.canvas.width, context.canvas.height)
57
+ resizeCanvases()
58
+ })
59
+
60
+ function resizeCanvases () {
61
+ [].forEach.call(document.querySelectorAll('.rainbow-pixel-canvas'), function (
62
+ canvas
63
+ ) {
64
+ delete canvas.width
65
+ delete canvas.height
66
+
67
+ var rect = canvas.getBoundingClientRect()
68
+
69
+ canvas.width = rect.width
70
+ canvas.height = rect.height
71
+ })
72
+ }
73
+
74
+ resizeCanvases()
75
+
76
+ // interact.js can also add DOM event listeners
77
+ interact(window).on('resize', resizeCanvases)
78
+ """
79
+
80
+ CODE2 = """
81
+ import 'https://cdn.interactjs.io/v1.9.20/auto-start/index.js'
82
+ import 'https://cdn.interactjs.io/v1.9.20/actions/drag/index.js'
83
+ import 'https://cdn.interactjs.io/v1.9.20/actions/resize/index.js'
84
+ import 'https://cdn.interactjs.io/v1.9.20/modifiers/index.js'
85
+ import 'https://cdn.interactjs.io/v1.9.20/dev-tools/index.js'
86
+ import interact from 'https://cdn.interactjs.io/v1.9.20/interactjs/index.js'
87
+ const svg = document.getElementById('connections');
88
+
89
+ // Function to draw an SVG line between two points
90
+ function createConnectionLine(x1, y1, x2, y2) {
91
+ const line = document.createElementNS("http://www.w3.org/2000/svg", "line");
92
+ line.setAttribute("x1", x1);
93
+ line.setAttribute("y1", y1);
94
+ line.setAttribute("x2", x2);
95
+ line.setAttribute("y2", y2);
96
+ line.setAttribute("stroke", "red");
97
+ line.setAttribute("stroke-width", "1");
98
+ return line;
99
+ }
100
+
101
+ // Function to update connection lines
102
+ function updateConnections() {
103
+ // Clear existing connections
104
+ svg.innerHTML = '';
105
+
106
+ // Get the positions of the nodes
107
+ const node1 = document.getElementById('node1');
108
+ const node2 = document.getElementById('node2');
109
+ const rect1 = node1.getBoundingClientRect();
110
+ const rect2 = node2.getBoundingClientRect();
111
+
112
+ // Calculate the centers of the nodes
113
+ const x1 = rect1.left + rect1.width / 2;
114
+ const y1 = rect1.top + rect1.height / 2;
115
+ const x2 = rect2.left + rect2.width / 2;
116
+ const y2 = rect2.top + rect2.height / 2;
117
+
118
+ // Create and append a connection line
119
+ const line = createConnectionLine(x1, y1, x2, y2);
120
+ svg.appendChild(line);
121
+ }
122
+
123
+ // Initialize Interact.js
124
+ interact('.node').draggable({
125
+ listeners: {
126
+ move(event) {
127
+ // Move the dragged node
128
+ const target = event.target;
129
+ const x = (parseFloat(target.getAttribute('data-x')) || 0) + event.dx;
130
+ const y = (parseFloat(target.getAttribute('data-y')) || 0) + event.dy;
131
+
132
+ target.style.transform = `translate(${x}px, ${y}px)`;
133
+ target.setAttribute('data-x', x);
134
+ target.setAttribute('data-y', y);
135
+
136
+ // Update the connections
137
+ updateConnections();
138
+ }
139
+ }
140
+ });
141
+
142
+ // Draw initial connections
143
+ updateConnections();
144
+ """
145
+
146
+ CODE3 = """
147
+ // Initial data
148
+ let data = {
149
+ nodes: [
150
+ {id: 1, name: "Node 1"},
151
+ {id: 2, name: "Node 2"},
152
+ {id: 3, name: "Node 3"}
153
+ ],
154
+ links: [
155
+ {source: 0, target: 1},
156
+ {source: 1, target: 2}
157
+ ]
158
+ };
159
+
160
+ // Create SVG container
161
+ const svg = d3.select("svg");
162
+ const width = +svg.attr("width");
163
+ const height = +svg.attr("height");
164
+
165
+ // Create force simulation
166
+ const simulation = d3.forceSimulation(data.nodes)
167
+ .force("link", d3.forceLink(data.links).id(d => d.id))
168
+ .force("charge", d3.forceManyBody().strength(-300))
169
+ .force("center", d3.forceCenter(width / 2, height / 2));
170
+
171
+ // Create the links
172
+ const link = svg.append("g")
173
+ .selectAll("line")
174
+ .data(data.links)
175
+ .join("line")
176
+ .attr("class", "link");
177
+
178
+ // Create the nodes
179
+ const node = svg.append("g")
180
+ .selectAll("g")
181
+ .data(data.nodes)
182
+ .join("g")
183
+ .attr("class", "node");
184
+
185
+ // Add circles to nodes
186
+ node.append("circle")
187
+ .attr("r", 10)
188
+ .style("fill", (d, i) => d3.schemeCategory10[i % 10]);
189
+
190
+ // Add labels to nodes
191
+ node.append("text")
192
+ .attr("dx", 12)
193
+ .attr("dy", ".35em")
194
+ .text(d => d.name);
195
+
196
+ // Add drag behavior
197
+ node.call(d3.drag()
198
+ .on("start", dragstarted)
199
+ .on("drag", dragged)
200
+ .on("end", dragended));
201
+
202
+ // Double click on background to add node
203
+ svg.on("dblclick", function(event) {
204
+ const coords = d3.pointer(event);
205
+ const newNode = {
206
+ id: data.nodes.length + 1,
207
+ name: `Node ${data.nodes.length + 1}`,
208
+ x: coords[0],
209
+ y: coords[1]
210
+ };
211
+ data.nodes.push(newNode);
212
+
213
+ // Add link to nearest node
214
+ if (data.nodes.length > 1) {
215
+ const lastNode = data.nodes[data.nodes.length - 2];
216
+ data.links.push({
217
+ source: lastNode,
218
+ target: newNode
219
+ });
220
+ }
221
+
222
+ updateGraph();
223
+ });
224
+
225
+ // Update function to refresh the graph
226
+ function updateGraph() {
227
+ // Update links
228
+ const link = svg.selectAll(".link")
229
+ .data(data.links)
230
+ .join("line")
231
+ .attr("class", "link");
232
+
233
+ // Update nodes
234
+ const node = svg.selectAll(".node")
235
+ .data(data.nodes)
236
+ .join(
237
+ enter => {
238
+ const nodeEnter = enter.append("g")
239
+ .attr("class", "node")
240
+ .call(d3.drag()
241
+ .on("start", dragstarted)
242
+ .on("drag", dragged)
243
+ .on("end", dragended));
244
+
245
+ nodeEnter.append("circle")
246
+ .attr("r", 10)
247
+ .style("fill", (d, i) => d3.schemeCategory10[i % 10]);
248
+
249
+ nodeEnter.append("text")
250
+ .attr("dx", 12)
251
+ .attr("dy", ".35em")
252
+ .text(d => d.name);
253
+
254
+ return nodeEnter;
255
+ }
256
+ );
257
+
258
+ // Update simulation
259
+ simulation.nodes(data.nodes);
260
+ simulation.force("link").links(data.links);
261
+ simulation.alpha(1).restart();
262
+ }
263
+
264
+ // Simulation tick function
265
+ simulation.on("tick", () => {
266
+ link
267
+ .attr("x1", d => d.source.x)
268
+ .attr("y1", d => d.source.y)
269
+ .attr("x2", d => d.target.x)
270
+ .attr("y2", d => d.target.y);
271
+
272
+ node
273
+ .attr("transform", d => `translate(${d.x},${d.y})`);
274
+ });
275
+
276
+ // Drag functions
277
+ function dragstarted(event, d) {
278
+ if (!event.active) simulation.alphaTarget(0.3).restart();
279
+ d.fx = d.x;
280
+ d.fy = d.y;
281
+ }
282
+
283
+ function dragged(event, d) {
284
+ d.fx = event.x;
285
+ d.fy = event.y;
286
+ }
287
+
288
+ function dragended(event, d) {
289
+ if (!event.active) simulation.alphaTarget(0);
290
+ d.fx = null;
291
+ d.fy = null;
292
+ }
293
+ """
294
+
295
+
296
+ def get_playground():
297
+ return Container(
298
+ Canvas(cls="rainbow-pixel-canvas w-full h-full"),
299
+ P("Drag to draw. Double tap to clear."),
300
+ Script(code=CODE, type="module"),
301
+ cls="w-full h-full",
302
+ )
303
+
304
+
305
+ def get_playground2():
306
+ return Container(
307
+ Svg(
308
+ width="800",
309
+ height="600",
310
+ ),
311
+ Script(code=CODE3),
312
+ )
313
+
314
+
315
+ def Playground():
316
+ return Div(cls="flex flex-col w-full")(
317
+ Div(cls="px-4 py-2 ")(
318
+ H3("interact.js demo"),
319
+ P("Rainbows!", cls=TextFont.muted_sm),
320
+ ),
321
+ get_playground2(),
322
+ )
@@ -0,0 +1,96 @@
1
+ """FrankenUI Forms Example built with MonsterUI (original design by ShadCN)"""
2
+
3
+ from fasthtml.common import *
4
+ from fasthtml.svg import *
5
+ from monsterui.all import *
6
+
7
+ from flock.app.components import ThemeDialog
8
+
9
+
10
+ def HelpText(c):
11
+ return P(c, cls=TextFont.muted_sm)
12
+
13
+
14
+ def heading():
15
+ return Div(cls="px-4 py-2 ")(
16
+ H3("Settings"),
17
+ P("Manage your account settings and set e-mail preferences.", cls=TextFont.muted_lg),
18
+ DividerSplit(),
19
+ )
20
+
21
+
22
+ sidebar_items = ["API Keys", "Appearance", "Display"]
23
+
24
+ sidebar = NavContainer(
25
+ *map(lambda x: Li(A(x)), sidebar_items),
26
+ uk_switcher="connect: #component-nav; animation: uk-animation-fade",
27
+ cls=(NavT.secondary, "space-y-4 p-4 w-1/5"),
28
+ )
29
+
30
+
31
+ def FormSectionDiv(*c, cls="space-y-2", **kwargs):
32
+ return Div(*c, cls=cls, **kwargs)
33
+
34
+
35
+ def api_key_form():
36
+ content = (
37
+ FormSectionDiv(
38
+ LabelInput("Open AI API Key", placeholder="sk-...", id="username"),
39
+ HelpText("This is your Open AI API key. You can find it in your account settings. "),
40
+ ),
41
+ )
42
+
43
+ return UkFormSection("API Keys", "Manage API keys of your agents", button_txt="Update api keys", *content)
44
+
45
+
46
+ def appearance_form():
47
+ content = (
48
+ FormSectionDiv(
49
+ LabelUkSelect(
50
+ *Options("Select a font family", "Inter", "Geist", "Open Sans", selected_idx=2, disabled_idxs={0}),
51
+ label="Font Family",
52
+ id="font_family",
53
+ ),
54
+ HelpText("Set the font you want to use in the dashboard."),
55
+ ),
56
+ FormSectionDiv(
57
+ FormLabel("Theme"),
58
+ HelpText("Select the theme for the dashboard."),
59
+ ThemeDialog(),
60
+ ),
61
+ )
62
+
63
+ return UkFormSection(
64
+ "Appearance",
65
+ "Customize the appearance of the app. Automatically switch between day and night themes.",
66
+ button_txt="Update preferences",
67
+ *content,
68
+ )
69
+
70
+
71
+ def display_form():
72
+ content = Div(cls="space-y-2")(
73
+ Div(cls="mb-4")(
74
+ Span("Sidebar", cls="text-base font-medium"),
75
+ HelpText("Select the items you want to display in the sidebar."),
76
+ ),
77
+ *[
78
+ Div(CheckboxX(id=f"display_{i}", checked=i in [0, 1, 2]), FormLabel(label))
79
+ for i, label in enumerate(["Recents", "Home", "Applications", "Desktop", "Downloads", "Documents"])
80
+ ],
81
+ )
82
+ return UkFormSection(
83
+ "Display", "Turn items on or off to control what's displayed in the app.", button_txt="Update display", *content
84
+ )
85
+
86
+
87
+ def Settings():
88
+ return Title("Settings form"), Container(
89
+ heading(),
90
+ Div(cls="flex gap-x-12")(
91
+ sidebar,
92
+ Ul(id="component-nav", cls="uk-switcher max-w-2xl")(
93
+ Li(cls="uk-active")(api_key_form(), *map(Li, [appearance_form(), display_form()]))
94
+ ),
95
+ ),
96
+ )
flock/core/__init__.py ADDED
@@ -0,0 +1,7 @@
1
+ from flock.core.agent import Agent
2
+ from flock.core.agent_registry import Registry
3
+ from flock.core.context import FlockContext
4
+ from flock.core.flock import Flock
5
+ from flock.core.serializable import Serializable
6
+
7
+ __all__ = ["Agent", "Flock", "FlockContext", "Registry", "Serializable"]