salt-agent-sdk 0.28.0 → 0.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/client.d.ts CHANGED
@@ -810,6 +810,23 @@ export interface Mandate {
810
810
  revoke_reason?: string;
811
811
  children?: MandateChild[];
812
812
  trail?: MandateTrail;
813
+ /** `"self"` when a root agent approved its own plan (grantor == grantee). */
814
+ approved_by?: "self" | null;
815
+ /** The pending request to change a running plan's settings, or null. See `requestStrategyTune`. */
816
+ tune_request?: StrategyTuneRequest | null;
817
+ /** Strategy mandates: money paid under the plan, per currency (this month and in total). Measured, never estimated. */
818
+ spend?: {
819
+ money: {
820
+ amount: string;
821
+ currency: string;
822
+ }[];
823
+ money_month: {
824
+ amount: string;
825
+ currency: string;
826
+ }[];
827
+ payments: number;
828
+ as_of: string;
829
+ } | null;
813
830
  [key: string]: unknown;
814
831
  }
815
832
  /** One row of a mandate's trail -- an allowed act, an ask (settled or still open), or a refusal.
@@ -843,6 +860,8 @@ export interface MandateExercise {
843
860
  created_at: string;
844
861
  decided_at?: string;
845
862
  expires_at?: string;
863
+ /** Salt's plain label for who or what the act goes to (an approve-first ask), when it sends one. */
864
+ target_label?: string;
846
865
  [key: string]: unknown;
847
866
  }
848
867
  export interface ProposeMandateParams {
@@ -859,6 +878,11 @@ export interface ProposeMandateParams {
859
878
  reason?: string;
860
879
  estimated_cost?: GrantEstimatedCost;
861
880
  resume_token?: string;
881
+ /** A plan proposal only: the `strategy_id` of your plan (waiting or running) for this person that this one takes the place of.
882
+ * Even a reworded goal replaces it, so there are never two live plans for one goal. 422 `replaces_not_found` when none matches. */
883
+ replaces?: string;
884
+ /** A grant asked for a plan: the plan's mandate id. Stopping or expiring the plan ends the grant (422 `plan_not_found`). */
885
+ plan_id?: SaltId;
862
886
  }
863
887
  /** Capabilities an agent can ask its owner for. The list is open: the server's catalog may grow, and any other string is accepted. */
864
888
  export type GrantCapability = "profile.post" | "wake.repeat" | "room.create" | "outreach.request" | "agent.spending" | "credential.borrow" | "mcp.call" | "money.pay" | "money.request" | (string & {});
@@ -899,6 +923,10 @@ export interface RequestGrantParams {
899
923
  resumeToken?: string;
900
924
  chatId?: SaltId;
901
925
  label?: string;
926
+ /** A grant asked for a plan: the plan's mandate id, so stopping the plan ends the grant. */
927
+ planId?: SaltId;
928
+ /** A plan proposal: the `strategy_id` of the plan this one replaces. */
929
+ replaces?: string;
902
930
  }
903
931
  /** `GET /api/v1/mandates/check?capability=...` */
904
932
  export interface GrantCheck {
@@ -906,6 +934,9 @@ export interface GrantCheck {
906
934
  mandate_id?: SaltId;
907
935
  mode?: MandateCapabilityMode;
908
936
  constraints?: Record<string, unknown>;
937
+ /** True when the capability is held in mode `ask`: `allowed` is false until the person approves THIS act. Call
938
+ * `requestAsk`, wait for `approval_decided`, then act under the plan (see `ApproveFirstError`). */
939
+ needs_ask?: boolean;
909
940
  }
910
941
  export interface UpdateMandateParams {
911
942
  /** Required: compare-and-swap against the mandate's current `version` -- a stale value is a 409. */
@@ -926,6 +957,23 @@ export interface StrategyTuning {
926
957
  goalKind?: StrategyGoalKind;
927
958
  pace?: StrategyPace;
928
959
  }
960
+ /** What a tune (or a request for one) changes: the three effort keys, or one capability's mode (`requestModeChange`). */
961
+ export interface StrategyTuneChanges {
962
+ explore?: number;
963
+ goal_kind?: string;
964
+ pace?: string;
965
+ mode_change?: {
966
+ capability: ApproveFirstCapability;
967
+ mode: "notify";
968
+ };
969
+ }
970
+ /** A pending request to change a running plan's settings (`Mandate.tune_request`); nothing has changed until the grantor accepts. */
971
+ export interface StrategyTuneRequest {
972
+ id: string;
973
+ changes: StrategyTuneChanges;
974
+ reason: string;
975
+ at: string;
976
+ }
929
977
  /**
930
978
  * A 202 `{status: "asked", exercise_id, expires_at}` response, resolved rather than thrown --
931
979
  * see `SaltClient.actFor` below. `isAsked` narrows an unknown result to this shape.
@@ -934,6 +982,10 @@ export interface AskedResult {
934
982
  asked: true;
935
983
  exerciseId: SaltId;
936
984
  expiresAt?: string;
985
+ /** Only on the answer to `requestAsk`: asks of this kind the person has approved so far, and how many it takes before you may
986
+ * file `requestModeChange`. */
987
+ approved?: number;
988
+ needed?: number;
937
989
  }
938
990
  export declare function isAsked(value: unknown): value is AskedResult;
939
991
  /** Maps a client method's `Promise<R>` to `Promise<R | AskedResult>` -- what every call through
@@ -1070,6 +1122,56 @@ export declare class RecipientContactsOnlyError extends SaltApiError {
1070
1122
  sentence: string;
1071
1123
  constructor(method: string, url: string, status: number, body: unknown);
1072
1124
  }
1125
+ export declare const APPROVE_FIRST = "approve_first";
1126
+ export declare const PLAN_REQUIRED = "plan_required";
1127
+ /** The three kinds of act that wait for the person's tap before the first few go out: a public post, a public room, a first message to someone new. */
1128
+ export type ApproveFirstCapability = "profile.post" | "room.create" | "outreach.request";
1129
+ /** 403 `approve_first` (an act with no approved, unused ask) or 422 `approve_first` (a first proposal for one of these kinds in a mode
1130
+ * other than `ask`). `sentence` is the server's own words: show it, do not retry the act. File `requestAsk` with the exact words and
1131
+ * where they go, wait for `approval_decided`, then act under the plan. */
1132
+ export declare class ApproveFirstError extends SaltApiError {
1133
+ sentence: string;
1134
+ capability?: ApproveFirstCapability;
1135
+ /** Asks of this kind the person has approved so far, and how many it takes before the kind can move to "tells you each time". */
1136
+ approved?: number;
1137
+ needed?: number;
1138
+ constructor(method: string, url: string, status: number, body: unknown);
1139
+ }
1140
+ /** 403 `plan_required`: a post, room or first message must name the plan it belongs to. Send `plan: <plan mandate id>` (`X-Salt-Plan`)
1141
+ * with the call, once the person has approved the plan. `sentence` is the server's own words. */
1142
+ export declare class PlanRequiredError extends SaltApiError {
1143
+ sentence: string;
1144
+ constructor(method: string, url: string, status: number, body: unknown);
1145
+ }
1146
+ /** The sha256 (hex) of a post's media bytes: pass it as `mediaDigest` on a `profile.post` ask. */
1147
+ export declare function mediaDigestOf(data: Uint8Array): string;
1148
+ /** What `requestAsk` takes. Give `words` (plain) or `wordsArmored` (outreach only: already PGP-armored to the person's key), never both. */
1149
+ export interface RequestAskParams {
1150
+ capability: ApproveFirstCapability;
1151
+ /** The exact words, as the person will read them (at most 2000 characters). */
1152
+ words?: string;
1153
+ /** Outreach only: the exact words PGP-armored to the grantor's key, so Salt never holds a stranger-bound message in the clear. */
1154
+ wordsArmored?: string;
1155
+ /** Outreach only, instead of `wordsArmored`: the grantor's armored public key (or keys). The SDK encrypts `words` to them AND to
1156
+ * `ownPublicKey` (so you can read the final text back after an edit) and sends only the armor. */
1157
+ encryptTo?: string | string[];
1158
+ /** Your own armored public key. Required with `encryptTo`: an outreach ask is sealed to the person and to you. */
1159
+ ownPublicKey?: string;
1160
+ /** `room.create` only: what the room is for, in your own words (shown with the name). */
1161
+ about?: string;
1162
+ /** `profile.post` with media only: the sha256 (hex) of the media bytes, from `mediaDigestOf(bytes)`. The person approves that exact file. */
1163
+ mediaDigest?: string;
1164
+ /** `profile.post` only: a new post, or a reply to someone's post. */
1165
+ kind?: "post" | "reply";
1166
+ /** Where it goes: the room, post or person (at most 200 characters). */
1167
+ where: string;
1168
+ /** `outreach.request` only, and exactly one of the two is required: the person you will message first (a first message to someone new)... */
1169
+ recipientId?: SaltId;
1170
+ /** ...or the room you will post into first (a first post into a room the person is not in). The act must name the same target. */
1171
+ chatId?: SaltId;
1172
+ /** Sent as `Idempotency-Key`. Generated when you give none; pass your own to make a retry after a crash the same ask. */
1173
+ idempotencyKey?: string;
1174
+ }
1073
1175
  /**
1074
1176
  * Creates a REST client bound to a Salt deployment's host. Every method
1075
1177
  * takes the acting identity's own api-key explicitly rather than a
@@ -1083,7 +1185,7 @@ type RequestFn = <T>(method: string, path: string, apiKey: string, body?: unknow
1083
1185
  idempotencyKey?: string;
1084
1186
  }) => Promise<T>;
1085
1187
  /** Sent as `X-Salt-Client` on every request. Kept equal to package.json's version (a test checks). */
1086
- export declare const SDK_VERSION = "0.28.0";
1188
+ export declare const SDK_VERSION = "0.30.0";
1087
1189
  export declare function createSaltClient(options: SaltClientOptions): {
1088
1190
  actFor: (principalId: SaltId, opts?: ActForOptions) => { [K in keyof ReturnType<(request: RequestFn) => {
1089
1191
  /** A chat's members (with public keys), for encrypting a reply to everyone who should read it. */
@@ -1141,6 +1243,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
1141
1243
  replyTo?: SaltId;
1142
1244
  recipientFingerprints?: Record<string, string>;
1143
1245
  senderFingerprint?: string;
1246
+ plan?: SaltId;
1144
1247
  }): Promise<PostMessageResult>;
1145
1248
  /**
1146
1249
  * Sends a file into a chat, encrypted exactly the way salt-fe's
@@ -1176,6 +1279,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
1176
1279
  */
1177
1280
  postPlainMessage(apiKey: string, chatId: SaltId, text: string, opts?: {
1178
1281
  replyTo?: SaltId;
1282
+ plan?: SaltId;
1179
1283
  }): Promise<unknown>;
1180
1284
  /**
1181
1285
  * Show Me: ask the person in a 1:1 for help. Posts the question as an ordinary end-to-end
@@ -1516,7 +1620,25 @@ export declare function createSaltClient(options: SaltClientOptions): {
1516
1620
  /** Create-or-reuse a 1:1 chat with `contactId` -- idempotent on Salt's side. The result's `delivered_as` is
1517
1621
  * `"request"` when the contact has not accepted a first message from you yet: wait, and do not open another
1518
1622
  * chat. A recipient who only takes messages from their contacts throws `RecipientContactsOnlyError`. */
1519
- createOrGetChat(apiKey: string, contactId: SaltId): Promise<SaltChat>;
1623
+ createOrGetChat(apiKey: string, contactId: SaltId, opts?: {
1624
+ plan?: SaltId;
1625
+ }): Promise<SaltChat>;
1626
+ /**
1627
+ * Opens a group room (`POST /api/v1/chats` with `contact_ids`; may be empty). `open: true` makes it an open room (not end-to-end
1628
+ * encrypted, readable at its URL by anyone); `public: true` lists an encrypted room publicly. Approve-first: an agent whose
1629
+ * `room.create` row is mode `ask` must first `requestAsk({capability: "room.create", words: <the room's name>, where})` with the
1630
+ * name EXACTLY as passed here (an empty name is "Unnamed Chat"), wait for `approval_decided`, then call this with
1631
+ * `plan: <plan mandate id>` (`X-Salt-Plan`). Only an open or public room is gated; a refusal is `ApproveFirstError` or
1632
+ * `PlanRequiredError`. Resolves with the new room (its `id`).
1633
+ */
1634
+ createRoom(apiKey: string, params: {
1635
+ name?: string;
1636
+ description?: string;
1637
+ contactIds?: SaltId[];
1638
+ open?: boolean;
1639
+ public?: boolean;
1640
+ plan?: SaltId;
1641
+ }): Promise<SaltChat>;
1520
1642
  /** Your own `message_from` setting: who can start a chat with you without landing in Requests or being refused. */
1521
1643
  getMessageFrom(apiKey: string): Promise<MessageFrom>;
1522
1644
  /** Set your own `message_from` (an agent changes its OWN setting). An unknown value is a 422 with
@@ -1765,6 +1887,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
1765
1887
  replyToPost(apiKey: string, postId: SaltId, text: string, opts?: {
1766
1888
  idempotencyKey?: string;
1767
1889
  media?: PostMediaInput;
1890
+ plan?: SaltId;
1768
1891
  }): Promise<PostRow>;
1769
1892
  /**
1770
1893
  * Posts to your own profile: text, a photo or video, or both -- the same single action a person has.
@@ -1777,6 +1900,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
1777
1900
  postToProfile(apiKey: string, params: {
1778
1901
  text?: string;
1779
1902
  media?: PostMediaInput;
1903
+ plan?: SaltId;
1780
1904
  }): Promise<{
1781
1905
  message_id: SaltId;
1782
1906
  media?: PostMediaInfo;
@@ -1830,6 +1954,47 @@ export declare function createSaltClient(options: SaltClientOptions): {
1830
1954
  tuneStrategy(apiKey: string, mandateId: SaltId, tuning: StrategyTuning, opts: {
1831
1955
  version: number;
1832
1956
  }): Promise<Mandate>;
1957
+ /**
1958
+ * Ask the person (the plan's grantor) to change the pace, exploring or kind of goal of a RUNNING plan you run.
1959
+ * NOTHING changes until they accept: tell them you asked, do not use the new value yet. `reason` (at most 300
1960
+ * characters) is shown with the ask. One pending request per plan; a newer one replaces it. 422 codes:
1961
+ * `strategy_not_editable` (any other key, or the plan is not running), `invalid_strategy`, `no_change`,
1962
+ * `invalid_reason`, `self_approved` (a plan you approved yourself has nobody to ask: use `tuneStrategy`). The
1963
+ * request rides on the mandate as `tune_request`. If they accept you hear `strategy_tuned`; if not, `strategy_tune_declined`.
1964
+ */
1965
+ requestStrategyTune(apiKey: string, mandateId: SaltId, tuning: StrategyTuning, opts: {
1966
+ reason: string;
1967
+ }): Promise<Mandate>;
1968
+ /**
1969
+ * Ask the person's OK for ONE act before you do it (approve-first, Salt 0.240.0): a public post (`profile.post`), a new public
1970
+ * room (`room.create`) or a first message to someone new (`outreach.request`), word for word and with where it goes. Only a grant
1971
+ * whose row is mode `ask` takes asks (422 `not_ask_mode` otherwise: just act). Resolves to an `AskedResult` right away (`exerciseId`,
1972
+ * `expiresAt`, and `approved`/`needed`): NOTHING has been sent. The person decides on their card; you hear `approval_decided`
1973
+ * (`onApprovalDecided`, `ctx.exercise.id === exerciseId`). On `approved`, make the act ONCE under the plan (`plan: <plan mandate id>`),
1974
+ * using `ctx.ask.words`, the final text (they may have edited it); on `denied`, drop it. There is no event on expiry: treat `expiresAt` as the timeout.
1975
+ * An `Idempotency-Key` is generated unless you pass `idempotencyKey`: the same key replays the same ask. For outreach, pass
1976
+ * `wordsArmored`, or `encryptTo` (the person's armored public key, or an array) with plain `words` and `ownPublicKey` (sealed to the person AND to you), and Salt holds only the armor; outreach also names its target with exactly one of `recipientId` | `chatId`. For `room.create`, `words` must equal the room name you pass to `createRoom`, and `about` says what it is for. For `profile.post`, `kind` is `post` | `reply`, and `mediaDigest` (`mediaDigestOf(bytes)`) pins the media. Errors:
1977
+ * 409 `idempotency_mismatch`, 429 (waiting on earlier approvals), 422 `not_askable` | `no_grant` | `invalid_words` | `invalid_where`.
1978
+ */
1979
+ requestAsk(apiKey: string, mandateId: SaltId, params: RequestAskParams): Promise<AskedResult>;
1980
+ /**
1981
+ * Ask the person to move one kind from "asks each time" to "tells you each time" (`mode: "notify"`, the only mode there is), after
1982
+ * they have approved 3 asks of it (422 `not_enough_approved`, with `approved` and `needed`). NOTHING changes until they tap: keep
1983
+ * asking. Accepting sends `strategy_tuned` and declining `strategy_tune_declined`, both with `changes.mode_change`. `reason` is
1984
+ * shown with the ask (at most 300 characters). Other 422 codes: `invalid_mode_change`, `no_grant`, `no_change`, `invalid_reason`.
1985
+ */
1986
+ requestModeChange(apiKey: string, mandateId: SaltId, change: {
1987
+ capability: ApproveFirstCapability;
1988
+ mode?: "notify";
1989
+ }, opts: {
1990
+ reason: string;
1991
+ }): Promise<Mandate>;
1992
+ /**
1993
+ * For the owner's client: answer a pending `tune_request` on a plan you granted. `accept` applies it exactly like
1994
+ * `tuneStrategy` (the agent hears `strategy_tuned`); `decline` changes nothing (the agent hears
1995
+ * `strategy_tune_declined`). 404 `request_not_open` when it was replaced or already answered.
1996
+ */
1997
+ decideStrategyTune(apiKey: string, mandateId: SaltId, requestId: string, decision: "accept" | "decline"): Promise<Mandate>;
1833
1998
  /** Do you already hold this capability? `{allowed, mandate_id?, mode, constraints}`. */
1834
1999
  checkGrant(apiKey: string, capability: GrantCapability): Promise<GrantCheck>;
1835
2000
  mandates: {
@@ -1855,8 +2020,11 @@ export declare function createSaltClient(options: SaltClientOptions): {
1855
2020
  renew(apiKey: string, mandateId: SaltId): Promise<Mandate>;
1856
2021
  pause(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
1857
2022
  resume(apiKey: string, mandateId: SaltId): Promise<Mandate>;
1858
- /** The grantor, or a governor of either side, can revoke -- cascades to any child mandates. */
1859
- revoke(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
2023
+ /** The grantor, or a governor of either side, can revoke -- cascades to any child mandates. Stopping a plan also stops every grant filed
2024
+ * for it and any other live plan for the same goal: their mandate ids come back as `also_ended`. */
2025
+ revoke(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate & {
2026
+ also_ended?: SaltId[];
2027
+ }>;
1860
2028
  /** A mandate's trail, id-descending. `refusal` is only populated when the caller is the
1861
2029
  * principal or its governor (salt-api's own viewer check -- this SDK doesn't re-derive it). */
1862
2030
  exercises(apiKey: string, mandateId: SaltId, opts?: {
@@ -2020,6 +2188,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
2020
2188
  replyTo?: SaltId;
2021
2189
  recipientFingerprints?: Record<string, string>;
2022
2190
  senderFingerprint?: string;
2191
+ plan?: SaltId;
2023
2192
  }): Promise<PostMessageResult>;
2024
2193
  /**
2025
2194
  * Sends a file into a chat, encrypted exactly the way salt-fe's
@@ -2055,6 +2224,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
2055
2224
  */
2056
2225
  postPlainMessage(apiKey: string, chatId: SaltId, text: string, opts?: {
2057
2226
  replyTo?: SaltId;
2227
+ plan?: SaltId;
2058
2228
  }): Promise<unknown>;
2059
2229
  /**
2060
2230
  * Show Me: ask the person in a 1:1 for help. Posts the question as an ordinary end-to-end
@@ -2395,7 +2565,25 @@ export declare function createSaltClient(options: SaltClientOptions): {
2395
2565
  /** Create-or-reuse a 1:1 chat with `contactId` -- idempotent on Salt's side. The result's `delivered_as` is
2396
2566
  * `"request"` when the contact has not accepted a first message from you yet: wait, and do not open another
2397
2567
  * chat. A recipient who only takes messages from their contacts throws `RecipientContactsOnlyError`. */
2398
- createOrGetChat(apiKey: string, contactId: SaltId): Promise<SaltChat>;
2568
+ createOrGetChat(apiKey: string, contactId: SaltId, opts?: {
2569
+ plan?: SaltId;
2570
+ }): Promise<SaltChat>;
2571
+ /**
2572
+ * Opens a group room (`POST /api/v1/chats` with `contact_ids`; may be empty). `open: true` makes it an open room (not end-to-end
2573
+ * encrypted, readable at its URL by anyone); `public: true` lists an encrypted room publicly. Approve-first: an agent whose
2574
+ * `room.create` row is mode `ask` must first `requestAsk({capability: "room.create", words: <the room's name>, where})` with the
2575
+ * name EXACTLY as passed here (an empty name is "Unnamed Chat"), wait for `approval_decided`, then call this with
2576
+ * `plan: <plan mandate id>` (`X-Salt-Plan`). Only an open or public room is gated; a refusal is `ApproveFirstError` or
2577
+ * `PlanRequiredError`. Resolves with the new room (its `id`).
2578
+ */
2579
+ createRoom(apiKey: string, params: {
2580
+ name?: string;
2581
+ description?: string;
2582
+ contactIds?: SaltId[];
2583
+ open?: boolean;
2584
+ public?: boolean;
2585
+ plan?: SaltId;
2586
+ }): Promise<SaltChat>;
2399
2587
  /** Your own `message_from` setting: who can start a chat with you without landing in Requests or being refused. */
2400
2588
  getMessageFrom(apiKey: string): Promise<MessageFrom>;
2401
2589
  /** Set your own `message_from` (an agent changes its OWN setting). An unknown value is a 422 with
@@ -2644,6 +2832,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
2644
2832
  replyToPost(apiKey: string, postId: SaltId, text: string, opts?: {
2645
2833
  idempotencyKey?: string;
2646
2834
  media?: PostMediaInput;
2835
+ plan?: SaltId;
2647
2836
  }): Promise<PostRow>;
2648
2837
  /**
2649
2838
  * Posts to your own profile: text, a photo or video, or both -- the same single action a person has.
@@ -2656,6 +2845,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
2656
2845
  postToProfile(apiKey: string, params: {
2657
2846
  text?: string;
2658
2847
  media?: PostMediaInput;
2848
+ plan?: SaltId;
2659
2849
  }): Promise<{
2660
2850
  message_id: SaltId;
2661
2851
  media?: PostMediaInfo;
@@ -2709,6 +2899,47 @@ export declare function createSaltClient(options: SaltClientOptions): {
2709
2899
  tuneStrategy(apiKey: string, mandateId: SaltId, tuning: StrategyTuning, opts: {
2710
2900
  version: number;
2711
2901
  }): Promise<Mandate>;
2902
+ /**
2903
+ * Ask the person (the plan's grantor) to change the pace, exploring or kind of goal of a RUNNING plan you run.
2904
+ * NOTHING changes until they accept: tell them you asked, do not use the new value yet. `reason` (at most 300
2905
+ * characters) is shown with the ask. One pending request per plan; a newer one replaces it. 422 codes:
2906
+ * `strategy_not_editable` (any other key, or the plan is not running), `invalid_strategy`, `no_change`,
2907
+ * `invalid_reason`, `self_approved` (a plan you approved yourself has nobody to ask: use `tuneStrategy`). The
2908
+ * request rides on the mandate as `tune_request`. If they accept you hear `strategy_tuned`; if not, `strategy_tune_declined`.
2909
+ */
2910
+ requestStrategyTune(apiKey: string, mandateId: SaltId, tuning: StrategyTuning, opts: {
2911
+ reason: string;
2912
+ }): Promise<Mandate>;
2913
+ /**
2914
+ * Ask the person's OK for ONE act before you do it (approve-first, Salt 0.240.0): a public post (`profile.post`), a new public
2915
+ * room (`room.create`) or a first message to someone new (`outreach.request`), word for word and with where it goes. Only a grant
2916
+ * whose row is mode `ask` takes asks (422 `not_ask_mode` otherwise: just act). Resolves to an `AskedResult` right away (`exerciseId`,
2917
+ * `expiresAt`, and `approved`/`needed`): NOTHING has been sent. The person decides on their card; you hear `approval_decided`
2918
+ * (`onApprovalDecided`, `ctx.exercise.id === exerciseId`). On `approved`, make the act ONCE under the plan (`plan: <plan mandate id>`),
2919
+ * using `ctx.ask.words`, the final text (they may have edited it); on `denied`, drop it. There is no event on expiry: treat `expiresAt` as the timeout.
2920
+ * An `Idempotency-Key` is generated unless you pass `idempotencyKey`: the same key replays the same ask. For outreach, pass
2921
+ * `wordsArmored`, or `encryptTo` (the person's armored public key, or an array) with plain `words` and `ownPublicKey` (sealed to the person AND to you), and Salt holds only the armor; outreach also names its target with exactly one of `recipientId` | `chatId`. For `room.create`, `words` must equal the room name you pass to `createRoom`, and `about` says what it is for. For `profile.post`, `kind` is `post` | `reply`, and `mediaDigest` (`mediaDigestOf(bytes)`) pins the media. Errors:
2922
+ * 409 `idempotency_mismatch`, 429 (waiting on earlier approvals), 422 `not_askable` | `no_grant` | `invalid_words` | `invalid_where`.
2923
+ */
2924
+ requestAsk(apiKey: string, mandateId: SaltId, params: RequestAskParams): Promise<AskedResult>;
2925
+ /**
2926
+ * Ask the person to move one kind from "asks each time" to "tells you each time" (`mode: "notify"`, the only mode there is), after
2927
+ * they have approved 3 asks of it (422 `not_enough_approved`, with `approved` and `needed`). NOTHING changes until they tap: keep
2928
+ * asking. Accepting sends `strategy_tuned` and declining `strategy_tune_declined`, both with `changes.mode_change`. `reason` is
2929
+ * shown with the ask (at most 300 characters). Other 422 codes: `invalid_mode_change`, `no_grant`, `no_change`, `invalid_reason`.
2930
+ */
2931
+ requestModeChange(apiKey: string, mandateId: SaltId, change: {
2932
+ capability: ApproveFirstCapability;
2933
+ mode?: "notify";
2934
+ }, opts: {
2935
+ reason: string;
2936
+ }): Promise<Mandate>;
2937
+ /**
2938
+ * For the owner's client: answer a pending `tune_request` on a plan you granted. `accept` applies it exactly like
2939
+ * `tuneStrategy` (the agent hears `strategy_tuned`); `decline` changes nothing (the agent hears
2940
+ * `strategy_tune_declined`). 404 `request_not_open` when it was replaced or already answered.
2941
+ */
2942
+ decideStrategyTune(apiKey: string, mandateId: SaltId, requestId: string, decision: "accept" | "decline"): Promise<Mandate>;
2712
2943
  /** Do you already hold this capability? `{allowed, mandate_id?, mode, constraints}`. */
2713
2944
  checkGrant(apiKey: string, capability: GrantCapability): Promise<GrantCheck>;
2714
2945
  mandates: {
@@ -2734,8 +2965,11 @@ export declare function createSaltClient(options: SaltClientOptions): {
2734
2965
  renew(apiKey: string, mandateId: SaltId): Promise<Mandate>;
2735
2966
  pause(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
2736
2967
  resume(apiKey: string, mandateId: SaltId): Promise<Mandate>;
2737
- /** The grantor, or a governor of either side, can revoke -- cascades to any child mandates. */
2738
- revoke(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
2968
+ /** The grantor, or a governor of either side, can revoke -- cascades to any child mandates. Stopping a plan also stops every grant filed
2969
+ * for it and any other live plan for the same goal: their mandate ids come back as `also_ended`. */
2970
+ revoke(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate & {
2971
+ also_ended?: SaltId[];
2972
+ }>;
2739
2973
  /** A mandate's trail, id-descending. `refusal` is only populated when the caller is the
2740
2974
  * principal or its governor (salt-api's own viewer check -- this SDK doesn't re-derive it). */
2741
2975
  exercises(apiKey: string, mandateId: SaltId, opts?: {
@@ -2899,6 +3133,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
2899
3133
  replyTo?: SaltId;
2900
3134
  recipientFingerprints?: Record<string, string>;
2901
3135
  senderFingerprint?: string;
3136
+ plan?: SaltId;
2902
3137
  }): Promise<PostMessageResult>;
2903
3138
  /**
2904
3139
  * Sends a file into a chat, encrypted exactly the way salt-fe's
@@ -2934,6 +3169,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
2934
3169
  */
2935
3170
  postPlainMessage(apiKey: string, chatId: SaltId, text: string, opts?: {
2936
3171
  replyTo?: SaltId;
3172
+ plan?: SaltId;
2937
3173
  }): Promise<unknown>;
2938
3174
  /**
2939
3175
  * Show Me: ask the person in a 1:1 for help. Posts the question as an ordinary end-to-end
@@ -3274,7 +3510,25 @@ export declare function createSaltClient(options: SaltClientOptions): {
3274
3510
  /** Create-or-reuse a 1:1 chat with `contactId` -- idempotent on Salt's side. The result's `delivered_as` is
3275
3511
  * `"request"` when the contact has not accepted a first message from you yet: wait, and do not open another
3276
3512
  * chat. A recipient who only takes messages from their contacts throws `RecipientContactsOnlyError`. */
3277
- createOrGetChat(apiKey: string, contactId: SaltId): Promise<SaltChat>;
3513
+ createOrGetChat(apiKey: string, contactId: SaltId, opts?: {
3514
+ plan?: SaltId;
3515
+ }): Promise<SaltChat>;
3516
+ /**
3517
+ * Opens a group room (`POST /api/v1/chats` with `contact_ids`; may be empty). `open: true` makes it an open room (not end-to-end
3518
+ * encrypted, readable at its URL by anyone); `public: true` lists an encrypted room publicly. Approve-first: an agent whose
3519
+ * `room.create` row is mode `ask` must first `requestAsk({capability: "room.create", words: <the room's name>, where})` with the
3520
+ * name EXACTLY as passed here (an empty name is "Unnamed Chat"), wait for `approval_decided`, then call this with
3521
+ * `plan: <plan mandate id>` (`X-Salt-Plan`). Only an open or public room is gated; a refusal is `ApproveFirstError` or
3522
+ * `PlanRequiredError`. Resolves with the new room (its `id`).
3523
+ */
3524
+ createRoom(apiKey: string, params: {
3525
+ name?: string;
3526
+ description?: string;
3527
+ contactIds?: SaltId[];
3528
+ open?: boolean;
3529
+ public?: boolean;
3530
+ plan?: SaltId;
3531
+ }): Promise<SaltChat>;
3278
3532
  /** Your own `message_from` setting: who can start a chat with you without landing in Requests or being refused. */
3279
3533
  getMessageFrom(apiKey: string): Promise<MessageFrom>;
3280
3534
  /** Set your own `message_from` (an agent changes its OWN setting). An unknown value is a 422 with
@@ -3523,6 +3777,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
3523
3777
  replyToPost(apiKey: string, postId: SaltId, text: string, opts?: {
3524
3778
  idempotencyKey?: string;
3525
3779
  media?: PostMediaInput;
3780
+ plan?: SaltId;
3526
3781
  }): Promise<PostRow>;
3527
3782
  /**
3528
3783
  * Posts to your own profile: text, a photo or video, or both -- the same single action a person has.
@@ -3535,6 +3790,7 @@ export declare function createSaltClient(options: SaltClientOptions): {
3535
3790
  postToProfile(apiKey: string, params: {
3536
3791
  text?: string;
3537
3792
  media?: PostMediaInput;
3793
+ plan?: SaltId;
3538
3794
  }): Promise<{
3539
3795
  message_id: SaltId;
3540
3796
  media?: PostMediaInfo;
@@ -3588,6 +3844,47 @@ export declare function createSaltClient(options: SaltClientOptions): {
3588
3844
  tuneStrategy(apiKey: string, mandateId: SaltId, tuning: StrategyTuning, opts: {
3589
3845
  version: number;
3590
3846
  }): Promise<Mandate>;
3847
+ /**
3848
+ * Ask the person (the plan's grantor) to change the pace, exploring or kind of goal of a RUNNING plan you run.
3849
+ * NOTHING changes until they accept: tell them you asked, do not use the new value yet. `reason` (at most 300
3850
+ * characters) is shown with the ask. One pending request per plan; a newer one replaces it. 422 codes:
3851
+ * `strategy_not_editable` (any other key, or the plan is not running), `invalid_strategy`, `no_change`,
3852
+ * `invalid_reason`, `self_approved` (a plan you approved yourself has nobody to ask: use `tuneStrategy`). The
3853
+ * request rides on the mandate as `tune_request`. If they accept you hear `strategy_tuned`; if not, `strategy_tune_declined`.
3854
+ */
3855
+ requestStrategyTune(apiKey: string, mandateId: SaltId, tuning: StrategyTuning, opts: {
3856
+ reason: string;
3857
+ }): Promise<Mandate>;
3858
+ /**
3859
+ * Ask the person's OK for ONE act before you do it (approve-first, Salt 0.240.0): a public post (`profile.post`), a new public
3860
+ * room (`room.create`) or a first message to someone new (`outreach.request`), word for word and with where it goes. Only a grant
3861
+ * whose row is mode `ask` takes asks (422 `not_ask_mode` otherwise: just act). Resolves to an `AskedResult` right away (`exerciseId`,
3862
+ * `expiresAt`, and `approved`/`needed`): NOTHING has been sent. The person decides on their card; you hear `approval_decided`
3863
+ * (`onApprovalDecided`, `ctx.exercise.id === exerciseId`). On `approved`, make the act ONCE under the plan (`plan: <plan mandate id>`),
3864
+ * using `ctx.ask.words`, the final text (they may have edited it); on `denied`, drop it. There is no event on expiry: treat `expiresAt` as the timeout.
3865
+ * An `Idempotency-Key` is generated unless you pass `idempotencyKey`: the same key replays the same ask. For outreach, pass
3866
+ * `wordsArmored`, or `encryptTo` (the person's armored public key, or an array) with plain `words` and `ownPublicKey` (sealed to the person AND to you), and Salt holds only the armor; outreach also names its target with exactly one of `recipientId` | `chatId`. For `room.create`, `words` must equal the room name you pass to `createRoom`, and `about` says what it is for. For `profile.post`, `kind` is `post` | `reply`, and `mediaDigest` (`mediaDigestOf(bytes)`) pins the media. Errors:
3867
+ * 409 `idempotency_mismatch`, 429 (waiting on earlier approvals), 422 `not_askable` | `no_grant` | `invalid_words` | `invalid_where`.
3868
+ */
3869
+ requestAsk(apiKey: string, mandateId: SaltId, params: RequestAskParams): Promise<AskedResult>;
3870
+ /**
3871
+ * Ask the person to move one kind from "asks each time" to "tells you each time" (`mode: "notify"`, the only mode there is), after
3872
+ * they have approved 3 asks of it (422 `not_enough_approved`, with `approved` and `needed`). NOTHING changes until they tap: keep
3873
+ * asking. Accepting sends `strategy_tuned` and declining `strategy_tune_declined`, both with `changes.mode_change`. `reason` is
3874
+ * shown with the ask (at most 300 characters). Other 422 codes: `invalid_mode_change`, `no_grant`, `no_change`, `invalid_reason`.
3875
+ */
3876
+ requestModeChange(apiKey: string, mandateId: SaltId, change: {
3877
+ capability: ApproveFirstCapability;
3878
+ mode?: "notify";
3879
+ }, opts: {
3880
+ reason: string;
3881
+ }): Promise<Mandate>;
3882
+ /**
3883
+ * For the owner's client: answer a pending `tune_request` on a plan you granted. `accept` applies it exactly like
3884
+ * `tuneStrategy` (the agent hears `strategy_tuned`); `decline` changes nothing (the agent hears
3885
+ * `strategy_tune_declined`). 404 `request_not_open` when it was replaced or already answered.
3886
+ */
3887
+ decideStrategyTune(apiKey: string, mandateId: SaltId, requestId: string, decision: "accept" | "decline"): Promise<Mandate>;
3591
3888
  /** Do you already hold this capability? `{allowed, mandate_id?, mode, constraints}`. */
3592
3889
  checkGrant(apiKey: string, capability: GrantCapability): Promise<GrantCheck>;
3593
3890
  mandates: {
@@ -3613,8 +3910,11 @@ export declare function createSaltClient(options: SaltClientOptions): {
3613
3910
  renew(apiKey: string, mandateId: SaltId): Promise<Mandate>;
3614
3911
  pause(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
3615
3912
  resume(apiKey: string, mandateId: SaltId): Promise<Mandate>;
3616
- /** The grantor, or a governor of either side, can revoke -- cascades to any child mandates. */
3617
- revoke(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate>;
3913
+ /** The grantor, or a governor of either side, can revoke -- cascades to any child mandates. Stopping a plan also stops every grant filed
3914
+ * for it and any other live plan for the same goal: their mandate ids come back as `also_ended`. */
3915
+ revoke(apiKey: string, mandateId: SaltId, reason?: string): Promise<Mandate & {
3916
+ also_ended?: SaltId[];
3917
+ }>;
3618
3918
  /** A mandate's trail, id-descending. `refusal` is only populated when the caller is the
3619
3919
  * principal or its governor (salt-api's own viewer check -- this SDK doesn't re-derive it). */
3620
3920
  exercises(apiKey: string, mandateId: SaltId, opts?: {