salt-agent-sdk 0.1.0 → 0.19.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/LICENSE +21 -0
- package/README.md +941 -30
- package/dist/actions.d.ts +21 -5
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +673 -54
- package/dist/actions.js.map +1 -1
- package/dist/ask.d.ts +83 -0
- package/dist/ask.d.ts.map +1 -0
- package/dist/ask.js +215 -0
- package/dist/ask.js.map +1 -0
- package/dist/chatPrivacy.d.ts +34 -0
- package/dist/chatPrivacy.d.ts.map +1 -0
- package/dist/chatPrivacy.js +60 -0
- package/dist/chatPrivacy.js.map +1 -0
- package/dist/client.d.ts +3123 -35
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +1267 -143
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +16 -6
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +16 -5
- package/dist/config.js.map +1 -1
- package/dist/crypto.d.ts +62 -0
- package/dist/crypto.d.ts.map +1 -1
- package/dist/crypto.js +121 -0
- package/dist/crypto.js.map +1 -1
- package/dist/delegations.d.ts +25 -8
- package/dist/delegations.d.ts.map +1 -1
- package/dist/delegations.js +67 -11
- package/dist/delegations.js.map +1 -1
- package/dist/device/client.d.ts +161 -0
- package/dist/device/client.d.ts.map +1 -0
- package/dist/device/client.js +601 -0
- package/dist/device/client.js.map +1 -0
- package/dist/device/host.d.ts +222 -0
- package/dist/device/host.d.ts.map +1 -0
- package/dist/device/host.js +891 -0
- package/dist/device/host.js.map +1 -0
- package/dist/device/http.d.ts +12 -0
- package/dist/device/http.d.ts.map +1 -0
- package/dist/device/http.js +124 -0
- package/dist/device/http.js.map +1 -0
- package/dist/device/index.d.ts +5 -0
- package/dist/device/index.d.ts.map +1 -0
- package/dist/device/index.js +27 -0
- package/dist/device/index.js.map +1 -0
- package/dist/device/protocol.d.ts +312 -0
- package/dist/device/protocol.d.ts.map +1 -0
- package/dist/device/protocol.js +435 -0
- package/dist/device/protocol.js.map +1 -0
- package/dist/identities.d.ts +9 -2
- package/dist/identities.d.ts.map +1 -1
- package/dist/identities.js +33 -3
- package/dist/identities.js.map +1 -1
- package/dist/identity.d.ts +155 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +196 -0
- package/dist/identity.js.map +1 -0
- package/dist/identityShare.d.ts +129 -0
- package/dist/identityShare.d.ts.map +1 -0
- package/dist/identityShare.js +308 -0
- package/dist/identityShare.js.map +1 -0
- package/dist/ids.d.ts +11 -0
- package/dist/ids.d.ts.map +1 -0
- package/dist/ids.js +17 -0
- package/dist/ids.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -0
- package/dist/index.js.map +1 -1
- package/dist/reconcile.d.ts +25 -0
- package/dist/reconcile.d.ts.map +1 -0
- package/dist/reconcile.js +60 -0
- package/dist/reconcile.js.map +1 -0
- package/dist/recovery.d.ts +51 -0
- package/dist/recovery.d.ts.map +1 -0
- package/dist/recovery.js +59 -0
- package/dist/recovery.js.map +1 -0
- package/dist/register.d.ts +32 -0
- package/dist/register.d.ts.map +1 -0
- package/dist/register.js +65 -0
- package/dist/register.js.map +1 -0
- package/dist/scriptJob.d.ts +92 -0
- package/dist/scriptJob.d.ts.map +1 -0
- package/dist/scriptJob.js +270 -0
- package/dist/scriptJob.js.map +1 -0
- package/dist/sessions.d.ts +131 -0
- package/dist/sessions.d.ts.map +1 -0
- package/dist/sessions.js +240 -0
- package/dist/sessions.js.map +1 -0
- package/dist/socket.d.ts +115 -0
- package/dist/socket.d.ts.map +1 -0
- package/dist/socket.js +1038 -0
- package/dist/socket.js.map +1 -0
- package/dist/webhook.d.ts +627 -28
- package/dist/webhook.d.ts.map +1 -1
- package/dist/webhook.js +1388 -84
- package/dist/webhook.js.map +1 -1
- package/dist/work.d.ts +57 -0
- package/dist/work.d.ts.map +1 -0
- package/dist/work.js +213 -0
- package/dist/work.js.map +1 -0
- package/package.json +26 -4
package/dist/client.d.ts
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
|
+
import { type SaltId } from "./ids.js";
|
|
2
|
+
import { type IdentityClaims, type IdentitySections, type SignedCard } from "./identity.js";
|
|
3
|
+
import { type HeldRecoveryShare, type RecoveryGuardianInvitation, type RecoveryRequestForGuardian } from "./recovery.js";
|
|
4
|
+
export interface IdentityDisclosure {
|
|
5
|
+
id: string;
|
|
6
|
+
section_keys: string[];
|
|
7
|
+
scope: string;
|
|
8
|
+
chat_id: SaltId;
|
|
9
|
+
recipient_id: SaltId;
|
|
10
|
+
message_id?: SaltId | null;
|
|
11
|
+
created_at: string;
|
|
12
|
+
revoked_at?: string | null;
|
|
13
|
+
}
|
|
14
|
+
export interface PostIdentityDisclosureParams {
|
|
15
|
+
/** Client-generated (crypto.randomUUID()), ONE per share() call and posted for every recipient -- also what rides in the SLICE/DECLINE wire marker's `id=`. The server keys a row on (subject, recipient, id), so the same id with a DIFFERENT recipient_id creates its own row; the same id AND recipient_id together is idempotent (200 with the existing row instead of a second one). */
|
|
16
|
+
id: string;
|
|
17
|
+
section_keys: string[];
|
|
18
|
+
/** Optional since 0.86.1: omitted, salt-api records the narrowest real scope; named, it is held to per section. */
|
|
19
|
+
scope?: string;
|
|
20
|
+
chat_id: SaltId;
|
|
21
|
+
recipient_id: SaltId;
|
|
22
|
+
}
|
|
1
23
|
export interface SaltUser {
|
|
2
|
-
id:
|
|
24
|
+
id: SaltId;
|
|
3
25
|
username: string;
|
|
4
26
|
display_name: string;
|
|
5
27
|
account_type: "User" | "Agent";
|
|
@@ -7,23 +29,259 @@ export interface SaltUser {
|
|
|
7
29
|
public_fingerprint?: string;
|
|
8
30
|
[key: string]: unknown;
|
|
9
31
|
}
|
|
32
|
+
/** Who may start a 1:1 with an account without being refused or parked in Requests (`users.message_from`).
|
|
33
|
+
* `everyone`: anyone. `known`: strangers land in the recipient's Requests (the default for a person).
|
|
34
|
+
* `contacts`: strangers are refused with 403 `recipient_contacts_only`. An agent account defaults to `everyone`. */
|
|
35
|
+
export type MessageFrom = "everyone" | "known" | "contacts";
|
|
36
|
+
/** `request` means the other member's row in the 1:1 is a pending message request: the recipient has not
|
|
37
|
+
* accepted yet, so they get no push and read receipts are held back. Wait for them; do not re-send and
|
|
38
|
+
* do not open another chat. `chat` is a normal delivery. */
|
|
39
|
+
export type DeliveredAs = "chat" | "request";
|
|
10
40
|
export interface SaltChat {
|
|
11
|
-
id:
|
|
41
|
+
id: SaltId;
|
|
42
|
+
/** On a chat-create response: whether the other member received a normal chat or a pending request. */
|
|
43
|
+
delivered_as?: DeliveredAs;
|
|
44
|
+
/** `encrypted` is undefined on a server that predates open rooms, which
|
|
45
|
+
* always means an ordinary end-to-end encrypted chat -- see getChat's
|
|
46
|
+
* doc comment for the resolved, defaulted value callers actually use. */
|
|
12
47
|
session?: {
|
|
13
48
|
users?: SaltUser[];
|
|
49
|
+
encrypted?: boolean;
|
|
50
|
+
public?: boolean;
|
|
51
|
+
[key: string]: unknown;
|
|
14
52
|
};
|
|
15
53
|
messages?: unknown[];
|
|
16
54
|
[key: string]: unknown;
|
|
17
55
|
}
|
|
56
|
+
/** One row of `GET /api/v1/chats` (and `?requests=1`). There is NO top-level `id`: the chat's id is `session.id`.
|
|
57
|
+
* `recent_message` is `{}` for a chat with no messages. `session.request_state` is `"pending"` on a request. */
|
|
58
|
+
export interface SaltChatListRow {
|
|
59
|
+
session: {
|
|
60
|
+
id: SaltId;
|
|
61
|
+
request_state?: "pending" | null;
|
|
62
|
+
users?: SaltUser[];
|
|
63
|
+
[key: string]: unknown;
|
|
64
|
+
};
|
|
65
|
+
recent_message?: {
|
|
66
|
+
message?: unknown;
|
|
67
|
+
user?: unknown;
|
|
68
|
+
[key: string]: unknown;
|
|
69
|
+
};
|
|
70
|
+
[key: string]: unknown;
|
|
71
|
+
}
|
|
72
|
+
/** What `POST /api/v1/messages` answers: the stored message plus how it was delivered. */
|
|
73
|
+
export interface PostMessageResult {
|
|
74
|
+
delivered_as?: DeliveredAs;
|
|
75
|
+
[key: string]: unknown;
|
|
76
|
+
}
|
|
77
|
+
/** One row of `GET /api/v1/contacts/incoming`: an account that added the caller and that the caller has not
|
|
78
|
+
* added back. `added_at` is when they added you. */
|
|
79
|
+
export interface IncomingContact {
|
|
80
|
+
user: {
|
|
81
|
+
id: SaltId;
|
|
82
|
+
username: string;
|
|
83
|
+
display_name: string;
|
|
84
|
+
avatar_url: string | null;
|
|
85
|
+
account_type: "User" | "Agent";
|
|
86
|
+
/** Your own private nickname for them, when you set one. */
|
|
87
|
+
nickname?: string;
|
|
88
|
+
};
|
|
89
|
+
added_at: string;
|
|
90
|
+
}
|
|
91
|
+
/** Which part of an agent draft `draftAgent` (re)writes: `brief` (name, handle, bio, brief, assumptions),
|
|
92
|
+
* `personality` (voice, first_message) or `authority` (skills, services, budget_per_day, actions_estimate). */
|
|
93
|
+
export type AgentDraftStep = "brief" | "personality" | "authority";
|
|
94
|
+
/** The whole draft `POST /api/v1/agents/draft` answers with. A step rewrites only its own fields and keeps
|
|
95
|
+
* the rest exactly as sent. `brief` is PRIVATE (it becomes `persona.purpose`); `bio` is PUBLIC. */
|
|
96
|
+
export interface AgentDraft {
|
|
97
|
+
idea: string;
|
|
98
|
+
/** At most 40 characters, never contains "Salt". */
|
|
99
|
+
name: string;
|
|
100
|
+
/** A suggestion; check availability before creating. */
|
|
101
|
+
handle: string;
|
|
102
|
+
/** At most 280 characters, public, written for strangers, never quotes the brief. */
|
|
103
|
+
bio: string;
|
|
104
|
+
/** At most 4000 characters, second person. Private: only the owner and the agent see it. */
|
|
105
|
+
brief: string;
|
|
106
|
+
/** The choices made where the idea left room (at most 8). */
|
|
107
|
+
assumptions: Array<{
|
|
108
|
+
about: string;
|
|
109
|
+
choice: string;
|
|
110
|
+
}>;
|
|
111
|
+
/** At most 2000 characters (`persona.voice`). */
|
|
112
|
+
voice: string;
|
|
113
|
+
/** At most 500 characters (`persona.first_message`). */
|
|
114
|
+
first_message: string;
|
|
115
|
+
/** Every known skill appears exactly once across the two lists. `money`, `mandates` and `agents` are always optional. */
|
|
116
|
+
skills: {
|
|
117
|
+
recommended: Array<{
|
|
118
|
+
key: string;
|
|
119
|
+
why: string;
|
|
120
|
+
}>;
|
|
121
|
+
optional: Array<{
|
|
122
|
+
key: string;
|
|
123
|
+
why: string;
|
|
124
|
+
}>;
|
|
125
|
+
};
|
|
126
|
+
/** Only providers the caller has connected; may be empty. */
|
|
127
|
+
services: Array<{
|
|
128
|
+
provider: string;
|
|
129
|
+
recommended: boolean;
|
|
130
|
+
why: string;
|
|
131
|
+
}>;
|
|
132
|
+
/** `persona.budget_per_day`. */
|
|
133
|
+
budget_per_day: number;
|
|
134
|
+
actions_estimate: string;
|
|
135
|
+
/** The agent's own model spend per UTC month in USD (`persona.model_budget_usd`): a decimal string of whole dollars,
|
|
136
|
+
* "10" to "1000". Null until the `authority` step has run. */
|
|
137
|
+
model_budget_usd?: string | null;
|
|
138
|
+
/** A short sentence on what that amount is sized from ("About 10 actions a day"); "" until `authority` has run. */
|
|
139
|
+
budget_basis?: string;
|
|
140
|
+
[key: string]: unknown;
|
|
141
|
+
}
|
|
142
|
+
export interface DraftAgentParams {
|
|
143
|
+
/** Required on the first call (at most 500 characters). */
|
|
144
|
+
idea?: string;
|
|
145
|
+
/** Which part to (re)write. */
|
|
146
|
+
step: AgentDraftStep;
|
|
147
|
+
/** The current draft as the person edited it; required for `personality` and `authority`. */
|
|
148
|
+
draft?: AgentDraft;
|
|
149
|
+
/** Steers a rewrite, at most 120 characters ("More playful"). */
|
|
150
|
+
nudge?: string;
|
|
151
|
+
}
|
|
152
|
+
/** Which of an agent's two faces is shown: the owner's `photo`, or the `drawing` Salt draws for it. */
|
|
153
|
+
export type AgentFace = "photo" | "drawing";
|
|
154
|
+
/** What `getAgentAdmin` / the face helpers answer for the face: `avatar_url` is the stored photo (null when none),
|
|
155
|
+
* `face` which one is shown, `face_set_by` whose choice it is (`owner` outranks the agent's own). */
|
|
156
|
+
export interface AgentFaceFields {
|
|
157
|
+
avatar_url: string | null;
|
|
158
|
+
face: AgentFace | null;
|
|
159
|
+
/** Present only for the agent's owner and the agent itself; a stranger gets `face` only. */
|
|
160
|
+
face_set_by?: "owner" | "agent" | null;
|
|
161
|
+
}
|
|
162
|
+
/** One member on a team's roster. `role` is the job ("Showrunner"), `lead` is true for the team's arbiter. */
|
|
163
|
+
export interface TeamMember {
|
|
164
|
+
id: SaltId;
|
|
165
|
+
handle: string;
|
|
166
|
+
display_name: string;
|
|
167
|
+
role: string | null;
|
|
168
|
+
lead: boolean;
|
|
169
|
+
/** True when the room's owner owns this agent. Only owned agents can lead or sit in the room; an outside agent is consulted, never added. */
|
|
170
|
+
owned: boolean;
|
|
171
|
+
}
|
|
172
|
+
/** A team: an agent group with a lead, a role per member and one encrypted group chat (its room). */
|
|
173
|
+
export interface TeamGroup {
|
|
174
|
+
id: SaltId;
|
|
175
|
+
name: string;
|
|
176
|
+
description?: string;
|
|
177
|
+
color?: string;
|
|
178
|
+
member_ids: SaltId[];
|
|
179
|
+
/** The member who arbitrates the room; null means no lead (then nobody answers an un-@'d message). */
|
|
180
|
+
lead_agent_id: SaltId | null;
|
|
181
|
+
/** Null until `openTeamRoom` has made it. */
|
|
182
|
+
room_chat_id: SaltId | null;
|
|
183
|
+
members: TeamMember[];
|
|
184
|
+
[key: string]: unknown;
|
|
185
|
+
}
|
|
186
|
+
/** One team as an agent reads its own (`GET /api/v1/agent/teams`). `owner_id` is the group owner's chain root. */
|
|
187
|
+
export interface MyTeam {
|
|
188
|
+
id: SaltId;
|
|
189
|
+
name: string;
|
|
190
|
+
lead_agent_id: SaltId | null;
|
|
191
|
+
room_chat_id: SaltId | null;
|
|
192
|
+
/** The chain root above the group's owner (a person, or a root agent). */
|
|
193
|
+
owner_id: SaltId;
|
|
194
|
+
/** The group's direct owner, who may be an agent. When it is the caller's own owner or the caller itself, see AGENTS.md "Teams". */
|
|
195
|
+
group_owner_id: SaltId;
|
|
196
|
+
members: TeamMember[];
|
|
197
|
+
}
|
|
198
|
+
export type TeamDraftStep = "team" | "personality" | "authority";
|
|
199
|
+
/** One member of a team draft. Each step fills only its own fields and keeps the rest as sent. */
|
|
200
|
+
export interface TeamDraftMember {
|
|
201
|
+
/** The job: "Showrunner". */
|
|
202
|
+
role: string;
|
|
203
|
+
name: string;
|
|
204
|
+
handle: string;
|
|
205
|
+
/** Public. */
|
|
206
|
+
bio: string;
|
|
207
|
+
/** Private; includes the team's rules in plain words. */
|
|
208
|
+
brief: string;
|
|
209
|
+
why: string;
|
|
210
|
+
/** `personality` step. */
|
|
211
|
+
voice?: string;
|
|
212
|
+
/** `personality` step. Only the lead has one (the room introduction); a member's is "". */
|
|
213
|
+
first_message?: string;
|
|
214
|
+
/** `authority` step. */
|
|
215
|
+
skills?: AgentDraft["skills"];
|
|
216
|
+
services?: AgentDraft["services"];
|
|
217
|
+
budget_per_day?: number | null;
|
|
218
|
+
actions_estimate?: string;
|
|
219
|
+
/** A decimal string of whole dollars, "10" to "1000"; null until `authority` has run. */
|
|
220
|
+
model_budget_usd?: string | null;
|
|
221
|
+
budget_basis?: string;
|
|
222
|
+
[key: string]: unknown;
|
|
223
|
+
}
|
|
224
|
+
/** The team's totals, filled by the `authority` step. */
|
|
225
|
+
export interface TeamDraftTotals {
|
|
226
|
+
actions_per_day: number | null;
|
|
227
|
+
/** A decimal string of whole dollars (the members' monthly model limits summed); null until `authority` has run. */
|
|
228
|
+
model_budget_usd: string | null;
|
|
229
|
+
budget_basis: string;
|
|
230
|
+
}
|
|
231
|
+
/** The whole team draft `POST /api/v1/teams/draft` answers with. Two to five members including the lead. */
|
|
232
|
+
export interface TeamDraft {
|
|
233
|
+
idea: string;
|
|
234
|
+
team_name: string;
|
|
235
|
+
description: string;
|
|
236
|
+
/** One plain line on how they work together (at most 300 characters). */
|
|
237
|
+
how_they_work: string;
|
|
238
|
+
/** Index into `members` of the lead, or null for no lead. */
|
|
239
|
+
lead_index: number | null;
|
|
240
|
+
members: TeamDraftMember[];
|
|
241
|
+
totals: TeamDraftTotals;
|
|
242
|
+
[key: string]: unknown;
|
|
243
|
+
}
|
|
244
|
+
export interface DraftTeamParams {
|
|
245
|
+
/** Required on the first call. */
|
|
246
|
+
idea?: string;
|
|
247
|
+
/** Defaults to "team" on the server. */
|
|
248
|
+
step?: TeamDraftStep;
|
|
249
|
+
/** The current draft as edited; `personality` and `authority` need `draft.members` (2 to 5, each with a brief). */
|
|
250
|
+
draft?: TeamDraft;
|
|
251
|
+
/** Steers a rewrite ("More playful"), at most 120 characters. */
|
|
252
|
+
nudge?: string;
|
|
253
|
+
}
|
|
254
|
+
export interface SendAttachmentParams {
|
|
255
|
+
bytes: Buffer;
|
|
256
|
+
filename: string;
|
|
257
|
+
/** Must be one of crypto.ts's ALLOWED_SEND_CONTENT_TYPES -- sendAttachment
|
|
258
|
+
* throws rather than send an unrecognised value another member's client
|
|
259
|
+
* will make a rendering decision on (see that list's own comment). */
|
|
260
|
+
contentType: string;
|
|
261
|
+
/** Defaults to "📎 <sanitized filename>", the same fallback salt-fe's
|
|
262
|
+
* chatbox.jsx sendOneAttachment uses, so a captionless attachment reads
|
|
263
|
+
* identically whether it came from a person or an agent. */
|
|
264
|
+
caption?: string;
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Basename only, control characters and path separators stripped, capped at
|
|
268
|
+
* 200 characters, falling back to "attachment" when nothing usable is left.
|
|
269
|
+
* A filename lives only inside an attachment's PGP-encrypted metadata blob
|
|
270
|
+
* (see Attachment's header comment in salt-api) -- Salt itself never sees
|
|
271
|
+
* or sanitizes it -- so anything that later treats a DECRYPTED filename as
|
|
272
|
+
* a filesystem path (an agent's own read/save-to-disk tool) must sanitize
|
|
273
|
+
* on the way OUT, since it is exactly as attacker-controlled as any other
|
|
274
|
+
* chat member's input. Exported so both sendAttachment (outgoing) and a
|
|
275
|
+
* consumer's incoming-attachment handler can share one rule.
|
|
276
|
+
*/
|
|
277
|
+
export declare function sanitizeAttachmentFilename(name: string | undefined | null): string;
|
|
18
278
|
export interface CreateAgentParams {
|
|
19
279
|
username: string;
|
|
20
280
|
display_name: string;
|
|
21
281
|
description?: string;
|
|
22
282
|
webhook: string;
|
|
23
283
|
public_key: string;
|
|
24
|
-
private_key: string;
|
|
25
284
|
public_fingerprint: string;
|
|
26
|
-
revocation_cert?: string;
|
|
27
285
|
category?: string;
|
|
28
286
|
message_price?: string | number;
|
|
29
287
|
link?: string;
|
|
@@ -32,37 +290,560 @@ export interface CardBlock {
|
|
|
32
290
|
type: string;
|
|
33
291
|
[key: string]: unknown;
|
|
34
292
|
}
|
|
293
|
+
/** The `input` block (NEW): one text field. `block_id` must be unique
|
|
294
|
+
* across the whole card (including private blocks), `[a-z0-9_-]{1,40}`.
|
|
295
|
+
* Tapping any `default` button in the same card sends every input block's
|
|
296
|
+
* current value alongside the action -- see `CardInteractionContext.values`
|
|
297
|
+
* / `CardInteraction.values`, keyed by `block_id`. A plain object satisfies
|
|
298
|
+
* `CardBlock` already; this is here for callers who want the shape typed. */
|
|
299
|
+
export interface InputCardBlock extends CardBlock {
|
|
300
|
+
type: "input";
|
|
301
|
+
block_id: string;
|
|
302
|
+
label: string;
|
|
303
|
+
placeholder?: string;
|
|
304
|
+
multiline?: boolean;
|
|
305
|
+
/** 1..1000, defaults to 500 server-side when omitted. */
|
|
306
|
+
max_length?: number;
|
|
307
|
+
}
|
|
308
|
+
/** One recorded tap on a card's button, as `getCard` returns it -- newest
|
|
309
|
+
* first. `transfer_request_id`/`transfer_request_status` are present only
|
|
310
|
+
* for a tap that created a real payment request (a "pay" button), and the
|
|
311
|
+
* status is read LIVE by the server, never a snapshot from tap time.
|
|
312
|
+
* `values` (NEW) carries whatever the card's `input` blocks held at tap
|
|
313
|
+
* time, keyed by `block_id` -- `{}` when the card has none or the tapped
|
|
314
|
+
* button ignored them (pay/handoff buttons always do). */
|
|
315
|
+
export interface CardInteraction {
|
|
316
|
+
id: string;
|
|
317
|
+
user_id: SaltId;
|
|
318
|
+
action_id: string;
|
|
319
|
+
value?: unknown;
|
|
320
|
+
values?: Record<string, string>;
|
|
321
|
+
created_at: string;
|
|
322
|
+
transfer_request_id?: SaltId;
|
|
323
|
+
transfer_request_status?: string;
|
|
324
|
+
}
|
|
325
|
+
/** `getCard`'s response shape: the card's raw state (as its owner sees it --
|
|
326
|
+
* `state.private` included, unlike the per-viewer projection every other
|
|
327
|
+
* member gets in chat payloads) plus its tap history. */
|
|
328
|
+
export interface CardWithInteractions {
|
|
329
|
+
id: SaltId;
|
|
330
|
+
state: {
|
|
331
|
+
blocks: CardBlock[];
|
|
332
|
+
[key: string]: unknown;
|
|
333
|
+
};
|
|
334
|
+
owner_id: SaltId;
|
|
335
|
+
interactions: CardInteraction[];
|
|
336
|
+
}
|
|
337
|
+
export interface AppPerson {
|
|
338
|
+
id: SaltId;
|
|
339
|
+
username: string;
|
|
340
|
+
display_name: string;
|
|
341
|
+
}
|
|
342
|
+
/** One placeholder text field a quick action collects before it's sent -- omitted, the action has no input and its `label` alone is the ask's `text`. */
|
|
343
|
+
export interface AppQuickActionInput {
|
|
344
|
+
placeholder?: string;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* A small "quick tap" a version declares alongside its html -- rendered as
|
|
348
|
+
* a chip/button beside the running app (e.g. `AppMessage.jsx`) that calls
|
|
349
|
+
* `salt.ask` bound to `id`, using `label` as the ask's text (or, with
|
|
350
|
+
* `input` set, whatever one line the person typed into that field).
|
|
351
|
+
* Versioned exactly like the html itself: a new version's `actions`
|
|
352
|
+
* replace the prior version's for any installation that later updates to
|
|
353
|
+
* it -- an installation still pinned to an older version keeps that
|
|
354
|
+
* version's own `actions`.
|
|
355
|
+
*/
|
|
356
|
+
export interface AppQuickAction {
|
|
357
|
+
id: string;
|
|
358
|
+
label: string;
|
|
359
|
+
input?: AppQuickActionInput;
|
|
360
|
+
}
|
|
361
|
+
/** A version's identity as it rides on an app's metadata, a `newVersion` response, or a chat resource -- never the html itself (fetch that via the app_frames route, keyed by `id`). */
|
|
362
|
+
export interface AppVersionRef {
|
|
363
|
+
id: SaltId;
|
|
364
|
+
number: number;
|
|
365
|
+
/** This version's quick actions, if it declared any -- see AppQuickAction. */
|
|
366
|
+
actions?: AppQuickAction[];
|
|
367
|
+
}
|
|
368
|
+
/** One agent's recipe inside a team template. Never a key, memory, credential, grant, wallet or chat -- see `teams` below. */
|
|
369
|
+
export interface TeamAgentRecipe {
|
|
370
|
+
name: string;
|
|
371
|
+
purpose: string;
|
|
372
|
+
/** The agent's voice text. */
|
|
373
|
+
persona: string;
|
|
374
|
+
directives: string[];
|
|
375
|
+
skills: string[];
|
|
376
|
+
/** Connector provider NAMES the agent was given; never a credential. */
|
|
377
|
+
services: string[];
|
|
378
|
+
/** Sanitised drawn look, when the agent has one. */
|
|
379
|
+
look?: {
|
|
380
|
+
svg: string;
|
|
381
|
+
description?: string;
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
/** A shared agent team: a recipe each installer makes their own copies from. */
|
|
385
|
+
export interface TeamTemplate {
|
|
386
|
+
id: SaltId;
|
|
387
|
+
/** Short id used in share links; accepted wherever an id is. */
|
|
388
|
+
slug: string;
|
|
389
|
+
name: string;
|
|
390
|
+
description: string | null;
|
|
391
|
+
listed: boolean;
|
|
392
|
+
install_count: number;
|
|
393
|
+
agent_count: number;
|
|
394
|
+
needs: string[];
|
|
395
|
+
coordinator_note: string | null;
|
|
396
|
+
author: {
|
|
397
|
+
id: SaltId;
|
|
398
|
+
username: string;
|
|
399
|
+
display_name: string;
|
|
400
|
+
avatar_url: string | null;
|
|
401
|
+
account_type: string;
|
|
402
|
+
};
|
|
403
|
+
/** Absent from list responses. */
|
|
404
|
+
agents?: TeamAgentRecipe[];
|
|
405
|
+
[key: string]: unknown;
|
|
406
|
+
}
|
|
407
|
+
export interface ShareTeamParams {
|
|
408
|
+
/** One of the caller's own agent groups. Only the agents the caller owns are shared. */
|
|
409
|
+
groupId: SaltId;
|
|
410
|
+
name?: string;
|
|
411
|
+
description?: string;
|
|
412
|
+
/** Listed on the Teams shelf; default is unlisted (reachable by its link only). */
|
|
413
|
+
listed?: boolean;
|
|
414
|
+
/** Plain text each installed agent gets as a directive about who hands off to whom (at most 200 characters). */
|
|
415
|
+
coordinatorNote?: string;
|
|
416
|
+
}
|
|
417
|
+
/** An app's metadata -- `GET /api/v1/apps/:id`, the App Store listing, and `/mine`. */
|
|
418
|
+
export interface AppSummary {
|
|
419
|
+
id: SaltId;
|
|
420
|
+
name: string;
|
|
421
|
+
description?: string;
|
|
422
|
+
listed?: boolean;
|
|
423
|
+
installs_count?: number;
|
|
424
|
+
latest_version_id?: SaltId | null;
|
|
425
|
+
/** Present on the single-app GET -- the latest version's {id, number}. */
|
|
426
|
+
version?: AppVersionRef;
|
|
427
|
+
owner?: AppPerson;
|
|
428
|
+
built_by?: AppPerson | null;
|
|
429
|
+
[key: string]: unknown;
|
|
430
|
+
}
|
|
431
|
+
export interface CreateAppParams {
|
|
432
|
+
name: string;
|
|
433
|
+
description?: string;
|
|
434
|
+
html: string;
|
|
435
|
+
/** An agent building FOR a person -- that person must share a chat with the caller, else 422. Omit to build for the caller itself. */
|
|
436
|
+
forId?: SaltId;
|
|
437
|
+
/** Installs the new app into this chat in the same transaction (caller must be a member). */
|
|
438
|
+
chatId?: SaltId;
|
|
439
|
+
/** Version 1's quick actions -- see AppQuickAction. */
|
|
440
|
+
actions?: AppQuickAction[];
|
|
441
|
+
}
|
|
442
|
+
/** `AppInstallation#as_chat_resource` -- what a chat message's `resource` carries for `resource_type: "AppInstallation"`, and what `create`/`install` return. */
|
|
443
|
+
export interface AppInstallation {
|
|
444
|
+
id: SaltId;
|
|
445
|
+
app_id?: SaltId;
|
|
446
|
+
app_version_id?: SaltId;
|
|
447
|
+
installed_by_id?: SaltId;
|
|
448
|
+
/** Null for a personal ("Your apps") installation. */
|
|
449
|
+
chat_id?: SaltId | null;
|
|
450
|
+
/** The agent that answers this installation's `ask` -- null when it has none. */
|
|
451
|
+
agent_id?: SaltId | null;
|
|
452
|
+
removed_at?: string | null;
|
|
453
|
+
app?: {
|
|
454
|
+
id: SaltId;
|
|
455
|
+
name: string;
|
|
456
|
+
description?: string;
|
|
457
|
+
owner?: AppPerson;
|
|
458
|
+
built_by?: AppPerson | null;
|
|
459
|
+
};
|
|
460
|
+
version?: AppVersionRef;
|
|
461
|
+
latest_number?: number;
|
|
462
|
+
/** The PINNED version's quick actions, flattened here (same values as `version.actions`) so a chat bubble can render them without a nested lookup. */
|
|
463
|
+
actions?: AppQuickAction[];
|
|
464
|
+
[key: string]: unknown;
|
|
465
|
+
}
|
|
466
|
+
export interface CreateAppResult {
|
|
467
|
+
app: AppSummary;
|
|
468
|
+
version: AppVersionRef;
|
|
469
|
+
/** Present only when `chatId` was given -- installed in the same transaction. */
|
|
470
|
+
installation?: AppInstallation;
|
|
471
|
+
}
|
|
472
|
+
export interface InstallAppParams {
|
|
473
|
+
chatId?: SaltId;
|
|
474
|
+
/** Another installation of the SAME app the caller can read -- copies its doc once into the new installation's state. */
|
|
475
|
+
copyStateFrom?: SaltId;
|
|
476
|
+
}
|
|
477
|
+
/** `GET`/`PUT .../state`'s shape -- also `.../mine`'s (the viewer's private doc), same CAS rules. */
|
|
478
|
+
export interface AppStateDoc {
|
|
479
|
+
doc: Record<string, unknown>;
|
|
480
|
+
version: number;
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* Thrown by `setState` on a 409 -- the installation's shared state moved
|
|
484
|
+
* under the caller since `ifVersion`. Carries the CURRENT `{doc, version}`
|
|
485
|
+
* straight off the response body (salt-api's own 409 payload), so a caller
|
|
486
|
+
* can merge its change onto the fresh doc and retry with the new version
|
|
487
|
+
* rather than spending a second round trip just to re-fetch first.
|
|
488
|
+
*/
|
|
489
|
+
export declare class AppStateConflictError extends Error {
|
|
490
|
+
doc: Record<string, unknown>;
|
|
491
|
+
version: number;
|
|
492
|
+
constructor(doc: Record<string, unknown>, version: number);
|
|
493
|
+
}
|
|
35
494
|
export interface InvoiceLineItem {
|
|
36
495
|
name: string;
|
|
37
496
|
qty: number;
|
|
38
497
|
unit_price: string | number;
|
|
39
498
|
subtotal: string | number;
|
|
40
|
-
product_id?:
|
|
499
|
+
product_id?: SaltId;
|
|
41
500
|
}
|
|
42
501
|
export interface CreateInvoiceParams {
|
|
43
|
-
chatId:
|
|
44
|
-
receiverId:
|
|
45
|
-
walletId?:
|
|
502
|
+
chatId: SaltId;
|
|
503
|
+
receiverId: SaltId;
|
|
504
|
+
walletId?: SaltId;
|
|
46
505
|
amount: string | number;
|
|
47
506
|
lineItems: InvoiceLineItem[];
|
|
48
507
|
message?: string;
|
|
49
508
|
dueAt?: string;
|
|
509
|
+
/** See createInvoice's JSDoc for retry/reconciliation semantics. */
|
|
510
|
+
idempotencyKey?: string;
|
|
50
511
|
}
|
|
51
512
|
export interface AddUsageParams {
|
|
52
|
-
productId:
|
|
53
|
-
chatId:
|
|
513
|
+
productId: SaltId;
|
|
514
|
+
chatId: SaltId;
|
|
54
515
|
qty: number;
|
|
55
516
|
description?: string;
|
|
56
|
-
payerId?:
|
|
517
|
+
payerId?: SaltId;
|
|
518
|
+
/** See addUsage's JSDoc for retry/reconciliation semantics. */
|
|
519
|
+
idempotencyKey?: string;
|
|
57
520
|
}
|
|
58
521
|
export interface SaltClientOptions {
|
|
59
522
|
host: string;
|
|
60
523
|
/** Override fetch (e.g. for tests). Defaults to global fetch. */
|
|
61
524
|
fetchImpl?: typeof fetch;
|
|
62
525
|
}
|
|
526
|
+
/** One chain's governed-spend budget, applied over a rolling period. */
|
|
527
|
+
export interface SpendingPolicyRule {
|
|
528
|
+
chain: string;
|
|
529
|
+
period: "daily" | "weekly" | "monthly";
|
|
530
|
+
/** HUMAN-DECIMAL string, e.g. "0.5" = half an ETH -- never base units (wei/satoshis). */
|
|
531
|
+
budget_amount: string;
|
|
532
|
+
/** HUMAN-DECIMAL string cap on a single send, if set. */
|
|
533
|
+
per_tx_max?: string;
|
|
534
|
+
/** Server-computed: HUMAN-DECIMAL string already spent in the current period. */
|
|
535
|
+
spent_this_period?: string;
|
|
536
|
+
/** Server-computed: HUMAN-DECIMAL string remaining in the current period. */
|
|
537
|
+
remaining?: string;
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* An agent's governed-spend policy, as returned by the API. `frozen: true`
|
|
541
|
+
* blocks every mainnet send regardless of `rules`; an agent with no policy
|
|
542
|
+
* at all is refused by default (salt-api default-denies agent mainnet
|
|
543
|
+
* sends until an owner sets one up) -- see getSpendingPolicy.
|
|
544
|
+
*/
|
|
545
|
+
export interface SpendingPolicy {
|
|
546
|
+
frozen: boolean;
|
|
547
|
+
rules: SpendingPolicyRule[];
|
|
548
|
+
}
|
|
549
|
+
/** Payload for updateSpendingPolicy -- same shape as SpendingPolicyRule minus the server-computed fields. */
|
|
550
|
+
export interface UpdateSpendingPolicyParams {
|
|
551
|
+
frozen: boolean;
|
|
552
|
+
rules: Array<{
|
|
553
|
+
chain: string;
|
|
554
|
+
period: string;
|
|
555
|
+
/** HUMAN-DECIMAL string, e.g. "0.5" = half an ETH -- never base units. */
|
|
556
|
+
budget_amount: string;
|
|
557
|
+
/** HUMAN-DECIMAL string, if set. */
|
|
558
|
+
per_tx_max?: string;
|
|
559
|
+
}>;
|
|
560
|
+
}
|
|
561
|
+
export interface ReceiptParty {
|
|
562
|
+
id: SaltId;
|
|
563
|
+
username: string;
|
|
564
|
+
}
|
|
565
|
+
/** Only present when the settled transfer paid a TransferRequest (a regular send has no `request`). */
|
|
566
|
+
export interface ReceiptRequestSummary {
|
|
567
|
+
id: SaltId;
|
|
568
|
+
request_type: string;
|
|
569
|
+
status: string;
|
|
570
|
+
line_items: InvoiceLineItem[] | null;
|
|
571
|
+
}
|
|
572
|
+
export interface ReceiptPayload {
|
|
573
|
+
transfer_id: SaltId;
|
|
574
|
+
/** HUMAN-DECIMAL string, the declared send amount. */
|
|
575
|
+
amount: string;
|
|
576
|
+
/** HUMAN-DECIMAL string, the value the chain actually moved -- absent until/unless verified; authoritative over `amount` where they disagree. */
|
|
577
|
+
settled_amount?: string;
|
|
578
|
+
chain?: string;
|
|
579
|
+
testnet?: boolean;
|
|
580
|
+
token_contract_address?: string;
|
|
581
|
+
tx_id?: string;
|
|
582
|
+
sender?: ReceiptParty;
|
|
583
|
+
receiver?: ReceiptParty;
|
|
584
|
+
settled_at: string;
|
|
585
|
+
/**
|
|
586
|
+
* The sending agent's budget internals at enforcement time. Redacted
|
|
587
|
+
* (key absent) unless the caller is the sending agent itself or its root
|
|
588
|
+
* human owner -- a counterparty never sees the agent's per-tx/budget
|
|
589
|
+
* limits, only that the send was governed.
|
|
590
|
+
*/
|
|
591
|
+
policy_snapshot?: unknown;
|
|
592
|
+
request?: ReceiptRequestSummary;
|
|
593
|
+
}
|
|
594
|
+
/** A tamper-evident settlement record, minted once a Transfer confirms on-chain. */
|
|
595
|
+
export interface Receipt {
|
|
596
|
+
transfer_id: SaltId;
|
|
597
|
+
payload: ReceiptPayload;
|
|
598
|
+
/** SHA-256 over sorted-key canonical JSON of the FULL (unredacted) payload -- still verifiable even when `policy_snapshot` was redacted for this viewer. */
|
|
599
|
+
digest: string;
|
|
600
|
+
created_at: string;
|
|
601
|
+
}
|
|
602
|
+
export interface BillingAccountParty {
|
|
603
|
+
id: SaltId;
|
|
604
|
+
username: string;
|
|
605
|
+
display_name: string;
|
|
606
|
+
account_type: "User" | "Agent";
|
|
607
|
+
}
|
|
608
|
+
export interface BillingAccountCreditEntry {
|
|
609
|
+
id: SaltId;
|
|
610
|
+
kind: "deposit" | "usage" | "refund";
|
|
611
|
+
/** HUMAN-DECIMAL string. */
|
|
612
|
+
amount: string;
|
|
613
|
+
qty?: string;
|
|
614
|
+
description?: string;
|
|
615
|
+
created_at: string;
|
|
616
|
+
}
|
|
617
|
+
/** A pair-scoped prepaid credit relationship: payer deposits with payee, payee's metered usage draws it down. */
|
|
618
|
+
export interface BillingAccount {
|
|
619
|
+
id: SaltId;
|
|
620
|
+
payer_id: SaltId;
|
|
621
|
+
payee_id: SaltId;
|
|
622
|
+
payer: BillingAccountParty;
|
|
623
|
+
payee: BillingAccountParty;
|
|
624
|
+
/** HUMAN-DECIMAL string: deposits + refunds - usage. This IS the payer's spend cap on this payee's metered products. */
|
|
625
|
+
balance: string;
|
|
626
|
+
/** Most recent 10 ledger entries, newest first. */
|
|
627
|
+
recent_entries: BillingAccountCreditEntry[];
|
|
628
|
+
}
|
|
629
|
+
/**
|
|
630
|
+
* Error codes salt-api can return for a governed-spend refusal. These ride
|
|
631
|
+
* in the response body as `{error: string, code: SpendGovernanceCode}` --
|
|
632
|
+
* check `SaltApiError.body.code` rather than parsing `.message`.
|
|
633
|
+
*
|
|
634
|
+
* - `spending_frozen` / `no_spending_policy` -- the agent's policy blocks all sends (see SpendingPolicy).
|
|
635
|
+
* - `per_tx_max_exceeded` / `budget_exceeded` -- the send exceeds a configured rule.
|
|
636
|
+
* - `spend_unconfirmed` -- the agent already has an unconfirmed governed send on this chain; wait for it to confirm, then retry.
|
|
637
|
+
* - `token_sends_ungoverned` / `ungoverned_wallet` -- this send path isn't covered by policy enforcement yet.
|
|
638
|
+
* - `invalid_amount` -- amount wasn't a valid human-decimal string.
|
|
639
|
+
* - `unverifiable_tx` -- the signed transaction couldn't be decoded at all; a governed send must be a standard signed transfer.
|
|
640
|
+
* - `declaration_mismatch` -- the signed transaction's destination, amount, or call data doesn't match what was declared.
|
|
641
|
+
* - `request_in_flight` / `request_failed_terminal` / `idempotency_key_reuse` -- see addUsage's JSDoc (the invoice rail does not implement these -- see createInvoice's JSDoc).
|
|
642
|
+
*/
|
|
643
|
+
export type SpendGovernanceCode = "spending_frozen" | "no_spending_policy" | "per_tx_max_exceeded" | "budget_exceeded" | "spend_unconfirmed" | "token_sends_ungoverned" | "ungoverned_wallet" | "invalid_amount" | "unverifiable_tx" | "declaration_mismatch" | "request_in_flight" | "request_failed_terminal" | "idempotency_key_reuse";
|
|
644
|
+
export type MandateKind = "explicit" | "governance" | "connection";
|
|
645
|
+
export type MandateStatus = "proposed" | "active" | "paused" | "revoked" | "expired";
|
|
646
|
+
export type MandateCapabilityMode = "auto" | "ask" | "notify";
|
|
647
|
+
export type MandateExerciseDecision = "allowed" | "asked" | "approved" | "denied" | "refused" | "expired";
|
|
648
|
+
export interface MandateParty {
|
|
649
|
+
id: SaltId;
|
|
650
|
+
username: string;
|
|
651
|
+
display_name: string;
|
|
652
|
+
account_type: "User" | "Agent";
|
|
653
|
+
avatar_url?: string;
|
|
654
|
+
[key: string]: unknown;
|
|
655
|
+
}
|
|
656
|
+
export interface MandateCapabilityRow {
|
|
657
|
+
id: SaltId;
|
|
658
|
+
capability: string;
|
|
659
|
+
/** e.g. `{chat_ids: [...]}`, `{wallet_ids: [...]}`, `{product_ids: [...]}`, or `{}` for "every one". */
|
|
660
|
+
selector: Record<string, unknown>;
|
|
661
|
+
mode: MandateCapabilityMode;
|
|
662
|
+
/** e.g. `per_request_max`, `budget_amount`/`period`, `rate_limit` -- shape depends on `capability`. */
|
|
663
|
+
constraints: Record<string, unknown>;
|
|
664
|
+
}
|
|
665
|
+
/** One `{capability, selector, mode, constraints}` row as sent to `propose`/`update` -- same shape as
|
|
666
|
+
* MandateCapabilityRow minus the server-assigned `id`. */
|
|
667
|
+
export interface MandateCapabilityInput {
|
|
668
|
+
capability: string;
|
|
669
|
+
selector?: Record<string, unknown>;
|
|
670
|
+
mode: MandateCapabilityMode;
|
|
671
|
+
constraints?: Record<string, unknown>;
|
|
672
|
+
}
|
|
673
|
+
export interface MandateTrail {
|
|
674
|
+
count: number;
|
|
675
|
+
today_count: number;
|
|
676
|
+
last_at?: string;
|
|
677
|
+
open_asks: number;
|
|
678
|
+
}
|
|
679
|
+
export interface MandateChild {
|
|
680
|
+
id: SaltId;
|
|
681
|
+
grantee: MandateParty;
|
|
682
|
+
label?: string;
|
|
683
|
+
}
|
|
684
|
+
/** A mandate row as served by `GET /api/v1/mandates`/`:id` and carried on `mandate_offered`/
|
|
685
|
+
* `mandate_activated`/`mandate_paused`/`mandate_revoked` webhook events (see webhook.ts). */
|
|
686
|
+
export interface Mandate {
|
|
687
|
+
id: SaltId;
|
|
688
|
+
kind: MandateKind;
|
|
689
|
+
status: MandateStatus;
|
|
690
|
+
label?: string;
|
|
691
|
+
grantor: MandateParty;
|
|
692
|
+
grantee: MandateParty;
|
|
693
|
+
capabilities: MandateCapabilityRow[];
|
|
694
|
+
starts_at: string;
|
|
695
|
+
expires_at?: string;
|
|
696
|
+
standing: boolean;
|
|
697
|
+
grantee_fingerprint?: string;
|
|
698
|
+
/** True when the grantee's current key no longer matches `grantee_fingerprint` -- salt-api pauses
|
|
699
|
+
* the mandate the moment it notices (see `mandate_paused` with `pause_reason: "key_changed"`). */
|
|
700
|
+
key_changed?: boolean;
|
|
701
|
+
parent_id?: SaltId;
|
|
702
|
+
depth?: number;
|
|
703
|
+
version: number;
|
|
704
|
+
chat_id?: SaltId;
|
|
705
|
+
proposed_by_id?: SaltId;
|
|
706
|
+
accepted_at?: string;
|
|
707
|
+
paused_at?: string;
|
|
708
|
+
pause_reason?: string;
|
|
709
|
+
revoked_at?: string;
|
|
710
|
+
revoke_reason?: string;
|
|
711
|
+
children?: MandateChild[];
|
|
712
|
+
trail?: MandateTrail;
|
|
713
|
+
[key: string]: unknown;
|
|
714
|
+
}
|
|
715
|
+
/** One row of a mandate's trail -- an allowed act, an ask (settled or still open), or a refusal.
|
|
716
|
+
* `refusal` is only ever populated for the principal (or its governor) -- see salt-api's
|
|
717
|
+
* `MandateExercise#as_json_for`. */
|
|
718
|
+
export interface MandateExercise {
|
|
719
|
+
id: SaltId | number;
|
|
720
|
+
mandate_id: SaltId;
|
|
721
|
+
capability: string;
|
|
722
|
+
action: string;
|
|
723
|
+
decision: MandateExerciseDecision;
|
|
724
|
+
reason?: string;
|
|
725
|
+
refusal?: string;
|
|
726
|
+
summary: Record<string, unknown>;
|
|
727
|
+
target?: {
|
|
728
|
+
type?: string;
|
|
729
|
+
id?: SaltId;
|
|
730
|
+
};
|
|
731
|
+
chat_id?: SaltId;
|
|
732
|
+
message_id?: SaltId;
|
|
733
|
+
actor: {
|
|
734
|
+
id: SaltId;
|
|
735
|
+
username: string;
|
|
736
|
+
display_name: string;
|
|
737
|
+
account_type: "User" | "Agent";
|
|
738
|
+
};
|
|
739
|
+
principal: {
|
|
740
|
+
id: SaltId;
|
|
741
|
+
username: string;
|
|
742
|
+
};
|
|
743
|
+
created_at: string;
|
|
744
|
+
decided_at?: string;
|
|
745
|
+
expires_at?: string;
|
|
746
|
+
[key: string]: unknown;
|
|
747
|
+
}
|
|
748
|
+
export interface ProposeMandateParams {
|
|
749
|
+
grantee_id?: SaltId;
|
|
750
|
+
grantee_username?: string;
|
|
751
|
+
/** Only when proposing UP to a grantor rather than granting down (the caller becomes `proposed_by`). */
|
|
752
|
+
grantor_id?: SaltId;
|
|
753
|
+
label?: string;
|
|
754
|
+
capabilities: MandateCapabilityInput[];
|
|
755
|
+
standing?: boolean;
|
|
756
|
+
expires_at?: string;
|
|
757
|
+
parent_id?: SaltId;
|
|
758
|
+
chat_id?: SaltId;
|
|
759
|
+
}
|
|
760
|
+
export interface UpdateMandateParams {
|
|
761
|
+
/** Required: compare-and-swap against the mandate's current `version` -- a stale value is a 409. */
|
|
762
|
+
version: number;
|
|
763
|
+
label?: string;
|
|
764
|
+
capabilities?: MandateCapabilityInput[];
|
|
765
|
+
standing?: boolean;
|
|
766
|
+
expires_at?: string;
|
|
767
|
+
}
|
|
768
|
+
/**
|
|
769
|
+
* A 202 `{status: "asked", exercise_id, expires_at}` response, resolved rather than thrown --
|
|
770
|
+
* see `SaltClient.actFor` below. `isAsked` narrows an unknown result to this shape.
|
|
771
|
+
*/
|
|
772
|
+
export interface AskedResult {
|
|
773
|
+
asked: true;
|
|
774
|
+
exerciseId: SaltId;
|
|
775
|
+
expiresAt?: string;
|
|
776
|
+
}
|
|
777
|
+
export declare function isAsked(value: unknown): value is AskedResult;
|
|
778
|
+
/** Maps a client method's `Promise<R>` to `Promise<R | AskedResult>` -- what every call through
|
|
779
|
+
* `actFor`'s returned client can resolve to, since any mapped action can come back an ask
|
|
780
|
+
* depending on how the grantor configured that capability's mode. Non-function properties (e.g.
|
|
781
|
+
* `mandates`) and non-Promise-returning ones (e.g. `trackEvent`) pass through unchanged. */
|
|
782
|
+
export type Acted<F> = F extends (...args: infer A) => Promise<infer R> ? (...args: A) => Promise<R | AskedResult> : F;
|
|
783
|
+
export interface ActForOptions {
|
|
784
|
+
/** Pin one specific mandate rather than letting salt-api pick the strictest match among every
|
|
785
|
+
* active mandate that grants the call. */
|
|
786
|
+
mandateId?: SaltId;
|
|
787
|
+
}
|
|
788
|
+
/** What the reactions endpoint answers: the message's reactions after your change. */
|
|
789
|
+
export interface ReactionSummary {
|
|
790
|
+
message_id: SaltId;
|
|
791
|
+
reactions: unknown;
|
|
792
|
+
}
|
|
793
|
+
/** The post a reply answers, as salt-api sends it on a reply row. `author` and `excerpt` are null
|
|
794
|
+
* when the original is gone or not visible to the caller. */
|
|
795
|
+
export interface PostReplyParent {
|
|
796
|
+
id: SaltId;
|
|
797
|
+
author: string | null;
|
|
798
|
+
excerpt: string | null;
|
|
799
|
+
}
|
|
800
|
+
/** A post's photo or video: image/jpeg|png|webp|gif|heic or video/mp4|webm|quicktime, up to 15 MB. */
|
|
801
|
+
export interface PostMediaInfo {
|
|
802
|
+
url: string;
|
|
803
|
+
content_type: string;
|
|
804
|
+
size: number;
|
|
805
|
+
}
|
|
806
|
+
/** The file to attach to a post. */
|
|
807
|
+
export interface PostMediaInput {
|
|
808
|
+
data: Uint8Array;
|
|
809
|
+
contentType: string;
|
|
810
|
+
}
|
|
811
|
+
/** A post in someone's profile room, as `POST /api/v1/posts/:id/reply` and `GET /api/v1/posts/:id/replies`
|
|
812
|
+
* serve it. A reply is its author's OWN post, linked to what it answers: `is_reply`, `parent` and
|
|
813
|
+
* `replying_to` are present only on replies. */
|
|
814
|
+
export interface PostRow {
|
|
815
|
+
id: SaltId;
|
|
816
|
+
room_id: SaltId;
|
|
817
|
+
created_at: string;
|
|
818
|
+
message: string;
|
|
819
|
+
author: unknown;
|
|
820
|
+
reply_count: number;
|
|
821
|
+
reactions: unknown;
|
|
822
|
+
following: boolean;
|
|
823
|
+
/** Present only on a post that carries a photo or video; `url` is public (GET /api/v1/posts/:id/media). */
|
|
824
|
+
media?: PostMediaInfo;
|
|
825
|
+
is_reply?: boolean;
|
|
826
|
+
parent?: PostReplyParent;
|
|
827
|
+
replying_to?: string | null;
|
|
828
|
+
}
|
|
829
|
+
export interface PostRepliesPage {
|
|
830
|
+
post: PostRow;
|
|
831
|
+
replies: PostRow[];
|
|
832
|
+
next_before: string | null;
|
|
833
|
+
}
|
|
63
834
|
export declare class SaltApiError extends Error {
|
|
64
835
|
status: number;
|
|
65
836
|
body: unknown;
|
|
837
|
+
/** Salt's machine-readable refusal code (`{error, code}`), when the body carries one. */
|
|
838
|
+
code?: string;
|
|
839
|
+
constructor(method: string, url: string, status: number, body: unknown);
|
|
840
|
+
}
|
|
841
|
+
export declare const RECIPIENT_CONTACTS_ONLY = "recipient_contacts_only";
|
|
842
|
+
/** 403 `recipient_contacts_only`: the recipient only takes messages from their contacts and the caller is
|
|
843
|
+
* not one, so no chat was created. `message` ends with the server's own sentence ("<name> only takes
|
|
844
|
+
* messages from their contacts."), also on `sentence`. Do not retry; a request for contact is the only way in. */
|
|
845
|
+
export declare class RecipientContactsOnlyError extends SaltApiError {
|
|
846
|
+
sentence: string;
|
|
66
847
|
constructor(method: string, url: string, status: number, body: unknown);
|
|
67
848
|
}
|
|
68
849
|
/**
|
|
@@ -71,71 +852,2378 @@ export declare class SaltApiError extends Error {
|
|
|
71
852
|
* module-level header, since one process can legitimately act as several
|
|
72
853
|
* Salt agents at once.
|
|
73
854
|
*/
|
|
855
|
+
/** Every client method's call shape -- `request<T>` itself, and `actingRequest`'s wrapper below,
|
|
856
|
+
* both match this so `buildMethods` (further down) can be built from either one interchangeably. */
|
|
857
|
+
type RequestFn = <T>(method: string, path: string, apiKey: string, body?: unknown, opts?: {
|
|
858
|
+
extraHeaders?: Record<string, string>;
|
|
859
|
+
idempotencyKey?: string;
|
|
860
|
+
}) => Promise<T>;
|
|
74
861
|
export declare function createSaltClient(options: SaltClientOptions): {
|
|
862
|
+
actFor: (principalId: SaltId, opts?: ActForOptions) => { [K in keyof ReturnType<(request: RequestFn) => {
|
|
863
|
+
/** A chat's members (with public keys), for encrypting a reply to everyone who should read it. */
|
|
864
|
+
getChatMembers(apiKey: string, chatId: SaltId): Promise<SaltUser[]>;
|
|
865
|
+
/** Recent messages in a chat this identity is a member of (even as a silent observer). */
|
|
866
|
+
getChatMessages(apiKey: string, chatId: SaltId): Promise<unknown[]>;
|
|
867
|
+
/**
|
|
868
|
+
* One `GET /api/v1/chats/:id` call for a caller that needs BOTH the
|
|
869
|
+
* member list and whether the chat is end-to-end encrypted -- e.g.
|
|
870
|
+
* actions.ts's request_floor, which (unlike delegate_to_agent/
|
|
871
|
+
* consult_agent) has no other reason to fetch the chat at all.
|
|
872
|
+
* `encrypted` is already resolved to a real boolean (defaulted `true`
|
|
873
|
+
* when the field is absent, same convention as ChatOpenedContext.encrypted
|
|
874
|
+
* and MessageContext.encrypted) -- never undefined.
|
|
875
|
+
*/
|
|
876
|
+
getChat(apiKey: string, chatId: SaltId): Promise<{
|
|
877
|
+
id: SaltId;
|
|
878
|
+
encrypted: boolean;
|
|
879
|
+
users: SaltUser[];
|
|
880
|
+
}>;
|
|
881
|
+
/**
|
|
882
|
+
* Salt's own record of a chat, exactly as `GET /api/v1/chats/:id` answers
|
|
883
|
+
* it (nothing flattened or defaulted, unlike getChat): `session.users`
|
|
884
|
+
* with each member's `observer` flag, `session.public`, `session.encrypted`.
|
|
885
|
+
* This is what `isPrivateChat(chat, speakerId, myId)` reads -- decide
|
|
886
|
+
* privacy-sensitive actions from THIS, fetched when you need it, never
|
|
887
|
+
* from a cache or a memory service.
|
|
888
|
+
*/
|
|
889
|
+
getChatRecord(apiKey: string, chatId: SaltId): Promise<SaltChat>;
|
|
890
|
+
/** Download an attachment's ciphertext bytes. Decrypt separately (see crypto.ts). */
|
|
891
|
+
getAttachment(apiKey: string, messageId: SaltId): Promise<Buffer>;
|
|
892
|
+
/**
|
|
893
|
+
* Post a reply into a chat. `message` is the ciphertext every human
|
|
894
|
+
* recipient reads; `senderMessage` is the copy encrypted to the
|
|
895
|
+
* sender's own key. `delegations` (optional) is the provenance trail
|
|
896
|
+
* -- salt-api re-validates every entry against the sender's actual
|
|
897
|
+
* memberships before storing it. The result carries `delivered_as`:
|
|
898
|
+
* `"request"` means the recipient has not accepted a first message from
|
|
899
|
+
* you yet (see Message requests in AGENTS.md) -- wait, do not re-send.
|
|
900
|
+
*/
|
|
901
|
+
postMessage(apiKey: string, chatId: SaltId, message: string, senderMessage?: string, delegations?: Array<{
|
|
902
|
+
agent_id: SaltId;
|
|
903
|
+
chat_id: SaltId;
|
|
904
|
+
username: string;
|
|
905
|
+
}>, mentions?: SaltId[], opts?: {
|
|
906
|
+
quiet?: boolean;
|
|
907
|
+
}): Promise<PostMessageResult>;
|
|
908
|
+
/**
|
|
909
|
+
* Sends a file into a chat, encrypted exactly the way salt-fe's
|
|
910
|
+
* chatbox.jsx sendOneAttachment encrypts one: a fresh one-time AES-256-
|
|
911
|
+
* GCM key encrypts the file bytes (crypto.ts's encryptAttachment,
|
|
912
|
+
* byte-identical wire format to the browser's Web Crypto output), and
|
|
913
|
+
* that key/iv plus the real filename/content_type/size are PGP-
|
|
914
|
+
* encrypted as one JSON blob for every current chat member's public
|
|
915
|
+
* key -- the SAME single recipient list the caption text is encrypted
|
|
916
|
+
* for, fetched fresh via GET /api/v1/chats/:id so a just-added or
|
|
917
|
+
* just-removed member is never missed or over-included. Unlike
|
|
918
|
+
* postMessage's reply() there is no separate sender_message: the web
|
|
919
|
+
* never excludes the sender from an attachment's recipient list (it
|
|
920
|
+
* has no reason to -- there's only one `attachment_encrypted_key`
|
|
921
|
+
* field, see Attachment#as_chat_resource), so a single PGP blob
|
|
922
|
+
* covering every member already covers the sender too.
|
|
923
|
+
*
|
|
924
|
+
* Throws before doing any crypto work on an oversized file (matches
|
|
925
|
+
* salt-api's own MAX_ATTACHMENT_BYTES so a doomed upload never even
|
|
926
|
+
* starts) or a content_type outside ALLOWED_SEND_CONTENT_TYPES.
|
|
927
|
+
*/
|
|
928
|
+
sendAttachment(apiKey: string, chatId: SaltId, params: SendAttachmentParams): Promise<unknown>;
|
|
929
|
+
/**
|
|
930
|
+
* Post into an OPEN ROOM -- a chat with no end-to-end encryption, so
|
|
931
|
+
* `text` rides the wire and is stored as plain text rather than a PGP
|
|
932
|
+
* blob. There is no `senderMessage`/`delegations`/`mentions` shape here
|
|
933
|
+
* the way postMessage has: salt-api refuses this call 422 against a
|
|
934
|
+
* chat that isn't plain (never silently encrypts, never silently
|
|
935
|
+
* drops the call). Webhook/socket deliveries for a plain chat carry
|
|
936
|
+
* `message.encrypted === false` -- see webhook.ts's handleMessage,
|
|
937
|
+
* which hands the body straight through as ctx.text (ctx.encrypted
|
|
938
|
+
* false) instead of attempting PGP decrypt.
|
|
939
|
+
*/
|
|
940
|
+
postPlainMessage(apiKey: string, chatId: SaltId, text: string): Promise<unknown>;
|
|
941
|
+
/**
|
|
942
|
+
* Open rooms (0.6x): declares what this identity wants delivered from
|
|
943
|
+
* a chat it isn't necessarily addressed in every message of --
|
|
944
|
+
* `"addressed"` (only a direct reply/@mention, the closest analogue to
|
|
945
|
+
* how a normal encrypted chat already gates agent delivery),
|
|
946
|
+
* `"keywords"` (any message containing one of `keywords`), or `"all"`
|
|
947
|
+
* (every message). Always this identity's OWN subscription for
|
|
948
|
+
* `chatId` -- same "acts on the caller, never someone else" shape as
|
|
949
|
+
* setDeliveryMode/setCallback.
|
|
950
|
+
*/
|
|
951
|
+
setChatSubscription(apiKey: string, chatId: SaltId, params: {
|
|
952
|
+
mode: "addressed" | "keywords" | "all";
|
|
953
|
+
keywords?: string[];
|
|
954
|
+
}): Promise<unknown>;
|
|
955
|
+
/** Removes this identity's subscription record for `chatId` -- salt-api's
|
|
956
|
+
* default (unsubscribed) behavior applies again, same as never having
|
|
957
|
+
* called setChatSubscription. */
|
|
958
|
+
clearChatSubscription(apiKey: string, chatId: SaltId): Promise<unknown>;
|
|
959
|
+
/**
|
|
960
|
+
* Get-or-create the private lane (a sidechain) between this identity and
|
|
961
|
+
* `withId`, both members of `chatId`. Once per pair on Salt's side. Answers
|
|
962
|
+
* 422 when `chatId` is itself a lane. The lane's members come back with
|
|
963
|
+
* their public keys.
|
|
964
|
+
*/
|
|
965
|
+
openSidechain(apiKey: string, chatId: SaltId, withId: SaltId): Promise<{
|
|
966
|
+
session: {
|
|
967
|
+
id: SaltId;
|
|
968
|
+
users?: SaltUser[];
|
|
969
|
+
coaching_for_chat_id?: SaltId;
|
|
970
|
+
[key: string]: unknown;
|
|
971
|
+
};
|
|
972
|
+
messages?: unknown[];
|
|
973
|
+
}>;
|
|
974
|
+
/**
|
|
975
|
+
* Opens (or reuses) a CONSULT lane between the caller and `withId`, both
|
|
976
|
+
* already members of `roomId` -- mechanically identical to
|
|
977
|
+
* openSidechain (same endpoint, same get-or-create-per-pair semantics),
|
|
978
|
+
* named separately because actions.ts's consult_agent reads more
|
|
979
|
+
* clearly calling "open the lane I'm about to consult in" than a
|
|
980
|
+
* generic sidechain call. salt-api tags the resulting chat
|
|
981
|
+
* `lane_kind: "consult"`, which webhook.ts reads back off the webhook
|
|
982
|
+
* body to raise the agent-to-agent reply cap for that lane and to gate
|
|
983
|
+
* request_floor.
|
|
984
|
+
*/
|
|
985
|
+
openConsultLane(apiKey: string, roomId: SaltId, withId: SaltId): Promise<{
|
|
986
|
+
session: {
|
|
987
|
+
id: SaltId;
|
|
988
|
+
users?: SaltUser[];
|
|
989
|
+
coaching_for_chat_id?: SaltId;
|
|
990
|
+
lane_kind?: string;
|
|
991
|
+
[key: string]: unknown;
|
|
992
|
+
};
|
|
993
|
+
messages?: unknown[];
|
|
994
|
+
}>;
|
|
995
|
+
/** Register a new Salt agent, owned by whoever's api-key calls this. */
|
|
996
|
+
/**
|
|
997
|
+
* The create response carries the new agent's raw api key EXACTLY ONCE --
|
|
998
|
+
* salt-api stores only a digest, so no later endpoint can show it again.
|
|
999
|
+
* Capture `api_key` here; a lost key means rotateAgentApiKey, not re-reading.
|
|
1000
|
+
*
|
|
1001
|
+
* Key custody: `CreateAgentParams` deliberately has no `private_key` --
|
|
1002
|
+
* salt-api rejects one with a 422 unconditionally (salt-api docs/
|
|
1003
|
+
* KEY_CUSTODY.md Phase 5). The key stays with whoever generates it
|
|
1004
|
+
* (pgp.generateKeypair, above the call site) and is registered with
|
|
1005
|
+
* identities.register/a session store; salt-api never receives a copy in
|
|
1006
|
+
* any form it can decrypt, so there is nothing to fetch back later --
|
|
1007
|
+
* getAgentAdmin's `userkeys` never carries a usable key either.
|
|
1008
|
+
*/
|
|
1009
|
+
createAgent(apiKey: string, params: CreateAgentParams): Promise<SaltUser & {
|
|
1010
|
+
api_key?: string;
|
|
1011
|
+
}>;
|
|
1012
|
+
/**
|
|
1013
|
+
* Draft an agent from one line (`POST /api/v1/agents/draft`): a person (token) or an agent by its own api-key.
|
|
1014
|
+
* Returns the WHOLE draft; each `step` rewrites only its own fields and keeps the rest exactly as sent, so
|
|
1015
|
+
* pass the person's edited draft back in. The AI proposes, the caller confirms: nothing is created. A model
|
|
1016
|
+
* failure is a 502 `SaltApiError` (`code: "draft_failed"`); a spent budget is a 429 or 402 with one sentence.
|
|
1017
|
+
* See AGENTS.md, "Make an agent from one line".
|
|
1018
|
+
*/
|
|
1019
|
+
draftAgent(apiKey: string, params: DraftAgentParams): Promise<AgentDraft>;
|
|
1020
|
+
/**
|
|
1021
|
+
* Draft a whole team from one line (`POST /api/v1/teams/draft`): two to five agents, one lead, a role each, in
|
|
1022
|
+
* one call per step (not one per member). Same contract as `draftAgent`: returns the WHOLE draft, a step
|
|
1023
|
+
* rewrites only its own fields, nothing is created, and the AI proposes while the caller confirms. See AGENTS.md,
|
|
1024
|
+
* "Teams: one room, the lead is the arbiter".
|
|
1025
|
+
*/
|
|
1026
|
+
draftTeam(apiKey: string, params: DraftTeamParams): Promise<TeamDraft>;
|
|
1027
|
+
/** Owner-only: make one member the team's lead (the arbiter of its room), or pass null for no lead. The lead must be a member the owner owns (422). */
|
|
1028
|
+
setTeamLead(apiKey: string, groupId: SaltId, leadAgentId: SaltId | null): Promise<TeamGroup>;
|
|
1029
|
+
/** Owner-only: set a member's job in the team ("Showrunner"; at most 40 characters, blank clears it). */
|
|
1030
|
+
setMemberRole(apiKey: string, groupId: SaltId, agentId: SaltId, role: string | null): Promise<TeamGroup>;
|
|
1031
|
+
/** Owner-only: make (or return) the team's room, one encrypted group chat with you and every member. Idempotent. `left_out` is present only when positive: members the owner does not own are not added to the room. */
|
|
1032
|
+
openTeamRoom(apiKey: string, groupId: SaltId): Promise<{
|
|
1033
|
+
room_chat_id: SaltId;
|
|
1034
|
+
created: boolean;
|
|
1035
|
+
left_out?: number;
|
|
1036
|
+
}>;
|
|
1037
|
+
/** The teams the caller is a member of, with each lead, room and roster (`GET /api/v1/agent/teams`, by the agent's own api-key). This is how a team agent learns who else is in its room. */
|
|
1038
|
+
myTeams(apiKey: string): Promise<MyTeam[]>;
|
|
1039
|
+
/** Owner-only: mint a new api key for an agent. The old one stops working immediately. */
|
|
1040
|
+
rotateAgentApiKey(apiKey: string, agentId: SaltId): Promise<{
|
|
1041
|
+
api_key: string;
|
|
1042
|
+
}>;
|
|
1043
|
+
/**
|
|
1044
|
+
* This identity's own webhook signing key, used to verify that an incoming
|
|
1045
|
+
* webhook really came from salt-api.
|
|
1046
|
+
*
|
|
1047
|
+
* Fetched with the identity's own api key rather than configured from the
|
|
1048
|
+
* environment: salt-api mints one secret per agent, so shipping them through
|
|
1049
|
+
* env/Secrets Manager would mean the deploy had to know values the API
|
|
1050
|
+
* generates. Fetching at boot also means rotation takes effect on restart.
|
|
1051
|
+
*/
|
|
1052
|
+
getWebhookSecret(apiKey: string): Promise<string | undefined>;
|
|
1053
|
+
/**
|
|
1054
|
+
* Which agent does this api key belong to, according to salt-api?
|
|
1055
|
+
*
|
|
1056
|
+
* The same endpoint as getWebhookSecret: alongside the secret it returns
|
|
1057
|
+
* the canonical `agent_id` of the key's owner, which is the id salt-api
|
|
1058
|
+
* puts in X-Salt-Agent-Id on every callback. An identity registered under
|
|
1059
|
+
* any other id -- an env var, or a store entry that predates an id
|
|
1060
|
+
* migration -- can never be found when a webhook arrives; that is what
|
|
1061
|
+
* reconcileIdentityIds uses this to detect and repair.
|
|
1062
|
+
*/
|
|
1063
|
+
whoAmI: (apiKey: string) => Promise<{
|
|
1064
|
+
agent_id: SaltId;
|
|
1065
|
+
webhook_secret?: string;
|
|
1066
|
+
}>;
|
|
1067
|
+
/**
|
|
1068
|
+
* Owner-only: mint a new webhook signing secret for an agent. The old
|
|
1069
|
+
* secret stops verifying immediately, so the agent must re-fetch via
|
|
1070
|
+
* getWebhookSecret before it can validate any further deliveries.
|
|
1071
|
+
*/
|
|
1072
|
+
rotateWebhookSecret(apiKey: string, agentId: SaltId): Promise<{
|
|
1073
|
+
agent_id: SaltId;
|
|
1074
|
+
webhook_secret: string;
|
|
1075
|
+
}>;
|
|
1076
|
+
/**
|
|
1077
|
+
* The caller sets its OWN webhook callback -- api-key auth, no id
|
|
1078
|
+
* parameter, same "acts on the caller, never someone else" shape as
|
|
1079
|
+
* setDeliveryMode/setChatSubscription. Exists so the platform hosting
|
|
1080
|
+
* an agent can point its callback at itself without the owner ever
|
|
1081
|
+
* opening Salt's web console -- see AgentsController#set_callback's
|
|
1082
|
+
* own comment. Same URL-safety rule as the owner's web form
|
|
1083
|
+
* (User#callback_must_be_safe) applies server-side; a human caller
|
|
1084
|
+
* (not an agent's own api-key) gets a 403.
|
|
1085
|
+
*/
|
|
1086
|
+
setCallback(apiKey: string, webhook: string): Promise<{
|
|
1087
|
+
agent_id: SaltId;
|
|
1088
|
+
callback: string;
|
|
1089
|
+
}>;
|
|
1090
|
+
/**
|
|
1091
|
+
* K2 socket mode: the caller sets its OWN delivery mode -- "webhook"
|
|
1092
|
+
* (the default, POST to its registered callback) or "socket" (drain
|
|
1093
|
+
* GET /api/v1/agent/updates or AgentUpdatesChannel instead; see
|
|
1094
|
+
* socket.ts's createSocketClient). No id parameter, same reason
|
|
1095
|
+
* getWebhookSecret has none -- an agent can only ever change its own.
|
|
1096
|
+
* A blank callback is always socket mode regardless of this setting.
|
|
1097
|
+
*/
|
|
1098
|
+
setDeliveryMode(apiKey: string, mode: "webhook" | "socket"): Promise<{
|
|
1099
|
+
agent_id: SaltId;
|
|
1100
|
+
delivery_mode: string;
|
|
1101
|
+
socket_mode: boolean;
|
|
1102
|
+
}>;
|
|
1103
|
+
/**
|
|
1104
|
+
* Owner-only agent admin record. `apikey` is metadata (hint, last-used) --
|
|
1105
|
+
* the raw key rides only on the createAgent response, and after that only
|
|
1106
|
+
* rotateAgentApiKey can produce a usable value.
|
|
1107
|
+
*/
|
|
1108
|
+
getAgentAdmin(apiKey: string, agentId: SaltId): Promise<{
|
|
1109
|
+
apikey: {
|
|
1110
|
+
token_hint?: string;
|
|
1111
|
+
last_used_at?: string;
|
|
1112
|
+
} | null;
|
|
1113
|
+
userkeys: unknown;
|
|
1114
|
+
/** A hosted agent's monthly model spend limit in USD, a decimal string ("10" when never set). */
|
|
1115
|
+
model_budget_usd?: string;
|
|
1116
|
+
/** A hosted agent's model spend so far this month. */
|
|
1117
|
+
model_usage?: unknown;
|
|
1118
|
+
[key: string]: unknown;
|
|
1119
|
+
}>;
|
|
1120
|
+
/**
|
|
1121
|
+
* Owner-only: set an agent's photo (`PUT /api/v1/agents/:id/admin_update`, `partial: true` so nothing else
|
|
1122
|
+
* changes). PNG, JPEG, WebP or GIF up to 3 MB; anything else is a 422 with one sentence. A photo the owner
|
|
1123
|
+
* sets becomes its face. Both the photo and the drawing are kept; see `setAgentFace`.
|
|
1124
|
+
*/
|
|
1125
|
+
setAgentPhoto(apiKey: string, agentId: SaltId, photo: {
|
|
1126
|
+
bytes: Uint8Array;
|
|
1127
|
+
contentType: string;
|
|
1128
|
+
}): Promise<{
|
|
1129
|
+
[key: string]: unknown;
|
|
1130
|
+
} & AgentFaceFields>;
|
|
1131
|
+
/** Owner-only: choose which face is shown, `"photo"` or `"drawing"`. `"photo"` with no photo uploaded is a 422
|
|
1132
|
+
* ("Upload a photo first."). The owner's choice outranks the agent's own. */
|
|
1133
|
+
setAgentFace(apiKey: string, agentId: SaltId, face: AgentFace): Promise<{
|
|
1134
|
+
[key: string]: unknown;
|
|
1135
|
+
} & AgentFaceFields>;
|
|
1136
|
+
/**
|
|
1137
|
+
* Owner-only: set the agent's own model spend limit per UTC month in USD (`PATCH /api/v1/agents/:id/persona`, the
|
|
1138
|
+
* route the web uses; a number from 1 to 1000, sent as a string, default 10 when never set). Past it the agent pauses until
|
|
1139
|
+
* the month turns or the owner raises it. Anything else is a 422 with one sentence.
|
|
1140
|
+
*/
|
|
1141
|
+
setAgentBudget(apiKey: string, agentId: SaltId, usd: number | string): Promise<{
|
|
1142
|
+
[key: string]: unknown;
|
|
1143
|
+
}>;
|
|
1144
|
+
/** Owner-only: remove the agent's photo; its drawing shows again. */
|
|
1145
|
+
removeAgentPhoto(apiKey: string, agentId: SaltId): Promise<{
|
|
1146
|
+
[key: string]: unknown;
|
|
1147
|
+
} & AgentFaceFields>;
|
|
1148
|
+
/**
|
|
1149
|
+
* This agent's own identity: every section (claim and proof) with
|
|
1150
|
+
* `scope`/`editable_by`/`checked_by`, plus the public card URL it's
|
|
1151
|
+
* served from. Cache-busted like getChatMembers -- a value just set
|
|
1152
|
+
* with setIdentity should read back immediately.
|
|
1153
|
+
*/
|
|
1154
|
+
identity(apiKey: string): Promise<IdentitySections>;
|
|
1155
|
+
/**
|
|
1156
|
+
* Set one or more of this agent's own CLAIM sections (see
|
|
1157
|
+
* AGENT_CLAIM_SECTION_KEYS). `scope` is never accepted here -- section
|
|
1158
|
+
* visibility is owner-authenticated through the agent-management API
|
|
1159
|
+
* only (plan section 7: "setScope is never on this surface"), so a
|
|
1160
|
+
* caller that tries to slip one in is refused BEFORE any request is
|
|
1161
|
+
* made, the same way a bad tool call should fail loud and immediately
|
|
1162
|
+
* rather than round-tripping to find out the server also says no.
|
|
1163
|
+
* A 422 from salt-api ({errors: {key: "line"}} for an invalid value, or
|
|
1164
|
+
* {error: "Scope comes later."} were scope to somehow reach it anyway)
|
|
1165
|
+
* surfaces as an ordinary SaltApiError.
|
|
1166
|
+
*/
|
|
1167
|
+
setIdentity(apiKey: string, claims: IdentityClaims): Promise<IdentitySections>;
|
|
1168
|
+
/**
|
|
1169
|
+
* Writes one disclosure ledger row -- metadata only, never a section
|
|
1170
|
+
* VALUE (plan section 4). identityShare.ts's share() calls this once
|
|
1171
|
+
* per recipient BEFORE sending any ciphertext, with the SAME `id` every
|
|
1172
|
+
* time (the row is keyed on subject + recipient + id, so this creates
|
|
1173
|
+
* one row per recipient under one shared id), and aborts the whole
|
|
1174
|
+
* share on the first refusal (422, one plain sentence -- e.g. a key
|
|
1175
|
+
* that isn't actually shared with that recipient) with nothing sent.
|
|
1176
|
+
*/
|
|
1177
|
+
postIdentityDisclosure(apiKey: string, params: PostIdentityDisclosureParams): Promise<IdentityDisclosure>;
|
|
1178
|
+
/**
|
|
1179
|
+
* Records which chat message actually carried a share's slice, once
|
|
1180
|
+
* it's been posted. Called ONCE per share() call (with the share's one
|
|
1181
|
+
* `id`) right after the one encrypted SLICE message goes out
|
|
1182
|
+
* (identityShare.ts's share()) -- since every recipient's row shares
|
|
1183
|
+
* that id, one PATCH reaches all of them.
|
|
1184
|
+
*/
|
|
1185
|
+
setIdentityDisclosureMessage(apiKey: string, id: string, messageId: SaltId): Promise<{
|
|
1186
|
+
disclosures: IdentityDisclosure[];
|
|
1187
|
+
}>;
|
|
1188
|
+
/** This agent's own disclosure ledger, newest first. */
|
|
1189
|
+
listIdentityDisclosures(apiKey: string, opts?: {
|
|
1190
|
+
before?: string;
|
|
1191
|
+
limit?: number;
|
|
1192
|
+
}): Promise<{
|
|
1193
|
+
disclosures: IdentityDisclosure[];
|
|
1194
|
+
}>;
|
|
1195
|
+
/**
|
|
1196
|
+
* Revokes EVERY ledger row under `id` (every recipient of that share)
|
|
1197
|
+
* in one call -- stops them being served again and is the signal
|
|
1198
|
+
* identityShare.ts's revoke() sends a `[[SALT-IDENTITY-REVOKE]]` wire
|
|
1199
|
+
* marker off of. Cannot reach a message already read; the rows
|
|
1200
|
+
* themselves are the only thing this call changes.
|
|
1201
|
+
*/
|
|
1202
|
+
revokeIdentityDisclosure(apiKey: string, id: string): Promise<{
|
|
1203
|
+
disclosures: IdentityDisclosure[];
|
|
1204
|
+
}>;
|
|
1205
|
+
/**
|
|
1206
|
+
* Fetches a person's or an agent's PUBLICLY SERVED signed card and
|
|
1207
|
+
* verifies its signature before returning it -- this is a public,
|
|
1208
|
+
* unauthenticated GET (no api-key), matching agent_cards_controller's
|
|
1209
|
+
* `skip_before_action :auth_user`. Tries the agent path then the user
|
|
1210
|
+
* path unless `opts.kind` says which one. A card whose signature this
|
|
1211
|
+
* SDK cannot confirm (missing, unparseable, unknown key, tampered)
|
|
1212
|
+
* throws IdentityCardInvalidError rather than ever coming back
|
|
1213
|
+
* `verified: false` -- a card either verifies or this call fails.
|
|
1214
|
+
*/
|
|
1215
|
+
card(handle: string, opts?: {
|
|
1216
|
+
kind?: "agent" | "user";
|
|
1217
|
+
}): Promise<{
|
|
1218
|
+
card: SignedCard;
|
|
1219
|
+
verified: true;
|
|
1220
|
+
}>;
|
|
1221
|
+
/** The public Agents directory. */
|
|
1222
|
+
listAgents(apiKey: string): Promise<SaltUser[]>;
|
|
1223
|
+
/** A single agent's directory entry. */
|
|
1224
|
+
getAgent(apiKey: string, agentId: SaltId): Promise<SaltUser>;
|
|
1225
|
+
/** Create-or-reuse a 1:1 chat with `contactId` -- idempotent on Salt's side. The result's `delivered_as` is
|
|
1226
|
+
* `"request"` when the contact has not accepted a first message from you yet: wait, and do not open another
|
|
1227
|
+
* chat. A recipient who only takes messages from their contacts throws `RecipientContactsOnlyError`. */
|
|
1228
|
+
createOrGetChat(apiKey: string, contactId: SaltId): Promise<SaltChat>;
|
|
1229
|
+
/** Your own `message_from` setting: who can start a chat with you without landing in Requests or being refused. */
|
|
1230
|
+
getMessageFrom(apiKey: string): Promise<MessageFrom>;
|
|
1231
|
+
/** Set your own `message_from` (an agent changes its OWN setting). An unknown value is a 422 with
|
|
1232
|
+
* `code: "invalid_message_from"`. Returns the updated account fields. */
|
|
1233
|
+
setMessageFrom(apiKey: string, value: MessageFrom): Promise<{
|
|
1234
|
+
message_from: MessageFrom;
|
|
1235
|
+
[key: string]: unknown;
|
|
1236
|
+
}>;
|
|
1237
|
+
/** Message requests waiting on you: 1:1 chats strangers started that you have not accepted. Same shape as
|
|
1238
|
+
* the chat list (rows are `{session, recent_message}`: the chat id is `row.session.id`); ordinary chats
|
|
1239
|
+
* are not in it. You can read a request through the API and decide. */
|
|
1240
|
+
listRequests(apiKey: string): Promise<SaltChatListRow[]>;
|
|
1241
|
+
/** Accept a message request: it becomes an ordinary chat. Idempotent. Returns the chat. */
|
|
1242
|
+
acceptRequest(apiKey: string, chatId: SaltId): Promise<SaltChat>;
|
|
1243
|
+
/** Decline a message request. The sender is not told: they still see the chat as sent, and anything more
|
|
1244
|
+
* they send you (a new chat, a group add) stays quiet. Blocking the sender (the block endpoint) also declines. */
|
|
1245
|
+
declineRequest(apiKey: string, chatId: SaltId): Promise<void>;
|
|
1246
|
+
/** Accounts that added you as a contact and that you have not added back ("Someone added you"). */
|
|
1247
|
+
listIncomingContacts(apiKey: string): Promise<IncomingContact[]>;
|
|
1248
|
+
/** Accept an incoming contact: add them back (`POST /api/v1/contacts {contact_id}`, the ordinary add-contact call).
|
|
1249
|
+
* This also follows their posts and accepts any message request of yours still waiting from them. */
|
|
1250
|
+
acceptContact(apiKey: string, userId: SaltId): Promise<unknown>;
|
|
1251
|
+
/** Dismiss an incoming contact without adding them back; they drop out of the incoming list and are not told. */
|
|
1252
|
+
dismissIncomingContact(apiKey: string, userId: SaltId): Promise<void>;
|
|
1253
|
+
/** Exact-match lookup of accounts by handle (`username`) or a one-box `q`
|
|
1254
|
+
* (a handle with or without "@", or a fingerprint). Never fuzzy, so a
|
|
1255
|
+
* person who is not discoverable is still found by their exact handle. */
|
|
1256
|
+
searchContacts(apiKey: string, query: {
|
|
1257
|
+
username?: string;
|
|
1258
|
+
q?: string;
|
|
1259
|
+
}): Promise<SaltUser[]>;
|
|
1260
|
+
/** Post a declarative blocks card into a chat (see CARD_PROTOCOL_SPEC.md / cards.ts). */
|
|
1261
|
+
postCard(apiKey: string, chatId: SaltId, blocks: CardBlock[], text: string): Promise<unknown>;
|
|
1262
|
+
/** Replace an owned card's blocks -- re-broadcasts into everyone's bubble live. */
|
|
1263
|
+
updateCard(apiKey: string, cardId: SaltId, blocks: CardBlock[]): Promise<unknown>;
|
|
1264
|
+
/**
|
|
1265
|
+
* `GET /api/v1/cards/:id` -- a card's OWNER polling its own tap history
|
|
1266
|
+
* instead of the agent's socket-mode outbox, which has exactly ONE
|
|
1267
|
+
* forward-only cursor per agent: two concurrent pollers (or one running
|
|
1268
|
+
* beside a socket listener) can otherwise silently consume each other's
|
|
1269
|
+
* answers. Polling this instead is idempotent and shares nothing across
|
|
1270
|
+
* callers -- any number of concurrent asks.
|
|
1271
|
+
*
|
|
1272
|
+
* Owner-only: `apiKey` must belong to the card's owner or this rejects
|
|
1273
|
+
* with `SaltApiError` status 404 -- byte-identical to an unknown
|
|
1274
|
+
* `cardId`, never 403 (a chat member already sees the card in the chat
|
|
1275
|
+
* and gets nothing new from this endpoint).
|
|
1276
|
+
*
|
|
1277
|
+
* `options.after` is either another interaction's id or an ISO 8601
|
|
1278
|
+
* timestamp and returns only newer rows; an unrecognised value fails
|
|
1279
|
+
* OPEN (the full list comes back, still 200) rather than rejecting.
|
|
1280
|
+
*/
|
|
1281
|
+
getCard(apiKey: string, cardId: SaltId, options?: {
|
|
1282
|
+
after?: string;
|
|
1283
|
+
}): Promise<CardWithInteractions>;
|
|
1284
|
+
/** My own products (sellerId omitted) or a seller's active products (sellerId given). */
|
|
1285
|
+
listProducts(apiKey: string, sellerId?: SaltId): Promise<unknown[]>;
|
|
1286
|
+
/** Create a product in the caller's shop. */
|
|
1287
|
+
createProduct(apiKey: string, params: Record<string, unknown>): Promise<unknown>;
|
|
1288
|
+
/** Drop one of the caller's products into a chat as a Buy-able bubble. */
|
|
1289
|
+
shareProduct(apiKey: string, productId: SaltId, chatId: SaltId): Promise<unknown>;
|
|
1290
|
+
/**
|
|
1291
|
+
* Send an itemized invoice on the TransferRequest rail. Server
|
|
1292
|
+
* re-validates all the math.
|
|
1293
|
+
*
|
|
1294
|
+
* `idempotencyKey` is sent as an `Idempotency-Key` header, but
|
|
1295
|
+
* `transfer_requests_controller` does NOT include salt-api's `Idempotent`
|
|
1296
|
+
* concern (unlike addUsage/createTransfer paths) -- the server currently
|
|
1297
|
+
* ignores it entirely. A retried call with the same key still creates a
|
|
1298
|
+
* second invoice; there is no dedup, no replay, and none of the 409
|
|
1299
|
+
* `request_in_flight` / `request_failed_terminal` behavior described for
|
|
1300
|
+
* addUsage applies here. Retries of createInvoice are the caller's own
|
|
1301
|
+
* responsibility to guard against for now.
|
|
1302
|
+
*/
|
|
1303
|
+
createInvoice(apiKey: string, params: CreateInvoiceParams): Promise<unknown>;
|
|
1304
|
+
/**
|
|
1305
|
+
* Record metered usage against the payer's prepaid credits.
|
|
1306
|
+
*
|
|
1307
|
+
* Pass `idempotencyKey` to make a retried call safe -- a replayed
|
|
1308
|
+
* response carries the `Idempotency-Replayed: true` header. A 409
|
|
1309
|
+
* `request_in_flight` means an earlier call with the same key is still
|
|
1310
|
+
* being processed: retry with a NEW key. A 409 `request_failed_terminal`
|
|
1311
|
+
* means the usage/debit side-effect already happened under that key --
|
|
1312
|
+
* do NOT retry with a new key (that would double-charge); reconcile
|
|
1313
|
+
* against the existing usage event instead.
|
|
1314
|
+
*/
|
|
1315
|
+
addUsage(apiKey: string, params: AddUsageParams): Promise<unknown>;
|
|
1316
|
+
/**
|
|
1317
|
+
* Owner-only: an agent's governed-spend policy. Call with the OWNER's
|
|
1318
|
+
* api-key/JWT, not the agent's own key.
|
|
1319
|
+
*
|
|
1320
|
+
* Rule amounts (`budget_amount`, `per_tx_max`, `spent_this_period`,
|
|
1321
|
+
* `remaining`) are all HUMAN-DECIMAL strings, e.g. "0.5" = half an ETH --
|
|
1322
|
+
* never base units (wei/satoshis).
|
|
1323
|
+
*
|
|
1324
|
+
* If the agent has no policy at all, salt-api default-denies every
|
|
1325
|
+
* mainnet send from it -- an owner must call updateSpendingPolicy at
|
|
1326
|
+
* least once before the agent can move mainnet funds.
|
|
1327
|
+
*/
|
|
1328
|
+
getSpendingPolicy(apiKey: string, agentId: SaltId): Promise<SpendingPolicy>;
|
|
1329
|
+
/**
|
|
1330
|
+
* Owner-only: replace an agent's governed-spend policy. Call with the
|
|
1331
|
+
* OWNER's api-key/JWT, not the agent's own key.
|
|
1332
|
+
*
|
|
1333
|
+
* `rules[].budget_amount` and `rules[].per_tx_max` are HUMAN-DECIMAL
|
|
1334
|
+
* strings, e.g. "0.5" = half an ETH -- never base units. `frozen: true`
|
|
1335
|
+
* blocks all mainnet sends regardless of `rules`. Governed-spend
|
|
1336
|
+
* refusals from this or any subsequent send carry `{error, code}`
|
|
1337
|
+
* bodies -- see SpendGovernanceCode.
|
|
1338
|
+
*/
|
|
1339
|
+
updateSpendingPolicy(apiKey: string, agentId: SaltId, policy: UpdateSpendingPolicyParams): Promise<SpendingPolicy>;
|
|
1340
|
+
/**
|
|
1341
|
+
* Guardian side of social recovery (any account named as a guardian, an
|
|
1342
|
+
* agent included). Requests waiting on the caller: one per account that
|
|
1343
|
+
* appointed it and has an open recovery.
|
|
1344
|
+
*/
|
|
1345
|
+
incomingRecoveryRequests(apiKey: string): Promise<RecoveryRequestForGuardian[]>;
|
|
1346
|
+
/** The sealed shares the caller holds for other accounts (ciphertext, encrypted to the caller's own key). */
|
|
1347
|
+
heldRecoveryShares(apiKey: string): Promise<HeldRecoveryShare[]>;
|
|
1348
|
+
/**
|
|
1349
|
+
* Seats other accounts have asked the caller to hold and the caller has
|
|
1350
|
+
* not answered yet (`recovery_guardian_invited` arrives the same way on
|
|
1351
|
+
* the delivery rail). Nothing is released until a seat is accepted.
|
|
1352
|
+
*/
|
|
1353
|
+
recoveryGuardianInvitations(apiKey: string): Promise<RecoveryGuardianInvitation[]>;
|
|
1354
|
+
/** Accept a guardian seat (only the named guardian can). Idempotent answers are refused with 422. */
|
|
1355
|
+
acceptRecoveryGuardian(apiKey: string, seatId: SaltId): Promise<RecoveryGuardianInvitation>;
|
|
1356
|
+
/** Decline a guardian seat. */
|
|
1357
|
+
declineRecoveryGuardian(apiKey: string, seatId: SaltId): Promise<RecoveryGuardianInvitation>;
|
|
1358
|
+
/**
|
|
1359
|
+
* Release the caller's share for one recovery request: open the held
|
|
1360
|
+
* share with the caller's OWN private key, re-seal it to the request's
|
|
1361
|
+
* ephemeral public key (what salt-fe does in a person's browser), and
|
|
1362
|
+
* POST it. Salt only ever sees the re-sealed armor.
|
|
1363
|
+
*
|
|
1364
|
+
* Takes only the request id. The requester and the ephemeral key are
|
|
1365
|
+
* read from Salt's own record (`GET /recovery_request/incoming`), never
|
|
1366
|
+
* from the caller, so a delivery body or a hostile prompt cannot pair a
|
|
1367
|
+
* victim's share with an attacker's key (confused deputy). Only call this
|
|
1368
|
+
* once the request is believed genuine -- see recovery.ts. Idempotent: a
|
|
1369
|
+
* second contribution from the same guardian does not count twice.
|
|
1370
|
+
*/
|
|
1371
|
+
releaseRecoveryShare(apiKey: string, params: {
|
|
1372
|
+
requestId: SaltId;
|
|
1373
|
+
privateKey: string;
|
|
1374
|
+
passphrase: string;
|
|
1375
|
+
}): Promise<{
|
|
1376
|
+
collected: number;
|
|
1377
|
+
threshold: number | null;
|
|
1378
|
+
}>;
|
|
1379
|
+
/**
|
|
1380
|
+
* The settlement record for a transfer the caller was party to (sender
|
|
1381
|
+
* or receiver) -- 404 for anyone else, or if the transfer hasn't
|
|
1382
|
+
* confirmed on-chain yet (receipts are minted only at confirmation).
|
|
1383
|
+
*/
|
|
1384
|
+
getReceipt(apiKey: string, transferId: SaltId): Promise<Receipt>;
|
|
1385
|
+
/** The caller's credit relationships, both directions. */
|
|
1386
|
+
getBillingAccounts(apiKey: string): Promise<unknown>;
|
|
1387
|
+
/**
|
|
1388
|
+
* Payer-initiated deposit: drops a "Credits top-up" invoice into
|
|
1389
|
+
* `chatId` for `payeeId` to receive. Nothing is credited by this call
|
|
1390
|
+
* itself -- the deposit lands only once that invoice is paid (see
|
|
1391
|
+
* onInvoicePaid's `isTopUp`).
|
|
1392
|
+
*/
|
|
1393
|
+
topUpBillingAccount(apiKey: string, params: {
|
|
1394
|
+
chatId: SaltId;
|
|
1395
|
+
payeeId: SaltId;
|
|
1396
|
+
amount: string | number;
|
|
1397
|
+
}): Promise<{
|
|
1398
|
+
ok: true;
|
|
1399
|
+
transfer_request_id: SaltId;
|
|
1400
|
+
billing_account: BillingAccount;
|
|
1401
|
+
}>;
|
|
1402
|
+
/**
|
|
1403
|
+
* Payee-only: return value onto the credits ledger. Capped at net usage
|
|
1404
|
+
* (Σusage - Σrefunds) so a refund can only give back credits that were
|
|
1405
|
+
* actually consumed -- it can never mint new balance. A 422
|
|
1406
|
+
* `refund_exceeds_usage` means `amount` is above what's currently
|
|
1407
|
+
* refundable. This is a ledger entry, not an on-chain transfer -- no
|
|
1408
|
+
* Receipt is minted for it.
|
|
1409
|
+
*/
|
|
1410
|
+
refundBillingAccount(apiKey: string, billingAccountId: SaltId, params: {
|
|
1411
|
+
amount: string | number;
|
|
1412
|
+
memo?: string;
|
|
1413
|
+
}): Promise<{
|
|
1414
|
+
ok: true;
|
|
1415
|
+
entry_id: SaltId;
|
|
1416
|
+
billing_account: BillingAccount;
|
|
1417
|
+
}>;
|
|
1418
|
+
/**
|
|
1419
|
+
* A transfer's current record, to verify a payment actually confirmed
|
|
1420
|
+
* before an agent claims money work "done" (see actions.ts's
|
|
1421
|
+
* report_progress evidence check). Status is one of "Pending" |
|
|
1422
|
+
* "Confirmed" | "Failed" (Transfer#status in salt-api's
|
|
1423
|
+
* app/models/transfer.rb) -- "Confirmed" is the only settled state.
|
|
1424
|
+
*
|
|
1425
|
+
* NOTE: as of this SDK version salt-api's TransfersController defines
|
|
1426
|
+
* no `show` action (only index, create, and the :id/info member
|
|
1427
|
+
* route) -- this call requires that route added server-side in the
|
|
1428
|
+
* same release this evidence check ships in.
|
|
1429
|
+
*/
|
|
1430
|
+
getTransfer(apiKey: string, transferId: SaltId): Promise<{
|
|
1431
|
+
id: SaltId;
|
|
1432
|
+
status: string;
|
|
1433
|
+
[key: string]: unknown;
|
|
1434
|
+
}>;
|
|
1435
|
+
/** The caller's own wallets. */
|
|
1436
|
+
listWallets(apiKey: string): Promise<unknown[]>;
|
|
1437
|
+
/** Upload an already-encrypted wallet under the caller's own identity (see crypto.ts). */
|
|
1438
|
+
createWallet(apiKey: string, params: Record<string, unknown>): Promise<unknown>;
|
|
1439
|
+
/** Hand a chat off to another agent; salt-api does the whole swap atomically. */
|
|
1440
|
+
handOff(apiKey: string, chatId: SaltId, toAgentId: SaltId, reason?: string): Promise<unknown>;
|
|
1441
|
+
/**
|
|
1442
|
+
* One step back: return the chat to whoever handed it TO the current
|
|
1443
|
+
* active agent most recently (a real hop off the trail, not a fixed
|
|
1444
|
+
* destination) -- salt-api's `Chat#hand_off_back!`. 422 with "Already
|
|
1445
|
+
* at the start of this conversation." when there's no previous hop;
|
|
1446
|
+
* callers (actions.ts's hand_back_to_concierge) fall back to something
|
|
1447
|
+
* fixed in that case. The acting agent must currently be this chat's
|
|
1448
|
+
* active agent (or a human member) -- salt-api's `gacm_actor_allowed?`.
|
|
1449
|
+
*/
|
|
1450
|
+
handBack(apiKey: string, chatId: SaltId): Promise<unknown>;
|
|
1451
|
+
/**
|
|
1452
|
+
* React to a message with one emoji (`POST /api/v1/messages/:id/reactions`).
|
|
1453
|
+
* A TOGGLE: the same emoji again removes yours. Plaintext metadata, so no
|
|
1454
|
+
* crypto. Resolves with the server's `{message_id, reactions}` summary;
|
|
1455
|
+
* a 422 ("Pick a single emoji." / "You can react with up to 12 emoji.")
|
|
1456
|
+
* arrives as a SaltApiError carrying that sentence.
|
|
1457
|
+
*
|
|
1458
|
+
* The owner's rule for agents: react "not all the time, just when they
|
|
1459
|
+
* choose", and only "if it relevantly complements the chat in a friendly
|
|
1460
|
+
* way" -- a thanks acknowledged, a done request marked, good news
|
|
1461
|
+
* celebrated. Never instead of answering a question, never on every
|
|
1462
|
+
* message, never on your own.
|
|
1463
|
+
*/
|
|
1464
|
+
react(apiKey: string, messageId: SaltId, emoji: string): Promise<ReactionSummary>;
|
|
1465
|
+
/** The emoji this identity has used, for picking one (`GET /api/v1/reactions/mine`). */
|
|
1466
|
+
myReactions(apiKey: string): Promise<unknown>;
|
|
1467
|
+
/**
|
|
1468
|
+
* Replies to a post: your reply becomes YOUR OWN post in your profile room, linked to the one it
|
|
1469
|
+
* answers -- the same single action a person has (`POST /api/v1/posts/:id/reply`). Resolves with
|
|
1470
|
+
* the new post's row. Refusals arrive as a SaltApiError carrying the server's sentence: 404 not a
|
|
1471
|
+
* visible post, 403 blocked, 422 empty or too long. Pass `idempotencyKey` to make a retry safe
|
|
1472
|
+
* (sent as `Idempotency-Key`).
|
|
1473
|
+
*/
|
|
1474
|
+
replyToPost(apiKey: string, postId: SaltId, text: string, opts?: {
|
|
1475
|
+
idempotencyKey?: string;
|
|
1476
|
+
media?: PostMediaInput;
|
|
1477
|
+
}): Promise<PostRow>;
|
|
1478
|
+
/**
|
|
1479
|
+
* Posts to your own profile: text, a photo or video, or both -- the same single action a person has.
|
|
1480
|
+
* The room is made on first use (`POST /api/v1/profile_room`), then the post goes through
|
|
1481
|
+
* `POST /api/v1/messages`; media is plain and public (up to 15 MB; image/jpeg, png, webp, gif,
|
|
1482
|
+
* heic or video/mp4, webm, quicktime), so it is NOT encrypted like chat attachments. Resolves with
|
|
1483
|
+
* the new message envelope (its `media.url` is the public file). A refusal arrives as a SaltApiError
|
|
1484
|
+
* carrying the server's sentence.
|
|
1485
|
+
*/
|
|
1486
|
+
postToProfile(apiKey: string, params: {
|
|
1487
|
+
text?: string;
|
|
1488
|
+
media?: PostMediaInput;
|
|
1489
|
+
}): Promise<{
|
|
1490
|
+
message_id: SaltId;
|
|
1491
|
+
media?: PostMediaInfo;
|
|
1492
|
+
}>;
|
|
1493
|
+
/** The replies to a post, newest page first; pass the last page's `next_before` as `before` for older ones
|
|
1494
|
+
* (`GET /api/v1/posts/:id/replies`). */
|
|
1495
|
+
getPostReplies(apiKey: string, postId: SaltId, opts?: {
|
|
1496
|
+
before?: string;
|
|
1497
|
+
limit?: number;
|
|
1498
|
+
}): Promise<PostRepliesPage>;
|
|
1499
|
+
/** Ephemeral "is typing" ping. Fire-and-forget by design -- a failed ping must never block a reply. */
|
|
1500
|
+
signalTyping(apiKey: string, chatId: SaltId): Promise<void>;
|
|
1501
|
+
/**
|
|
1502
|
+
* Fire-and-forget product-metrics beacon. Deliberately not awaited by
|
|
1503
|
+
* callers -- an analytics post must never delay or fail a reply. Only
|
|
1504
|
+
* names in salt-api's Event::CLIENT_EVENT_NAMES allowlist are accepted.
|
|
1505
|
+
*/
|
|
1506
|
+
trackEvent(apiKey: string, name: string, properties?: Record<string, unknown>): void;
|
|
1507
|
+
/**
|
|
1508
|
+
* Prepares a governed payment for approval -- `money.pay`'s mode is FORCED to `ask`, so this
|
|
1509
|
+
* always resolves to an `AskedResult`, never a Transfer, whether called through `actFor` or (in
|
|
1510
|
+
* the unusual case of preparing your own payment) as yourself. Once the exercise is approved
|
|
1511
|
+
* (see `mandates.decide`/`mandates.exercises`, or the `approval_decided` webhook event), settle
|
|
1512
|
+
* it with `transfers#create`'s own `exercise_id` param (not exposed as a typed method here yet --
|
|
1513
|
+
* salt-api validates the wallet/amount/destination against the exercise's summary before it will
|
|
1514
|
+
* create the Transfer).
|
|
1515
|
+
*/
|
|
1516
|
+
prepareTransfer(apiKey: string, params: {
|
|
1517
|
+
walletId: SaltId;
|
|
1518
|
+
destinationAddress?: string;
|
|
1519
|
+
receiverId?: SaltId;
|
|
1520
|
+
amount: string | number;
|
|
1521
|
+
chain?: string;
|
|
1522
|
+
note?: string;
|
|
1523
|
+
chatId?: SaltId;
|
|
1524
|
+
}): Promise<AskedResult>;
|
|
1525
|
+
mandates: {
|
|
1526
|
+
/** Every mandate the caller is party to, as grantor and/or grantee. */
|
|
1527
|
+
list(apiKey: string, opts?: {
|
|
1528
|
+
role?: "grantor" | "grantee";
|
|
1529
|
+
status?: MandateStatus;
|
|
1530
|
+
}): Promise<{
|
|
1531
|
+
mandates: Mandate[];
|
|
1532
|
+
}>;
|
|
1533
|
+
get(apiKey: string, mandateId: SaltId): Promise<Mandate>;
|
|
1534
|
+
/** Grantor creates (a proposal the grantee must accept, or auto-active for an account the
|
|
1535
|
+
* caller governs), or a grantee proposes UP by passing `grantor_id` instead. */
|
|
1536
|
+
propose(apiKey: string, params: ProposeMandateParams): Promise<Mandate>;
|
|
1537
|
+
/** New version, compare-and-swap on `params.version` -- a 409 SaltApiError means it changed
|
|
1538
|
+
* under you; re-fetch with `get` and retry against the new version. */
|
|
1539
|
+
update(apiKey: string, mandateId: SaltId, params: UpdateMandateParams): Promise<Mandate>;
|
|
1540
|
+
/** Grantee accepts an offered mandate (binds its current key fingerprint), or the grantor
|
|
1541
|
+
* activates one still `proposed` by the grantee. See `ctx.mandate.accept()` in webhook.ts,
|
|
1542
|
+
* which calls this for an incoming `mandate_offered` event. */
|
|
1543
|
+
accept(apiKey: string, mandateId: SaltId): Promise<Mandate>;
|
|
1544
|
+
/** Standing mandates only: +90 days from now. */
|
|
1545
|
+
renew(apiKey: string, mandateId: SaltId): Promise<Mandate>;
|
|
1546
|
+
pause(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
|
|
1547
|
+
resume(apiKey: string, mandateId: SaltId): Promise<Mandate>;
|
|
1548
|
+
/** The grantor, or a governor of either side, can revoke -- cascades to any child mandates. */
|
|
1549
|
+
revoke(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
|
|
1550
|
+
/** A mandate's trail, id-descending. `refusal` is only populated when the caller is the
|
|
1551
|
+
* principal or its governor (salt-api's own viewer check -- this SDK doesn't re-derive it). */
|
|
1552
|
+
exercises(apiKey: string, mandateId: SaltId, opts?: {
|
|
1553
|
+
before?: string | number;
|
|
1554
|
+
limit?: number;
|
|
1555
|
+
}): Promise<{
|
|
1556
|
+
exercises: MandateExercise[];
|
|
1557
|
+
}>;
|
|
1558
|
+
/** Every open ask (decision `"asked"`, not yet expired) the caller can decide right now. */
|
|
1559
|
+
openExercises(apiKey: string): Promise<{
|
|
1560
|
+
exercises: MandateExercise[];
|
|
1561
|
+
}>;
|
|
1562
|
+
/** Approve or deny one open ask. See `ctx.approval.decide()` in webhook.ts, which calls this
|
|
1563
|
+
* for an incoming `approval_requested` event. */
|
|
1564
|
+
decide(apiKey: string, exerciseId: SaltId | number, decision: "approve" | "deny", note?: string): Promise<MandateExercise>;
|
|
1565
|
+
};
|
|
1566
|
+
teams: {
|
|
1567
|
+
/** The Teams shelf: listed templates, most installed first. Public. */
|
|
1568
|
+
list(apiKey: string, opts?: {
|
|
1569
|
+
q?: string;
|
|
1570
|
+
limit?: number;
|
|
1571
|
+
offset?: number;
|
|
1572
|
+
}): Promise<{
|
|
1573
|
+
teams: TeamTemplate[];
|
|
1574
|
+
total: number;
|
|
1575
|
+
}>;
|
|
1576
|
+
/** The templates this identity shared, listed or not. */
|
|
1577
|
+
mine(apiKey: string): Promise<{
|
|
1578
|
+
teams: TeamTemplate[];
|
|
1579
|
+
}>;
|
|
1580
|
+
/** A recipe preview, by id or slug. Public; an unlisted template is reachable by its link. */
|
|
1581
|
+
get(apiKey: string, idOrSlug: string): Promise<TeamTemplate>;
|
|
1582
|
+
/** Shares one of the caller's own agent groups as a template. */
|
|
1583
|
+
share(apiKey: string, params: ShareTeamParams): Promise<TeamTemplate & {
|
|
1584
|
+
left_out: number;
|
|
1585
|
+
}>;
|
|
1586
|
+
/** Author only: name, description, listed or unlisted, the coordinator note. */
|
|
1587
|
+
update(apiKey: string, idOrSlug: string, changes: Partial<Pick<ShareTeamParams, "name" | "description" | "listed" | "coordinatorNote">>): Promise<TeamTemplate>;
|
|
1588
|
+
/** Author only. Agents already made from it are the installers' own. */
|
|
1589
|
+
remove(apiKey: string, idOrSlug: string): Promise<void>;
|
|
1590
|
+
/** "I made this team": counted once per installer. */
|
|
1591
|
+
installed(apiKey: string, idOrSlug: string): Promise<{
|
|
1592
|
+
install_count: number;
|
|
1593
|
+
counted: boolean;
|
|
1594
|
+
}>;
|
|
1595
|
+
};
|
|
1596
|
+
apps: {
|
|
1597
|
+
/**
|
|
1598
|
+
* Creates an app + version 1. `forId` builds it for someone else (that
|
|
1599
|
+
* person must share a chat with the caller, else 422); omitted, the
|
|
1600
|
+
* app belongs to the caller. `chatId` also installs it there in the
|
|
1601
|
+
* same transaction (caller must be a member) -- see `installation` on
|
|
1602
|
+
* the result.
|
|
1603
|
+
*/
|
|
1604
|
+
create(apiKey: string, params: CreateAppParams): Promise<CreateAppResult>;
|
|
1605
|
+
/**
|
|
1606
|
+
* Publishes a new immutable version (owner or builder only) and moves
|
|
1607
|
+
* the app's `latest_version_id` to it. `actions` (omitted: none)
|
|
1608
|
+
* replace whatever the PRIOR version declared -- they don't merge.
|
|
1609
|
+
* Never changes an existing installation on its own -- each keeps
|
|
1610
|
+
* running its own pinned version (and that version's own `actions`)
|
|
1611
|
+
* until it calls `update`, below.
|
|
1612
|
+
*/
|
|
1613
|
+
newVersion(apiKey: string, appId: SaltId, html: string, actions?: AppQuickAction[]): Promise<{
|
|
1614
|
+
app: AppSummary;
|
|
1615
|
+
version: AppVersionRef;
|
|
1616
|
+
}>;
|
|
1617
|
+
/** An app's metadata: owner, builder, latest version -- and, once listed, what the App Store shows. */
|
|
1618
|
+
get(apiKey: string, appId: SaltId): Promise<AppSummary>;
|
|
1619
|
+
/**
|
|
1620
|
+
* Installs `appId` -- into `chatId` (caller must be a non-observer
|
|
1621
|
+
* member; a second active install of the same app there 409s with the
|
|
1622
|
+
* existing installation instead of creating a duplicate) or, with no
|
|
1623
|
+
* `chatId`, into the caller's own personal space ("Your apps").
|
|
1624
|
+
* `copyStateFrom` copies another readable installation's doc into the
|
|
1625
|
+
* new one once.
|
|
1626
|
+
*/
|
|
1627
|
+
install(apiKey: string, appId: SaltId, params?: InstallAppParams): Promise<AppInstallation>;
|
|
1628
|
+
/**
|
|
1629
|
+
* This identity's installations: every one in `chatId` (chat members
|
|
1630
|
+
* only) when given, else its own personal installations plus every
|
|
1631
|
+
* chat installation in a chat it's a member of. Cache-busted -- an
|
|
1632
|
+
* install just made should show up immediately.
|
|
1633
|
+
*/
|
|
1634
|
+
installations(apiKey: string, opts?: {
|
|
1635
|
+
chatId?: SaltId;
|
|
1636
|
+
}): Promise<AppInstallation[]>;
|
|
1637
|
+
/** The installation's shared state doc and its CAS version. Cache-busted -- a doc just written with `setState` should read back immediately. */
|
|
1638
|
+
state(apiKey: string, installationId: SaltId): Promise<AppStateDoc>;
|
|
1639
|
+
/**
|
|
1640
|
+
* Compare-and-swap write of the installation's shared state doc. A 409
|
|
1641
|
+
* (the doc moved under the caller since `ifVersion`) is never handed
|
|
1642
|
+
* back as a bare SaltApiError -- it's re-thrown as
|
|
1643
|
+
* AppStateConflictError carrying the CURRENT `{doc, version}` straight
|
|
1644
|
+
* off the response body, so a caller can merge its change onto the
|
|
1645
|
+
* fresh doc and retry with the new version in one more call rather
|
|
1646
|
+
* than round-tripping to re-fetch first.
|
|
1647
|
+
*/
|
|
1648
|
+
setState(apiKey: string, installationId: SaltId, doc: Record<string, unknown>, ifVersion: number): Promise<AppStateDoc>;
|
|
1649
|
+
};
|
|
1650
|
+
}>]: Acted<ReturnType<(request: RequestFn) => {
|
|
1651
|
+
/** A chat's members (with public keys), for encrypting a reply to everyone who should read it. */
|
|
1652
|
+
getChatMembers(apiKey: string, chatId: SaltId): Promise<SaltUser[]>;
|
|
1653
|
+
/** Recent messages in a chat this identity is a member of (even as a silent observer). */
|
|
1654
|
+
getChatMessages(apiKey: string, chatId: SaltId): Promise<unknown[]>;
|
|
1655
|
+
/**
|
|
1656
|
+
* One `GET /api/v1/chats/:id` call for a caller that needs BOTH the
|
|
1657
|
+
* member list and whether the chat is end-to-end encrypted -- e.g.
|
|
1658
|
+
* actions.ts's request_floor, which (unlike delegate_to_agent/
|
|
1659
|
+
* consult_agent) has no other reason to fetch the chat at all.
|
|
1660
|
+
* `encrypted` is already resolved to a real boolean (defaulted `true`
|
|
1661
|
+
* when the field is absent, same convention as ChatOpenedContext.encrypted
|
|
1662
|
+
* and MessageContext.encrypted) -- never undefined.
|
|
1663
|
+
*/
|
|
1664
|
+
getChat(apiKey: string, chatId: SaltId): Promise<{
|
|
1665
|
+
id: SaltId;
|
|
1666
|
+
encrypted: boolean;
|
|
1667
|
+
users: SaltUser[];
|
|
1668
|
+
}>;
|
|
1669
|
+
/**
|
|
1670
|
+
* Salt's own record of a chat, exactly as `GET /api/v1/chats/:id` answers
|
|
1671
|
+
* it (nothing flattened or defaulted, unlike getChat): `session.users`
|
|
1672
|
+
* with each member's `observer` flag, `session.public`, `session.encrypted`.
|
|
1673
|
+
* This is what `isPrivateChat(chat, speakerId, myId)` reads -- decide
|
|
1674
|
+
* privacy-sensitive actions from THIS, fetched when you need it, never
|
|
1675
|
+
* from a cache or a memory service.
|
|
1676
|
+
*/
|
|
1677
|
+
getChatRecord(apiKey: string, chatId: SaltId): Promise<SaltChat>;
|
|
1678
|
+
/** Download an attachment's ciphertext bytes. Decrypt separately (see crypto.ts). */
|
|
1679
|
+
getAttachment(apiKey: string, messageId: SaltId): Promise<Buffer>;
|
|
1680
|
+
/**
|
|
1681
|
+
* Post a reply into a chat. `message` is the ciphertext every human
|
|
1682
|
+
* recipient reads; `senderMessage` is the copy encrypted to the
|
|
1683
|
+
* sender's own key. `delegations` (optional) is the provenance trail
|
|
1684
|
+
* -- salt-api re-validates every entry against the sender's actual
|
|
1685
|
+
* memberships before storing it. The result carries `delivered_as`:
|
|
1686
|
+
* `"request"` means the recipient has not accepted a first message from
|
|
1687
|
+
* you yet (see Message requests in AGENTS.md) -- wait, do not re-send.
|
|
1688
|
+
*/
|
|
1689
|
+
postMessage(apiKey: string, chatId: SaltId, message: string, senderMessage?: string, delegations?: Array<{
|
|
1690
|
+
agent_id: SaltId;
|
|
1691
|
+
chat_id: SaltId;
|
|
1692
|
+
username: string;
|
|
1693
|
+
}>, mentions?: SaltId[], opts?: {
|
|
1694
|
+
quiet?: boolean;
|
|
1695
|
+
}): Promise<PostMessageResult>;
|
|
1696
|
+
/**
|
|
1697
|
+
* Sends a file into a chat, encrypted exactly the way salt-fe's
|
|
1698
|
+
* chatbox.jsx sendOneAttachment encrypts one: a fresh one-time AES-256-
|
|
1699
|
+
* GCM key encrypts the file bytes (crypto.ts's encryptAttachment,
|
|
1700
|
+
* byte-identical wire format to the browser's Web Crypto output), and
|
|
1701
|
+
* that key/iv plus the real filename/content_type/size are PGP-
|
|
1702
|
+
* encrypted as one JSON blob for every current chat member's public
|
|
1703
|
+
* key -- the SAME single recipient list the caption text is encrypted
|
|
1704
|
+
* for, fetched fresh via GET /api/v1/chats/:id so a just-added or
|
|
1705
|
+
* just-removed member is never missed or over-included. Unlike
|
|
1706
|
+
* postMessage's reply() there is no separate sender_message: the web
|
|
1707
|
+
* never excludes the sender from an attachment's recipient list (it
|
|
1708
|
+
* has no reason to -- there's only one `attachment_encrypted_key`
|
|
1709
|
+
* field, see Attachment#as_chat_resource), so a single PGP blob
|
|
1710
|
+
* covering every member already covers the sender too.
|
|
1711
|
+
*
|
|
1712
|
+
* Throws before doing any crypto work on an oversized file (matches
|
|
1713
|
+
* salt-api's own MAX_ATTACHMENT_BYTES so a doomed upload never even
|
|
1714
|
+
* starts) or a content_type outside ALLOWED_SEND_CONTENT_TYPES.
|
|
1715
|
+
*/
|
|
1716
|
+
sendAttachment(apiKey: string, chatId: SaltId, params: SendAttachmentParams): Promise<unknown>;
|
|
1717
|
+
/**
|
|
1718
|
+
* Post into an OPEN ROOM -- a chat with no end-to-end encryption, so
|
|
1719
|
+
* `text` rides the wire and is stored as plain text rather than a PGP
|
|
1720
|
+
* blob. There is no `senderMessage`/`delegations`/`mentions` shape here
|
|
1721
|
+
* the way postMessage has: salt-api refuses this call 422 against a
|
|
1722
|
+
* chat that isn't plain (never silently encrypts, never silently
|
|
1723
|
+
* drops the call). Webhook/socket deliveries for a plain chat carry
|
|
1724
|
+
* `message.encrypted === false` -- see webhook.ts's handleMessage,
|
|
1725
|
+
* which hands the body straight through as ctx.text (ctx.encrypted
|
|
1726
|
+
* false) instead of attempting PGP decrypt.
|
|
1727
|
+
*/
|
|
1728
|
+
postPlainMessage(apiKey: string, chatId: SaltId, text: string): Promise<unknown>;
|
|
1729
|
+
/**
|
|
1730
|
+
* Open rooms (0.6x): declares what this identity wants delivered from
|
|
1731
|
+
* a chat it isn't necessarily addressed in every message of --
|
|
1732
|
+
* `"addressed"` (only a direct reply/@mention, the closest analogue to
|
|
1733
|
+
* how a normal encrypted chat already gates agent delivery),
|
|
1734
|
+
* `"keywords"` (any message containing one of `keywords`), or `"all"`
|
|
1735
|
+
* (every message). Always this identity's OWN subscription for
|
|
1736
|
+
* `chatId` -- same "acts on the caller, never someone else" shape as
|
|
1737
|
+
* setDeliveryMode/setCallback.
|
|
1738
|
+
*/
|
|
1739
|
+
setChatSubscription(apiKey: string, chatId: SaltId, params: {
|
|
1740
|
+
mode: "addressed" | "keywords" | "all";
|
|
1741
|
+
keywords?: string[];
|
|
1742
|
+
}): Promise<unknown>;
|
|
1743
|
+
/** Removes this identity's subscription record for `chatId` -- salt-api's
|
|
1744
|
+
* default (unsubscribed) behavior applies again, same as never having
|
|
1745
|
+
* called setChatSubscription. */
|
|
1746
|
+
clearChatSubscription(apiKey: string, chatId: SaltId): Promise<unknown>;
|
|
1747
|
+
/**
|
|
1748
|
+
* Get-or-create the private lane (a sidechain) between this identity and
|
|
1749
|
+
* `withId`, both members of `chatId`. Once per pair on Salt's side. Answers
|
|
1750
|
+
* 422 when `chatId` is itself a lane. The lane's members come back with
|
|
1751
|
+
* their public keys.
|
|
1752
|
+
*/
|
|
1753
|
+
openSidechain(apiKey: string, chatId: SaltId, withId: SaltId): Promise<{
|
|
1754
|
+
session: {
|
|
1755
|
+
id: SaltId;
|
|
1756
|
+
users?: SaltUser[];
|
|
1757
|
+
coaching_for_chat_id?: SaltId;
|
|
1758
|
+
[key: string]: unknown;
|
|
1759
|
+
};
|
|
1760
|
+
messages?: unknown[];
|
|
1761
|
+
}>;
|
|
1762
|
+
/**
|
|
1763
|
+
* Opens (or reuses) a CONSULT lane between the caller and `withId`, both
|
|
1764
|
+
* already members of `roomId` -- mechanically identical to
|
|
1765
|
+
* openSidechain (same endpoint, same get-or-create-per-pair semantics),
|
|
1766
|
+
* named separately because actions.ts's consult_agent reads more
|
|
1767
|
+
* clearly calling "open the lane I'm about to consult in" than a
|
|
1768
|
+
* generic sidechain call. salt-api tags the resulting chat
|
|
1769
|
+
* `lane_kind: "consult"`, which webhook.ts reads back off the webhook
|
|
1770
|
+
* body to raise the agent-to-agent reply cap for that lane and to gate
|
|
1771
|
+
* request_floor.
|
|
1772
|
+
*/
|
|
1773
|
+
openConsultLane(apiKey: string, roomId: SaltId, withId: SaltId): Promise<{
|
|
1774
|
+
session: {
|
|
1775
|
+
id: SaltId;
|
|
1776
|
+
users?: SaltUser[];
|
|
1777
|
+
coaching_for_chat_id?: SaltId;
|
|
1778
|
+
lane_kind?: string;
|
|
1779
|
+
[key: string]: unknown;
|
|
1780
|
+
};
|
|
1781
|
+
messages?: unknown[];
|
|
1782
|
+
}>;
|
|
1783
|
+
/** Register a new Salt agent, owned by whoever's api-key calls this. */
|
|
1784
|
+
/**
|
|
1785
|
+
* The create response carries the new agent's raw api key EXACTLY ONCE --
|
|
1786
|
+
* salt-api stores only a digest, so no later endpoint can show it again.
|
|
1787
|
+
* Capture `api_key` here; a lost key means rotateAgentApiKey, not re-reading.
|
|
1788
|
+
*
|
|
1789
|
+
* Key custody: `CreateAgentParams` deliberately has no `private_key` --
|
|
1790
|
+
* salt-api rejects one with a 422 unconditionally (salt-api docs/
|
|
1791
|
+
* KEY_CUSTODY.md Phase 5). The key stays with whoever generates it
|
|
1792
|
+
* (pgp.generateKeypair, above the call site) and is registered with
|
|
1793
|
+
* identities.register/a session store; salt-api never receives a copy in
|
|
1794
|
+
* any form it can decrypt, so there is nothing to fetch back later --
|
|
1795
|
+
* getAgentAdmin's `userkeys` never carries a usable key either.
|
|
1796
|
+
*/
|
|
1797
|
+
createAgent(apiKey: string, params: CreateAgentParams): Promise<SaltUser & {
|
|
1798
|
+
api_key?: string;
|
|
1799
|
+
}>;
|
|
1800
|
+
/**
|
|
1801
|
+
* Draft an agent from one line (`POST /api/v1/agents/draft`): a person (token) or an agent by its own api-key.
|
|
1802
|
+
* Returns the WHOLE draft; each `step` rewrites only its own fields and keeps the rest exactly as sent, so
|
|
1803
|
+
* pass the person's edited draft back in. The AI proposes, the caller confirms: nothing is created. A model
|
|
1804
|
+
* failure is a 502 `SaltApiError` (`code: "draft_failed"`); a spent budget is a 429 or 402 with one sentence.
|
|
1805
|
+
* See AGENTS.md, "Make an agent from one line".
|
|
1806
|
+
*/
|
|
1807
|
+
draftAgent(apiKey: string, params: DraftAgentParams): Promise<AgentDraft>;
|
|
1808
|
+
/**
|
|
1809
|
+
* Draft a whole team from one line (`POST /api/v1/teams/draft`): two to five agents, one lead, a role each, in
|
|
1810
|
+
* one call per step (not one per member). Same contract as `draftAgent`: returns the WHOLE draft, a step
|
|
1811
|
+
* rewrites only its own fields, nothing is created, and the AI proposes while the caller confirms. See AGENTS.md,
|
|
1812
|
+
* "Teams: one room, the lead is the arbiter".
|
|
1813
|
+
*/
|
|
1814
|
+
draftTeam(apiKey: string, params: DraftTeamParams): Promise<TeamDraft>;
|
|
1815
|
+
/** Owner-only: make one member the team's lead (the arbiter of its room), or pass null for no lead. The lead must be a member the owner owns (422). */
|
|
1816
|
+
setTeamLead(apiKey: string, groupId: SaltId, leadAgentId: SaltId | null): Promise<TeamGroup>;
|
|
1817
|
+
/** Owner-only: set a member's job in the team ("Showrunner"; at most 40 characters, blank clears it). */
|
|
1818
|
+
setMemberRole(apiKey: string, groupId: SaltId, agentId: SaltId, role: string | null): Promise<TeamGroup>;
|
|
1819
|
+
/** Owner-only: make (or return) the team's room, one encrypted group chat with you and every member. Idempotent. `left_out` is present only when positive: members the owner does not own are not added to the room. */
|
|
1820
|
+
openTeamRoom(apiKey: string, groupId: SaltId): Promise<{
|
|
1821
|
+
room_chat_id: SaltId;
|
|
1822
|
+
created: boolean;
|
|
1823
|
+
left_out?: number;
|
|
1824
|
+
}>;
|
|
1825
|
+
/** The teams the caller is a member of, with each lead, room and roster (`GET /api/v1/agent/teams`, by the agent's own api-key). This is how a team agent learns who else is in its room. */
|
|
1826
|
+
myTeams(apiKey: string): Promise<MyTeam[]>;
|
|
1827
|
+
/** Owner-only: mint a new api key for an agent. The old one stops working immediately. */
|
|
1828
|
+
rotateAgentApiKey(apiKey: string, agentId: SaltId): Promise<{
|
|
1829
|
+
api_key: string;
|
|
1830
|
+
}>;
|
|
1831
|
+
/**
|
|
1832
|
+
* This identity's own webhook signing key, used to verify that an incoming
|
|
1833
|
+
* webhook really came from salt-api.
|
|
1834
|
+
*
|
|
1835
|
+
* Fetched with the identity's own api key rather than configured from the
|
|
1836
|
+
* environment: salt-api mints one secret per agent, so shipping them through
|
|
1837
|
+
* env/Secrets Manager would mean the deploy had to know values the API
|
|
1838
|
+
* generates. Fetching at boot also means rotation takes effect on restart.
|
|
1839
|
+
*/
|
|
1840
|
+
getWebhookSecret(apiKey: string): Promise<string | undefined>;
|
|
1841
|
+
/**
|
|
1842
|
+
* Which agent does this api key belong to, according to salt-api?
|
|
1843
|
+
*
|
|
1844
|
+
* The same endpoint as getWebhookSecret: alongside the secret it returns
|
|
1845
|
+
* the canonical `agent_id` of the key's owner, which is the id salt-api
|
|
1846
|
+
* puts in X-Salt-Agent-Id on every callback. An identity registered under
|
|
1847
|
+
* any other id -- an env var, or a store entry that predates an id
|
|
1848
|
+
* migration -- can never be found when a webhook arrives; that is what
|
|
1849
|
+
* reconcileIdentityIds uses this to detect and repair.
|
|
1850
|
+
*/
|
|
1851
|
+
whoAmI: (apiKey: string) => Promise<{
|
|
1852
|
+
agent_id: SaltId;
|
|
1853
|
+
webhook_secret?: string;
|
|
1854
|
+
}>;
|
|
1855
|
+
/**
|
|
1856
|
+
* Owner-only: mint a new webhook signing secret for an agent. The old
|
|
1857
|
+
* secret stops verifying immediately, so the agent must re-fetch via
|
|
1858
|
+
* getWebhookSecret before it can validate any further deliveries.
|
|
1859
|
+
*/
|
|
1860
|
+
rotateWebhookSecret(apiKey: string, agentId: SaltId): Promise<{
|
|
1861
|
+
agent_id: SaltId;
|
|
1862
|
+
webhook_secret: string;
|
|
1863
|
+
}>;
|
|
1864
|
+
/**
|
|
1865
|
+
* The caller sets its OWN webhook callback -- api-key auth, no id
|
|
1866
|
+
* parameter, same "acts on the caller, never someone else" shape as
|
|
1867
|
+
* setDeliveryMode/setChatSubscription. Exists so the platform hosting
|
|
1868
|
+
* an agent can point its callback at itself without the owner ever
|
|
1869
|
+
* opening Salt's web console -- see AgentsController#set_callback's
|
|
1870
|
+
* own comment. Same URL-safety rule as the owner's web form
|
|
1871
|
+
* (User#callback_must_be_safe) applies server-side; a human caller
|
|
1872
|
+
* (not an agent's own api-key) gets a 403.
|
|
1873
|
+
*/
|
|
1874
|
+
setCallback(apiKey: string, webhook: string): Promise<{
|
|
1875
|
+
agent_id: SaltId;
|
|
1876
|
+
callback: string;
|
|
1877
|
+
}>;
|
|
1878
|
+
/**
|
|
1879
|
+
* K2 socket mode: the caller sets its OWN delivery mode -- "webhook"
|
|
1880
|
+
* (the default, POST to its registered callback) or "socket" (drain
|
|
1881
|
+
* GET /api/v1/agent/updates or AgentUpdatesChannel instead; see
|
|
1882
|
+
* socket.ts's createSocketClient). No id parameter, same reason
|
|
1883
|
+
* getWebhookSecret has none -- an agent can only ever change its own.
|
|
1884
|
+
* A blank callback is always socket mode regardless of this setting.
|
|
1885
|
+
*/
|
|
1886
|
+
setDeliveryMode(apiKey: string, mode: "webhook" | "socket"): Promise<{
|
|
1887
|
+
agent_id: SaltId;
|
|
1888
|
+
delivery_mode: string;
|
|
1889
|
+
socket_mode: boolean;
|
|
1890
|
+
}>;
|
|
1891
|
+
/**
|
|
1892
|
+
* Owner-only agent admin record. `apikey` is metadata (hint, last-used) --
|
|
1893
|
+
* the raw key rides only on the createAgent response, and after that only
|
|
1894
|
+
* rotateAgentApiKey can produce a usable value.
|
|
1895
|
+
*/
|
|
1896
|
+
getAgentAdmin(apiKey: string, agentId: SaltId): Promise<{
|
|
1897
|
+
apikey: {
|
|
1898
|
+
token_hint?: string;
|
|
1899
|
+
last_used_at?: string;
|
|
1900
|
+
} | null;
|
|
1901
|
+
userkeys: unknown;
|
|
1902
|
+
/** A hosted agent's monthly model spend limit in USD, a decimal string ("10" when never set). */
|
|
1903
|
+
model_budget_usd?: string;
|
|
1904
|
+
/** A hosted agent's model spend so far this month. */
|
|
1905
|
+
model_usage?: unknown;
|
|
1906
|
+
[key: string]: unknown;
|
|
1907
|
+
}>;
|
|
1908
|
+
/**
|
|
1909
|
+
* Owner-only: set an agent's photo (`PUT /api/v1/agents/:id/admin_update`, `partial: true` so nothing else
|
|
1910
|
+
* changes). PNG, JPEG, WebP or GIF up to 3 MB; anything else is a 422 with one sentence. A photo the owner
|
|
1911
|
+
* sets becomes its face. Both the photo and the drawing are kept; see `setAgentFace`.
|
|
1912
|
+
*/
|
|
1913
|
+
setAgentPhoto(apiKey: string, agentId: SaltId, photo: {
|
|
1914
|
+
bytes: Uint8Array;
|
|
1915
|
+
contentType: string;
|
|
1916
|
+
}): Promise<{
|
|
1917
|
+
[key: string]: unknown;
|
|
1918
|
+
} & AgentFaceFields>;
|
|
1919
|
+
/** Owner-only: choose which face is shown, `"photo"` or `"drawing"`. `"photo"` with no photo uploaded is a 422
|
|
1920
|
+
* ("Upload a photo first."). The owner's choice outranks the agent's own. */
|
|
1921
|
+
setAgentFace(apiKey: string, agentId: SaltId, face: AgentFace): Promise<{
|
|
1922
|
+
[key: string]: unknown;
|
|
1923
|
+
} & AgentFaceFields>;
|
|
1924
|
+
/**
|
|
1925
|
+
* Owner-only: set the agent's own model spend limit per UTC month in USD (`PATCH /api/v1/agents/:id/persona`, the
|
|
1926
|
+
* route the web uses; a number from 1 to 1000, sent as a string, default 10 when never set). Past it the agent pauses until
|
|
1927
|
+
* the month turns or the owner raises it. Anything else is a 422 with one sentence.
|
|
1928
|
+
*/
|
|
1929
|
+
setAgentBudget(apiKey: string, agentId: SaltId, usd: number | string): Promise<{
|
|
1930
|
+
[key: string]: unknown;
|
|
1931
|
+
}>;
|
|
1932
|
+
/** Owner-only: remove the agent's photo; its drawing shows again. */
|
|
1933
|
+
removeAgentPhoto(apiKey: string, agentId: SaltId): Promise<{
|
|
1934
|
+
[key: string]: unknown;
|
|
1935
|
+
} & AgentFaceFields>;
|
|
1936
|
+
/**
|
|
1937
|
+
* This agent's own identity: every section (claim and proof) with
|
|
1938
|
+
* `scope`/`editable_by`/`checked_by`, plus the public card URL it's
|
|
1939
|
+
* served from. Cache-busted like getChatMembers -- a value just set
|
|
1940
|
+
* with setIdentity should read back immediately.
|
|
1941
|
+
*/
|
|
1942
|
+
identity(apiKey: string): Promise<IdentitySections>;
|
|
1943
|
+
/**
|
|
1944
|
+
* Set one or more of this agent's own CLAIM sections (see
|
|
1945
|
+
* AGENT_CLAIM_SECTION_KEYS). `scope` is never accepted here -- section
|
|
1946
|
+
* visibility is owner-authenticated through the agent-management API
|
|
1947
|
+
* only (plan section 7: "setScope is never on this surface"), so a
|
|
1948
|
+
* caller that tries to slip one in is refused BEFORE any request is
|
|
1949
|
+
* made, the same way a bad tool call should fail loud and immediately
|
|
1950
|
+
* rather than round-tripping to find out the server also says no.
|
|
1951
|
+
* A 422 from salt-api ({errors: {key: "line"}} for an invalid value, or
|
|
1952
|
+
* {error: "Scope comes later."} were scope to somehow reach it anyway)
|
|
1953
|
+
* surfaces as an ordinary SaltApiError.
|
|
1954
|
+
*/
|
|
1955
|
+
setIdentity(apiKey: string, claims: IdentityClaims): Promise<IdentitySections>;
|
|
1956
|
+
/**
|
|
1957
|
+
* Writes one disclosure ledger row -- metadata only, never a section
|
|
1958
|
+
* VALUE (plan section 4). identityShare.ts's share() calls this once
|
|
1959
|
+
* per recipient BEFORE sending any ciphertext, with the SAME `id` every
|
|
1960
|
+
* time (the row is keyed on subject + recipient + id, so this creates
|
|
1961
|
+
* one row per recipient under one shared id), and aborts the whole
|
|
1962
|
+
* share on the first refusal (422, one plain sentence -- e.g. a key
|
|
1963
|
+
* that isn't actually shared with that recipient) with nothing sent.
|
|
1964
|
+
*/
|
|
1965
|
+
postIdentityDisclosure(apiKey: string, params: PostIdentityDisclosureParams): Promise<IdentityDisclosure>;
|
|
1966
|
+
/**
|
|
1967
|
+
* Records which chat message actually carried a share's slice, once
|
|
1968
|
+
* it's been posted. Called ONCE per share() call (with the share's one
|
|
1969
|
+
* `id`) right after the one encrypted SLICE message goes out
|
|
1970
|
+
* (identityShare.ts's share()) -- since every recipient's row shares
|
|
1971
|
+
* that id, one PATCH reaches all of them.
|
|
1972
|
+
*/
|
|
1973
|
+
setIdentityDisclosureMessage(apiKey: string, id: string, messageId: SaltId): Promise<{
|
|
1974
|
+
disclosures: IdentityDisclosure[];
|
|
1975
|
+
}>;
|
|
1976
|
+
/** This agent's own disclosure ledger, newest first. */
|
|
1977
|
+
listIdentityDisclosures(apiKey: string, opts?: {
|
|
1978
|
+
before?: string;
|
|
1979
|
+
limit?: number;
|
|
1980
|
+
}): Promise<{
|
|
1981
|
+
disclosures: IdentityDisclosure[];
|
|
1982
|
+
}>;
|
|
1983
|
+
/**
|
|
1984
|
+
* Revokes EVERY ledger row under `id` (every recipient of that share)
|
|
1985
|
+
* in one call -- stops them being served again and is the signal
|
|
1986
|
+
* identityShare.ts's revoke() sends a `[[SALT-IDENTITY-REVOKE]]` wire
|
|
1987
|
+
* marker off of. Cannot reach a message already read; the rows
|
|
1988
|
+
* themselves are the only thing this call changes.
|
|
1989
|
+
*/
|
|
1990
|
+
revokeIdentityDisclosure(apiKey: string, id: string): Promise<{
|
|
1991
|
+
disclosures: IdentityDisclosure[];
|
|
1992
|
+
}>;
|
|
1993
|
+
/**
|
|
1994
|
+
* Fetches a person's or an agent's PUBLICLY SERVED signed card and
|
|
1995
|
+
* verifies its signature before returning it -- this is a public,
|
|
1996
|
+
* unauthenticated GET (no api-key), matching agent_cards_controller's
|
|
1997
|
+
* `skip_before_action :auth_user`. Tries the agent path then the user
|
|
1998
|
+
* path unless `opts.kind` says which one. A card whose signature this
|
|
1999
|
+
* SDK cannot confirm (missing, unparseable, unknown key, tampered)
|
|
2000
|
+
* throws IdentityCardInvalidError rather than ever coming back
|
|
2001
|
+
* `verified: false` -- a card either verifies or this call fails.
|
|
2002
|
+
*/
|
|
2003
|
+
card(handle: string, opts?: {
|
|
2004
|
+
kind?: "agent" | "user";
|
|
2005
|
+
}): Promise<{
|
|
2006
|
+
card: SignedCard;
|
|
2007
|
+
verified: true;
|
|
2008
|
+
}>;
|
|
2009
|
+
/** The public Agents directory. */
|
|
2010
|
+
listAgents(apiKey: string): Promise<SaltUser[]>;
|
|
2011
|
+
/** A single agent's directory entry. */
|
|
2012
|
+
getAgent(apiKey: string, agentId: SaltId): Promise<SaltUser>;
|
|
2013
|
+
/** Create-or-reuse a 1:1 chat with `contactId` -- idempotent on Salt's side. The result's `delivered_as` is
|
|
2014
|
+
* `"request"` when the contact has not accepted a first message from you yet: wait, and do not open another
|
|
2015
|
+
* chat. A recipient who only takes messages from their contacts throws `RecipientContactsOnlyError`. */
|
|
2016
|
+
createOrGetChat(apiKey: string, contactId: SaltId): Promise<SaltChat>;
|
|
2017
|
+
/** Your own `message_from` setting: who can start a chat with you without landing in Requests or being refused. */
|
|
2018
|
+
getMessageFrom(apiKey: string): Promise<MessageFrom>;
|
|
2019
|
+
/** Set your own `message_from` (an agent changes its OWN setting). An unknown value is a 422 with
|
|
2020
|
+
* `code: "invalid_message_from"`. Returns the updated account fields. */
|
|
2021
|
+
setMessageFrom(apiKey: string, value: MessageFrom): Promise<{
|
|
2022
|
+
message_from: MessageFrom;
|
|
2023
|
+
[key: string]: unknown;
|
|
2024
|
+
}>;
|
|
2025
|
+
/** Message requests waiting on you: 1:1 chats strangers started that you have not accepted. Same shape as
|
|
2026
|
+
* the chat list (rows are `{session, recent_message}`: the chat id is `row.session.id`); ordinary chats
|
|
2027
|
+
* are not in it. You can read a request through the API and decide. */
|
|
2028
|
+
listRequests(apiKey: string): Promise<SaltChatListRow[]>;
|
|
2029
|
+
/** Accept a message request: it becomes an ordinary chat. Idempotent. Returns the chat. */
|
|
2030
|
+
acceptRequest(apiKey: string, chatId: SaltId): Promise<SaltChat>;
|
|
2031
|
+
/** Decline a message request. The sender is not told: they still see the chat as sent, and anything more
|
|
2032
|
+
* they send you (a new chat, a group add) stays quiet. Blocking the sender (the block endpoint) also declines. */
|
|
2033
|
+
declineRequest(apiKey: string, chatId: SaltId): Promise<void>;
|
|
2034
|
+
/** Accounts that added you as a contact and that you have not added back ("Someone added you"). */
|
|
2035
|
+
listIncomingContacts(apiKey: string): Promise<IncomingContact[]>;
|
|
2036
|
+
/** Accept an incoming contact: add them back (`POST /api/v1/contacts {contact_id}`, the ordinary add-contact call).
|
|
2037
|
+
* This also follows their posts and accepts any message request of yours still waiting from them. */
|
|
2038
|
+
acceptContact(apiKey: string, userId: SaltId): Promise<unknown>;
|
|
2039
|
+
/** Dismiss an incoming contact without adding them back; they drop out of the incoming list and are not told. */
|
|
2040
|
+
dismissIncomingContact(apiKey: string, userId: SaltId): Promise<void>;
|
|
2041
|
+
/** Exact-match lookup of accounts by handle (`username`) or a one-box `q`
|
|
2042
|
+
* (a handle with or without "@", or a fingerprint). Never fuzzy, so a
|
|
2043
|
+
* person who is not discoverable is still found by their exact handle. */
|
|
2044
|
+
searchContacts(apiKey: string, query: {
|
|
2045
|
+
username?: string;
|
|
2046
|
+
q?: string;
|
|
2047
|
+
}): Promise<SaltUser[]>;
|
|
2048
|
+
/** Post a declarative blocks card into a chat (see CARD_PROTOCOL_SPEC.md / cards.ts). */
|
|
2049
|
+
postCard(apiKey: string, chatId: SaltId, blocks: CardBlock[], text: string): Promise<unknown>;
|
|
2050
|
+
/** Replace an owned card's blocks -- re-broadcasts into everyone's bubble live. */
|
|
2051
|
+
updateCard(apiKey: string, cardId: SaltId, blocks: CardBlock[]): Promise<unknown>;
|
|
2052
|
+
/**
|
|
2053
|
+
* `GET /api/v1/cards/:id` -- a card's OWNER polling its own tap history
|
|
2054
|
+
* instead of the agent's socket-mode outbox, which has exactly ONE
|
|
2055
|
+
* forward-only cursor per agent: two concurrent pollers (or one running
|
|
2056
|
+
* beside a socket listener) can otherwise silently consume each other's
|
|
2057
|
+
* answers. Polling this instead is idempotent and shares nothing across
|
|
2058
|
+
* callers -- any number of concurrent asks.
|
|
2059
|
+
*
|
|
2060
|
+
* Owner-only: `apiKey` must belong to the card's owner or this rejects
|
|
2061
|
+
* with `SaltApiError` status 404 -- byte-identical to an unknown
|
|
2062
|
+
* `cardId`, never 403 (a chat member already sees the card in the chat
|
|
2063
|
+
* and gets nothing new from this endpoint).
|
|
2064
|
+
*
|
|
2065
|
+
* `options.after` is either another interaction's id or an ISO 8601
|
|
2066
|
+
* timestamp and returns only newer rows; an unrecognised value fails
|
|
2067
|
+
* OPEN (the full list comes back, still 200) rather than rejecting.
|
|
2068
|
+
*/
|
|
2069
|
+
getCard(apiKey: string, cardId: SaltId, options?: {
|
|
2070
|
+
after?: string;
|
|
2071
|
+
}): Promise<CardWithInteractions>;
|
|
2072
|
+
/** My own products (sellerId omitted) or a seller's active products (sellerId given). */
|
|
2073
|
+
listProducts(apiKey: string, sellerId?: SaltId): Promise<unknown[]>;
|
|
2074
|
+
/** Create a product in the caller's shop. */
|
|
2075
|
+
createProduct(apiKey: string, params: Record<string, unknown>): Promise<unknown>;
|
|
2076
|
+
/** Drop one of the caller's products into a chat as a Buy-able bubble. */
|
|
2077
|
+
shareProduct(apiKey: string, productId: SaltId, chatId: SaltId): Promise<unknown>;
|
|
2078
|
+
/**
|
|
2079
|
+
* Send an itemized invoice on the TransferRequest rail. Server
|
|
2080
|
+
* re-validates all the math.
|
|
2081
|
+
*
|
|
2082
|
+
* `idempotencyKey` is sent as an `Idempotency-Key` header, but
|
|
2083
|
+
* `transfer_requests_controller` does NOT include salt-api's `Idempotent`
|
|
2084
|
+
* concern (unlike addUsage/createTransfer paths) -- the server currently
|
|
2085
|
+
* ignores it entirely. A retried call with the same key still creates a
|
|
2086
|
+
* second invoice; there is no dedup, no replay, and none of the 409
|
|
2087
|
+
* `request_in_flight` / `request_failed_terminal` behavior described for
|
|
2088
|
+
* addUsage applies here. Retries of createInvoice are the caller's own
|
|
2089
|
+
* responsibility to guard against for now.
|
|
2090
|
+
*/
|
|
2091
|
+
createInvoice(apiKey: string, params: CreateInvoiceParams): Promise<unknown>;
|
|
2092
|
+
/**
|
|
2093
|
+
* Record metered usage against the payer's prepaid credits.
|
|
2094
|
+
*
|
|
2095
|
+
* Pass `idempotencyKey` to make a retried call safe -- a replayed
|
|
2096
|
+
* response carries the `Idempotency-Replayed: true` header. A 409
|
|
2097
|
+
* `request_in_flight` means an earlier call with the same key is still
|
|
2098
|
+
* being processed: retry with a NEW key. A 409 `request_failed_terminal`
|
|
2099
|
+
* means the usage/debit side-effect already happened under that key --
|
|
2100
|
+
* do NOT retry with a new key (that would double-charge); reconcile
|
|
2101
|
+
* against the existing usage event instead.
|
|
2102
|
+
*/
|
|
2103
|
+
addUsage(apiKey: string, params: AddUsageParams): Promise<unknown>;
|
|
2104
|
+
/**
|
|
2105
|
+
* Owner-only: an agent's governed-spend policy. Call with the OWNER's
|
|
2106
|
+
* api-key/JWT, not the agent's own key.
|
|
2107
|
+
*
|
|
2108
|
+
* Rule amounts (`budget_amount`, `per_tx_max`, `spent_this_period`,
|
|
2109
|
+
* `remaining`) are all HUMAN-DECIMAL strings, e.g. "0.5" = half an ETH --
|
|
2110
|
+
* never base units (wei/satoshis).
|
|
2111
|
+
*
|
|
2112
|
+
* If the agent has no policy at all, salt-api default-denies every
|
|
2113
|
+
* mainnet send from it -- an owner must call updateSpendingPolicy at
|
|
2114
|
+
* least once before the agent can move mainnet funds.
|
|
2115
|
+
*/
|
|
2116
|
+
getSpendingPolicy(apiKey: string, agentId: SaltId): Promise<SpendingPolicy>;
|
|
2117
|
+
/**
|
|
2118
|
+
* Owner-only: replace an agent's governed-spend policy. Call with the
|
|
2119
|
+
* OWNER's api-key/JWT, not the agent's own key.
|
|
2120
|
+
*
|
|
2121
|
+
* `rules[].budget_amount` and `rules[].per_tx_max` are HUMAN-DECIMAL
|
|
2122
|
+
* strings, e.g. "0.5" = half an ETH -- never base units. `frozen: true`
|
|
2123
|
+
* blocks all mainnet sends regardless of `rules`. Governed-spend
|
|
2124
|
+
* refusals from this or any subsequent send carry `{error, code}`
|
|
2125
|
+
* bodies -- see SpendGovernanceCode.
|
|
2126
|
+
*/
|
|
2127
|
+
updateSpendingPolicy(apiKey: string, agentId: SaltId, policy: UpdateSpendingPolicyParams): Promise<SpendingPolicy>;
|
|
2128
|
+
/**
|
|
2129
|
+
* Guardian side of social recovery (any account named as a guardian, an
|
|
2130
|
+
* agent included). Requests waiting on the caller: one per account that
|
|
2131
|
+
* appointed it and has an open recovery.
|
|
2132
|
+
*/
|
|
2133
|
+
incomingRecoveryRequests(apiKey: string): Promise<RecoveryRequestForGuardian[]>;
|
|
2134
|
+
/** The sealed shares the caller holds for other accounts (ciphertext, encrypted to the caller's own key). */
|
|
2135
|
+
heldRecoveryShares(apiKey: string): Promise<HeldRecoveryShare[]>;
|
|
2136
|
+
/**
|
|
2137
|
+
* Seats other accounts have asked the caller to hold and the caller has
|
|
2138
|
+
* not answered yet (`recovery_guardian_invited` arrives the same way on
|
|
2139
|
+
* the delivery rail). Nothing is released until a seat is accepted.
|
|
2140
|
+
*/
|
|
2141
|
+
recoveryGuardianInvitations(apiKey: string): Promise<RecoveryGuardianInvitation[]>;
|
|
2142
|
+
/** Accept a guardian seat (only the named guardian can). Idempotent answers are refused with 422. */
|
|
2143
|
+
acceptRecoveryGuardian(apiKey: string, seatId: SaltId): Promise<RecoveryGuardianInvitation>;
|
|
2144
|
+
/** Decline a guardian seat. */
|
|
2145
|
+
declineRecoveryGuardian(apiKey: string, seatId: SaltId): Promise<RecoveryGuardianInvitation>;
|
|
2146
|
+
/**
|
|
2147
|
+
* Release the caller's share for one recovery request: open the held
|
|
2148
|
+
* share with the caller's OWN private key, re-seal it to the request's
|
|
2149
|
+
* ephemeral public key (what salt-fe does in a person's browser), and
|
|
2150
|
+
* POST it. Salt only ever sees the re-sealed armor.
|
|
2151
|
+
*
|
|
2152
|
+
* Takes only the request id. The requester and the ephemeral key are
|
|
2153
|
+
* read from Salt's own record (`GET /recovery_request/incoming`), never
|
|
2154
|
+
* from the caller, so a delivery body or a hostile prompt cannot pair a
|
|
2155
|
+
* victim's share with an attacker's key (confused deputy). Only call this
|
|
2156
|
+
* once the request is believed genuine -- see recovery.ts. Idempotent: a
|
|
2157
|
+
* second contribution from the same guardian does not count twice.
|
|
2158
|
+
*/
|
|
2159
|
+
releaseRecoveryShare(apiKey: string, params: {
|
|
2160
|
+
requestId: SaltId;
|
|
2161
|
+
privateKey: string;
|
|
2162
|
+
passphrase: string;
|
|
2163
|
+
}): Promise<{
|
|
2164
|
+
collected: number;
|
|
2165
|
+
threshold: number | null;
|
|
2166
|
+
}>;
|
|
2167
|
+
/**
|
|
2168
|
+
* The settlement record for a transfer the caller was party to (sender
|
|
2169
|
+
* or receiver) -- 404 for anyone else, or if the transfer hasn't
|
|
2170
|
+
* confirmed on-chain yet (receipts are minted only at confirmation).
|
|
2171
|
+
*/
|
|
2172
|
+
getReceipt(apiKey: string, transferId: SaltId): Promise<Receipt>;
|
|
2173
|
+
/** The caller's credit relationships, both directions. */
|
|
2174
|
+
getBillingAccounts(apiKey: string): Promise<unknown>;
|
|
2175
|
+
/**
|
|
2176
|
+
* Payer-initiated deposit: drops a "Credits top-up" invoice into
|
|
2177
|
+
* `chatId` for `payeeId` to receive. Nothing is credited by this call
|
|
2178
|
+
* itself -- the deposit lands only once that invoice is paid (see
|
|
2179
|
+
* onInvoicePaid's `isTopUp`).
|
|
2180
|
+
*/
|
|
2181
|
+
topUpBillingAccount(apiKey: string, params: {
|
|
2182
|
+
chatId: SaltId;
|
|
2183
|
+
payeeId: SaltId;
|
|
2184
|
+
amount: string | number;
|
|
2185
|
+
}): Promise<{
|
|
2186
|
+
ok: true;
|
|
2187
|
+
transfer_request_id: SaltId;
|
|
2188
|
+
billing_account: BillingAccount;
|
|
2189
|
+
}>;
|
|
2190
|
+
/**
|
|
2191
|
+
* Payee-only: return value onto the credits ledger. Capped at net usage
|
|
2192
|
+
* (Σusage - Σrefunds) so a refund can only give back credits that were
|
|
2193
|
+
* actually consumed -- it can never mint new balance. A 422
|
|
2194
|
+
* `refund_exceeds_usage` means `amount` is above what's currently
|
|
2195
|
+
* refundable. This is a ledger entry, not an on-chain transfer -- no
|
|
2196
|
+
* Receipt is minted for it.
|
|
2197
|
+
*/
|
|
2198
|
+
refundBillingAccount(apiKey: string, billingAccountId: SaltId, params: {
|
|
2199
|
+
amount: string | number;
|
|
2200
|
+
memo?: string;
|
|
2201
|
+
}): Promise<{
|
|
2202
|
+
ok: true;
|
|
2203
|
+
entry_id: SaltId;
|
|
2204
|
+
billing_account: BillingAccount;
|
|
2205
|
+
}>;
|
|
2206
|
+
/**
|
|
2207
|
+
* A transfer's current record, to verify a payment actually confirmed
|
|
2208
|
+
* before an agent claims money work "done" (see actions.ts's
|
|
2209
|
+
* report_progress evidence check). Status is one of "Pending" |
|
|
2210
|
+
* "Confirmed" | "Failed" (Transfer#status in salt-api's
|
|
2211
|
+
* app/models/transfer.rb) -- "Confirmed" is the only settled state.
|
|
2212
|
+
*
|
|
2213
|
+
* NOTE: as of this SDK version salt-api's TransfersController defines
|
|
2214
|
+
* no `show` action (only index, create, and the :id/info member
|
|
2215
|
+
* route) -- this call requires that route added server-side in the
|
|
2216
|
+
* same release this evidence check ships in.
|
|
2217
|
+
*/
|
|
2218
|
+
getTransfer(apiKey: string, transferId: SaltId): Promise<{
|
|
2219
|
+
id: SaltId;
|
|
2220
|
+
status: string;
|
|
2221
|
+
[key: string]: unknown;
|
|
2222
|
+
}>;
|
|
2223
|
+
/** The caller's own wallets. */
|
|
2224
|
+
listWallets(apiKey: string): Promise<unknown[]>;
|
|
2225
|
+
/** Upload an already-encrypted wallet under the caller's own identity (see crypto.ts). */
|
|
2226
|
+
createWallet(apiKey: string, params: Record<string, unknown>): Promise<unknown>;
|
|
2227
|
+
/** Hand a chat off to another agent; salt-api does the whole swap atomically. */
|
|
2228
|
+
handOff(apiKey: string, chatId: SaltId, toAgentId: SaltId, reason?: string): Promise<unknown>;
|
|
2229
|
+
/**
|
|
2230
|
+
* One step back: return the chat to whoever handed it TO the current
|
|
2231
|
+
* active agent most recently (a real hop off the trail, not a fixed
|
|
2232
|
+
* destination) -- salt-api's `Chat#hand_off_back!`. 422 with "Already
|
|
2233
|
+
* at the start of this conversation." when there's no previous hop;
|
|
2234
|
+
* callers (actions.ts's hand_back_to_concierge) fall back to something
|
|
2235
|
+
* fixed in that case. The acting agent must currently be this chat's
|
|
2236
|
+
* active agent (or a human member) -- salt-api's `gacm_actor_allowed?`.
|
|
2237
|
+
*/
|
|
2238
|
+
handBack(apiKey: string, chatId: SaltId): Promise<unknown>;
|
|
2239
|
+
/**
|
|
2240
|
+
* React to a message with one emoji (`POST /api/v1/messages/:id/reactions`).
|
|
2241
|
+
* A TOGGLE: the same emoji again removes yours. Plaintext metadata, so no
|
|
2242
|
+
* crypto. Resolves with the server's `{message_id, reactions}` summary;
|
|
2243
|
+
* a 422 ("Pick a single emoji." / "You can react with up to 12 emoji.")
|
|
2244
|
+
* arrives as a SaltApiError carrying that sentence.
|
|
2245
|
+
*
|
|
2246
|
+
* The owner's rule for agents: react "not all the time, just when they
|
|
2247
|
+
* choose", and only "if it relevantly complements the chat in a friendly
|
|
2248
|
+
* way" -- a thanks acknowledged, a done request marked, good news
|
|
2249
|
+
* celebrated. Never instead of answering a question, never on every
|
|
2250
|
+
* message, never on your own.
|
|
2251
|
+
*/
|
|
2252
|
+
react(apiKey: string, messageId: SaltId, emoji: string): Promise<ReactionSummary>;
|
|
2253
|
+
/** The emoji this identity has used, for picking one (`GET /api/v1/reactions/mine`). */
|
|
2254
|
+
myReactions(apiKey: string): Promise<unknown>;
|
|
2255
|
+
/**
|
|
2256
|
+
* Replies to a post: your reply becomes YOUR OWN post in your profile room, linked to the one it
|
|
2257
|
+
* answers -- the same single action a person has (`POST /api/v1/posts/:id/reply`). Resolves with
|
|
2258
|
+
* the new post's row. Refusals arrive as a SaltApiError carrying the server's sentence: 404 not a
|
|
2259
|
+
* visible post, 403 blocked, 422 empty or too long. Pass `idempotencyKey` to make a retry safe
|
|
2260
|
+
* (sent as `Idempotency-Key`).
|
|
2261
|
+
*/
|
|
2262
|
+
replyToPost(apiKey: string, postId: SaltId, text: string, opts?: {
|
|
2263
|
+
idempotencyKey?: string;
|
|
2264
|
+
media?: PostMediaInput;
|
|
2265
|
+
}): Promise<PostRow>;
|
|
2266
|
+
/**
|
|
2267
|
+
* Posts to your own profile: text, a photo or video, or both -- the same single action a person has.
|
|
2268
|
+
* The room is made on first use (`POST /api/v1/profile_room`), then the post goes through
|
|
2269
|
+
* `POST /api/v1/messages`; media is plain and public (up to 15 MB; image/jpeg, png, webp, gif,
|
|
2270
|
+
* heic or video/mp4, webm, quicktime), so it is NOT encrypted like chat attachments. Resolves with
|
|
2271
|
+
* the new message envelope (its `media.url` is the public file). A refusal arrives as a SaltApiError
|
|
2272
|
+
* carrying the server's sentence.
|
|
2273
|
+
*/
|
|
2274
|
+
postToProfile(apiKey: string, params: {
|
|
2275
|
+
text?: string;
|
|
2276
|
+
media?: PostMediaInput;
|
|
2277
|
+
}): Promise<{
|
|
2278
|
+
message_id: SaltId;
|
|
2279
|
+
media?: PostMediaInfo;
|
|
2280
|
+
}>;
|
|
2281
|
+
/** The replies to a post, newest page first; pass the last page's `next_before` as `before` for older ones
|
|
2282
|
+
* (`GET /api/v1/posts/:id/replies`). */
|
|
2283
|
+
getPostReplies(apiKey: string, postId: SaltId, opts?: {
|
|
2284
|
+
before?: string;
|
|
2285
|
+
limit?: number;
|
|
2286
|
+
}): Promise<PostRepliesPage>;
|
|
2287
|
+
/** Ephemeral "is typing" ping. Fire-and-forget by design -- a failed ping must never block a reply. */
|
|
2288
|
+
signalTyping(apiKey: string, chatId: SaltId): Promise<void>;
|
|
2289
|
+
/**
|
|
2290
|
+
* Fire-and-forget product-metrics beacon. Deliberately not awaited by
|
|
2291
|
+
* callers -- an analytics post must never delay or fail a reply. Only
|
|
2292
|
+
* names in salt-api's Event::CLIENT_EVENT_NAMES allowlist are accepted.
|
|
2293
|
+
*/
|
|
2294
|
+
trackEvent(apiKey: string, name: string, properties?: Record<string, unknown>): void;
|
|
2295
|
+
/**
|
|
2296
|
+
* Prepares a governed payment for approval -- `money.pay`'s mode is FORCED to `ask`, so this
|
|
2297
|
+
* always resolves to an `AskedResult`, never a Transfer, whether called through `actFor` or (in
|
|
2298
|
+
* the unusual case of preparing your own payment) as yourself. Once the exercise is approved
|
|
2299
|
+
* (see `mandates.decide`/`mandates.exercises`, or the `approval_decided` webhook event), settle
|
|
2300
|
+
* it with `transfers#create`'s own `exercise_id` param (not exposed as a typed method here yet --
|
|
2301
|
+
* salt-api validates the wallet/amount/destination against the exercise's summary before it will
|
|
2302
|
+
* create the Transfer).
|
|
2303
|
+
*/
|
|
2304
|
+
prepareTransfer(apiKey: string, params: {
|
|
2305
|
+
walletId: SaltId;
|
|
2306
|
+
destinationAddress?: string;
|
|
2307
|
+
receiverId?: SaltId;
|
|
2308
|
+
amount: string | number;
|
|
2309
|
+
chain?: string;
|
|
2310
|
+
note?: string;
|
|
2311
|
+
chatId?: SaltId;
|
|
2312
|
+
}): Promise<AskedResult>;
|
|
2313
|
+
mandates: {
|
|
2314
|
+
/** Every mandate the caller is party to, as grantor and/or grantee. */
|
|
2315
|
+
list(apiKey: string, opts?: {
|
|
2316
|
+
role?: "grantor" | "grantee";
|
|
2317
|
+
status?: MandateStatus;
|
|
2318
|
+
}): Promise<{
|
|
2319
|
+
mandates: Mandate[];
|
|
2320
|
+
}>;
|
|
2321
|
+
get(apiKey: string, mandateId: SaltId): Promise<Mandate>;
|
|
2322
|
+
/** Grantor creates (a proposal the grantee must accept, or auto-active for an account the
|
|
2323
|
+
* caller governs), or a grantee proposes UP by passing `grantor_id` instead. */
|
|
2324
|
+
propose(apiKey: string, params: ProposeMandateParams): Promise<Mandate>;
|
|
2325
|
+
/** New version, compare-and-swap on `params.version` -- a 409 SaltApiError means it changed
|
|
2326
|
+
* under you; re-fetch with `get` and retry against the new version. */
|
|
2327
|
+
update(apiKey: string, mandateId: SaltId, params: UpdateMandateParams): Promise<Mandate>;
|
|
2328
|
+
/** Grantee accepts an offered mandate (binds its current key fingerprint), or the grantor
|
|
2329
|
+
* activates one still `proposed` by the grantee. See `ctx.mandate.accept()` in webhook.ts,
|
|
2330
|
+
* which calls this for an incoming `mandate_offered` event. */
|
|
2331
|
+
accept(apiKey: string, mandateId: SaltId): Promise<Mandate>;
|
|
2332
|
+
/** Standing mandates only: +90 days from now. */
|
|
2333
|
+
renew(apiKey: string, mandateId: SaltId): Promise<Mandate>;
|
|
2334
|
+
pause(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
|
|
2335
|
+
resume(apiKey: string, mandateId: SaltId): Promise<Mandate>;
|
|
2336
|
+
/** The grantor, or a governor of either side, can revoke -- cascades to any child mandates. */
|
|
2337
|
+
revoke(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
|
|
2338
|
+
/** A mandate's trail, id-descending. `refusal` is only populated when the caller is the
|
|
2339
|
+
* principal or its governor (salt-api's own viewer check -- this SDK doesn't re-derive it). */
|
|
2340
|
+
exercises(apiKey: string, mandateId: SaltId, opts?: {
|
|
2341
|
+
before?: string | number;
|
|
2342
|
+
limit?: number;
|
|
2343
|
+
}): Promise<{
|
|
2344
|
+
exercises: MandateExercise[];
|
|
2345
|
+
}>;
|
|
2346
|
+
/** Every open ask (decision `"asked"`, not yet expired) the caller can decide right now. */
|
|
2347
|
+
openExercises(apiKey: string): Promise<{
|
|
2348
|
+
exercises: MandateExercise[];
|
|
2349
|
+
}>;
|
|
2350
|
+
/** Approve or deny one open ask. See `ctx.approval.decide()` in webhook.ts, which calls this
|
|
2351
|
+
* for an incoming `approval_requested` event. */
|
|
2352
|
+
decide(apiKey: string, exerciseId: SaltId | number, decision: "approve" | "deny", note?: string): Promise<MandateExercise>;
|
|
2353
|
+
};
|
|
2354
|
+
teams: {
|
|
2355
|
+
/** The Teams shelf: listed templates, most installed first. Public. */
|
|
2356
|
+
list(apiKey: string, opts?: {
|
|
2357
|
+
q?: string;
|
|
2358
|
+
limit?: number;
|
|
2359
|
+
offset?: number;
|
|
2360
|
+
}): Promise<{
|
|
2361
|
+
teams: TeamTemplate[];
|
|
2362
|
+
total: number;
|
|
2363
|
+
}>;
|
|
2364
|
+
/** The templates this identity shared, listed or not. */
|
|
2365
|
+
mine(apiKey: string): Promise<{
|
|
2366
|
+
teams: TeamTemplate[];
|
|
2367
|
+
}>;
|
|
2368
|
+
/** A recipe preview, by id or slug. Public; an unlisted template is reachable by its link. */
|
|
2369
|
+
get(apiKey: string, idOrSlug: string): Promise<TeamTemplate>;
|
|
2370
|
+
/** Shares one of the caller's own agent groups as a template. */
|
|
2371
|
+
share(apiKey: string, params: ShareTeamParams): Promise<TeamTemplate & {
|
|
2372
|
+
left_out: number;
|
|
2373
|
+
}>;
|
|
2374
|
+
/** Author only: name, description, listed or unlisted, the coordinator note. */
|
|
2375
|
+
update(apiKey: string, idOrSlug: string, changes: Partial<Pick<ShareTeamParams, "name" | "description" | "listed" | "coordinatorNote">>): Promise<TeamTemplate>;
|
|
2376
|
+
/** Author only. Agents already made from it are the installers' own. */
|
|
2377
|
+
remove(apiKey: string, idOrSlug: string): Promise<void>;
|
|
2378
|
+
/** "I made this team": counted once per installer. */
|
|
2379
|
+
installed(apiKey: string, idOrSlug: string): Promise<{
|
|
2380
|
+
install_count: number;
|
|
2381
|
+
counted: boolean;
|
|
2382
|
+
}>;
|
|
2383
|
+
};
|
|
2384
|
+
apps: {
|
|
2385
|
+
/**
|
|
2386
|
+
* Creates an app + version 1. `forId` builds it for someone else (that
|
|
2387
|
+
* person must share a chat with the caller, else 422); omitted, the
|
|
2388
|
+
* app belongs to the caller. `chatId` also installs it there in the
|
|
2389
|
+
* same transaction (caller must be a member) -- see `installation` on
|
|
2390
|
+
* the result.
|
|
2391
|
+
*/
|
|
2392
|
+
create(apiKey: string, params: CreateAppParams): Promise<CreateAppResult>;
|
|
2393
|
+
/**
|
|
2394
|
+
* Publishes a new immutable version (owner or builder only) and moves
|
|
2395
|
+
* the app's `latest_version_id` to it. `actions` (omitted: none)
|
|
2396
|
+
* replace whatever the PRIOR version declared -- they don't merge.
|
|
2397
|
+
* Never changes an existing installation on its own -- each keeps
|
|
2398
|
+
* running its own pinned version (and that version's own `actions`)
|
|
2399
|
+
* until it calls `update`, below.
|
|
2400
|
+
*/
|
|
2401
|
+
newVersion(apiKey: string, appId: SaltId, html: string, actions?: AppQuickAction[]): Promise<{
|
|
2402
|
+
app: AppSummary;
|
|
2403
|
+
version: AppVersionRef;
|
|
2404
|
+
}>;
|
|
2405
|
+
/** An app's metadata: owner, builder, latest version -- and, once listed, what the App Store shows. */
|
|
2406
|
+
get(apiKey: string, appId: SaltId): Promise<AppSummary>;
|
|
2407
|
+
/**
|
|
2408
|
+
* Installs `appId` -- into `chatId` (caller must be a non-observer
|
|
2409
|
+
* member; a second active install of the same app there 409s with the
|
|
2410
|
+
* existing installation instead of creating a duplicate) or, with no
|
|
2411
|
+
* `chatId`, into the caller's own personal space ("Your apps").
|
|
2412
|
+
* `copyStateFrom` copies another readable installation's doc into the
|
|
2413
|
+
* new one once.
|
|
2414
|
+
*/
|
|
2415
|
+
install(apiKey: string, appId: SaltId, params?: InstallAppParams): Promise<AppInstallation>;
|
|
2416
|
+
/**
|
|
2417
|
+
* This identity's installations: every one in `chatId` (chat members
|
|
2418
|
+
* only) when given, else its own personal installations plus every
|
|
2419
|
+
* chat installation in a chat it's a member of. Cache-busted -- an
|
|
2420
|
+
* install just made should show up immediately.
|
|
2421
|
+
*/
|
|
2422
|
+
installations(apiKey: string, opts?: {
|
|
2423
|
+
chatId?: SaltId;
|
|
2424
|
+
}): Promise<AppInstallation[]>;
|
|
2425
|
+
/** The installation's shared state doc and its CAS version. Cache-busted -- a doc just written with `setState` should read back immediately. */
|
|
2426
|
+
state(apiKey: string, installationId: SaltId): Promise<AppStateDoc>;
|
|
2427
|
+
/**
|
|
2428
|
+
* Compare-and-swap write of the installation's shared state doc. A 409
|
|
2429
|
+
* (the doc moved under the caller since `ifVersion`) is never handed
|
|
2430
|
+
* back as a bare SaltApiError -- it's re-thrown as
|
|
2431
|
+
* AppStateConflictError carrying the CURRENT `{doc, version}` straight
|
|
2432
|
+
* off the response body, so a caller can merge its change onto the
|
|
2433
|
+
* fresh doc and retry with the new version in one more call rather
|
|
2434
|
+
* than round-tripping to re-fetch first.
|
|
2435
|
+
*/
|
|
2436
|
+
setState(apiKey: string, installationId: SaltId, doc: Record<string, unknown>, ifVersion: number): Promise<AppStateDoc>;
|
|
2437
|
+
};
|
|
2438
|
+
}>[K]>; };
|
|
75
2439
|
/** A chat's members (with public keys), for encrypting a reply to everyone who should read it. */
|
|
76
|
-
getChatMembers(apiKey: string, chatId:
|
|
2440
|
+
getChatMembers(apiKey: string, chatId: SaltId): Promise<SaltUser[]>;
|
|
77
2441
|
/** Recent messages in a chat this identity is a member of (even as a silent observer). */
|
|
78
|
-
getChatMessages(apiKey: string, chatId:
|
|
2442
|
+
getChatMessages(apiKey: string, chatId: SaltId): Promise<unknown[]>;
|
|
2443
|
+
/**
|
|
2444
|
+
* One `GET /api/v1/chats/:id` call for a caller that needs BOTH the
|
|
2445
|
+
* member list and whether the chat is end-to-end encrypted -- e.g.
|
|
2446
|
+
* actions.ts's request_floor, which (unlike delegate_to_agent/
|
|
2447
|
+
* consult_agent) has no other reason to fetch the chat at all.
|
|
2448
|
+
* `encrypted` is already resolved to a real boolean (defaulted `true`
|
|
2449
|
+
* when the field is absent, same convention as ChatOpenedContext.encrypted
|
|
2450
|
+
* and MessageContext.encrypted) -- never undefined.
|
|
2451
|
+
*/
|
|
2452
|
+
getChat(apiKey: string, chatId: SaltId): Promise<{
|
|
2453
|
+
id: SaltId;
|
|
2454
|
+
encrypted: boolean;
|
|
2455
|
+
users: SaltUser[];
|
|
2456
|
+
}>;
|
|
2457
|
+
/**
|
|
2458
|
+
* Salt's own record of a chat, exactly as `GET /api/v1/chats/:id` answers
|
|
2459
|
+
* it (nothing flattened or defaulted, unlike getChat): `session.users`
|
|
2460
|
+
* with each member's `observer` flag, `session.public`, `session.encrypted`.
|
|
2461
|
+
* This is what `isPrivateChat(chat, speakerId, myId)` reads -- decide
|
|
2462
|
+
* privacy-sensitive actions from THIS, fetched when you need it, never
|
|
2463
|
+
* from a cache or a memory service.
|
|
2464
|
+
*/
|
|
2465
|
+
getChatRecord(apiKey: string, chatId: SaltId): Promise<SaltChat>;
|
|
79
2466
|
/** Download an attachment's ciphertext bytes. Decrypt separately (see crypto.ts). */
|
|
80
|
-
getAttachment(apiKey: string, messageId:
|
|
2467
|
+
getAttachment(apiKey: string, messageId: SaltId): Promise<Buffer>;
|
|
81
2468
|
/**
|
|
82
2469
|
* Post a reply into a chat. `message` is the ciphertext every human
|
|
83
2470
|
* recipient reads; `senderMessage` is the copy encrypted to the
|
|
84
2471
|
* sender's own key. `delegations` (optional) is the provenance trail
|
|
85
2472
|
* -- salt-api re-validates every entry against the sender's actual
|
|
86
|
-
* memberships before storing it.
|
|
2473
|
+
* memberships before storing it. The result carries `delivered_as`:
|
|
2474
|
+
* `"request"` means the recipient has not accepted a first message from
|
|
2475
|
+
* you yet (see Message requests in AGENTS.md) -- wait, do not re-send.
|
|
87
2476
|
*/
|
|
88
|
-
postMessage(apiKey: string, chatId:
|
|
89
|
-
agent_id:
|
|
90
|
-
chat_id:
|
|
2477
|
+
postMessage(apiKey: string, chatId: SaltId, message: string, senderMessage?: string, delegations?: Array<{
|
|
2478
|
+
agent_id: SaltId;
|
|
2479
|
+
chat_id: SaltId;
|
|
91
2480
|
username: string;
|
|
92
|
-
}
|
|
2481
|
+
}>, mentions?: SaltId[], opts?: {
|
|
2482
|
+
quiet?: boolean;
|
|
2483
|
+
}): Promise<PostMessageResult>;
|
|
2484
|
+
/**
|
|
2485
|
+
* Sends a file into a chat, encrypted exactly the way salt-fe's
|
|
2486
|
+
* chatbox.jsx sendOneAttachment encrypts one: a fresh one-time AES-256-
|
|
2487
|
+
* GCM key encrypts the file bytes (crypto.ts's encryptAttachment,
|
|
2488
|
+
* byte-identical wire format to the browser's Web Crypto output), and
|
|
2489
|
+
* that key/iv plus the real filename/content_type/size are PGP-
|
|
2490
|
+
* encrypted as one JSON blob for every current chat member's public
|
|
2491
|
+
* key -- the SAME single recipient list the caption text is encrypted
|
|
2492
|
+
* for, fetched fresh via GET /api/v1/chats/:id so a just-added or
|
|
2493
|
+
* just-removed member is never missed or over-included. Unlike
|
|
2494
|
+
* postMessage's reply() there is no separate sender_message: the web
|
|
2495
|
+
* never excludes the sender from an attachment's recipient list (it
|
|
2496
|
+
* has no reason to -- there's only one `attachment_encrypted_key`
|
|
2497
|
+
* field, see Attachment#as_chat_resource), so a single PGP blob
|
|
2498
|
+
* covering every member already covers the sender too.
|
|
2499
|
+
*
|
|
2500
|
+
* Throws before doing any crypto work on an oversized file (matches
|
|
2501
|
+
* salt-api's own MAX_ATTACHMENT_BYTES so a doomed upload never even
|
|
2502
|
+
* starts) or a content_type outside ALLOWED_SEND_CONTENT_TYPES.
|
|
2503
|
+
*/
|
|
2504
|
+
sendAttachment(apiKey: string, chatId: SaltId, params: SendAttachmentParams): Promise<unknown>;
|
|
2505
|
+
/**
|
|
2506
|
+
* Post into an OPEN ROOM -- a chat with no end-to-end encryption, so
|
|
2507
|
+
* `text` rides the wire and is stored as plain text rather than a PGP
|
|
2508
|
+
* blob. There is no `senderMessage`/`delegations`/`mentions` shape here
|
|
2509
|
+
* the way postMessage has: salt-api refuses this call 422 against a
|
|
2510
|
+
* chat that isn't plain (never silently encrypts, never silently
|
|
2511
|
+
* drops the call). Webhook/socket deliveries for a plain chat carry
|
|
2512
|
+
* `message.encrypted === false` -- see webhook.ts's handleMessage,
|
|
2513
|
+
* which hands the body straight through as ctx.text (ctx.encrypted
|
|
2514
|
+
* false) instead of attempting PGP decrypt.
|
|
2515
|
+
*/
|
|
2516
|
+
postPlainMessage(apiKey: string, chatId: SaltId, text: string): Promise<unknown>;
|
|
2517
|
+
/**
|
|
2518
|
+
* Open rooms (0.6x): declares what this identity wants delivered from
|
|
2519
|
+
* a chat it isn't necessarily addressed in every message of --
|
|
2520
|
+
* `"addressed"` (only a direct reply/@mention, the closest analogue to
|
|
2521
|
+
* how a normal encrypted chat already gates agent delivery),
|
|
2522
|
+
* `"keywords"` (any message containing one of `keywords`), or `"all"`
|
|
2523
|
+
* (every message). Always this identity's OWN subscription for
|
|
2524
|
+
* `chatId` -- same "acts on the caller, never someone else" shape as
|
|
2525
|
+
* setDeliveryMode/setCallback.
|
|
2526
|
+
*/
|
|
2527
|
+
setChatSubscription(apiKey: string, chatId: SaltId, params: {
|
|
2528
|
+
mode: "addressed" | "keywords" | "all";
|
|
2529
|
+
keywords?: string[];
|
|
2530
|
+
}): Promise<unknown>;
|
|
2531
|
+
/** Removes this identity's subscription record for `chatId` -- salt-api's
|
|
2532
|
+
* default (unsubscribed) behavior applies again, same as never having
|
|
2533
|
+
* called setChatSubscription. */
|
|
2534
|
+
clearChatSubscription(apiKey: string, chatId: SaltId): Promise<unknown>;
|
|
2535
|
+
/**
|
|
2536
|
+
* Get-or-create the private lane (a sidechain) between this identity and
|
|
2537
|
+
* `withId`, both members of `chatId`. Once per pair on Salt's side. Answers
|
|
2538
|
+
* 422 when `chatId` is itself a lane. The lane's members come back with
|
|
2539
|
+
* their public keys.
|
|
2540
|
+
*/
|
|
2541
|
+
openSidechain(apiKey: string, chatId: SaltId, withId: SaltId): Promise<{
|
|
2542
|
+
session: {
|
|
2543
|
+
id: SaltId;
|
|
2544
|
+
users?: SaltUser[];
|
|
2545
|
+
coaching_for_chat_id?: SaltId;
|
|
2546
|
+
[key: string]: unknown;
|
|
2547
|
+
};
|
|
2548
|
+
messages?: unknown[];
|
|
2549
|
+
}>;
|
|
2550
|
+
/**
|
|
2551
|
+
* Opens (or reuses) a CONSULT lane between the caller and `withId`, both
|
|
2552
|
+
* already members of `roomId` -- mechanically identical to
|
|
2553
|
+
* openSidechain (same endpoint, same get-or-create-per-pair semantics),
|
|
2554
|
+
* named separately because actions.ts's consult_agent reads more
|
|
2555
|
+
* clearly calling "open the lane I'm about to consult in" than a
|
|
2556
|
+
* generic sidechain call. salt-api tags the resulting chat
|
|
2557
|
+
* `lane_kind: "consult"`, which webhook.ts reads back off the webhook
|
|
2558
|
+
* body to raise the agent-to-agent reply cap for that lane and to gate
|
|
2559
|
+
* request_floor.
|
|
2560
|
+
*/
|
|
2561
|
+
openConsultLane(apiKey: string, roomId: SaltId, withId: SaltId): Promise<{
|
|
2562
|
+
session: {
|
|
2563
|
+
id: SaltId;
|
|
2564
|
+
users?: SaltUser[];
|
|
2565
|
+
coaching_for_chat_id?: SaltId;
|
|
2566
|
+
lane_kind?: string;
|
|
2567
|
+
[key: string]: unknown;
|
|
2568
|
+
};
|
|
2569
|
+
messages?: unknown[];
|
|
2570
|
+
}>;
|
|
93
2571
|
/** Register a new Salt agent, owned by whoever's api-key calls this. */
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
2572
|
+
/**
|
|
2573
|
+
* The create response carries the new agent's raw api key EXACTLY ONCE --
|
|
2574
|
+
* salt-api stores only a digest, so no later endpoint can show it again.
|
|
2575
|
+
* Capture `api_key` here; a lost key means rotateAgentApiKey, not re-reading.
|
|
2576
|
+
*
|
|
2577
|
+
* Key custody: `CreateAgentParams` deliberately has no `private_key` --
|
|
2578
|
+
* salt-api rejects one with a 422 unconditionally (salt-api docs/
|
|
2579
|
+
* KEY_CUSTODY.md Phase 5). The key stays with whoever generates it
|
|
2580
|
+
* (pgp.generateKeypair, above the call site) and is registered with
|
|
2581
|
+
* identities.register/a session store; salt-api never receives a copy in
|
|
2582
|
+
* any form it can decrypt, so there is nothing to fetch back later --
|
|
2583
|
+
* getAgentAdmin's `userkeys` never carries a usable key either.
|
|
2584
|
+
*/
|
|
2585
|
+
createAgent(apiKey: string, params: CreateAgentParams): Promise<SaltUser & {
|
|
2586
|
+
api_key?: string;
|
|
2587
|
+
}>;
|
|
2588
|
+
/**
|
|
2589
|
+
* Draft an agent from one line (`POST /api/v1/agents/draft`): a person (token) or an agent by its own api-key.
|
|
2590
|
+
* Returns the WHOLE draft; each `step` rewrites only its own fields and keeps the rest exactly as sent, so
|
|
2591
|
+
* pass the person's edited draft back in. The AI proposes, the caller confirms: nothing is created. A model
|
|
2592
|
+
* failure is a 502 `SaltApiError` (`code: "draft_failed"`); a spent budget is a 429 or 402 with one sentence.
|
|
2593
|
+
* See AGENTS.md, "Make an agent from one line".
|
|
2594
|
+
*/
|
|
2595
|
+
draftAgent(apiKey: string, params: DraftAgentParams): Promise<AgentDraft>;
|
|
2596
|
+
/**
|
|
2597
|
+
* Draft a whole team from one line (`POST /api/v1/teams/draft`): two to five agents, one lead, a role each, in
|
|
2598
|
+
* one call per step (not one per member). Same contract as `draftAgent`: returns the WHOLE draft, a step
|
|
2599
|
+
* rewrites only its own fields, nothing is created, and the AI proposes while the caller confirms. See AGENTS.md,
|
|
2600
|
+
* "Teams: one room, the lead is the arbiter".
|
|
2601
|
+
*/
|
|
2602
|
+
draftTeam(apiKey: string, params: DraftTeamParams): Promise<TeamDraft>;
|
|
2603
|
+
/** Owner-only: make one member the team's lead (the arbiter of its room), or pass null for no lead. The lead must be a member the owner owns (422). */
|
|
2604
|
+
setTeamLead(apiKey: string, groupId: SaltId, leadAgentId: SaltId | null): Promise<TeamGroup>;
|
|
2605
|
+
/** Owner-only: set a member's job in the team ("Showrunner"; at most 40 characters, blank clears it). */
|
|
2606
|
+
setMemberRole(apiKey: string, groupId: SaltId, agentId: SaltId, role: string | null): Promise<TeamGroup>;
|
|
2607
|
+
/** Owner-only: make (or return) the team's room, one encrypted group chat with you and every member. Idempotent. `left_out` is present only when positive: members the owner does not own are not added to the room. */
|
|
2608
|
+
openTeamRoom(apiKey: string, groupId: SaltId): Promise<{
|
|
2609
|
+
room_chat_id: SaltId;
|
|
2610
|
+
created: boolean;
|
|
2611
|
+
left_out?: number;
|
|
2612
|
+
}>;
|
|
2613
|
+
/** The teams the caller is a member of, with each lead, room and roster (`GET /api/v1/agent/teams`, by the agent's own api-key). This is how a team agent learns who else is in its room. */
|
|
2614
|
+
myTeams(apiKey: string): Promise<MyTeam[]>;
|
|
2615
|
+
/** Owner-only: mint a new api key for an agent. The old one stops working immediately. */
|
|
2616
|
+
rotateAgentApiKey(apiKey: string, agentId: SaltId): Promise<{
|
|
2617
|
+
api_key: string;
|
|
2618
|
+
}>;
|
|
2619
|
+
/**
|
|
2620
|
+
* This identity's own webhook signing key, used to verify that an incoming
|
|
2621
|
+
* webhook really came from salt-api.
|
|
2622
|
+
*
|
|
2623
|
+
* Fetched with the identity's own api key rather than configured from the
|
|
2624
|
+
* environment: salt-api mints one secret per agent, so shipping them through
|
|
2625
|
+
* env/Secrets Manager would mean the deploy had to know values the API
|
|
2626
|
+
* generates. Fetching at boot also means rotation takes effect on restart.
|
|
2627
|
+
*/
|
|
2628
|
+
getWebhookSecret(apiKey: string): Promise<string | undefined>;
|
|
2629
|
+
/**
|
|
2630
|
+
* Which agent does this api key belong to, according to salt-api?
|
|
2631
|
+
*
|
|
2632
|
+
* The same endpoint as getWebhookSecret: alongside the secret it returns
|
|
2633
|
+
* the canonical `agent_id` of the key's owner, which is the id salt-api
|
|
2634
|
+
* puts in X-Salt-Agent-Id on every callback. An identity registered under
|
|
2635
|
+
* any other id -- an env var, or a store entry that predates an id
|
|
2636
|
+
* migration -- can never be found when a webhook arrives; that is what
|
|
2637
|
+
* reconcileIdentityIds uses this to detect and repair.
|
|
2638
|
+
*/
|
|
2639
|
+
whoAmI: (apiKey: string) => Promise<{
|
|
2640
|
+
agent_id: SaltId;
|
|
2641
|
+
webhook_secret?: string;
|
|
2642
|
+
}>;
|
|
2643
|
+
/**
|
|
2644
|
+
* Owner-only: mint a new webhook signing secret for an agent. The old
|
|
2645
|
+
* secret stops verifying immediately, so the agent must re-fetch via
|
|
2646
|
+
* getWebhookSecret before it can validate any further deliveries.
|
|
2647
|
+
*/
|
|
2648
|
+
rotateWebhookSecret(apiKey: string, agentId: SaltId): Promise<{
|
|
2649
|
+
agent_id: SaltId;
|
|
2650
|
+
webhook_secret: string;
|
|
2651
|
+
}>;
|
|
2652
|
+
/**
|
|
2653
|
+
* The caller sets its OWN webhook callback -- api-key auth, no id
|
|
2654
|
+
* parameter, same "acts on the caller, never someone else" shape as
|
|
2655
|
+
* setDeliveryMode/setChatSubscription. Exists so the platform hosting
|
|
2656
|
+
* an agent can point its callback at itself without the owner ever
|
|
2657
|
+
* opening Salt's web console -- see AgentsController#set_callback's
|
|
2658
|
+
* own comment. Same URL-safety rule as the owner's web form
|
|
2659
|
+
* (User#callback_must_be_safe) applies server-side; a human caller
|
|
2660
|
+
* (not an agent's own api-key) gets a 403.
|
|
2661
|
+
*/
|
|
2662
|
+
setCallback(apiKey: string, webhook: string): Promise<{
|
|
2663
|
+
agent_id: SaltId;
|
|
2664
|
+
callback: string;
|
|
2665
|
+
}>;
|
|
2666
|
+
/**
|
|
2667
|
+
* K2 socket mode: the caller sets its OWN delivery mode -- "webhook"
|
|
2668
|
+
* (the default, POST to its registered callback) or "socket" (drain
|
|
2669
|
+
* GET /api/v1/agent/updates or AgentUpdatesChannel instead; see
|
|
2670
|
+
* socket.ts's createSocketClient). No id parameter, same reason
|
|
2671
|
+
* getWebhookSecret has none -- an agent can only ever change its own.
|
|
2672
|
+
* A blank callback is always socket mode regardless of this setting.
|
|
2673
|
+
*/
|
|
2674
|
+
setDeliveryMode(apiKey: string, mode: "webhook" | "socket"): Promise<{
|
|
2675
|
+
agent_id: SaltId;
|
|
2676
|
+
delivery_mode: string;
|
|
2677
|
+
socket_mode: boolean;
|
|
2678
|
+
}>;
|
|
2679
|
+
/**
|
|
2680
|
+
* Owner-only agent admin record. `apikey` is metadata (hint, last-used) --
|
|
2681
|
+
* the raw key rides only on the createAgent response, and after that only
|
|
2682
|
+
* rotateAgentApiKey can produce a usable value.
|
|
2683
|
+
*/
|
|
2684
|
+
getAgentAdmin(apiKey: string, agentId: SaltId): Promise<{
|
|
97
2685
|
apikey: {
|
|
98
|
-
|
|
99
|
-
|
|
2686
|
+
token_hint?: string;
|
|
2687
|
+
last_used_at?: string;
|
|
2688
|
+
} | null;
|
|
100
2689
|
userkeys: unknown;
|
|
2690
|
+
/** A hosted agent's monthly model spend limit in USD, a decimal string ("10" when never set). */
|
|
2691
|
+
model_budget_usd?: string;
|
|
2692
|
+
/** A hosted agent's model spend so far this month. */
|
|
2693
|
+
model_usage?: unknown;
|
|
101
2694
|
[key: string]: unknown;
|
|
102
2695
|
}>;
|
|
2696
|
+
/**
|
|
2697
|
+
* Owner-only: set an agent's photo (`PUT /api/v1/agents/:id/admin_update`, `partial: true` so nothing else
|
|
2698
|
+
* changes). PNG, JPEG, WebP or GIF up to 3 MB; anything else is a 422 with one sentence. A photo the owner
|
|
2699
|
+
* sets becomes its face. Both the photo and the drawing are kept; see `setAgentFace`.
|
|
2700
|
+
*/
|
|
2701
|
+
setAgentPhoto(apiKey: string, agentId: SaltId, photo: {
|
|
2702
|
+
bytes: Uint8Array;
|
|
2703
|
+
contentType: string;
|
|
2704
|
+
}): Promise<{
|
|
2705
|
+
[key: string]: unknown;
|
|
2706
|
+
} & AgentFaceFields>;
|
|
2707
|
+
/** Owner-only: choose which face is shown, `"photo"` or `"drawing"`. `"photo"` with no photo uploaded is a 422
|
|
2708
|
+
* ("Upload a photo first."). The owner's choice outranks the agent's own. */
|
|
2709
|
+
setAgentFace(apiKey: string, agentId: SaltId, face: AgentFace): Promise<{
|
|
2710
|
+
[key: string]: unknown;
|
|
2711
|
+
} & AgentFaceFields>;
|
|
2712
|
+
/**
|
|
2713
|
+
* Owner-only: set the agent's own model spend limit per UTC month in USD (`PATCH /api/v1/agents/:id/persona`, the
|
|
2714
|
+
* route the web uses; a number from 1 to 1000, sent as a string, default 10 when never set). Past it the agent pauses until
|
|
2715
|
+
* the month turns or the owner raises it. Anything else is a 422 with one sentence.
|
|
2716
|
+
*/
|
|
2717
|
+
setAgentBudget(apiKey: string, agentId: SaltId, usd: number | string): Promise<{
|
|
2718
|
+
[key: string]: unknown;
|
|
2719
|
+
}>;
|
|
2720
|
+
/** Owner-only: remove the agent's photo; its drawing shows again. */
|
|
2721
|
+
removeAgentPhoto(apiKey: string, agentId: SaltId): Promise<{
|
|
2722
|
+
[key: string]: unknown;
|
|
2723
|
+
} & AgentFaceFields>;
|
|
2724
|
+
/**
|
|
2725
|
+
* This agent's own identity: every section (claim and proof) with
|
|
2726
|
+
* `scope`/`editable_by`/`checked_by`, plus the public card URL it's
|
|
2727
|
+
* served from. Cache-busted like getChatMembers -- a value just set
|
|
2728
|
+
* with setIdentity should read back immediately.
|
|
2729
|
+
*/
|
|
2730
|
+
identity(apiKey: string): Promise<IdentitySections>;
|
|
2731
|
+
/**
|
|
2732
|
+
* Set one or more of this agent's own CLAIM sections (see
|
|
2733
|
+
* AGENT_CLAIM_SECTION_KEYS). `scope` is never accepted here -- section
|
|
2734
|
+
* visibility is owner-authenticated through the agent-management API
|
|
2735
|
+
* only (plan section 7: "setScope is never on this surface"), so a
|
|
2736
|
+
* caller that tries to slip one in is refused BEFORE any request is
|
|
2737
|
+
* made, the same way a bad tool call should fail loud and immediately
|
|
2738
|
+
* rather than round-tripping to find out the server also says no.
|
|
2739
|
+
* A 422 from salt-api ({errors: {key: "line"}} for an invalid value, or
|
|
2740
|
+
* {error: "Scope comes later."} were scope to somehow reach it anyway)
|
|
2741
|
+
* surfaces as an ordinary SaltApiError.
|
|
2742
|
+
*/
|
|
2743
|
+
setIdentity(apiKey: string, claims: IdentityClaims): Promise<IdentitySections>;
|
|
2744
|
+
/**
|
|
2745
|
+
* Writes one disclosure ledger row -- metadata only, never a section
|
|
2746
|
+
* VALUE (plan section 4). identityShare.ts's share() calls this once
|
|
2747
|
+
* per recipient BEFORE sending any ciphertext, with the SAME `id` every
|
|
2748
|
+
* time (the row is keyed on subject + recipient + id, so this creates
|
|
2749
|
+
* one row per recipient under one shared id), and aborts the whole
|
|
2750
|
+
* share on the first refusal (422, one plain sentence -- e.g. a key
|
|
2751
|
+
* that isn't actually shared with that recipient) with nothing sent.
|
|
2752
|
+
*/
|
|
2753
|
+
postIdentityDisclosure(apiKey: string, params: PostIdentityDisclosureParams): Promise<IdentityDisclosure>;
|
|
2754
|
+
/**
|
|
2755
|
+
* Records which chat message actually carried a share's slice, once
|
|
2756
|
+
* it's been posted. Called ONCE per share() call (with the share's one
|
|
2757
|
+
* `id`) right after the one encrypted SLICE message goes out
|
|
2758
|
+
* (identityShare.ts's share()) -- since every recipient's row shares
|
|
2759
|
+
* that id, one PATCH reaches all of them.
|
|
2760
|
+
*/
|
|
2761
|
+
setIdentityDisclosureMessage(apiKey: string, id: string, messageId: SaltId): Promise<{
|
|
2762
|
+
disclosures: IdentityDisclosure[];
|
|
2763
|
+
}>;
|
|
2764
|
+
/** This agent's own disclosure ledger, newest first. */
|
|
2765
|
+
listIdentityDisclosures(apiKey: string, opts?: {
|
|
2766
|
+
before?: string;
|
|
2767
|
+
limit?: number;
|
|
2768
|
+
}): Promise<{
|
|
2769
|
+
disclosures: IdentityDisclosure[];
|
|
2770
|
+
}>;
|
|
2771
|
+
/**
|
|
2772
|
+
* Revokes EVERY ledger row under `id` (every recipient of that share)
|
|
2773
|
+
* in one call -- stops them being served again and is the signal
|
|
2774
|
+
* identityShare.ts's revoke() sends a `[[SALT-IDENTITY-REVOKE]]` wire
|
|
2775
|
+
* marker off of. Cannot reach a message already read; the rows
|
|
2776
|
+
* themselves are the only thing this call changes.
|
|
2777
|
+
*/
|
|
2778
|
+
revokeIdentityDisclosure(apiKey: string, id: string): Promise<{
|
|
2779
|
+
disclosures: IdentityDisclosure[];
|
|
2780
|
+
}>;
|
|
2781
|
+
/**
|
|
2782
|
+
* Fetches a person's or an agent's PUBLICLY SERVED signed card and
|
|
2783
|
+
* verifies its signature before returning it -- this is a public,
|
|
2784
|
+
* unauthenticated GET (no api-key), matching agent_cards_controller's
|
|
2785
|
+
* `skip_before_action :auth_user`. Tries the agent path then the user
|
|
2786
|
+
* path unless `opts.kind` says which one. A card whose signature this
|
|
2787
|
+
* SDK cannot confirm (missing, unparseable, unknown key, tampered)
|
|
2788
|
+
* throws IdentityCardInvalidError rather than ever coming back
|
|
2789
|
+
* `verified: false` -- a card either verifies or this call fails.
|
|
2790
|
+
*/
|
|
2791
|
+
card(handle: string, opts?: {
|
|
2792
|
+
kind?: "agent" | "user";
|
|
2793
|
+
}): Promise<{
|
|
2794
|
+
card: SignedCard;
|
|
2795
|
+
verified: true;
|
|
2796
|
+
}>;
|
|
103
2797
|
/** The public Agents directory. */
|
|
104
2798
|
listAgents(apiKey: string): Promise<SaltUser[]>;
|
|
105
2799
|
/** A single agent's directory entry. */
|
|
106
|
-
getAgent(apiKey: string, agentId:
|
|
107
|
-
/** Create-or-reuse a 1:1 chat with `contactId` -- idempotent on Salt's side.
|
|
108
|
-
|
|
2800
|
+
getAgent(apiKey: string, agentId: SaltId): Promise<SaltUser>;
|
|
2801
|
+
/** Create-or-reuse a 1:1 chat with `contactId` -- idempotent on Salt's side. The result's `delivered_as` is
|
|
2802
|
+
* `"request"` when the contact has not accepted a first message from you yet: wait, and do not open another
|
|
2803
|
+
* chat. A recipient who only takes messages from their contacts throws `RecipientContactsOnlyError`. */
|
|
2804
|
+
createOrGetChat(apiKey: string, contactId: SaltId): Promise<SaltChat>;
|
|
2805
|
+
/** Your own `message_from` setting: who can start a chat with you without landing in Requests or being refused. */
|
|
2806
|
+
getMessageFrom(apiKey: string): Promise<MessageFrom>;
|
|
2807
|
+
/** Set your own `message_from` (an agent changes its OWN setting). An unknown value is a 422 with
|
|
2808
|
+
* `code: "invalid_message_from"`. Returns the updated account fields. */
|
|
2809
|
+
setMessageFrom(apiKey: string, value: MessageFrom): Promise<{
|
|
2810
|
+
message_from: MessageFrom;
|
|
2811
|
+
[key: string]: unknown;
|
|
2812
|
+
}>;
|
|
2813
|
+
/** Message requests waiting on you: 1:1 chats strangers started that you have not accepted. Same shape as
|
|
2814
|
+
* the chat list (rows are `{session, recent_message}`: the chat id is `row.session.id`); ordinary chats
|
|
2815
|
+
* are not in it. You can read a request through the API and decide. */
|
|
2816
|
+
listRequests(apiKey: string): Promise<SaltChatListRow[]>;
|
|
2817
|
+
/** Accept a message request: it becomes an ordinary chat. Idempotent. Returns the chat. */
|
|
2818
|
+
acceptRequest(apiKey: string, chatId: SaltId): Promise<SaltChat>;
|
|
2819
|
+
/** Decline a message request. The sender is not told: they still see the chat as sent, and anything more
|
|
2820
|
+
* they send you (a new chat, a group add) stays quiet. Blocking the sender (the block endpoint) also declines. */
|
|
2821
|
+
declineRequest(apiKey: string, chatId: SaltId): Promise<void>;
|
|
2822
|
+
/** Accounts that added you as a contact and that you have not added back ("Someone added you"). */
|
|
2823
|
+
listIncomingContacts(apiKey: string): Promise<IncomingContact[]>;
|
|
2824
|
+
/** Accept an incoming contact: add them back (`POST /api/v1/contacts {contact_id}`, the ordinary add-contact call).
|
|
2825
|
+
* This also follows their posts and accepts any message request of yours still waiting from them. */
|
|
2826
|
+
acceptContact(apiKey: string, userId: SaltId): Promise<unknown>;
|
|
2827
|
+
/** Dismiss an incoming contact without adding them back; they drop out of the incoming list and are not told. */
|
|
2828
|
+
dismissIncomingContact(apiKey: string, userId: SaltId): Promise<void>;
|
|
2829
|
+
/** Exact-match lookup of accounts by handle (`username`) or a one-box `q`
|
|
2830
|
+
* (a handle with or without "@", or a fingerprint). Never fuzzy, so a
|
|
2831
|
+
* person who is not discoverable is still found by their exact handle. */
|
|
2832
|
+
searchContacts(apiKey: string, query: {
|
|
2833
|
+
username?: string;
|
|
2834
|
+
q?: string;
|
|
2835
|
+
}): Promise<SaltUser[]>;
|
|
109
2836
|
/** Post a declarative blocks card into a chat (see CARD_PROTOCOL_SPEC.md / cards.ts). */
|
|
110
|
-
postCard(apiKey: string, chatId:
|
|
2837
|
+
postCard(apiKey: string, chatId: SaltId, blocks: CardBlock[], text: string): Promise<unknown>;
|
|
111
2838
|
/** Replace an owned card's blocks -- re-broadcasts into everyone's bubble live. */
|
|
112
|
-
updateCard(apiKey: string, cardId:
|
|
2839
|
+
updateCard(apiKey: string, cardId: SaltId, blocks: CardBlock[]): Promise<unknown>;
|
|
2840
|
+
/**
|
|
2841
|
+
* `GET /api/v1/cards/:id` -- a card's OWNER polling its own tap history
|
|
2842
|
+
* instead of the agent's socket-mode outbox, which has exactly ONE
|
|
2843
|
+
* forward-only cursor per agent: two concurrent pollers (or one running
|
|
2844
|
+
* beside a socket listener) can otherwise silently consume each other's
|
|
2845
|
+
* answers. Polling this instead is idempotent and shares nothing across
|
|
2846
|
+
* callers -- any number of concurrent asks.
|
|
2847
|
+
*
|
|
2848
|
+
* Owner-only: `apiKey` must belong to the card's owner or this rejects
|
|
2849
|
+
* with `SaltApiError` status 404 -- byte-identical to an unknown
|
|
2850
|
+
* `cardId`, never 403 (a chat member already sees the card in the chat
|
|
2851
|
+
* and gets nothing new from this endpoint).
|
|
2852
|
+
*
|
|
2853
|
+
* `options.after` is either another interaction's id or an ISO 8601
|
|
2854
|
+
* timestamp and returns only newer rows; an unrecognised value fails
|
|
2855
|
+
* OPEN (the full list comes back, still 200) rather than rejecting.
|
|
2856
|
+
*/
|
|
2857
|
+
getCard(apiKey: string, cardId: SaltId, options?: {
|
|
2858
|
+
after?: string;
|
|
2859
|
+
}): Promise<CardWithInteractions>;
|
|
113
2860
|
/** My own products (sellerId omitted) or a seller's active products (sellerId given). */
|
|
114
|
-
listProducts(apiKey: string, sellerId?:
|
|
2861
|
+
listProducts(apiKey: string, sellerId?: SaltId): Promise<unknown[]>;
|
|
115
2862
|
/** Create a product in the caller's shop. */
|
|
116
2863
|
createProduct(apiKey: string, params: Record<string, unknown>): Promise<unknown>;
|
|
117
2864
|
/** Drop one of the caller's products into a chat as a Buy-able bubble. */
|
|
118
|
-
shareProduct(apiKey: string, productId:
|
|
119
|
-
/**
|
|
2865
|
+
shareProduct(apiKey: string, productId: SaltId, chatId: SaltId): Promise<unknown>;
|
|
2866
|
+
/**
|
|
2867
|
+
* Send an itemized invoice on the TransferRequest rail. Server
|
|
2868
|
+
* re-validates all the math.
|
|
2869
|
+
*
|
|
2870
|
+
* `idempotencyKey` is sent as an `Idempotency-Key` header, but
|
|
2871
|
+
* `transfer_requests_controller` does NOT include salt-api's `Idempotent`
|
|
2872
|
+
* concern (unlike addUsage/createTransfer paths) -- the server currently
|
|
2873
|
+
* ignores it entirely. A retried call with the same key still creates a
|
|
2874
|
+
* second invoice; there is no dedup, no replay, and none of the 409
|
|
2875
|
+
* `request_in_flight` / `request_failed_terminal` behavior described for
|
|
2876
|
+
* addUsage applies here. Retries of createInvoice are the caller's own
|
|
2877
|
+
* responsibility to guard against for now.
|
|
2878
|
+
*/
|
|
120
2879
|
createInvoice(apiKey: string, params: CreateInvoiceParams): Promise<unknown>;
|
|
121
|
-
/**
|
|
2880
|
+
/**
|
|
2881
|
+
* Record metered usage against the payer's prepaid credits.
|
|
2882
|
+
*
|
|
2883
|
+
* Pass `idempotencyKey` to make a retried call safe -- a replayed
|
|
2884
|
+
* response carries the `Idempotency-Replayed: true` header. A 409
|
|
2885
|
+
* `request_in_flight` means an earlier call with the same key is still
|
|
2886
|
+
* being processed: retry with a NEW key. A 409 `request_failed_terminal`
|
|
2887
|
+
* means the usage/debit side-effect already happened under that key --
|
|
2888
|
+
* do NOT retry with a new key (that would double-charge); reconcile
|
|
2889
|
+
* against the existing usage event instead.
|
|
2890
|
+
*/
|
|
122
2891
|
addUsage(apiKey: string, params: AddUsageParams): Promise<unknown>;
|
|
2892
|
+
/**
|
|
2893
|
+
* Owner-only: an agent's governed-spend policy. Call with the OWNER's
|
|
2894
|
+
* api-key/JWT, not the agent's own key.
|
|
2895
|
+
*
|
|
2896
|
+
* Rule amounts (`budget_amount`, `per_tx_max`, `spent_this_period`,
|
|
2897
|
+
* `remaining`) are all HUMAN-DECIMAL strings, e.g. "0.5" = half an ETH --
|
|
2898
|
+
* never base units (wei/satoshis).
|
|
2899
|
+
*
|
|
2900
|
+
* If the agent has no policy at all, salt-api default-denies every
|
|
2901
|
+
* mainnet send from it -- an owner must call updateSpendingPolicy at
|
|
2902
|
+
* least once before the agent can move mainnet funds.
|
|
2903
|
+
*/
|
|
2904
|
+
getSpendingPolicy(apiKey: string, agentId: SaltId): Promise<SpendingPolicy>;
|
|
2905
|
+
/**
|
|
2906
|
+
* Owner-only: replace an agent's governed-spend policy. Call with the
|
|
2907
|
+
* OWNER's api-key/JWT, not the agent's own key.
|
|
2908
|
+
*
|
|
2909
|
+
* `rules[].budget_amount` and `rules[].per_tx_max` are HUMAN-DECIMAL
|
|
2910
|
+
* strings, e.g. "0.5" = half an ETH -- never base units. `frozen: true`
|
|
2911
|
+
* blocks all mainnet sends regardless of `rules`. Governed-spend
|
|
2912
|
+
* refusals from this or any subsequent send carry `{error, code}`
|
|
2913
|
+
* bodies -- see SpendGovernanceCode.
|
|
2914
|
+
*/
|
|
2915
|
+
updateSpendingPolicy(apiKey: string, agentId: SaltId, policy: UpdateSpendingPolicyParams): Promise<SpendingPolicy>;
|
|
2916
|
+
/**
|
|
2917
|
+
* Guardian side of social recovery (any account named as a guardian, an
|
|
2918
|
+
* agent included). Requests waiting on the caller: one per account that
|
|
2919
|
+
* appointed it and has an open recovery.
|
|
2920
|
+
*/
|
|
2921
|
+
incomingRecoveryRequests(apiKey: string): Promise<RecoveryRequestForGuardian[]>;
|
|
2922
|
+
/** The sealed shares the caller holds for other accounts (ciphertext, encrypted to the caller's own key). */
|
|
2923
|
+
heldRecoveryShares(apiKey: string): Promise<HeldRecoveryShare[]>;
|
|
2924
|
+
/**
|
|
2925
|
+
* Seats other accounts have asked the caller to hold and the caller has
|
|
2926
|
+
* not answered yet (`recovery_guardian_invited` arrives the same way on
|
|
2927
|
+
* the delivery rail). Nothing is released until a seat is accepted.
|
|
2928
|
+
*/
|
|
2929
|
+
recoveryGuardianInvitations(apiKey: string): Promise<RecoveryGuardianInvitation[]>;
|
|
2930
|
+
/** Accept a guardian seat (only the named guardian can). Idempotent answers are refused with 422. */
|
|
2931
|
+
acceptRecoveryGuardian(apiKey: string, seatId: SaltId): Promise<RecoveryGuardianInvitation>;
|
|
2932
|
+
/** Decline a guardian seat. */
|
|
2933
|
+
declineRecoveryGuardian(apiKey: string, seatId: SaltId): Promise<RecoveryGuardianInvitation>;
|
|
2934
|
+
/**
|
|
2935
|
+
* Release the caller's share for one recovery request: open the held
|
|
2936
|
+
* share with the caller's OWN private key, re-seal it to the request's
|
|
2937
|
+
* ephemeral public key (what salt-fe does in a person's browser), and
|
|
2938
|
+
* POST it. Salt only ever sees the re-sealed armor.
|
|
2939
|
+
*
|
|
2940
|
+
* Takes only the request id. The requester and the ephemeral key are
|
|
2941
|
+
* read from Salt's own record (`GET /recovery_request/incoming`), never
|
|
2942
|
+
* from the caller, so a delivery body or a hostile prompt cannot pair a
|
|
2943
|
+
* victim's share with an attacker's key (confused deputy). Only call this
|
|
2944
|
+
* once the request is believed genuine -- see recovery.ts. Idempotent: a
|
|
2945
|
+
* second contribution from the same guardian does not count twice.
|
|
2946
|
+
*/
|
|
2947
|
+
releaseRecoveryShare(apiKey: string, params: {
|
|
2948
|
+
requestId: SaltId;
|
|
2949
|
+
privateKey: string;
|
|
2950
|
+
passphrase: string;
|
|
2951
|
+
}): Promise<{
|
|
2952
|
+
collected: number;
|
|
2953
|
+
threshold: number | null;
|
|
2954
|
+
}>;
|
|
2955
|
+
/**
|
|
2956
|
+
* The settlement record for a transfer the caller was party to (sender
|
|
2957
|
+
* or receiver) -- 404 for anyone else, or if the transfer hasn't
|
|
2958
|
+
* confirmed on-chain yet (receipts are minted only at confirmation).
|
|
2959
|
+
*/
|
|
2960
|
+
getReceipt(apiKey: string, transferId: SaltId): Promise<Receipt>;
|
|
123
2961
|
/** The caller's credit relationships, both directions. */
|
|
124
2962
|
getBillingAccounts(apiKey: string): Promise<unknown>;
|
|
2963
|
+
/**
|
|
2964
|
+
* Payer-initiated deposit: drops a "Credits top-up" invoice into
|
|
2965
|
+
* `chatId` for `payeeId` to receive. Nothing is credited by this call
|
|
2966
|
+
* itself -- the deposit lands only once that invoice is paid (see
|
|
2967
|
+
* onInvoicePaid's `isTopUp`).
|
|
2968
|
+
*/
|
|
2969
|
+
topUpBillingAccount(apiKey: string, params: {
|
|
2970
|
+
chatId: SaltId;
|
|
2971
|
+
payeeId: SaltId;
|
|
2972
|
+
amount: string | number;
|
|
2973
|
+
}): Promise<{
|
|
2974
|
+
ok: true;
|
|
2975
|
+
transfer_request_id: SaltId;
|
|
2976
|
+
billing_account: BillingAccount;
|
|
2977
|
+
}>;
|
|
2978
|
+
/**
|
|
2979
|
+
* Payee-only: return value onto the credits ledger. Capped at net usage
|
|
2980
|
+
* (Σusage - Σrefunds) so a refund can only give back credits that were
|
|
2981
|
+
* actually consumed -- it can never mint new balance. A 422
|
|
2982
|
+
* `refund_exceeds_usage` means `amount` is above what's currently
|
|
2983
|
+
* refundable. This is a ledger entry, not an on-chain transfer -- no
|
|
2984
|
+
* Receipt is minted for it.
|
|
2985
|
+
*/
|
|
2986
|
+
refundBillingAccount(apiKey: string, billingAccountId: SaltId, params: {
|
|
2987
|
+
amount: string | number;
|
|
2988
|
+
memo?: string;
|
|
2989
|
+
}): Promise<{
|
|
2990
|
+
ok: true;
|
|
2991
|
+
entry_id: SaltId;
|
|
2992
|
+
billing_account: BillingAccount;
|
|
2993
|
+
}>;
|
|
2994
|
+
/**
|
|
2995
|
+
* A transfer's current record, to verify a payment actually confirmed
|
|
2996
|
+
* before an agent claims money work "done" (see actions.ts's
|
|
2997
|
+
* report_progress evidence check). Status is one of "Pending" |
|
|
2998
|
+
* "Confirmed" | "Failed" (Transfer#status in salt-api's
|
|
2999
|
+
* app/models/transfer.rb) -- "Confirmed" is the only settled state.
|
|
3000
|
+
*
|
|
3001
|
+
* NOTE: as of this SDK version salt-api's TransfersController defines
|
|
3002
|
+
* no `show` action (only index, create, and the :id/info member
|
|
3003
|
+
* route) -- this call requires that route added server-side in the
|
|
3004
|
+
* same release this evidence check ships in.
|
|
3005
|
+
*/
|
|
3006
|
+
getTransfer(apiKey: string, transferId: SaltId): Promise<{
|
|
3007
|
+
id: SaltId;
|
|
3008
|
+
status: string;
|
|
3009
|
+
[key: string]: unknown;
|
|
3010
|
+
}>;
|
|
125
3011
|
/** The caller's own wallets. */
|
|
126
3012
|
listWallets(apiKey: string): Promise<unknown[]>;
|
|
127
3013
|
/** Upload an already-encrypted wallet under the caller's own identity (see crypto.ts). */
|
|
128
3014
|
createWallet(apiKey: string, params: Record<string, unknown>): Promise<unknown>;
|
|
129
3015
|
/** Hand a chat off to another agent; salt-api does the whole swap atomically. */
|
|
130
|
-
handOff(apiKey: string, chatId:
|
|
3016
|
+
handOff(apiKey: string, chatId: SaltId, toAgentId: SaltId, reason?: string): Promise<unknown>;
|
|
3017
|
+
/**
|
|
3018
|
+
* One step back: return the chat to whoever handed it TO the current
|
|
3019
|
+
* active agent most recently (a real hop off the trail, not a fixed
|
|
3020
|
+
* destination) -- salt-api's `Chat#hand_off_back!`. 422 with "Already
|
|
3021
|
+
* at the start of this conversation." when there's no previous hop;
|
|
3022
|
+
* callers (actions.ts's hand_back_to_concierge) fall back to something
|
|
3023
|
+
* fixed in that case. The acting agent must currently be this chat's
|
|
3024
|
+
* active agent (or a human member) -- salt-api's `gacm_actor_allowed?`.
|
|
3025
|
+
*/
|
|
3026
|
+
handBack(apiKey: string, chatId: SaltId): Promise<unknown>;
|
|
3027
|
+
/**
|
|
3028
|
+
* React to a message with one emoji (`POST /api/v1/messages/:id/reactions`).
|
|
3029
|
+
* A TOGGLE: the same emoji again removes yours. Plaintext metadata, so no
|
|
3030
|
+
* crypto. Resolves with the server's `{message_id, reactions}` summary;
|
|
3031
|
+
* a 422 ("Pick a single emoji." / "You can react with up to 12 emoji.")
|
|
3032
|
+
* arrives as a SaltApiError carrying that sentence.
|
|
3033
|
+
*
|
|
3034
|
+
* The owner's rule for agents: react "not all the time, just when they
|
|
3035
|
+
* choose", and only "if it relevantly complements the chat in a friendly
|
|
3036
|
+
* way" -- a thanks acknowledged, a done request marked, good news
|
|
3037
|
+
* celebrated. Never instead of answering a question, never on every
|
|
3038
|
+
* message, never on your own.
|
|
3039
|
+
*/
|
|
3040
|
+
react(apiKey: string, messageId: SaltId, emoji: string): Promise<ReactionSummary>;
|
|
3041
|
+
/** The emoji this identity has used, for picking one (`GET /api/v1/reactions/mine`). */
|
|
3042
|
+
myReactions(apiKey: string): Promise<unknown>;
|
|
3043
|
+
/**
|
|
3044
|
+
* Replies to a post: your reply becomes YOUR OWN post in your profile room, linked to the one it
|
|
3045
|
+
* answers -- the same single action a person has (`POST /api/v1/posts/:id/reply`). Resolves with
|
|
3046
|
+
* the new post's row. Refusals arrive as a SaltApiError carrying the server's sentence: 404 not a
|
|
3047
|
+
* visible post, 403 blocked, 422 empty or too long. Pass `idempotencyKey` to make a retry safe
|
|
3048
|
+
* (sent as `Idempotency-Key`).
|
|
3049
|
+
*/
|
|
3050
|
+
replyToPost(apiKey: string, postId: SaltId, text: string, opts?: {
|
|
3051
|
+
idempotencyKey?: string;
|
|
3052
|
+
media?: PostMediaInput;
|
|
3053
|
+
}): Promise<PostRow>;
|
|
3054
|
+
/**
|
|
3055
|
+
* Posts to your own profile: text, a photo or video, or both -- the same single action a person has.
|
|
3056
|
+
* The room is made on first use (`POST /api/v1/profile_room`), then the post goes through
|
|
3057
|
+
* `POST /api/v1/messages`; media is plain and public (up to 15 MB; image/jpeg, png, webp, gif,
|
|
3058
|
+
* heic or video/mp4, webm, quicktime), so it is NOT encrypted like chat attachments. Resolves with
|
|
3059
|
+
* the new message envelope (its `media.url` is the public file). A refusal arrives as a SaltApiError
|
|
3060
|
+
* carrying the server's sentence.
|
|
3061
|
+
*/
|
|
3062
|
+
postToProfile(apiKey: string, params: {
|
|
3063
|
+
text?: string;
|
|
3064
|
+
media?: PostMediaInput;
|
|
3065
|
+
}): Promise<{
|
|
3066
|
+
message_id: SaltId;
|
|
3067
|
+
media?: PostMediaInfo;
|
|
3068
|
+
}>;
|
|
3069
|
+
/** The replies to a post, newest page first; pass the last page's `next_before` as `before` for older ones
|
|
3070
|
+
* (`GET /api/v1/posts/:id/replies`). */
|
|
3071
|
+
getPostReplies(apiKey: string, postId: SaltId, opts?: {
|
|
3072
|
+
before?: string;
|
|
3073
|
+
limit?: number;
|
|
3074
|
+
}): Promise<PostRepliesPage>;
|
|
131
3075
|
/** Ephemeral "is typing" ping. Fire-and-forget by design -- a failed ping must never block a reply. */
|
|
132
|
-
signalTyping(apiKey: string, chatId:
|
|
3076
|
+
signalTyping(apiKey: string, chatId: SaltId): Promise<void>;
|
|
133
3077
|
/**
|
|
134
3078
|
* Fire-and-forget product-metrics beacon. Deliberately not awaited by
|
|
135
3079
|
* callers -- an analytics post must never delay or fail a reply. Only
|
|
136
3080
|
* names in salt-api's Event::CLIENT_EVENT_NAMES allowlist are accepted.
|
|
137
3081
|
*/
|
|
138
3082
|
trackEvent(apiKey: string, name: string, properties?: Record<string, unknown>): void;
|
|
3083
|
+
/**
|
|
3084
|
+
* Prepares a governed payment for approval -- `money.pay`'s mode is FORCED to `ask`, so this
|
|
3085
|
+
* always resolves to an `AskedResult`, never a Transfer, whether called through `actFor` or (in
|
|
3086
|
+
* the unusual case of preparing your own payment) as yourself. Once the exercise is approved
|
|
3087
|
+
* (see `mandates.decide`/`mandates.exercises`, or the `approval_decided` webhook event), settle
|
|
3088
|
+
* it with `transfers#create`'s own `exercise_id` param (not exposed as a typed method here yet --
|
|
3089
|
+
* salt-api validates the wallet/amount/destination against the exercise's summary before it will
|
|
3090
|
+
* create the Transfer).
|
|
3091
|
+
*/
|
|
3092
|
+
prepareTransfer(apiKey: string, params: {
|
|
3093
|
+
walletId: SaltId;
|
|
3094
|
+
destinationAddress?: string;
|
|
3095
|
+
receiverId?: SaltId;
|
|
3096
|
+
amount: string | number;
|
|
3097
|
+
chain?: string;
|
|
3098
|
+
note?: string;
|
|
3099
|
+
chatId?: SaltId;
|
|
3100
|
+
}): Promise<AskedResult>;
|
|
3101
|
+
mandates: {
|
|
3102
|
+
/** Every mandate the caller is party to, as grantor and/or grantee. */
|
|
3103
|
+
list(apiKey: string, opts?: {
|
|
3104
|
+
role?: "grantor" | "grantee";
|
|
3105
|
+
status?: MandateStatus;
|
|
3106
|
+
}): Promise<{
|
|
3107
|
+
mandates: Mandate[];
|
|
3108
|
+
}>;
|
|
3109
|
+
get(apiKey: string, mandateId: SaltId): Promise<Mandate>;
|
|
3110
|
+
/** Grantor creates (a proposal the grantee must accept, or auto-active for an account the
|
|
3111
|
+
* caller governs), or a grantee proposes UP by passing `grantor_id` instead. */
|
|
3112
|
+
propose(apiKey: string, params: ProposeMandateParams): Promise<Mandate>;
|
|
3113
|
+
/** New version, compare-and-swap on `params.version` -- a 409 SaltApiError means it changed
|
|
3114
|
+
* under you; re-fetch with `get` and retry against the new version. */
|
|
3115
|
+
update(apiKey: string, mandateId: SaltId, params: UpdateMandateParams): Promise<Mandate>;
|
|
3116
|
+
/** Grantee accepts an offered mandate (binds its current key fingerprint), or the grantor
|
|
3117
|
+
* activates one still `proposed` by the grantee. See `ctx.mandate.accept()` in webhook.ts,
|
|
3118
|
+
* which calls this for an incoming `mandate_offered` event. */
|
|
3119
|
+
accept(apiKey: string, mandateId: SaltId): Promise<Mandate>;
|
|
3120
|
+
/** Standing mandates only: +90 days from now. */
|
|
3121
|
+
renew(apiKey: string, mandateId: SaltId): Promise<Mandate>;
|
|
3122
|
+
pause(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
|
|
3123
|
+
resume(apiKey: string, mandateId: SaltId): Promise<Mandate>;
|
|
3124
|
+
/** The grantor, or a governor of either side, can revoke -- cascades to any child mandates. */
|
|
3125
|
+
revoke(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
|
|
3126
|
+
/** A mandate's trail, id-descending. `refusal` is only populated when the caller is the
|
|
3127
|
+
* principal or its governor (salt-api's own viewer check -- this SDK doesn't re-derive it). */
|
|
3128
|
+
exercises(apiKey: string, mandateId: SaltId, opts?: {
|
|
3129
|
+
before?: string | number;
|
|
3130
|
+
limit?: number;
|
|
3131
|
+
}): Promise<{
|
|
3132
|
+
exercises: MandateExercise[];
|
|
3133
|
+
}>;
|
|
3134
|
+
/** Every open ask (decision `"asked"`, not yet expired) the caller can decide right now. */
|
|
3135
|
+
openExercises(apiKey: string): Promise<{
|
|
3136
|
+
exercises: MandateExercise[];
|
|
3137
|
+
}>;
|
|
3138
|
+
/** Approve or deny one open ask. See `ctx.approval.decide()` in webhook.ts, which calls this
|
|
3139
|
+
* for an incoming `approval_requested` event. */
|
|
3140
|
+
decide(apiKey: string, exerciseId: SaltId | number, decision: "approve" | "deny", note?: string): Promise<MandateExercise>;
|
|
3141
|
+
};
|
|
3142
|
+
teams: {
|
|
3143
|
+
/** The Teams shelf: listed templates, most installed first. Public. */
|
|
3144
|
+
list(apiKey: string, opts?: {
|
|
3145
|
+
q?: string;
|
|
3146
|
+
limit?: number;
|
|
3147
|
+
offset?: number;
|
|
3148
|
+
}): Promise<{
|
|
3149
|
+
teams: TeamTemplate[];
|
|
3150
|
+
total: number;
|
|
3151
|
+
}>;
|
|
3152
|
+
/** The templates this identity shared, listed or not. */
|
|
3153
|
+
mine(apiKey: string): Promise<{
|
|
3154
|
+
teams: TeamTemplate[];
|
|
3155
|
+
}>;
|
|
3156
|
+
/** A recipe preview, by id or slug. Public; an unlisted template is reachable by its link. */
|
|
3157
|
+
get(apiKey: string, idOrSlug: string): Promise<TeamTemplate>;
|
|
3158
|
+
/** Shares one of the caller's own agent groups as a template. */
|
|
3159
|
+
share(apiKey: string, params: ShareTeamParams): Promise<TeamTemplate & {
|
|
3160
|
+
left_out: number;
|
|
3161
|
+
}>;
|
|
3162
|
+
/** Author only: name, description, listed or unlisted, the coordinator note. */
|
|
3163
|
+
update(apiKey: string, idOrSlug: string, changes: Partial<Pick<ShareTeamParams, "name" | "description" | "listed" | "coordinatorNote">>): Promise<TeamTemplate>;
|
|
3164
|
+
/** Author only. Agents already made from it are the installers' own. */
|
|
3165
|
+
remove(apiKey: string, idOrSlug: string): Promise<void>;
|
|
3166
|
+
/** "I made this team": counted once per installer. */
|
|
3167
|
+
installed(apiKey: string, idOrSlug: string): Promise<{
|
|
3168
|
+
install_count: number;
|
|
3169
|
+
counted: boolean;
|
|
3170
|
+
}>;
|
|
3171
|
+
};
|
|
3172
|
+
apps: {
|
|
3173
|
+
/**
|
|
3174
|
+
* Creates an app + version 1. `forId` builds it for someone else (that
|
|
3175
|
+
* person must share a chat with the caller, else 422); omitted, the
|
|
3176
|
+
* app belongs to the caller. `chatId` also installs it there in the
|
|
3177
|
+
* same transaction (caller must be a member) -- see `installation` on
|
|
3178
|
+
* the result.
|
|
3179
|
+
*/
|
|
3180
|
+
create(apiKey: string, params: CreateAppParams): Promise<CreateAppResult>;
|
|
3181
|
+
/**
|
|
3182
|
+
* Publishes a new immutable version (owner or builder only) and moves
|
|
3183
|
+
* the app's `latest_version_id` to it. `actions` (omitted: none)
|
|
3184
|
+
* replace whatever the PRIOR version declared -- they don't merge.
|
|
3185
|
+
* Never changes an existing installation on its own -- each keeps
|
|
3186
|
+
* running its own pinned version (and that version's own `actions`)
|
|
3187
|
+
* until it calls `update`, below.
|
|
3188
|
+
*/
|
|
3189
|
+
newVersion(apiKey: string, appId: SaltId, html: string, actions?: AppQuickAction[]): Promise<{
|
|
3190
|
+
app: AppSummary;
|
|
3191
|
+
version: AppVersionRef;
|
|
3192
|
+
}>;
|
|
3193
|
+
/** An app's metadata: owner, builder, latest version -- and, once listed, what the App Store shows. */
|
|
3194
|
+
get(apiKey: string, appId: SaltId): Promise<AppSummary>;
|
|
3195
|
+
/**
|
|
3196
|
+
* Installs `appId` -- into `chatId` (caller must be a non-observer
|
|
3197
|
+
* member; a second active install of the same app there 409s with the
|
|
3198
|
+
* existing installation instead of creating a duplicate) or, with no
|
|
3199
|
+
* `chatId`, into the caller's own personal space ("Your apps").
|
|
3200
|
+
* `copyStateFrom` copies another readable installation's doc into the
|
|
3201
|
+
* new one once.
|
|
3202
|
+
*/
|
|
3203
|
+
install(apiKey: string, appId: SaltId, params?: InstallAppParams): Promise<AppInstallation>;
|
|
3204
|
+
/**
|
|
3205
|
+
* This identity's installations: every one in `chatId` (chat members
|
|
3206
|
+
* only) when given, else its own personal installations plus every
|
|
3207
|
+
* chat installation in a chat it's a member of. Cache-busted -- an
|
|
3208
|
+
* install just made should show up immediately.
|
|
3209
|
+
*/
|
|
3210
|
+
installations(apiKey: string, opts?: {
|
|
3211
|
+
chatId?: SaltId;
|
|
3212
|
+
}): Promise<AppInstallation[]>;
|
|
3213
|
+
/** The installation's shared state doc and its CAS version. Cache-busted -- a doc just written with `setState` should read back immediately. */
|
|
3214
|
+
state(apiKey: string, installationId: SaltId): Promise<AppStateDoc>;
|
|
3215
|
+
/**
|
|
3216
|
+
* Compare-and-swap write of the installation's shared state doc. A 409
|
|
3217
|
+
* (the doc moved under the caller since `ifVersion`) is never handed
|
|
3218
|
+
* back as a bare SaltApiError -- it's re-thrown as
|
|
3219
|
+
* AppStateConflictError carrying the CURRENT `{doc, version}` straight
|
|
3220
|
+
* off the response body, so a caller can merge its change onto the
|
|
3221
|
+
* fresh doc and retry with the new version in one more call rather
|
|
3222
|
+
* than round-tripping to re-fetch first.
|
|
3223
|
+
*/
|
|
3224
|
+
setState(apiKey: string, installationId: SaltId, doc: Record<string, unknown>, ifVersion: number): Promise<AppStateDoc>;
|
|
3225
|
+
};
|
|
139
3226
|
};
|
|
140
3227
|
export type SaltClient = ReturnType<typeof createSaltClient>;
|
|
3228
|
+
export {};
|
|
141
3229
|
//# sourceMappingURL=client.d.ts.map
|