@ampcode/plugin 0.0.0-20260727003132-g7dd9424 → 0.0.0-20260729002615-g8a974c9

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.
Files changed (3) hide show
  1. package/README.md +3 -0
  2. package/index.d.ts +108 -9
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -12,6 +12,9 @@ Plugins can:
12
12
  - **Show UI** — `ctx.ui.notify(...)`, `ctx.ui.confirm(...)`, `ctx.ui.input(...)`, and `ctx.ui.select(...)`
13
13
  - **Use AI** — `amp.ai.ask(...)` for thread-scoped yes/no classification that defaults to no
14
14
  reasoning unless `{ reasoningEffort }` is set
15
+ - **Upload attachments** — `amp.attachments.upload(...)` to upload image bytes and get back a URL
16
+ for URL-backed `{ type: 'image', mimeType, url }` tool result blocks, keeping large images out
17
+ of thread state
15
18
 
16
19
  ## Locations
17
20
 
package/index.d.ts CHANGED
@@ -108,6 +108,32 @@ declare module '@ampcode/plugin' {
108
108
  */
109
109
  registerTool(definition: PluginToolDefinition): Subscription
110
110
 
111
+ /**
112
+ * Register a callback that runs before this plugin instance is stopped.
113
+ *
114
+ * Dispose callbacks run when the plugin is unloaded or reloaded and on graceful
115
+ * host shutdown. Use them to release resources the plugin owns outside its own
116
+ * process, such as child processes, remote sessions, or temporary files.
117
+ *
118
+ * The host bounds cleanup time: all of a plugin's dispose callbacks together
119
+ * get about 3 seconds. After they settle or the budget elapses, the plugin
120
+ * process is terminated. Callbacks run concurrently, in no guaranteed order,
121
+ * and thrown errors are logged and otherwise ignored.
122
+ *
123
+ * Dispose callbacks do NOT run when the plugin process crashes or is killed
124
+ * with SIGKILL. Keep an external backstop (such as a server-side idle
125
+ * timeout) for resources that must not outlive the plugin in those cases.
126
+ *
127
+ * @example
128
+ * ```ts
129
+ * const server = await startHelperProcess()
130
+ * amp.onDispose(async () => {
131
+ * await server.stop()
132
+ * })
133
+ * ```
134
+ */
135
+ onDispose(callback: () => void | Promise<void>): Subscription
136
+
111
137
  /**
112
138
  * Register a durable generic webhook for this plugin and the owning Orb thread.
113
139
  *
@@ -120,7 +146,6 @@ declare module '@ampcode/plugin' {
120
146
  * before durable consumption is recorded. Handlers have 30 seconds to complete;
121
147
  * `ctx.signal` is aborted when that deadline elapses, and the event is retried.
122
148
  *
123
- * @experimental
124
149
  * @example
125
150
  * ```ts
126
151
  * const { url } = await amp.createWebhook({
@@ -136,6 +161,9 @@ declare module '@ampcode/plugin' {
136
161
  /** AI helpers */
137
162
  ai: PluginAI
138
163
 
164
+ /** Attachment uploads, for URL-backed image tool result blocks */
165
+ attachments: PluginAttachments
166
+
139
167
  /**
140
168
  * Create a custom agent bound to this plugin runtime.
141
169
  *
@@ -279,7 +307,11 @@ declare module '@ampcode/plugin' {
279
307
  }
280
308
 
281
309
  export interface CreateAgentConfig {
282
- /** Optional stable identifier for logs, UI, and persisted run metadata. */
310
+ /**
311
+ * Optional agent identity. Amp includes this name in the base system prompt as
312
+ * `You are <name>, a custom agent running in Amp.` It is also used for logs, UI,
313
+ * and persisted run metadata. Omit it to avoid adding a named identity to the prompt.
314
+ */
283
315
  name?: string
284
316
  /**
285
317
  * Model identifier in `provider/model` format, such as `anthropic/claude-sonnet-4-6`.
@@ -361,11 +393,10 @@ declare module '@ampcode/plugin' {
361
393
  /** Show the created thread and make it active in the client when supported. */
362
394
  show?: boolean
363
395
  /**
364
- * Serving speed for the new thread. When omitted, the thread inherits the
365
- * creating thread's speed. Fast mode uses faster serving for supported
366
- * models and is billed at a premium.
396
+ * Features for the new thread. Omit to inherit the creating thread's features;
397
+ * pass an empty array to clear them.
367
398
  */
368
- speed?: 'standard' | 'fast'
399
+ features?: readonly 'fast'[]
369
400
  /**
370
401
  * Enable multiplayer for this many seconds. Multiplayer threads must run in an
371
402
  * Orb and belong to a workspace. Valid values range from 5 minutes to 7 days.
@@ -579,6 +610,58 @@ declare module '@ampcode/plugin' {
579
610
  ask(question: string, options?: PluginAIAskOptions): Promise<PluginAIAskResult>
580
611
  }
581
612
 
613
+ /**
614
+ * Input for {@link PluginAttachments.upload}.
615
+ */
616
+ export interface PluginAttachmentUploadInput {
617
+ /** Raw bytes, or a base64-encoded payload with no data: prefix. */
618
+ data: Uint8Array | string
619
+
620
+ /** MIME type, e.g. 'image/png', 'image/jpeg', or 'image/webp'. */
621
+ mimeType: string
622
+ }
623
+
624
+ /**
625
+ * An attachment uploaded to the Amp server.
626
+ */
627
+ export interface PluginAttachment {
628
+ /** HTTPS URL that serves the uploaded bytes. */
629
+ url: string
630
+ }
631
+
632
+ /**
633
+ * Attachment upload capability provided to plugins.
634
+ */
635
+ export interface PluginAttachments {
636
+ /**
637
+ * Upload bytes to the Amp server as an attachment and get back a URL.
638
+ *
639
+ * The returned URL can be used in a `{ type: 'image', mimeType, url }` tool result
640
+ * block, which keeps large image payloads (e.g. screenshots) out of thread state.
641
+ * The upload is subject to the Amp server's attachment media-type and size policy,
642
+ * and the resulting URL is fetchable by Amp's inference providers. Image uploads are
643
+ * additionally validated against Amp's inference image limits before uploading:
644
+ * at most 4.9 MB decoded and at most 8000px per dimension.
645
+ *
646
+ * Throws if the upload fails (e.g. offline, unauthorized, payload rejected by the
647
+ * server's policy, or an image exceeding the inference image limits). Callers
648
+ * returning tool results should catch errors and fall back to an inline base64
649
+ * image block.
650
+ *
651
+ * @example
652
+ * ```ts
653
+ * const png: Uint8Array = await captureScreenshot()
654
+ * try {
655
+ * const { url } = await amp.attachments.upload({ data: png, mimeType: 'image/png' })
656
+ * return [{ type: 'image', mimeType: 'image/png', url }]
657
+ * } catch {
658
+ * return [{ type: 'image', mimeType: 'image/png', data: Buffer.from(png).toString('base64') }]
659
+ * }
660
+ * ```
661
+ */
662
+ upload(input: PluginAttachmentUploadInput): Promise<PluginAttachment>
663
+ }
664
+
582
665
  /**
583
666
  * Observer interface for subscribing to configuration changes.
584
667
  */
@@ -1013,7 +1096,7 @@ declare module '@ampcode/plugin' {
1013
1096
  /** Dialog title */
1014
1097
  title: string
1015
1098
 
1016
- /** Message body shown below the title */
1099
+ /** Markdown message body shown below the title */
1017
1100
  message?: string
1018
1101
 
1019
1102
  /** Text for the confirm button (default: "Yes") */
@@ -1033,7 +1116,7 @@ declare module '@ampcode/plugin' {
1033
1116
  */
1034
1117
  allowOther?: boolean
1035
1118
 
1036
- /** Message body shown below the title */
1119
+ /** Markdown message body shown below the title */
1037
1120
  message?: string
1038
1121
 
1039
1122
  /** Initially selected option value */
@@ -1169,12 +1252,28 @@ declare module '@ampcode/plugin' {
1169
1252
  /** Base64-encoded payload with no data: prefix. */
1170
1253
  data: string
1171
1254
  }
1255
+ | {
1256
+ type: 'image'
1257
+
1258
+ /** MIME type, e.g. 'image/png', 'image/jpeg', or 'image/webp'. */
1259
+ mimeType: string
1260
+
1261
+ /**
1262
+ * HTTPS URL of the image, typically obtained from {@link PluginAttachments.upload}.
1263
+ * The URL must be fetchable by Amp's inference providers and web/CLI clients.
1264
+ * Using a URL keeps large image payloads out of thread state.
1265
+ */
1266
+ url: string
1267
+ }
1172
1268
 
1173
1269
  /**
1174
1270
  * Result returned from a plugin tool.
1175
1271
  *
1176
1272
  * Returning a bare string keeps the existing text-only behavior. Returning an array
1177
- * of content blocks lets a tool mix text and inline base64 image blocks.
1273
+ * of content blocks lets a tool mix text and image blocks. Image blocks carry either
1274
+ * an inline base64 payload (`data`) or a URL (`url`), never both. Prefer uploading
1275
+ * large images with {@link PluginAttachments.upload} and returning a URL block, and
1276
+ * fall back to an inline base64 block if the upload fails.
1178
1277
  */
1179
1278
  export type PluginToolResult = string | PluginToolResultContentBlock[]
1180
1279
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ampcode/plugin",
3
- "version": "0.0.0-20260727003132-g7dd9424",
3
+ "version": "0.0.0-20260729002615-g8a974c9",
4
4
  "description": "Amp Plugin API",
5
5
  "homepage": "https://ampcode.com/manual/plugin-api",
6
6
  "author": {