Skip to content

Commit ce2a923

Browse files
authored
Merge pull request #91 from ClaydeCode/fix/pebble-prompt-timeout-budget
fix(pebble): surface timeout budget in system prompt
2 parents 71ed2f7 + 65baef3 commit ce2a923

5 files changed

Lines changed: 26 additions & 6 deletions

File tree

src/clayde/webhook/skills.py

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@ def _parse_skill(path: Path) -> Skill:
4444
_SYSTEM_PROMPT_TEMPLATE = """\
4545
You are Clayde, executing a request from the user via a Pebble watch.
4646
47+
You have a hard wall-clock budget of {timeout_s} seconds for this
48+
entire request. If your process exceeds it, it is killed and the user gets
49+
no result. Scope your work to fit: prefer a smaller, complete action over an
50+
ambitious one that risks timing out. If the request is too big to finish in
51+
time, do the most valuable part you can and say so in the JSON summary.
52+
4753
{skill_section}
4854
4955
Skills are suggestions, not constraints. Use as many as the command needs,
@@ -63,8 +69,12 @@ def _parse_skill(path: Path) -> Skill:
6369
"""
6470

6571

66-
def build_system_prompt(skills: list[Skill]) -> str:
67-
"""Build the system prompt sent to the Claude CLI for a Pebble request."""
72+
def build_system_prompt(skills: list[Skill], timeout_s: int = 300) -> str:
73+
"""Build the system prompt sent to the Claude CLI for a Pebble request.
74+
75+
``timeout_s`` is the hard wall-clock budget enforced by the runner; it is
76+
surfaced in the prompt so Claude can scope work to fit.
77+
"""
6878
if not skills:
6979
skill_section = "Available skills: (none currently registered)"
7080
else:
@@ -76,7 +86,9 @@ def build_system_prompt(skills: list[Skill]) -> str:
7686
"Skill file paths:\n\n"
7787
f"{files}"
7888
)
79-
return _SYSTEM_PROMPT_TEMPLATE.format(skill_section=skill_section)
89+
return _SYSTEM_PROMPT_TEMPLATE.format(
90+
skill_section=skill_section, timeout_s=timeout_s,
91+
)
8092

8193

8294
def build_user_prompt(text: str, timestamp: int) -> str:

src/clayde/webhook/worker.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ async def process_job(job: PebbleJob, *, timeout_s: int, kb_path: str) -> None:
5656

5757
skills = discover_skills(SKILLS_ROOT)
5858
span.set_attribute("pebble.skills_available", len(skills))
59-
system_prompt = build_system_prompt(skills)
59+
system_prompt = build_system_prompt(skills, timeout_s=timeout_s)
6060
user_text = build_user_prompt(job.text, job.timestamp)
6161

6262
t0 = time.monotonic()

tests/test_pebble_e2e.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ async def fake_invoke(**kwargs):
4040

4141
monkeypatch.setattr(worker_mod, "invoke_claude_pebble", fake_invoke)
4242
monkeypatch.setattr(worker_mod, "discover_skills", lambda root=None: [])
43-
monkeypatch.setattr(worker_mod, "build_system_prompt", lambda skills: "SYS")
43+
monkeypatch.setattr(worker_mod, "build_system_prompt", lambda skills, timeout_s=300: "SYS")
4444
monkeypatch.setattr(worker_mod, "build_user_prompt", lambda text, ts: text)
4545

4646
# Real queue + real worker_loop.

tests/test_webhook_skills.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,14 @@ def test_build_system_prompt_empty_catalog():
118118
assert "(none currently registered)" in prompt
119119

120120

121+
def test_prompt_mentions_timeout_budget():
122+
p = build_system_prompt([], timeout_s=300)
123+
assert "300 seconds" in p
124+
assert "budget" in p.lower()
125+
# the runner kills on overrun — the agent must be told to scope work
126+
assert "killed" in p.lower()
127+
128+
121129
def test_build_user_prompt():
122130
out = build_user_prompt("hello world", 1778068506)
123131
assert "1778068506" in out

tests/test_webhook_worker.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ async def fake_send(*, title, body, success, **_):
3636
@pytest.fixture
3737
def fake_skills(monkeypatch):
3838
monkeypatch.setattr(worker, "discover_skills", lambda root=None: [])
39-
monkeypatch.setattr(worker, "build_system_prompt", lambda skills: "SYS")
39+
monkeypatch.setattr(worker, "build_system_prompt", lambda skills, timeout_s=300: "SYS")
4040
monkeypatch.setattr(worker, "build_user_prompt", lambda text, ts: f"USER:{text}")
4141

4242

0 commit comments

Comments
 (0)