Skip to content

Commit f14eafe

Browse files
authored
refactor(codemode): remove generic agent tool (#35417)
1 parent b7e4f1e commit f14eafe

5 files changed

Lines changed: 21 additions & 62 deletions

File tree

packages/codemode/README.md

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ Effect-native confined code execution over explicit, schema-described tools.
44

55
CodeMode lets a model write a small JavaScript program that can call only the tools supplied by the host. The program can sequence calls, transform plain data, branch, loop, and run independent calls in parallel without receiving ambient filesystem, process, network, module, or application authority.
66

7-
The package is currently private to this workspace. Its API is designed around three uses:
7+
The package is currently private to this workspace. Its API is designed around one-shot and reusable execution:
88

99
```ts
1010
// One execution
@@ -13,9 +13,6 @@ yield * CodeMode.execute({ tools, code })
1313
// A reusable runtime
1414
const runtime = CodeMode.make({ tools, limits })
1515
yield * runtime.execute(code)
16-
17-
// One agent-facing code tool
18-
const codeTool = runtime.agentTool()
1916
```
2017

2118
## Install
@@ -117,10 +114,9 @@ const runtime = CodeMode.make({
117114
runtime.catalog() // structured tool descriptions
118115
runtime.instructions() // model-facing syntax and tool guide
119116
runtime.execute(source) // ExecuteResult
120-
runtime.agentTool() // { name, description, input, output, execute }
121117
```
122118

123-
`catalog`, `instructions`, and `agentTool` are projections of the same configured tool tree. `agentTool().description` is exactly `instructions()`.
119+
`CodeMode.Input` and `CodeMode.Result` are Effect schemas for the execution request and result. Hosts can combine them with `runtime.instructions()` and `runtime.execute()` when constructing a framework-specific agent tool.
124120

125121
### Results
126122

@@ -333,8 +329,6 @@ A program cannot gain authority through prose or generated code. It can only exe
333329
The public contract is guided by these equivalences:
334330

335331
- `CodeMode.execute({ ...options, code })` is equivalent to `CodeMode.make(options).execute(code)`.
336-
- `CodeMode.make(options).agentTool().execute({ code })` is equivalent to `CodeMode.make(options).execute(code)`.
337-
- `CodeMode.make(options).agentTool().description` equals `CodeMode.make(options).instructions()`.
338332
- A tool implementation is not invoked unless its input has decoded successfully.
339333
- A tool result is not visible to the program unless its output has decoded and crossed the plain-data boundary successfully.
340334
- Unknown host failures do not become model-visible diagnostics; `ToolError` is the explicit safe-message channel.

packages/codemode/codemode.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ maxOutputBytes? }` (defaults 10_000 / 100 / 32_000). This wave kept the other kn
246246
serialized values become truncated text + ` [result truncated: N bytes exceeds the M-byte
247247
output limit; return a smaller value]`; logs keep leading lines within the remaining budget
248248
- `[logs truncated: showing K of N lines]`; result gains `truncated: true` (also added to
249-
`ExecuteResultSchema`). UTF-8-safe truncation (no split code points). (The in-sandbox
249+
`CodeMode.Result`). UTF-8-safe truncation (no split code points). (The in-sandbox
250250
`maxDataBytes` check that used to throw first on oversized raw values died in Fix 5 -
251251
truncation is now the only result-size mechanism.)
252252
- **Search polish**: default limit 12 -> **10** (`defaultSearchLimit`); exact-path lookup - a
@@ -575,7 +575,7 @@ configurable knobs; the internal limit system dies):
575575
`maxCollectionLength` (every array-length/object-field-count check - this knob was
576576
actively harmful: an MCP tool returning 20k rows failed). The `OperationLimitExceeded`
577577
and `AuditLimitExceeded` diagnostic kinds are gone from the `DiagnosticKind` union and
578-
`ExecuteResultSchema` (fine - the package is unreleased).
578+
`CodeMode.Result` (fine - the package is unreleased).
579579
- **Fixed constants, not knobs**: `TOOL_CALL_CONCURRENCY = 8` (codemode.ts; the fork
580580
semaphore) and `MAX_VALUE_DEPTH = 32` (tool-runtime.ts; the `copyIn` depth check - kept
581581
only because it produces a clearer error than a native stack-overflow RangeError; still

packages/codemode/src/codemode.ts

Lines changed: 8 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,14 @@ export type ExecuteFailure = {
108108
/** Result of executing a CodeMode program. Program failures are data, not Effect failures. */
109109
export type ExecuteResult = ExecuteSuccess | ExecuteFailure
110110

111-
/** Reusable CodeMode configuration shared by `execute` and `agentTool`. */
111+
/** Configuration shared by `CodeMode.make` and `CodeMode.execute`. */
112112
export type CodeModeOptions<Tools extends Record<string, unknown> = {}> = Omit<ExecuteOptions<Tools>, "code"> & {
113113
/** Progressive-disclosure configuration for the agent-facing tool catalog. */
114114
readonly discovery?: DiscoveryOptions
115115
}
116116

117-
/** Input schema for the single agent-facing tool produced by `runtime.agentTool()`. */
118-
export const ExecuteInputSchema = Schema.Struct({ code: Schema.String })
117+
/** Schema for a CodeMode execution request. */
118+
const Input = Schema.Struct({ code: Schema.String })
119119

120120
const DiagnosticKindSchema = Schema.Literals([
121121
"ParseError",
@@ -130,8 +130,8 @@ const DiagnosticKindSchema = Schema.Literals([
130130
"ExecutionFailure",
131131
])
132132

133-
/** Structured success or diagnostic result schema returned by CodeMode execution. */
134-
export const ExecuteResultSchema = Schema.Union([
133+
/** Schema for the structured success or diagnostic returned by CodeMode execution. */
134+
const Result = Schema.Union([
135135
Schema.Struct({
136136
ok: Schema.Literal(true),
137137
value: Schema.Json,
@@ -153,23 +153,12 @@ export const ExecuteResultSchema = Schema.Union([
153153
}),
154154
])
155155

156-
/** Agent-facing projection of a configured CodeMode runtime. */
157-
export type AgentToolDefinition<R = never> = {
158-
readonly name: "code"
159-
readonly description: string
160-
readonly input: typeof ExecuteInputSchema
161-
readonly output: typeof ExecuteResultSchema
162-
readonly execute: (input: { readonly code: string }) => Effect.Effect<ExecuteResult, never, R>
163-
}
164-
165156
/** Reusable confined runtime over one explicit tool tree. */
166157
export type CodeModeRuntime<R = never> = {
167158
/** Lists schema-described tool paths provided by the host. */
168159
readonly catalog: () => ReadonlyArray<ToolDescription>
169160
/** Builds model-facing syntax guidance and visible tool signatures. */
170161
readonly instructions: () => string
171-
/** Projects the configured runtime as one agent-facing `code` tool. */
172-
readonly agentTool: () => AgentToolDefinition<R>
173162
/** Executes a program using this runtime's configured host tools. */
174163
readonly execute: (code: string) => Effect.Effect<ExecuteResult, never, R>
175164
}
@@ -4088,13 +4077,12 @@ export const execute = <const Tools extends Record<string, unknown>>(
40884077
/**
40894078
* Creates an Effect-native runtime over explicit, schema-described tools.
40904079
*
4091-
* Use `execute` for host-driven execution or `agentTool` to expose one confined code tool to an
4092-
* agent framework. Tool requirements remain in the returned Effect environment.
4080+
* Use `execute` for host-driven execution. Tool requirements remain in the returned Effect environment.
40934081
*
40944082
* @example
40954083
* ```ts
40964084
* const runtime = CodeMode.make({ tools: { orders: { lookup } } })
4097-
* const code = runtime.agentTool()
4085+
* const result = runtime.execute("return await tools.orders.lookup({ id: 'order_42' })")
40984086
* ```
40994087
*/
41004088
export const make = <const Tools extends Record<string, unknown> = {}>(
@@ -4111,16 +4099,9 @@ export const make = <const Tools extends Record<string, unknown> = {}>(
41114099
return {
41124100
catalog: () => catalog,
41134101
instructions: () => instructions,
4114-
agentTool: () => ({
4115-
name: "code",
4116-
description: instructions,
4117-
input: ExecuteInputSchema,
4118-
output: ExecuteResultSchema,
4119-
execute: ({ code }) => executeProgram(code),
4120-
}),
41214102
execute: executeProgram,
41224103
}
41234104
}
41244105

41254106
/** Constructors for one-shot and reusable CodeMode execution. */
4126-
export const CodeMode = { make, execute }
4107+
export const CodeMode = { Input, Result, make, execute }

packages/codemode/src/index.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
1-
export { ToolError, CodeMode, ExecuteInputSchema, ExecuteResultSchema, toolError } from "./codemode.js"
1+
export { ToolError, CodeMode, toolError } from "./codemode.js"
22
export { Tool } from "./tool.js"
33
export * as OpenAPI from "./openapi/index.js"
44
export type { Definition as ToolDefinition, JsonSchema, ToolSchema } from "./tool.js"
55
export type { ToolCallEnded, ToolCallHooks } from "./tool-runtime.js"
66
export type {
7-
AgentToolDefinition,
87
CodeModeOptions,
98
CodeModeRuntime,
109
DataValue,

packages/codemode/test/codemode.test.ts

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,6 @@
11
import { describe, expect, test } from "bun:test"
22
import { Cause, Effect, Schema } from "effect"
3-
import {
4-
CodeMode,
5-
ExecuteInputSchema,
6-
ExecuteResultSchema,
7-
Tool,
8-
toolError,
9-
type ExecutionLimits,
10-
} from "../src/index.js"
3+
import { CodeMode, Tool, toolError, type ExecutionLimits } from "../src/index.js"
114
import type { Definition } from "../src/tool.js"
125

136
const run = (tool: Definition<never>) =>
@@ -235,7 +228,7 @@ describe("CodeMode console capture", () => {
235228
logs: ['Thread info: {"name":"Demo","count":2}', "[warn] careful"],
236229
toolCalls: [],
237230
})
238-
expect(Schema.decodeUnknownSync(ExecuteResultSchema)(JSON.parse(JSON.stringify(result)))).toStrictEqual(result)
231+
expect(Schema.decodeUnknownSync(CodeMode.Result)(JSON.parse(JSON.stringify(result)))).toStrictEqual(result)
239232
})
240233

241234
test("keeps logs captured before failures", async () => {
@@ -371,7 +364,7 @@ describe("CodeMode output budget", () => {
371364
expect(result.value).toMatch(
372365
/^\{"data":"x+ \[result truncated: \d+ bytes exceeds the 40-byte output limit; return a smaller value\]$/,
373366
)
374-
expect(Schema.decodeUnknownSync(ExecuteResultSchema)(JSON.parse(JSON.stringify(result)))).toStrictEqual(result)
367+
expect(Schema.decodeUnknownSync(CodeMode.Result)(JSON.parse(JSON.stringify(result)))).toStrictEqual(result)
375368
})
376369

377370
test("keeps leading logs within the remaining budget and marks the cut", async () => {
@@ -501,24 +494,16 @@ describe("CodeMode public contract", () => {
501494
const tools = { orders: { lookup } }
502495
const source = `return await tools.orders.lookup({ id: "order_42" })`
503496

504-
test("keeps one-shot, reusable, and agent-tool execution equivalent", async () => {
497+
test("keeps one-shot and reusable execution equivalent", async () => {
505498
const runtime = CodeMode.make({ tools })
506-
const agentTool = runtime.agentTool()
507-
const [oneShot, reusable, projected] = await Promise.all([
499+
const [oneShot, reusable] = await Promise.all([
508500
Effect.runPromise(CodeMode.execute({ tools, code: source })),
509501
Effect.runPromise(runtime.execute(source)),
510-
Effect.runPromise(agentTool.execute({ code: source })),
511502
])
512503

513504
expect(reusable).toStrictEqual(oneShot)
514-
expect(projected).toStrictEqual(oneShot)
515-
expect(agentTool.name).toBe("code")
516-
expect(agentTool.input).toBe(ExecuteInputSchema)
517-
expect(agentTool.output).toBe(ExecuteResultSchema)
518-
expect(agentTool.description).toBe(runtime.instructions())
519-
expect(Schema.decodeUnknownSync(ExecuteResultSchema)(JSON.parse(JSON.stringify(projected)))).toStrictEqual(
520-
projected,
521-
)
505+
expect(Schema.decodeUnknownSync(CodeMode.Input)({ code: source })).toStrictEqual({ code: source })
506+
expect(Schema.decodeUnknownSync(CodeMode.Result)(JSON.parse(JSON.stringify(reusable)))).toStrictEqual(reusable)
522507
})
523508

524509
test("inlines a COMPLETE small catalog and keeps search registered but unadvertised", async () => {
@@ -1035,7 +1020,7 @@ describe("CodeMode public contract", () => {
10351020
value: { top: null, nested: [1, null] },
10361021
toolCalls: [],
10371022
})
1038-
expect(Schema.decodeUnknownSync(ExecuteResultSchema)(JSON.parse(JSON.stringify(result)))).toStrictEqual(result)
1023+
expect(Schema.decodeUnknownSync(CodeMode.Result)(JSON.parse(JSON.stringify(result)))).toStrictEqual(result)
10391024
})
10401025

10411026
test("rejects invalid configuration and discovery limits", async () => {

0 commit comments

Comments
 (0)