Skip to content
Merged
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
15 changes: 7 additions & 8 deletions lib/messages/prune.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import type { SessionState, WithParts } from "../state"
import type { Logger } from "../logger"
import type { PluginConfig } from "../config"
import { getLastUserMessage, extractParameterKey, buildToolIdList } from "./utils"
import { loadPrompt } from "../prompt"
import { extractParameterKey, buildToolIdList } from "./utils"
import { getLastUserMessage } from "../shared-utils"
import { UserMessage } from "@opencode-ai/sdk"

const PRUNED_TOOL_OUTPUT_REPLACEMENT = '[Output removed to save context - information superseded or no longer needed]'
const NUDGE_STRING = loadPrompt("nudge")
Expand Down Expand Up @@ -51,7 +53,7 @@ export const insertPruneToolContext = (
}

const lastUserMessage = getLastUserMessage(messages)
if (!lastUserMessage || lastUserMessage.info.role !== 'user') {
if (!lastUserMessage) {
return
}

Expand All @@ -72,10 +74,10 @@ export const insertPruneToolContext = (
sessionID: lastUserMessage.info.sessionID,
role: "user",
time: { created: Date.now() },
agent: lastUserMessage.info.agent || "build",
agent: (lastUserMessage.info as UserMessage).agent || "build",
model: {
providerID: lastUserMessage.info.model.providerID,
modelID: lastUserMessage.info.model.modelID
providerID: (lastUserMessage.info as UserMessage).model.providerID,
modelID: (lastUserMessage.info as UserMessage).model.modelID
}
},
parts: [
Expand Down Expand Up @@ -118,9 +120,6 @@ const pruneToolOutputs = (
if (part.state.status === 'completed') {
part.state.output = PRUNED_TOOL_OUTPUT_REPLACEMENT
}
// if (part.state.status === 'error') {
// part.state.error = PRUNED_TOOL_OUTPUT_REPLACEMENT
// }
}
}
}
34 changes: 0 additions & 34 deletions lib/messages/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { UserMessage } from "@opencode-ai/sdk"
import { Logger } from "../logger"
import type { WithParts } from "../state"

/**
Expand Down Expand Up @@ -73,38 +71,6 @@ export const extractParameterKey = (tool: string, parameters: any): string => {
return paramStr.substring(0, 50)
}

export const getLastUserMessage = (
messages: WithParts[]
): WithParts | null => {
for (let i = messages.length - 1; i >= 0; i--) {
const msg = messages[i]
if (msg.info.role === 'user') {
return msg
}
}
return null
}

export function getCurrentParams(
messages: WithParts[],
logger: Logger
): {
providerId: string | undefined,
modelId: string | undefined,
agent: string | undefined
} {
const userMsg = getLastUserMessage(messages)
if (!userMsg) {
logger.debug("No user message found when determining current params")
return { providerId: undefined, modelId: undefined, agent: undefined }
}
const agent: string = (userMsg.info as UserMessage).agent
const providerId: string | undefined = (userMsg.info as UserMessage).model.providerID
const modelId: string | undefined = (userMsg.info as UserMessage).model.modelID

return { providerId, modelId, agent }
}

export function buildToolIdList(messages: WithParts[]): string[] {
const toolIds: string[] = []
for (const msg of messages) {
Expand Down
13 changes: 13 additions & 0 deletions lib/shared-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { WithParts } from "./state"

export const getLastUserMessage = (
messages: WithParts[]
): WithParts | null => {
for (let i = messages.length - 1; i >= 0; i--) {
const msg = messages[i]
if (msg.info.role === 'user') {
return msg
}
}
return null
}
4 changes: 2 additions & 2 deletions lib/state/state.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import type { SessionState, ToolParameterEntry, WithParts } from "./types"
import type { Logger } from "../logger"
import { loadSessionState } from "./persistence"
import { getLastUserMessage } from "../messages/utils"
import { isSubAgentSession } from "../utils"
import { isSubAgentSession } from "./utils"
import { getLastUserMessage } from "../shared-utils"

export const checkSession = async (
client: any,
Expand Down
8 changes: 8 additions & 0 deletions lib/state/utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export async function isSubAgentSession(client: any, sessionID: string): Promise<boolean> {
try {
const result = await client.session.get({ path: { id: sessionID } })
return !!result.data?.parentID
} catch (error: any) {
return false
}
}
2 changes: 1 addition & 1 deletion lib/strategies/deduplication.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { PluginConfig } from "../config"
import { Logger } from "../logger"
import type { SessionState, WithParts } from "../state"
import { calculateTokensSaved } from "../utils"
import { buildToolIdList } from "../messages/utils"
import { calculateTokensSaved } from "./utils"

/**
* Deduplication strategy - prunes older tool calls that have identical
Expand Down
3 changes: 1 addition & 2 deletions lib/strategies/on-idle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,9 @@ import type { Logger } from "../logger"
import type { PluginConfig } from "../config"
import { buildAnalysisPrompt } from "../prompt"
import { selectModel, ModelInfo } from "../model-selector"
import { calculateTokensSaved } from "../utils"
import { getCurrentParams } from "../messages/utils"
import { saveSessionState } from "../state/persistence"
import { sendUnifiedNotification } from "../ui/notification"
import { calculateTokensSaved, getCurrentParams } from "./utils"

export interface OnIdleResult {
prunedCount: number
Expand Down
6 changes: 3 additions & 3 deletions lib/strategies/prune-tool.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { tool } from "@opencode-ai/plugin"
import type { SessionState, ToolParameterEntry, WithParts } from "../state"
import type { PluginConfig } from "../config"
import { getCurrentParams, buildToolIdList } from "../messages/utils"
import { calculateTokensSaved } from "../utils"
import { buildToolIdList } from "../messages/utils"
import { PruneReason, sendUnifiedNotification } from "../ui/notification"
import { formatPruningResultForTool } from "../ui/display-utils"
import { formatPruningResultForTool } from "../ui/utils"
import { ensureSessionInitialized } from "../state"
import { saveSessionState } from "../state/persistence"
import type { Logger } from "../logger"
import { loadPrompt } from "../prompt"
import { calculateTokensSaved, getCurrentParams } from "./utils"

/** Tool description loaded from prompts/tool.txt */
const TOOL_DESCRIPTION = loadPrompt("tool")
Expand Down
41 changes: 24 additions & 17 deletions lib/utils.ts → lib/strategies/utils.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
import { WithParts } from "./state"
import { WithParts } from "../state"
import { UserMessage } from "@opencode-ai/sdk"
import { Logger } from "../logger"
import { encode } from 'gpt-tokenizer'
import { getLastUserMessage } from "../shared-utils"

export function getCurrentParams(
messages: WithParts[],
logger: Logger
): {
providerId: string | undefined,
modelId: string | undefined,
agent: string | undefined
} {
const userMsg = getLastUserMessage(messages)
if (!userMsg) {
logger.debug("No user message found when determining current params")
return { providerId: undefined, modelId: undefined, agent: undefined }
}
const agent: string = (userMsg.info as UserMessage).agent
const providerId: string | undefined = (userMsg.info as UserMessage).model.providerID
const modelId: string | undefined = (userMsg.info as UserMessage).model.modelID

return { providerId, modelId, agent }
}

/**
* Estimates token counts for a batch of texts using gpt-tokenizer.
Expand Down Expand Up @@ -47,19 +70,3 @@ export const calculateTokensSaved = (
return 0
}
}

export function formatTokenCount(tokens: number): string {
if (tokens >= 1000) {
return `${(tokens / 1000).toFixed(1)}K`.replace('.0K', 'K') + ' tokens'
}
return tokens.toString() + ' tokens'
}

export async function isSubAgentSession(client: any, sessionID: string): Promise<boolean> {
try {
const result = await client.session.get({ path: { id: sessionID } })
return !!result.data?.parentID
} catch (error: any) {
return false
}
}
3 changes: 1 addition & 2 deletions lib/ui/notification.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { Logger } from "../logger"
import type { SessionState } from "../state"
import { formatTokenCount } from "../utils"
import { formatPrunedItemsList } from "./display-utils"
import { formatPrunedItemsList, formatTokenCount } from "./utils"
import { ToolParameterEntry } from "../state"
import { PluginConfig } from "../config"

Expand Down
7 changes: 7 additions & 0 deletions lib/ui/display-utils.ts → lib/ui/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { ToolParameterEntry } from "../state"
import { extractParameterKey } from "../messages/utils"

export function formatTokenCount(tokens: number): string {
if (tokens >= 1000) {
return `${(tokens / 1000).toFixed(1)}K`.replace('.0K', 'K') + ' tokens'
}
return tokens.toString() + ' tokens'
}

export function truncate(str: string, maxLen: number = 60): string {
if (str.length <= maxLen) return str
return str.slice(0, maxLen - 3) + '...'
Expand Down