Agent configuration implementation plan
Reusable configuration, optional long-term memory, consistent execution semantics.
中文Delivery boundary and fixed choices
This plan implements the linked configuration contract. The current deliverable is documentation and a browser-testable editor prototype; it does not migrate real user data or modify runtime behavior. The first production release covers saved/inline configurations, atomic persistence, shared resolution, optional memory and the editor. Optional automatic selection has its own later stage; it is not a prerequisite for manual per-call model selection.
- AgentSpec remains the only saved registry; AgentConfig is a typed value. Reuse Runtime.exec, MemoryBackend, Context Engine, capability catalogs and existing resource governance.
- New saved/anonymous configurations default to memory off. Legacy profiles preserve effective behavior through explicit migration; no history or memory store is silently moved.
- Model selection occurs at invocation admission. Changing model mid-response or replaying side effects under a fallback model is outside this release.
- Single-base resolution only; no named-Agent inheritance tree. No role is mandatory, no autonomous creation of saved Agents, no new worker or orchestration engine.
Stages, dependencies and public evidence
| Stage / dependency | Owned change | Exit evidence |
|---|---|---|
| P0 · first | Typed AgentConfig projection; schema 2 migration; whole-config revision/CAS; recoverable multi-file lifecycle writes | A01/A02/A11: same-revision clients cannot both win; restart sees old or complete new config; migration semantic diff empty |
| P1 · P0 | One pure resolver and read-only preview; canonical capability semantics; errors and provenance | A03/A07: equivalent inputs resolve identically, selected empty stays empty, explicit denied call fails |
| P2 · P1 | Per-execution memory policy, namespace binding, eligibility lineage and policy-epoch revalidation | A05: reads, writes, delayed extraction, compaction and queued commits obey policy; optional outage visibly degrades |
| P3 · P1 + P2 | Python agent()/llm(), chat, CLI, dispatch and scheduler adapters; immutable execution snapshot and history filtering | A03/A04/A06/A08/A12: public entry parity; concurrent/failing/cancelled calls do not leak config; resumes retain intent |
| P4 · P0 + P1; finish after P2/P3 | Eight-section UI, whole draft, registry model picker, capability selectors and effective preview | A01/A02/A07/A10: real page actions, conflict recovery, unavailable references, responsive and keyboard acceptance |
| P5 · P0–P4 | Portable import/export, duplicate/delete previews, compatibility preflight, product docs and release gate | A09/A11/A12: owned resources only; legacy callable behavior preserved; final reviewed candidate fully verified |
| P6 · optional after P5 | Explicit opt-in Agent/model selection policy over eligible candidates | Routing tests below pass; manual paths unchanged when policy is absent |
Schema and compatibility are implemented before consumers. UI layout work may use fixtures after P1, but a mock does not satisfy P4. Memory controls are not released before every P2 ingress/egress path is covered. Finish and review one bounded stage before treating dependent work as complete.
Source ownership and change locations
| Area | Existing boundary | Planned responsibility |
|---|---|---|
| Persistence | openprogram/agent/management/manager.py; openprogram/agent/management/workspace.py | Keep AgentSpec and storage owner; new colocated configuration.py/resolution.py may separate typed values and pure logic; both filenames are proposed |
| API | apps/server/openprogram_server/_webui/routes/catalog/agents.py | Call one atomic manager operation; typed preview, revision and readiness responses; no route-local merge or second tools write |
| Function calls | openprogram/agentic_programming/agent.py; openprogram/agentic_programming/llm.py; openprogram/agentic_programming/runtime/execution.py | Normalize old/new arguments once; immutable scoped configuration; preserve return/validation, no Program/MCP tool loop, and explicit authorized native search |
| Durable dispatch | openprogram/programs/tools/agents/agent/agent/agent.py; openprogram/agent/sub_agent_run.py | Reuse dispatch and existing task lifecycle; persist snapshot/lineage through actual run and DAG stores |
| Memory | openprogram/memory/backend.py; openprogram/memory/management/config.py | Policy enforcement above backend; namespace and commit contracts within backend; trace every caller before signoff |
| UI | apps/web/components/agents/agents-page.tsx | Reuse components; typed draft and atomic save; extend existing API/type layer at its actual import path |
| Docs | Configuration contract; Editor; Capabilities; Programs | Update these canonical pages, both languages; product usage pages change only alongside real implementation |
Before each implementation brief, locate actual chat/scheduler/CLI consumers and persistence schemas through the current call graph, and record their concrete file paths. The paths above are confirmed boundaries, not an invented exhaustive patch list. Do not perform unrelated frontend, provider or memory-engine refactors.
Migration, old clients and rollback
- Preflight reads all saved Agent records, the default pointer and effective legacy global settings under the configuration writer lock. Produce a dry-run report of IDs, schema versions, unresolved references and semantic differences. Do not include secrets or memory contents. Unknown schemas and corrupt records block migration for that profile; never silently replace them with main.
- A legacy config has schema 1 when the version is absent. Normalize it to schema 2 with initial revision 1. Preserve unknown extension data in a dedicated migration backup; reject unsupported executable fields until understood. Explicitly preserve the old memory binding and effective behavior; do not switch old Agents to new empty self spaces. Legacy global inheritance remains a named compatibility source until a user selects a concrete mode.
- Back up the exact owned configuration files and index with restrictive existing permissions before the first write. Use a journal and restart-safe reconciliation for multi-file work. Commit a profile only after normalized validation succeeds; interrupted migration resumes idempotently. No external workspace, credential, session, DAG or learned-memory content is modified.
- New UI/API writes require expected_revision. Existing clients supplying updated_at use a temporary compatibility adapter: compare their timestamp under the same writer lock, derive the current revision, then perform one atomic write. Missing both preconditions returns 428; the UI must preserve drafts and request reload. Do not accept last-write-wins to keep an old client apparently working.
- No-selector Python calls retain their current model/history/memory behavior and output type. New keywords are keyword-only. Explicit agent_id/config defaults to clean history; an explicit inherit request remains subject to visibility rules. Conflicting aliases are validation errors. Existing durable start_from and to meanings do not change.
- Roll back code only with a reader that understands schema 2, or perform an explicit verified downgrade while writers are stopped. Unsupported new fields prevent a lossless downgrade. Restore the backup only before post-migration edits, or after separately exporting/reconciling those edits; never overwrite newer user changes. A legacy binary must not silently rewrite schema 2.
- Compatibility removal requires updated first-party clients and a documented deprecation period. Additive schema support must land before strict write preconditions ship; deployment order is backend dual-reader, updated clients, migration enablement, then legacy-adapter retirement.
Failure-oriented acceptance scenarios
P3 also owns C1–C10 in collaboration §§6–7: preserve actual execution_id/job_id interfaces, connect completion follow-up and async archive, retain authorized output reads after message exhaustion, and unify history visibility, result limits and exact attach navigation. A helper definition or a test calling it directly is not public-entry completion evidence.
| IDs | Input / action | Required assertion |
|---|---|---|
| A01/A03 | Create name-only config; call agent and llm using saved versus equivalent inline fields | No role requirement; no anonymous persistence; equivalent effective fields except identity/provenance; llm performs no Program/MCP loop; web_search=False emits no native search, while explicit authorized True preserves it |
| A02 | Two processes PATCH model + tools from the same revision; inject failure before replace | Exactly one 200, one 409; complete old/new file; next read never sees mixed fields; draft survives error |
| A04 | Two nested parallel invocations with different model and memory; one cancelled during await | Provider requests use their own resolved fields; finally restores the caller; cancellation propagates |
| A05 | Put distinct sentinels in memory and off/read-only execution outputs; force recall, compaction and session-end writer | No forbidden sentinel enters a request/store through disallowed paths; derived summaries retain write restrictions |
| A05/A08 | Pause queued recall/write, revoke access, then release queue and restart worker | Late recall discarded; write denied at commit; retry/recovery cannot broaden grant |
| A06 | Switch saved Agent with clean, inherit and selected history; request inaccessible node | Only authorized chosen context is visible; no implicit transfer; inaccessible node fails before inference |
| A07 | selected=[]; denied explicit tool; missing required MCP; llm native search both with/without Agent selection | Discovery and invocation agree; no provider/tool side effect before preflight succeeds |
| A08/A12 | Queue a run, edit Agent, resume; then fire next scheduled execution | Resumed run uses pinned config plus current revocations; new firing resolves latest revision |
| A09 | Duplicate/export/import/delete with self and shared memory, active run and external cwd | No copied memory/history/credentials/schedules; shared and external resources remain; active deletion rejected |
| A10 | Operate all editor sections at desktop/mobile with keyboard; two-client save conflict | No draft loss, fake success, overflow or unreachable tabs; conflict details offer reload or explicit reapplication |
| A11 | Migrate legacy fixtures including global-memory inheritance, empty allows, simultaneous names/categories, uncategorized items and default Agent | Before/after effective model, capabilities, memory and default selection match; rerun is a no-op |
First bounded implementation brief: P0
Implement the saved configuration format and atomic update boundary first. Touch Agent management types/storage, Agent routes, their existing tests and the relevant bilingual product/design documentation. Introduce the minimum value/schema module if separating it keeps the manager readable. Do not modify function execution, memory behavior, UI layout or installed App in this brief.
Public RED: submit concurrent same-precondition PATCH requests changing model and tools, then read the saved Agent. The current route-level check and split writes do not establish the required whole-record transaction; the test must demonstrate a reproducible lost-update/mixed-write gap, not merely inspect method names. Extend tests/component/webui/abilities/test_agent_tools_routes.py for the public concurrency/lifecycle cases; place pure migration fixtures alongside the existing agent-management tests after checking their current location. The focused command is uv run --locked --extra dev python -m pytest -q tests/component/webui/abilities/test_agent_tools_routes.py. Add migration fixtures proving the intended legacy semantics before changing serialization.
GREEN: one validated manager transaction compares revision under a cross-process writer lock and atomically replaces the complete canonical file; routes cannot save tools separately. Keep read compatibility, explicit typed errors and timestamp-adapter behavior. Record the actual public-entry command, failure/pass evidence, changed files and commit in the implementation ledger. Run independent specification review, then fresh quality review. P0 remains incomplete until both pass; no runtime feature can be marked implemented from this plan alone.
Verification and release evidence
Choose focused RED/GREEN tests from the current suite at each brief; extend existing ownership before inventing a new test hierarchy. Confirmed related tests include tests/component/webui/abilities/test_agent_tools_routes.py, tests/unit/agent/workflows/test_agentic_programming_agent.py, tests/component/agent/workflows/test_goal_role_configuration.py, tests/component/webui/settings/test_memory_settings_routes.py, tests/unit/memory/test_memory_runtime_config.py and tests/unit/config/test_docs_information_architecture.py. These are starting points, not evidence that the target scenarios already exist.
# Documentation-only deliverable: run from the design checkout.
uv run --locked --with markdown-it-py --with mdit-py-plugins --with pygments python -m scripts.docs_site.build
uv run --locked --with markdown-it-py --with mdit-py-plugins --with pygments python -m scripts.docs_site.checklinks
uv run --locked --with markdown-it-py --with mdit-py-plugins --with pygments python -m scripts.docs_site.checklang
uv run --locked --with markdown-it-py --with mdit-py-plugins --with pygments python -m scripts.docs_site.check_landing
uv run --locked --extra dev --with markdown-it-py --with mdit-py-plugins --with pygments python -m pytest -q tests/unit/config/test_docs_information_architecture.py
# Runtime implementation: focused checks first, final candidate full layers.
uv run --locked --extra dev python -m pytest -q tests/contracts tests/unit tests/component tests/integration
# Web commands execute in apps/web after its documented dependency setup.
cd apps/web
npm test
npx tsc --noEmit
npm run check
npm run build
cd ../..
uv run --locked --extra dev --extra browser python -m pytest -q -m browser tests/e2e/web
Reconcile these commands with tests/README.md and CONTRIBUTING at implementation time; record any additional prescribed full gates. Browser artifacts must exercise the built production page. Final App acceptance uses /Applications/OpenProgram.app, default profile, port 18100 and ~/.openprogram. After the complete implemented feature is committed, refresh once with scripts/refresh-local-app.sh from the final checkout; do not restart from an old worktree or start a second development profile.
Keep source, tests, local commit, remote push, installed App and live deployment as separate evidence fields. A documentation build does not satisfy runtime or App acceptance. This planning task does not commit, push, migrate, restart or release the application.
Optional selection policy: complete extension boundary
P6 is opt-in and runs before the existing resolver. A caller supplies an existing policy reference instead of agent_id/config; they are mutually exclusive. Policy candidates are saved Agent IDs or provider-qualified model references, never arbitrary generated executable configuration. Model-only selection retains the caller’s non-model fields; Agent selection changes the base and uses the normal history rules. The policy must declare which kind it selects, so a model choice cannot silently change memory or instructions.
| Decision | Contract |
|---|---|
| Eligibility | Filter unavailable provider/account/model, required modality or structured output/tool support, context limit, authority and remaining resource cap before ranking |
| Ranking | Versioned ordered deterministic rules over explicit task tags, required capabilities and caller preferences; model-assisted ranking is a separately enabled later mode |
| No match / unavailable | Return a typed no-eligible-candidate error, or use an explicitly configured eligible fallback before inference starts; never broaden authority |
| Trace | Record policy version, eligible candidate IDs, exclusions, chosen ID and rule identifier; avoid raw user content and unsupported cost/latency claims |
| Stability | Pin selection for retries/resume; new invocation may select again. Never switch an already active tool loop automatically |
| Evaluation | Fixed fixture cases for routing correctness, no-match, denied candidate, unknown price metadata and deterministic replay; report measured quality/cost/latency on an approved corpus before claims |
For one Agent-kind policy, all results are saved Agent IDs: task tag=classify and structured-output capability required → the first eligible saved Agent configured with a selected small model; task tag=code-edit and tools required → a selected saved coding Agent; otherwise → a specified saved default Agent. A separate model-kind policy returns only model references and retains non-model fields. Candidate IDs and thresholds are user-configured from the available catalog, not hardcoded product rankings. Missing price/latency metadata means unknown, not free or fast.
Known integration risks and resolved limits
| Risk | Required treatment |
|---|---|
| Memory content indirectly appears in derived history | Propagate write restrictions through context dependencies and generated summaries; test cross-Agent transfer, not just original node ingestion |
| A plugin cannot enforce namespace isolation | Expose unsupported readiness; block requested scoped binding, do not claim prompt-only isolation |
| Concurrent files/default index lifecycle | Journal with recovery and idempotence; mutation authority remains in one manager |
| Old clients overwrite newly typed fields | Dual-reader/conditional-write compatibility and explicit errors; no silent downgrade |
| Configuration snapshots contain personal instructions | Protect with existing execution storage ACLs/retention; diagnostics show hashes/references, not prompt text |
| Expanding UI before runtime supports fields | Feature readiness follows verified backend support; prototype status remains explicit |
There is no unresolved product decision required to begin P0. Exact consumer file paths and backend-specific revocation support are implementation discovery items with the fail-closed behavior specified above. A backend that cannot meet it stays unsupported; implementation convenience does not silently weaken the contract.
Implementation status
| Stage | Design | Implementation / acceptance |
|---|---|---|
| P0 | Specified | Revision/CAS and compatible reads implemented; schema 2 migration and transactional lifecycle remain planned |
| P1 | Specified | Existing runtime resolution and capability policies reused; unified resolver and effective preview remain planned |
| P2 | Specified | Execution, background extraction, derived eligibility and recovery policy implemented for self and legacy_global |
| P3 | Specified | Saved Web configurations and trial snapshots implemented; full Python/CLI/scheduler entry parity remains planned |
| P4 | Specified | Eight sections, shared drafts, model selection and conflict comparison implemented; embedded trial and effective preview remain planned |
| P5 | Specified | Configuration duplication/deletion and product docs implemented; portable import/export remains planned, delivery verification recorded separately |
| P6 (optional) | Specified | Not implemented |
The design document checks and prototype inspection are recorded in the delivery message. They are distinct from the runtime stage evidence listed here. Update this appendix as reviewed implementation lands; keep execution dates and commit history in Git and the implementation ledger, not as appended revisions of this design.