Projects as configuration entries (M1.4, D8)
CI / checks (push) Skipped
CI / checks (pull_request) Failing after 5m7s
CI / checks (push) Skipped
CI / checks (pull_request) Failing after 5m7s
- Config: `projects: {name: entry}` with repo, base_branch, workspace,
build_host, push credential, labels (defaults added to every issue),
secrets by ${VAR} reference with visibility (commands | harness), and
egress (recorded, not enforced). Every problem in every entry is
reported at once; an inline secret, a bad visibility, a repeated repo or
a non-slug name is an error.
- The old loop runs exactly one project (only_project) and refuses more.
- The new loop is per project: each its own clone, workspace (with its
commands-visible secrets, redacted on return), push credential and
milestones; intake polls every project's repository; items are scoped
to their project for every run, publish and PR watch. Issues are named
project#14 when there is more than one project, and a bare #14 that
matches two is asked about. Switching projects parks the one worked on
last (all others after a boot).
- A restatement that ends in a question is sent back to the driver, not
posted: the e2e driver kept asking "Is this the right interpretation?",
which a plain yes can't answer.
Tests: config entries and errors, two-project assembly, two-project loop
tests (intake, own workspaces and repos, #14 in both, do-next, label
defaults, parking across projects), the property walk over two projects
with a new own_repository_only property (an item using the first
project's repo fails 15 of 16 seeds), and the restatement check.
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
4ecff19933
commit
064d9bf554
17 files changed
+1139
-315
No files matched your search
@@ -16,7 +16,7 @@ from nisse_dev.agent import (
|
||||
from nisse_dev.cancel import Cancel
|
||||
from nisse_dev.config import AgentConfig
|
||||
from nisse_dev.gitea import GiteaClient
|
||||
from nisse_dev.loop.agent import LoopAgent
|
||||
from nisse_dev.loop.agent import LoopAgent, Project
|
||||
from nisse_dev.loop.driver import Driver
|
||||
from nisse_dev.loop.milestones import Milestones
|
||||
from nisse_dev.loop.reader import GoAheadReader
|
||||
@@ -41,7 +41,8 @@ class RunningLoop:
|
||||
def start(self) -> None:
|
||||
self.loop.start()
|
||||
self.transport.post(
|
||||
f"nisse-dev up as {self.account} (new loop) on {self.config.gitea_repo}; "
|
||||
f"nisse-dev up as {self.account} (new loop) on "
|
||||
f"{', '.join(p.repo for p in self.config.projects)}; "
|
||||
f"{self.loop_status()}"
|
||||
)
|
||||
|
||||
@@ -75,16 +76,37 @@ def build_loop_agent(config: AgentConfig) -> RunningLoop:
|
||||
catalog = discover_models(config, oplog)
|
||||
gitea = GiteaClient(config.gitea_url, config.gitea_token)
|
||||
account = gitea.whoami()
|
||||
host = build_host(config)
|
||||
credential = push_credential(config)
|
||||
remote = remote_url(gitea, config.gitea_repo, credential)
|
||||
git = prepare_workspace(host, config, account, remote, credential)
|
||||
workspace = Workspace(
|
||||
host,
|
||||
config.workspace,
|
||||
timeout_s=config.tuning.tools.command_timeout_s,
|
||||
max_output_chars=config.tuning.tools.max_output_chars,
|
||||
)
|
||||
# D8: each project its own build VM, clone, push credential and milestones.
|
||||
projects = []
|
||||
for entry in config.projects:
|
||||
host = build_host(config, entry)
|
||||
credential = push_credential(config, entry)
|
||||
remote = remote_url(gitea, entry.repo, credential)
|
||||
git = prepare_workspace(host, config, account, remote, credential, entry)
|
||||
projects.append(
|
||||
Project(
|
||||
name=entry.name,
|
||||
repo=entry.repo,
|
||||
labels=entry.labels,
|
||||
workspace=Workspace(
|
||||
host,
|
||||
entry.workspace,
|
||||
timeout_s=config.tuning.tools.command_timeout_s,
|
||||
max_output_chars=config.tuning.tools.max_output_chars,
|
||||
# D7: the secrets its commands may see, redacted on return.
|
||||
secrets=entry.command_secrets(),
|
||||
),
|
||||
milestones=Milestones(
|
||||
store,
|
||||
git,
|
||||
gitea,
|
||||
repo=entry.repo,
|
||||
remote=remote,
|
||||
credential=credential,
|
||||
base=entry.base_branch,
|
||||
),
|
||||
)
|
||||
)
|
||||
normalized, _passthrough = make_llm_clients(config, catalog)
|
||||
cancel = Cancel()
|
||||
# The driver is the planner's model for now (M2.6 brings the driver role).
|
||||
@@ -99,13 +121,11 @@ def build_loop_agent(config: AgentConfig) -> RunningLoop:
|
||||
store,
|
||||
transport,
|
||||
gitea,
|
||||
repo=config.gitea_repo,
|
||||
project=config.project,
|
||||
projects=projects,
|
||||
account=account,
|
||||
operators=config.operators,
|
||||
gitea_operators=config.gitea_operators,
|
||||
driver=driver,
|
||||
workspace=workspace,
|
||||
worker=worker,
|
||||
cancel=cancel,
|
||||
oplog=oplog,
|
||||
@@ -114,15 +134,6 @@ def build_loop_agent(config: AgentConfig) -> RunningLoop:
|
||||
# classifier role arrives (M2.6).
|
||||
reader=GoAheadReader(normalized, config.roles.resolve("planner")),
|
||||
bug_grace_s=config.tuning.loop.bug_grace_s,
|
||||
milestones=Milestones(
|
||||
store,
|
||||
git,
|
||||
gitea,
|
||||
repo=config.gitea_repo,
|
||||
remote=remote,
|
||||
credential=credential,
|
||||
base=config.base_branch,
|
||||
),
|
||||
)
|
||||
return RunningLoop(
|
||||
config=config,
|
||||
|
||||
Reference in new issue
Block a user