Skip to content

Instantly share code, notes, and snippets.

@ShamanicArts
Created January 22, 2026 00:53
Show Gist options
  • Select an option

  • Save ShamanicArts/b2ae98c0f51ff2e6f7cebc93fa37978f to your computer and use it in GitHub Desktop.

Select an option

Save ShamanicArts/b2ae98c0f51ff2e6f7cebc93fa37978f to your computer and use it in GitHub Desktop.
Dialog API test plugin for opencode PR #9910
/**
* Dialog Test Plugin
*
* Template plugin demonstrating various dialog patterns for plugin developers.
* Each handler shows a different approach to using the dialog API.
*/
import type { Plugin } from "@opencode-ai/plugin"
export const dialogTestPlugin: Plugin = async ({ client, dialog }) => {
return {
config: async (input) => {
input.command ??= {}
input.command["dialog-select"] = {
template:
"[DIALOG_SELECT_COMMAND]\n\nThe user wants to select a color from a dialog. Wait for their selection.\n$ARGUMENTS",
description: "Test dialog with LLM response",
}
input.command["dialog-test"] = {
template: "[DIALOG_TEST_COMMAND]",
description: "Test dialog without LLM response",
}
input.command["dialog-drill"] = {
template: "[DIALOG_DRILL_COMMAND]",
description: "Test multi-level drill-down dialog",
}
input.command["dialog-inline-test"] = {
template: "[DIALOG_INLINE_TEST_COMMAND]",
description: "Test inline dialog without LLM response",
}
input.command["dialog-inline-select"] = {
template:
"[DIALOG_INLINE_SELECT_COMMAND]\n\nThe user wants to select a color from an inline dialog. Wait for their selection.\n$ARGUMENTS",
description: "Test inline dialog with LLM response",
}
input.command["dialog-confirm"] = {
template: "[DIALOG_CONFIRM_COMMAND]",
description: "Test confirmation dialog",
}
input.command["dialog-alert"] = {
template: "[DIALOG_ALERT_COMMAND]",
description: "Test alert dialog",
}
input.command["dialog-prompt"] = {
template: "[DIALOG_PROMPT_COMMAND]",
description: "Test prompt dialog",
}
input.command["dialog-prompt-default"] = {
template: "[DIALOG_PROMPT_DEFAULT_COMMAND]",
description: "Test prompt dialog with default value",
}
},
"chat.message": async (input, output) => {
const text = output.parts.find((p) => p.type === "text")?.text ?? ""
// Pattern A: Modal dialog that modifies message, then sends to LLM
// Use case: Let user make a choice, then have LLM respond to that choice
if (text.includes("[DIALOG_SELECT_COMMAND]")) {
const result = await dialog.show({
type: "select",
mode: "modal",
title: "Pick a Color",
options: [
{ value: "red", title: "Red", description: "A warm color" },
{ value: "blue", title: "Blue", description: "A cool color" },
{ value: "green", title: "Green", description: "Nature's color" },
],
})
if (result.dismissed) return
// Test: If user selects "blue", switch to plan agent
if (result.value === "blue") {
output.message.agent = "plan"
}
// Modify message - LLM will process this
const textPart = output.parts.find((p) => p.type === "text")
if (textPart && "text" in textPart) {
textPart.text = `User selected color: ${result.value}. Please acknowledge their choice.`
}
return
}
// Pattern B: Modal dialog that bypasses LLM entirely
// Use case: Quick actions that don't need AI processing
if (text.includes("[DIALOG_TEST_COMMAND]")) {
const result = await dialog.show({
type: "select",
mode: "modal",
title: "Pick a Color (No LLM)",
options: [
{ value: "red", title: "Red" },
{ value: "blue", title: "Blue" },
{ value: "green", title: "Green" },
],
})
if (result.dismissed) throw new Error("__DIALOG_TEST_HANDLED__")
// Inject response directly (bypasses LLM)
await client.session.prompt({
path: { id: input.sessionID },
body: {
noReply: true,
agent: input.agent,
model: input.model,
parts: [
{
type: "text",
text: `You selected: ${result.value}`,
ignored: true,
},
],
},
})
// Throw to abort - LLM never runs
throw new Error("__DIALOG_TEST_HANDLED__")
}
// Pattern C: Multi-level drill-down dialog
// Use case: Hierarchical navigation (category -> item)
if (text.includes("[DIALOG_DRILL_COMMAND]")) {
const categoryResult = await dialog.show({
type: "select",
mode: "modal",
title: "Pick a Category",
options: [
{ value: "colors", title: "Colors" },
{ value: "shapes", title: "Shapes" },
],
})
if (categoryResult.dismissed) throw new Error("__DIALOG_DRILL_HANDLED__")
const category = categoryResult.value
const options =
category === "colors"
? [
{ value: "red", title: "Red" },
{ value: "blue", title: "Blue" },
{ value: "green", title: "Green" },
]
: [
{ value: "circle", title: "Circle" },
{ value: "square", title: "Square" },
{ value: "triangle", title: "Triangle" },
]
const itemResult = await dialog.show({
type: "select",
mode: "modal",
title: category === "colors" ? "Pick a Color" : "Pick a Shape",
options,
})
if (itemResult.dismissed) throw new Error("__DIALOG_DRILL_HANDLED__")
await client.session.prompt({
path: { id: input.sessionID },
body: {
noReply: true,
agent: input.agent,
model: input.model,
parts: [{ type: "text", text: `You selected: ${itemResult.value} from ${category}`, ignored: true }],
},
})
throw new Error("__DIALOG_DRILL_HANDLED__")
}
// Pattern D: Inline dialog (appears in session area, not modal overlay)
// Use case: Non-blocking selection that keeps context visible
if (text.includes("[DIALOG_INLINE_TEST_COMMAND]")) {
const result = await dialog.show({
type: "select",
mode: "inline",
title: "Pick a Color (Inline, No LLM)",
options: [
{ value: "red", title: "Red" },
{ value: "blue", title: "Blue" },
{ value: "green", title: "Green" },
],
})
if (result.dismissed) throw new Error("__DIALOG_INLINE_TEST_HANDLED__")
await client.session.prompt({
path: { id: input.sessionID },
body: {
noReply: true,
agent: input.agent,
model: input.model,
parts: [{ type: "text", text: `You selected (inline): ${result.value}`, ignored: true }],
},
})
throw new Error("__DIALOG_INLINE_TEST_HANDLED__")
}
// Pattern E: Inline dialog that modifies message for LLM
// Use case: Inline selection that feeds into AI response
if (text.includes("[DIALOG_INLINE_SELECT_COMMAND]")) {
const result = await dialog.show({
type: "select",
mode: "inline",
title: "Pick a Color (Inline)",
options: [
{ value: "red", title: "Red", description: "A warm color" },
{ value: "blue", title: "Blue", description: "A cool color" },
{ value: "green", title: "Green", description: "Nature's color" },
],
})
if (result.dismissed) throw new Error("__DIALOG_INLINE_SELECT_HANDLED__")
const textPart = output.parts.find((p) => p.type === "text")
if (textPart && "text" in textPart) {
textPart.text = `User selected color (via inline dialog): ${result.value}. Please acknowledge their choice.`
}
return
}
// Pattern F: Confirmation dialog
// Use case: Yes/No decisions
if (text.includes("[DIALOG_CONFIRM_COMMAND]")) {
await dialog.show({
type: "confirm",
mode: "modal",
title: "Confirm Action",
message: "Are you sure you want to proceed with this action?",
})
throw new Error("__DIALOG_CONFIRM_HANDLED__")
}
// Pattern G: Alert dialog
// Use case: Informational messages that require acknowledgment
if (text.includes("[DIALOG_ALERT_COMMAND]")) {
await dialog.show({
type: "alert",
mode: "modal",
title: "Important Notice",
message: "This is an important message that requires acknowledgment.",
})
throw new Error("__DIALOG_ALERT_HANDLED__")
}
// Pattern H: Prompt dialog
// Use case: Get text input from user
if (text.includes("[DIALOG_PROMPT_COMMAND]")) {
const result = await dialog.show({
type: "prompt",
mode: "modal",
title: "Enter Value",
message: "Please enter a value below:",
placeholder: "Type something...",
})
if (result.dismissed) throw new Error("__DIALOG_PROMPT_HANDLED__")
await client.session.prompt({
path: { id: input.sessionID },
body: {
noReply: true,
agent: input.agent,
model: input.model,
parts: [
{
type: "text",
text: `User entered: "${result.value}"`,
ignored: true,
},
],
},
})
throw new Error("__DIALOG_PROMPT_HANDLED__")
}
// Pattern I: Prompt dialog with default value
// Use case: Get text input with pre-filled value
if (text.includes("[DIALOG_PROMPT_DEFAULT_COMMAND]")) {
const result = await dialog.show({
type: "prompt",
mode: "modal",
title: "Edit Value",
message: "Edit default value below:",
placeholder: "Type something...",
defaultValue: "Default Text",
})
if (result.dismissed) throw new Error("__DIALOG_PROMPT_DEFAULT_HANDLED__")
await client.session.prompt({
path: { id: input.sessionID },
body: {
noReply: true,
agent: input.agent,
model: input.model,
parts: [
{
type: "text",
text: `User entered: "${result.value}"`,
ignored: true,
},
],
},
})
throw new Error("__DIALOG_PROMPT_DEFAULT_HANDLED__")
}
},
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment