Skip to content

📐 feat: Add @librechat/dev-tools Package for Coding Tool Definitions - #262

Open
lia-by-librechat[bot] wants to merge 1 commit into
mainfrom
lia/dev-tools-package
Open

lia-by-librechat[bot] wants to merge 1 commit into
mainfrom
lia/dev-tools-package

Conversation

@lia-by-librechat

Copy link
Copy Markdown
Contributor

Summary

Port the LLM-visible surface of the harness-native coding tools from @librechat/agents into this repository as a new package, @librechat/dev-tools — the code-interpreter side of moving the coding tool definitions next to the Code API that provides their execution environments.

The package holds exactly what the LLM sees:

  • Canonical tool names (ToolNames) and the CODE_EXECUTION_TOOLS / LOCAL_CODING_TOOL_NAMES / LOCAL_CODING_BUNDLE_NAMES sets
  • JSON schemas and descriptions for the remote-engine tools: execute_code, bash_tool, run_tools_with_code, run_tools_with_bash, read_file — including the stateful, attached-workspace, and tool-output-reference description/schema builders
  • Schemas, descriptions, and registry definitions for the local-engine tools: read_file, write_file, edit_file, grep_search, glob_search, list_directory, compile_check
  • The intent-label contract embedded in every schema: INTENT_PROPERTY, withIntent/withoutIntent, arg readers/strippers, and outcome resolution
  • The shared /mnt/data and bash guidance
  • The programmatic-run timeout schema with environment-resolved defaults and clamping

Why

The schemas describe the execution environments this service provides, so they live here rather than inside the agent harness: @librechat/agents and LibreChat (BYOM provisioning) consume the definitions without the harness owning them. Zero runtime dependencies — everything is plain data and pure functions.

Execution stays harness-native in @librechat/agents (Code API client, ToolNode event dispatch, the local engine, result replay, and output shaping). The sibling @librechat/code package covers the worker side of provisioning.

Provenance and fidelity

Ported from @librechat/agents src/tools/ with export-name parity so the agents-side swap is mechanical. Intentional differences:

  • Constants tool-name members became ToolNames (the harness enum mixes orchestration constants; only the coding-tool members moved)
  • Schemas that were module-private in the harness (CompileCheckSchema, the local programmatic tool calling schema builders) are exported here — sharing them is the package's purpose
  • Local-engine descriptions that lived inline inside tool factories are first-class Local*ToolDescription constants
  • JsonSchemaType is widened with the JSON-Schema keywords these schemas use (minLength, minimum, maximum, default, uniqueItems)

Every ported string was verified byte-for-byte against the harness source at port time — full-file diffs for the intent and timeout modules, block diffs for the schema builders, extraction-and-compare for every description constant. Descriptions are prompt surface, so drift is behavior change.

Verification

  • npm test in packages/dev-tools: 42 tests pass — canonical names and sets, intent-first property ordering, required properties, timeout bounds and env resolution, and the stateful/attached description and schema builders
  • npx tsc --noEmit clean
  • Prettier (repo config) clean on all new files
  • CI adds a dev-tools-package-tests job on Node 22.21.0 — pure TypeScript with zero runtime deps, so no matrix and no native tooling

Not in this PR

The agents-side swap (importing @librechat/dev-tools from the harness) comes in a follow-up against the agents repository.

Port the LLM-visible surface of the harness-native coding tools from
@librechat/agents into packages/dev-tools, published as
@librechat/dev-tools: canonical tool names, the JSON schemas and
descriptions for the remote-engine tools (execute_code, bash_tool,
run_tools_with_code, run_tools_with_bash, read_file) and the
local-engine tools (read_file, write_file, edit_file, grep_search,
glob_search, list_directory, compile_check), the intent-label contract
embedded in every schema, the /mnt/data and bash guidance, and the
timeout schema with its environment-resolved defaults.

The package has zero runtime dependencies: everything is plain data and
pure functions, so the agent harness and BYOM provisioning consume the
definitions without the harness owning them. Execution stays
harness-native in @librechat/agents; the definitions describe the
execution environments this service provides.

Ported with export-name parity so the agents-side swap is mechanical;
every ported string was verified byte-for-byte against the harness
source. Tests pin the canonical names, intent-first property ordering,
required properties, and the stateful/attached description builders.
CI runs the package tests on Node 22.21.0.
@danny-avila

Copy link
Copy Markdown
Collaborator

@codex review the latest head

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 28, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-09-28T04:25:02.075436Z f51a8ae Manual request
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f51a8aedc3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

} as const;
}

export const LocalProgrammaticToolCallingDescription = `${ProgrammaticToolCallingDescription}\n\nLocal engine: runs bash by default, or Python when \`lang\` is \`py\` or \`python\`, on the host machine and calls tools through an in-process localhost bridge.`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Match the local default to the inherited Python prompt

When a model omits the optional lang argument, this definition defaults execution to bash, but the inherited ProgrammaticToolCallingDescription and code-parameter description instruct it to emit Python using await, asyncio, and print(). The resulting Python is then interpreted as bash and fails; use runtime-neutral instructions, default to Python, or require an explicit runtime choice.

Useful? React with 👍 / 👎.

```ts
import {
CodeExecutionToolDefinition,
LocalCodingBundleNames,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use the exported bundle-name identifier in the example

The documented root import names LocalCodingBundleNames, but the package exports only LOCAL_CODING_BUNDLE_NAMES. Copying this primary usage example therefore produces a missing-export error instead of compiling; update the example to use the actual exported identifier.

Useful? React with 👍 / 👎.

Comment on lines +104 to +105
- For payloads that may contain quotes, parentheses, backticks, or arbitrary bytes (random/binary data, JSON with embedded quotes, multi-line strings), prefer a quoted-delimiter heredoc over \`echo '…'\`. The heredoc body is not interpreted by the shell, so substituted payloads pass through unchanged.
- Heredoc example: \`wc -c << 'EOF'\\n{{tool0turn0}}\\nEOF\` (the quotes around \`'EOF'\` disable interpolation inside the body).

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Avoid fixed heredoc delimiters for substituted tool output

When tool-output references are enabled and a referenced result contains a line equal to EOF, the recommended fixed-delimiter heredoc terminates at that line even though the delimiter is quoted; the remaining result is then parsed as shell commands. Because prior tool output can be untrusted and this guide is also appended for attached workspaces, such a payload can execute unintended commands or modify persistent project files. Do not describe this form as safe for arbitrary data; use an encoding or a delimiter guaranteed not to occur in the substituted payload.

Useful? React with 👍 / 👎.

Comment on lines +17 to +21
'c',
'cpp',
'java',
'php',
'rs',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict the schema to deployed execution runtimes

On the repository's default service deployment, the runtime registry accepts only bash, js, node, py, and ts (service/src/enum/service.ts and service/src/config.ts), while this schema advertises C, C++, Java, PHP, Rust, Go, D, Fortran, and R and omits the available Node runtime. Selecting one of the advertised-but-unregistered values therefore reaches the service as an unknown runtime; derive this enum from the deployed runtime surface or limit it to the supported aliases.

Useful? React with 👍 / 👎.

Comment on lines +3 to +5
* The local engine reuses the remote schemas (`../execute-code.js`,
* `../bash-tool.js`) and swaps only the descriptions, because the schema
* shape is identical while the semantics (local machine, configured

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Replace remote path guidance in local execution schemas

When consumers combine these local descriptions with the reused remote schemas as directed here, the model still receives parameter-level instructions that prior /mnt/data files are available and that anything needed later must be written under /mnt/data. That conflicts with the local descriptions' persistent project working directory and can cause generated or edited files to be written outside the project instead of into the repository. Provide local schema variants that replace the remote /mnt/data guidance along with the descriptions.

Useful? React with 👍 / 👎.

Comment on lines +100 to +102
...ProgrammaticToolCallingSchema,
properties: {
...ProgrammaticToolCallingSchema.properties,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Return independent nested objects from schema builders

This builder copies only the outer properties map, so its intent, code, and tool_manifest subschemas are the same objects held by ProgrammaticToolCallingSchema and by every other builder result; the bash builder has the same problem. Registering multiple variants can therefore leak validator-added metadata or consumer mutations from one schema into the remote definition and subsequent schemas—the package already notes that LangChain mutates dereferenced subschemas. Clone the nested property schemas when constructing each result.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants