Harness spec 1.1.0: one plan, prototypes and the library shared; the CLI implements it
The spec: plan_write and plan_update (new, shared, offered in every mode) and plan_submit (now shared) keep one structured plan — findings, objectives, phases of tasks — in place of the todo list, which lives on as a former name of plan_write. The shared system text is one text for both projects, with variables for what differs; the mode texts, a prototypes block and a library block are shared. acp.md: the client hands the device what only it knows (context, library, prototypes), the plan travels as a structure (plan_state), library calls carry the chat's scope, and a client may rewind a session. loop.json says its numbers as numbers. Four conformance areas: plan, prototype, library_scope, toolcall_index. The CLI: the plan is kept per session in the store and drawn above the prompt and on the approval card; the prompt is assembled from the spec's texts with their variables filled; the link reads the instance's instructions, personalization, knowledge scope and prototype offer, sends the plan as a structure and answers rewind; library calls to the instance carry the session as scope; a prototype written in the terminal is saved as a file and named in the transcript; a tool-call fragment without an index continues the last call; the default theme is Moria; dead exports and Hermes leftovers removed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
96 files changed
+3259
-527
No files matched your search
@@ -12,6 +12,10 @@ import { replace } from "../src/tool/replace.ts"
|
||||
import { applyUnified, parseUnified } from "../src/tool/unidiff.ts"
|
||||
import { derive, joinBom, parse } from "../src/tool/patch.ts"
|
||||
import type { Mode, PermissionConfig } from "../src/config/schema.ts"
|
||||
import { apply, fromTodos, normalise, type Plan } from "../src/plan/plan.ts"
|
||||
import { ToolCallAccumulator } from "../src/provider/openai-chat.ts"
|
||||
import { parseInfo, titleFor } from "../src/prototype/fence.ts"
|
||||
import { resolveBase } from "../src/library/store.ts"
|
||||
|
||||
type Case = Record<string, unknown>
|
||||
|
||||
@@ -57,6 +61,23 @@ export const AREAS: Record<string, (c: Case) => unknown> = {
|
||||
return { error: (e as Error).message }
|
||||
}
|
||||
},
|
||||
plan: (c) => {
|
||||
if (c.op === "normalise") return normalise(c.plan)
|
||||
if (c.op === "update") return apply(c.plan as Plan, c.changes)
|
||||
if (c.op === "todos") return fromTodos(c.todos)
|
||||
throw new Error(`plan: unknown op ${String(c.op)}`)
|
||||
},
|
||||
prototype: (c) => {
|
||||
const info = parseInfo(c.info as string)
|
||||
return info ? { kind: info.kind, title: titleFor(c.code as string, info.title) } : null
|
||||
},
|
||||
library_scope: (c) => resolveBase(c.bases as { id: string; name: string }[], c.base as string | null),
|
||||
toolcall_index: (c) => {
|
||||
// The deltas as the OpenAI stream carries them: `function.name` and `function.arguments`.
|
||||
const acc = new ToolCallAccumulator()
|
||||
acc.feed((c.deltas as Record<string, unknown>[]).map(({ index, id, name, arguments: args }) => ({ index, id, function: { name, arguments: args } })))
|
||||
return acc.result().map((p) => ({ id: p.id, name: p.name, arguments: p.args }))
|
||||
},
|
||||
envelope: (c) => {
|
||||
// planPatch's logic without the filesystem: every file followed through the patch in memory.
|
||||
const files = new Map<string, string | null>(Object.entries(c.files as Record<string, string>))
|
||||
|
||||
Reference in new issue
Block a user