@stina/extension-api 1.3.1 → 1.6.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/dist/{chunk-ZB7GJUPS.js → chunk-3Q3YXWOH.js} +1 -1
- package/dist/{chunk-ZB7GJUPS.js.map → chunk-3Q3YXWOH.js.map} +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +11 -4
- package/dist/index.d.ts +11 -4
- package/dist/index.js +1 -1
- package/dist/runtime.cjs +34 -5
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.d.cts +2 -2
- package/dist/runtime.d.ts +2 -2
- package/dist/runtime.js +35 -6
- package/dist/runtime.js.map +1 -1
- package/dist/schemas/index.cjs +9 -1
- package/dist/schemas/index.cjs.map +1 -1
- package/dist/schemas/index.d.cts +4 -4
- package/dist/schemas/index.d.ts +4 -4
- package/dist/schemas/index.js +9 -1
- package/dist/schemas/index.js.map +1 -1
- package/dist/{types.tools-C0GqXQlu.d.cts → types.tools-R0xGhiBa.d.cts} +119 -17
- package/dist/{types.tools-C0GqXQlu.d.ts → types.tools-R0xGhiBa.d.ts} +119 -17
- package/package.json +1 -1
- package/schema/extension-manifest.schema.json +1 -0
- package/src/index.ts +3 -0
- package/src/messages.ts +2 -0
- package/src/runtime/executionContext.test.ts +71 -0
- package/src/runtime/executionContext.ts +22 -2
- package/src/runtime.ts +26 -3
- package/src/schemas/permissions.schema.ts +9 -1
- package/src/types.context.ts +43 -0
- package/src/types.permissions.ts +7 -0
- package/src/types.provider.ts +51 -1
- package/src/types.tools.ts +29 -15
- package/src/types.ts +3 -0
package/src/types.context.ts
CHANGED
|
@@ -85,6 +85,49 @@ export interface ExecutionContext {
|
|
|
85
85
|
|
|
86
86
|
/** User-scoped secrets */
|
|
87
87
|
readonly userSecrets: SecretsAPI
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* The files attached to this user's conversations.
|
|
91
|
+
*
|
|
92
|
+
* Present only for an extension holding `attachments.read`, and only on a request
|
|
93
|
+
* that knows whose it is. Absent otherwise, so a tool that wants files has to say
|
|
94
|
+
* so in its manifest and check before reaching for them.
|
|
95
|
+
*/
|
|
96
|
+
readonly attachments?: AttachmentsAPI
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* Reading a file that is already in a conversation.
|
|
101
|
+
*
|
|
102
|
+
* For handing one on: mailing back the PDF she was just shown, printing it, putting
|
|
103
|
+
* it somewhere. Not for finding out what it says — `core_read_attachment` does that
|
|
104
|
+
* without an extension, and getting the text is nearly always what she actually
|
|
105
|
+
* wants.
|
|
106
|
+
*/
|
|
107
|
+
export interface AttachmentsAPI {
|
|
108
|
+
/**
|
|
109
|
+
* Read one attachment by id.
|
|
110
|
+
*
|
|
111
|
+
* The id comes from Stina, which is the whole point: she gets it from the message
|
|
112
|
+
* a file arrived on, or from the result of the tool that handed it over, and
|
|
113
|
+
* passes it to a tool as a parameter.
|
|
114
|
+
*
|
|
115
|
+
* Resolves `null` when no such attachment belongs to this user — deleted, or
|
|
116
|
+
* never theirs. The two are the same answer on purpose.
|
|
117
|
+
*/
|
|
118
|
+
read(attachmentId: string): Promise<AttachmentContent | null>
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** One attachment's bytes, with what is known about them. */
|
|
122
|
+
export interface AttachmentContent {
|
|
123
|
+
id: string
|
|
124
|
+
/** `image/jpeg`, `image/png`, `application/pdf` or `text/plain`, read from the bytes. */
|
|
125
|
+
mime: string
|
|
126
|
+
/** base64, no data-URI prefix. */
|
|
127
|
+
data: string
|
|
128
|
+
byteSize: number
|
|
129
|
+
/** The name it was stored under, when it had one. */
|
|
130
|
+
name?: string
|
|
88
131
|
}
|
|
89
132
|
|
|
90
133
|
/**
|
package/src/types.permissions.ts
CHANGED
|
@@ -28,6 +28,13 @@ export type UserDataPermission =
|
|
|
28
28
|
| 'user.location.read'
|
|
29
29
|
| 'chat.history.read'
|
|
30
30
|
| 'chat.current.read'
|
|
31
|
+
/**
|
|
32
|
+
* Read the bytes of a file attached to one of this user's conversations, given
|
|
33
|
+
* its id. For handing a file on — mailing the PDF she was shown, printing it —
|
|
34
|
+
* not for reading what it says, which `core_read_attachment` does without an
|
|
35
|
+
* extension.
|
|
36
|
+
*/
|
|
37
|
+
| 'attachments.read'
|
|
31
38
|
|
|
32
39
|
/** Capability permissions */
|
|
33
40
|
export type CapabilityPermission =
|
package/src/types.provider.ts
CHANGED
|
@@ -89,9 +89,23 @@ export interface ModelCapabilities {
|
|
|
89
89
|
* Report this per model *and* per auth mode, like `voiceDuplex`: the same
|
|
90
90
|
* provider often serves both a vision model and a text-only one, and a picture
|
|
91
91
|
* sent to the latter is at best ignored and at worst an error mid-conversation.
|
|
92
|
-
* Stina uses it to decide whether the paperclip is offered at all.
|
|
93
92
|
*/
|
|
94
93
|
vision?: boolean
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* The model can be given files to read alongside the text of a message, and
|
|
97
|
+
* the provider folds {@link ChatMessage.files} into whatever its API calls them.
|
|
98
|
+
*
|
|
99
|
+
* Separate from `vision` because the two come apart in both directions: a model
|
|
100
|
+
* that reads a PDF natively is not necessarily one that looks at a photograph,
|
|
101
|
+
* and an OpenAI-compatible server with a vision model behind it may take images
|
|
102
|
+
* and nothing else. Report it per model and per auth mode for the same reason
|
|
103
|
+
* `vision` is reported that way.
|
|
104
|
+
*
|
|
105
|
+
* A provider that says nothing here keeps behaving exactly as before: it is
|
|
106
|
+
* handed the text, and `files` is simply a field it does not read.
|
|
107
|
+
*/
|
|
108
|
+
documents?: boolean
|
|
95
109
|
}
|
|
96
110
|
|
|
97
111
|
/**
|
|
@@ -189,6 +203,18 @@ export interface ChatMessage {
|
|
|
189
203
|
* Only ever `image/jpeg` or `image/png` — see `ChatAttachmentDTO` for why.
|
|
190
204
|
*/
|
|
191
205
|
images?: ChatImage[]
|
|
206
|
+
/**
|
|
207
|
+
* Files the user attached for the model to read: PDFs and plain text.
|
|
208
|
+
*
|
|
209
|
+
* Additive in the same way `images` is, and split from it for the same reason
|
|
210
|
+
* the two capabilities are separate — a provider folds a document into a
|
|
211
|
+
* different content block than a picture, and many can do one and not the other.
|
|
212
|
+
* A provider that ignores the field behaves exactly as it did before.
|
|
213
|
+
*
|
|
214
|
+
* Only present on user messages, because that is where both hosted providers
|
|
215
|
+
* require a document to sit.
|
|
216
|
+
*/
|
|
217
|
+
files?: ChatFile[]
|
|
192
218
|
/** For assistant messages: tool calls made by the model */
|
|
193
219
|
tool_calls?: ToolCall[]
|
|
194
220
|
/** For tool messages: the ID of the tool call this is a response to */
|
|
@@ -210,6 +236,30 @@ export interface ChatImage {
|
|
|
210
236
|
data: string
|
|
211
237
|
}
|
|
212
238
|
|
|
239
|
+
/**
|
|
240
|
+
* One file the user attached for the model to read, rather than to look at.
|
|
241
|
+
*
|
|
242
|
+
* `application/pdf` and `text/plain` are what the host stores, so those are what
|
|
243
|
+
* arrive. Both hosted providers read a PDF natively and want it as its own content
|
|
244
|
+
* block; plain text needs no such thing and can simply be put in the prompt, which
|
|
245
|
+
* is why a provider with no document support at all can still do something useful
|
|
246
|
+
* with a `text/plain` file if it chooses to.
|
|
247
|
+
*/
|
|
248
|
+
export interface ChatFile {
|
|
249
|
+
/** `application/pdf` or `text/plain`. */
|
|
250
|
+
mime: string
|
|
251
|
+
/** The file itself, base64 with no data-URI prefix. */
|
|
252
|
+
data: string
|
|
253
|
+
/**
|
|
254
|
+
* The name the file arrived under, when it had one.
|
|
255
|
+
*
|
|
256
|
+
* Worth passing on rather than dropping: `faktura-1042.pdf` is most of what is
|
|
257
|
+
* known about a file before it is opened, and both providers have somewhere to
|
|
258
|
+
* put it — a file name on the one, a document title on the other.
|
|
259
|
+
*/
|
|
260
|
+
name?: string
|
|
261
|
+
}
|
|
262
|
+
|
|
213
263
|
/**
|
|
214
264
|
* A tool call made by the model
|
|
215
265
|
*/
|
package/src/types.tools.ts
CHANGED
|
@@ -75,31 +75,45 @@ export interface ToolResult {
|
|
|
75
75
|
cardSuggestion?: string
|
|
76
76
|
|
|
77
77
|
/**
|
|
78
|
-
*
|
|
78
|
+
* Files to put in front of the user, in the conversation where the tool ran.
|
|
79
79
|
*
|
|
80
|
-
* For what a card cannot hold and the model cannot reproduce: a generated
|
|
81
|
-
*
|
|
82
|
-
* {@link ToolResult.display}, this is for the user
|
|
83
|
-
*
|
|
84
|
-
*
|
|
85
|
-
*
|
|
80
|
+
* For what a card cannot hold and the model cannot reproduce: a generated image,
|
|
81
|
+
* a photo fetched on the user's behalf, the PDF that came attached to a mail.
|
|
82
|
+
* Like {@link ToolResult.display}, this is for the user — it is lifted out before
|
|
83
|
+
* the result reaches the model, which would have nothing to do with the bytes but
|
|
84
|
+
* spend tokens on them. Say in `data` that a file was attached, so she can talk
|
|
85
|
+
* about it without reciting it.
|
|
86
86
|
*
|
|
87
|
-
* The host stores each one as an attachment of the conversation,
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
*
|
|
87
|
+
* The host stores each one as an attachment of the conversation, exactly as a
|
|
88
|
+
* file the user sends is stored, so it is served to every client and can be saved
|
|
89
|
+
* or shared from there. The store's own rules apply: JPEG and PNG, PDF, and plain
|
|
90
|
+
* text, up to 20 MB (1 MB for text). What the file *is* is read from the bytes,
|
|
91
|
+
* not from `name`, so a PDF mislabelled `.png` still lands as a PDF. One that
|
|
92
|
+
* fails the rules is dropped with a warning rather than half-shown.
|
|
93
|
+
*
|
|
94
|
+
* Attaching a file does not read it to the model. What comes back in the result
|
|
95
|
+
* the model sees is a reference apiece — `{ id, mime, name? }` under this same
|
|
96
|
+
* key, in place of the bytes — and she reads one with `core_read_attachment` if
|
|
97
|
+
* she decides to. That is the intended flow for a mail's attachment: hand it over
|
|
98
|
+
* here, and let her choose whether to open it.
|
|
92
99
|
*/
|
|
93
100
|
attachments?: ToolAttachment[]
|
|
94
101
|
}
|
|
95
102
|
|
|
96
103
|
/**
|
|
97
|
-
* One
|
|
104
|
+
* One file a tool wants to put in the conversation. See {@link ToolResult.attachments}.
|
|
98
105
|
*/
|
|
99
106
|
export interface ToolAttachment {
|
|
100
|
-
/** The
|
|
107
|
+
/** The bytes, base64 encoded. What they are is read from them, not from `name`. */
|
|
101
108
|
data: string
|
|
102
|
-
/**
|
|
109
|
+
/**
|
|
110
|
+
* A file name to offer when the user saves it, e.g. `friday.png` or
|
|
111
|
+
* `faktura-1042.pdf`.
|
|
112
|
+
*
|
|
113
|
+
* Worth sending for a picture and close to required for a document: it is the
|
|
114
|
+
* whole label the user sees in the conversation, and it is what Stina has to go
|
|
115
|
+
* on when she decides whether to read it.
|
|
116
|
+
*/
|
|
103
117
|
name?: string
|
|
104
118
|
}
|
|
105
119
|
|
package/src/types.ts
CHANGED
|
@@ -59,6 +59,7 @@ export type {
|
|
|
59
59
|
ModelCapabilities,
|
|
60
60
|
ChatMessage,
|
|
61
61
|
ChatImage,
|
|
62
|
+
ChatFile,
|
|
62
63
|
ToolCall,
|
|
63
64
|
ChatOptions,
|
|
64
65
|
GetModelsOptions,
|
|
@@ -100,6 +101,8 @@ export type {
|
|
|
100
101
|
BackgroundTaskCallback,
|
|
101
102
|
BackgroundTaskHealth,
|
|
102
103
|
BackgroundWorkersAPI,
|
|
104
|
+
AttachmentsAPI,
|
|
105
|
+
AttachmentContent,
|
|
103
106
|
} from './types.context.js'
|
|
104
107
|
|
|
105
108
|
// Storage and Secrets
|