salt-agent-sdk 0.20.0 → 0.22.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/README.md +28 -3
- package/dist/actions.d.ts.map +1 -1
- package/dist/actions.js +72 -1
- package/dist/actions.js.map +1 -1
- package/dist/callBundle.d.ts +90 -0
- package/dist/callBundle.d.ts.map +1 -0
- package/dist/callBundle.js +199 -0
- package/dist/callBundle.js.map +1 -0
- package/dist/client.d.ts +88 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +80 -2
- package/dist/client.js.map +1 -1
- package/dist/device/client.d.ts +12 -4
- package/dist/device/client.d.ts.map +1 -1
- package/dist/device/client.js +44 -1
- package/dist/device/client.js.map +1 -1
- package/dist/device/host.d.ts +74 -3
- package/dist/device/host.d.ts.map +1 -1
- package/dist/device/host.js +262 -12
- package/dist/device/host.js.map +1 -1
- package/dist/device/http.d.ts.map +1 -1
- package/dist/device/http.js +3 -2
- package/dist/device/http.js.map +1 -1
- package/dist/device/protocol.d.ts +97 -1
- package/dist/device/protocol.d.ts.map +1 -1
- package/dist/device/protocol.js +155 -1
- package/dist/device/protocol.js.map +1 -1
- package/dist/help.d.ts +54 -0
- package/dist/help.d.ts.map +1 -0
- package/dist/help.js +62 -0
- package/dist/help.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lattice.d.ts +206 -0
- package/dist/lattice.d.ts.map +1 -0
- package/dist/lattice.js +366 -0
- package/dist/lattice.js.map +1 -0
- package/dist/webhook.d.ts +67 -3
- package/dist/webhook.d.ts.map +1 -1
- package/dist/webhook.js +72 -4
- package/dist/webhook.js.map +1 -1
- package/dist/work.d.ts +2 -0
- package/dist/work.d.ts.map +1 -1
- package/dist/work.js +4 -0
- package/dist/work.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { type SaltId } from "./ids.js";
|
|
2
|
+
/**
|
|
3
|
+
* How long request_personal_data waits for a release before reporting
|
|
4
|
+
* "pending" instead of "released". This bounds how long ONE chat turn keeps
|
|
5
|
+
* whoever's waiting on the agent hanging -- it is NOT protecting against
|
|
6
|
+
* Salt's own webhook delivery timeout: webhook.ts acknowledges salt-api's
|
|
7
|
+
* POST before ever calling dispatch(), so nothing here is on the clock for
|
|
8
|
+
* that deadline. A "pending" result past this is the normal case, not an
|
|
9
|
+
* error -- see actions.ts's request_personal_data and onRelease/
|
|
10
|
+
* onLatticeRelease for what happens when the answer arrives afterward.
|
|
11
|
+
*/
|
|
12
|
+
export declare const LATTICE_REQUEST_TIMEOUT_MS = 15000;
|
|
13
|
+
export declare const REQUEST_MARKER_RE: RegExp;
|
|
14
|
+
export declare const RELEASE_MARKER_RE: RegExp;
|
|
15
|
+
export declare const PROPOSE_MARKER_RE: RegExp;
|
|
16
|
+
export interface LatticeFact {
|
|
17
|
+
path: string;
|
|
18
|
+
type: string;
|
|
19
|
+
field: string;
|
|
20
|
+
/** A JSON primitive (string/number/boolean/null) -- normalizeFact rejects an object or array here. */
|
|
21
|
+
value: string | number | boolean | null;
|
|
22
|
+
/** "you" or "agent" -- WHICH agent wrote it is deliberately never disclosed (PROTOCOL.md). */
|
|
23
|
+
author: "you" | "agent";
|
|
24
|
+
updated: number;
|
|
25
|
+
}
|
|
26
|
+
/** The JSON body of a [[SALT-LATTICE-RELEASE]] message, either shape (a
|
|
27
|
+
* reply to one request, or a standing push -- see the module comment). */
|
|
28
|
+
export interface ReleaseBody {
|
|
29
|
+
facts: LatticeFact[];
|
|
30
|
+
/** Present on an ordinary reply to a request; absent on a standing push. */
|
|
31
|
+
request_id?: string;
|
|
32
|
+
/** Present only on a standing push. */
|
|
33
|
+
grant_id?: string;
|
|
34
|
+
/** Present only on a standing push: facts changed since this sequence number. */
|
|
35
|
+
since_seq?: number;
|
|
36
|
+
}
|
|
37
|
+
export interface LatticeRelease {
|
|
38
|
+
/** The release message's own id (for the disclosure log) -- NOT the request id it answers. */
|
|
39
|
+
id: string;
|
|
40
|
+
/** Set to a grant id for a standing push; absent for an ordinary reply. */
|
|
41
|
+
standing?: string;
|
|
42
|
+
/** The chat and sender this release actually arrived from (Salt-authenticated, not attacker-controlled). */
|
|
43
|
+
chatId: SaltId;
|
|
44
|
+
senderId: SaltId;
|
|
45
|
+
body: ReleaseBody;
|
|
46
|
+
}
|
|
47
|
+
export interface BuildRequestInput {
|
|
48
|
+
/** One plain sentence, shown to the person before they decide -- PROTOCOL.md's Request. */
|
|
49
|
+
purpose: string;
|
|
50
|
+
/** Selectors, e.g. "preferences.food.cuisine.*" -- only what the agent's grant names is ever released; asking for more is not an error. */
|
|
51
|
+
asks: string[];
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Mints a fresh request id and its wire text. Send `text` as an ordinary
|
|
55
|
+
* encrypted chat message into the current chat (or the agent's private
|
|
56
|
+
* lane); the phone answers it -- in a group, inside a sidechain it opens
|
|
57
|
+
* with this agent, never in the room (PROTOCOL.md R6).
|
|
58
|
+
*/
|
|
59
|
+
export declare function buildRequest(input: BuildRequestInput): {
|
|
60
|
+
id: string;
|
|
61
|
+
text: string;
|
|
62
|
+
};
|
|
63
|
+
export interface LatticeProposalInput {
|
|
64
|
+
/** A closed-schema type name (PROTOCOL.md) -- an unknown type or field is silently dropped on the phone, never an error here or there. */
|
|
65
|
+
type: string;
|
|
66
|
+
parent_name?: string;
|
|
67
|
+
fields: Record<string, unknown>;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Builds a [[SALT-LATTICE-PROPOSE]] message suggesting new facts. Always
|
|
71
|
+
* lands `pending` on the phone unless the agent's grant trusts its writes
|
|
72
|
+
* to that compartment (PROTOCOL.md R3) -- there is no reply to wait for,
|
|
73
|
+
* so unlike buildRequest this returns only the wire text.
|
|
74
|
+
*/
|
|
75
|
+
export declare function buildProposal(proposals: LatticeProposalInput[]): string;
|
|
76
|
+
/** A single release's fact count is capped here -- not rejected outright,
|
|
77
|
+
* just bounded, since an over-long but otherwise well-formed release isn't
|
|
78
|
+
* a protocol violation the way a malformed entry is (see normalizeFact). */
|
|
79
|
+
export declare const MAX_FACTS_PER_RELEASE = 200;
|
|
80
|
+
/** A fact's string value is capped to this many characters, after marker
|
|
81
|
+
* stripping (see sanitizeFactValue) -- bounds how much untrusted text from
|
|
82
|
+
* the other end of the wire can reach a model in one fact. */
|
|
83
|
+
export declare const MAX_FACT_VALUE_LENGTH = 2000;
|
|
84
|
+
/**
|
|
85
|
+
* Splits an incoming plaintext into its release marker's id, optional
|
|
86
|
+
* standing grant id, and parsed JSON body -- or null when `plaintext` isn't
|
|
87
|
+
* a (well-formed, in-protocol) lattice release at all. Returns null for an
|
|
88
|
+
* unparseable or malformed body, and also for a body that is neither an
|
|
89
|
+
* ordinary reply (`request_id`) nor a standing push (`standing=` on the
|
|
90
|
+
* marker line AND `grant_id` in the body) -- PROTOCOL.md says a release is
|
|
91
|
+
* "always a reply to a request id" unless it's a standing push, so anything
|
|
92
|
+
* else is out-of-protocol. Deliberate in all these cases: it's safer to let
|
|
93
|
+
* a corrupt or nonsensical release fall through as ordinary (harmless)
|
|
94
|
+
* message text than to silently act on it. A standing push's marker-line
|
|
95
|
+
* `standing=<grant id>` and its body's `grant_id` must name the SAME grant
|
|
96
|
+
* -- PROTOCOL.md's own example shows them matching, and disagreeing values
|
|
97
|
+
* are simply invalid rather than a case to guess between (whoever
|
|
98
|
+
* eventually checks `grant_id` against this agent's actual grants -- see
|
|
99
|
+
* webhook.ts's onLatticeRelease verification -- must be checking the one
|
|
100
|
+
* value the marker itself also claims).
|
|
101
|
+
*/
|
|
102
|
+
export declare function parseRelease(plaintext: string): {
|
|
103
|
+
id: string;
|
|
104
|
+
standing?: string;
|
|
105
|
+
body: ReleaseBody;
|
|
106
|
+
} | null;
|
|
107
|
+
export declare function hasPending(id: string): boolean;
|
|
108
|
+
export interface RegisterBinding {
|
|
109
|
+
/** The chat the request was actually sent into. */
|
|
110
|
+
chatId: SaltId;
|
|
111
|
+
/** The person the request was actually addressed to -- see actions.ts's request_personal_data, which resolves this to one specific chat member even in a group. */
|
|
112
|
+
senderId: SaltId;
|
|
113
|
+
timeoutMs: number;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Registers a wait for the release answering request `id`, bound to the
|
|
117
|
+
* exact chat and person it was sent to. Only a release arriving from THAT
|
|
118
|
+
* chat and THAT sender can resolve it (see classifyRelease) -- a request's
|
|
119
|
+
* plaintext id is visible to every current member of the chat it's sent
|
|
120
|
+
* into (see actions.ts), so the id alone must never be sufficient to claim
|
|
121
|
+
* a release.
|
|
122
|
+
*
|
|
123
|
+
* Resolves with that release's parsed body, or rejects once `timeoutMs`
|
|
124
|
+
* elapses -- rejecting is an expected outcome, not a protocol error:
|
|
125
|
+
* PROTOCOL.md says the phone only answers when the app is next open, which
|
|
126
|
+
* routinely outlasts one webhook round-trip. Throws synchronously (before
|
|
127
|
+
* any caller does anything else) if `id` already has a pending wait.
|
|
128
|
+
*/
|
|
129
|
+
export declare function register(id: string, binding: RegisterBinding): Promise<ReleaseBody>;
|
|
130
|
+
/**
|
|
131
|
+
* Clears a pending wait without settling its promise -- used when sending
|
|
132
|
+
* the request message itself fails right after register() ran, so the
|
|
133
|
+
* registry entry doesn't leak (the caller throws its own error instead).
|
|
134
|
+
*/
|
|
135
|
+
export declare function cancel(id: string): void;
|
|
136
|
+
type ReleaseHandler = (release: LatticeRelease) => void | Promise<void>;
|
|
137
|
+
/**
|
|
138
|
+
* Subscribes to releases that arrive with nothing waiting on them: a late
|
|
139
|
+
* reply (the request already timed out) or a standing push (there was
|
|
140
|
+
* never a request to begin with). Returns an unsubscribe function.
|
|
141
|
+
*
|
|
142
|
+
* UNVERIFIED: lattice.ts has no REST client and no concept of a grant, so a
|
|
143
|
+
* handler here fires for ANY sender in ANY chat with no check that they
|
|
144
|
+
* actually hold a live grant to this agent. webhook.ts's `onLatticeRelease`
|
|
145
|
+
* option is the verified, recommended path for exactly this case (it
|
|
146
|
+
* fetches this agent's live grants and checks the sender is human and,
|
|
147
|
+
* for a standing push, that `grant_id` names one, before ever calling your
|
|
148
|
+
* handler) -- reach for this lower-level hook only if you're bypassing
|
|
149
|
+
* webhook.ts entirely, and do your own equivalent check.
|
|
150
|
+
*
|
|
151
|
+
* A handler may be async. Either a synchronous throw or a rejected promise
|
|
152
|
+
* is swallowed -- like every other fire-and-forget hook in this SDK, a bug
|
|
153
|
+
* in a consumer's handler must not take down webhook processing (an
|
|
154
|
+
* unhandled rejection crashes the process on modern Node defaults).
|
|
155
|
+
*/
|
|
156
|
+
export declare function onRelease(handler: ReleaseHandler): () => void;
|
|
157
|
+
export type ReleaseOutcome = {
|
|
158
|
+
kind: "not-a-release";
|
|
159
|
+
} | {
|
|
160
|
+
kind: "matched";
|
|
161
|
+
} | {
|
|
162
|
+
kind: "refused";
|
|
163
|
+
} | {
|
|
164
|
+
kind: "unmatched";
|
|
165
|
+
release: LatticeRelease;
|
|
166
|
+
};
|
|
167
|
+
/**
|
|
168
|
+
* Call right after decrypting an inbound message, before deciding whether
|
|
169
|
+
* to run a fresh reply cycle -- the same spot webhook.ts calls
|
|
170
|
+
* delegations.resolveIfPending (and what webhook.ts itself calls, to also
|
|
171
|
+
* learn about an "unmatched" release for its onLatticeRelease option).
|
|
172
|
+
*
|
|
173
|
+
* - "not-a-release": `plaintext` isn't lattice wire protocol at all --
|
|
174
|
+
* including this identity's own outgoing requests/proposals, which never
|
|
175
|
+
* match RELEASE_MARKER_RE, and any genuinely unrelated message.
|
|
176
|
+
* - "matched": `chatId`/`senderId` agree with a live register() wait for
|
|
177
|
+
* this release's `request_id` -- that wait's promise is resolved directly;
|
|
178
|
+
* there is nothing further for a caller to do.
|
|
179
|
+
* - "refused": this release names a request id a wait IS pending for, but
|
|
180
|
+
* `chatId`/`senderId` don't match what register() bound it to -- e.g. a
|
|
181
|
+
* bystander who merely saw the plaintext request id (see
|
|
182
|
+
* RegisterBinding's doc comment) replaying it as a forged release. The
|
|
183
|
+
* live wait is untouched (still running, still resolvable by the real
|
|
184
|
+
* answer); this message is left for the caller to process as ordinary,
|
|
185
|
+
* harmless text -- it must NOT be treated as Lattice traffic.
|
|
186
|
+
* - "unmatched": a genuine late reply or standing push -- fired to
|
|
187
|
+
* onRelease() before this returns.
|
|
188
|
+
*/
|
|
189
|
+
export declare function classifyRelease(chatId: SaltId, senderId: SaltId, plaintext: string): ReleaseOutcome;
|
|
190
|
+
/**
|
|
191
|
+
* Boolean convenience wrapper over classifyRelease, mirroring
|
|
192
|
+
* delegations.resolveIfPending(chatId, senderId, plaintext)'s shape for a
|
|
193
|
+
* simple caller that doesn't need an "unmatched" release's details (e.g. a
|
|
194
|
+
* custom integration built directly on lattice.ts, without webhook.ts).
|
|
195
|
+
* True for "matched" and "unmatched" (don't treat `plaintext` as a fresh
|
|
196
|
+
* prompt); false for "not-a-release" AND "refused" (a forged/misdirected
|
|
197
|
+
* release is left to fall through exactly like ordinary text, same as
|
|
198
|
+
* "not-a-release" -- see classifyRelease's doc comment).
|
|
199
|
+
*
|
|
200
|
+
* webhook.ts itself calls classifyRelease directly instead of this, since
|
|
201
|
+
* it also needs an "unmatched" release's details (chat/sender/body) to
|
|
202
|
+
* offer to its own onLatticeRelease option.
|
|
203
|
+
*/
|
|
204
|
+
export declare function resolveIfPending(chatId: SaltId, senderId: SaltId, plaintext: string): boolean;
|
|
205
|
+
export {};
|
|
206
|
+
//# sourceMappingURL=lattice.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lattice.d.ts","sourceRoot":"","sources":["../src/lattice.ts"],"names":[],"mappings":"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"}
|
package/dist/lattice.js
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Lets a hosted identity ask the person it's chatting with for personal
|
|
3
|
+
// facts from Lattice -- their private, on-device knowledge graph -- and get
|
|
4
|
+
// an answer back over a real Salt message, the same way delegations.ts gets
|
|
5
|
+
// a reply from another agent. See ../../salt-lattice/docs/PROTOCOL.md for
|
|
6
|
+
// the wire contract this implements; nothing here decides WHETHER a fact is
|
|
7
|
+
// released (that is entirely the phone's own grant evaluation, offline and
|
|
8
|
+
// invisible to the server) -- this module only builds the outgoing
|
|
9
|
+
// markers, parses the incoming one, and matches a release back to the
|
|
10
|
+
// request it answers.
|
|
11
|
+
//
|
|
12
|
+
// Three message shapes ride inside encrypted plaintext, one line then a
|
|
13
|
+
// JSON body, exactly like [[SALT-DELEGATION]]:
|
|
14
|
+
// [[SALT-LATTICE-REQUEST id=<ulid>]] agent -> person, asking
|
|
15
|
+
// [[SALT-LATTICE-RELEASE id=<ulid> [standing=<grant id>]]] person's phone -> agent, answering
|
|
16
|
+
// [[SALT-LATTICE-PROPOSE id=<ulid>]] agent -> person's phone, suggesting a fact
|
|
17
|
+
//
|
|
18
|
+
// A release is matched back to its request by `request_id` IN ITS JSON BODY
|
|
19
|
+
// -- never by the release's own `id`, which only identifies that one
|
|
20
|
+
// disclosure for the log -- AND by the chat and sender it was actually
|
|
21
|
+
// registered against (see register()/classifyRelease()). A request's
|
|
22
|
+
// plaintext id is visible to every current member of whatever chat it was
|
|
23
|
+
// sent into (see actions.ts's request_personal_data), so a request id alone
|
|
24
|
+
// is not a secret; the chat+sender binding is what stops a bystander who
|
|
25
|
+
// merely SAW that id from forging a release and having it accepted as the
|
|
26
|
+
// real recipient's answer.
|
|
27
|
+
//
|
|
28
|
+
// Three outcomes a release-shaped message can produce, besides "not a
|
|
29
|
+
// release at all" (see ReleaseOutcome/classifyRelease):
|
|
30
|
+
// - matched: chat and sender agree with what register() bound to this
|
|
31
|
+
// request id. Resolves that wait's promise directly; nothing else to do.
|
|
32
|
+
// - refused: names a request id this process really is waiting on, but
|
|
33
|
+
// the chat or the sender don't match the binding -- a forged or
|
|
34
|
+
// misdirected release. The live wait keeps waiting; this message is
|
|
35
|
+
// left for the caller to fall through as ordinary (harmless) text.
|
|
36
|
+
// - unmatched (late or standing): a release-shaped message with no live
|
|
37
|
+
// wait to resolve -- either a genuinely late reply (the request already
|
|
38
|
+
// timed out; the phone only answers when the app is next open, which
|
|
39
|
+
// routinely outlasts one webhook round-trip) or an opted-in standing
|
|
40
|
+
// push, which never had a request to begin with. Unlike "matched",
|
|
41
|
+
// THIS module never authenticates who sent it -- lattice.ts has no
|
|
42
|
+
// REST client and no concept of a grant. Reaches onRelease() (raw,
|
|
43
|
+
// unverified) and, via webhook.ts's onLatticeRelease option, a
|
|
44
|
+
// consumer's own follow-up logic -- webhook.ts is what verifies the
|
|
45
|
+
// sender is human and holds a live grant (and, for standing, that it's
|
|
46
|
+
// the grant named) before that option ever fires, dropping and logging
|
|
47
|
+
// otherwise. Reaching onRelease/onLatticeRelease at all is not itself a
|
|
48
|
+
// trust signal.
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.MAX_FACT_VALUE_LENGTH = exports.MAX_FACTS_PER_RELEASE = exports.PROPOSE_MARKER_RE = exports.RELEASE_MARKER_RE = exports.REQUEST_MARKER_RE = exports.LATTICE_REQUEST_TIMEOUT_MS = void 0;
|
|
51
|
+
exports.buildRequest = buildRequest;
|
|
52
|
+
exports.buildProposal = buildProposal;
|
|
53
|
+
exports.parseRelease = parseRelease;
|
|
54
|
+
exports.hasPending = hasPending;
|
|
55
|
+
exports.register = register;
|
|
56
|
+
exports.cancel = cancel;
|
|
57
|
+
exports.onRelease = onRelease;
|
|
58
|
+
exports.classifyRelease = classifyRelease;
|
|
59
|
+
exports.resolveIfPending = resolveIfPending;
|
|
60
|
+
const ids_js_1 = require("./ids.js");
|
|
61
|
+
/**
|
|
62
|
+
* How long request_personal_data waits for a release before reporting
|
|
63
|
+
* "pending" instead of "released". This bounds how long ONE chat turn keeps
|
|
64
|
+
* whoever's waiting on the agent hanging -- it is NOT protecting against
|
|
65
|
+
* Salt's own webhook delivery timeout: webhook.ts acknowledges salt-api's
|
|
66
|
+
* POST before ever calling dispatch(), so nothing here is on the clock for
|
|
67
|
+
* that deadline. A "pending" result past this is the normal case, not an
|
|
68
|
+
* error -- see actions.ts's request_personal_data and onRelease/
|
|
69
|
+
* onLatticeRelease for what happens when the answer arrives afterward.
|
|
70
|
+
*/
|
|
71
|
+
exports.LATTICE_REQUEST_TIMEOUT_MS = 15_000;
|
|
72
|
+
// Embed ULID_RE's character class without its ^...$ anchors, so the id
|
|
73
|
+
// group inside each marker regex stays in lock-step with what newUlid()
|
|
74
|
+
// actually produces.
|
|
75
|
+
const ULID_SRC = ids_js_1.ULID_RE.source.slice(1, -1);
|
|
76
|
+
exports.REQUEST_MARKER_RE = new RegExp(`^\\[\\[SALT-LATTICE-REQUEST id=(${ULID_SRC})\\]\\]\\n`, "i");
|
|
77
|
+
exports.RELEASE_MARKER_RE = new RegExp(`^\\[\\[SALT-LATTICE-RELEASE id=(${ULID_SRC})(?: standing=(\\S+))?\\]\\]\\n`, "i");
|
|
78
|
+
exports.PROPOSE_MARKER_RE = new RegExp(`^\\[\\[SALT-LATTICE-PROPOSE id=(${ULID_SRC})\\]\\]\\n`, "i");
|
|
79
|
+
/**
|
|
80
|
+
* Mints a fresh request id and its wire text. Send `text` as an ordinary
|
|
81
|
+
* encrypted chat message into the current chat (or the agent's private
|
|
82
|
+
* lane); the phone answers it -- in a group, inside a sidechain it opens
|
|
83
|
+
* with this agent, never in the room (PROTOCOL.md R6).
|
|
84
|
+
*/
|
|
85
|
+
function buildRequest(input) {
|
|
86
|
+
const id = (0, ids_js_1.newUlid)();
|
|
87
|
+
const body = JSON.stringify({ purpose: input.purpose, asks: input.asks });
|
|
88
|
+
return { id, text: `[[SALT-LATTICE-REQUEST id=${id}]]\n${body}` };
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Builds a [[SALT-LATTICE-PROPOSE]] message suggesting new facts. Always
|
|
92
|
+
* lands `pending` on the phone unless the agent's grant trusts its writes
|
|
93
|
+
* to that compartment (PROTOCOL.md R3) -- there is no reply to wait for,
|
|
94
|
+
* so unlike buildRequest this returns only the wire text.
|
|
95
|
+
*/
|
|
96
|
+
function buildProposal(proposals) {
|
|
97
|
+
const id = (0, ids_js_1.newUlid)();
|
|
98
|
+
const body = JSON.stringify({ proposals });
|
|
99
|
+
return `[[SALT-LATTICE-PROPOSE id=${id}]]\n${body}`;
|
|
100
|
+
}
|
|
101
|
+
const FACT_AUTHORS = new Set(["you", "agent"]);
|
|
102
|
+
// PROTOCOL.md's exact fact shape. Validated field-by-field, not just "facts
|
|
103
|
+
// is an array": a forged or buggy release could otherwise hand a model
|
|
104
|
+
// whatever shape it likes under `facts[]`, and (pre-binding-fix) that used
|
|
105
|
+
// to reach a calling tool's "released" result unfiltered. One malformed
|
|
106
|
+
// entry rejects the WHOLE body (returns null), the same fail-closed
|
|
107
|
+
// convention as an unparseable body -- a partially-trusted release is worse
|
|
108
|
+
// than a dropped one.
|
|
109
|
+
function isPrimitive(value) {
|
|
110
|
+
return value === null || typeof value === "string" || typeof value === "number" || typeof value === "boolean";
|
|
111
|
+
}
|
|
112
|
+
/** A single release's fact count is capped here -- not rejected outright,
|
|
113
|
+
* just bounded, since an over-long but otherwise well-formed release isn't
|
|
114
|
+
* a protocol violation the way a malformed entry is (see normalizeFact). */
|
|
115
|
+
exports.MAX_FACTS_PER_RELEASE = 200;
|
|
116
|
+
/** A fact's string value is capped to this many characters, after marker
|
|
117
|
+
* stripping (see sanitizeFactValue) -- bounds how much untrusted text from
|
|
118
|
+
* the other end of the wire can reach a model in one fact. */
|
|
119
|
+
exports.MAX_FACT_VALUE_LENGTH = 2_000;
|
|
120
|
+
// Every wire marker this SDK recognizes starts with this exact two-bracket
|
|
121
|
+
// prefix, anchored at the very start of a plaintext (see the *_MARKER_RE
|
|
122
|
+
// definitions above -- none of them carry the `m` flag). A fact's value is
|
|
123
|
+
// untrusted content from the other end of the wire; without this, a value
|
|
124
|
+
// containing literal "[[SALT-...]]" text could later start some OTHER
|
|
125
|
+
// outbound message built by echoing the fact back (e.g. "the person's
|
|
126
|
+
// favorite cuisine is <value>") and be mistaken for a genuine protocol
|
|
127
|
+
// marker by whatever receives it. Breaks the bracket pair rather than
|
|
128
|
+
// deleting the text outright, so the value stays legible.
|
|
129
|
+
const MARKER_TEXT_RE = /\[\[SALT-/g;
|
|
130
|
+
function sanitizeFactValue(value) {
|
|
131
|
+
if (typeof value !== "string")
|
|
132
|
+
return value;
|
|
133
|
+
const stripped = value.replace(MARKER_TEXT_RE, "[SALT-");
|
|
134
|
+
return stripped.length > exports.MAX_FACT_VALUE_LENGTH ? stripped.slice(0, exports.MAX_FACT_VALUE_LENGTH) : stripped;
|
|
135
|
+
}
|
|
136
|
+
function normalizeFact(raw) {
|
|
137
|
+
if (!raw || typeof raw !== "object")
|
|
138
|
+
return null;
|
|
139
|
+
const f = raw;
|
|
140
|
+
if (typeof f.path !== "string" || typeof f.type !== "string" || typeof f.field !== "string")
|
|
141
|
+
return null;
|
|
142
|
+
if (typeof f.author !== "string" || !FACT_AUTHORS.has(f.author))
|
|
143
|
+
return null;
|
|
144
|
+
if (typeof f.updated !== "number")
|
|
145
|
+
return null;
|
|
146
|
+
if (!isPrimitive(f.value))
|
|
147
|
+
return null;
|
|
148
|
+
return { path: f.path, type: f.type, field: f.field, value: sanitizeFactValue(f.value), author: f.author, updated: f.updated };
|
|
149
|
+
}
|
|
150
|
+
function normalizeReleaseBody(parsed) {
|
|
151
|
+
if (!parsed || typeof parsed !== "object")
|
|
152
|
+
return null;
|
|
153
|
+
const obj = parsed;
|
|
154
|
+
if (!Array.isArray(obj.facts))
|
|
155
|
+
return null;
|
|
156
|
+
const facts = [];
|
|
157
|
+
for (const raw of obj.facts) {
|
|
158
|
+
const fact = normalizeFact(raw);
|
|
159
|
+
if (!fact)
|
|
160
|
+
return null;
|
|
161
|
+
facts.push(fact);
|
|
162
|
+
}
|
|
163
|
+
const body = { facts: facts.slice(0, exports.MAX_FACTS_PER_RELEASE) };
|
|
164
|
+
if (typeof obj.request_id === "string")
|
|
165
|
+
body.request_id = obj.request_id;
|
|
166
|
+
if (typeof obj.grant_id === "string")
|
|
167
|
+
body.grant_id = obj.grant_id;
|
|
168
|
+
if (typeof obj.since_seq === "number")
|
|
169
|
+
body.since_seq = obj.since_seq;
|
|
170
|
+
return body;
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Splits an incoming plaintext into its release marker's id, optional
|
|
174
|
+
* standing grant id, and parsed JSON body -- or null when `plaintext` isn't
|
|
175
|
+
* a (well-formed, in-protocol) lattice release at all. Returns null for an
|
|
176
|
+
* unparseable or malformed body, and also for a body that is neither an
|
|
177
|
+
* ordinary reply (`request_id`) nor a standing push (`standing=` on the
|
|
178
|
+
* marker line AND `grant_id` in the body) -- PROTOCOL.md says a release is
|
|
179
|
+
* "always a reply to a request id" unless it's a standing push, so anything
|
|
180
|
+
* else is out-of-protocol. Deliberate in all these cases: it's safer to let
|
|
181
|
+
* a corrupt or nonsensical release fall through as ordinary (harmless)
|
|
182
|
+
* message text than to silently act on it. A standing push's marker-line
|
|
183
|
+
* `standing=<grant id>` and its body's `grant_id` must name the SAME grant
|
|
184
|
+
* -- PROTOCOL.md's own example shows them matching, and disagreeing values
|
|
185
|
+
* are simply invalid rather than a case to guess between (whoever
|
|
186
|
+
* eventually checks `grant_id` against this agent's actual grants -- see
|
|
187
|
+
* webhook.ts's onLatticeRelease verification -- must be checking the one
|
|
188
|
+
* value the marker itself also claims).
|
|
189
|
+
*/
|
|
190
|
+
function parseRelease(plaintext) {
|
|
191
|
+
const match = exports.RELEASE_MARKER_RE.exec(plaintext);
|
|
192
|
+
if (!match)
|
|
193
|
+
return null;
|
|
194
|
+
const [full, id, standing] = match;
|
|
195
|
+
let parsed;
|
|
196
|
+
try {
|
|
197
|
+
parsed = JSON.parse(plaintext.slice(full.length));
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
const body = normalizeReleaseBody(parsed);
|
|
203
|
+
if (!body)
|
|
204
|
+
return null;
|
|
205
|
+
if (standing) {
|
|
206
|
+
if (!body.grant_id || !(0, ids_js_1.sameId)(body.grant_id, standing))
|
|
207
|
+
return null;
|
|
208
|
+
return { id, standing, body };
|
|
209
|
+
}
|
|
210
|
+
if (!body.request_id)
|
|
211
|
+
return null;
|
|
212
|
+
return { id, body };
|
|
213
|
+
}
|
|
214
|
+
// Keyed by REQUEST id (the id a request_personal_data call minted and put
|
|
215
|
+
// in the marker it sent) -- NOT by chat, unlike delegations.ts's registry,
|
|
216
|
+
// which is chat-scoped because a chat can only be mid-delegation with one
|
|
217
|
+
// target at a time. A person can plausibly be asked several independent
|
|
218
|
+
// things in parallel (different tool calls, possibly from different hosted
|
|
219
|
+
// identities sharing this process), so the request id is what safely tells
|
|
220
|
+
// two pending waits apart.
|
|
221
|
+
//
|
|
222
|
+
// Lowercased on every store/lookup -- like delegations.ts's own `mapKey` and
|
|
223
|
+
// ids.ts's `sameId`, whose comments say why: an id can cross this SDK's
|
|
224
|
+
// boundary (webhook body, REST response, a phone's own JSON) without a
|
|
225
|
+
// casing guarantee, and RELEASE_MARKER_RE already matches either case
|
|
226
|
+
// (ULID_RE's `/i` flag), so the map lookup that follows it must too.
|
|
227
|
+
const pending = new Map();
|
|
228
|
+
const mapKey = (id) => id.toLowerCase();
|
|
229
|
+
function hasPending(id) {
|
|
230
|
+
return pending.has(mapKey(id));
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Registers a wait for the release answering request `id`, bound to the
|
|
234
|
+
* exact chat and person it was sent to. Only a release arriving from THAT
|
|
235
|
+
* chat and THAT sender can resolve it (see classifyRelease) -- a request's
|
|
236
|
+
* plaintext id is visible to every current member of the chat it's sent
|
|
237
|
+
* into (see actions.ts), so the id alone must never be sufficient to claim
|
|
238
|
+
* a release.
|
|
239
|
+
*
|
|
240
|
+
* Resolves with that release's parsed body, or rejects once `timeoutMs`
|
|
241
|
+
* elapses -- rejecting is an expected outcome, not a protocol error:
|
|
242
|
+
* PROTOCOL.md says the phone only answers when the app is next open, which
|
|
243
|
+
* routinely outlasts one webhook round-trip. Throws synchronously (before
|
|
244
|
+
* any caller does anything else) if `id` already has a pending wait.
|
|
245
|
+
*/
|
|
246
|
+
function register(id, binding) {
|
|
247
|
+
const key = mapKey(id);
|
|
248
|
+
if (pending.has(key)) {
|
|
249
|
+
throw new Error("Already waiting on a release for this request.");
|
|
250
|
+
}
|
|
251
|
+
return new Promise((resolve, reject) => {
|
|
252
|
+
const timer = setTimeout(() => {
|
|
253
|
+
pending.delete(key);
|
|
254
|
+
reject(new Error(`No release within ${Math.round(binding.timeoutMs / 1000)}s.`));
|
|
255
|
+
}, binding.timeoutMs);
|
|
256
|
+
pending.set(key, { chatId: binding.chatId, senderId: binding.senderId, resolve, reject, timer });
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Clears a pending wait without settling its promise -- used when sending
|
|
261
|
+
* the request message itself fails right after register() ran, so the
|
|
262
|
+
* registry entry doesn't leak (the caller throws its own error instead).
|
|
263
|
+
*/
|
|
264
|
+
function cancel(id) {
|
|
265
|
+
const key = mapKey(id);
|
|
266
|
+
const entry = pending.get(key);
|
|
267
|
+
if (!entry)
|
|
268
|
+
return;
|
|
269
|
+
clearTimeout(entry.timer);
|
|
270
|
+
pending.delete(key);
|
|
271
|
+
}
|
|
272
|
+
const releaseHandlers = new Set();
|
|
273
|
+
/**
|
|
274
|
+
* Subscribes to releases that arrive with nothing waiting on them: a late
|
|
275
|
+
* reply (the request already timed out) or a standing push (there was
|
|
276
|
+
* never a request to begin with). Returns an unsubscribe function.
|
|
277
|
+
*
|
|
278
|
+
* UNVERIFIED: lattice.ts has no REST client and no concept of a grant, so a
|
|
279
|
+
* handler here fires for ANY sender in ANY chat with no check that they
|
|
280
|
+
* actually hold a live grant to this agent. webhook.ts's `onLatticeRelease`
|
|
281
|
+
* option is the verified, recommended path for exactly this case (it
|
|
282
|
+
* fetches this agent's live grants and checks the sender is human and,
|
|
283
|
+
* for a standing push, that `grant_id` names one, before ever calling your
|
|
284
|
+
* handler) -- reach for this lower-level hook only if you're bypassing
|
|
285
|
+
* webhook.ts entirely, and do your own equivalent check.
|
|
286
|
+
*
|
|
287
|
+
* A handler may be async. Either a synchronous throw or a rejected promise
|
|
288
|
+
* is swallowed -- like every other fire-and-forget hook in this SDK, a bug
|
|
289
|
+
* in a consumer's handler must not take down webhook processing (an
|
|
290
|
+
* unhandled rejection crashes the process on modern Node defaults).
|
|
291
|
+
*/
|
|
292
|
+
function onRelease(handler) {
|
|
293
|
+
releaseHandlers.add(handler);
|
|
294
|
+
return () => releaseHandlers.delete(handler);
|
|
295
|
+
}
|
|
296
|
+
function fireOnRelease(release) {
|
|
297
|
+
for (const handler of releaseHandlers) {
|
|
298
|
+
Promise.resolve()
|
|
299
|
+
.then(() => handler(release))
|
|
300
|
+
.catch(() => {
|
|
301
|
+
// see onRelease's doc comment
|
|
302
|
+
});
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* Call right after decrypting an inbound message, before deciding whether
|
|
307
|
+
* to run a fresh reply cycle -- the same spot webhook.ts calls
|
|
308
|
+
* delegations.resolveIfPending (and what webhook.ts itself calls, to also
|
|
309
|
+
* learn about an "unmatched" release for its onLatticeRelease option).
|
|
310
|
+
*
|
|
311
|
+
* - "not-a-release": `plaintext` isn't lattice wire protocol at all --
|
|
312
|
+
* including this identity's own outgoing requests/proposals, which never
|
|
313
|
+
* match RELEASE_MARKER_RE, and any genuinely unrelated message.
|
|
314
|
+
* - "matched": `chatId`/`senderId` agree with a live register() wait for
|
|
315
|
+
* this release's `request_id` -- that wait's promise is resolved directly;
|
|
316
|
+
* there is nothing further for a caller to do.
|
|
317
|
+
* - "refused": this release names a request id a wait IS pending for, but
|
|
318
|
+
* `chatId`/`senderId` don't match what register() bound it to -- e.g. a
|
|
319
|
+
* bystander who merely saw the plaintext request id (see
|
|
320
|
+
* RegisterBinding's doc comment) replaying it as a forged release. The
|
|
321
|
+
* live wait is untouched (still running, still resolvable by the real
|
|
322
|
+
* answer); this message is left for the caller to process as ordinary,
|
|
323
|
+
* harmless text -- it must NOT be treated as Lattice traffic.
|
|
324
|
+
* - "unmatched": a genuine late reply or standing push -- fired to
|
|
325
|
+
* onRelease() before this returns.
|
|
326
|
+
*/
|
|
327
|
+
function classifyRelease(chatId, senderId, plaintext) {
|
|
328
|
+
const parsed = parseRelease(plaintext);
|
|
329
|
+
if (!parsed)
|
|
330
|
+
return { kind: "not-a-release" };
|
|
331
|
+
if (!parsed.standing) {
|
|
332
|
+
const key = mapKey(parsed.body.request_id); // parseRelease guarantees request_id is set for a non-standing release
|
|
333
|
+
const entry = pending.get(key);
|
|
334
|
+
if (entry) {
|
|
335
|
+
if ((0, ids_js_1.sameId)(entry.chatId, chatId) && (0, ids_js_1.sameId)(entry.senderId, senderId)) {
|
|
336
|
+
clearTimeout(entry.timer);
|
|
337
|
+
pending.delete(key);
|
|
338
|
+
entry.resolve(parsed.body);
|
|
339
|
+
return { kind: "matched" };
|
|
340
|
+
}
|
|
341
|
+
return { kind: "refused" };
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
const release = { id: parsed.id, standing: parsed.standing, chatId, senderId, body: parsed.body };
|
|
345
|
+
fireOnRelease(release);
|
|
346
|
+
return { kind: "unmatched", release };
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Boolean convenience wrapper over classifyRelease, mirroring
|
|
350
|
+
* delegations.resolveIfPending(chatId, senderId, plaintext)'s shape for a
|
|
351
|
+
* simple caller that doesn't need an "unmatched" release's details (e.g. a
|
|
352
|
+
* custom integration built directly on lattice.ts, without webhook.ts).
|
|
353
|
+
* True for "matched" and "unmatched" (don't treat `plaintext` as a fresh
|
|
354
|
+
* prompt); false for "not-a-release" AND "refused" (a forged/misdirected
|
|
355
|
+
* release is left to fall through exactly like ordinary text, same as
|
|
356
|
+
* "not-a-release" -- see classifyRelease's doc comment).
|
|
357
|
+
*
|
|
358
|
+
* webhook.ts itself calls classifyRelease directly instead of this, since
|
|
359
|
+
* it also needs an "unmatched" release's details (chat/sender/body) to
|
|
360
|
+
* offer to its own onLatticeRelease option.
|
|
361
|
+
*/
|
|
362
|
+
function resolveIfPending(chatId, senderId, plaintext) {
|
|
363
|
+
const outcome = classifyRelease(chatId, senderId, plaintext);
|
|
364
|
+
return outcome.kind === "matched" || outcome.kind === "unmatched";
|
|
365
|
+
}
|
|
366
|
+
//# sourceMappingURL=lattice.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"lattice.js","sourceRoot":"","sources":["../src/lattice.ts"],"names":[],"mappings":"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"}
|