Scheduler polishing 1
frdel committed
May 3, 2025 at 08:35 UTC
b7127616504eeeb3fc8ebeec945b67f104a6834c
14 files changed
+72
-77
agent.py
+6
-10
@@ -163,10 +163,10 @@ class AgentContext:
163
tool_name="call_subordinate", tool_result=msg # type: ignore
164
)
165
)
166
- response = await agent.monologue()
166
+ response = await agent.monologue() # type: ignore
167
superior = agent.data.get(Agent.DATA_NAME_SUPERIOR, None)
168
if superior:
169
- response = await self._process_chain(superior, response, False)
169
+ response = await self._process_chain(superior, response, False) # type: ignore
170
return response
171
except Exception as e:
172
agent.handle_critical_exception(e)
@@ -313,7 +313,7 @@ class Agent:
313
314
agent_response = await self.call_chat_model(
315
prompt, callback=stream_callback
316
- )
316
+ ) # type: ignore
317
318
await self.handle_intervention(agent_response)
319
@@ -499,13 +499,9 @@ class Agent:
499
system_message=message.system_message
500
)
501
502
- # remove empty attachments from template
503
- if (
504
- isinstance(content, dict)
505
- and "attachments" in content
506
- and not content["attachments"]
507
- ):
508
- del content["attachments"]
502
+ # remove empty parts from template
503
+ if isinstance(content, dict):
504
+ content = {k: v for k, v in content.items() if v}
505
506
# add to history
507
msg = self.hist_add_message(False, content=content) # type: ignore
docker/run/Dockerfile
-3
@@ -43,8 +43,5 @@ EXPOSE 22 80
43
44
RUN chmod +x /exe/initialize.sh /exe/run_A0.sh /exe/run_searxng.sh
45
46
-# This is important or cron will not execute the file
47
-RUN chmod 0644 /etc/cron.d/scheduler_tick
48
-
46
# initialize runtime and switch to supervisord
47
CMD ["/exe/initialize.sh", "$BRANCH"]
docker/run/DockerfileKali
-3
@@ -44,8 +44,5 @@ EXPOSE 22 80
44
45
RUN chmod +x /exe/initialize.sh /exe/run_A0.sh /exe/run_searxng.sh
46
47
-# This is important or cron will not execute the file
48
-RUN chmod 0644 /etc/cron.d/scheduler_tick
49
-
47
# initialize runtime and switch to supervisord
48
CMD ["/exe/initialize.sh", "$BRANCH"]
docker/run/fs/etc/cron.d/scheduler_tick
deleted
-5
@@ -1,5 +0,0 @@
1
-# TaskScheduler CronJob
2
-
3
-* * * * * root curl http://127.0.0.1:80/scheduler_tick
4
-
5
-# END
docker/run/fs/ins/pre_install.sh
+3
@@ -1,5 +1,8 @@
1
#!/bin/bash
2
3
+# fix permissions for cron files
4
+chmod 0644 /etc/cron.d/*
5
+
6
# Update and install necessary packages
7
apt-get update && apt-get install -y \
8
python3 \
python/api/poll.py
+1
-1
@@ -32,7 +32,7 @@ class Poll(ApiHandler):
32
scheduler = TaskScheduler.get()
33
34
# Always reload the scheduler on each poll to ensure we have the latest task state
35
- await scheduler.reload()
35
+ # await scheduler.reload() # TODO:SCHEDULER must optimize this
36
37
# loop AgentContext._contexts and divide into contexts and tasks
38
python/extensions/message_loop_prompts/_60_include_current_datetime.py
+8
-7
@@ -7,16 +7,17 @@ from python.helpers.localization import Localization
7
class IncludeCurrentDatetime(Extension):
8
async def execute(self, loop_data: LoopData = LoopData(), **kwargs):
9
# get current datetime
10
- current_datetime = Localization.get().utc_dt_to_localtime_str(datetime.now(timezone.utc), sep=" ", timespec="seconds")
10
+ current_datetime = Localization.get().utc_dt_to_localtime_str(
11
+ datetime.now(timezone.utc), sep=" ", timespec="seconds"
12
+ )
13
# remove timezone offset
12
- current_datetime = current_datetime.split("+")[0]
13
-
14
- # remove old current datetime from loop data
15
- if "current_datetime" in loop_data.extras_temporary:
16
- del loop_data.extras_temporary["current_datetime"]
14
+ if current_datetime and "+" in current_datetime:
15
+ current_datetime = current_datetime.split("+")[0]
16
17
# read prompt
19
- datetime_prompt = self.agent.read_prompt("agent.system.datetime.md", date_time=current_datetime)
18
+ datetime_prompt = self.agent.read_prompt(
19
+ "agent.system.datetime.md", date_time=current_datetime
20
+ )
21
22
# add current datetime to the loop data
23
loop_data.extras_temporary["current_datetime"] = datetime_prompt
python/extensions/system_prompt/_10_system_prompt.py
+4
-19
@@ -15,26 +15,11 @@ class SystemPrompt(Extension):
15
16
17
def get_main_prompt(agent: Agent):
18
- return get_prompt("agent.system.main.md", agent)
18
+ return agent.read_prompt("agent.system.main.md")
19
20
21
def get_tools_prompt(agent: Agent):
22
- prompt = get_prompt("agent.system.tools.md", agent)
22
+ prompt = agent.read_prompt("agent.system.tools.md")
23
if agent.config.chat_model.vision:
24
- prompt += '\n' + get_prompt("agent.system.tools_vision.md", agent)
25
- return prompt
26
-
27
-
28
-def get_prompt(file: str, agent: Agent):
29
- # variables for system prompts
30
- # TODO: move variables to the end of chain
31
- # variables in system prompt would break prompt caching, better to add them to the last message in conversation
32
- # get current datetime
33
- current_datetime = Localization.get().utc_dt_to_localtime_str(datetime.now(timezone.utc), sep=" ", timespec="seconds")
34
- # remove timezone offset
35
- current_datetime = current_datetime.split("+")[0]
36
- vars = {
37
- "date_time": current_datetime,
38
- "agent_name": agent.agent_name,
39
- }
40
- return agent.read_prompt(file, **vars)
24
+ prompt += '\n' + agent.read_prompt("agent.system.tools_vision.md")
25
+ return prompt
\ No newline at end of file
python/helpers/job_loop.py
new
+20
@@ -0,0 +1,20 @@
1
+import asyncio
2
+from python.helpers.task_scheduler import TaskScheduler
3
+from python.helpers.print_style import PrintStyle
4
+from python.helpers import errors
5
+
6
+
7
+async def run_loop():
8
+ while True:
9
+ try:
10
+ await scheduler_tick()
11
+ except Exception as e:
12
+ PrintStyle().error(errors.format_error(e))
13
+ await asyncio.sleep(60)
14
+
15
+
16
+async def scheduler_tick():
17
+ # Get the task scheduler instance and print detailed debug info
18
+ scheduler = TaskScheduler.get()
19
+ # Run the scheduler tick
20
+ await scheduler.tick()
\ No newline at end of file
python/tools/input.py
+1
-1
@@ -12,7 +12,7 @@ class Input(Tool):
12
13
# forward keyboard input to code execution tool
14
args = {"runtime": "terminal", "code": keyboard}
15
- cot = CodeExecution(self.agent, "code_execution_tool", args, self.message)
15
+ cot = CodeExecution(self.agent, "code_execution_tool", "", args, self.message)
16
cot.log = self.log
17
return await cot.execute(**args)
18
run_ui.py
+21
-4
@@ -15,11 +15,13 @@ from python.helpers import persist_chat, runtime, dotenv, process
15
from python.helpers.cloudflare_tunnel import CloudflareTunnel
16
from python.helpers.extract_tools import load_classes_from_folder
17
from python.helpers.api import ApiHandler
18
+from python.helpers.job_loop import run_loop
19
from python.helpers.print_style import PrintStyle
20
from python.helpers.task_scheduler import TaskScheduler
21
+from python.helpers.defer import DeferredTask
22
23
# Set the new timezone to 'UTC'
22
-os.environ['TZ'] = 'UTC'
24
+os.environ["TZ"] = "UTC"
25
# Apply the timezone change
26
time.tzset()
27
@@ -35,8 +37,10 @@ basic_auth = BasicAuth(app)
37
38
def is_loopback_address(address):
39
loopback_checker = {
38
- socket.AF_INET: lambda x: struct.unpack('!I', socket.inet_aton(x))[0] >> (32 - 8) == 127,
39
- socket.AF_INET6: lambda x: x == '::1'
40
+ socket.AF_INET: lambda x: struct.unpack("!I", socket.inet_aton(x))[0]
41
+ >> (32 - 8)
42
+ == 127,
43
+ socket.AF_INET6: lambda x: x == "::1",
44
}
45
address_type = "hostname"
46
try:
@@ -79,6 +83,7 @@ def requires_api_key(f):
83
else:
84
return Response("API key required", 401)
85
return await f(*args, **kwargs)
86
+
87
return decorated
88
89
@@ -93,6 +98,7 @@ def requires_loopback(f):
98
{},
99
)
100
return await f(*args, **kwargs)
101
+
102
return decorated
103
104
@@ -142,6 +148,10 @@ def run():
148
from werkzeug.serving import WSGIRequestHandler
149
from werkzeug.serving import make_server
150
151
+ PrintStyle().print("Starting job loop...")
152
+ job_loop = DeferredTask().start_task(run_loop)
153
+
154
+ PrintStyle().print("Starting server...")
155
class NoRequestLoggingWSGIRequestHandler(WSGIRequestHandler):
156
def log_request(self, code="-", size="-"):
157
pass # Override to suppress request logging
@@ -188,17 +198,23 @@ def run():
198
instance = handler(app, lock)
199
200
if handler.requires_loopback():
201
+
202
@requires_loopback
203
async def handle_request():
204
return await instance.handle_request(request=request)
205
+
206
elif handler.requires_auth():
207
+
208
@requires_auth
209
async def handle_request():
210
return await instance.handle_request(request=request)
211
+
212
elif handler.requires_api_key():
213
+
214
@requires_api_key
215
async def handle_request():
216
return await instance.handle_request(request=request)
217
+
218
else:
219
# Fallback to requires_auth
220
@requires_auth
@@ -232,7 +248,8 @@ def run():
248
nonlocal tunnel, server, printer
249
with lock:
250
printer.print("Caught signal, stopping server...")
235
- server.shutdown()
251
+ if server:
252
+ server.shutdown()
253
process.stop_server()
254
if tunnel:
255
tunnel.stop()
test_scheduler.py
deleted
-16
@@ -1,16 +0,0 @@
1
-from python.helpers.task_scheduler import ScheduledTask, TaskSchedule, SchedulerTaskList, TaskState
2
-import asyncio
3
-
4
-slist = SchedulerTaskList.get()
5
-
6
-print(slist.model_dump_json(indent=4))
7
-
8
-for task in slist.tasks:
9
- t = slist.get_task_by_uuid(task.uuid)
10
- t.update(state=TaskState.DISABLED)
11
- print("-" * 100)
12
- print(t.model_dump_json(indent=4))
13
-
14
-print("-" * 100)
15
-
16
-print(slist.model_dump_json(indent=4))
webui/css/settings.css
+5
-5
@@ -329,21 +329,21 @@ nav ul li a img {
329
330
.settings-tab.active {
331
border-color: var(--color-border);
332
- box-shadow:
332
+ /* box-shadow:
333
0 -4px 8px -2px var(--color-border),
334
4px 0 8px -2px var(--color-border),
335
- -4px 0 8px -2px var(--color-border);
335
+ -4px 0 8px -2px var(--color-border); */
336
font-weight: bold;
337
background-color: var(--color-panel);
338
}
339
340
/* Light mode overrides */
341
.light-mode .settings-tab.active {
342
- color: var(--color-border);
343
- box-shadow:
342
+ /* color: var(--color-border); */
343
+ /* box-shadow:
344
0 -4px 8px -2px var(--color-border),
345
4px 0 8px -2px var(--color-border),
346
- -4px 0 8px -2px var(--color-border);
346
+ -4px 0 8px -2px var(--color-border); */
347
}
348
349
.light-mode .settings-tab:not(.active) {
webui/index.css
+3
-3
@@ -2259,7 +2259,7 @@ a:active {
2259
2260
.light-mode .tab.active::after {
2261
background-color: var(--highlight-pink);
2262
- box-shadow: 0 0 8px var(--highlight-pink);
2262
+ /* box-shadow: 0 0 8px var(--highlight-pink); */
2263
}
2264
/* Tabs styling */
2265
.tabs-container {
@@ -2300,10 +2300,10 @@ a:active {
2300
2301
.tab.active {
2302
border-color: var(--color-border);
2303
- box-shadow:
2303
+ /* box-shadow:
2304
0 -4px 8px -2px var(--color-border),
2305
4px 0 8px -2px var(--color-border),
2306
- -4px 0 8px -2px var(--color-border);
2306
+ -4px 0 8px -2px var(--color-border); */
2307
font-weight: bold;
2308
background-color: var(--color-panel);
2309
}