mirror of
https://github.com/NCBM/plyngent.git
synced 2026-07-23 05:55:16 +08:00
core/agent: agent-facing [TODO OPEN] review nag
This commit is contained in:
@@ -174,15 +174,19 @@ class TodoStack:
|
|||||||
return "\n".join(lines)
|
return "\n".join(lines)
|
||||||
|
|
||||||
def review_prompt(self) -> str:
|
def review_prompt(self) -> str:
|
||||||
return (
|
"""Compact, model-facing nag: open work still exists this turn."""
|
||||||
"Todo stack review (internal control — not a human message).\n"
|
open_items = self.open_items()
|
||||||
"This is a LIFO stack of **task groups** (not a queue of single tasks).\n"
|
n_open = len(open_items)
|
||||||
"push([T1,T2]) creates one group of siblings; push([T1.1,T1.2]) pushes a "
|
n_groups = self.depth
|
||||||
"child group; pop removes the whole top group. Update items by id; "
|
lines = [
|
||||||
"pop when a breakdown level is finished. Open work remains and you "
|
f"[TODO OPEN] {n_open} open item(s) across {n_groups} group(s) "
|
||||||
"did not call any todo_* tools this turn.\n\n"
|
f"(not empty). You did not call todo_* this turn.",
|
||||||
f"Current stack:\n{self.render()}"
|
"Tools: todo_list | todo_push(titles=[...]) | todo_update | todo_pop | todo_clear",
|
||||||
)
|
"Rules: TOP group = current level; push=one sibling group; pop=remove whole TOP group.",
|
||||||
|
"Act on open work before ending (finish/pop TOP, or push child tasks). Stack:",
|
||||||
|
self.render(),
|
||||||
|
]
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
def _existing_numeric_ids(self) -> list[int]:
|
def _existing_numeric_ids(self) -> list[int]:
|
||||||
"""Numeric suffixes of ids that look like ``tN`` (for counter reuse)."""
|
"""Numeric suffixes of ids that look like ``tN`` (for counter reuse)."""
|
||||||
|
|||||||
@@ -152,11 +152,11 @@ async def test_todo_tools_and_persist(tmp_path: object) -> None:
|
|||||||
stack = TodoStack()
|
stack = TodoStack()
|
||||||
set_todo_stack(stack, on_change=None)
|
set_todo_stack(stack, on_change=None)
|
||||||
registry = ToolRegistry(list(TODO_TOOLS))
|
registry = ToolRegistry(list(TODO_TOOLS))
|
||||||
out = await registry.execute("todo_push", '{"titles": "T1\\nT2"}')
|
out = await registry.execute("todo_push", '{"titles": ["T1", "T2"]}')
|
||||||
assert "group" in out.lower() or "pushed" in out
|
assert "group" in out.lower() or "pushed" in out
|
||||||
assert stack.depth == 1
|
assert stack.depth == 1
|
||||||
assert [i.title for i in stack.groups[0].items] == ["T1", "T2"]
|
assert [i.title for i in stack.groups[0].items] == ["T1", "T2"]
|
||||||
_ = await registry.execute("todo_push", '{"titles": "T1.1; T1.2"}')
|
out = await registry.execute("todo_push", '{"titles": ["T1", "T2"]}')
|
||||||
assert stack.depth == 2
|
assert stack.depth == 2
|
||||||
out3 = await registry.execute("todo_pop", "{}")
|
out3 = await registry.execute("todo_pop", "{}")
|
||||||
assert "popped" in out3
|
assert "popped" in out3
|
||||||
@@ -193,7 +193,7 @@ class ScriptedClient:
|
|||||||
self.calls += 1
|
self.calls += 1
|
||||||
text = "ok" if self.calls > 1 else "done without todos"
|
text = "ok" if self.calls > 1 else "done without todos"
|
||||||
for msg in param.messages:
|
for msg in param.messages:
|
||||||
if isinstance(msg, DeveloperChatMessage) and "Todo stack review" in msg.content:
|
if isinstance(msg, DeveloperChatMessage) and "[TODO OPEN]" in msg.content:
|
||||||
text = "reviewed stack"
|
text = "reviewed stack"
|
||||||
break
|
break
|
||||||
return ChatCompletionResponse(
|
return ChatCompletionResponse(
|
||||||
@@ -232,7 +232,7 @@ async def test_loop_injects_todo_review_when_untouched() -> None:
|
|||||||
async for _event in agent.run("do stuff"):
|
async for _event in agent.run("do stuff"):
|
||||||
pass
|
pass
|
||||||
assert client.calls >= 2
|
assert client.calls >= 2
|
||||||
assert any(isinstance(m, DeveloperChatMessage) and "Todo stack review" in m.content for m in agent.messages)
|
assert any(isinstance(m, DeveloperChatMessage) and "[TODO OPEN]" in m.content for m in agent.messages)
|
||||||
assert not any(isinstance(m, UserChatMessage) and "Todo stack review" in m.content for m in agent.messages)
|
assert not any(isinstance(m, UserChatMessage) and "[TODO OPEN]" in m.content for m in agent.messages)
|
||||||
finally:
|
finally:
|
||||||
set_todo_stack(None)
|
set_todo_stack(None)
|
||||||
|
|||||||
Reference in New Issue
Block a user