M2.8: switch over to the new loop
nisse-dev now runs only the conversational loop. The gated state machine it was built alongside is gone: - Removed control.py, planner.py, executor.py, approvals.py, gates.py (command_form moves to loop/reader.py), publish.py and poller.py, the old assembly in agent.py (its shared helpers move to loop/build.py), the store's state-machine view (get_state, transition), their tests, the old end-to-end and live planning/milestone/gate tests, and specs/orchestrator.qnt with its scenarios. - Roles are driver, helper, expert and classifier; driver is required. loop:, roles.planner, roles.executor and tuning.executor are refused with what to use instead; tuning.driver takes the turn cap and failure limit. - The benchmark and the capability matrix measure the driver: the loop's own system prompt and tools, the task's plan as the agreed restatement. Task plans end with finish_milestone, so earlier runs show as (old); stored runs' executor tuning reads as the driver's. - A delegation on the loop records what its helper's alias resolved to (L9), as the old path's did. - The dump shows a work item's revision and what it waits for. - Behaviour the old tests covered and the loop shares stays covered: driver runs that fail on a model call, stop mid-turn, reset the failure count; go-aheads ignoring case and punctuation; a request too big to fit is never sent; the assembly tests, now on build_loop_agent. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PPQ14L3LikyefCMFBqEbKE
This commit is contained in:
1 parent
09232dcbdd
commit
6ae2375194
89 files changed
+951
-8592
No files matched your search
@@ -37,7 +37,6 @@ from nisse_dev.canonical import (
|
||||
from nisse_dev.config import GENERAL
|
||||
from nisse_dev.delegation import DELEGATION_INTENT, Delegation
|
||||
from nisse_dev.expert import BudgetExhausted, ExpertDesk
|
||||
from nisse_dev.gates import command_form
|
||||
from nisse_dev.git import GitError
|
||||
from nisse_dev.gitea import GiteaClient, GiteaError, Issue
|
||||
from nisse_dev.llm import LLMError, RoleMap
|
||||
@@ -61,7 +60,7 @@ from nisse_dev.loop.items import (
|
||||
save,
|
||||
)
|
||||
from nisse_dev.loop.milestones import OPEN_PR, Milestones
|
||||
from nisse_dev.loop.reader import GoAheadReader, is_question
|
||||
from nisse_dev.loop.reader import GoAheadReader, command_form, is_question
|
||||
from nisse_dev.loop.tools import (
|
||||
ASK_HUMAN,
|
||||
CLOSE_ITEM,
|
||||
@@ -75,7 +74,7 @@ from nisse_dev.loop.tools import (
|
||||
)
|
||||
from nisse_dev.oplog import OpLog
|
||||
from nisse_dev.state import StateStore, WorkItem
|
||||
from nisse_dev.tools import EXECUTOR_TOOLS, Workspace
|
||||
from nisse_dev.tools import EXECUTION_TOOLS, Workspace
|
||||
from nisse_dev.transport import InboundMessage, Transport
|
||||
from nisse_dev.worker import Worker
|
||||
|
||||
@@ -113,7 +112,7 @@ _MARKER = re.compile(r"<!-- nisse-item: ([A-Za-z0-9-]+) -->")
|
||||
|
||||
# Before the go-ahead the driver may look around (read, list, run a command
|
||||
# to reproduce a bug) but not change anything (D1); after it, everything.
|
||||
_LOOK = [t for t in EXECUTOR_TOOLS if t["function"]["name"] != "write_file"]
|
||||
_LOOK = [t for t in EXECUTION_TOOLS if t["function"]["name"] != "write_file"]
|
||||
|
||||
SYSTEM = """You are nisse-dev, a software agent working with the operator on
|
||||
the repository {repo}. You are on one work item: issue #{issue}, "{title}".
|
||||
@@ -1411,12 +1410,7 @@ class LoopAgent:
|
||||
default = (
|
||||
self._helpers.roles
|
||||
if self._helpers
|
||||
else RoleMap(
|
||||
executor="",
|
||||
planner=self._roles.get("planner", ""),
|
||||
helper="",
|
||||
expert="",
|
||||
)
|
||||
else RoleMap(driver=self._roles.get("driver", ""), helper="", expert="")
|
||||
)
|
||||
pinned = item.data.get("roles") or self._roles
|
||||
return RoleMap.from_pinned(dict(pinned), default)
|
||||
@@ -1454,6 +1448,9 @@ class LoopAgent:
|
||||
workspace,
|
||||
milestones.git,
|
||||
model=helper,
|
||||
backing_model=(
|
||||
self._helpers.backing(helper) if self._helpers.backing else ""
|
||||
),
|
||||
caps=self._helpers.caps,
|
||||
cancel=self._cancel,
|
||||
reader=self._helpers.reader(roles),
|
||||
@@ -1737,7 +1734,7 @@ class LoopAgent:
|
||||
*([WAIT_FOR_REVIEW] if loop.pr else []),
|
||||
*([DELEGATE, ASK_EXPERT] if self._helpers else []),
|
||||
*([REPLY] if loop.back_to else []),
|
||||
*EXECUTOR_TOOLS,
|
||||
*EXECUTION_TOOLS,
|
||||
]
|
||||
),
|
||||
]
|
||||
@@ -1826,7 +1823,7 @@ class LoopAgent:
|
||||
text = str(args.get("text", "")).strip()
|
||||
rev = loop.rev + 1
|
||||
self._store.transcript(item.id, "driver").append(
|
||||
PlanSubmitted(plan=text, model=self._roles.get("planner", ""))
|
||||
PlanSubmitted(plan=text, model=self._roles.get("driver", ""))
|
||||
)
|
||||
self._fact(item, f"restatement rev-{rev} put up for a go-ahead")
|
||||
self._shown[loop.thread] = rev
|
||||
@@ -1869,7 +1866,7 @@ class LoopAgent:
|
||||
summary = str(args.get("summary", "")).strip()
|
||||
rev = loop.rev + 1
|
||||
self._store.transcript(item.id, "driver").append(
|
||||
PlanSubmitted(plan=summary, model=self._roles.get("planner", ""))
|
||||
PlanSubmitted(plan=summary, model=self._roles.get("driver", ""))
|
||||
)
|
||||
self._fact(item, f"work proposed as rev-{rev}: {project.repo}, {title}")
|
||||
self._shown[loop.thread] = rev
|
||||
@@ -1899,7 +1896,7 @@ class LoopAgent:
|
||||
brief = f"{purpose}\n\nDecisions:\n{decisions}" if decisions else purpose
|
||||
rev = loop.rev + 1
|
||||
self._store.transcript(item.id, "driver").append(
|
||||
PlanSubmitted(plan=brief, model=self._roles.get("planner", ""))
|
||||
PlanSubmitted(plan=brief, model=self._roles.get("driver", ""))
|
||||
)
|
||||
self._fact(item, f"new project proposed as rev-{rev}: {name}")
|
||||
self._shown[loop.thread] = rev
|
||||
|
||||
Reference in new issue
Block a user