xyne-plugin 1.2.24 → 1.2.27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/hooks.ts +47 -60
- package/src/index.ts +33 -6
- package/src/tool.ts +51 -12
package/package.json
CHANGED
package/src/hooks.ts
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Plugin hook type definitions.
|
|
3
|
+
*
|
|
4
|
+
* A plugin is a function that receives context about the current workspace
|
|
5
|
+
* and returns a bag of hooks the host can call at various extension points.
|
|
6
|
+
*
|
|
7
|
+
* Pattern: `Plugin = (input) => Promise<Hooks>`
|
|
8
|
+
*/
|
|
9
|
+
|
|
1
10
|
import type { ToolDefinition } from "./tool"
|
|
2
11
|
|
|
3
12
|
// ─── Simplified types for hook signatures ───────────────────────────────────
|
|
4
|
-
// These are minimal versions of internal types — just enough for plugin authors
|
|
5
|
-
// to work with hook parameters.
|
|
6
13
|
|
|
7
14
|
/** Model descriptor passed to chat hooks. */
|
|
8
15
|
export interface ModelSpec {
|
|
9
|
-
/** Model identifier, e.g. "claude-opus-4-6" */
|
|
10
16
|
id: string
|
|
11
|
-
/** Provider identifier, e.g. "anthropic" */
|
|
12
17
|
providerID: string
|
|
13
|
-
/** Human-readable name */
|
|
14
18
|
name: string
|
|
15
19
|
[key: string]: unknown
|
|
16
20
|
}
|
|
@@ -31,8 +35,6 @@ export interface ProviderInfo {
|
|
|
31
35
|
models: Record<string, { name: string; contextLength: number; maxOutputTokens: number; [key: string]: unknown }>
|
|
32
36
|
}
|
|
33
37
|
|
|
34
|
-
// ─── Message & Part types for hook signatures ────────────────────────────────
|
|
35
|
-
|
|
36
38
|
/** Token usage breakdown. */
|
|
37
39
|
export interface TokenInfo {
|
|
38
40
|
input: number
|
|
@@ -42,58 +44,29 @@ export interface TokenInfo {
|
|
|
42
44
|
reasoning: number
|
|
43
45
|
}
|
|
44
46
|
|
|
45
|
-
/**
|
|
46
|
-
export type MessageError =
|
|
47
|
-
| { name: "AuthError"; providerID: string; message: string }
|
|
48
|
-
| { name: "APIError"; message: string; statusCode?: number; isRetryable: boolean }
|
|
49
|
-
| { name: "ContextOverflowError"; message: string }
|
|
50
|
-
| { name: "AbortedError"; message: string }
|
|
51
|
-
| { name: "OutputLengthError" }
|
|
52
|
-
| { name: "StructuredOutputError"; message: string; retries: number }
|
|
53
|
-
| { name: "Unknown"; message: string }
|
|
54
|
-
|
|
55
|
-
/** A message in the session (user or assistant turn). */
|
|
47
|
+
/** Message info passed to hooks. */
|
|
56
48
|
export interface MessageInfo {
|
|
57
49
|
id: string
|
|
58
50
|
sessionID: string
|
|
59
51
|
role: "user" | "assistant"
|
|
60
52
|
created: number
|
|
61
53
|
completed?: number
|
|
62
|
-
parentID?: string
|
|
63
54
|
agentID?: string
|
|
64
55
|
modelID?: string
|
|
65
56
|
providerID?: string
|
|
66
|
-
path?: { cwd: string; root: string }
|
|
67
|
-
finish?: string
|
|
68
|
-
error?: MessageError
|
|
69
|
-
cost?: number
|
|
70
57
|
tokens?: TokenInfo
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
structured?: unknown
|
|
74
|
-
summary?: string
|
|
58
|
+
cost?: number
|
|
59
|
+
[key: string]: unknown
|
|
75
60
|
}
|
|
76
61
|
|
|
77
|
-
/**
|
|
78
|
-
export
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
export type PartInfo =
|
|
86
|
-
| { type: "text"; id: string; messageID: string; sessionID: string; text: string; startTime: number; endTime?: number; metadata?: Record<string, unknown>; synthetic?: boolean; ignored?: boolean }
|
|
87
|
-
| { type: "reasoning"; id: string; messageID: string; sessionID: string; text: string; startTime: number; endTime?: number; metadata?: Record<string, unknown> }
|
|
88
|
-
| { type: "tool"; id: string; messageID: string; sessionID: string; callID: string; tool: string; state: ToolState }
|
|
89
|
-
| { type: "step-start"; id: string; messageID: string; sessionID: string }
|
|
90
|
-
| { type: "step-finish"; id: string; messageID: string; sessionID: string; reason: string; tokens?: TokenInfo; cost?: number }
|
|
91
|
-
| { type: "retry"; id: string; messageID: string; sessionID: string; attempt: number; error: MessageError; time: { created: number } }
|
|
92
|
-
| { type: "compaction"; id: string; messageID: string; sessionID: string; auto: boolean; overflow?: boolean }
|
|
93
|
-
| { type: "subtask"; id: string; messageID: string; sessionID: string; prompt: string; description: string; agent: string; model?: { providerID: string; modelID: string }; command?: string }
|
|
94
|
-
| { type: "patch"; id: string; messageID: string; sessionID: string; hash: string; files: string[] }
|
|
95
|
-
| { type: "media"; id: string; messageID: string; sessionID: string; mime: string; filename?: string; url: string }
|
|
96
|
-
| { type: "agent"; id: string; messageID: string; sessionID: string; name: string }
|
|
62
|
+
/** Part info passed to hooks. */
|
|
63
|
+
export interface PartInfo {
|
|
64
|
+
id: string
|
|
65
|
+
messageID: string
|
|
66
|
+
sessionID: string
|
|
67
|
+
type: string
|
|
68
|
+
[key: string]: unknown
|
|
69
|
+
}
|
|
97
70
|
|
|
98
71
|
// ─── Plugin agent types ─────────────────────────────────────────────────────
|
|
99
72
|
|
|
@@ -102,7 +75,9 @@ export type PartInfo =
|
|
|
102
75
|
*
|
|
103
76
|
* Plugin agents follow the same Agent.Info shape but use a reduced surface:
|
|
104
77
|
* - `name` is derived from the record key
|
|
105
|
-
* - `
|
|
78
|
+
* - `native` is always false
|
|
79
|
+
* - `tools` is a record of ToolDefinitions (same format as plugin tools)
|
|
80
|
+
* that are converted to Tool.Info[] at registration time
|
|
106
81
|
* - `permission` accepts a simple string map instead of a raw Permission.Ruleset
|
|
107
82
|
*/
|
|
108
83
|
export interface PluginAgentDef {
|
|
@@ -114,12 +89,14 @@ export interface PluginAgentDef {
|
|
|
114
89
|
/** Tools scoped to this agent. These are added on top of session tools. */
|
|
115
90
|
tools?: Record<string, ToolDefinition>
|
|
116
91
|
/**
|
|
117
|
-
* If true, this agent ONLY has access to its own `tools` (built-in session tools are excluded).
|
|
92
|
+
* If true, this agent ONLY has access to its own `tools` (plus built-in session tools are excluded).
|
|
118
93
|
* If false (default), the agent's tools are merged with the session's tool set.
|
|
119
94
|
*/
|
|
120
95
|
isolatedTools?: boolean
|
|
121
96
|
/** Permission overrides. Keys are tool IDs or "*", values are "allow" | "deny" | "ask". */
|
|
122
97
|
permission?: Record<string, "allow" | "deny" | "ask" | Record<string, "allow" | "deny" | "ask">>
|
|
98
|
+
/** Subagent names this agent can spawn via the Task tool. If unset, all subagents are available. */
|
|
99
|
+
agents?: string[]
|
|
123
100
|
maxSteps?: number
|
|
124
101
|
color?: string
|
|
125
102
|
hidden?: boolean
|
|
@@ -134,11 +111,11 @@ export type PluginInput = {
|
|
|
134
111
|
worktree: string
|
|
135
112
|
appName: string
|
|
136
113
|
/** SDK client — available for plugins that need session/message/tool APIs. */
|
|
137
|
-
client?: unknown
|
|
114
|
+
client?: unknown | undefined
|
|
138
115
|
/** Base URL for the local server (if running). */
|
|
139
|
-
serverUrl?: URL
|
|
116
|
+
serverUrl?: URL | undefined
|
|
140
117
|
/** Bun shell for running commands. */
|
|
141
|
-
$?: unknown
|
|
118
|
+
$?: unknown | undefined
|
|
142
119
|
}
|
|
143
120
|
|
|
144
121
|
export type Plugin = (input: PluginInput) => Promise<Hooks>
|
|
@@ -206,7 +183,7 @@ export type AuthMethod =
|
|
|
206
183
|
label: string
|
|
207
184
|
/** Message shown in the TUI while authorize() runs (default: "Connecting..."). */
|
|
208
185
|
pendingMessage?: string
|
|
209
|
-
/** Hint shown below the pending message. */
|
|
186
|
+
/** Hint shown below the pending message (e.g. "Waiting for approval... · esc cancel"). */
|
|
210
187
|
pendingHint?: string
|
|
211
188
|
prompts?: AuthPrompt[]
|
|
212
189
|
/** Plugin handles the entire auth flow. UI shows pendingMessage while this runs. */
|
|
@@ -218,6 +195,10 @@ export type AuthMethod =
|
|
|
218
195
|
|
|
219
196
|
/**
|
|
220
197
|
* Options returned by an auth loader to configure the provider SDK.
|
|
198
|
+
*
|
|
199
|
+
* Standard SDK options (baseURL, apiKey, fetch) are merged into the SDK factory call.
|
|
200
|
+
* The optional `getModel` callback lets the loader control model selection
|
|
201
|
+
* (e.g. routing gpt-5 to a responses API vs chat API).
|
|
221
202
|
*/
|
|
222
203
|
export interface AuthLoaderResult {
|
|
223
204
|
baseURL?: string
|
|
@@ -234,6 +215,7 @@ export type AuthHook = {
|
|
|
234
215
|
* Called after auth succeeds to configure the provider SDK.
|
|
235
216
|
* Receives a getter for the auth entry and the provider info.
|
|
236
217
|
* Returns SDK options (baseURL, apiKey, fetch, getModel, etc.)
|
|
218
|
+
* that are merged into the provider's SDK configuration.
|
|
237
219
|
*/
|
|
238
220
|
loader?: (auth: () => Promise<unknown>, provider: unknown) => Promise<AuthLoaderResult>
|
|
239
221
|
methods: AuthMethod[]
|
|
@@ -279,13 +261,13 @@ export interface Hooks {
|
|
|
279
261
|
|
|
280
262
|
/** Mutate LLM sampling parameters before a chat request. */
|
|
281
263
|
"chat.params"?: (
|
|
282
|
-
input: { sessionID: string; agent: string; model: ModelSpec; provider?: ProviderInfo; message?: MessageInfo },
|
|
264
|
+
input: { sessionID: string; agent: string; model: ModelSpec; provider?: ProviderInfo | undefined; message?: MessageInfo | undefined },
|
|
283
265
|
output: { temperature?: number; topP?: number; topK?: number; options?: Record<string, unknown> },
|
|
284
266
|
) => Promise<void>
|
|
285
267
|
|
|
286
268
|
/** Inject extra HTTP headers into the provider request. */
|
|
287
269
|
"chat.headers"?: (
|
|
288
|
-
input: { sessionID: string; agent: string; model: ModelSpec; provider?: ProviderInfo; message?: MessageInfo },
|
|
270
|
+
input: { sessionID: string; agent: string; model: ModelSpec; provider?: ProviderInfo | undefined; message?: MessageInfo | undefined },
|
|
289
271
|
output: { headers: Record<string, string> },
|
|
290
272
|
) => Promise<void>
|
|
291
273
|
|
|
@@ -313,15 +295,20 @@ export interface Hooks {
|
|
|
313
295
|
output: { parts: PartInfo[] },
|
|
314
296
|
) => Promise<void>
|
|
315
297
|
|
|
316
|
-
/**
|
|
298
|
+
/**
|
|
299
|
+
* Modify tool args before execution, or block the tool call entirely.
|
|
300
|
+
*
|
|
301
|
+
* To block: set `output.blocked = true` and optionally `output.reason = "why"`.
|
|
302
|
+
* The reason is returned to the LLM as the tool output so it can adapt.
|
|
303
|
+
*/
|
|
317
304
|
"tool.execute.before"?: (
|
|
318
|
-
input: { tool: string; sessionID: string; callID: string },
|
|
319
|
-
output: { args: unknown },
|
|
305
|
+
input: { tool: string; sessionID: string; callID: string; agent: string; isSubagent: boolean },
|
|
306
|
+
output: { args: unknown; blocked?: boolean; reason?: string },
|
|
320
307
|
) => Promise<void>
|
|
321
308
|
|
|
322
309
|
/** Modify tool output after execution. */
|
|
323
310
|
"tool.execute.after"?: (
|
|
324
|
-
input: { tool: string; sessionID: string; callID: string; args: unknown },
|
|
311
|
+
input: { tool: string; sessionID: string; callID: string; agent: string; isSubagent: boolean; args: unknown },
|
|
325
312
|
output: { title: string; output: string; metadata: unknown },
|
|
326
313
|
) => Promise<void>
|
|
327
314
|
|
|
@@ -340,7 +327,7 @@ export interface Hooks {
|
|
|
340
327
|
/** Customise context preservation during session compaction. */
|
|
341
328
|
"session.compacting"?: (
|
|
342
329
|
input: { sessionID: string },
|
|
343
|
-
output: { context: string[]; prompt?: string },
|
|
330
|
+
output: { context: string[]; prompt?: string | undefined },
|
|
344
331
|
) => Promise<void>
|
|
345
332
|
|
|
346
333
|
/** Text completion hook — modify or provide text completions. */
|
package/src/index.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* xyne
|
|
2
|
+
* @xyne/plugin — SDK for writing Xyne plugins.
|
|
3
|
+
*
|
|
4
|
+
* Self-contained — no @tui/agent-core dependency.
|
|
5
|
+
* All types are defined locally in hooks.ts and tool.ts.
|
|
3
6
|
*
|
|
4
7
|
* @example
|
|
5
8
|
* ```ts
|
|
6
|
-
* import { type Plugin, tool, z } from "xyne
|
|
9
|
+
* import { type Plugin, tool, z } from "@xyne/plugin"
|
|
7
10
|
*
|
|
8
11
|
* const plugin: Plugin = async ({ directory }) => ({
|
|
9
12
|
* tool: {
|
|
@@ -21,12 +24,36 @@
|
|
|
21
24
|
* ```
|
|
22
25
|
*/
|
|
23
26
|
|
|
24
|
-
// Plugin types
|
|
25
|
-
export type {
|
|
27
|
+
// Plugin types (from hooks.ts — self-contained, no workspace imports)
|
|
28
|
+
export type {
|
|
29
|
+
Plugin,
|
|
30
|
+
PluginInput,
|
|
31
|
+
Hooks,
|
|
32
|
+
PluginAgentDef,
|
|
33
|
+
AuthMethod,
|
|
34
|
+
AuthPrompt,
|
|
35
|
+
AuthOAuthResult,
|
|
36
|
+
AuthHook,
|
|
37
|
+
AuthLoaderResult,
|
|
38
|
+
ModelSpec,
|
|
39
|
+
Message,
|
|
40
|
+
CredentialSource,
|
|
41
|
+
ProviderInfo,
|
|
42
|
+
TokenInfo,
|
|
43
|
+
MessageInfo,
|
|
44
|
+
PartInfo,
|
|
45
|
+
} from "./hooks"
|
|
26
46
|
|
|
27
|
-
// Tool authoring
|
|
47
|
+
// Tool authoring (from tool.ts — self-contained)
|
|
28
48
|
export { tool } from "./tool"
|
|
29
|
-
export type {
|
|
49
|
+
export type {
|
|
50
|
+
ToolDefinition,
|
|
51
|
+
ToolContext,
|
|
52
|
+
ToolAuthConfig,
|
|
53
|
+
ServiceCredentials,
|
|
54
|
+
ToolAttachment,
|
|
55
|
+
PluginToolResult,
|
|
56
|
+
} from "./tool"
|
|
30
57
|
|
|
31
58
|
// Zod re-export for convenience
|
|
32
59
|
export { z } from "zod"
|
package/src/tool.ts
CHANGED
|
@@ -63,6 +63,13 @@ export type ToolContext = {
|
|
|
63
63
|
abort: AbortSignal
|
|
64
64
|
metadata(input: { title?: string; metadata?: { [key: string]: unknown } }): void
|
|
65
65
|
ask(input: AskInput): Promise<void>
|
|
66
|
+
/**
|
|
67
|
+
* Ask the user a free-text question and wait for their reply.
|
|
68
|
+
* Pauses the agent loop until the user submits an answer.
|
|
69
|
+
* Returns a string[][] — one string[] per question containing the selected/typed answers.
|
|
70
|
+
* Pass options: [] to render a plain free-text input with no predefined choices.
|
|
71
|
+
*/
|
|
72
|
+
askQuestion(input: AskQuestionInput): Promise<string[][]>
|
|
66
73
|
/**
|
|
67
74
|
* Service credentials for this tool's declared `auth` service.
|
|
68
75
|
* Populated automatically before execute() when the tool has a `ToolAuthConfig`
|
|
@@ -85,8 +92,46 @@ type AskInput = {
|
|
|
85
92
|
metadata: { [key: string]: unknown }
|
|
86
93
|
}
|
|
87
94
|
|
|
95
|
+
type QuestionOption = {
|
|
96
|
+
label: string
|
|
97
|
+
description: string
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
type AskQuestionInput = {
|
|
101
|
+
questions: Array<{
|
|
102
|
+
question: string
|
|
103
|
+
/** Very short label shown in the tab bar (max 30 chars). Defaults to the first 30 chars of question. */
|
|
104
|
+
header?: string
|
|
105
|
+
/** Predefined choices. Pass [] or omit for a plain free-text input. */
|
|
106
|
+
options?: QuestionOption[]
|
|
107
|
+
multiple?: boolean
|
|
108
|
+
}>
|
|
109
|
+
}
|
|
110
|
+
|
|
88
111
|
// ─── Tool definition ────────────────────────────────────────────────────────
|
|
89
112
|
|
|
113
|
+
/**
|
|
114
|
+
* Define a custom tool. Use this in .agent/tool/*.ts files or in plugin packages.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```ts
|
|
118
|
+
* import { tool } from "@tui/agent-core/plugin"
|
|
119
|
+
*
|
|
120
|
+
* export default tool({
|
|
121
|
+
* description: "Does something useful",
|
|
122
|
+
* args: {
|
|
123
|
+
* query: tool.schema.string().describe("Search query"),
|
|
124
|
+
* },
|
|
125
|
+
* async execute(args, ctx) {
|
|
126
|
+
* return "result"
|
|
127
|
+
* },
|
|
128
|
+
* })
|
|
129
|
+
* ```
|
|
130
|
+
*/
|
|
131
|
+
/**
|
|
132
|
+
* The wide storage type used in Hooks.tool and internal registries.
|
|
133
|
+
* Plugin authors don't construct this directly — use the `tool()` factory.
|
|
134
|
+
*/
|
|
90
135
|
export interface ToolAttachment {
|
|
91
136
|
type: "file"
|
|
92
137
|
mime: string
|
|
@@ -96,10 +141,6 @@ export interface ToolAttachment {
|
|
|
96
141
|
|
|
97
142
|
export type PluginToolResult = string | { text: string; attachments: ToolAttachment[] }
|
|
98
143
|
|
|
99
|
-
/**
|
|
100
|
-
* The wide storage type used in Hooks.tool and internal registries.
|
|
101
|
-
* Plugin authors don't construct this directly — use the `tool()` factory.
|
|
102
|
-
*/
|
|
103
144
|
export interface ToolDefinition {
|
|
104
145
|
description: string
|
|
105
146
|
args: Record<string, z.ZodType>
|
|
@@ -108,19 +149,17 @@ export interface ToolDefinition {
|
|
|
108
149
|
}
|
|
109
150
|
|
|
110
151
|
/**
|
|
111
|
-
* Define a custom tool.
|
|
152
|
+
* Define a custom tool. Args are inferred from the zod schema so
|
|
153
|
+
* `execute` gets strongly-typed parameters.
|
|
112
154
|
*
|
|
113
155
|
* @example
|
|
114
156
|
* ```ts
|
|
115
|
-
* import { tool, z } from "xyne-plugin"
|
|
116
|
-
*
|
|
117
157
|
* export default tool({
|
|
118
|
-
* description: "
|
|
119
|
-
* args: {
|
|
120
|
-
* query: z.string().describe("Search query"),
|
|
121
|
-
* },
|
|
158
|
+
* description: "Does something useful",
|
|
159
|
+
* args: { query: tool.schema.string().describe("Search query") },
|
|
122
160
|
* async execute(args, ctx) {
|
|
123
|
-
*
|
|
161
|
+
* args.query // ← string
|
|
162
|
+
* return "result"
|
|
124
163
|
* },
|
|
125
164
|
* })
|
|
126
165
|
* ```
|