@ericsanchezok/synergy-plugin 2.2.1 → 2.3.0
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/README.md +69 -6
- package/dist/display.d.ts +15 -0
- package/dist/display.js +0 -0
- package/dist/example.js +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +15 -9
- package/dist/index.d.ts +123 -3
- package/dist/manifest.d.ts +48 -0
- package/dist/manifest.js +45 -1
- package/dist/tool.d.ts +24 -1
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -12,11 +12,9 @@ Plugin authors should use `@ericsanchezok/synergy-plugin-kit` and this SDK from
|
|
|
12
12
|
bunx @ericsanchezok/synergy-plugin-kit create my-plugin --template tool-ui
|
|
13
13
|
cd my-plugin
|
|
14
14
|
bun install
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
bun run sign my-plugin-0.1.0.synergy-plugin.tgz
|
|
19
|
-
bun run publish:market
|
|
15
|
+
synergy-plugin dev
|
|
16
|
+
synergy-plugin validate --runtime-discovery
|
|
17
|
+
synergy-plugin publish-market
|
|
20
18
|
```
|
|
21
19
|
|
|
22
20
|
During local development you can also install directly:
|
|
@@ -63,6 +61,68 @@ export default plugin
|
|
|
63
61
|
|
|
64
62
|
There is no compatibility layer for legacy descriptor shapes. `plugin.json.name` must match `plugin.id`; Synergy fails validation or loading if they differ.
|
|
65
63
|
|
|
64
|
+
## Tool Results And Attachments
|
|
65
|
+
|
|
66
|
+
Tools can return user-facing files through `attachments`. Use the generated SDK `asset.upload()` route or the public `/asset` endpoint to upload binary data, then return the resulting `asset://...` URL. Do not import Synergy internal asset modules from a plugin.
|
|
67
|
+
|
|
68
|
+
For visual tools whose output should appear as the main answer instead of a tool card, set `metadata.display.presentation` to `artifact-only` and list the attachment ids to promote:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
return {
|
|
72
|
+
output: "",
|
|
73
|
+
metadata: {
|
|
74
|
+
display: {
|
|
75
|
+
presentation: "artifact-only",
|
|
76
|
+
primaryAttachmentIds: [partId],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
attachments: [
|
|
80
|
+
{
|
|
81
|
+
id: partId,
|
|
82
|
+
sessionID: context.sessionID,
|
|
83
|
+
messageID: context.messageID,
|
|
84
|
+
type: "file",
|
|
85
|
+
mime: "image/svg+xml",
|
|
86
|
+
filename: "result.svg",
|
|
87
|
+
url: uploaded.url,
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Running and failed tool states still render normally, so progress, approvals, and errors remain visible.
|
|
94
|
+
|
|
95
|
+
For image, video, or audio generation tools, declare the display protocol on the tool definition as well. This lets Synergy show its built-in media generation placeholder as soon as the tool starts, then replace it with the promoted attachment when the tool completes:
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
const mediaDisplay = {
|
|
99
|
+
kind: "media-generation",
|
|
100
|
+
visibility: "media",
|
|
101
|
+
presentation: "artifact-only",
|
|
102
|
+
media: {
|
|
103
|
+
type: "image",
|
|
104
|
+
actionLabel: "Create image",
|
|
105
|
+
pendingTitle: "Generating image",
|
|
106
|
+
pendingDescription: "Preparing the image...",
|
|
107
|
+
promptField: "prompt",
|
|
108
|
+
aspectRatio: "1:1",
|
|
109
|
+
},
|
|
110
|
+
} as const
|
|
111
|
+
|
|
112
|
+
tool({
|
|
113
|
+
description: "Generate an image",
|
|
114
|
+
display: mediaDisplay,
|
|
115
|
+
args: {
|
|
116
|
+
prompt: tool.schema.string(),
|
|
117
|
+
},
|
|
118
|
+
async execute(args, context) {
|
|
119
|
+
// Upload the generated image, then return metadata.display with primaryAttachmentIds.
|
|
120
|
+
},
|
|
121
|
+
})
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
Use `visibility: "media"` for tools whose running and completed success states should be represented by the media surface instead of the ordinary tool transcript. Error states still fall back to normal tool cards.
|
|
125
|
+
|
|
66
126
|
## Plugin Input
|
|
67
127
|
|
|
68
128
|
`init(input)` receives runtime services scoped to the active Synergy Scope:
|
|
@@ -109,6 +169,9 @@ Each distributable plugin has a root `plugin.json`:
|
|
|
109
169
|
"name": "greet",
|
|
110
170
|
"title": "Greet",
|
|
111
171
|
"description": "Greet a user by name",
|
|
172
|
+
"display": {
|
|
173
|
+
"kind": "default",
|
|
174
|
+
},
|
|
112
175
|
"capabilities": {
|
|
113
176
|
"filesystem": "none",
|
|
114
177
|
"network": false,
|
|
@@ -157,7 +220,7 @@ Worker and process plugins are started through Synergy's plugin runner. The runn
|
|
|
157
220
|
- `dist/permissions.summary.json`
|
|
158
221
|
- `dist/integrity.json`
|
|
159
222
|
|
|
160
|
-
`synergy-plugin pack` archives `dist/` into `<name>-<version>.synergy-plugin.tgz`. `synergy-plugin sign` writes `<tarball>.sig`. `synergy-plugin publish-market` prepares the official marketplace submission by uploading or checking GitHub Release assets, writing a `SII-Holos/synergy-plugins` entry, running registry validation, and opening a PR when `gh` is available.
|
|
223
|
+
`synergy-plugin pack` archives `dist/` into `<name>-<version>.synergy-plugin.tgz`. `synergy-plugin sign` writes `<tarball>.sig`. `synergy-plugin publish-market` prepares the official marketplace submission by uploading or checking GitHub Release assets, writing a `SII-Holos/synergy-plugins` entry with the signer public key, regenerating the registry index, running registry validation, and opening a PR when `gh` is available.
|
|
161
224
|
|
|
162
225
|
For local marketplace UX testing, the Synergy runtime still provides `synergy plugin publish <tarball>` to publish into the local development registry.
|
|
163
226
|
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface ToolMediaDisplay {
|
|
2
|
+
type: "image" | "video" | "audio";
|
|
3
|
+
actionLabel?: string;
|
|
4
|
+
pendingTitle?: string;
|
|
5
|
+
pendingDescription?: string;
|
|
6
|
+
promptField?: string;
|
|
7
|
+
aspectRatio?: "1:1" | "4:3" | "16:9" | "auto";
|
|
8
|
+
}
|
|
9
|
+
export interface ToolDisplay {
|
|
10
|
+
kind?: "default" | "media-generation";
|
|
11
|
+
visibility?: "default" | "media" | "hidden-unless-error";
|
|
12
|
+
presentation?: "default" | "artifact-only";
|
|
13
|
+
media?: ToolMediaDisplay;
|
|
14
|
+
primaryAttachmentIds?: string[];
|
|
15
|
+
}
|
package/dist/display.js
ADDED
|
File without changes
|
package/dist/example.js
CHANGED
|
@@ -79,7 +79,7 @@ export const ExamplePlugin = {
|
|
|
79
79
|
output.note.title = output.note.title.trim() || "Untitled note";
|
|
80
80
|
output.note.tags = mergeTags(output.note.tags);
|
|
81
81
|
},
|
|
82
|
-
async "
|
|
82
|
+
async "library.memory.search.after"(input, output) {
|
|
83
83
|
output.results = output.results
|
|
84
84
|
.slice()
|
|
85
85
|
.sort((left, right) => right.similarity - left.similarity)
|
package/dist/hooks.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type HookCategory = "core" | "chat" | "permission" | "tool" | "session" | "cortex" | "agenda" | "note" | "
|
|
1
|
+
export type HookCategory = "core" | "chat" | "permission" | "tool" | "session" | "cortex" | "agenda" | "note" | "library" | "experimental";
|
|
2
2
|
export interface HookDescriptor {
|
|
3
3
|
name: string;
|
|
4
4
|
category: HookCategory;
|
package/dist/hooks.js
CHANGED
|
@@ -11,6 +11,12 @@ export const HOOKS = [
|
|
|
11
11
|
mutatesOutput: false,
|
|
12
12
|
summary: "Add provider auth methods and auth loaders",
|
|
13
13
|
},
|
|
14
|
+
{
|
|
15
|
+
name: "provider",
|
|
16
|
+
category: "core",
|
|
17
|
+
mutatesOutput: false,
|
|
18
|
+
summary: "Register provider catalog/runtime profiles",
|
|
19
|
+
},
|
|
14
20
|
{
|
|
15
21
|
name: "config",
|
|
16
22
|
category: "core",
|
|
@@ -120,20 +126,20 @@ export const HOOKS = [
|
|
|
120
126
|
summary: "Filter or reorder note search results",
|
|
121
127
|
},
|
|
122
128
|
{
|
|
123
|
-
name: "
|
|
124
|
-
category: "
|
|
129
|
+
name: "library.memory.search.before",
|
|
130
|
+
category: "library",
|
|
125
131
|
mutatesOutput: true,
|
|
126
|
-
summary: "Rewrite
|
|
132
|
+
summary: "Rewrite library memory search query and options",
|
|
127
133
|
},
|
|
128
134
|
{
|
|
129
|
-
name: "
|
|
130
|
-
category: "
|
|
135
|
+
name: "library.memory.search.after",
|
|
136
|
+
category: "library",
|
|
131
137
|
mutatesOutput: true,
|
|
132
|
-
summary: "Filter or reorder
|
|
138
|
+
summary: "Filter or reorder library memory results",
|
|
133
139
|
},
|
|
134
140
|
{
|
|
135
|
-
name: "
|
|
136
|
-
category: "
|
|
141
|
+
name: "library.experience.encode.after",
|
|
142
|
+
category: "library",
|
|
137
143
|
mutatesOutput: false,
|
|
138
144
|
summary: "Observe experience encoding outcomes",
|
|
139
145
|
},
|
|
@@ -275,6 +281,6 @@ export const HOOK_CATEGORIES = [
|
|
|
275
281
|
"cortex",
|
|
276
282
|
"agenda",
|
|
277
283
|
"note",
|
|
278
|
-
"
|
|
284
|
+
"library",
|
|
279
285
|
"experimental",
|
|
280
286
|
];
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { AgendaItem, AgendaRunLog, CortexTask, Event, createSynergyClient,
|
|
|
2
2
|
import type { BunShell } from "./shell";
|
|
3
3
|
import type { ToolDefinition, ToolResult } from "./tool";
|
|
4
4
|
export * from "./tool";
|
|
5
|
+
export type { ToolDisplay, ToolMediaDisplay } from "./display";
|
|
5
6
|
export type { ToolResult };
|
|
6
7
|
export * from "./manifest";
|
|
7
8
|
export type { BunShell, BunShellOutput, BunShellPromise, ShellExpression, ShellFunction } from "./shell";
|
|
@@ -150,8 +151,43 @@ export type AuthHook = {
|
|
|
150
151
|
} | {
|
|
151
152
|
type: "failed";
|
|
152
153
|
}>;
|
|
154
|
+
} | {
|
|
155
|
+
type: "import";
|
|
156
|
+
label: string;
|
|
157
|
+
prompts?: Array<{
|
|
158
|
+
type: "text";
|
|
159
|
+
key: string;
|
|
160
|
+
message: string;
|
|
161
|
+
placeholder?: string;
|
|
162
|
+
validate?: (value: string) => string | undefined;
|
|
163
|
+
condition?: (inputs: Record<string, string>) => boolean;
|
|
164
|
+
} | {
|
|
165
|
+
type: "select";
|
|
166
|
+
key: string;
|
|
167
|
+
message: string;
|
|
168
|
+
options: Array<{
|
|
169
|
+
label: string;
|
|
170
|
+
value: string;
|
|
171
|
+
hint?: string;
|
|
172
|
+
}>;
|
|
173
|
+
condition?: (inputs: Record<string, string>) => boolean;
|
|
174
|
+
}>;
|
|
175
|
+
import(inputs?: Record<string, string>): Promise<AuthImportResult>;
|
|
153
176
|
})[];
|
|
154
177
|
};
|
|
178
|
+
export type AuthImportResult = ({
|
|
179
|
+
type: "success";
|
|
180
|
+
provider?: string;
|
|
181
|
+
} & ({
|
|
182
|
+
refresh: string;
|
|
183
|
+
access: string;
|
|
184
|
+
expires: number;
|
|
185
|
+
} | {
|
|
186
|
+
key: string;
|
|
187
|
+
})) | {
|
|
188
|
+
type: "failed";
|
|
189
|
+
message?: string;
|
|
190
|
+
};
|
|
155
191
|
export type AuthOuathResult = {
|
|
156
192
|
url: string;
|
|
157
193
|
instructions: string;
|
|
@@ -184,6 +220,88 @@ export type AuthOuathResult = {
|
|
|
184
220
|
type: "failed";
|
|
185
221
|
}>;
|
|
186
222
|
});
|
|
223
|
+
export type ProviderProfileHook = {
|
|
224
|
+
id: string;
|
|
225
|
+
name: string;
|
|
226
|
+
aliases?: string[];
|
|
227
|
+
description?: string;
|
|
228
|
+
signupUrl?: string;
|
|
229
|
+
env?: string[];
|
|
230
|
+
baseURL?: string;
|
|
231
|
+
modelsURL?: string;
|
|
232
|
+
apiMode?: "chat_completions" | "responses" | "anthropic_messages" | "codex_responses" | "external_process";
|
|
233
|
+
authKind?: "api_key" | "oauth" | "oauth_external" | "copilot" | "wellknown" | "none";
|
|
234
|
+
aiSdkPackage?: string;
|
|
235
|
+
modelFactory?: "languageModel" | "openaiResponses" | "openaiChat" | "openaiResponsesUnlessCompletionUrls" | "call" | "copilotAuto" | "anthropicMessages";
|
|
236
|
+
modelsDevProviderID?: string;
|
|
237
|
+
fallbackModels?: string[];
|
|
238
|
+
defaultAuxModel?: string;
|
|
239
|
+
usageKind?: "codex" | "anthropic-oauth" | "openrouter" | "unsupported";
|
|
240
|
+
healthCheck?: "models" | "none";
|
|
241
|
+
requestQuirks?: string[];
|
|
242
|
+
autoload?: (input: {
|
|
243
|
+
providerID: string;
|
|
244
|
+
auth?: Auth;
|
|
245
|
+
provider?: Provider;
|
|
246
|
+
}) => Promise<boolean>;
|
|
247
|
+
resolveAuth?: (input: {
|
|
248
|
+
providerID: string;
|
|
249
|
+
auth?: Auth;
|
|
250
|
+
provider?: Provider;
|
|
251
|
+
}) => Promise<Auth | undefined>;
|
|
252
|
+
refreshAuth?: (input: {
|
|
253
|
+
providerID: string;
|
|
254
|
+
auth?: Auth;
|
|
255
|
+
provider?: Provider;
|
|
256
|
+
}) => Promise<Auth | undefined>;
|
|
257
|
+
buildHeaders?: (input: {
|
|
258
|
+
providerID: string;
|
|
259
|
+
auth?: Auth;
|
|
260
|
+
url: string;
|
|
261
|
+
headers: Headers;
|
|
262
|
+
body?: unknown;
|
|
263
|
+
}) => Promise<Record<string, string> | Headers | undefined>;
|
|
264
|
+
rewriteBody?: (input: {
|
|
265
|
+
providerID: string;
|
|
266
|
+
auth?: Auth;
|
|
267
|
+
url: string;
|
|
268
|
+
headers: Headers;
|
|
269
|
+
body?: unknown;
|
|
270
|
+
}) => Promise<unknown>;
|
|
271
|
+
modelOptions?: (input: {
|
|
272
|
+
providerID: string;
|
|
273
|
+
auth?: Auth;
|
|
274
|
+
provider?: Provider;
|
|
275
|
+
}) => Promise<Record<string, any>>;
|
|
276
|
+
classifyError?: (input: {
|
|
277
|
+
providerID: string;
|
|
278
|
+
status?: number;
|
|
279
|
+
error?: unknown;
|
|
280
|
+
body?: unknown;
|
|
281
|
+
}) => {
|
|
282
|
+
code: string;
|
|
283
|
+
retryable: boolean;
|
|
284
|
+
reloginRequired?: boolean;
|
|
285
|
+
exhausted?: boolean;
|
|
286
|
+
cooldownUntil?: number;
|
|
287
|
+
resetAt?: number;
|
|
288
|
+
} | undefined;
|
|
289
|
+
runtimeOptions?: (input: {
|
|
290
|
+
providerID: string;
|
|
291
|
+
auth?: Auth;
|
|
292
|
+
provider?: Provider;
|
|
293
|
+
}) => Promise<Record<string, any>>;
|
|
294
|
+
getModel?: (input: {
|
|
295
|
+
sdk: any;
|
|
296
|
+
modelID: string;
|
|
297
|
+
options?: Record<string, any>;
|
|
298
|
+
}) => Promise<any>;
|
|
299
|
+
fetchModels?: (input: {
|
|
300
|
+
auth?: Auth;
|
|
301
|
+
fetch?: typeof fetch;
|
|
302
|
+
baseURL?: string;
|
|
303
|
+
}) => Promise<string[]>;
|
|
304
|
+
};
|
|
187
305
|
export type PluginInput = {
|
|
188
306
|
client: ReturnType<typeof createSynergyClient>;
|
|
189
307
|
scope: {
|
|
@@ -235,6 +353,8 @@ export interface PluginHooks {
|
|
|
235
353
|
tool?: Record<string, ToolDefinition>;
|
|
236
354
|
/** Provider auth integration */
|
|
237
355
|
auth?: AuthHook;
|
|
356
|
+
/** Provider runtime/catalog profiles */
|
|
357
|
+
provider?: ProviderProfileHook | ProviderProfileHook[];
|
|
238
358
|
/** Observe runtime bus events */
|
|
239
359
|
event?(input: {
|
|
240
360
|
event: Event;
|
|
@@ -415,7 +535,7 @@ export interface PluginHooks {
|
|
|
415
535
|
notes: NoteInfo[];
|
|
416
536
|
}): Promise<void>;
|
|
417
537
|
/** Rewrite memory search query */
|
|
418
|
-
"
|
|
538
|
+
"library.memory.search.before"?(input: {}, output: {
|
|
419
539
|
query: string;
|
|
420
540
|
vector?: number[];
|
|
421
541
|
topK?: number;
|
|
@@ -424,14 +544,14 @@ export interface PluginHooks {
|
|
|
424
544
|
rerank?: boolean;
|
|
425
545
|
}): Promise<void>;
|
|
426
546
|
/** Filter or reorder memory results */
|
|
427
|
-
"
|
|
547
|
+
"library.memory.search.after"?(input: {
|
|
428
548
|
query: string;
|
|
429
549
|
topK: number;
|
|
430
550
|
}, output: {
|
|
431
551
|
results: MemorySearchResult[];
|
|
432
552
|
}): Promise<void>;
|
|
433
553
|
/** Observe experience encoding outcomes */
|
|
434
|
-
"
|
|
554
|
+
"library.experience.encode.after"?(input: {
|
|
435
555
|
sessionID: string;
|
|
436
556
|
userMessageID: string;
|
|
437
557
|
}, output: {
|
package/dist/manifest.d.ts
CHANGED
|
@@ -53,6 +53,7 @@ export declare const PluginManifest: z.ZodObject<{
|
|
|
53
53
|
config: z.ZodDefault<z.ZodEnum<{
|
|
54
54
|
plugin: "plugin";
|
|
55
55
|
global: "global";
|
|
56
|
+
none: "none";
|
|
56
57
|
}>>;
|
|
57
58
|
secrets: z.ZodDefault<z.ZodEnum<{
|
|
58
59
|
none: "none";
|
|
@@ -107,6 +108,52 @@ export declare const PluginManifest: z.ZodObject<{
|
|
|
107
108
|
icon: z.ZodOptional<z.ZodString>;
|
|
108
109
|
category: z.ZodOptional<z.ZodString>;
|
|
109
110
|
kind: z.ZodOptional<z.ZodString>;
|
|
111
|
+
exposure: z.ZodOptional<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
112
|
+
mode: z.ZodLiteral<"resident">;
|
|
113
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
114
|
+
mode: z.ZodLiteral<"group">;
|
|
115
|
+
group: z.ZodString;
|
|
116
|
+
title: z.ZodOptional<z.ZodString>;
|
|
117
|
+
description: z.ZodOptional<z.ZodString>;
|
|
118
|
+
whenToExpand: z.ZodOptional<z.ZodString>;
|
|
119
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
120
|
+
mode: z.ZodLiteral<"search">;
|
|
121
|
+
title: z.ZodOptional<z.ZodString>;
|
|
122
|
+
keywords: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
123
|
+
}, z.core.$strict>], "mode">>;
|
|
124
|
+
display: z.ZodOptional<z.ZodObject<{
|
|
125
|
+
kind: z.ZodOptional<z.ZodEnum<{
|
|
126
|
+
default: "default";
|
|
127
|
+
"media-generation": "media-generation";
|
|
128
|
+
}>>;
|
|
129
|
+
visibility: z.ZodOptional<z.ZodEnum<{
|
|
130
|
+
default: "default";
|
|
131
|
+
media: "media";
|
|
132
|
+
"hidden-unless-error": "hidden-unless-error";
|
|
133
|
+
}>>;
|
|
134
|
+
presentation: z.ZodOptional<z.ZodEnum<{
|
|
135
|
+
default: "default";
|
|
136
|
+
"artifact-only": "artifact-only";
|
|
137
|
+
}>>;
|
|
138
|
+
media: z.ZodOptional<z.ZodObject<{
|
|
139
|
+
type: z.ZodEnum<{
|
|
140
|
+
image: "image";
|
|
141
|
+
video: "video";
|
|
142
|
+
audio: "audio";
|
|
143
|
+
}>;
|
|
144
|
+
actionLabel: z.ZodOptional<z.ZodString>;
|
|
145
|
+
pendingTitle: z.ZodOptional<z.ZodString>;
|
|
146
|
+
pendingDescription: z.ZodOptional<z.ZodString>;
|
|
147
|
+
promptField: z.ZodOptional<z.ZodString>;
|
|
148
|
+
aspectRatio: z.ZodOptional<z.ZodEnum<{
|
|
149
|
+
"1:1": "1:1";
|
|
150
|
+
"4:3": "4:3";
|
|
151
|
+
"16:9": "16:9";
|
|
152
|
+
auto: "auto";
|
|
153
|
+
}>>;
|
|
154
|
+
}, z.core.$strict>>;
|
|
155
|
+
primaryAttachmentIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
156
|
+
}, z.core.$strict>>;
|
|
110
157
|
capabilities: z.ZodOptional<z.ZodObject<{
|
|
111
158
|
filesystem: z.ZodOptional<z.ZodEnum<{
|
|
112
159
|
read: "read";
|
|
@@ -315,6 +362,7 @@ export declare const PluginManifest: z.ZodObject<{
|
|
|
315
362
|
config: z.ZodDefault<z.ZodEnum<{
|
|
316
363
|
plugin: "plugin";
|
|
317
364
|
global: "global";
|
|
365
|
+
none: "none";
|
|
318
366
|
}>>;
|
|
319
367
|
secrets: z.ZodDefault<z.ZodEnum<{
|
|
320
368
|
none: "none";
|
package/dist/manifest.js
CHANGED
|
@@ -87,6 +87,48 @@ const UICommandDef = z
|
|
|
87
87
|
icon: z.string().optional(),
|
|
88
88
|
})
|
|
89
89
|
.strict();
|
|
90
|
+
const ToolExposureDef = z.discriminatedUnion("mode", [
|
|
91
|
+
z
|
|
92
|
+
.object({
|
|
93
|
+
mode: z.literal("resident"),
|
|
94
|
+
})
|
|
95
|
+
.strict(),
|
|
96
|
+
z
|
|
97
|
+
.object({
|
|
98
|
+
mode: z.literal("group"),
|
|
99
|
+
group: z.string().min(1),
|
|
100
|
+
title: z.string().optional(),
|
|
101
|
+
description: z.string().optional(),
|
|
102
|
+
whenToExpand: z.string().optional(),
|
|
103
|
+
})
|
|
104
|
+
.strict(),
|
|
105
|
+
z
|
|
106
|
+
.object({
|
|
107
|
+
mode: z.literal("search"),
|
|
108
|
+
title: z.string().optional(),
|
|
109
|
+
keywords: z.array(z.string()).optional(),
|
|
110
|
+
})
|
|
111
|
+
.strict(),
|
|
112
|
+
]);
|
|
113
|
+
const ToolDisplayDef = z
|
|
114
|
+
.object({
|
|
115
|
+
kind: z.enum(["default", "media-generation"]).optional(),
|
|
116
|
+
visibility: z.enum(["default", "media", "hidden-unless-error"]).optional(),
|
|
117
|
+
presentation: z.enum(["default", "artifact-only"]).optional(),
|
|
118
|
+
media: z
|
|
119
|
+
.object({
|
|
120
|
+
type: z.enum(["image", "video", "audio"]),
|
|
121
|
+
actionLabel: z.string().min(1).max(80).optional(),
|
|
122
|
+
pendingTitle: z.string().min(1).max(120).optional(),
|
|
123
|
+
pendingDescription: z.string().min(1).max(200).optional(),
|
|
124
|
+
promptField: z.string().min(1).max(64).optional(),
|
|
125
|
+
aspectRatio: z.enum(["1:1", "4:3", "16:9", "auto"]).optional(),
|
|
126
|
+
})
|
|
127
|
+
.strict()
|
|
128
|
+
.optional(),
|
|
129
|
+
primaryAttachmentIds: z.array(z.string().min(1)).optional(),
|
|
130
|
+
})
|
|
131
|
+
.strict();
|
|
90
132
|
const UIContribution = z
|
|
91
133
|
.object({
|
|
92
134
|
entry: z
|
|
@@ -134,7 +176,7 @@ const PluginPermissionsSchema = z
|
|
|
134
176
|
.object({
|
|
135
177
|
session: z.enum(["none", "metadata", "read"]).default("none"),
|
|
136
178
|
workspace: z.enum(["none", "metadata", "read"]).default("none"),
|
|
137
|
-
config: z.enum(["plugin", "global"]).default("plugin"),
|
|
179
|
+
config: z.enum(["none", "plugin", "global"]).default("plugin"),
|
|
138
180
|
secrets: z.enum(["none", "own"]).default("none"),
|
|
139
181
|
})
|
|
140
182
|
.optional(),
|
|
@@ -221,6 +263,8 @@ export const PluginManifest = z
|
|
|
221
263
|
icon: z.string().optional(),
|
|
222
264
|
category: z.string().optional(),
|
|
223
265
|
kind: z.string().optional(),
|
|
266
|
+
exposure: ToolExposureDef.optional(),
|
|
267
|
+
display: ToolDisplayDef.optional(),
|
|
224
268
|
capabilities: z
|
|
225
269
|
.object({
|
|
226
270
|
filesystem: z.enum(["none", "read", "write"]).optional(),
|
package/dist/tool.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
+
import type { ToolDisplay } from "./display";
|
|
3
|
+
export type { ToolDisplay, ToolMediaDisplay } from "./display";
|
|
2
4
|
export type ToolContext = {
|
|
3
5
|
sessionID: string;
|
|
4
6
|
messageID: string;
|
|
@@ -12,10 +14,14 @@ export type ToolContext = {
|
|
|
12
14
|
metadata?: Record<string, any>;
|
|
13
15
|
}): Promise<void>;
|
|
14
16
|
};
|
|
17
|
+
export type ToolResultMetadata = Record<string, any> & {
|
|
18
|
+
display?: ToolDisplay;
|
|
19
|
+
primaryAttachmentIds?: string[];
|
|
20
|
+
};
|
|
15
21
|
export interface ToolResult {
|
|
16
22
|
title?: string;
|
|
17
23
|
output: string;
|
|
18
|
-
metadata?:
|
|
24
|
+
metadata?: ToolResultMetadata;
|
|
19
25
|
attachments?: Array<{
|
|
20
26
|
type: "file";
|
|
21
27
|
id: string;
|
|
@@ -27,12 +33,29 @@ export interface ToolResult {
|
|
|
27
33
|
localPath?: string;
|
|
28
34
|
}>;
|
|
29
35
|
}
|
|
36
|
+
export type ToolExposure = {
|
|
37
|
+
mode: "resident";
|
|
38
|
+
} | {
|
|
39
|
+
mode: "group";
|
|
40
|
+
group: string;
|
|
41
|
+
title?: string;
|
|
42
|
+
description?: string;
|
|
43
|
+
whenToExpand?: string;
|
|
44
|
+
} | {
|
|
45
|
+
mode: "search";
|
|
46
|
+
title?: string;
|
|
47
|
+
keywords?: string[];
|
|
48
|
+
};
|
|
30
49
|
export declare function tool<Args extends z.ZodRawShape>(input: {
|
|
31
50
|
description: string;
|
|
51
|
+
exposure?: ToolExposure;
|
|
52
|
+
display?: ToolDisplay;
|
|
32
53
|
args: Args;
|
|
33
54
|
execute(args: z.infer<z.ZodObject<Args>>, context: ToolContext): Promise<string | ToolResult>;
|
|
34
55
|
}): {
|
|
35
56
|
description: string;
|
|
57
|
+
exposure?: ToolExposure;
|
|
58
|
+
display?: ToolDisplay;
|
|
36
59
|
args: Args;
|
|
37
60
|
execute(args: z.infer<z.ZodObject<Args>>, context: ToolContext): Promise<string | ToolResult>;
|
|
38
61
|
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
3
|
"name": "@ericsanchezok/synergy-plugin",
|
|
4
|
-
"version": "2.
|
|
4
|
+
"version": "2.3.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
@@ -25,6 +25,10 @@
|
|
|
25
25
|
"import": "./dist/tool.js",
|
|
26
26
|
"types": "./dist/tool.d.ts"
|
|
27
27
|
},
|
|
28
|
+
"./display": {
|
|
29
|
+
"import": "./dist/display.js",
|
|
30
|
+
"types": "./dist/display.d.ts"
|
|
31
|
+
},
|
|
28
32
|
"./hooks": {
|
|
29
33
|
"import": "./dist/hooks.js",
|
|
30
34
|
"types": "./dist/hooks.d.ts"
|