feat(codemode): make search a global built-in and rewrite README (#36450)

This commit is contained in:
Aiden Cline 2026-07-11 13:43:33 -05:00 committed by GitHub
commit 6eeeb4bfcf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
11 changed files with 274 additions and 416 deletions

View file

@ -541,11 +541,11 @@ describe("CodeMode public contract", () => {
" - tools.orders.lookup(input: {\n id: string,\n}): Promise<{\n id: string,\n status: string,\n}> // Look up an order by ID",
)
// A fully inlined catalog does not advertise search in the instructions...
expect(runtime.instructions()).not.toMatch(/\$codemode/)
expect(runtime.instructions()).not.toContain("search(")
// ...but the search tool stays registered, so a speculative call still works with the
// ...but the search built-in stays available, so a speculative call still works with the
// same signature as the inline catalog.
const result = await Effect.runPromise(runtime.execute(`return await tools.$codemode.search({ query: "order" })`))
const result = await Effect.runPromise(runtime.execute(`return search({ query: "order" })`))
expect(result.ok).toBe(true)
if (result.ok) {
expect(result.value).toStrictEqual({
@ -583,9 +583,7 @@ describe("CodeMode public contract", () => {
'tools.context7["resolve-library-id"](input: {\n libraryName: string,\n}): Promise<string>',
)
const search = await Effect.runPromise(
runtime.execute(`return await tools.$codemode.search({ query: "resolve library id" })`),
)
const search = await Effect.runPromise(runtime.execute(`return search({ query: "resolve library id" })`))
expect(search.ok).toBe(true)
if (search.ok) {
expect(search.value).toStrictEqual({
@ -608,7 +606,7 @@ describe("CodeMode public contract", () => {
if (call.ok) expect(call.value).toBe("/resolved/TypeScript")
const exact = await Effect.runPromise(
runtime.execute(`return await tools.$codemode.search({ query: 'tools.context7["resolve-library-id"]' })`),
runtime.execute(`return search({ query: 'tools.context7["resolve-library-id"]' })`),
)
expect(exact.ok).toBe(true)
if (exact.ok) expect(exact.value).toMatchObject({ remaining: 0, next: null })
@ -632,7 +630,7 @@ describe("CodeMode public contract", () => {
expect(instructions).toContain("Do not infer or normalize tool names")
expect(instructions).toContain("bracket notation and quotes are part of the path")
expect(instructions).toContain("surrounding agent tools are not available")
expect(instructions).toContain("Only Code Mode tools listed here and internal runtime tools")
expect(instructions).toContain("Only Code Mode tools listed here are available")
// Placeholders use generic namespace/tool/field names only - no fabricated real tools
// and no real catalog tools cherry-picked into example lines.
expect(instructions).toContain("`const result = await tools.<namespace>.<tool>(input)`")
@ -651,15 +649,11 @@ describe("CodeMode public contract", () => {
// PARTIAL: the workflow starts with search (with query-style guidance that is clearly
// a query string, never a tool name) and the browse-namespace rule appears.
expect(partial).toContain(
'1. If needed, discover tools: `return await tools.$codemode.search({ query: "<intent + key nouns>" })`.',
'1. If needed, discover tools with the built-in search function: `return search({ query: "<intent + key nouns>" })`.',
)
expect(partial).toContain("In the next execution, copy a returned path exactly")
expect(partial).toContain(
"Only Code Mode tools listed here or returned by `tools.$codemode.search` and internal runtime tools",
)
expect(partial).toContain(
'- Browse one namespace: `await tools.$codemode.search({ query: "", namespace: "<name>" })`.',
)
expect(partial).toContain("Only Code Mode tools listed here or returned by the built-in `search` function")
expect(partial).toContain('- Browse one namespace: `search({ query: "", namespace: "<name>" })`.')
expect(partial).toContain("repeat the same search with `offset: next.offset`")
expect(partial).toContain(" limit?: number,\n offset?: number,")
expect(partial).not.toContain("total_count")
@ -696,7 +690,7 @@ describe("CodeMode public contract", () => {
expect(instructions).toContain("## Available tools")
expect(instructions).not.toContain("## Workflow")
expect(instructions).not.toContain("## Rules")
expect(instructions).not.toMatch(/\$codemode/)
expect(instructions).not.toContain("search(")
})
test("uses one ranked search returning complete definitions for large catalogs", async () => {
@ -716,17 +710,15 @@ describe("CodeMode public contract", () => {
tools: { thread: { uploadFile: upload, generateImage: generate }, orders: { lookup } },
discovery: { catalogBudget: 0 },
})
expect(runtime.instructions()).toContain(
"Available tools (PARTIAL - 0 of 3 shown; find the rest with tools.$codemode.search)",
)
expect(runtime.instructions()).toContain("Available tools (PARTIAL - 0 of 3 shown; find the rest with search(...))")
expect(runtime.instructions()).toContain("- thread (2 tools, none shown)")
expect(runtime.instructions()).toContain("- orders (1 tool, none shown)")
expect(runtime.instructions()).toMatch(/\$codemode\.search/)
expect(runtime.instructions()).toContain("Search returns complete callable signatures:\n- search(input: {")
expect(runtime.instructions()).not.toMatch(/tools\.thread\.uploadFile\(input/)
const result = await Effect.runPromise(
runtime.execute(`
return await tools.$codemode.search({
return search({
query: "send message attachment upload file to current Discord thread",
limit: 2
})
@ -750,14 +742,14 @@ describe("CodeMode public contract", () => {
remaining: 0,
next: null,
})
expect(result.toolCalls).toStrictEqual([{ name: "$codemode.search" }])
expect(result.toolCalls).toStrictEqual([{ name: "search" }])
const variants = await Effect.runPromise(
runtime.execute(`
return await Promise.all([
tools.$codemode.search({ query: "file" }),
tools.$codemode.search({ query: "image" })
])
return [
search({ query: "file" }),
search({ query: "image" })
]
`),
)
expect(variants.ok).toBe(true)
@ -770,13 +762,41 @@ describe("CodeMode public contract", () => {
)
}
const removed = await Effect.runPromise(
runtime.execute(`return await tools.$codemode.describe({ path: "thread.uploadFile" })`),
)
// The retired $codemode namespace is gone from the tools tree entirely.
const removed = await Effect.runPromise(runtime.execute(`return await tools.$codemode.search({ query: "file" })`))
expect(removed.ok).toBe(false)
if (!removed.ok) expect(removed.error.kind).toBe("UnknownTool")
})
test("search is a counted tool call: it burns maxToolCalls and fires the hooks", async () => {
const started: Array<string> = []
const ended: Array<string> = []
const limited = CodeMode.make({
tools,
limits: { maxToolCalls: 1 },
onToolCallStart: (call) => Effect.sync(() => void started.push(call.name)),
onToolCallEnd: (call) => Effect.sync(() => void ended.push(`${call.name}:${call.outcome}`)),
})
const result = await Effect.runPromise(limited.execute(`search({}); return search({})`))
expect(result.ok).toBe(false)
if (!result.ok) expect(result.error.kind).toBe("ToolCallLimitExceeded")
expect(started).toEqual(["search"])
expect(ended).toEqual(["search:success"])
})
test("search is an opaque, shadowable global like other built-ins", async () => {
const runtime = CodeMode.make({ tools })
expect(await Effect.runPromise(runtime.execute(`return typeof search`))).toMatchObject({ value: "function" })
// A program-level declaration shadows the global, as JS module scope does.
const shadowed = await Effect.runPromise(runtime.execute(`const search = () => "local"; return search()`))
expect(shadowed.ok).toBe(true)
if (shadowed.ok) expect(shadowed.value).toBe("local")
// The reference itself cannot cross the data boundary.
const escaped = await Effect.runPromise(runtime.execute(`return { search }`))
expect(escaped.ok).toBe(false)
if (!escaped.ok) expect(escaped.error.kind).toBe("InvalidDataValue")
})
test("search defaults to 10 results and resolves exact tool paths", async () => {
const tool = (index: number) =>
Tool.make({
@ -791,7 +811,7 @@ describe("CodeMode public contract", () => {
},
})
const browse = await Effect.runPromise(runtime.execute(`return await tools.$codemode.search({})`))
const browse = await Effect.runPromise(runtime.execute(`return search({})`))
expect(browse.ok).toBe(true)
if (browse.ok) {
const value = browse.value as {
@ -805,9 +825,7 @@ describe("CodeMode public contract", () => {
}
for (const query of ["many.tool13", "tools.many.tool13"]) {
const exact = await Effect.runPromise(
runtime.execute(`return await tools.$codemode.search({ query: ${JSON.stringify(query)} })`),
)
const exact = await Effect.runPromise(runtime.execute(`return search({ query: ${JSON.stringify(query)} })`))
expect(exact.ok).toBe(true)
if (exact.ok) {
expect(exact.value).toStrictEqual({
@ -841,9 +859,7 @@ describe("CodeMode public contract", () => {
})
// Empty query + namespace browses just that namespace, alphabetical by path.
const browse = await Effect.runPromise(
runtime.execute(`return await tools.$codemode.search({ query: "", namespace: "github" })`),
)
const browse = await Effect.runPromise(runtime.execute(`return search({ query: "", namespace: "github" })`))
expect(browse.ok).toBe(true)
if (browse.ok) {
const value = browse.value as { items: Array<{ path: string }>; remaining: number }
@ -855,9 +871,7 @@ describe("CodeMode public contract", () => {
}
// A query + namespace ranks within that namespace only.
const scoped = await Effect.runPromise(
runtime.execute(`return await tools.$codemode.search({ query: "issues", namespace: "linear" })`),
)
const scoped = await Effect.runPromise(runtime.execute(`return search({ query: "issues", namespace: "linear" })`))
expect(scoped.ok).toBe(true)
if (scoped.ok) {
const value = scoped.value as { items: Array<{ path: string }>; remaining: number }
@ -865,9 +879,7 @@ describe("CodeMode public contract", () => {
expect(value.items[0]?.path).toBe("tools.linear.list_issues")
}
const invalid = await Effect.runPromise(
runtime.execute(`return await tools.$codemode.search({ query: "issues", namespace: 7 })`),
)
const invalid = await Effect.runPromise(runtime.execute(`return search({ query: "issues", namespace: 7 })`))
expect(invalid.ok).toBe(false)
if (!invalid.ok) expect(invalid.error.kind).toBe("InvalidToolInput")
})
@ -892,9 +904,7 @@ describe("CodeMode public contract", () => {
// "attachment" appears in neither path nor description - only in the input schema's
// property names, which the searchable text includes.
const byParameter = await Effect.runPromise(
runtime.execute(`return await tools.$codemode.search({ query: "attachment" })`),
)
const byParameter = await Effect.runPromise(runtime.execute(`return search({ query: "attachment" })`))
expect(byParameter.ok).toBe(true)
if (byParameter.ok) {
const value = byParameter.value as { items: Array<{ path: string }>; remaining: number }
@ -903,9 +913,7 @@ describe("CodeMode public contract", () => {
}
// Substring matching: a partial word ("docum") still hits the description.
const bySubstring = await Effect.runPromise(
runtime.execute(`return await tools.$codemode.search({ query: "docum" })`),
)
const bySubstring = await Effect.runPromise(runtime.execute(`return search({ query: "docum" })`))
expect(bySubstring.ok).toBe(true)
if (bySubstring.ok) {
const value = bySubstring.value as { items: Array<{ path: string }>; remaining: number }
@ -932,9 +940,7 @@ describe("CodeMode public contract", () => {
})
// "issues" still finds the singular-only tool (term OR singular(term) per field)...
const plural = await Effect.runPromise(
runtime.execute(`return await tools.$codemode.search({ query: "issues", namespace: "tracker" })`),
)
const plural = await Effect.runPromise(runtime.execute(`return search({ query: "issues", namespace: "tracker" })`))
expect(plural.ok).toBe(true)
if (plural.ok) {
const value = plural.value as { items: Array<{ path: string }>; remaining: number }
@ -943,7 +949,7 @@ describe("CodeMode public contract", () => {
}
// ...while a true "issues" path match still outranks the singular-only description match.
const ranked = await Effect.runPromise(runtime.execute(`return await tools.$codemode.search({ query: "issues" })`))
const ranked = await Effect.runPromise(runtime.execute(`return search({ query: "issues" })`))
expect(ranked.ok).toBe(true)
if (ranked.ok) {
const value = ranked.value as { items: Array<{ path: string }>; remaining: number }
@ -970,7 +976,7 @@ describe("CodeMode public contract", () => {
alpha: { beta: simple("Middle"), aardvark: simple("First") },
},
})
const browse = await Effect.runPromise(runtime.execute(`return await tools.$codemode.search({})`))
const browse = await Effect.runPromise(runtime.execute(`return search({})`))
expect(browse.ok).toBe(true)
if (browse.ok) {
const value = browse.value as { items: Array<{ path: string }>; remaining: number; next: unknown }
@ -983,9 +989,7 @@ describe("CodeMode public contract", () => {
expect(value.next).toBeNull()
}
const middle = await Effect.runPromise(
runtime.execute(`return await tools.$codemode.search({ limit: 1, offset: 1 })`),
)
const middle = await Effect.runPromise(runtime.execute(`return search({ limit: 1, offset: 1 })`))
expect(middle.ok).toBe(true)
if (middle.ok) {
expect(middle.value).toMatchObject({
@ -995,9 +999,7 @@ describe("CodeMode public contract", () => {
})
}
const exhausted = await Effect.runPromise(
runtime.execute(`return await tools.$codemode.search({ limit: 1, offset: 3 })`),
)
const exhausted = await Effect.runPromise(runtime.execute(`return search({ limit: 1, offset: 3 })`))
expect(exhausted.ok).toBe(true)
if (exhausted.ok) expect(exhausted.value).toStrictEqual({ items: [], remaining: 0, next: null })
})
@ -1028,16 +1030,14 @@ describe("CodeMode public contract", () => {
})
const instructions = runtime.instructions()
expect(instructions).toContain(
"Available tools (PARTIAL - 2 of 3 shown; find the rest with tools.$codemode.search)",
)
expect(instructions).toContain("Available tools (PARTIAL - 2 of 3 shown; find the rest with search(...))")
expect(instructions).toContain("- alpha (2 tools, 1 shown)")
expect(instructions).toContain(" - tools.alpha.cheap(input: {\n q: string,\n}): Promise<string> // Cheap")
expect(instructions).not.toContain("tools.alpha.expensive(")
// Fully shown namespaces read cleanly (no "shown" annotation).
expect(instructions).toContain("- beta (1 tool)")
expect(instructions).toContain(" - tools.beta.cheap(input: {\n q: string,\n}): Promise<string> // Cheap")
expect(instructions).toMatch(/\$codemode\.search/)
expect(instructions).toContain("Search returns complete callable signatures:\n- search(input: {")
})
test("charges inline JSDoc against the catalog token budget", () => {
@ -1058,9 +1058,7 @@ describe("CodeMode public contract", () => {
})
expect(runtime.catalog()[0]?.signature).toContain("/** A detailed identifier description.")
expect(runtime.instructions()).toContain(
"Available tools (PARTIAL - 0 of 1 shown; find the rest with tools.$codemode.search)",
)
expect(runtime.instructions()).toContain("Available tools (PARTIAL - 0 of 1 shown; find the rest with search(...))")
expect(runtime.instructions()).not.toContain("tools.records.lookup(input:")
})
@ -1138,7 +1136,7 @@ describe("CodeMode public contract", () => {
CodeMode.make({
tools,
discovery: { catalogBudget: 0 },
}).execute(`return await tools.$codemode.search({ query: "order", limit: 0.5 })`),
}).execute(`return search({ query: "order", limit: 0.5 })`),
)
expect(result.ok).toBe(false)
if (result.ok) return
@ -1146,9 +1144,7 @@ describe("CodeMode public contract", () => {
for (const offset of [-1, 0.5, Number.MAX_SAFE_INTEGER + 1, "1"]) {
const invalidOffset = await Effect.runPromise(
CodeMode.make({ tools }).execute(
`return await tools.$codemode.search({ query: "order", offset: ${JSON.stringify(offset)} })`,
),
CodeMode.make({ tools }).execute(`return search({ query: "order", offset: ${JSON.stringify(offset)} })`),
)
expect(invalidOffset.ok).toBe(false)
if (!invalidOffset.ok) expect(invalidOffset.error.kind).toBe("InvalidToolInput")
@ -1200,7 +1196,10 @@ describe("CodeMode public contract", () => {
expect(elapsedMs).toBeLessThan(3_000)
})
test("reserves the discovery namespace", () => {
expect(() => CodeMode.make({ tools: { $codemode: { lookup } } })).toThrow(/reserved for CodeMode discovery tools/)
test("a host $codemode namespace is an ordinary namespace now that search is a built-in", async () => {
const runtime = CodeMode.make({ tools: { $codemode: { lookup } } })
const result = await Effect.runPromise(runtime.execute(`return await tools.$codemode.lookup({ id: "order_1" })`))
expect(result.ok).toBe(true)
if (result.ok) expect(result.value).toStrictEqual({ id: "order_1", status: "open" })
})
})

View file

@ -41,7 +41,7 @@ describe("Object.keys over tool references", () => {
const namespaces = Object.keys(tools)
return { namespaces, count: namespaces.length }
`),
).toEqual({ namespaces: ["github", "memory", "playwright", "$codemode"], count: 4 })
).toEqual({ namespaces: ["github", "memory", "playwright"], count: 3 })
})
test("enumerates tool names at a nested namespace", async () => {
@ -52,8 +52,10 @@ describe("Object.keys over tool references", () => {
expect(await value(`return Object.keys(tools.github.list_issues)`)).toEqual([])
})
test("the internal discovery namespace enumerates its callable surface", async () => {
expect(await value(`return Object.keys(tools.$codemode)`)).toEqual(["search"])
test("search is a global built-in function, not a tools namespace", async () => {
expect(await value(`return typeof search`)).toBe("function")
const failure = await error(`return Object.keys(tools.$codemode)`)
expect(failure.kind).toBe("UnknownTool")
})
test("an unknown namespace is an UnknownTool error pointing at the discovery idioms", async () => {
@ -68,7 +70,7 @@ describe("Object.keys over tool references", () => {
const failure = await error(`return Object.${method}(tools)`)
expect(failure.kind).toBe("InvalidDataValue")
expect(failure.message).toContain(
`Object.${method}(...) cannot read tool references: they are not plain data. Use Object.keys(tools) for names, or tools.$codemode.search({ query }) for signatures.`,
`Object.${method}(...) cannot read tool references: they are not plain data. Use Object.keys(tools) for names, or search({ query }) for signatures.`,
)
}
const nested = await error(`return Object.entries(tools.github)`)
@ -146,7 +148,7 @@ describe("for...in", () => {
}
return names
`),
).toEqual(["github.list_issues", "github.get_issue", "memory.search", "playwright.navigate", "$codemode.search"])
).toEqual(["github.list_issues", "github.get_issue", "memory.search", "playwright.navigate"])
})
test("unsupported values fail with a hint at for...of and Object.keys", async () => {

View file

@ -377,7 +377,7 @@ describe("OpenAPI.fromSpec", () => {
runtime
.execute(
`
return await tools.$codemode.search({ query: "global health", namespace: "opencode", limit: 1 })
return search({ query: "global health", namespace: "opencode", limit: 1 })
`,
)
.pipe(Effect.provide(layer)),

View file

@ -342,9 +342,7 @@ describe("JSDoc signatures in catalogs and search results", () => {
const runtime = CodeMode.make({ tools: { github: { list_issues: listIssues }, orders: { lookup: lookupOrder } } })
const search = async (query: string) => {
const result = await Effect.runPromise(
runtime.execute(`return await tools.$codemode.search({ query: ${JSON.stringify(query)} })`),
)
const result = await Effect.runPromise(runtime.execute(`return search({ query: ${JSON.stringify(query)} })`))
expect(result.ok).toBe(true)
if (!result.ok) throw new Error("search failed")
return result.value as { items: Array<{ path: string; signature: string }>; remaining: number }
@ -436,9 +434,7 @@ describe("non-identifier tool paths", () => {
})
test("search results return callable bracket-notation paths and signatures", async () => {
const result = await Effect.runPromise(
runtime.execute(`return await tools.$codemode.search({ query: "resolve library" })`),
)
const result = await Effect.runPromise(runtime.execute(`return search({ query: "resolve library" })`))
expect(result.ok).toBe(true)
if (!result.ok) throw new Error("search failed")