summaryrefslogtreecommitdiffhomepage
path: root/packages
diff options
context:
space:
mode:
authorJorgen Henriksen <[email protected]>2025-12-11 21:38:45 +0100
committerGitHub <[email protected]>2025-12-11 14:38:45 -0600
commit2a9269c3471f95a4c39884e03e56d242854b6b5e (patch)
tree00371e8b1bb167b44f43703b25cca3b413076e01 /packages
parent0efdc3a8a05fa4f78aa8dc7105aebf742aa8866f (diff)
downloadopencode-2a9269c3471f95a4c39884e03e56d242854b6b5e.tar.gz
opencode-2a9269c3471f95a4c39884e03e56d242854b6b5e.zip
add experimental.chat.messages.transform hook (#5207)
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Diffstat (limited to 'packages')
-rw-r--r--packages/opencode/src/session/prompt.ts40
-rw-r--r--packages/plugin/src/index.ts10
2 files changed, 33 insertions, 17 deletions
diff --git a/packages/opencode/src/session/prompt.ts b/packages/opencode/src/session/prompt.ts
index 76c702982..d31153331 100644
--- a/packages/opencode/src/session/prompt.ts
+++ b/packages/opencode/src/session/prompt.ts
@@ -29,7 +29,7 @@ import PROMPT_PLAN from "../session/prompt/plan.txt"
import BUILD_SWITCH from "../session/prompt/build-switch.txt"
import MAX_STEPS from "../session/prompt/max-steps.txt"
import { defer } from "../util/defer"
-import { mergeDeep, pipe } from "remeda"
+import { clone, mergeDeep, pipe } from "remeda"
import { ToolRegistry } from "../tool/registry"
import { Wildcard } from "../util/wildcard"
import { MCP } from "../mcp"
@@ -520,28 +520,33 @@ export namespace SessionPrompt {
})
}
- const messages = [
+ // Deep copy message history so that modifications made by plugins do not
+ // affect the original messages
+ const sessionMessages = clone(
+ msgs.filter((m) => {
+ if (m.info.role !== "assistant" || m.info.error === undefined) {
+ return true
+ }
+ if (
+ MessageV2.AbortedError.isInstance(m.info.error) &&
+ m.parts.some((part) => part.type !== "step-start" && part.type !== "reasoning")
+ ) {
+ return true
+ }
+ return false
+ }),
+ )
+
+ await Plugin.trigger("experimental.chat.messages.transform", {}, { messages: sessionMessages })
+
+ const messages: ModelMessage[] = [
...system.map(
(x): ModelMessage => ({
role: "system",
content: x,
}),
),
- ...MessageV2.toModelMessage(
- msgs.filter((m) => {
- if (m.info.role !== "assistant" || m.info.error === undefined) {
- return true
- }
- if (
- MessageV2.AbortedError.isInstance(m.info.error) &&
- m.parts.some((part) => part.type !== "step-start" && part.type !== "reasoning")
- ) {
- return true
- }
-
- return false
- }),
- ),
+ ...MessageV2.toModelMessage(sessionMessages),
...(isLastStep
? [
{
@@ -551,6 +556,7 @@ export namespace SessionPrompt {
]
: []),
]
+
const result = await processor.process({
onError(error) {
log.error("stream error", {
diff --git a/packages/plugin/src/index.ts b/packages/plugin/src/index.ts
index f00e90482..57ca75d60 100644
--- a/packages/plugin/src/index.ts
+++ b/packages/plugin/src/index.ts
@@ -6,6 +6,7 @@ import type {
Provider,
Permission,
UserMessage,
+ Message,
Part,
Auth,
Config,
@@ -175,6 +176,15 @@ export interface Hooks {
metadata: any
},
) => Promise<void>
+ "experimental.chat.messages.transform"?: (
+ input: {},
+ output: {
+ messages: {
+ info: Message
+ parts: Part[]
+ }[]
+ },
+ ) => Promise<void>
"experimental.text.complete"?: (
input: { sessionID: string; messageID: string; partID: string },
output: { text: string },