| 1 | // Node strips these erasable types; no compiler or package installation is needed. |
| 2 | // `@deepseek-ai/schemastery` is supplied by the host, not installed. |
| 3 | import Schema from '@deepseek-ai/schemastery' |
| 4 | |
| 5 | type Input = { name?: string } |
| 6 | type Execution = { signal: AbortSignal; callId: string } |
| 7 | type Invocation = { args: string; signal: AbortSignal } |
| 8 | |
| 9 | export const name = 'hello-extension' |
| 10 | export const inject = ['tools', 'commands'] |
| 11 | |
| 12 | // The one setting this example reads. The user sets it in their config.toml: |
| 13 | // |
| 14 | // [plugins."hello-extension".config] |
| 15 | // greeting = "Howdy" |
| 16 | // |
| 17 | // The host checks it against this schema before `apply` runs (a wrong type |
| 18 | // fails activation with the reason) and fills in the default when it is unset. |
| 19 | export const Config = Schema.object({ |
| 20 | greeting: Schema.string().default('Hello'), |
| 21 | }) |
| 22 | |
| 23 | export function apply(ctx: any, config: { greeting: string }) { |
| 24 | ctx.tools.register({ |
| 25 | name: 'hello_greet', |
| 26 | description: 'Return a greeting. This example does not read files or use the network.', |
| 27 | parameters: { |
| 28 | type: 'object', |
| 29 | properties: { name: { type: 'string' } }, |
| 30 | additionalProperties: false, |
| 31 | }, |
| 32 | execute(input: Input, exec: Execution) { |
| 33 | exec.signal.throwIfAborted() |
| 34 | return { greeting: `${config.greeting}, ${input.name ?? 'world'}!`, callId: exec.callId } |
| 35 | }, |
| 36 | }) |
| 37 | |
| 38 | // `/hello-greet [name]`: a slash command the *user* runs. It can only |
| 39 | // answer: text shown in the transcript, or `{ kind: 'submit', prompt }` to |
| 40 | // send a prompt as the user's next message (the model's work after that |
| 41 | // goes through the normal turn and its approvals). |
| 42 | ctx.commands.register({ |
| 43 | name: 'hello-greet', |
| 44 | description: 'Greet someone. This example does not read files or use the network.', |
| 45 | argumentHint: '[name]', |
| 46 | handler(invocation: Invocation) { |
| 47 | invocation.signal.throwIfAborted() |
| 48 | return { kind: 'success', text: `${config.greeting}, ${invocation.args || 'world'}!` } |
| 49 | }, |
| 50 | }) |
| 51 | } |
| 52 |