@datalayer/agent-runtimes 1.5.48 → 1.5.49
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/lib/portable/hosts/agentClient.d.ts +15 -2
- package/lib/portable/hosts/agentClient.js +3 -0
- package/lib/portable/hosts/client.d.ts +16 -0
- package/lib/portable/hosts/client.js +16 -0
- package/lib/portable/hosts/contracts.json +86 -3
- package/lib/portable/hosts/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -41,16 +41,29 @@ export type Place = Readonly<{
|
|
|
41
41
|
kind: 'channel' | 'direct';
|
|
42
42
|
id: string;
|
|
43
43
|
}>;
|
|
44
|
+
/**
|
|
45
|
+
* Where a turn comes from, as the session API takes it on the turn itself
|
|
46
|
+
* (`provenance`, plans/DISCORD.md §4.3, §4.4; at most 1 KiB): the host's
|
|
47
|
+
* kind, the place, the thread and the message.
|
|
48
|
+
*/
|
|
49
|
+
export type TurnProvenance = Readonly<{
|
|
50
|
+
host_kind: string;
|
|
51
|
+
place: Place;
|
|
52
|
+
thread: string;
|
|
53
|
+
message_id: string;
|
|
54
|
+
}>;
|
|
44
55
|
/**
|
|
45
56
|
* What is the host's own in a turn: the session uid its thread derives
|
|
46
57
|
* (`hostSessionUid`), the place Datalayer checks the channel policy against,
|
|
47
|
-
* the delivery target handed back with every delivery,
|
|
48
|
-
* its installation holds no host key.
|
|
58
|
+
* the delivery target handed back with every delivery, the provenance sent
|
|
59
|
+
* with the turn, and what is said when its installation holds no host key.
|
|
49
60
|
*/
|
|
50
61
|
export type HostShape<P> = Readonly<{
|
|
51
62
|
sessionUidOf(request: HostTurnRequest<P>): string;
|
|
52
63
|
placeOf(request: HostTurnRequest<P>): Place;
|
|
53
64
|
targetOf(request: HostTurnRequest<P>): Record<string, unknown>;
|
|
65
|
+
/** The turn's provenance; a host that sends none leaves it out. */
|
|
66
|
+
provenanceOf?(request: HostTurnRequest<P>): TurnProvenance;
|
|
54
67
|
notBound: string;
|
|
55
68
|
}>;
|
|
56
69
|
/**
|
|
@@ -220,6 +220,7 @@ export class HttpAgentClient {
|
|
|
220
220
|
const host = await this.credentials.forTurn(request);
|
|
221
221
|
assertTrustedStreamUrl(this.apiUrl, host.sessionApiUrl);
|
|
222
222
|
const sessionId = request.sessionId ?? this.shape.sessionUidOf(request);
|
|
223
|
+
const provenance = this.shape.provenanceOf?.(request);
|
|
223
224
|
const headers = {
|
|
224
225
|
accept: 'text/event-stream',
|
|
225
226
|
authorization: `Bearer ${host.accessToken}`,
|
|
@@ -231,6 +232,7 @@ export class HttpAgentClient {
|
|
|
231
232
|
body: JSON.stringify({
|
|
232
233
|
external_event_id: request.externalEventId,
|
|
233
234
|
text: request.prompt,
|
|
235
|
+
...(provenance ? { provenance } : {}),
|
|
234
236
|
}),
|
|
235
237
|
headers,
|
|
236
238
|
method: 'POST',
|
|
@@ -243,6 +245,7 @@ export class HttpAgentClient {
|
|
|
243
245
|
opener: request.prompt,
|
|
244
246
|
session: sessionId,
|
|
245
247
|
...(host.userToken ? { user_token: host.userToken } : {}),
|
|
248
|
+
...(provenance ? { provenance } : {}),
|
|
246
249
|
}),
|
|
247
250
|
headers,
|
|
248
251
|
method: 'POST',
|
|
@@ -53,6 +53,22 @@ export declare class DatalayerHostClient {
|
|
|
53
53
|
* channel policy and whether it is paused.
|
|
54
54
|
*/
|
|
55
55
|
self(hostKey: string): Promise<HostSelf>;
|
|
56
|
+
/**
|
|
57
|
+
* The host's own administration (plans/DISCORD.md DC-106,
|
|
58
|
+
* `/datalayer-admin`): pause, resume or one channel's rule, for the host
|
|
59
|
+
* user linked to the installation's owner; Datalayer refuses anyone else
|
|
60
|
+
* (403), whatever their role in the host.
|
|
61
|
+
*/
|
|
62
|
+
admin(hostKey: string, externalUserId: string, change: Readonly<{
|
|
63
|
+
paused?: boolean;
|
|
64
|
+
channel?: Readonly<{
|
|
65
|
+
id: string;
|
|
66
|
+
state: 'allow' | 'deny';
|
|
67
|
+
deployment?: string;
|
|
68
|
+
}>;
|
|
69
|
+
}>): Promise<{
|
|
70
|
+
paused: boolean;
|
|
71
|
+
}>;
|
|
56
72
|
/** The host unlinks one of its users: how many links ended. */
|
|
57
73
|
unlink(hostKey: string, externalUserId: string): Promise<number>;
|
|
58
74
|
/** A one-use code a host user redeems, signed in to Datalayer, to link their account. */
|
|
@@ -102,6 +102,22 @@ export class DatalayerHostClient {
|
|
|
102
102
|
paused: host.paused ?? false,
|
|
103
103
|
};
|
|
104
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* The host's own administration (plans/DISCORD.md DC-106,
|
|
107
|
+
* `/datalayer-admin`): pause, resume or one channel's rule, for the host
|
|
108
|
+
* user linked to the installation's owner; Datalayer refuses anyone else
|
|
109
|
+
* (403), whatever their role in the host.
|
|
110
|
+
*/
|
|
111
|
+
async admin(hostKey, externalUserId, change) {
|
|
112
|
+
const answered = await this.#call('Datalayer did not take the change', '/apps/hosts/self/admin', {
|
|
113
|
+
body: { external_user_id: externalUserId, ...change },
|
|
114
|
+
hostKey,
|
|
115
|
+
method: 'POST',
|
|
116
|
+
}, z.object({
|
|
117
|
+
host: z.object({ paused: z.boolean().optional() }).loose(),
|
|
118
|
+
}));
|
|
119
|
+
return { paused: answered.host.paused ?? false };
|
|
120
|
+
}
|
|
105
121
|
/** The host unlinks one of its users: how many links ended. */
|
|
106
122
|
async unlink(hostKey, externalUserId) {
|
|
107
123
|
const answered = await this.#call('Datalayer did not unlink the account', `/apps/hosts/self/links/${encodeURIComponent(externalUserId)}`, { hostKey, method: 'DELETE' }, z.object({ revoked: z.number().int() }));
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 1,
|
|
3
|
-
"about": "The generic host contracts of plans/SLACK.md §4.3, as ai-agents and the runtime's session API answer them. Shared verbatim by ai-agents (tests/fixtures/hosts) and the Slack
|
|
3
|
+
"about": "The generic host contracts of plans/SLACK.md §4.3 and plans/DISCORD.md §4.3, as ai-agents and the runtime's session API answer them. Shared verbatim by ai-agents (tests/fixtures/hosts) and agent-runtimes (src/portable/hosts, read by the Slack and Discord adapters from lib/portable/hosts): each side's tests check its half against this file.",
|
|
4
4
|
"headers": {
|
|
5
5
|
"host_key": "X-Datalayer-Host-Key",
|
|
6
6
|
"signature": "X-Datalayer-Signature",
|
|
@@ -29,7 +29,8 @@
|
|
|
29
29
|
"preview_link": "GET /api/ai-agents/v1/apps/hosts/links/preview?code={code}",
|
|
30
30
|
"change_host": "PATCH /api/ai-agents/v1/apps/hosts/{uid}",
|
|
31
31
|
"handoff": "POST /api/ai-agents/v1/apps/hosts/handoffs",
|
|
32
|
-
"redeem_handoff": "POST /api/ai-agents/v1/apps/hosts/handoffs/redeem"
|
|
32
|
+
"redeem_handoff": "POST /api/ai-agents/v1/apps/hosts/handoffs/redeem",
|
|
33
|
+
"admin": "POST /api/ai-agents/v1/apps/hosts/self/admin"
|
|
33
34
|
},
|
|
34
35
|
"bind": {
|
|
35
36
|
"request": {
|
|
@@ -147,7 +148,19 @@
|
|
|
147
148
|
"state"
|
|
148
149
|
]
|
|
149
150
|
},
|
|
150
|
-
"replay": "The same Idempotency-Key (or, without one, the same external_event_id) and the same request answer the original session and turn with replayed=true, and run nothing; the same key with another request is 409."
|
|
151
|
+
"replay": "The same Idempotency-Key (or, without one, the same external_event_id) and the same request answer the original session and turn with replayed=true, and run nothing; the same key with another request is 409.",
|
|
152
|
+
"optional_request": {
|
|
153
|
+
"provenance": {
|
|
154
|
+
"host_kind": "discord",
|
|
155
|
+
"place": {
|
|
156
|
+
"kind": "channel",
|
|
157
|
+
"id": "345678901234567890"
|
|
158
|
+
},
|
|
159
|
+
"thread": "456789012345678901",
|
|
160
|
+
"message_id": "456789012345678901"
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
"provenance_limit_bytes": 1024
|
|
151
164
|
},
|
|
152
165
|
"webhook": {
|
|
153
166
|
"request": {
|
|
@@ -380,5 +393,75 @@
|
|
|
380
393
|
"expired": 410,
|
|
381
394
|
"spent_or_unknown": 404
|
|
382
395
|
}
|
|
396
|
+
},
|
|
397
|
+
"admin": {
|
|
398
|
+
"request": {
|
|
399
|
+
"external_user_id": "567890123456789012",
|
|
400
|
+
"paused": true
|
|
401
|
+
},
|
|
402
|
+
"channel_request": {
|
|
403
|
+
"external_user_id": "567890123456789012",
|
|
404
|
+
"channel": {
|
|
405
|
+
"id": "345678901234567890",
|
|
406
|
+
"state": "deny"
|
|
407
|
+
}
|
|
408
|
+
},
|
|
409
|
+
"response_keys": [
|
|
410
|
+
"success",
|
|
411
|
+
"host"
|
|
412
|
+
],
|
|
413
|
+
"refusals": {
|
|
414
|
+
"not_the_owner": 403,
|
|
415
|
+
"nothing_to_change": 422
|
|
416
|
+
}
|
|
417
|
+
},
|
|
418
|
+
"discord": {
|
|
419
|
+
"about": "Discord's forms of the generic contracts (plans/DISCORD.md §4.3): the installation is <application_id>:<guild_id>, a member is their snowflake, a thread is sent as its parent channel, the session uid is hostSessionUid(\"discord\", [application, guild, channel, thread]).",
|
|
420
|
+
"application_id": "123456789012345678",
|
|
421
|
+
"guild_id": "234567890123456789",
|
|
422
|
+
"bind_request": {
|
|
423
|
+
"code": "dlhc_…",
|
|
424
|
+
"external_id": "123456789012345678:234567890123456789",
|
|
425
|
+
"name": "Acme"
|
|
426
|
+
},
|
|
427
|
+
"external_user_id": "567890123456789012",
|
|
428
|
+
"thread": {
|
|
429
|
+
"channel": {
|
|
430
|
+
"id": "456789012345678901",
|
|
431
|
+
"type": 11,
|
|
432
|
+
"parent_id": "345678901234567890"
|
|
433
|
+
},
|
|
434
|
+
"place": {
|
|
435
|
+
"kind": "channel",
|
|
436
|
+
"id": "345678901234567890"
|
|
437
|
+
}
|
|
438
|
+
},
|
|
439
|
+
"direct": {
|
|
440
|
+
"channel": {
|
|
441
|
+
"id": "678901234567890123",
|
|
442
|
+
"type": 1
|
|
443
|
+
},
|
|
444
|
+
"place": {
|
|
445
|
+
"kind": "direct",
|
|
446
|
+
"id": "678901234567890123"
|
|
447
|
+
}
|
|
448
|
+
},
|
|
449
|
+
"session": {
|
|
450
|
+
"parts": [
|
|
451
|
+
"123456789012345678",
|
|
452
|
+
"234567890123456789",
|
|
453
|
+
"345678901234567890",
|
|
454
|
+
"456789012345678901"
|
|
455
|
+
],
|
|
456
|
+
"uid": "discord-15beb80510370bbe027882df9d4d4666925017df"
|
|
457
|
+
},
|
|
458
|
+
"target": {
|
|
459
|
+
"applicationId": "123456789012345678",
|
|
460
|
+
"channelId": "345678901234567890",
|
|
461
|
+
"guildId": "234567890123456789",
|
|
462
|
+
"messageId": "456789012345678901",
|
|
463
|
+
"threadId": "456789012345678901",
|
|
464
|
+
"userId": "567890123456789012"
|
|
465
|
+
}
|
|
383
466
|
}
|
|
384
467
|
}
|
|
@@ -22,7 +22,7 @@ export * from '../semantic';
|
|
|
22
22
|
export { askQuestionOf, semanticOf, turnOf, type TurnInfo, } from '../semanticOfAgUi';
|
|
23
23
|
export * from './contracts';
|
|
24
24
|
export { DatalayerHostClient, HostRefusedError, type BoundHost, type HostSelf, } from './client';
|
|
25
|
-
export { agUiEventsOf, assertTrustedStreamUrl, DevelopmentCredentials, HostKeyCredentials, hostSessionOf, HostStarters, HttpAgentClient, InstallationCredentials, lastAnswer, type AgentClient, type HostCredentials, type HostKeyLookup, type HostSession, type HostShape, type HostTurnRequest, type Place, type Starter, type StarterSource, type TurnStream, } from './agentClient';
|
|
25
|
+
export { agUiEventsOf, assertTrustedStreamUrl, DevelopmentCredentials, HostKeyCredentials, hostSessionOf, HostStarters, HttpAgentClient, InstallationCredentials, lastAnswer, type AgentClient, type HostCredentials, type HostKeyLookup, type HostSession, type HostShape, type HostTurnRequest, type Place, type Starter, type StarterSource, type TurnProvenance, type TurnStream, } from './agentClient';
|
|
26
26
|
export { hostSessionUid } from './sessionUid';
|
|
27
27
|
export { DATALAYER_ONLY, MAIL_WORDS, RENDERERS, renderApproval, type RenderedAction, type RenderedField, } from './approvalRenderers';
|
|
28
28
|
export { DELIVERY_PATH, DELIVERY_ROUTE, DeliveryPoller, deliveryRoute, receiveDelivery, type BoundHostKey, type DeliveryClaimStore, type DeliveryJob, type DeliverySink, } from './deliveries';
|