Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions packages/opencode/src/session/llm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,12 +66,13 @@ export namespace LLM {
])
// TODO: move this to a proper hook
const isOpenaiOauth = provider.id === "openai" && auth?.type === "oauth"
const tools = await resolveTools(input)

const system: string[] = []
system.push(
[
// use agent prompt otherwise provider prompt
...(input.agent.prompt ? [input.agent.prompt] : SystemPrompt.provider(input.model)),
...(input.agent.prompt ? [input.agent.prompt] : SystemPrompt.provider(input.model, { tools: Object.keys(tools) })),
// any custom prompt passed into this call
...input.system,
// any custom prompt from last user message
Expand Down Expand Up @@ -166,8 +167,6 @@ export namespace LLM {
? undefined
: ProviderTransform.maxOutputTokens(input.model)

const tools = await resolveTools(input)

// LiteLLM and some Anthropic proxies require the tools parameter to be present
// when message history contains tool calls, even if no tools are being used.
// Add a dummy tool that is never called to satisfy this validation.
Expand Down
51 changes: 3 additions & 48 deletions packages/opencode/src/session/prompt/anthropic.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,57 +20,12 @@ When the user directly asks about OpenCode (eg. "can OpenCode do...", "does Open
# Professional objectivity
Prioritize technical accuracy and truthfulness over validating the user's beliefs. Focus on facts and problem-solving, providing direct, objective technical info without any unnecessary superlatives, praise, or emotional validation. It is best for the user if OpenCode honestly applies the same rigorous standards to all ideas and disagrees when necessary, even if it may not be what the user wants to hear. Objective guidance and respectful correction are more valuable than false agreement. Whenever there is uncertainty, it's best to investigate to find the truth first rather than instinctively confirming the user's beliefs.

# Task Management
You have access to the TodoWrite tools to help you manage and plan tasks. Use these tools VERY frequently to ensure that you are tracking your tasks and giving the user visibility into your progress.
These tools are also EXTREMELY helpful for planning tasks, and for breaking down larger complex tasks into smaller steps. If you do not use this tool when planning, you may forget to do important tasks - and that is unacceptable.

It is critical that you mark todos as completed as soon as you are done with a task. Do not batch up multiple tasks before marking them as completed.

Examples:

<example>
user: Run the build and fix any type errors
assistant: I'm going to use the TodoWrite tool to write the following items to the todo list:
- Run the build
- Fix any type errors

I'm now going to run the build using Bash.

Looks like I found 10 type errors. I'm going to use the TodoWrite tool to write 10 items to the todo list.

marking the first todo as in_progress

Let me start working on the first item...

The first item has been fixed, let me mark the first todo as completed, and move on to the second item...
..
..
</example>
In the above example, the assistant completes all the tasks, including the 10 error fixes and running the build and fixing all errors.

<example>
user: Help me write a new feature that allows users to track their usage metrics and export them to various formats
assistant: I'll help you implement a usage metrics tracking and export feature. Let me first use the TodoWrite tool to plan this task.
Adding the following todos to the todo list:
1. Research existing metrics tracking in the codebase
2. Design the metrics collection system
3. Implement core metrics tracking functionality
4. Create export functionality for different formats

Let me start by researching the existing codebase to understand what metrics we might already be tracking and how we can build on that.

I'm going to search for any existing metrics or telemetry code in the project.

I've found some existing telemetry code. Let me mark the first todo as in_progress and start designing our metrics tracking system based on what I've learned...

[Assistant continues implementing the feature step by step, marking todos as in_progress and completed as they go]
</example>
{{TODO_TASK_MANAGEMENT}}


# Doing tasks
The user will primarily request you perform software engineering tasks. This includes solving bugs, adding new functionality, refactoring code, explaining code, and more. For these tasks the following steps are recommended:
-
- Use the TodoWrite tool to plan the task if required
{{TODO_TASK_PLANNING}}

- Tool results and user messages may include <system-reminder> tags. <system-reminder> tags contain useful information and reminders. They are automatically added by the system, and bear no direct relation to the specific tool results or user messages in which they appear.

Expand All @@ -93,7 +48,7 @@ user: What is the codebase structure?
assistant: [Uses the Task tool]
</example>

IMPORTANT: Always use the TodoWrite tool to plan and track tasks throughout the conversation.
{{TODO_ALWAYS_USE}}

# Code References

Expand Down
74 changes: 67 additions & 7 deletions packages/opencode/src/session/system.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,74 @@ import { Permission } from "@/permission"
import { Skill } from "@/skill"

export namespace SystemPrompt {
export function provider(model: Provider.Model) {
const TODO_TASK_MANAGEMENT = `# Task Management
You have access to the TodoWrite tools to help you manage and plan tasks. Use these tools VERY frequently to ensure that you are tracking your tasks and giving the user visibility into your progress.
These tools are also EXTREMELY helpful for planning tasks, and for breaking down larger complex tasks into smaller steps. If you do not use this tool when planning, you may forget to do important tasks - and that is unacceptable.

It is critical that you mark todos as completed as soon as you are done with a task. Do not batch up multiple tasks before marking them as completed.

Examples:

<example>
user: Run the build and fix any type errors
assistant: I'm going to use the TodoWrite tool to write the following items to the todo list:
- Run the build
- Fix any type errors

I'm now going to run the build using Bash.

Looks like I found 10 type errors. I'm going to use the TodoWrite tool to write 10 items to the todo list.

marking the first todo as in_progress

Let me start working on the first item...

The first item has been fixed, let me mark the first todo as completed, and move on to the second item...
..
..
</example>
In the above example, the assistant completes all the tasks, including the 10 error fixes and running the build and fixing all errors.

<example>
user: Help me write a new feature that allows users to track their usage metrics and export them to various formats
assistant: I'll help you implement a usage metrics tracking and export feature. Let me first use the TodoWrite tool to plan this task.
Adding the following todos to the todo list:
1. Research existing metrics tracking in the codebase
2. Design the metrics collection system
3. Implement core metrics tracking functionality
4. Create export functionality for different formats

Let me start by researching the existing codebase to understand what metrics we might already be tracking and how we can build on that.

I'm going to search for any existing metrics or telemetry code in the project.

I've found some existing telemetry code. Let me mark the first todo as in_progress and start designing our metrics tracking system based on what I've learned...

[Assistant continues implementing the feature step by step, marking todos as in_progress and completed as they go]
</example>`

const TODO_TASK_PLANNING = "- Use the TodoWrite tool to plan the task if required"
const TODO_ALWAYS_USE = "IMPORTANT: Always use the TodoWrite tool to plan and track tasks throughout the conversation."

function applyToolAvailability(prompt: string, tools: string[] = []) {
if (!prompt.includes("{{TODO_")) return prompt
const hasTodoWrite = tools.includes("todowrite")
return prompt
.replace("{{TODO_TASK_MANAGEMENT}}", hasTodoWrite ? TODO_TASK_MANAGEMENT : "")
.replace("{{TODO_TASK_PLANNING}}", hasTodoWrite ? TODO_TASK_PLANNING : "")
.replace("{{TODO_ALWAYS_USE}}", hasTodoWrite ? TODO_ALWAYS_USE : "")
.replace(/\n{3,}/g, "\n\n")
}

export function provider(model: Provider.Model, input?: { tools?: string[] }) {
const tools = input?.tools ?? []
if (model.api.id.includes("gpt-4") || model.api.id.includes("o1") || model.api.id.includes("o3"))
return [PROMPT_BEAST]
if (model.api.id.includes("gpt")) return [PROMPT_CODEX]
if (model.api.id.includes("gemini-")) return [PROMPT_GEMINI]
if (model.api.id.includes("claude")) return [PROMPT_ANTHROPIC]
if (model.api.id.toLowerCase().includes("trinity")) return [PROMPT_TRINITY]
return [PROMPT_DEFAULT]
return [applyToolAvailability(PROMPT_BEAST, tools)]
if (model.api.id.includes("gpt")) return [applyToolAvailability(PROMPT_CODEX, tools)]
if (model.api.id.includes("gemini-")) return [applyToolAvailability(PROMPT_GEMINI, tools)]
if (model.api.id.includes("claude")) return [applyToolAvailability(PROMPT_ANTHROPIC, tools)]
if (model.api.id.toLowerCase().includes("trinity")) return [applyToolAvailability(PROMPT_TRINITY, tools)]
return [applyToolAvailability(PROMPT_DEFAULT, tools)]
}

export async function environment(model: Provider.Model) {
Expand Down
16 changes: 16 additions & 0 deletions packages/opencode/test/session/system.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test"
import path from "path"
import { Agent } from "../../src/agent/agent"
import { Instance } from "../../src/project/instance"
import { ProviderID } from "../../src/provider/schema"
import { SystemPrompt } from "../../src/session/system"
import { tmpdir } from "../fixture/fixture"

Expand Down Expand Up @@ -56,4 +57,19 @@ description: ${description}
process.env.OPENCODE_TEST_HOME = home
}
})

test("anthropic prompt only includes todo instructions when todowrite is available", () => {
const model = {
providerID: ProviderID.make("anthropic"),
api: { id: "claude-sonnet-4-5" },
} as any

const withoutTodo = SystemPrompt.provider(model, { tools: [] }).join("\n")
expect(withoutTodo).not.toContain("Use these tools VERY frequently")
expect(withoutTodo).not.toContain("Always use the TodoWrite tool")

const withTodo = SystemPrompt.provider(model, { tools: ["todowrite", "todoread"] }).join("\n")
expect(withTodo).toContain("Use these tools VERY frequently")
expect(withTodo).toContain("Always use the TodoWrite tool")
})
})
Loading