opencode: add custom tools support

Adds support for custom tools - user-defined functions that the LLM can
call during conversations. Custom tools work alongside opencode's built-in
tools and are configured through the new `tools` option.

The configuration follows the same pattern as other opencode settings like
`agents` and `commands`, supporting:
- Inline TypeScript content
- Individual file paths
- Bulk directory imports
This commit is contained in:
Thierry Delafontaine
2026-01-04 13:19:56 +01:00
committed by Austin Horstman
parent 081234b704
commit b1b1c68033
11 changed files with 213 additions and 0 deletions

View File

@@ -0,0 +1,12 @@
import { tool } from "@opencode-ai/plugin"
export default tool({
description: "Make API requests to external services",
args: {
endpoint: tool.schema.string().describe("API endpoint to call"),
method: tool.schema.string().describe("HTTP method"),
},
async execute(args) {
return `Called ${args.method} ${args.endpoint}`
},
})

View File

@@ -0,0 +1,11 @@
import { tool } from "@opencode-ai/plugin"
export default tool({
description: "Query the project database",
args: {
query: tool.schema.string().describe("SQL query to execute"),
},
async execute(args) {
return `Executed query: ${args.query}`
},
})

View File

@@ -10,6 +10,9 @@
opencode-commands-path = ./commands-path.nix;
opencode-agents-bulk-directory = ./agents-bulk-directory.nix;
opencode-commands-bulk-directory = ./commands-bulk-directory.nix;
opencode-tools-inline = ./tools-inline.nix;
opencode-tools-path = ./tools-path.nix;
opencode-tools-bulk-directory = ./tools-bulk-directory.nix;
opencode-mixed-content = ./mixed-content.nix;
opencode-skills-inline = ./skills-inline.nix;
opencode-skills-path = ./skills-path.nix;

View File

@@ -15,6 +15,22 @@
'';
path-agent = ./test-agent.md;
};
tools = {
inline-tool = ''
import { tool } from "@opencode-ai/plugin"
export default tool({
description: "Inline tool definition",
args: {
input: tool.schema.string().describe("Test input"),
},
async execute(args) {
return `Processed: ''${args.input}`
},
})
'';
path-tool = ./test-tool.ts;
};
skills = {
inline-skill = ''
---
@@ -54,6 +70,13 @@
assertFileContent home-files/.config/opencode/agent/path-agent.md \
${./test-agent.md}
# Tools
assertFileExists home-files/.config/opencode/tool/inline-tool.ts
assertFileExists home-files/.config/opencode/tool/path-tool.ts
assertFileContent home-files/.config/opencode/tool/path-tool.ts \
${./test-tool.ts}
# Skills
assertFileExists home-files/.config/opencode/skill/inline-skill/SKILL.md
assertFileExists home-files/.config/opencode/skill/path-skill/SKILL.md

View File

@@ -0,0 +1,11 @@
import { tool } from "@opencode-ai/plugin"
export default tool({
description: "Test tool for unit testing",
args: {
input: tool.schema.string().describe("Test input parameter"),
},
async execute(args) {
return `Processed: ${args.input}`
},
})

View File

@@ -0,0 +1,15 @@
{
programs.opencode = {
enable = true;
tools = ./tools-bulk;
};
nmt.script = ''
assertFileExists home-files/.config/opencode/tool/database-query.ts
assertFileExists home-files/.config/opencode/tool/api-client.ts
assertFileContent home-files/.config/opencode/tool/database-query.ts \
${./tools-bulk/database-query.ts}
assertFileContent home-files/.config/opencode/tool/api-client.ts \
${./tools-bulk/api-client.ts}
'';
}

View File

@@ -0,0 +1,12 @@
import { tool } from "@opencode-ai/plugin"
export default tool({
description: "Make API requests to external services",
args: {
endpoint: tool.schema.string().describe("API endpoint to call"),
method: tool.schema.string().describe("HTTP method"),
},
async execute(args) {
return `Called ${args.method} ${args.endpoint}`
},
})

View File

@@ -0,0 +1,11 @@
import { tool } from "@opencode-ai/plugin"
export default tool({
description: "Query the project database",
args: {
query: tool.schema.string().describe("SQL query to execute"),
},
async execute(args) {
return `Executed query: ${args.query}`
},
})

View File

@@ -0,0 +1,42 @@
{
programs.opencode = {
enable = true;
tools = {
database-query = ''
import { tool } from "@opencode-ai/plugin"
export default tool({
description: "Query the project database",
args: {
query: tool.schema.string().describe("SQL query to execute"),
},
async execute(args) {
return `Executed query: ''${args.query}`
},
})
'';
api-client = ''
import { tool } from "@opencode-ai/plugin"
export default tool({
description: "Make API requests to external services",
args: {
endpoint: tool.schema.string().describe("API endpoint to call"),
method: tool.schema.string().describe("HTTP method"),
},
async execute(args) {
return `Called ''${args.method} ''${args.endpoint}`
},
})
'';
};
};
nmt.script = ''
assertFileExists home-files/.config/opencode/tool/database-query.ts
assertFileExists home-files/.config/opencode/tool/api-client.ts
assertFileContent home-files/.config/opencode/tool/database-query.ts \
${./database-query-tool.ts}
assertFileContent home-files/.config/opencode/tool/api-client.ts \
${./api-client-tool.ts}
'';
}

View File

@@ -0,0 +1,13 @@
{
programs.opencode = {
enable = true;
tools = {
test-tool = ./test-tool.ts;
};
};
nmt.script = ''
assertFileExists home-files/.config/opencode/tool/test-tool.ts
assertFileContent home-files/.config/opencode/tool/test-tool.ts \
${./test-tool.ts}
'';
}