index.ts 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. import type {
  2. Event,
  3. createOpencodeClient,
  4. Project,
  5. Model,
  6. Provider,
  7. Permission,
  8. UserMessage,
  9. Message,
  10. Part,
  11. Auth,
  12. Config,
  13. } from "@opencode-ai/sdk"
  14. import type { BunShell } from "./shell"
  15. import { type ToolDefinition } from "./tool"
  16. export * from "./tool"
  17. export type ProviderContext = {
  18. source: "env" | "config" | "custom" | "api"
  19. info: Provider
  20. options: Record<string, any>
  21. }
  22. export type PluginInput = {
  23. client: ReturnType<typeof createOpencodeClient>
  24. project: Project
  25. directory: string
  26. worktree: string
  27. serverUrl: URL
  28. $: BunShell
  29. }
  30. export type Plugin = (input: PluginInput) => Promise<Hooks>
  31. export type AuthHook = {
  32. provider: string
  33. loader?: (auth: () => Promise<Auth>, provider: Provider) => Promise<Record<string, any>>
  34. methods: (
  35. | {
  36. type: "oauth"
  37. label: string
  38. prompts?: Array<
  39. | {
  40. type: "text"
  41. key: string
  42. message: string
  43. placeholder?: string
  44. validate?: (value: string) => string | undefined
  45. condition?: (inputs: Record<string, string>) => boolean
  46. }
  47. | {
  48. type: "select"
  49. key: string
  50. message: string
  51. options: Array<{
  52. label: string
  53. value: string
  54. hint?: string
  55. }>
  56. condition?: (inputs: Record<string, string>) => boolean
  57. }
  58. >
  59. authorize(inputs?: Record<string, string>): Promise<AuthOuathResult>
  60. }
  61. | {
  62. type: "api"
  63. label: string
  64. prompts?: Array<
  65. | {
  66. type: "text"
  67. key: string
  68. message: string
  69. placeholder?: string
  70. validate?: (value: string) => string | undefined
  71. condition?: (inputs: Record<string, string>) => boolean
  72. }
  73. | {
  74. type: "select"
  75. key: string
  76. message: string
  77. options: Array<{
  78. label: string
  79. value: string
  80. hint?: string
  81. }>
  82. condition?: (inputs: Record<string, string>) => boolean
  83. }
  84. >
  85. authorize?(inputs?: Record<string, string>): Promise<
  86. | {
  87. type: "success"
  88. key: string
  89. provider?: string
  90. }
  91. | {
  92. type: "failed"
  93. }
  94. >
  95. }
  96. )[]
  97. }
  98. export type AuthOuathResult = { url: string; instructions: string } & (
  99. | {
  100. method: "auto"
  101. callback(): Promise<
  102. | ({
  103. type: "success"
  104. provider?: string
  105. } & (
  106. | {
  107. refresh: string
  108. access: string
  109. expires: number
  110. accountId?: string
  111. }
  112. | { key: string }
  113. ))
  114. | {
  115. type: "failed"
  116. }
  117. >
  118. }
  119. | {
  120. method: "code"
  121. callback(code: string): Promise<
  122. | ({
  123. type: "success"
  124. provider?: string
  125. } & (
  126. | {
  127. refresh: string
  128. access: string
  129. expires: number
  130. accountId?: string
  131. }
  132. | { key: string }
  133. ))
  134. | {
  135. type: "failed"
  136. }
  137. >
  138. }
  139. )
  140. export interface Hooks {
  141. event?: (input: { event: Event }) => Promise<void>
  142. config?: (input: Config) => Promise<void>
  143. tool?: {
  144. [key: string]: ToolDefinition
  145. }
  146. auth?: AuthHook
  147. /**
  148. * Called when a new message is received
  149. */
  150. "chat.message"?: (
  151. input: {
  152. sessionID: string
  153. agent?: string
  154. model?: { providerID: string; modelID: string }
  155. messageID?: string
  156. variant?: string
  157. },
  158. output: { message: UserMessage; parts: Part[] },
  159. ) => Promise<void>
  160. /**
  161. * Modify parameters sent to LLM
  162. */
  163. "chat.params"?: (
  164. input: { sessionID: string; agent: string; model: Model; provider: ProviderContext; message: UserMessage },
  165. output: { temperature: number; topP: number; topK: number; options: Record<string, any> },
  166. ) => Promise<void>
  167. "chat.headers"?: (
  168. input: { sessionID: string; agent: string; model: Model; provider: ProviderContext; message: UserMessage },
  169. output: { headers: Record<string, string> },
  170. ) => Promise<void>
  171. "permission.ask"?: (input: Permission, output: { status: "ask" | "deny" | "allow" }) => Promise<void>
  172. "command.execute.before"?: (
  173. input: { command: string; sessionID: string; arguments: string },
  174. output: { parts: Part[] },
  175. ) => Promise<void>
  176. "tool.execute.before"?: (
  177. input: { tool: string; sessionID: string; callID: string },
  178. output: { args: any },
  179. ) => Promise<void>
  180. "tool.execute.after"?: (
  181. input: { tool: string; sessionID: string; callID: string },
  182. output: {
  183. title: string
  184. output: string
  185. metadata: any
  186. },
  187. ) => Promise<void>
  188. "experimental.chat.messages.transform"?: (
  189. input: {},
  190. output: {
  191. messages: {
  192. info: Message
  193. parts: Part[]
  194. }[]
  195. },
  196. ) => Promise<void>
  197. "experimental.chat.system.transform"?: (
  198. input: { sessionID?: string; model: Model },
  199. output: {
  200. system: string[]
  201. },
  202. ) => Promise<void>
  203. /**
  204. * Called before session compaction starts. Allows plugins to customize
  205. * the compaction prompt.
  206. *
  207. * - `context`: Additional context strings appended to the default prompt
  208. * - `prompt`: If set, replaces the default compaction prompt entirely
  209. */
  210. "experimental.session.compacting"?: (
  211. input: { sessionID: string },
  212. output: { context: string[]; prompt?: string },
  213. ) => Promise<void>
  214. "experimental.text.complete"?: (
  215. input: { sessionID: string; messageID: string; partID: string },
  216. output: { text: string },
  217. ) => Promise<void>
  218. }