@stratusagent/core 0.11.1 → 0.11.3
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/index.d.ts +657 -8
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +766 -24
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,138 @@ export type JsonObject = {
|
|
|
10
10
|
*/
|
|
11
11
|
export type SessionStatus = 'idle' | 'running' | 'pending_approval' | 'completed' | 'failed';
|
|
12
12
|
export type MessageRole = 'system' | 'user' | 'assistant' | 'tool';
|
|
13
|
+
/**
|
|
14
|
+
* The image formats a model request may carry. The list is the Messages
|
|
15
|
+
* API's, and it is exported so a channel deciding which of a message's
|
|
16
|
+
* attachments to fetch asks this rather than keeping its own copy — a
|
|
17
|
+
* format the API rejects is one the channel should never have downloaded.
|
|
18
|
+
*/
|
|
19
|
+
export declare const IMAGE_ATTACHMENT_MEDIA_TYPES: readonly ["image/jpeg", "image/png", "image/gif", "image/webp"];
|
|
20
|
+
export type ImageAttachmentMediaType = (typeof IMAGE_ATTACHMENT_MEDIA_TYPES)[number];
|
|
21
|
+
export declare const isImageAttachmentMediaType: (value: unknown) => value is ImageAttachmentMediaType;
|
|
22
|
+
/**
|
|
23
|
+
* The largest image a message may carry, in decoded bytes. The Messages
|
|
24
|
+
* API refuses anything over 5 MB per image, and a session is one JSON row
|
|
25
|
+
* that every later turn re-reads — an image is stored with the message it
|
|
26
|
+
* arrived on, so the cap is also what keeps a transcript readable.
|
|
27
|
+
*/
|
|
28
|
+
export declare const IMAGE_ATTACHMENT_MAX_BYTES: number;
|
|
29
|
+
/**
|
|
30
|
+
* The most image bytes one message may carry in total, decoded. The
|
|
31
|
+
* Messages API caps a request body at 32 MiB, and base64 costs a third
|
|
32
|
+
* again — so five images each just under the per-image cap pass one by one
|
|
33
|
+
* and still fail the turn together. 20 MiB decoded is 26.7 MiB encoded,
|
|
34
|
+
* leaving room for the text around it.
|
|
35
|
+
*/
|
|
36
|
+
export declare const IMAGE_ATTACHMENTS_MAX_TOTAL_BYTES: number;
|
|
37
|
+
/**
|
|
38
|
+
* The most images one request may carry, whatever they weigh. The Messages
|
|
39
|
+
* API accepts 100 per request, but past 20 it also shrinks what each may
|
|
40
|
+
* measure to 2000 pixels a side — and an image was accepted at up to
|
|
41
|
+
* `IMAGE_ATTACHMENT_MAX_DIMENSION` when it arrived. Twenty is the count at
|
|
42
|
+
* which every image already stored is still one the API takes.
|
|
43
|
+
*/
|
|
44
|
+
export declare const IMAGE_ATTACHMENTS_MAX_REPLAY_COUNT = 20;
|
|
45
|
+
/**
|
|
46
|
+
* The most an image may measure on either side, in pixels. The Messages
|
|
47
|
+
* API refuses anything larger, and a large flat PNG compresses far below
|
|
48
|
+
* the byte cap — so bytes alone would let an image in that fails the turn
|
|
49
|
+
* it arrives on and, once stored, every turn after.
|
|
50
|
+
*/
|
|
51
|
+
export declare const IMAGE_ATTACHMENT_MAX_DIMENSION = 8000;
|
|
52
|
+
export interface ImageDimensions {
|
|
53
|
+
width: number;
|
|
54
|
+
height: number;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* An image's pixel size, read from its header without decoding it, or
|
|
58
|
+
* nothing when the bytes do not carry the header and trailer their media
|
|
59
|
+
* type promises — which a caller should treat as "not an image it can
|
|
60
|
+
* send". The trailer is what catches a download cut short: a PNG ends in
|
|
61
|
+
* IEND, a JPEG in an end-of-image marker, a GIF in a trailer byte, and a
|
|
62
|
+
* RIFF container declares its own length. It is not a decode — bytes that
|
|
63
|
+
* open and close correctly can still be refused by a model API, and a
|
|
64
|
+
* provider handles that when it happens (see `omitImage`) — but it is
|
|
65
|
+
* everything that can be checked without an image library, which core
|
|
66
|
+
* does not carry. One reader for the four accepted formats, so a channel
|
|
67
|
+
* deciding whether to keep a download asks this rather than trusting the
|
|
68
|
+
* uploader's metadata.
|
|
69
|
+
*/
|
|
70
|
+
export declare const imageDimensions: (bytes: Uint8Array, mediaType: ImageAttachmentMediaType) => ImageDimensions | undefined;
|
|
71
|
+
/** What `imagesWithinReplayBudget` holds a request to; each defaults to the constant above it. */
|
|
72
|
+
export interface ImageReplayBudget {
|
|
73
|
+
bytes?: number;
|
|
74
|
+
count?: number;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* An image a person sent with a user message, as the model receives it.
|
|
78
|
+
* Bytes are base64 so the attachment survives in the session's JSON body
|
|
79
|
+
* and replays on every later turn the way the text does.
|
|
80
|
+
*/
|
|
81
|
+
export interface ImageAttachment {
|
|
82
|
+
mediaType: ImageAttachmentMediaType;
|
|
83
|
+
/** Base64-encoded image bytes. */
|
|
84
|
+
data: string;
|
|
85
|
+
/**
|
|
86
|
+
* What the sender called it, for a runtime that renders the transcript
|
|
87
|
+
* as text and can only say that an image was there.
|
|
88
|
+
*/
|
|
89
|
+
name?: string;
|
|
90
|
+
/**
|
|
91
|
+
* Set once the bytes have been let go of: the image fell outside the
|
|
92
|
+
* replay window when a later turn was stored (see
|
|
93
|
+
* `omitImagesOutsideReplayBudget`), and `data` is empty. The record that
|
|
94
|
+
* an image was here, and what it was called, outlives the pixels.
|
|
95
|
+
*/
|
|
96
|
+
omitted?: true;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Which of a transcript's images still travel on a request. Every image a
|
|
100
|
+
* session ever received is stored with its message and replayed on every
|
|
101
|
+
* later turn, so a per-message budget alone is not one: two messages that
|
|
102
|
+
* each fit would together exceed the request limit on the turn after. The
|
|
103
|
+
* budget — bytes and a count, both API limits — is spent newest first,
|
|
104
|
+
* within a message as well as across them: the latest message always
|
|
105
|
+
* arrives whole, because a channel already holds one message to this same
|
|
106
|
+
* budget, and once an image does not fit, nothing older does either, so
|
|
107
|
+
* what the model sees is a contiguous recent window rather than a
|
|
108
|
+
* scatter. A provider
|
|
109
|
+
* that sends image bytes asks this and sends a note in place of the rest;
|
|
110
|
+
* the transcript itself is never trimmed.
|
|
111
|
+
*
|
|
112
|
+
* Membership is by identity: the set holds the very objects on the
|
|
113
|
+
* messages, so a provider walking them asks `has(image)`.
|
|
114
|
+
*/
|
|
115
|
+
export declare const imagesWithinReplayBudget: (messages: readonly Message[], budget?: ImageReplayBudget) => ReadonlySet<ImageAttachment>;
|
|
116
|
+
/**
|
|
117
|
+
* Lets go of the bytes of every image outside the replay window, in
|
|
118
|
+
* place, keeping its name and the fact that it was there. The runner calls
|
|
119
|
+
* this as it stores a turn: the replay budget bounds what a provider
|
|
120
|
+
* sends, but a session is one JSON row that every turn re-reads and
|
|
121
|
+
* re-writes whole, and without this every image a thread ever received
|
|
122
|
+
* would stay in it — so anyone who can post to a channel could grow a row
|
|
123
|
+
* by the whole budget per message, forever. What the model can be shown is
|
|
124
|
+
* exactly what is kept, so nothing the trim removes could have been sent.
|
|
125
|
+
* Returns how many images it emptied.
|
|
126
|
+
*/
|
|
127
|
+
export declare const omitImagesOutsideReplayBudget: (messages: Message[], budget?: ImageReplayBudget) => number;
|
|
128
|
+
/**
|
|
129
|
+
* Lets go of one image's bytes in place, keeping the record that it was
|
|
130
|
+
* there. Besides the replay window, this is what a provider does to an
|
|
131
|
+
* image the model API refused: the header checks a channel runs are not a
|
|
132
|
+
* decode, so a file that opens and closes correctly can still be rejected
|
|
133
|
+
* — and because an image is stored before the provider is called, a
|
|
134
|
+
* rejection left alone would replay on every later turn of the session.
|
|
135
|
+
* Emptied in place on the session's own object, so the runner's next save
|
|
136
|
+
* carries it and the turn goes on with a note in the image's place.
|
|
137
|
+
*/
|
|
138
|
+
export declare const omitImage: (image: ImageAttachment) => void;
|
|
139
|
+
/**
|
|
140
|
+
* What stands in for an image `imagesWithinReplayBudget` left out — one
|
|
141
|
+
* wording, so every provider tells the model the same thing about the
|
|
142
|
+
* same gap.
|
|
143
|
+
*/
|
|
144
|
+
export declare const droppedImageNote: (image: ImageAttachment) => string;
|
|
13
145
|
export interface Message {
|
|
14
146
|
id: string;
|
|
15
147
|
role: MessageRole;
|
|
@@ -18,6 +150,25 @@ export interface Message {
|
|
|
18
150
|
createdAt: string;
|
|
19
151
|
toolCalls?: ToolCall[];
|
|
20
152
|
toolResult?: ToolResult;
|
|
153
|
+
/**
|
|
154
|
+
* Images sent with a user message. Present only on `user` messages that
|
|
155
|
+
* carried one; a provider that can show the model an image sends these
|
|
156
|
+
* alongside the text, and one that cannot names them instead.
|
|
157
|
+
*/
|
|
158
|
+
images?: ImageAttachment[];
|
|
159
|
+
/**
|
|
160
|
+
* A user message the agent was not spoken to by: something said in a
|
|
161
|
+
* conversation it is in, to somebody else — appended by `observe` with
|
|
162
|
+
* no turn run on it, or dispatched with `addressed: false`, which runs a
|
|
163
|
+
* turn the agent may answer with nothing. Present only when true.
|
|
164
|
+
*
|
|
165
|
+
* Durable, because it changes how the message is rendered on every later
|
|
166
|
+
* turn, not just the next one: every renderer passes user content through
|
|
167
|
+
* `promptTextOf`, which frames an overheard message as third-party speech
|
|
168
|
+
* so a stranger's words never read as something the agent was told to do
|
|
169
|
+
* — the boundary provenance draws, here at the point text enters.
|
|
170
|
+
*/
|
|
171
|
+
overheard?: boolean;
|
|
21
172
|
}
|
|
22
173
|
export interface AgentDescriptor {
|
|
23
174
|
id: string;
|
|
@@ -53,7 +204,32 @@ export interface AgentDefinition extends AgentDescriptor {
|
|
|
53
204
|
skills?: string[];
|
|
54
205
|
/** Credential names this agent may resolve. Omitted = none. */
|
|
55
206
|
credentials?: string[];
|
|
207
|
+
/**
|
|
208
|
+
* How this agent listens in a conversation it shares with people talking
|
|
209
|
+
* to each other — see `ListensMode`. Omitted = `thread`. Part of what an
|
|
210
|
+
* agent is rather than how a daemon is deployed, which is why it sits
|
|
211
|
+
* beside `tools` and `skills` and not in a channel's config block.
|
|
212
|
+
*/
|
|
213
|
+
listens?: ListensMode;
|
|
56
214
|
}
|
|
215
|
+
/**
|
|
216
|
+
* When an agent in a thread answers a message that did not name it.
|
|
217
|
+
*
|
|
218
|
+
* - `mentions`: only when named. The behavior before thread follow-through,
|
|
219
|
+
* kept because some agents should be exactly this.
|
|
220
|
+
* - `thread`: every untagged reply in a thread it is in, by the rule people
|
|
221
|
+
* use — the voice that just answered you is the one you are answering.
|
|
222
|
+
* Cheap and predictable, and right for a thread with one person in it.
|
|
223
|
+
* - `judge`: overhear everything, and while attentive — a bounded window
|
|
224
|
+
* after it last spoke — run a turn nobody asked for on each message and
|
|
225
|
+
* let the model decide whether it has anything to add. Outside the
|
|
226
|
+
* window a message is overheard for free. Every message the agent does
|
|
227
|
+
* not answer is heard in every mode; the modes differ only in what it
|
|
228
|
+
* answers.
|
|
229
|
+
*/
|
|
230
|
+
export type ListensMode = 'mentions' | 'thread' | 'judge';
|
|
231
|
+
export declare const LISTENS_MODES: readonly ListensMode[];
|
|
232
|
+
export declare const isListensMode: (value: unknown) => value is ListensMode;
|
|
57
233
|
export declare class AgentRegistry {
|
|
58
234
|
private agents;
|
|
59
235
|
register(agent: AgentDefinition): AgentDefinition;
|
|
@@ -110,12 +286,70 @@ export interface ToolCall {
|
|
|
110
286
|
toolName: string;
|
|
111
287
|
input: JsonObject;
|
|
112
288
|
}
|
|
289
|
+
/**
|
|
290
|
+
* Where a piece of content came from — the one answer to "who wrote this",
|
|
291
|
+
* carried from the tool that produced it through the session that read it
|
|
292
|
+
* into the memory entry that restates it.
|
|
293
|
+
*
|
|
294
|
+
* Ordered from most to least trusted, and the ordering is the whole
|
|
295
|
+
* mechanism: a session's label only ever moves down it, a memory write
|
|
296
|
+
* carries the lowest label the session has seen, and a delegate reply
|
|
297
|
+
* carries its target's. `leastTrusted` is the one place the order is read.
|
|
298
|
+
*
|
|
299
|
+
* - `user` — an authorized principal: the operator at a local terminal, or
|
|
300
|
+
* a channel sender the operator has named. Earned, never inferred from
|
|
301
|
+
* the shape of a channel; a DM proves nothing about who is typing.
|
|
302
|
+
* - `agent` — the agent's own work: its tools' output, its own conclusions,
|
|
303
|
+
* in a session where everything in context was `user` or `agent`.
|
|
304
|
+
* - `unknown` — provenance that was never recorded: a transcript or a
|
|
305
|
+
* memory entry from before it was tracked, a sender nobody has vouched
|
|
306
|
+
* for. Not `agent`, because absence of provenance is not evidence of
|
|
307
|
+
* trust; not `external`, because claiming a stranger wrote it overstates
|
|
308
|
+
* what is known.
|
|
309
|
+
* - `external` — written by a party the operator has not authorized: a web
|
|
310
|
+
* page, a search snippet, an MCP server's response, a fetched document.
|
|
311
|
+
*
|
|
312
|
+
* This is a label, not a gate. Nothing here refuses on it; what a consumer
|
|
313
|
+
* does about the label is that consumer's business.
|
|
314
|
+
*/
|
|
315
|
+
export type TrustLevel = 'user' | 'agent' | 'unknown' | 'external';
|
|
316
|
+
/** Every level, most trusted first. The order, stated once. */
|
|
317
|
+
export declare const TRUST_LEVELS: readonly TrustLevel[];
|
|
318
|
+
export declare const isTrustLevel: (value: unknown) => value is TrustLevel;
|
|
319
|
+
/**
|
|
320
|
+
* The lowest label among several — how trust combines everywhere: a
|
|
321
|
+
* session reading two things is as trusted as the less trusted of them.
|
|
322
|
+
* With no arguments, the top of the lattice.
|
|
323
|
+
*/
|
|
324
|
+
export declare const leastTrusted: (...levels: readonly TrustLevel[]) => TrustLevel;
|
|
325
|
+
/**
|
|
326
|
+
* The paths a tool result refers to as files for a channel to deliver: an
|
|
327
|
+
* ok result whose object output carries `file: string` or `files:
|
|
328
|
+
* string[]`. The one reading of that convention, shared by the channel
|
|
329
|
+
* that uploads them and the gateway that counts a turn which produced one
|
|
330
|
+
* as having said something — a chart in the thread is the last thing said
|
|
331
|
+
* as surely as a sentence is.
|
|
332
|
+
*/
|
|
333
|
+
export declare const filePathsOf: (result: Pick<ToolResult, "ok" | "output">) => string[];
|
|
113
334
|
export interface ToolResult {
|
|
114
335
|
callId: string;
|
|
115
336
|
toolName: string;
|
|
116
337
|
ok: boolean;
|
|
117
338
|
output: JsonValue;
|
|
118
339
|
error?: string;
|
|
340
|
+
/**
|
|
341
|
+
* Where this result's content came from. Set by the executor from the
|
|
342
|
+
* two producer channels — the tool's `outputTrust` declaration and any
|
|
343
|
+
* per-call `ExecutionContext.markTrust` — and `agent` for a tool that
|
|
344
|
+
* used neither.
|
|
345
|
+
*
|
|
346
|
+
* Optional only because persisted results predate it. A stored result
|
|
347
|
+
* with no label was written before provenance was tracked, and the
|
|
348
|
+
* runner reads that absence as `unknown`: those transcripts are the one
|
|
349
|
+
* corpus guaranteed to exist on the day this shipped, and some of them
|
|
350
|
+
* already hold hostile page content. A new result always carries one.
|
|
351
|
+
*/
|
|
352
|
+
trust?: TrustLevel;
|
|
119
353
|
}
|
|
120
354
|
export type ProviderPart = {
|
|
121
355
|
type: 'text';
|
|
@@ -263,6 +497,23 @@ export declare const originOf: (rawUrl: string) => string | undefined;
|
|
|
263
497
|
* is a second answer to "what may this agent do".
|
|
264
498
|
*/
|
|
265
499
|
export declare const matchesToolAllowlist: (toolName: string, allowlist: readonly string[]) => boolean;
|
|
500
|
+
/**
|
|
501
|
+
* Whether an allowlist entry and a declared namespace select any of the
|
|
502
|
+
* same tools — true when either sits under the other.
|
|
503
|
+
*
|
|
504
|
+
* Namespaces nest, so both shapes are real: `mcp.linear.*` sits under a
|
|
505
|
+
* declared `mcp.*`, and a granted `mcp.*` covers everything a narrower
|
|
506
|
+
* declared `mcp.linear.*` will register. Both arguments are passed where a
|
|
507
|
+
* tool name goes on purpose — entry and namespace are the same dotted-prefix
|
|
508
|
+
* glob, so this is the reading the allowlists already use rather than a
|
|
509
|
+
* second one.
|
|
510
|
+
*
|
|
511
|
+
* Exported because the dead-entry check is no longer the only caller:
|
|
512
|
+
* `stratus plugins` answers which agents a namespace reaches before any of
|
|
513
|
+
* its tools exist, and a second hand-rolled overlap would drift from this
|
|
514
|
+
* one immediately.
|
|
515
|
+
*/
|
|
516
|
+
export declare const toolScopesOverlap: (entry: string, namespace: string) => boolean;
|
|
266
517
|
/**
|
|
267
518
|
* Whether an agent's `skills:` allowlist permits a skill id.
|
|
268
519
|
*
|
|
@@ -413,7 +664,45 @@ export interface MemoryEntry {
|
|
|
413
664
|
content: string;
|
|
414
665
|
createdAt: string;
|
|
415
666
|
metadata?: JsonObject;
|
|
667
|
+
/**
|
|
668
|
+
* Where the fact came from — the least trusted thing the writing session
|
|
669
|
+
* had in context. Absent on an entry recorded before provenance was
|
|
670
|
+
* tracked and on a hand-added line; `memoryEntryTrust` reads that
|
|
671
|
+
* absence as `unknown`, and so does every consumer, because defaulting it
|
|
672
|
+
* to `agent` would carry the laundering path forward across every
|
|
673
|
+
* upgrade, on the only corpus anyone has. `trust` is the control;
|
|
674
|
+
* `origin` below is description.
|
|
675
|
+
*/
|
|
676
|
+
trust?: TrustLevel;
|
|
677
|
+
/**
|
|
678
|
+
* Descriptive, and complete as stated: the session the entry was written
|
|
679
|
+
* in, and what tainted that session when something did. Nothing decides
|
|
680
|
+
* anything from it — it answers "where did this come from" for a person
|
|
681
|
+
* reading the store, and travels with the entry as ordinary data.
|
|
682
|
+
*/
|
|
683
|
+
origin?: MemoryOrigin;
|
|
684
|
+
}
|
|
685
|
+
export interface MemoryOrigin {
|
|
686
|
+
sessionId?: string;
|
|
687
|
+
/**
|
|
688
|
+
* The tool whose result lowered the writing session's trust — or
|
|
689
|
+
* `memory`, `sender`, or `legacy` when it was an injected entry, the
|
|
690
|
+
* turn's sender, or a transcript from before provenance was tracked.
|
|
691
|
+
* Absent when nothing did.
|
|
692
|
+
*/
|
|
693
|
+
taintedBy?: string;
|
|
416
694
|
}
|
|
695
|
+
/** What a writer says about a fact's provenance — the label, and where it was written. */
|
|
696
|
+
export interface MemoryProvenance {
|
|
697
|
+
trust: TrustLevel;
|
|
698
|
+
origin?: MemoryOrigin;
|
|
699
|
+
}
|
|
700
|
+
/**
|
|
701
|
+
* An entry's label as every consumer reads it: the recorded one, or
|
|
702
|
+
* `unknown` when none was recorded. Never `agent` by default — see
|
|
703
|
+
* `MemoryEntry.trust`.
|
|
704
|
+
*/
|
|
705
|
+
export declare const memoryEntryTrust: (entry: Pick<MemoryEntry, "trust">) => TrustLevel;
|
|
417
706
|
/**
|
|
418
707
|
* A memory entry as the operator's audit read returns it: tombstoned entries
|
|
419
708
|
* stay visible there, marked with when the agent dropped them. The paths that
|
|
@@ -518,8 +807,13 @@ export declare const boundMemoryList: (candidates: readonly MemoryEntry[], limit
|
|
|
518
807
|
* visible to an operator.
|
|
519
808
|
*/
|
|
520
809
|
export interface AgentMemoryStore {
|
|
521
|
-
/**
|
|
522
|
-
|
|
810
|
+
/**
|
|
811
|
+
* Refuses content over `MEMORY_ENTRY_MAX_BYTES` rather than truncating it.
|
|
812
|
+
* `provenance` is what the writer knows about where the fact came from;
|
|
813
|
+
* an append without one stores an entry that reads as `unknown`, which
|
|
814
|
+
* is the honest label for a writer that did not say.
|
|
815
|
+
*/
|
|
816
|
+
append(agentId: string, content: string, metadata?: JsonObject, provenance?: MemoryProvenance): Promise<MemoryEntry>;
|
|
523
817
|
/** Live entries, oldest first. See `MemoryListOptions` for the bounded form. */
|
|
524
818
|
list(agentId: string, options?: MemoryListOptions): Promise<MemoryReadResult>;
|
|
525
819
|
/** Live entries matching the literal query, newest first, bounded. */
|
|
@@ -528,6 +822,18 @@ export interface AgentMemoryStore {
|
|
|
528
822
|
forget(agentId: string, entryId: string): Promise<boolean>;
|
|
529
823
|
/** The operator's audit read: every entry, tombstoned included, oldest first. */
|
|
530
824
|
audit(agentId: string): Promise<MemoryAuditEntry[]>;
|
|
825
|
+
/**
|
|
826
|
+
* Re-label a live entry's trust — the one way a label ever rises, and it
|
|
827
|
+
* is a person's to use: an upgraded install's whole corpus is `unknown`
|
|
828
|
+
* and would stay so forever otherwise, since new writes carry the field
|
|
829
|
+
* and nothing else does. No tool exposes this; an agent re-labelling its
|
|
830
|
+
* own memory as trusted is the attack writing its own permission slip.
|
|
831
|
+
* False when no live entry of this agent has that id.
|
|
832
|
+
*
|
|
833
|
+
* Optional: a store that omits it cannot be re-asserted, and its
|
|
834
|
+
* operator has no way out of `unknown` but rewriting the record.
|
|
835
|
+
*/
|
|
836
|
+
reassertTrust?(agentId: string, entryId: string, trust: TrustLevel): Promise<boolean>;
|
|
531
837
|
}
|
|
532
838
|
export declare class InMemoryAgentMemoryStore implements AgentMemoryStore {
|
|
533
839
|
private entries;
|
|
@@ -536,12 +842,13 @@ export declare class InMemoryAgentMemoryStore implements AgentMemoryStore {
|
|
|
536
842
|
constructor(options?: {
|
|
537
843
|
now?: () => Date;
|
|
538
844
|
});
|
|
539
|
-
append(agentId: string, content: string, metadata?: JsonObject): Promise<MemoryEntry>;
|
|
845
|
+
append(agentId: string, content: string, metadata?: JsonObject, provenance?: MemoryProvenance): Promise<MemoryEntry>;
|
|
540
846
|
private live;
|
|
541
847
|
list(agentId: string, options?: MemoryListOptions): Promise<MemoryReadResult>;
|
|
542
848
|
search(agentId: string, query: string, limit?: number): Promise<MemoryReadResult>;
|
|
543
849
|
forget(agentId: string, entryId: string): Promise<boolean>;
|
|
544
850
|
audit(agentId: string): Promise<MemoryAuditEntry[]>;
|
|
851
|
+
reassertTrust(agentId: string, entryId: string, trust: TrustLevel): Promise<boolean>;
|
|
545
852
|
}
|
|
546
853
|
/**
|
|
547
854
|
* Resolves named credentials for an agent. Implementations must enforce the
|
|
@@ -750,6 +1057,18 @@ export declare const DEFAULT_SUBPROCESS_PASS_ENV: readonly string[];
|
|
|
750
1057
|
*/
|
|
751
1058
|
export interface ExecutionContext {
|
|
752
1059
|
signal?: AbortSignal;
|
|
1060
|
+
/**
|
|
1061
|
+
* Label this one call's output — the per-call half of the producer
|
|
1062
|
+
* channel, for a tool whose output is only sometimes external: an
|
|
1063
|
+
* `fs.read` of a file the agent downloaded, an MCP tool with mixed
|
|
1064
|
+
* responses, a `memory.recall` that surfaced an `external` entry. The
|
|
1065
|
+
* tool-wide half is `Tool.outputTrust`. Rides here as a sink, the way
|
|
1066
|
+
* `onUsage` does on a provider request, so `execute`'s return type does
|
|
1067
|
+
* not change. Several marks combine to the least trusted; the executor
|
|
1068
|
+
* promotes the result into `ToolResult.trust`. A host that hands a tool
|
|
1069
|
+
* no sink gets whatever `outputTrust` declares.
|
|
1070
|
+
*/
|
|
1071
|
+
markTrust?: (trust: TrustLevel) => void;
|
|
753
1072
|
}
|
|
754
1073
|
export interface Tool {
|
|
755
1074
|
name: string;
|
|
@@ -758,6 +1077,19 @@ export interface Tool {
|
|
|
758
1077
|
parameters?: JsonObject;
|
|
759
1078
|
/** See ToolRisk. Omitted means `gated`, never `safe`. */
|
|
760
1079
|
risk?: ToolRisk;
|
|
1080
|
+
/**
|
|
1081
|
+
* Where this tool's output comes from, declared once for every call —
|
|
1082
|
+
* `risk`'s twin for provenance. `browser.read` returns a page's text and
|
|
1083
|
+
* `web.fetch` a document's, so both declare `external` statically; a
|
|
1084
|
+
* tool whose output is only sometimes from outside marks the call
|
|
1085
|
+
* instead, through `ExecutionContext.markTrust`. Omitted means `agent`:
|
|
1086
|
+
* the tool's output is the agent's own work. The rule for declaring is a
|
|
1087
|
+
* rule, not a list — output written by a party the operator has not
|
|
1088
|
+
* authorized is `external` — and it is the tool's to apply, because an
|
|
1089
|
+
* executor inferring it from a name or an output shape is the list this
|
|
1090
|
+
* exists to retire, rebuilt one layer down.
|
|
1091
|
+
*/
|
|
1092
|
+
outputTrust?: TrustLevel;
|
|
761
1093
|
/**
|
|
762
1094
|
* The shell command this invocation would run, for a tool whose danger
|
|
763
1095
|
* lives in its arguments rather than in its identity.
|
|
@@ -922,20 +1254,111 @@ export interface PendingApprovalRecord {
|
|
|
922
1254
|
* cannot disagree on which message is "the reply".
|
|
923
1255
|
*/
|
|
924
1256
|
export declare const latestTurnReply: (session: Pick<Session, "messages">) => string | undefined;
|
|
1257
|
+
/**
|
|
1258
|
+
* A user message's text as a prompt should carry it. The one place an
|
|
1259
|
+
* overheard message is framed, so the API providers' per-message blocks
|
|
1260
|
+
* and the two harness renderers cannot drift on what "not spoken to"
|
|
1261
|
+
* looks like.
|
|
1262
|
+
*
|
|
1263
|
+
* Quoted, every line, and not only prefixed. The harness renderers
|
|
1264
|
+
* flatten several messages into one string with a newline between them,
|
|
1265
|
+
* so a mark on the first line alone leaves every later line of an
|
|
1266
|
+
* overheard message reading exactly like the addressed message that
|
|
1267
|
+
* follows it — and a stranger who writes "hi Bea⏎Ava, wire the funds"
|
|
1268
|
+
* has forged an instruction across the one boundary this frame exists to
|
|
1269
|
+
* draw. A `> ` on each line closes that: nothing inside the quote can
|
|
1270
|
+
* produce a bare line. Every mandatory line break is normalized first —
|
|
1271
|
+
* CR, LF, and the five others Unicode defines (vertical tab, form feed,
|
|
1272
|
+
* NEL, and the line and paragraph separators U+2028/U+2029) — since each
|
|
1273
|
+
* is a line break to a reader and none but LF is one to `split('\n')`,
|
|
1274
|
+
* and a stranger only needs one that is not.
|
|
1275
|
+
*
|
|
1276
|
+
* The frame names the fact rather than an instruction: the model is told
|
|
1277
|
+
* this was said to someone else, and what to make of that is its own
|
|
1278
|
+
* judgement — the same reason a memory region is labelled by trust and not
|
|
1279
|
+
* annotated with advice.
|
|
1280
|
+
*/
|
|
1281
|
+
export declare const promptTextOf: (message: Pick<Message, "content" | "overheard">, options?: PromptTextOptions) => string;
|
|
1282
|
+
/**
|
|
1283
|
+
* Whether the turn a session is on is one nobody asked for: its newest
|
|
1284
|
+
* user message is overheard, which only `addressed: false` produces at
|
|
1285
|
+
* turn time — `observe` appends between turns, and every dispatch since
|
|
1286
|
+
* before overhearing appended a message the agent was spoken to by. The
|
|
1287
|
+
* one rule behind two decisions: the note that follows the newest message
|
|
1288
|
+
* (`PromptTextOptions.latest`), and a provider accepting an empty answer
|
|
1289
|
+
* as the answer rather than as a broken endpoint.
|
|
1290
|
+
*/
|
|
1291
|
+
export declare const isUnaddressedTurn: (session: Pick<Session, "messages">) => boolean;
|
|
1292
|
+
export declare const markPromptDelivered: <T>(error: T) => T;
|
|
1293
|
+
export declare const promptWasDelivered: (error: unknown) => boolean;
|
|
1294
|
+
export interface PromptTextOptions {
|
|
1295
|
+
/**
|
|
1296
|
+
* Whether this is the newest user message of the turn being run. A turn
|
|
1297
|
+
* that ends on an overheard message is one nobody asked for — it was
|
|
1298
|
+
* dispatched with `addressed: false` — and the message is followed by
|
|
1299
|
+
* `UNADDRESSED_TURN_NOTE`, telling the model so. Only the newest: the
|
|
1300
|
+
* same message rendered on a later turn is history, and the decision it
|
|
1301
|
+
* carried has been made.
|
|
1302
|
+
*/
|
|
1303
|
+
latest?: boolean;
|
|
1304
|
+
}
|
|
1305
|
+
/**
|
|
1306
|
+
* What a turn nobody asked for is told, after the message it ends on.
|
|
1307
|
+
*
|
|
1308
|
+
* The load-bearing sentence of reading the room, and the one that cannot
|
|
1309
|
+
* be specified into correctness: a model asked "should you answer?" says
|
|
1310
|
+
* yes far more often than a person would, so the note leans on silence
|
|
1311
|
+
* hard, names the few things worth breaking it for, and says what an
|
|
1312
|
+
* answer must not be — an acknowledgement is the interruption it exists
|
|
1313
|
+
* to prevent. In the message and not the system prompt, because it has
|
|
1314
|
+
* to reach a harness that holds its own history and takes only the newest
|
|
1315
|
+
* message, and because a rule read next to the thing it applies to is
|
|
1316
|
+
* followed more often than one read an hour ago.
|
|
1317
|
+
*/
|
|
1318
|
+
export declare const UNADDRESSED_TURN_NOTE = "Nobody said that to you, and nobody is waiting on you. Reply only if you have something these people would want from you and do not have \u2014 an answer to a question left open, a correction to something wrong, a thing you were asked to watch for. Otherwise reply with nothing at all: no acknowledgement, no summary, no offer to help. Saying nothing is usually the right answer here.";
|
|
925
1319
|
/** Reads the checkpoint off a session, if it is parked. */
|
|
926
1320
|
export declare const readPendingApproval: (session: Session) => PendingApprovalRecord | undefined;
|
|
927
1321
|
/**
|
|
928
1322
|
* What a human decided about one gated call.
|
|
929
1323
|
*
|
|
930
1324
|
* - `once` — run this call, ask again next time.
|
|
931
|
-
* - `always` — run it and stop asking
|
|
1325
|
+
* - `always` — run it, and stop asking this agent's future calls that
|
|
1326
|
+
* the answer covers. What it covers is the policy's to say, in advance,
|
|
1327
|
+
* through `AlwaysMeans`.
|
|
932
1328
|
* - `deny` — refuse it.
|
|
933
|
-
*
|
|
934
|
-
* `always` is deliberately not "forever": a persistent whitelist is a
|
|
935
|
-
* different, narrower promise (a normalized command scope) and belongs
|
|
936
|
-
* with the shell tool that needs one.
|
|
937
1329
|
*/
|
|
938
1330
|
export type ApprovalAnswer = 'once' | 'always' | 'deny';
|
|
1331
|
+
/**
|
|
1332
|
+
* What answering `always` to one request would remember, said before
|
|
1333
|
+
* anyone is asked so every surface can word the button honestly.
|
|
1334
|
+
*
|
|
1335
|
+
* - `scope` — the command's normalized scope, durable and per agent
|
|
1336
|
+
* (`Tool.commandFor`).
|
|
1337
|
+
* - `origin` — the site the conversation is on, durable and per agent
|
|
1338
|
+
* (`Tool.originFor`).
|
|
1339
|
+
* - `tool` — the tool itself, durable and per agent, until an operator
|
|
1340
|
+
* revokes it: the standing grant, for a gated tool that names no scope.
|
|
1341
|
+
* - `session` — the tool, for this session and this process only. What a
|
|
1342
|
+
* tool judged by destination (`Tool.destinationFor`) gets outside a
|
|
1343
|
+
* schedule, because a durable grant there would be a standing yes to
|
|
1344
|
+
* every destination, and no per-destination grant exists yet.
|
|
1345
|
+
*
|
|
1346
|
+
* Absent when `always` remembers nothing at all — the one-shot case,
|
|
1347
|
+
* which `oneShot` names.
|
|
1348
|
+
*/
|
|
1349
|
+
export type AlwaysMeans = 'scope' | 'origin' | 'tool' | 'session';
|
|
1350
|
+
/**
|
|
1351
|
+
* A human's answer, and who gave it when a channel can say. What a
|
|
1352
|
+
* transport settles a request with: the policy records the actor on a
|
|
1353
|
+
* standing grant, and nothing else about the decision needs a person's
|
|
1354
|
+
* id — which is why the plain answer is still accepted everywhere an
|
|
1355
|
+
* outcome is.
|
|
1356
|
+
*/
|
|
1357
|
+
export interface ApprovalOutcome {
|
|
1358
|
+
answer: ApprovalAnswer;
|
|
1359
|
+
/** Channel-native id (a Slack user). */
|
|
1360
|
+
actor?: string;
|
|
1361
|
+
}
|
|
939
1362
|
/**
|
|
940
1363
|
* Why an approval request stopped being pending. Only `decided` involved a
|
|
941
1364
|
* person; the rest are the request running out of patience, the turn it
|
|
@@ -954,6 +1377,17 @@ export type StratusEvent = {
|
|
|
954
1377
|
type: 'session.updated';
|
|
955
1378
|
sessionId: string;
|
|
956
1379
|
status: SessionStatus;
|
|
1380
|
+
}
|
|
1381
|
+
/**
|
|
1382
|
+
* A message entered the session without a turn — `AgentRunner.observe`.
|
|
1383
|
+
* Its own event rather than a `session.updated`, because a renderer that
|
|
1384
|
+
* takes `running` as "a reply is coming" would open a placeholder for a
|
|
1385
|
+
* turn that never speaks. By name only, like everything the log keeps.
|
|
1386
|
+
*/
|
|
1387
|
+
| {
|
|
1388
|
+
type: 'session.observed';
|
|
1389
|
+
sessionId: string;
|
|
1390
|
+
agentId: string;
|
|
957
1391
|
} | {
|
|
958
1392
|
type: 'provider.delta';
|
|
959
1393
|
sessionId: string;
|
|
@@ -1008,6 +1442,14 @@ export type StratusEvent = {
|
|
|
1008
1442
|
* will not create. See `Tool.originFor` and `ToolRisk`.
|
|
1009
1443
|
*/
|
|
1010
1444
|
oneShot?: boolean;
|
|
1445
|
+
/**
|
|
1446
|
+
* What `always` would remember, when it would remember something —
|
|
1447
|
+
* see `AlwaysMeans`. A renderer that reports the outcome of an
|
|
1448
|
+
* `always` reads this rather than guessing at a lifetime: a grant
|
|
1449
|
+
* that survives restarts and one that dies with the session are the
|
|
1450
|
+
* same button, and only the request knows which it is.
|
|
1451
|
+
*/
|
|
1452
|
+
always?: AlwaysMeans;
|
|
1011
1453
|
metadata?: JsonObject;
|
|
1012
1454
|
/**
|
|
1013
1455
|
* When the request gives up and denies itself, ISO-8601. Absent when
|
|
@@ -1041,6 +1483,19 @@ export type StratusEvent = {
|
|
|
1041
1483
|
type: 'session.failed';
|
|
1042
1484
|
sessionId: string;
|
|
1043
1485
|
error: string;
|
|
1486
|
+
}
|
|
1487
|
+
/**
|
|
1488
|
+
* The session's trust label went down. `source` names what lowered it —
|
|
1489
|
+
* a tool, by name, or `memory` (an injected or recalled entry), `sender`
|
|
1490
|
+
* (the turn's principal), `legacy` (a transcript from before provenance
|
|
1491
|
+
* was tracked). Never the content: this is what the daemon log records,
|
|
1492
|
+
* and the log is a trace, not a transcript.
|
|
1493
|
+
*/
|
|
1494
|
+
| {
|
|
1495
|
+
type: 'session.tainted';
|
|
1496
|
+
sessionId: string;
|
|
1497
|
+
trust: TrustLevel;
|
|
1498
|
+
source: string;
|
|
1044
1499
|
};
|
|
1045
1500
|
export type EventHandler = (event: StratusEvent) => void | Promise<void>;
|
|
1046
1501
|
export interface EventBusOptions {
|
|
@@ -1307,6 +1762,34 @@ export declare const createSkillReadTool: (skills: SkillRegistry, options?: Skil
|
|
|
1307
1762
|
export declare const renderPersonaSection: (agent: Pick<AgentDefinition, "name" | "instructions">, options?: {
|
|
1308
1763
|
fallback?: boolean;
|
|
1309
1764
|
}) => string | undefined;
|
|
1765
|
+
/**
|
|
1766
|
+
* How each trust label introduces its region of the memory block. The
|
|
1767
|
+
* `agent` line is the one memory has always rendered under; the others say
|
|
1768
|
+
* what the label means, because the point of a region is that the model
|
|
1769
|
+
* reads a stranger's sentence as a stranger's.
|
|
1770
|
+
*/
|
|
1771
|
+
export declare const memoryRegionHeading: (trust: TrustLevel) => string;
|
|
1772
|
+
/**
|
|
1773
|
+
* The memory block, one region per trust label present, most trusted
|
|
1774
|
+
* first, entries in the order given within each.
|
|
1775
|
+
*
|
|
1776
|
+
* The invariant this enforces: nothing in the prompt derived from an entry
|
|
1777
|
+
* renders under a higher label than that entry carries. Stated over the
|
|
1778
|
+
* whole ordering rather than over `external` alone, because `unknown`
|
|
1779
|
+
* stopped being only a legacy artifact the moment an unauthorized sender's
|
|
1780
|
+
* message started producing it. An entry with no label renders in the
|
|
1781
|
+
* `unknown` region — never as the agent's own conclusion.
|
|
1782
|
+
*/
|
|
1783
|
+
/**
|
|
1784
|
+
* `text` on one line, every control character spelled out the way JSON
|
|
1785
|
+
* does (`\n`, `\u001b`), C1 controls and the Unicode line separators
|
|
1786
|
+
* included. The memory block and `stratus memory list` both frame an entry
|
|
1787
|
+
* by its line — `- ` under a region heading, an indent under an id — and a
|
|
1788
|
+
* fact holding a newline could otherwise start a line of its own that reads
|
|
1789
|
+
* as a heading, the trusted region's heading among them. Escaped rather
|
|
1790
|
+
* than dropped, so what is shown is still what is stored.
|
|
1791
|
+
*/
|
|
1792
|
+
export declare const escapeControlCharacters: (text: string) => string;
|
|
1310
1793
|
export declare const renderMemorySection: (memory: readonly MemoryEntry[] | undefined) => string | undefined;
|
|
1311
1794
|
/**
|
|
1312
1795
|
* The skills block: one line per enabled skill — id, name, and the
|
|
@@ -1354,9 +1837,93 @@ export declare const renderSystemPromptParts: (request: Pick<ProviderRequest, "s
|
|
|
1354
1837
|
export declare const renderSystemPromptSections: (request: Pick<ProviderRequest, "session" | "memory" | "skills">, options?: SystemPromptOptions) => string[];
|
|
1355
1838
|
/** The sections joined the way single-string providers send them. */
|
|
1356
1839
|
export declare const renderSystemPrompt: (request: Pick<ProviderRequest, "session" | "memory" | "skills">, options?: SystemPromptOptions) => string | undefined;
|
|
1840
|
+
/**
|
|
1841
|
+
* The two producer channels, collected for one call: the tool's standing
|
|
1842
|
+
* `outputTrust` declaration and whatever the tool marks through the
|
|
1843
|
+
* `markTrust` sink during the call. `resolve()` is the label the executor
|
|
1844
|
+
* promotes into the result — the least trusted of everything that fired,
|
|
1845
|
+
* `agent` when nothing did.
|
|
1846
|
+
*/
|
|
1847
|
+
export interface TrustMarking {
|
|
1848
|
+
/** The context to hand the tool: the caller's, with the sink attached. */
|
|
1849
|
+
context: ExecutionContext;
|
|
1850
|
+
resolve(): TrustLevel;
|
|
1851
|
+
}
|
|
1852
|
+
/**
|
|
1853
|
+
* Exported for every executor — `DefaultExecutor` here, `DirectExecutor`
|
|
1854
|
+
* and `LocalCommandExecutor` in their packages — so the promotion rule is
|
|
1855
|
+
* written once. An executor that inferred the label from a tool's name or
|
|
1856
|
+
* its output shape would be the enumerated list this replaces, rebuilt one
|
|
1857
|
+
* layer down; this one only reads what the tool said.
|
|
1858
|
+
*/
|
|
1859
|
+
export declare const createTrustMarking: (tool: Pick<Tool, "outputTrust">, context?: ExecutionContext) => TrustMarking;
|
|
1357
1860
|
export declare class DefaultExecutor implements Executor {
|
|
1358
1861
|
execute(call: ToolCall, tool: Tool, session: Session, context?: ExecutionContext): Promise<ToolResult>;
|
|
1359
1862
|
}
|
|
1863
|
+
/**
|
|
1864
|
+
* Where a session's trust label lives in `session.metadata`, so it survives
|
|
1865
|
+
* what the session survives: the gateway's store is SQLite and a thread
|
|
1866
|
+
* resumes across daemon restarts, and an in-memory flag would launder
|
|
1867
|
+
* every fact written after a restart mid-thread.
|
|
1868
|
+
*/
|
|
1869
|
+
export declare const SESSION_TRUST_METADATA_KEY = "sessionTrust";
|
|
1870
|
+
/** What last lowered the label — a tool name, or `memory` / `sender` / `legacy`. Description, not control. */
|
|
1871
|
+
export declare const SESSION_TAINTED_BY_METADATA_KEY = "sessionTaintedBy";
|
|
1872
|
+
/**
|
|
1873
|
+
* A turn's principal, as the dispatching surface evaluated it — carried on
|
|
1874
|
+
* the *turn's* metadata (`RunInput.metadata`, `ResumeInput.metadata`) and
|
|
1875
|
+
* never persisted: a Slack thread keys one session for every turn in it,
|
|
1876
|
+
* so an authorized member can open a thread and a stranger can mention the
|
|
1877
|
+
* agent inside it afterwards. Read off the session, the first sender's
|
|
1878
|
+
* trust would cover the stranger's message forever. Absent means `user`,
|
|
1879
|
+
* which is what every path without a channel already assumes: the
|
|
1880
|
+
* machine's owner is the operator.
|
|
1881
|
+
*/
|
|
1882
|
+
export declare const SENDER_TRUST_METADATA_KEY = "senderTrust";
|
|
1883
|
+
/**
|
|
1884
|
+
* A session's current label. `unknown` when none is recorded — a session
|
|
1885
|
+
* from before provenance was tracked — which is the reading every consumer
|
|
1886
|
+
* must share: absence of provenance is not evidence of trust.
|
|
1887
|
+
*/
|
|
1888
|
+
export declare const sessionTrustOf: (session: Pick<Session, "metadata">) => TrustLevel;
|
|
1889
|
+
/** What last lowered a session's label, when something did. */
|
|
1890
|
+
export declare const sessionTaintedBy: (session: Pick<Session, "metadata">) => string | undefined;
|
|
1891
|
+
/**
|
|
1892
|
+
* The trust a turn's sender earns, from the turn's metadata. See
|
|
1893
|
+
* `SENDER_TRUST_METADATA_KEY`. No key at all is the operator's own call —
|
|
1894
|
+
* the CLI, a control API client holding the token. A key holding anything
|
|
1895
|
+
* but a label is a channel that meant to say something and misspelled it,
|
|
1896
|
+
* and a misspelled authorization is not one: it reads `unknown`, the label
|
|
1897
|
+
* for provenance nobody can vouch for, never `user`.
|
|
1898
|
+
*/
|
|
1899
|
+
export declare const senderTrustOf: (metadata: JsonObject | undefined) => TrustLevel;
|
|
1900
|
+
/**
|
|
1901
|
+
* Whether a label is a taint — content from outside the boundary, or
|
|
1902
|
+
* content nobody can vouch for. `user` and `agent` are both inside it: an
|
|
1903
|
+
* agent's own work in its operator's conversation is the ordinary case, not
|
|
1904
|
+
* a lowering worth announcing.
|
|
1905
|
+
*/
|
|
1906
|
+
export declare const isTaintedTrust: (trust: TrustLevel) => boolean;
|
|
1907
|
+
/**
|
|
1908
|
+
* The label content the agent itself produces in this session carries — a
|
|
1909
|
+
* remembered fact, a prompt it delegates, a schedule it sets. At most
|
|
1910
|
+
* `agent`, whatever the session's own label: a restatement is the agent's
|
|
1911
|
+
* even when everything it restated was the operator's, which is what keeps
|
|
1912
|
+
* `user` meaning "a person said this" rather than "an agent said this to a
|
|
1913
|
+
* person". Below that, the session's label wins, so a session that has
|
|
1914
|
+
* seen `unknown` or `external` content writes that.
|
|
1915
|
+
*/
|
|
1916
|
+
export declare const sessionWriteTrust: (session: Pick<Session, "metadata">) => TrustLevel;
|
|
1917
|
+
/**
|
|
1918
|
+
* Lower a session's label to `trust` if that is lower than what it has,
|
|
1919
|
+
* recording `source` as the reason when the result is a taint. Monotonic: a
|
|
1920
|
+
* label never rises within a session, because raising it would need a
|
|
1921
|
+
* claim about what left the context, which nothing can make honestly.
|
|
1922
|
+
* Writes the key even when nothing lowers, so a session the runner has
|
|
1923
|
+
* evaluated is distinguishable from one it never saw. Returns whether the
|
|
1924
|
+
* label moved.
|
|
1925
|
+
*/
|
|
1926
|
+
export declare const lowerSessionTrust: (session: Session, trust: TrustLevel, source: string) => boolean;
|
|
1360
1927
|
export declare class AllowAllApprovalPolicy implements ApprovalPolicy {
|
|
1361
1928
|
approve(): Promise<boolean>;
|
|
1362
1929
|
}
|
|
@@ -1365,6 +1932,22 @@ export interface RunInput {
|
|
|
1365
1932
|
/** See Session.agent: the allowlist travels with the run. */
|
|
1366
1933
|
agent: AgentDefinition;
|
|
1367
1934
|
userMessage: string;
|
|
1935
|
+
/** Images sent with the message; see `Message.images`. */
|
|
1936
|
+
images?: ImageAttachment[];
|
|
1937
|
+
/**
|
|
1938
|
+
* Whether the message was said TO the agent. Omitted or true, the turn
|
|
1939
|
+
* is one somebody asked for, as every turn was before overhearing.
|
|
1940
|
+
* `false` runs a turn on something said to somebody else: the message
|
|
1941
|
+
* is stored `overheard`, rendered as third-party speech, and the model
|
|
1942
|
+
* is told (`UNADDRESSED_TURN_NOTE`) that it may answer with nothing — an
|
|
1943
|
+
* empty reply is then a decision, not a failure, and the turn completes
|
|
1944
|
+
* with an empty assistant message: no text for a surface to post, and a
|
|
1945
|
+
* boundary so the message is never judged twice. Such a turn carries no
|
|
1946
|
+
* images: they enter a prompt ahead of any frame that could mark them as
|
|
1947
|
+
* somebody else's, so a message nobody addressed to the agent names its
|
|
1948
|
+
* attachments instead, as an overheard one does.
|
|
1949
|
+
*/
|
|
1950
|
+
addressed?: boolean;
|
|
1368
1951
|
metadata?: JsonObject;
|
|
1369
1952
|
/** Aborting fails the turn cleanly; see RunAbortedError. */
|
|
1370
1953
|
signal?: AbortSignal;
|
|
@@ -1372,9 +1955,33 @@ export interface RunInput {
|
|
|
1372
1955
|
export interface ResumeInput {
|
|
1373
1956
|
sessionId: string;
|
|
1374
1957
|
userMessage: string;
|
|
1958
|
+
/** Images sent with the message; see `Message.images`. */
|
|
1959
|
+
images?: ImageAttachment[];
|
|
1960
|
+
/** See `RunInput.addressed`. */
|
|
1961
|
+
addressed?: boolean;
|
|
1962
|
+
/**
|
|
1963
|
+
* This turn's metadata — read for the sender's trust
|
|
1964
|
+
* (`SENDER_TRUST_METADATA_KEY`) and not merged into the session's. The
|
|
1965
|
+
* principal is a property of the turn, and a resumed turn that could not
|
|
1966
|
+
* say who sent it would hand a stranger's message the first sender's
|
|
1967
|
+
* trust.
|
|
1968
|
+
*/
|
|
1969
|
+
metadata?: JsonObject;
|
|
1375
1970
|
/** Aborting fails the turn cleanly; see RunAbortedError. */
|
|
1376
1971
|
signal?: AbortSignal;
|
|
1377
1972
|
}
|
|
1973
|
+
export interface ObserveInput {
|
|
1974
|
+
sessionId: string;
|
|
1975
|
+
/** What was said, as the transcript will carry it — speaker included, the way a channel already writes a user turn. */
|
|
1976
|
+
message: string;
|
|
1977
|
+
/**
|
|
1978
|
+
* This message's metadata, read for the speaker's trust exactly as
|
|
1979
|
+
* `ResumeInput.metadata` is and merged into nothing: an overheard
|
|
1980
|
+
* stranger lowers the session's label the same way one who addressed the
|
|
1981
|
+
* agent would, because their text is in the transcript either way.
|
|
1982
|
+
*/
|
|
1983
|
+
metadata?: JsonObject;
|
|
1984
|
+
}
|
|
1378
1985
|
/**
|
|
1379
1986
|
* Thrown when a run is stopped by its abort signal. The session ends up
|
|
1380
1987
|
* `failed` with this error's message as `lastError`, so an aborted turn is
|
|
@@ -1420,6 +2027,14 @@ export interface AgentRunnerOptions {
|
|
|
1420
2027
|
skills?: SkillRegistry;
|
|
1421
2028
|
/** Agent-scoped long-term memory, injected into every provider request. */
|
|
1422
2029
|
memory?: AgentMemoryStore;
|
|
2030
|
+
/**
|
|
2031
|
+
* How much of a session's images stay stored — bytes and a count, see
|
|
2032
|
+
* `omitImagesOutsideReplayBudget`. Defaults to core's constants for the
|
|
2033
|
+
* model API's limits; a host that omits it gets those, which is right
|
|
2034
|
+
* for every real provider and only wrong for a test that cannot afford
|
|
2035
|
+
* 20 MiB fixtures.
|
|
2036
|
+
*/
|
|
2037
|
+
imageReplayBudget?: ImageReplayBudget;
|
|
1423
2038
|
/** Maximum provider turns per run before the session fails. */
|
|
1424
2039
|
maxTurns?: number;
|
|
1425
2040
|
/**
|
|
@@ -1443,10 +2058,44 @@ export declare class AgentRunner {
|
|
|
1443
2058
|
readonly maxTurns: number;
|
|
1444
2059
|
readonly streaming: boolean;
|
|
1445
2060
|
private readonly options;
|
|
2061
|
+
private readonly imageReplayBudget;
|
|
1446
2062
|
constructor(options: AgentRunnerOptions);
|
|
1447
2063
|
initialize(): Promise<void>;
|
|
1448
2064
|
run(input: RunInput): Promise<Session>;
|
|
2065
|
+
/**
|
|
2066
|
+
* Lower the session's label and say so on the bus when it moved. The one
|
|
2067
|
+
* place the label is written during a turn, so every reason for a drop
|
|
2068
|
+
* — a tool's result, an injected entry, a sender, a legacy transcript —
|
|
2069
|
+
* is announced the same way and by name only.
|
|
2070
|
+
*/
|
|
2071
|
+
private taint;
|
|
2072
|
+
/**
|
|
2073
|
+
* A session with no label was written before provenance was tracked. It
|
|
2074
|
+
* reads `unknown` from here on, and the transcript it carries — which may
|
|
2075
|
+
* already hold hostile page content — is the reason: treating that
|
|
2076
|
+
* absence as untainted keeps the laundering path open for every
|
|
2077
|
+
* pre-upgrade conversation, the one corpus guaranteed to exist on the day
|
|
2078
|
+
* this shipped. Marking it `external` would be the other overcorrection.
|
|
2079
|
+
*/
|
|
2080
|
+
private labelLegacySession;
|
|
1449
2081
|
resume(input: ResumeInput): Promise<Session>;
|
|
2082
|
+
/**
|
|
2083
|
+
* A message reaching the session with no turn run on it: something said
|
|
2084
|
+
* in a conversation the agent is in, to somebody else. Appended and
|
|
2085
|
+
* saved, so the next turn the agent does take has it in hand; no
|
|
2086
|
+
* provider call, no reply, no status change, and its own event rather
|
|
2087
|
+
* than `session.updated`, since nothing is running.
|
|
2088
|
+
*
|
|
2089
|
+
* Refused while a turn is in flight. A parked turn's transcript ends in
|
|
2090
|
+
* a tool call awaiting its result, and a user message spliced in ahead
|
|
2091
|
+
* of that result is a wire-format violation on the API path — the one
|
|
2092
|
+
* shape `reconcileInterruptedToolCalls` exists to repair, and repairing
|
|
2093
|
+
* it here would close a call a human is still deciding on. A host that
|
|
2094
|
+
* serializes writes per session (the gateway's chain) only ever sees
|
|
2095
|
+
* this for a turn parked across a restart, and says so rather than
|
|
2096
|
+
* dropping the message silently.
|
|
2097
|
+
*/
|
|
2098
|
+
observe(input: ObserveInput): Promise<Session>;
|
|
1450
2099
|
/**
|
|
1451
2100
|
* Appends a synthetic failed result directly after every tool call that
|
|
1452
2101
|
* has none — the durable trace of a turn interrupted between the call's
|