Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions src/octopal/runtime/temporal_context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
from __future__ import annotations

from collections.abc import Mapping
from datetime import UTC, datetime
from typing import Any

from octopal.utils import utc_now


def build_temporal_context(now: datetime | None = None) -> dict[str, Any]:
utc_dt = now or utc_now()
if utc_dt.tzinfo is None:
utc_dt = utc_dt.replace(tzinfo=UTC)
utc_dt = utc_dt.astimezone(UTC)
local_dt = utc_dt.astimezone()
timezone_name = local_dt.tzname() or local_dt.strftime("%z") or "local"
return {
"current_date": local_dt.date().isoformat(),
"current_time": local_dt.strftime("%H:%M:%S"),
"current_datetime": local_dt.isoformat(),
"current_weekday": local_dt.strftime("%A"),
"local_date": local_dt.date().isoformat(),
"local_time": local_dt.strftime("%H:%M:%S"),
"local_datetime": local_dt.isoformat(),
"local_weekday": local_dt.strftime("%A"),
"local_timezone": timezone_name,
"utc_date": utc_dt.date().isoformat(),
"utc_time": utc_dt.strftime("%H:%M:%S"),
"utc_datetime": utc_dt.isoformat(),
"utc_weekday": utc_dt.strftime("%A"),
}


def format_temporal_context_prompt(context: Mapping[str, Any] | None = None) -> str:
ctx = dict(context or build_temporal_context())
return (
"Temporal context:\n"
f"- Current local date: {ctx['local_date']} ({ctx['local_weekday']})\n"
f"- Current local time: {ctx['local_time']} ({ctx['local_timezone']})\n"
f"- Current local datetime: {ctx['local_datetime']}\n"
f"- Current UTC datetime: {ctx['utc_datetime']}\n"
"- Treat relative dates like today, yesterday, tomorrow, this morning, and this "
"week relative to this context unless the task gives a more specific date."
)

5 changes: 5 additions & 0 deletions src/octopal/runtime/workers/agent_worker.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

from octopal.infrastructure.config.settings import load_settings
from octopal.infrastructure.providers.litellm_provider import LiteLLMProvider
from octopal.runtime.temporal_context import format_temporal_context_prompt
from octopal.runtime.tool_errors import ToolBridgeError
from octopal.runtime.tool_loop import (
_detect_tool_loop,
Expand Down Expand Up @@ -699,8 +700,12 @@ async def mcp_proxy_handler(args: dict, ctx: dict, s_id=s_id, t_name=t_name):
has_child_spawn_tools=has_child_spawn_tools
)

temporal_context_prompt = format_temporal_context_prompt()

system_prompt = f"""{spec.system_prompt}

{temporal_context_prompt}

Available tools:
{tool_descriptions}

Expand Down
2 changes: 2 additions & 0 deletions tests/test_agent_loop_improvements.py
Original file line number Diff line number Diff line change
Expand Up @@ -846,6 +846,8 @@ async def _fake_call_llm(provider, messages, tools):
assert "request_instruction" in tool_names
assert "answer_worker_instruction" not in tool_names
system_prompt = str(messages[0]["content"])
assert "Temporal context:" in system_prompt
assert "Current local date:" in system_prompt
assert "Worker coordination:" in system_prompt
assert "Parent-worker coordination:" not in system_prompt
assert "normal tool calls" in system_prompt
Expand Down
24 changes: 24 additions & 0 deletions tests/test_temporal_context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from __future__ import annotations

from octopal.runtime.temporal_context import format_temporal_context_prompt

_CONTEXT = {
"local_date": "2026-05-15",
"local_time": "09:30:00",
"local_datetime": "2026-05-15T09:30:00+00:00",
"local_weekday": "Friday",
"local_timezone": "UTC",
"utc_date": "2026-05-15",
"utc_time": "09:30:00",
"utc_datetime": "2026-05-15T09:30:00+00:00",
"utc_weekday": "Friday",
}


def test_temporal_context_formats_worker_prompt() -> None:
prompt = format_temporal_context_prompt(_CONTEXT)

assert "Temporal context:" in prompt
assert "Current local date: 2026-05-15" in prompt
assert "Current UTC datetime: 2026-05-15T09:30:00+00:00" in prompt
assert "relative dates" in prompt