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/delegations.js
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
// only channel available between two separately-hosted agents is the
|
|
19
19
|
// message text itself), and `register`'s timeout bounds each hop.
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.DELEGATION_TIMEOUT_MS = exports.MAX_DELEGATION_DEPTH = void 0;
|
|
21
|
+
exports.FLOOR_REQUEST_MARKER = exports.DELEGATION_TIMEOUT_MS = exports.MAX_DELEGATION_DEPTH = void 0;
|
|
22
22
|
exports.wrap = wrap;
|
|
23
23
|
exports.parseIncoming = parseIncoming;
|
|
24
24
|
exports.hasPending = hasPending;
|
|
@@ -27,6 +27,11 @@ exports.cancel = cancel;
|
|
|
27
27
|
exports.resolveIfPending = resolveIfPending;
|
|
28
28
|
exports.recordTrail = recordTrail;
|
|
29
29
|
exports.drainTrail = drainTrail;
|
|
30
|
+
exports.wrapConsult = wrapConsult;
|
|
31
|
+
exports.stripConsultMarker = stripConsultMarker;
|
|
32
|
+
exports.registerConsultAsker = registerConsultAsker;
|
|
33
|
+
exports.consultAskerFor = consultAskerFor;
|
|
34
|
+
const ids_js_1 = require("./ids.js");
|
|
30
35
|
/** depth counts hops already taken; a call at depth >= this is refused, so a
|
|
31
36
|
* chain reaches at most MAX_DELEGATION_DEPTH+1 agents before the last one
|
|
32
37
|
* is forced to answer directly instead of delegating further. */
|
|
@@ -62,9 +67,12 @@ function parseIncoming(plaintext) {
|
|
|
62
67
|
// concurrent delegation call into the same chat is a clean error (see
|
|
63
68
|
// register below) rather than an ambiguous race over which reply belongs
|
|
64
69
|
// to which caller.
|
|
70
|
+
// Keyed by the lowercased chat id -- see identities.ts for why ids are
|
|
71
|
+
// normalised before they are used as map keys.
|
|
65
72
|
const pending = new Map();
|
|
73
|
+
const mapKey = (id) => String(id).toLowerCase();
|
|
66
74
|
function hasPending(chatId) {
|
|
67
|
-
return pending.has(chatId);
|
|
75
|
+
return pending.has(mapKey(chatId));
|
|
68
76
|
}
|
|
69
77
|
/**
|
|
70
78
|
* Registers a wait for the next reply in `chatId` from `targetId`, and
|
|
@@ -73,15 +81,15 @@ function hasPending(chatId) {
|
|
|
73
81
|
* if this chat already has a pending wait.
|
|
74
82
|
*/
|
|
75
83
|
function register(chatId, targetId, timeoutMs) {
|
|
76
|
-
if (pending.has(chatId)) {
|
|
84
|
+
if (pending.has(mapKey(chatId))) {
|
|
77
85
|
throw new Error("Already waiting on a reply from this agent in this chat -- wait for that to finish first.");
|
|
78
86
|
}
|
|
79
87
|
return new Promise((resolve, reject) => {
|
|
80
88
|
const timer = setTimeout(() => {
|
|
81
|
-
pending.delete(chatId);
|
|
89
|
+
pending.delete(mapKey(chatId));
|
|
82
90
|
reject(new Error(`No reply within ${Math.round(timeoutMs / 1000)}s -- the agent may be offline or slow.`));
|
|
83
91
|
}, timeoutMs);
|
|
84
|
-
pending.set(chatId, { targetId, resolve, reject, timer });
|
|
92
|
+
pending.set(mapKey(chatId), { targetId, resolve, reject, timer });
|
|
85
93
|
});
|
|
86
94
|
}
|
|
87
95
|
/**
|
|
@@ -90,11 +98,11 @@ function register(chatId, targetId, timeoutMs) {
|
|
|
90
98
|
* registry entry doesn't leak (the caller throws its own error instead).
|
|
91
99
|
*/
|
|
92
100
|
function cancel(chatId) {
|
|
93
|
-
const entry = pending.get(chatId);
|
|
101
|
+
const entry = pending.get(mapKey(chatId));
|
|
94
102
|
if (!entry)
|
|
95
103
|
return;
|
|
96
104
|
clearTimeout(entry.timer);
|
|
97
|
-
pending.delete(chatId);
|
|
105
|
+
pending.delete(mapKey(chatId));
|
|
98
106
|
}
|
|
99
107
|
/**
|
|
100
108
|
* Call right after decrypting an inbound message, before deciding whether
|
|
@@ -106,11 +114,16 @@ function cancel(chatId) {
|
|
|
106
114
|
* entry on its own server.
|
|
107
115
|
*/
|
|
108
116
|
function resolveIfPending(chatId, senderId, plaintext) {
|
|
109
|
-
const entry = pending.get(chatId);
|
|
110
|
-
|
|
117
|
+
const entry = pending.get(mapKey(chatId));
|
|
118
|
+
// sameId, not `!==`: this decides whether an inbound message is THE reply
|
|
119
|
+
// being waited on. Comparing a uuid that came from a webhook body against one
|
|
120
|
+
// that came from a REST response is not guaranteed to match on casing, and a
|
|
121
|
+
// false negative here restarts the whole prompt cycle instead of completing
|
|
122
|
+
// the delegation.
|
|
123
|
+
if (!entry || !(0, ids_js_1.sameId)(entry.targetId, senderId))
|
|
111
124
|
return false;
|
|
112
125
|
clearTimeout(entry.timer);
|
|
113
|
-
pending.delete(chatId);
|
|
126
|
+
pending.delete(mapKey(chatId));
|
|
114
127
|
entry.resolve(plaintext);
|
|
115
128
|
return true;
|
|
116
129
|
}
|
|
@@ -123,7 +136,7 @@ function resolveIfPending(chatId, senderId, plaintext) {
|
|
|
123
136
|
// identities) never mix their trails.
|
|
124
137
|
const trails = new Map();
|
|
125
138
|
function trailKey(identityId, mainChatId) {
|
|
126
|
-
return `${identityId}:${mainChatId}`;
|
|
139
|
+
return `${mapKey(identityId)}:${mapKey(mainChatId)}`;
|
|
127
140
|
}
|
|
128
141
|
function recordTrail(identityId, mainChatId, entry) {
|
|
129
142
|
const key = trailKey(identityId, mainChatId);
|
|
@@ -137,4 +150,47 @@ function drainTrail(identityId, mainChatId) {
|
|
|
137
150
|
trails.delete(key);
|
|
138
151
|
return entries;
|
|
139
152
|
}
|
|
153
|
+
// --- Consult lanes ---------------------------------------------------------
|
|
154
|
+
//
|
|
155
|
+
// A consult is a delegation that happens INLINE, in a lane off a chat both
|
|
156
|
+
// parties are already in (actions.ts's consult_agent), rather than in a
|
|
157
|
+
// separate 1:1 (delegate_to_agent). The reply-matching above (register/
|
|
158
|
+
// resolveIfPending) is reused as-is -- consult_agent registers a pending
|
|
159
|
+
// wait on the lane's own chat id exactly like delegate_to_agent does on a
|
|
160
|
+
// delegation chat's id. What's new is the wire marker the CONSULT PROMPT
|
|
161
|
+
// itself carries (stripped before the consulted agent's onMessage ever
|
|
162
|
+
// sees it, same convention as the depth marker above), and a small
|
|
163
|
+
// registry so the asking agent's OWN webhook.ts recognizes a request_floor
|
|
164
|
+
// message arriving back in a lane it opened.
|
|
165
|
+
const CONSULT_MARKER_RE = /^\[\[SALT-CONSULT room=[^\]\n]+\]\]\n/;
|
|
166
|
+
/** Prefixes a consult prompt so the receiving end can strip it before the task text reaches that identity's agent logic. `roomId` is informational only -- the receiving side gets the authoritative room id from the lane's own `coaching_for_chat_id`, already server-verified. */
|
|
167
|
+
function wrapConsult(roomId, text) {
|
|
168
|
+
return `[[SALT-CONSULT room=${roomId}]]\n${text}`;
|
|
169
|
+
}
|
|
170
|
+
/** Strips a leading SALT-CONSULT marker, if present. A no-op on anything else (an ordinary message, or an agent's plain-text reply). */
|
|
171
|
+
function stripConsultMarker(text) {
|
|
172
|
+
return text.replace(CONSULT_MARKER_RE, "");
|
|
173
|
+
}
|
|
174
|
+
/** The exact marker request_floor (actions.ts) posts into a consult lane to ask the asker to hand off rather than keep relaying through the lane. webhook.ts treats a message starting with this as wire protocol -- never an onMessage prompt -- for whichever identity opened that lane. */
|
|
175
|
+
exports.FLOOR_REQUEST_MARKER = "[[SALT-FLOOR-REQUEST]]";
|
|
176
|
+
// laneChatId (lowercased) -> who opened it and from where. Bounded the same
|
|
177
|
+
// way webhook.ts bounds its own dedup sets: a long-lived process consults a
|
|
178
|
+
// great many lanes over time, and none of them need to be remembered once
|
|
179
|
+
// they're old enough that a floor request on them is no longer plausible.
|
|
180
|
+
const MAX_CONSULT_ASKERS = 2000;
|
|
181
|
+
const consultAskers = new Map();
|
|
182
|
+
/** Records that `askerId` opened `laneChatId` as a consult lane off `roomId`. Called by consult_agent right after the lane is opened. */
|
|
183
|
+
function registerConsultAsker(laneChatId, askerId, roomId) {
|
|
184
|
+
const key = mapKey(laneChatId);
|
|
185
|
+
consultAskers.set(key, { askerId, roomId });
|
|
186
|
+
if (consultAskers.size > MAX_CONSULT_ASKERS) {
|
|
187
|
+
const oldest = consultAskers.keys().next().value;
|
|
188
|
+
if (oldest !== undefined)
|
|
189
|
+
consultAskers.delete(oldest);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
/** Who opened `laneChatId` as a consult lane, and from where -- or undefined if this process didn't (or has forgotten). */
|
|
193
|
+
function consultAskerFor(laneChatId) {
|
|
194
|
+
return consultAskers.get(mapKey(laneChatId));
|
|
195
|
+
}
|
|
140
196
|
//# sourceMappingURL=delegations.js.map
|
package/dist/delegations.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"delegations.js","sourceRoot":"","sources":["../src/delegations.ts"],"names":[],"mappings":";AAAA,4EAA4E;AAC5E,4DAA4D;AAC5D,8EAA8E;AAC9E,EAAE;AACF,0EAA0E;AAC1E,6EAA6E;AAC7E,0EAA0E;AAC1E,6EAA6E;AAC7E,uEAAuE;AACvE,iFAAiF;AACjF,4EAA4E;AAC5E,wEAAwE;AACxE,cAAc;AACd,6EAA6E;AAC7E,yEAAyE;AACzE,2EAA2E;AAC3E,wEAAwE;AACxE,qEAAqE;;;
|
|
1
|
+
{"version":3,"file":"delegations.js","sourceRoot":"","sources":["../src/delegations.ts"],"names":[],"mappings":";AAAA,4EAA4E;AAC5E,4DAA4D;AAC5D,8EAA8E;AAC9E,EAAE;AACF,0EAA0E;AAC1E,6EAA6E;AAC7E,0EAA0E;AAC1E,6EAA6E;AAC7E,uEAAuE;AACvE,iFAAiF;AACjF,4EAA4E;AAC5E,wEAAwE;AACxE,cAAc;AACd,6EAA6E;AAC7E,yEAAyE;AACzE,2EAA2E;AAC3E,wEAAwE;AACxE,qEAAqE;;;AAsBrE,oBAEC;AASD,sCAIC;AAkBD,gCAEC;AAQD,4BAWC;AAOD,wBAKC;AAWD,4CAYC;AAuBD,kCAIC;AAED,gCAKC;AAkBD,kCAEC;AAGD,gDAEC;AAmBD,oDAOC;AAGD,0CAEC;AAvMD,qCAA+C;AAE/C;;kEAEkE;AACrD,QAAA,oBAAoB,GAAG,CAAC,CAAC;AAEtC;;gDAEgD;AACnC,QAAA,qBAAqB,GAAG,MAAM,CAAC;AAE5C,MAAM,SAAS,GAAG,wCAAwC,CAAC;AAE3D;;;;;GAKG;AACH,SAAgB,IAAI,CAAC,KAAa,EAAE,IAAY;IAC9C,OAAO,2BAA2B,KAAK,OAAO,IAAI,EAAE,CAAC;AACvD,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,aAAa,CAAC,SAAiB;IAC7C,MAAM,KAAK,GAAG,SAAS,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACxC,IAAI,CAAC,KAAK;QAAE,OAAO,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;IACjD,OAAO,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;AACnF,CAAC;AASD,0EAA0E;AAC1E,sEAAsE;AACtE,yEAAyE;AACzE,mBAAmB;AACnB,uEAAuE;AACvE,+CAA+C;AAC/C,MAAM,OAAO,GAAG,IAAI,GAAG,EAAwB,CAAC;AAChD,MAAM,MAAM,GAAG,CAAC,EAAU,EAAU,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;AAEhE,SAAgB,UAAU,CAAC,MAAc;IACvC,OAAO,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AACrC,CAAC;AAED;;;;;GAKG;AACH,SAAgB,QAAQ,CAAC,MAAc,EAAE,QAAgB,EAAE,SAAiB;IAC1E,IAAI,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,KAAK,CAAC,2FAA2F,CAAC,CAAC;IAC/G,CAAC;IACD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YAC5B,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YAC/B,MAAM,CAAC,IAAI,KAAK,CAAC,mBAAmB,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,wCAAwC,CAAC,CAAC,CAAC;QAC7G,CAAC,EAAE,SAAS,CAAC,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,CAAC;IACpE,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,SAAgB,MAAM,CAAC,MAAc;IACnC,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1C,IAAI,CAAC,KAAK;QAAE,OAAO;IACnB,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC1B,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;AACjC,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,gBAAgB,CAAC,MAAc,EAAE,QAAgB,EAAE,SAAiB;IAClF,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAC1C,0EAA0E;IAC1E,8EAA8E;IAC9E,6EAA6E;IAC7E,4EAA4E;IAC5E,kBAAkB;IAClB,IAAI,CAAC,KAAK,IAAI,CAAC,IAAA,eAAM,EAAC,KAAK,CAAC,QAAQ,EAAE,QAAQ,CAAC;QAAE,OAAO,KAAK,CAAC;IAC9D,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC1B,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IAC/B,KAAK,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACzB,OAAO,IAAI,CAAC;AACd,CAAC;AAUD,uEAAuE;AACvE,uEAAuE;AACvE,kEAAkE;AAClE,sEAAsE;AACtE,uEAAuE;AACvE,mEAAmE;AACnE,sCAAsC;AACtC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkC,CAAC;AAEzD,SAAS,QAAQ,CAAC,UAAkB,EAAE,UAAkB;IACtD,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,IAAI,MAAM,CAAC,UAAU,CAAC,EAAE,CAAC;AACvD,CAAC;AAED,SAAgB,WAAW,CAAC,UAAkB,EAAE,UAAkB,EAAE,KAA2B;IAC7F,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IAC7C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC;QAAE,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC1C,MAAM,CAAC,GAAG,CAAC,GAAG,CAAE,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC/B,CAAC;AAED,SAAgB,UAAU,CAAC,UAAkB,EAAE,UAAkB;IAC/D,MAAM,GAAG,GAAG,QAAQ,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IAC7C,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IACtC,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,8EAA8E;AAC9E,EAAE;AACF,2EAA2E;AAC3E,wEAAwE;AACxE,wEAAwE;AACxE,yEAAyE;AACzE,0EAA0E;AAC1E,yEAAyE;AACzE,uEAAuE;AACvE,mEAAmE;AACnE,2EAA2E;AAC3E,6CAA6C;AAE7C,MAAM,iBAAiB,GAAG,uCAAuC,CAAC;AAElE,qRAAqR;AACrR,SAAgB,WAAW,CAAC,MAAc,EAAE,IAAY;IACtD,OAAO,uBAAuB,MAAM,OAAO,IAAI,EAAE,CAAC;AACpD,CAAC;AAED,wIAAwI;AACxI,SAAgB,kBAAkB,CAAC,IAAY;IAC7C,OAAO,IAAI,CAAC,OAAO,CAAC,iBAAiB,EAAE,EAAE,CAAC,CAAC;AAC7C,CAAC;AAED,8RAA8R;AACjR,QAAA,oBAAoB,GAAG,wBAAwB,CAAC;AAQ7D,4EAA4E;AAC5E,4EAA4E;AAC5E,0EAA0E;AAC1E,0EAA0E;AAC1E,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAChC,MAAM,aAAa,GAAG,IAAI,GAAG,EAAwB,CAAC;AAEtD,yIAAyI;AACzI,SAAgB,oBAAoB,CAAC,UAAkB,EAAE,OAAe,EAAE,MAAc;IACtF,MAAM,GAAG,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC;IAC/B,aAAa,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IAC5C,IAAI,aAAa,CAAC,IAAI,GAAG,kBAAkB,EAAE,CAAC;QAC5C,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC;QACjD,IAAI,MAAM,KAAK,SAAS;YAAE,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IACzD,CAAC;AACH,CAAC;AAED,2HAA2H;AAC3H,SAAgB,eAAe,CAAC,UAAkB;IAChD,OAAO,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { DeviceProtocolError, type ClickArgs, type DevicePauseReason, type DeviceResultOp, type FileResult, type ObservationResult, type ObserveArgs, type ScrollArgs, type ElementRef, type AppsResult, type Progress, type TaskResult } from "./protocol.js";
|
|
2
|
+
import { type SaltId } from "../ids.js";
|
|
3
|
+
/** Who the lane messages must be encrypted for: every reader's armored public
|
|
4
|
+
* key. Carried by the `device_session_active` delivery. */
|
|
5
|
+
export interface LaneReaders {
|
|
6
|
+
chatId: SaltId;
|
|
7
|
+
publicKeys: string[];
|
|
8
|
+
}
|
|
9
|
+
export type DeviceSessionStatus = "queued" | "requested" | "active" | "paused" | "ended";
|
|
10
|
+
export interface DeviceSessionMeta {
|
|
11
|
+
id: SaltId;
|
|
12
|
+
device_id: SaltId;
|
|
13
|
+
agent_id: SaltId;
|
|
14
|
+
mandate_id: SaltId;
|
|
15
|
+
status: DeviceSessionStatus;
|
|
16
|
+
/** `queued` only: 1-based place in the device's queue. */
|
|
17
|
+
position?: number;
|
|
18
|
+
/** `paused` only. */
|
|
19
|
+
pause_reason?: DevicePauseReason;
|
|
20
|
+
chat?: {
|
|
21
|
+
id: SaltId;
|
|
22
|
+
readers: string[];
|
|
23
|
+
};
|
|
24
|
+
/** What the agent said it is doing when it opened (its own words, untrusted; null/absent when it gave none). */
|
|
25
|
+
intent?: string | null;
|
|
26
|
+
}
|
|
27
|
+
/** Thrown by a transport's openSession on `409 {code:"session_live", session_id}`:
|
|
28
|
+
* this agent already has a live session on the device. open() reattaches. */
|
|
29
|
+
export declare class DeviceSessionLiveError extends Error {
|
|
30
|
+
readonly sessionId: SaltId;
|
|
31
|
+
constructor(sessionId: SaltId);
|
|
32
|
+
}
|
|
33
|
+
/** A command was refused (or not sent) because the session is paused: the
|
|
34
|
+
* person is using the machine, or a secure field needs them. Wait for the
|
|
35
|
+
* `resumed` state (onState) and try again. */
|
|
36
|
+
export declare class DevicePausedError extends DeviceProtocolError {
|
|
37
|
+
readonly reason: DevicePauseReason;
|
|
38
|
+
constructor(reason: DevicePauseReason);
|
|
39
|
+
}
|
|
40
|
+
/** What onState emits. */
|
|
41
|
+
export type DeviceState = {
|
|
42
|
+
state: "queued";
|
|
43
|
+
position: number;
|
|
44
|
+
} | {
|
|
45
|
+
state: "requested";
|
|
46
|
+
} | {
|
|
47
|
+
state: "active";
|
|
48
|
+
} | {
|
|
49
|
+
state: "paused";
|
|
50
|
+
reason: DevicePauseReason;
|
|
51
|
+
} | {
|
|
52
|
+
state: "resumed";
|
|
53
|
+
} | {
|
|
54
|
+
state: "ended";
|
|
55
|
+
reason: string;
|
|
56
|
+
};
|
|
57
|
+
/** The injected transport. httpDeviceTransport provides a real one. */
|
|
58
|
+
export interface DeviceClientTransport {
|
|
59
|
+
/** POST /api/v1/devices/:id/sessions -> the created session: status
|
|
60
|
+
* `requested` (device must approve locally), `active`, or `queued` (202,
|
|
61
|
+
* another agent controls the device). Throws DeviceSessionLiveError on a 409
|
|
62
|
+
* `session_live`. */
|
|
63
|
+
openSession(deviceId: SaltId, opts?: {
|
|
64
|
+
intent?: string;
|
|
65
|
+
}): Promise<DeviceSessionMeta>;
|
|
66
|
+
/** POST /api/v1/device_sessions/:sid/reattach -> {session, last_seq}. */
|
|
67
|
+
reattachSession?(sessionId: SaltId): Promise<{
|
|
68
|
+
session: DeviceSessionMeta;
|
|
69
|
+
last_seq: number;
|
|
70
|
+
}>;
|
|
71
|
+
/** GET /api/v1/device_sessions/:sid; used only to learn the lane readers when
|
|
72
|
+
* a promotion delivery did not carry them. */
|
|
73
|
+
fetchSession?(sessionId: SaltId): Promise<DeviceSessionMeta>;
|
|
74
|
+
/** POST /api/v1/device_sessions/:sid/stop (subtract-only, idempotent). */
|
|
75
|
+
stopSession(sessionId: SaltId): Promise<void>;
|
|
76
|
+
/** Encrypt `plaintext` for the current lane readers and POST it as one lane
|
|
77
|
+
* message. The transport owns the crypto and the readers; this module only
|
|
78
|
+
* decides the plaintext. */
|
|
79
|
+
postCommand(plaintext: string, readers: LaneReaders): Promise<void>;
|
|
80
|
+
}
|
|
81
|
+
export interface DeviceClientOptions {
|
|
82
|
+
/** How long a session may sit in `requested` (waiting for the device's local
|
|
83
|
+
* approval) before open() gives up. Does not run while `queued`. The server
|
|
84
|
+
* ends an unanswered request after 2 minutes with `request_expired`;
|
|
85
|
+
* default here is a touch longer so the server's own end reaches us first. */
|
|
86
|
+
approvalTimeoutMs?: number;
|
|
87
|
+
/** Per-command timeout waiting for a result. Default 30s. On timeout the
|
|
88
|
+
* client sends `cancel {id}`. */
|
|
89
|
+
commandTimeoutMs?: number;
|
|
90
|
+
/** How long a command stays valid (header `exp`). Default COMMAND_TTL_MS. */
|
|
91
|
+
commandTtlMs?: number;
|
|
92
|
+
}
|
|
93
|
+
export interface DeviceResult {
|
|
94
|
+
op: DeviceResultOp;
|
|
95
|
+
body: unknown;
|
|
96
|
+
}
|
|
97
|
+
type Listener = (...args: unknown[]) => void;
|
|
98
|
+
export interface DeviceClient {
|
|
99
|
+
/** Open a session. By default resolves when it is `active`, waiting through
|
|
100
|
+
* `queued` (another agent controls the device) and `requested` (the device's
|
|
101
|
+
* local approval) on `device_session` deliveries, never polling. Rejects if
|
|
102
|
+
* the device declines, the request expires, or the mandate is gone. With
|
|
103
|
+
* `{wait: false}` it returns at once with the state the server answered
|
|
104
|
+
* (e.g. `queued` with `position`); watch onState for the rest. If this
|
|
105
|
+
* agent already has a live session on the device (409 session_live) it
|
|
106
|
+
* reattaches and continues at last_seq + 1. */
|
|
107
|
+
open(opts?: {
|
|
108
|
+
wait?: boolean;
|
|
109
|
+
intent?: string;
|
|
110
|
+
}): Promise<DeviceSessionMeta>;
|
|
111
|
+
observe(args?: ObserveArgs): Promise<ObservationResult>;
|
|
112
|
+
click(args: ClickArgs): Promise<void>;
|
|
113
|
+
type(text: string): Promise<void>;
|
|
114
|
+
key(keys: string[]): Promise<void>;
|
|
115
|
+
scroll(args: ScrollArgs): Promise<void>;
|
|
116
|
+
/** Confirm a named field/form through the accessibility layer (never a keystroke). */
|
|
117
|
+
submit(element: ElementRef): Promise<void>;
|
|
118
|
+
focusApp(app: string): Promise<void>;
|
|
119
|
+
listApps(): Promise<AppsResult>;
|
|
120
|
+
readFile(path: string): Promise<FileResult>;
|
|
121
|
+
writeFile(path: string, contentB64: string): Promise<void>;
|
|
122
|
+
/** Hand the computer ONE whole task (op `task`, grant `device.task`) and wait for its checked
|
|
123
|
+
* result. `goal` is what the person asked for, in plain words (1..2000 characters); `doneWhen`
|
|
124
|
+
* says how the device should check it worked (<= 500). The device does the work itself: command
|
|
125
|
+
* output and screenshots never come back, only a `TaskResult` of words and numbers. Rejects with
|
|
126
|
+
* `bad_args` before sending when the arguments are out of range, `unsupported` when the computer
|
|
127
|
+
* cannot run tasks, `out_of_scope` without the grant or when the budget is spent. `onProgress`
|
|
128
|
+
* gets each non-final line in order (at most one every 2 s, newest wins). Waits
|
|
129
|
+
* `timeoutS + 30` s (default 180 + 30); on that timeout, or when `signal` aborts, it sends
|
|
130
|
+
* `cancel` with the task's id as `re`. After an abort it waits up to 10 s for the device's
|
|
131
|
+
* `stopped` result and resolves with it, else rejects. */
|
|
132
|
+
task(goal: string, opts?: {
|
|
133
|
+
doneWhen?: string;
|
|
134
|
+
maxSteps?: number;
|
|
135
|
+
timeoutS?: number;
|
|
136
|
+
onProgress?: (p: Progress) => void;
|
|
137
|
+
signal?: AbortSignal;
|
|
138
|
+
}): Promise<TaskResult>;
|
|
139
|
+
/** End the session (subtract-only). Safe to call more than once. */
|
|
140
|
+
stop(): Promise<void>;
|
|
141
|
+
/** The live session metadata, or null before open() / after it ended. */
|
|
142
|
+
session(): DeviceSessionMeta | null;
|
|
143
|
+
/** The pause reason while paused, else null. */
|
|
144
|
+
pausedReason(): DevicePauseReason | null;
|
|
145
|
+
/** Feed a `device_session` socket delivery in (promoted / queue_moved /
|
|
146
|
+
* paused / resumed / ended, and the legacy active / ended types). The
|
|
147
|
+
* consumer calls this from its dispatcher. */
|
|
148
|
+
handleDelivery(event: string, body: unknown): void;
|
|
149
|
+
/** Feed a decrypted lane message in (a result the device posted). Returns
|
|
150
|
+
* true if it was a device result this client consumed. */
|
|
151
|
+
handleLaneMessage(plaintext: string): boolean;
|
|
152
|
+
on(event: "active" | "ended" | "ask", cb: Listener): void;
|
|
153
|
+
/** Session state changes: queued(position) / requested / active /
|
|
154
|
+
* paused(reason) / resumed / ended(reason). Returns an unsubscribe. */
|
|
155
|
+
onState(cb: (s: DeviceState) => void): () => void;
|
|
156
|
+
}
|
|
157
|
+
export declare function createDeviceClient(transport: DeviceClientTransport, params: {
|
|
158
|
+
deviceId: SaltId;
|
|
159
|
+
}, options?: DeviceClientOptions): DeviceClient;
|
|
160
|
+
export {};
|
|
161
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/device/client.ts"],"names":[],"mappings":"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"}
|