CLI loads harness spec 3.0.0-draft; the show tool over the link
The spec's version may be a pre-release (3.0.0-draft). Every tool file is loaded, with the new fields `sessions`, `requires`, `unavailable` and `confirm`; the CLI's tools are those not the server's alone and offered in an agent session (forCli) — a chat's own tools over the server's tree (mkdir, mv, rm, search, python, the forge verbs) are not built in. blocks/context.md is known; blocks/workspace.md is the server's alone. show is built in with `requires: display`: offered only in a session a client opened over the link when that client said `show: true` (capability `show`); the device reads the file (at most 1 MB) and sends it with `_lembas/show`. The harness tests now say 3.0.0's split of tools instead of "the execution tools are the CLI's alone". Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
10 files changed
+200
-24
No files matched your search
+22
-2
@@ -64,7 +64,7 @@ const limitsFor = (root: string, extra: Partial<Limits> = {}): Limits => ({ root
|
||||
|
||||
/** A fake LLeMbas on one side of the agent. `lembas: false`: an editor that is not LLeMbas. */
|
||||
/** `protocol`: what the client says it speaks (2 by default; 1 is an older client). */
|
||||
async function client(limits?: Limits, o: { lembas?: boolean; protocol?: number; instance?: string; hub?: Hub; handlers?: Record<string, (p: any) => unknown> } = {}) {
|
||||
async function client(limits?: Limits, o: { lembas?: boolean; protocol?: number; instance?: string; hub?: Hub; show?: boolean; handlers?: Record<string, (p: any) => unknown> } = {}) {
|
||||
const [ta, tb] = pair()
|
||||
new AcpAgent(new Peer(ta), limits, o.instance, o.hub)
|
||||
const c = new Peer(tb)
|
||||
@@ -76,7 +76,7 @@ async function client(limits?: Limits, o: { lembas?: boolean; protocol?: number;
|
||||
c.on("_lembas/permission/settled", (p) => void notes.push({ method: "settled", params: p }))
|
||||
c.handle("session/request_permission", () => ({ outcome: { outcome: "selected", optionId: "once" } }))
|
||||
for (const [m, fn] of Object.entries(o.handlers ?? {})) c.handle(m, fn)
|
||||
const init: any = await c.request("initialize", { protocolVersion: 1, clientCapabilities: o.lembas === false ? {} : { _meta: { lembas: o.protocol === 1 ? true : { protocol: o.protocol ?? 2 } } } })
|
||||
const init: any = await c.request("initialize", { protocolVersion: 1, clientCapabilities: o.lembas === false ? {} : { _meta: { lembas: o.protocol === 1 ? true : { protocol: o.protocol ?? 2, ...(o.show ? { show: true } : {}) } } } })
|
||||
return { c, updates, events, notes, init }
|
||||
}
|
||||
|
||||
@@ -312,6 +312,26 @@ test("initialize lists the 1.1.0 capabilities", async () => {
|
||||
for (const cap of ["context", "library", "prototypes", "plan_state", "rewind"]) expect(init._meta.lembas.capabilities).toContain(cap)
|
||||
})
|
||||
|
||||
test("show (spec 3.0.0): offered only to a client that shows files; the file goes over _lembas/show", async () => {
|
||||
const page = "<!doctype html><h1>Hi</h1>"
|
||||
fake = fakeProvider([{ chunks: [toolCall(0, "s1", "show", JSON.stringify({ path: "out/page.html", line: 1 }))] }, { chunks: [delta({ content: "there" })] }, { chunks: [delta({ content: "plain" })] }])
|
||||
config(fake.url)
|
||||
const root = project({ "out/page.html": page })
|
||||
let shown: any
|
||||
const { c, init } = await client(limitsFor(root), { show: true, handlers: { "_lembas/show": (p) => ((shown = p), { shown: true }) } })
|
||||
expect(init._meta.lembas.capabilities).toContain("show")
|
||||
const s: any = await c.request("session/new", { cwd: root })
|
||||
await c.request("session/prompt", { sessionId: s.sessionId, prompt: [{ type: "text", text: "make a page" }] })
|
||||
expect(fake.requests[0].tools.map((t: any) => t.function.name)).toContain("show")
|
||||
expect(shown).toEqual({ sessionId: s.sessionId, toolCallId: "s1", path: "out/page.html", kind: "html", line: 1, text: page })
|
||||
expect(fake.requests[1].messages.find((m: any) => m.role === "tool").content).toContain("Shown to the user: out/page.html")
|
||||
// A client that did not say it shows files: no show tool.
|
||||
const other = await client(limitsFor(root))
|
||||
const s2: any = await other.c.request("session/new", { cwd: root })
|
||||
await other.c.request("session/prompt", { sessionId: s2.sessionId, prompt: [{ type: "text", text: "hi" }] })
|
||||
expect(fake.requests[2].tools.map((t: any) => t.function.name)).not.toContain("show")
|
||||
})
|
||||
|
||||
test("the context reaches the prompt: the instance's instructions, its personalization, the library's scope, prototypes", async () => {
|
||||
fake = fakeProvider([{ chunks: [delta({ content: "one" })] }, { chunks: [delta({ content: "two" })] }, { chunks: [delta({ content: "three" })] }])
|
||||
config(fake.url, "personality: concise\ninstructions: local words\n")
|
||||
|
||||
Reference in new issue
Block a user