index.ts 5.3 KB

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