@ampcode/plugin 0.0.0-20260727003132-g7dd9424 → 0.0.0-20260728002927-g60f34f5

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 +102 -3
  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,34 @@ 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, when a modified plugin
115
+ * is reloaded (the old instance's callbacks complete before the new instance
116
+ * is activated), and on graceful host shutdown. Use them to release resources
117
+ * the plugin owns outside its own process, such as child processes, remote
118
+ * sessions, or temporary files.
119
+ *
120
+ * The host bounds cleanup time: all of a plugin's dispose callbacks together
121
+ * get about 3 seconds. After they settle or the budget elapses, the plugin
122
+ * process is terminated. Callbacks run concurrently, in no guaranteed order,
123
+ * and thrown errors are logged and otherwise ignored.
124
+ *
125
+ * Dispose callbacks do NOT run when the plugin process crashes or is killed
126
+ * with SIGKILL. Keep an external backstop (such as a server-side idle
127
+ * timeout) for resources that must not outlive the plugin in those cases.
128
+ *
129
+ * @example
130
+ * ```ts
131
+ * const server = await startHelperProcess()
132
+ * amp.onDispose(async () => {
133
+ * await server.stop()
134
+ * })
135
+ * ```
136
+ */
137
+ onDispose(callback: () => void | Promise<void>): Subscription
138
+
111
139
  /**
112
140
  * Register a durable generic webhook for this plugin and the owning Orb thread.
113
141
  *
@@ -136,6 +164,9 @@ declare module '@ampcode/plugin' {
136
164
  /** AI helpers */
137
165
  ai: PluginAI
138
166
 
167
+ /** Attachment uploads, for URL-backed image tool result blocks */
168
+ attachments: PluginAttachments
169
+
139
170
  /**
140
171
  * Create a custom agent bound to this plugin runtime.
141
172
  *
@@ -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-20260728002927-g60f34f5",
4
4
  "description": "Amp Plugin API",
5
5
  "homepage": "https://ampcode.com/manual/plugin-api",
6
6
  "author": {