flock-core 0.2.1__py3-none-any.whl → 0.2.3__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 +4 -0
- flock/config.py +29 -0
- flock/core/__init__.py +5 -0
- flock/core/context/context.py +104 -133
- flock/core/execution/temporal_executor.py +22 -6
- flock/core/flock.py +94 -62
- flock/core/flock_agent.py +150 -68
- flock/core/logging/logging.py +22 -4
- flock/core/logging/telemetry.py +109 -0
- flock/core/logging/telemetry_exporter/file_span.py +37 -0
- flock/core/logging/telemetry_exporter/sqllite_span.py +68 -0
- flock/core/logging/trace_and_logged.py +55 -0
- flock/core/mixin/dspy_integration.py +40 -14
- flock/core/registry/agent_registry.py +89 -74
- flock/core/tools/basic_tools.py +27 -4
- flock/core/tools/dev_tools/github.py +37 -8
- flock/core/util/cli_helper.py +7 -3
- flock/workflow/activities.py +148 -90
- {flock_core-0.2.1.dist-info → flock_core-0.2.3.dist-info}/METADATA +36 -2
- {flock_core-0.2.1.dist-info → flock_core-0.2.3.dist-info}/RECORD +22 -22
- flock/agents/__init__.py +0 -0
- flock/agents/batch_agent.py +0 -140
- flock/agents/loop_agent.py +0 -117
- flock/agents/trigger_agent.py +0 -113
- flock/agents/user_agent.py +0 -145
- {flock_core-0.2.1.dist-info → flock_core-0.2.3.dist-info}/WHEEL +0 -0
- {flock_core-0.2.1.dist-info → flock_core-0.2.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,26 +1,30 @@
|
|
|
1
1
|
"""Mixin class for integrating with the dspy library."""
|
|
2
2
|
|
|
3
3
|
import sys
|
|
4
|
-
from typing import Any
|
|
5
|
-
|
|
6
|
-
import dspy
|
|
4
|
+
from typing import Any, Literal
|
|
7
5
|
|
|
8
6
|
from flock.core.logging.logging import get_logger
|
|
9
7
|
from flock.core.util.input_resolver import split_top_level
|
|
10
8
|
|
|
11
9
|
logger = get_logger("flock")
|
|
12
10
|
|
|
11
|
+
AgentType = (
|
|
12
|
+
Literal["ReAct"] | Literal["Completion"] | Literal["ChainOfThought"] | None
|
|
13
|
+
)
|
|
14
|
+
|
|
13
15
|
|
|
14
16
|
class DSPyIntegrationMixin:
|
|
15
17
|
"""Mixin class for integrating with the dspy library."""
|
|
16
18
|
|
|
17
19
|
def create_dspy_signature_class(
|
|
18
20
|
self, agent_name, description_spec, fields_spec
|
|
19
|
-
) ->
|
|
21
|
+
) -> Any:
|
|
20
22
|
"""Trying to create a dynamic class using dspy library."""
|
|
21
23
|
# ---------------------------
|
|
22
24
|
# 1. Parse the class specification.
|
|
23
25
|
# ---------------------------
|
|
26
|
+
import dspy
|
|
27
|
+
|
|
24
28
|
base_class = dspy.Signature
|
|
25
29
|
|
|
26
30
|
# Start building the class dictionary with a docstring and annotations dict.
|
|
@@ -116,13 +120,16 @@ class DSPyIntegrationMixin:
|
|
|
116
120
|
return type("dspy_" + agent_name, (base_class,), class_dict)
|
|
117
121
|
|
|
118
122
|
def _configure_language_model(self) -> None:
|
|
123
|
+
import dspy
|
|
124
|
+
|
|
119
125
|
"""Initialize and configure the language model using dspy."""
|
|
120
126
|
lm = dspy.LM(self.model, cache=self.use_cache)
|
|
121
127
|
dspy.configure(lm=lm)
|
|
122
128
|
|
|
123
129
|
def _select_task(
|
|
124
130
|
self,
|
|
125
|
-
signature:
|
|
131
|
+
signature: Any,
|
|
132
|
+
agent_type_override: AgentType,
|
|
126
133
|
) -> Any:
|
|
127
134
|
"""Select and instantiate the appropriate task based on tool availability.
|
|
128
135
|
|
|
@@ -134,17 +141,36 @@ class DSPyIntegrationMixin:
|
|
|
134
141
|
Returns:
|
|
135
142
|
An instance of a dspy task (either ReAct or Predict).
|
|
136
143
|
"""
|
|
144
|
+
import dspy
|
|
145
|
+
|
|
137
146
|
dspy_solver = None
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
147
|
+
|
|
148
|
+
if agent_type_override:
|
|
149
|
+
if agent_type_override == "ChainOfThought":
|
|
150
|
+
dspy_solver = dspy.ChainOfThought(
|
|
151
|
+
signature,
|
|
152
|
+
)
|
|
153
|
+
if agent_type_override == "ReAct":
|
|
154
|
+
dspy.ReAct(
|
|
155
|
+
signature,
|
|
156
|
+
tools=self.tools,
|
|
157
|
+
max_iters=10,
|
|
158
|
+
)
|
|
159
|
+
if agent_type_override == "Completion":
|
|
160
|
+
dspy_solver = dspy.Predict(
|
|
161
|
+
signature,
|
|
162
|
+
)
|
|
144
163
|
else:
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
164
|
+
if self.tools:
|
|
165
|
+
dspy_solver = dspy.ReAct(
|
|
166
|
+
signature,
|
|
167
|
+
tools=self.tools,
|
|
168
|
+
max_iters=10,
|
|
169
|
+
)
|
|
170
|
+
else:
|
|
171
|
+
dspy_solver = dspy.Predict(
|
|
172
|
+
signature,
|
|
173
|
+
)
|
|
148
174
|
|
|
149
175
|
return dspy_solver
|
|
150
176
|
|
|
@@ -1,8 +1,14 @@
|
|
|
1
|
-
"""Registry for storing and managing agents and tools."""
|
|
1
|
+
"""Registry for storing and managing agents and tools with logging and tracing integration."""
|
|
2
2
|
|
|
3
3
|
from collections.abc import Callable
|
|
4
4
|
|
|
5
|
+
from opentelemetry import trace
|
|
6
|
+
|
|
5
7
|
from flock.core.flock_agent import FlockAgent
|
|
8
|
+
from flock.core.logging.logging import get_logger
|
|
9
|
+
|
|
10
|
+
logger = get_logger("registry")
|
|
11
|
+
tracer = trace.get_tracer(__name__)
|
|
6
12
|
|
|
7
13
|
|
|
8
14
|
class Registry:
|
|
@@ -16,88 +22,97 @@ class Registry:
|
|
|
16
22
|
_instance = None
|
|
17
23
|
|
|
18
24
|
def __new__(cls):
|
|
19
|
-
""
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
25
|
+
with tracer.start_as_current_span("Registry.__new__") as span:
|
|
26
|
+
if cls._instance is None:
|
|
27
|
+
cls._instance = super().__new__(cls)
|
|
28
|
+
cls._instance._initialize()
|
|
29
|
+
logger.info("Registry instance created")
|
|
30
|
+
span.set_attribute("instance.created", True)
|
|
31
|
+
return cls._instance
|
|
24
32
|
|
|
25
33
|
def _initialize(self):
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
34
|
+
with tracer.start_as_current_span("Registry._initialize"):
|
|
35
|
+
self._agents: list[FlockAgent] = []
|
|
36
|
+
self._tools: list[tuple[str, Callable]] = []
|
|
37
|
+
logger.info("Registry initialized", agents_count=0, tools_count=0)
|
|
29
38
|
|
|
30
39
|
def register_tool(self, tool_name: str, tool: Callable) -> None:
|
|
31
|
-
""
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
with tracer.start_as_current_span("Registry.register_tool") as span:
|
|
41
|
+
span.set_attribute("tool_name", tool_name)
|
|
42
|
+
try:
|
|
43
|
+
self._tools.append((tool_name, tool))
|
|
44
|
+
logger.info("Tool registered", tool_name=tool_name)
|
|
45
|
+
except Exception as e:
|
|
46
|
+
logger.error(
|
|
47
|
+
"Error registering tool", tool_name=tool_name, error=str(e)
|
|
48
|
+
)
|
|
49
|
+
span.record_exception(e)
|
|
50
|
+
raise
|
|
41
51
|
|
|
42
52
|
def register_agent(self, agent: FlockAgent) -> None:
|
|
43
|
-
""
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
with tracer.start_as_current_span("Registry.register_agent") as span:
|
|
54
|
+
span.set_attribute("agent_name", agent.name)
|
|
55
|
+
try:
|
|
56
|
+
self._agents.append(agent)
|
|
57
|
+
logger.info("Agent registered", agent=agent.name)
|
|
58
|
+
except Exception as e:
|
|
59
|
+
logger.error(
|
|
60
|
+
"Error registering agent", agent=agent.name, error=str(e)
|
|
61
|
+
)
|
|
62
|
+
span.record_exception(e)
|
|
63
|
+
raise
|
|
52
64
|
|
|
53
65
|
def get_agent(self, name: str) -> FlockAgent | None:
|
|
54
|
-
""
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
66
|
+
with tracer.start_as_current_span("Registry.get_agent") as span:
|
|
67
|
+
span.set_attribute("search_agent_name", name)
|
|
68
|
+
try:
|
|
69
|
+
for agent in self._agents:
|
|
70
|
+
if agent.name == name:
|
|
71
|
+
logger.info("Agent found", agent=name)
|
|
72
|
+
span.set_attribute("found", True)
|
|
73
|
+
return agent
|
|
74
|
+
logger.warning("Agent not found", agent=name)
|
|
75
|
+
span.set_attribute("found", False)
|
|
76
|
+
return None
|
|
77
|
+
except Exception as e:
|
|
78
|
+
logger.error("Error retrieving agent", agent=name, error=str(e))
|
|
79
|
+
span.record_exception(e)
|
|
80
|
+
raise
|
|
69
81
|
|
|
70
82
|
def get_tool(self, name: str) -> Callable | None:
|
|
71
|
-
""
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
83
|
+
with tracer.start_as_current_span("Registry.get_tool") as span:
|
|
84
|
+
span.set_attribute("search_tool_name", name)
|
|
85
|
+
try:
|
|
86
|
+
for tool_name, tool in self._tools:
|
|
87
|
+
if tool_name == name:
|
|
88
|
+
logger.info("Tool found", tool=name)
|
|
89
|
+
span.set_attribute("found", True)
|
|
90
|
+
return tool
|
|
91
|
+
logger.warning("Tool not found", tool=name)
|
|
92
|
+
span.set_attribute("found", False)
|
|
93
|
+
return None
|
|
94
|
+
except Exception as e:
|
|
95
|
+
logger.error("Error retrieving tool", tool=name, error=str(e))
|
|
96
|
+
span.record_exception(e)
|
|
97
|
+
raise
|
|
86
98
|
|
|
87
99
|
def get_tools(self, names: list[str] | None) -> list[Callable]:
|
|
88
|
-
""
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
with tracer.start_as_current_span("Registry.get_tools") as span:
|
|
101
|
+
span.set_attribute("search_tool_names", str(names))
|
|
102
|
+
try:
|
|
103
|
+
if not names:
|
|
104
|
+
logger.info("No tool names provided")
|
|
105
|
+
return []
|
|
106
|
+
tools = [self.get_tool(name) for name in names]
|
|
107
|
+
found_tools = [tool for tool in tools if tool is not None]
|
|
108
|
+
logger.info(
|
|
109
|
+
"Tools retrieved", requested=names, found=len(found_tools)
|
|
110
|
+
)
|
|
111
|
+
span.set_attribute("found_tools_count", len(found_tools))
|
|
112
|
+
return found_tools
|
|
113
|
+
except Exception as e:
|
|
114
|
+
logger.error(
|
|
115
|
+
"Error retrieving tools", names=str(names), error=str(e)
|
|
116
|
+
)
|
|
117
|
+
span.record_exception(e)
|
|
118
|
+
raise
|
flock/core/tools/basic_tools.py
CHANGED
|
@@ -3,7 +3,10 @@
|
|
|
3
3
|
import importlib
|
|
4
4
|
import os
|
|
5
5
|
|
|
6
|
+
from flock.core.logging.trace_and_logged import traced_and_logged
|
|
6
7
|
|
|
8
|
+
|
|
9
|
+
@traced_and_logged
|
|
7
10
|
def web_search_tavily(query: str):
|
|
8
11
|
"""Performs a web search using the Tavily client.
|
|
9
12
|
|
|
@@ -32,9 +35,12 @@ def web_search_tavily(query: str):
|
|
|
32
35
|
except Exception:
|
|
33
36
|
raise
|
|
34
37
|
else:
|
|
35
|
-
raise ImportError(
|
|
38
|
+
raise ImportError(
|
|
39
|
+
"Optional tool dependencies not installed. Install with 'pip install flock-core[tools]'."
|
|
40
|
+
)
|
|
36
41
|
|
|
37
42
|
|
|
43
|
+
@traced_and_logged
|
|
38
44
|
def get_web_content_as_markdown(url: str):
|
|
39
45
|
"""Fetches web content from a URL and converts it to Markdown.
|
|
40
46
|
|
|
@@ -51,7 +57,10 @@ def get_web_content_as_markdown(url: str):
|
|
|
51
57
|
ImportError: If either 'httpx' or 'markdownify' dependencies are not installed.
|
|
52
58
|
Exception: Re-raises any exceptions encountered during the HTTP request or conversion.
|
|
53
59
|
"""
|
|
54
|
-
if
|
|
60
|
+
if (
|
|
61
|
+
importlib.util.find_spec("httpx") is not None
|
|
62
|
+
and importlib.util.find_spec("markdownify") is not None
|
|
63
|
+
):
|
|
55
64
|
import httpx
|
|
56
65
|
from markdownify import markdownify as md
|
|
57
66
|
|
|
@@ -63,9 +72,12 @@ def get_web_content_as_markdown(url: str):
|
|
|
63
72
|
except Exception:
|
|
64
73
|
raise
|
|
65
74
|
else:
|
|
66
|
-
raise ImportError(
|
|
75
|
+
raise ImportError(
|
|
76
|
+
"Optional tool dependencies not installed. Install with 'pip install flock-core[tools]'."
|
|
77
|
+
)
|
|
67
78
|
|
|
68
79
|
|
|
80
|
+
@traced_and_logged
|
|
69
81
|
def get_anything_as_markdown(url_or_file_path: str):
|
|
70
82
|
"""Converts the content of a URL or file into Markdown format.
|
|
71
83
|
|
|
@@ -94,9 +106,12 @@ def get_anything_as_markdown(url_or_file_path: str):
|
|
|
94
106
|
except Exception:
|
|
95
107
|
raise
|
|
96
108
|
else:
|
|
97
|
-
raise ImportError(
|
|
109
|
+
raise ImportError(
|
|
110
|
+
"Optional tool dependencies not installed. Install with 'pip install flock-core[all-tools]'."
|
|
111
|
+
)
|
|
98
112
|
|
|
99
113
|
|
|
114
|
+
@traced_and_logged
|
|
100
115
|
def evaluate_math(expression: str) -> float:
|
|
101
116
|
"""Evaluates a mathematical expression using the dspy interpreter.
|
|
102
117
|
|
|
@@ -121,6 +136,7 @@ def evaluate_math(expression: str) -> float:
|
|
|
121
136
|
raise
|
|
122
137
|
|
|
123
138
|
|
|
139
|
+
@traced_and_logged
|
|
124
140
|
def code_eval(python_code: str) -> float:
|
|
125
141
|
"""Executes Python code using the dspy interpreter.
|
|
126
142
|
|
|
@@ -145,6 +161,7 @@ def code_eval(python_code: str) -> float:
|
|
|
145
161
|
raise
|
|
146
162
|
|
|
147
163
|
|
|
164
|
+
@traced_and_logged
|
|
148
165
|
def get_current_time() -> str:
|
|
149
166
|
"""Retrieves the current time in ISO 8601 format.
|
|
150
167
|
|
|
@@ -157,6 +174,7 @@ def get_current_time() -> str:
|
|
|
157
174
|
return time
|
|
158
175
|
|
|
159
176
|
|
|
177
|
+
@traced_and_logged
|
|
160
178
|
def count_words(text: str) -> int:
|
|
161
179
|
"""Counts the number of words in the provided text.
|
|
162
180
|
|
|
@@ -172,6 +190,7 @@ def count_words(text: str) -> int:
|
|
|
172
190
|
return count
|
|
173
191
|
|
|
174
192
|
|
|
193
|
+
@traced_and_logged
|
|
175
194
|
def extract_urls(text: str) -> list[str]:
|
|
176
195
|
"""Extracts all URLs from the given text.
|
|
177
196
|
|
|
@@ -191,6 +210,7 @@ def extract_urls(text: str) -> list[str]:
|
|
|
191
210
|
return urls
|
|
192
211
|
|
|
193
212
|
|
|
213
|
+
@traced_and_logged
|
|
194
214
|
def extract_numbers(text: str) -> list[float]:
|
|
195
215
|
"""Extracts all numerical values from the provided text.
|
|
196
216
|
|
|
@@ -209,6 +229,7 @@ def extract_numbers(text: str) -> list[float]:
|
|
|
209
229
|
return numbers
|
|
210
230
|
|
|
211
231
|
|
|
232
|
+
@traced_and_logged
|
|
212
233
|
def json_parse_safe(text: str) -> dict:
|
|
213
234
|
"""Safely parses a JSON string into a dictionary.
|
|
214
235
|
|
|
@@ -230,6 +251,7 @@ def json_parse_safe(text: str) -> dict:
|
|
|
230
251
|
return {}
|
|
231
252
|
|
|
232
253
|
|
|
254
|
+
@traced_and_logged
|
|
233
255
|
def save_to_file(content: str, filename: str):
|
|
234
256
|
"""Saves the given content to a file.
|
|
235
257
|
|
|
@@ -250,6 +272,7 @@ def save_to_file(content: str, filename: str):
|
|
|
250
272
|
raise
|
|
251
273
|
|
|
252
274
|
|
|
275
|
+
@traced_and_logged
|
|
253
276
|
def read_from_file(filename: str) -> str:
|
|
254
277
|
"""Reads and returns the content of a file.
|
|
255
278
|
|
|
@@ -5,7 +5,10 @@ import os
|
|
|
5
5
|
|
|
6
6
|
import httpx
|
|
7
7
|
|
|
8
|
+
from flock.core.logging.trace_and_logged import traced_and_logged
|
|
8
9
|
|
|
10
|
+
|
|
11
|
+
@traced_and_logged
|
|
9
12
|
def create_user_stories_as_github_issue(title: str, body: str) -> str:
|
|
10
13
|
"""Create a new GitHub issue representing a user story.
|
|
11
14
|
|
|
@@ -44,6 +47,7 @@ def create_user_stories_as_github_issue(title: str, body: str) -> str:
|
|
|
44
47
|
return "Failed to create issue. Please try again later."
|
|
45
48
|
|
|
46
49
|
|
|
50
|
+
@traced_and_logged
|
|
47
51
|
def upload_readme(content: str):
|
|
48
52
|
"""Upload or update the README.md file in a GitHub repository.
|
|
49
53
|
|
|
@@ -66,7 +70,9 @@ def upload_readme(content: str):
|
|
|
66
70
|
GITHUB_TOKEN = os.getenv("GITHUB_PAT")
|
|
67
71
|
|
|
68
72
|
if not GITHUB_USERNAME or not REPO_NAME or not GITHUB_TOKEN:
|
|
69
|
-
raise ValueError(
|
|
73
|
+
raise ValueError(
|
|
74
|
+
"Missing environment variables: GITHUB_USERNAME, GITHUB_REPO, or GITHUB_PAT"
|
|
75
|
+
)
|
|
70
76
|
|
|
71
77
|
GITHUB_API_URL = f"https://api.github.com/repos/{GITHUB_USERNAME}/{REPO_NAME}/contents/README.md"
|
|
72
78
|
|
|
@@ -75,13 +81,20 @@ def upload_readme(content: str):
|
|
|
75
81
|
with httpx.Client() as client:
|
|
76
82
|
response = client.get(
|
|
77
83
|
GITHUB_API_URL,
|
|
78
|
-
headers={
|
|
84
|
+
headers={
|
|
85
|
+
"Authorization": f"Bearer {GITHUB_TOKEN}",
|
|
86
|
+
"Accept": "application/vnd.github.v3+json",
|
|
87
|
+
},
|
|
79
88
|
)
|
|
80
89
|
|
|
81
90
|
data = response.json()
|
|
82
91
|
sha = data.get("sha", None)
|
|
83
92
|
|
|
84
|
-
payload = {
|
|
93
|
+
payload = {
|
|
94
|
+
"message": "Updating README.md",
|
|
95
|
+
"content": encoded_content,
|
|
96
|
+
"branch": "main",
|
|
97
|
+
}
|
|
85
98
|
|
|
86
99
|
if sha:
|
|
87
100
|
payload["sha"] = sha
|
|
@@ -89,7 +102,10 @@ def upload_readme(content: str):
|
|
|
89
102
|
response = client.put(
|
|
90
103
|
GITHUB_API_URL,
|
|
91
104
|
json=payload,
|
|
92
|
-
headers={
|
|
105
|
+
headers={
|
|
106
|
+
"Authorization": f"Bearer {GITHUB_TOKEN}",
|
|
107
|
+
"Accept": "application/vnd.github.v3+json",
|
|
108
|
+
},
|
|
93
109
|
)
|
|
94
110
|
|
|
95
111
|
if response.status_code in [200, 201]:
|
|
@@ -98,6 +114,7 @@ def upload_readme(content: str):
|
|
|
98
114
|
print("Failed to upload README.md:", response.json())
|
|
99
115
|
|
|
100
116
|
|
|
117
|
+
@traced_and_logged
|
|
101
118
|
def create_files(file_paths) -> str:
|
|
102
119
|
"""Create multiple files in a GitHub repository with a predefined content.
|
|
103
120
|
|
|
@@ -122,7 +139,9 @@ def create_files(file_paths) -> str:
|
|
|
122
139
|
GITHUB_TOKEN = os.getenv("GITHUB_PAT")
|
|
123
140
|
|
|
124
141
|
if not GITHUB_USERNAME or not REPO_NAME or not GITHUB_TOKEN:
|
|
125
|
-
raise ValueError(
|
|
142
|
+
raise ValueError(
|
|
143
|
+
"Missing environment variables: GITHUB_USERNAME, GITHUB_REPO, or GITHUB_PAT"
|
|
144
|
+
)
|
|
126
145
|
|
|
127
146
|
encoded_content = base64.b64encode(b"#created by flock").decode()
|
|
128
147
|
|
|
@@ -132,13 +151,20 @@ def create_files(file_paths) -> str:
|
|
|
132
151
|
|
|
133
152
|
response = client.get(
|
|
134
153
|
GITHUB_API_URL,
|
|
135
|
-
headers={
|
|
154
|
+
headers={
|
|
155
|
+
"Authorization": f"token {GITHUB_TOKEN}",
|
|
156
|
+
"Accept": "application/vnd.github.v3+json",
|
|
157
|
+
},
|
|
136
158
|
)
|
|
137
159
|
|
|
138
160
|
data = response.json()
|
|
139
161
|
sha = data.get("sha", None)
|
|
140
162
|
|
|
141
|
-
payload = {
|
|
163
|
+
payload = {
|
|
164
|
+
"message": f"Creating {file_path}",
|
|
165
|
+
"content": encoded_content,
|
|
166
|
+
"branch": "main",
|
|
167
|
+
}
|
|
142
168
|
|
|
143
169
|
if sha:
|
|
144
170
|
print(f"Skipping {file_path}, file already exists.")
|
|
@@ -147,7 +173,10 @@ def create_files(file_paths) -> str:
|
|
|
147
173
|
response = client.put(
|
|
148
174
|
GITHUB_API_URL,
|
|
149
175
|
json=payload,
|
|
150
|
-
headers={
|
|
176
|
+
headers={
|
|
177
|
+
"Authorization": f"token {GITHUB_TOKEN}",
|
|
178
|
+
"Accept": "application/vnd.github.v3+json",
|
|
179
|
+
},
|
|
151
180
|
)
|
|
152
181
|
|
|
153
182
|
if response.status_code in [200, 201]:
|
flock/core/util/cli_helper.py
CHANGED
|
@@ -8,9 +8,13 @@ def display_banner():
|
|
|
8
8
|
"""Display the Flock banner."""
|
|
9
9
|
banner_text = Text(
|
|
10
10
|
"""
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
🦆 🐓 🐤 🦆
|
|
12
|
+
╭━━━━━━━━━━━━━━━━━━━━━━━━╮
|
|
13
|
+
🐓 │ ▒█▀▀▀ █░░ █▀▀█ █▀▀ █░█ │ 🐧
|
|
14
|
+
│ ▒█▀▀▀ █░░ █░░█ █░░ █▀▄ │
|
|
15
|
+
🐧 │ ▒█░░░ ▀▀▀ ▀▀▀▀ ▀▀▀ ▀░▀ │ 🐓
|
|
16
|
+
╰━━━━━━━━━━━━━━━━━━━━━━━━╯
|
|
17
|
+
🦆 🐤 🐧 🐓
|
|
14
18
|
""",
|
|
15
19
|
justify="center",
|
|
16
20
|
style="bold orange3",
|