@ampcode/plugin 0.0.0-20260726003151-g56c26ca → 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 +105 -4
  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
  */
@@ -934,7 +1017,9 @@ declare module '@ampcode/plugin' {
934
1017
  */
935
1018
  waitForResponse(options?: { timeoutMs?: number }): Promise<ThreadAssistantMessage>
936
1019
 
937
- /** Stop the agent's current turn in this thread, if one is running. */
1020
+ /**
1021
+ * Stop the agent's current turn. During agent.start, prevents the turn from starting.
1022
+ */
938
1023
  cancel(): Promise<void>
939
1024
 
940
1025
  /**
@@ -1011,7 +1096,7 @@ declare module '@ampcode/plugin' {
1011
1096
  /** Dialog title */
1012
1097
  title: string
1013
1098
 
1014
- /** Message body shown below the title */
1099
+ /** Markdown message body shown below the title */
1015
1100
  message?: string
1016
1101
 
1017
1102
  /** Text for the confirm button (default: "Yes") */
@@ -1031,7 +1116,7 @@ declare module '@ampcode/plugin' {
1031
1116
  */
1032
1117
  allowOther?: boolean
1033
1118
 
1034
- /** Message body shown below the title */
1119
+ /** Markdown message body shown below the title */
1035
1120
  message?: string
1036
1121
 
1037
1122
  /** Initially selected option value */
@@ -1167,12 +1252,28 @@ declare module '@ampcode/plugin' {
1167
1252
  /** Base64-encoded payload with no data: prefix. */
1168
1253
  data: string
1169
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
+ }
1170
1268
 
1171
1269
  /**
1172
1270
  * Result returned from a plugin tool.
1173
1271
  *
1174
1272
  * Returning a bare string keeps the existing text-only behavior. Returning an array
1175
- * 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.
1176
1277
  */
1177
1278
  export type PluginToolResult = string | PluginToolResultContentBlock[]
1178
1279
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ampcode/plugin",
3
- "version": "0.0.0-20260726003151-g56c26ca",
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": {