|
|
|
|
@@ -0,0 +1,63 @@
|
|
|
|
|
# RFC: Model-facing same-session goal tools
|
|
|
|
|
|
|
|
|
|
Status: implemented
|
|
|
|
|
|
|
|
|
|
English | [中文](2026-07-19-model-facing-goal-tools.zh.md)
|
|
|
|
|
|
|
|
|
|
## Problem
|
|
|
|
|
|
|
|
|
|
The persisted goal domain deliberately exposes lifecycle verbs to plugins, not directly to a model. A model still needs a small control surface for discovering the current goal, creating one from human intent, and changing its lifecycle. Prompt guidance alone cannot establish who authorized a mutation: a subagent, injected plugin message, stale model turn, or resumed session could all produce the same tool arguments.
|
|
|
|
|
|
|
|
|
|
The surface also needs to preserve the separation between durable state and live execution authority. A restored or forked session can replay an active goal but starts disarmed; a later human request such as “continue” should let the model rearm it without requiring a literal command phrase. Conversely, an admitted autonomous goal round must be able to report completion or a persistent blocker without gaining permission to edit, pause, resume, or replace the human objective.
|
|
|
|
|
|
|
|
|
|
## Decision
|
|
|
|
|
|
|
|
|
|
`@deepseek-ai/dsh-tool-goal` in `packages/goal/tool-goal/` contributes three exclusive tools and one system-prompt policy section over `ctx.goals`: `get_goal`, `create_goal`, and `update_goal`. The names and read-create-update shape follow Codex's compact goal tool surface while the authority rules use this repository's public agent, session, tool, and goal seams.
|
|
|
|
|
|
|
|
|
|
### Tools and model contract
|
|
|
|
|
|
|
|
|
|
`get_goal()` returns the current goal or `null`. A non-null result contains the compare-and-set id and revision, objective, durable phase, admitted and maximum goal rounds, plus the process-local activation observation. `create_goal(objective, max_goal_rounds?)` creates one long-running same-session objective. `update_goal(goal_id, revision, action, objective?, max_goal_rounds?)` supports `edit`, `pause`, `resume`, `complete`, and `blocked`; replacement fields are valid only for `edit`.
|
|
|
|
|
|
|
|
|
|
The prompt tells the model that it may infer goal intent from a direct human request in any wording or language, but should not convert routine single-turn work into a goal. It must read the current goal before updating and copy the exact id and revision. On a restored or forked active-but-disarmed goal, a semantic human request to continue is grounds for `resume`. Completion is reserved for an achieved objective, and difficulty or uncertainty alone is not a blocker.
|
|
|
|
|
|
|
|
|
|
All three tools use exclusive execution so a model-ordered batch observes prior mutations and their new revisions. Results are compact JSON. ACP presentation is a pure function of arguments and uses generic read or mutation cards; activation is reported only as live observation and is never written into replay state.
|
|
|
|
|
|
|
|
|
|
### Execution authority
|
|
|
|
|
|
|
|
|
|
Every call requires an `exec.agent` that is the exact running object in `AgentRegistry`, is the current inherited driver initiator, and has an open turn. These are execution-time checks and cannot be bypassed by prompt injection or hand-authored tool arguments.
|
|
|
|
|
|
|
|
|
|
Create, edit, pause, and resume additionally require an accepted user message or user steering event in the current turn of a runtime-root agent. Root ownership is derived from the live agent graph rather than durable fork ancestry: a resumed fork can receive direct human authority, while a live child remains a subagent and cannot mutate these states. The runtime proves provenance, not whether the human's wording semantically warrants creation or resumption; that interpretation remains with the model.
|
|
|
|
|
|
|
|
|
|
Complete and blocked accept either direct-human authority or the exact current goal round. Goal-round authority requires a goal-sourced `user/message` whose goal id, revision, and round all equal the folded current goal. It grants only the two terminal reports. Direct human authority may stop a goal immediately.
|
|
|
|
|
|
|
|
|
|
### Blocking threshold
|
|
|
|
|
|
|
|
|
|
`blockedAfterConsecutiveRounds` is a validated positive safe-integer configuration with default `3`. When an autonomous goal round calls `blocked`, the plugin mechanically requires at least that many admitted rounds; the configured value also appears in model guidance. The runtime cannot determine whether those rounds encountered the same blocking condition, so semantic equivalence remains a model judgment. This count is deliberately separate from the goal's generous continuation cap.
|
|
|
|
|
|
|
|
|
|
## Testing
|
|
|
|
|
|
|
|
|
|
Unit coverage pins registration and disposal, exclusive scheduling, generated prompt policy, generic presentation, direct-human creation in a non-English turn, exact live-agent and driver checks, root-versus-child authority, steering, mismatched initiators, read/create/edit/pause/resume behavior, rearming after a session-start edge, compare-and-set and argument failures, exact goal-round completion, the configured blocking threshold, and immediate human blocking. A keyless Loader/stdio process test mounts the real goal, tool, loop, and persistence plugins through `cordis.yml`, drives scripted model tool calls, and reads the JSONL externally to verify the model-visible create/pause snapshots, structured tool results, and configured prompt text.
|
|
|
|
|
|
|
|
|
|
## Alternatives considered
|
|
|
|
|
|
|
|
|
|
- **Rely on prompt instructions for authority** — rejected because text can guide model judgment but cannot authenticate the live caller, turn, or source event.
|
|
|
|
|
- **Expose every goal-service verb as a separate tool** — rejected because a compact read/create/update surface reduces schema cost and keeps compare-and-set behavior uniform.
|
|
|
|
|
- **Require exact command phrases** — rejected because natural-language intent, including languages other than English, should be interpreted by the model; execution authority depends on provenance rather than spelling.
|
|
|
|
|
- **Authorize from persisted root or fork metadata** — rejected because a fork that becomes an independently resumed top-level session should accept new human authority, while a currently owned child should not.
|
|
|
|
|
- **Let autonomous rounds edit or resume the goal** — rejected because continuation authority is narrower than authority to redefine or restart the human objective.
|
|
|
|
|
- **Treat the blocked threshold as an evaluator** — rejected because event counts cannot prove that an obstacle is semantically unchanged or truly terminal.
|
|
|
|
|
|
|
|
|
|
## Consequences
|
|
|
|
|
|
|
|
|
|
- Models receive a stable, compact lifecycle surface without direct access to the goal service.
|
|
|
|
|
- State-changing calls are constrained by live runtime provenance as well as durable compare-and-set references.
|
|
|
|
|
- Human requests can create and rearm goals through ordinary natural language, while restored sessions remain inert until such input arrives.
|
|
|
|
|
- Goal rounds can finish or report a repeated blocker but cannot broaden their own mandate.
|
|
|
|
|
- Deployment policy selects the blocking lower bound; the same resolved value controls enforcement and prompt guidance.
|
|
|
|
|
|
|
|
|
|
## Known limitations and deferred work
|
|
|
|
|
|
|
|
|
|
- Semantic classification of a substantial goal, a request to continue, objective completion, and the same blocking condition remains model judgment. An independent evaluator or completion certificate is deferred.
|
|
|
|
|
- These tools mutate goal state but do not schedule goal rounds, classify abnormal driver stops, or cancel an active turn; the same-session driver owns those behaviors.
|
|
|
|
|
- Human slash-command discovery and rendering are deferred to the command-surface layer.
|
|
|
|
|
- A scope can hide tool registrations while leaving the independently registered prompt section visible unless the deployment scopes both together.
|