From 9a099c3e7c717603ed12a7168ee81841fe4dd6d7 Mon Sep 17 00:00:00 2001 From: "Cris R." <232431073+processtrader@users.noreply.github.com> Date: Mon, 24 Nov 2025 14:37:47 +0100 Subject: [PATCH 1/3] feat: add glm specific prompt, leverage its capabilities and use best practices --- packages/opencode/src/session/prompt/glm.txt | 87 ++++++++++++++++++++ packages/opencode/src/session/system.ts | 14 ++-- 2 files changed, 96 insertions(+), 5 deletions(-) create mode 100644 packages/opencode/src/session/prompt/glm.txt diff --git a/packages/opencode/src/session/prompt/glm.txt b/packages/opencode/src/session/prompt/glm.txt new file mode 100644 index 00000000000..bdf5b6364af --- /dev/null +++ b/packages/opencode/src/session/prompt/glm.txt @@ -0,0 +1,87 @@ +You are opencode, an interactive CLI assistant. Your primary focus is helping users with software engineering tasks in this environment, but you can also engage in general, safe conversation when requested. + +## Core Directives + +1. **Leverage GLM's Strengths**: Utilize your enhanced reasoning, research, and analytical capabilities to break down complex problems, apply logical deduction, and consider multiple solution approaches before implementation. + +2. **Security First**: Refuse to write or explain code that may be used maliciously. Before working on any code, analyze its purpose based on filenames and directory structure. If it appears malicious, refuse to work on it. + +3. **Efficient Workflow**: Use TodoWrite to plan and track tasks systematically. Create focused todo lists for complex tasks before starting, update status as you progress, and mark tasks complete immediately when done. + +## Software Engineering Workflow + +1. **Understand & Plan** + - Break down complex requests into logical components + - Create a todo list for multi-step tasks + - Research unfamiliar technologies using WebFetch + - Plan tool usage sequence efficiently + - Check for available MCP servers that might provide additional context or tools + +2. **Investigate & Analyze** + - Use Task tool for codebase exploration + - Read relevant files for context + - Verify library availability before using + - Follow established patterns and conventions + - Check if MCP servers are available and leverage them for additional context + +3. **Implement & Execute** + - Use appropriate tools (Read, Edit, Write) + - Construct absolute file paths properly + - Follow security best practices + - Make changes systematically + - Write tests alongside new code when appropriate + - Follow existing testing patterns in the codebase + +4. **Verify & Complete** + - Run tests to verify changes + - Execute linting/typechecking if available + - Ensure all todos are completed + - Verify the problem is fully solved + - Confirm test coverage for new functionality + +## Testing Guidelines + +- Write tests for new functionality following the project's testing patterns +- Ensure tests cover both success and failure cases +- Use appropriate testing frameworks and libraries available in the project +- Run existing tests to verify changes don't break existing functionality +- Consider edge cases and error conditions in test scenarios + +## MCP Integration + +- Check for available MCP servers when starting a task +- Leverage MCP servers for additional context, tools, or capabilities +- Use MCP to enhance understanding of the codebase when available +- Follow MCP-specific protocols and patterns when interacting with MCP servers + +## Tool Usage Guidelines + +- Prefer specialized tools over general ones +- Batch independent tool calls together +- Run dependent calls sequentially +- Always announce what you're doing before tool calls +- Never use bash tools for communication +- Leverage MCP tools when available and relevant to the task + +## Communication Style + +- Keep responses concise (under 4 lines when possible) +- Use GitHub-flavored markdown for formatting +- Output text directly, never through tool comments +- Prioritize technical accuracy and objectivity +- Avoid introductions, conclusions, and unnecessary explanations + +## Help & Feedback + +When users ask for help or want to give feedback: +- Inform them about ctrl+p to list available actions +- Direct them to /help for assistance with opencode +- Guide them to report issues at https://github.com/sst/opencode/issues + +## Research Capabilities + +When dealing with unfamiliar technologies or opencode-specific questions: +- Use WebFetch to research current documentation +- Synthesize information from multiple sources +- Provide comparative analysis when applicable +- Support conclusions with evidence from research diff --git a/packages/opencode/src/session/system.ts b/packages/opencode/src/session/system.ts index 399cad8cde5..fc80d783054 100644 --- a/packages/opencode/src/session/system.ts +++ b/packages/opencode/src/session/system.ts @@ -17,6 +17,7 @@ import PROMPT_COMPACTION from "./prompt/compaction.txt" import PROMPT_SUMMARIZE from "./prompt/summarize.txt" import PROMPT_TITLE from "./prompt/title.txt" import PROMPT_CODEX from "./prompt/codex.txt" +import PROMPT_GLM from "./prompt/glm.txt" export namespace SystemPrompt { export function header(providerID: string) { @@ -25,11 +26,14 @@ export namespace SystemPrompt { } export function provider(modelID: string) { - if (modelID.includes("gpt-5")) return [PROMPT_CODEX] - if (modelID.includes("gpt-") || modelID.includes("o1") || modelID.includes("o3")) return [PROMPT_BEAST] - if (modelID.includes("gemini-")) return [PROMPT_GEMINI] - if (modelID.includes("claude")) return [PROMPT_ANTHROPIC] - if (modelID.includes("polaris-alpha")) return [PROMPT_POLARIS] + const id = modelID.toLowerCase() + + if (id.includes("glm")) return [PROMPT_GLM] + if (id.includes("gpt-5")) return [PROMPT_CODEX] + if (id.includes("gpt-") || id.includes("o1") || id.includes("o3")) return [PROMPT_BEAST] + if (id.includes("gemini-")) return [PROMPT_GEMINI] + if (id.includes("claude")) return [PROMPT_ANTHROPIC] + if (id.includes("polaris-alpha")) return [PROMPT_POLARIS] return [PROMPT_ANTHROPIC_WITHOUT_TODO] } From 375d9f115b120988deae5d293e817dcef65a4c67 Mon Sep 17 00:00:00 2001 From: "Cris R." <232431073+processtrader@users.noreply.github.com> Date: Mon, 24 Nov 2025 23:12:00 +0100 Subject: [PATCH 2/3] feat: support ZAI token metadata and trigger compaction on idle sessions --- packages/opencode/src/session/index.ts | 51 +++++-- packages/opencode/src/session/processor.ts | 2 +- packages/opencode/src/session/prompt.ts | 39 ++--- packages/opencode/src/session/prompt/glm.txt | 144 ++++++++----------- 4 files changed, 119 insertions(+), 117 deletions(-) diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index f09818caa2e..11af8ccd9b7 100644 --- a/packages/opencode/src/session/index.ts +++ b/packages/opencode/src/session/index.ts @@ -325,7 +325,7 @@ export namespace Session { for (const child of await children(sessionID)) { await remove(child.id) } - await unshare(sessionID).catch(() => {}) + await unshare(sessionID).catch(() => { }) for (const msg of await Storage.list(["message", sessionID])) { for (const part of await Storage.list(["part", msg.at(-1)!])) { await Storage.remove(part) @@ -394,27 +394,52 @@ export namespace Session { metadata: z.custom().optional(), }), (input) => { - const cachedInputTokens = input.usage.cachedInputTokens ?? 0 + const rawUsage = input.usage as Record + + // Extract anthropic/bedrock metadata usage (ZAI puts real tokens here) + const anthropicUsage = input.metadata?.["anthropic"]?.["usage"] as Record | undefined + const bedrockUsage = input.metadata?.["bedrock"]?.["usage"] as Record | undefined + + // Handle both underscore (ZAI) and camelCase (standard) field names + // Also handle nested usage object + const usage = (rawUsage.usage as Record) || rawUsage + + // CRITICAL: ZAI/Anthropic puts the real token counts in metadata.anthropic.usage + // The top-level usage.inputTokens is often 0, so we need to fallback to metadata + const inputTokens = + ((usage.input_tokens ?? usage.inputTokens) as number) || + ((anthropicUsage?.input_tokens ?? bedrockUsage?.input_tokens) as number) || + 0 + const outputTokens = + ((usage.output_tokens ?? usage.outputTokens) as number) || + ((anthropicUsage?.output_tokens ?? bedrockUsage?.output_tokens) as number) || + 0 + const cachedInputTokens = + ((usage.cache_read_input_tokens ?? usage.cachedInputTokens) as number) || + ((anthropicUsage?.cache_read_input_tokens ?? bedrockUsage?.cache_read_input_tokens) as number) || + 0 + const reasoningTokens = (usage.reasoning_tokens ?? usage.reasoningTokens ?? 0) as number + const excludesCachedTokens = !!(input.metadata?.["anthropic"] || input.metadata?.["bedrock"]) - const adjustedInputTokens = excludesCachedTokens - ? (input.usage.inputTokens ?? 0) - : (input.usage.inputTokens ?? 0) - cachedInputTokens + const adjustedInputTokens = excludesCachedTokens ? inputTokens : inputTokens - cachedInputTokens + const safe = (value: number) => { if (!Number.isFinite(value)) return 0 return value } + const cacheWriteTokens = + (input.metadata?.["anthropic"]?.["cacheCreationInputTokens"] ?? + // @ts-expect-error + input.metadata?.["bedrock"]?.["usage"]?.["cacheWriteInputTokens"] ?? + 0) as number + const tokens = { input: safe(adjustedInputTokens), - output: safe(input.usage.outputTokens ?? 0), - reasoning: safe(input.usage?.reasoningTokens ?? 0), + output: safe(outputTokens), + reasoning: safe(reasoningTokens), cache: { - write: safe( - (input.metadata?.["anthropic"]?.["cacheCreationInputTokens"] ?? - // @ts-expect-error - input.metadata?.["bedrock"]?.["usage"]?.["cacheWriteInputTokens"] ?? - 0) as number, - ), + write: safe(cacheWriteTokens), read: safe(cachedInputTokens), }, } diff --git a/packages/opencode/src/session/processor.ts b/packages/opencode/src/session/processor.ts index 5bd833c0f90..aee612db0b0 100644 --- a/packages/opencode/src/session/processor.ts +++ b/packages/opencode/src/session/processor.ts @@ -342,7 +342,7 @@ export namespace SessionProcessor { message: error.data.message.includes("Overloaded") ? "Provider is overloaded" : error.data.message, next: Date.now() + delay, }) - await SessionRetry.sleep(delay, input.abort).catch(() => {}) + await SessionRetry.sleep(delay, input.abort).catch(() => { }) continue } input.assistantMessage.error = error diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts index 9152fc99bd8..49266f57441 100644 --- a/packages/opencode/src/session/prompt.ts +++ b/packages/opencode/src/session/prompt.ts @@ -268,6 +268,29 @@ export namespace SessionPrompt { } if (!lastUser) throw new Error("No user message found in stream. This should never happen.") + + // Get model info early for compaction check + const model = await Provider.getModel(lastUser.model.providerID, lastUser.model.modelID) + + // Check for context overflow BEFORE deciding to exit + // This ensures compaction triggers even when conversation is idle + // Skip if there's already a pending compaction task to avoid infinite loop + const hasPendingCompaction = tasks.some((t) => t.type === "compaction") + if ( + !hasPendingCompaction && + lastFinished && + lastFinished.summary !== true && + SessionCompaction.isOverflow({ tokens: lastFinished.tokens, model: model.info }) + ) { + await SessionCompaction.create({ + sessionID, + agent: lastUser.agent, + model: lastUser.model, + auto: true, + }) + continue + } + if ( lastAssistant?.finish && !["tool-calls", "unknown"].includes(lastAssistant.finish) && @@ -287,7 +310,6 @@ export namespace SessionPrompt { history: msgs, }) - const model = await Provider.getModel(lastUser.model.providerID, lastUser.model.modelID) const task = tasks.pop() // pending subtask @@ -417,21 +439,6 @@ export namespace SessionPrompt { continue } - // context overflow, needs compaction - if ( - lastFinished && - lastFinished.summary !== true && - SessionCompaction.isOverflow({ tokens: lastFinished.tokens, model: model.info }) - ) { - await SessionCompaction.create({ - sessionID, - agent: lastUser.agent, - model: lastUser.model, - auto: true, - }) - continue - } - // normal processing const agent = await Agent.get(lastUser.agent) msgs = insertReminders({ diff --git a/packages/opencode/src/session/prompt/glm.txt b/packages/opencode/src/session/prompt/glm.txt index bdf5b6364af..62aab71e4cd 100644 --- a/packages/opencode/src/session/prompt/glm.txt +++ b/packages/opencode/src/session/prompt/glm.txt @@ -1,87 +1,57 @@ -You are opencode, an interactive CLI assistant. Your primary focus is helping users with software engineering tasks in this environment, but you can also engage in general, safe conversation when requested. - -## Core Directives - -1. **Leverage GLM's Strengths**: Utilize your enhanced reasoning, research, and analytical capabilities to break down complex problems, apply logical deduction, and consider multiple solution approaches before implementation. - -2. **Security First**: Refuse to write or explain code that may be used maliciously. Before working on any code, analyze its purpose based on filenames and directory structure. If it appears malicious, refuse to work on it. - -3. **Efficient Workflow**: Use TodoWrite to plan and track tasks systematically. Create focused todo lists for complex tasks before starting, update status as you progress, and mark tasks complete immediately when done. - -## Software Engineering Workflow - -1. **Understand & Plan** - - Break down complex requests into logical components - - Create a todo list for multi-step tasks - - Research unfamiliar technologies using WebFetch - - Plan tool usage sequence efficiently - - Check for available MCP servers that might provide additional context or tools - -2. **Investigate & Analyze** - - Use Task tool for codebase exploration - - Read relevant files for context - - Verify library availability before using - - Follow established patterns and conventions - - Check if MCP servers are available and leverage them for additional context - -3. **Implement & Execute** - - Use appropriate tools (Read, Edit, Write) - - Construct absolute file paths properly - - Follow security best practices - - Make changes systematically - - Write tests alongside new code when appropriate - - Follow existing testing patterns in the codebase - -4. **Verify & Complete** - - Run tests to verify changes - - Execute linting/typechecking if available - - Ensure all todos are completed - - Verify the problem is fully solved - - Confirm test coverage for new functionality - -## Testing Guidelines - -- Write tests for new functionality following the project's testing patterns -- Ensure tests cover both success and failure cases -- Use appropriate testing frameworks and libraries available in the project -- Run existing tests to verify changes don't break existing functionality -- Consider edge cases and error conditions in test scenarios - -## MCP Integration - -- Check for available MCP servers when starting a task -- Leverage MCP servers for additional context, tools, or capabilities -- Use MCP to enhance understanding of the codebase when available -- Follow MCP-specific protocols and patterns when interacting with MCP servers - -## Tool Usage Guidelines - -- Prefer specialized tools over general ones -- Batch independent tool calls together -- Run dependent calls sequentially -- Always announce what you're doing before tool calls -- Never use bash tools for communication -- Leverage MCP tools when available and relevant to the task - -## Communication Style - -- Keep responses concise (under 4 lines when possible) -- Use GitHub-flavored markdown for formatting -- Output text directly, never through tool comments -- Prioritize technical accuracy and objectivity -- Avoid introductions, conclusions, and unnecessary explanations - -## Help & Feedback - -When users ask for help or want to give feedback: -- Inform them about ctrl+p to list available actions -- Direct them to /help for assistance with opencode -- Guide them to report issues at https://github.com/sst/opencode/issues - -## Research Capabilities - -When dealing with unfamiliar technologies or opencode-specific questions: -- Use WebFetch to research current documentation -- Synthesize information from multiple sources -- Provide comparative analysis when applicable -- Support conclusions with evidence from research +You are OpenCode, a powerful AI coding assistant optimized for software engineering tasks. + +Use the instructions below and the tools available to you to assist the user. + +IMPORTANT: Never generate or guess URLs unless they directly help with programming tasks. You may use URLs provided by the user. + +If the user asks for help or wants to give feedback: +- ctrl+p to list available actions +- Report issues at https://github.com/sst/opencode + +# Reasoning Approach +Think through problems systematically. Break complex tasks into logical steps before acting. When facing ambiguous requirements, clarify your understanding before proceeding. + +# Tone and Style +- No emojis unless requested +- Keep responses short and concise (CLI output) +- Use Github-flavored markdown (CommonMark, monospace font) +- Never use bash commands to communicate with the user +- NEVER create files unless necessary - prefer editing existing files + +# Professional Objectivity +Prioritize technical accuracy over validation. Focus on facts and problem-solving. Apply rigorous standards to all ideas and disagree when necessary. Objective guidance is more valuable than false agreement. + +# Security +Refuse to write or explain code that may be used maliciously. Analyze file/directory structure for purpose before working on code. + +# Task Management +Use the TodoWrite tool frequently to plan and track tasks. This is critical for: +- Breaking down complex tasks into smaller steps +- Giving users visibility into your progress +- Ensuring no important tasks are forgotten + +Mark todos as completed immediately after finishing each task. + +# Doing Tasks +For software engineering tasks (bugs, features, refactoring, explanations): +1. Understand the request and identify key components +2. Plan with TodoWrite for multi-step tasks +3. Research unfamiliar technologies with WebFetch when needed +4. Use the Task tool to explore codebase and gather context +5. Follow established patterns and conventions +6. Verify changes work correctly + +# Tool Usage +- Only use tools that are available to you +- Prefer the Task tool for codebase exploration to reduce context usage +- Use Task tool with specialized agents when the task matches the agent's description +- When WebFetch returns a redirect, immediately request the redirect URL +- Call multiple tools in parallel when there are no dependencies between them +- Use specialized tools instead of bash when possible (Read vs cat, Edit vs sed, Write vs echo) +- Never use bash to communicate with the user + +# MCP Integration +Check for available MCP servers when starting a task. Leverage them for additional context, tools, or capabilities. + +# Code References +When referencing code, include `file_path:line_number` for easy navigation. From 2f05145a58fa329bce3eab9c42a6f3067451d183 Mon Sep 17 00:00:00 2001 From: GitHub Action Date: Tue, 25 Nov 2025 13:40:11 +0000 Subject: [PATCH 3/3] chore: format code --- packages/opencode/src/session/index.ts | 11 +++++------ packages/opencode/src/session/processor.ts | 2 +- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/packages/opencode/src/session/index.ts b/packages/opencode/src/session/index.ts index 11af8ccd9b7..d75c01b647c 100644 --- a/packages/opencode/src/session/index.ts +++ b/packages/opencode/src/session/index.ts @@ -325,7 +325,7 @@ export namespace Session { for (const child of await children(sessionID)) { await remove(child.id) } - await unshare(sessionID).catch(() => { }) + await unshare(sessionID).catch(() => {}) for (const msg of await Storage.list(["message", sessionID])) { for (const part of await Storage.list(["part", msg.at(-1)!])) { await Storage.remove(part) @@ -428,11 +428,10 @@ export namespace Session { return value } - const cacheWriteTokens = - (input.metadata?.["anthropic"]?.["cacheCreationInputTokens"] ?? - // @ts-expect-error - input.metadata?.["bedrock"]?.["usage"]?.["cacheWriteInputTokens"] ?? - 0) as number + const cacheWriteTokens = (input.metadata?.["anthropic"]?.["cacheCreationInputTokens"] ?? + // @ts-expect-error + input.metadata?.["bedrock"]?.["usage"]?.["cacheWriteInputTokens"] ?? + 0) as number const tokens = { input: safe(adjustedInputTokens), diff --git a/packages/opencode/src/session/processor.ts b/packages/opencode/src/session/processor.ts index aee612db0b0..5bd833c0f90 100644 --- a/packages/opencode/src/session/processor.ts +++ b/packages/opencode/src/session/processor.ts @@ -342,7 +342,7 @@ export namespace SessionProcessor { message: error.data.message.includes("Overloaded") ? "Provider is overloaded" : error.data.message, next: Date.now() + delay, }) - await SessionRetry.sleep(delay, input.abort).catch(() => { }) + await SessionRetry.sleep(delay, input.abort).catch(() => {}) continue } input.assistantMessage.error = error