@butlerbot/sdk 0.0.45 → 0.0.46
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/index.d.ts +1 -0
- package/dist/index.js +3 -1
- package/dist/link/protocol.d.ts +10 -0
- package/dist/modules/conversation.d.ts +23 -0
- package/dist/modules/transport.d.ts +20 -0
- package/dist/modules/transport.js +48 -0
- package/dist/modules/transport_link.js +6 -0
- package/dist/modules/transport_sse.js +7 -1
- package/dist/types/conversation/context.d.ts +28 -0
- package/dist/types/conversation/context.js +2 -0
- package/dist/types/type_registry.d.ts +1 -0
- package/dist/types/type_registry.js +1 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -81,3 +81,4 @@ export type { OutreachRequestOptions, ListDeliveriesOptions, AnswerDeliveryOptio
|
|
|
81
81
|
export { LinkConversationTransport } from "./modules/transport_link";
|
|
82
82
|
export { SSEConversationTransport } from "./modules/transport_sse";
|
|
83
83
|
export type { SteerResult, TurnStopMode, TurnStopped } from "./modules/transport";
|
|
84
|
+
export { RESERVED_TURN_FIELDS } from "./modules/transport";
|
package/dist/index.js
CHANGED
|
@@ -14,7 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
-
exports.SSEConversationTransport = exports.LinkConversationTransport = exports.answerDelivery = exports.listDeliveries = exports.updateJobSettings = exports.updateJob = exports.resumeJob = exports.cancelJob = exports.getJob = exports.listJobs = exports.ButlerBotAPIError = exports.Conversation = exports.ButlerBotClient = void 0;
|
|
17
|
+
exports.RESERVED_TURN_FIELDS = exports.SSEConversationTransport = exports.LinkConversationTransport = exports.answerDelivery = exports.listDeliveries = exports.updateJobSettings = exports.updateJob = exports.resumeJob = exports.cancelJob = exports.getJob = exports.listJobs = exports.ButlerBotAPIError = exports.Conversation = exports.ButlerBotClient = void 0;
|
|
18
18
|
const config_1 = require("./config");
|
|
19
19
|
const link_1 = require("./link");
|
|
20
20
|
const conversation_1 = require("./modules/conversation");
|
|
@@ -137,3 +137,5 @@ var transport_link_1 = require("./modules/transport_link");
|
|
|
137
137
|
Object.defineProperty(exports, "LinkConversationTransport", { enumerable: true, get: function () { return transport_link_1.LinkConversationTransport; } });
|
|
138
138
|
var transport_sse_1 = require("./modules/transport_sse");
|
|
139
139
|
Object.defineProperty(exports, "SSEConversationTransport", { enumerable: true, get: function () { return transport_sse_1.SSEConversationTransport; } });
|
|
140
|
+
var transport_1 = require("./modules/transport");
|
|
141
|
+
Object.defineProperty(exports, "RESERVED_TURN_FIELDS", { enumerable: true, get: function () { return transport_1.RESERVED_TURN_FIELDS; } });
|
package/dist/link/protocol.d.ts
CHANGED
|
@@ -122,6 +122,16 @@ export type LinkClientPayloads = {
|
|
|
122
122
|
personality?: string;
|
|
123
123
|
/** Why Alfred is speaking on this one turn: a line for its system prompt, at most 500 characters. */
|
|
124
124
|
wake?: string;
|
|
125
|
+
/**
|
|
126
|
+
* What the platform attaches beside this turn's message: a `MessageContextItem[]`,
|
|
127
|
+
* JSON-encoded, passed to the server as it is. Absent when there are no items.
|
|
128
|
+
*/
|
|
129
|
+
context?: string;
|
|
130
|
+
/**
|
|
131
|
+
* Further turn parameters, which the Link service spreads into the server's query.
|
|
132
|
+
* Never one of the fields above or the credential; absent when there are none.
|
|
133
|
+
*/
|
|
134
|
+
extra?: Record<string, string>;
|
|
125
135
|
};
|
|
126
136
|
"conversation.end": {
|
|
127
137
|
sessionId: string;
|
|
@@ -6,6 +6,7 @@ import { RequestResponseV3, RequestResponseV4 } from "../types/type_registry";
|
|
|
6
6
|
import { RequestResponseV5 } from "../types/response/v5/dialogue_response_v5";
|
|
7
7
|
import { ConversationStateResponse } from "../types/state/convo_state_response";
|
|
8
8
|
import { ConversationAddress } from "../types/conversation/address";
|
|
9
|
+
import { MessageContextItem } from "../types/conversation/context";
|
|
9
10
|
import { TurnProgressEntry } from "../types/response/v4/turn_registry_v4";
|
|
10
11
|
import { TurnProgressEntryV5 } from "../types/response/v5/turn_registry_v5";
|
|
11
12
|
export type DialogueRequestParams = {
|
|
@@ -35,6 +36,28 @@ export type DialogueRequestParams = {
|
|
|
35
36
|
* 500 characters; the server refuses a longer one. Left off when blank.
|
|
36
37
|
*/
|
|
37
38
|
wake?: string;
|
|
39
|
+
/**
|
|
40
|
+
* What the platform attaches beside this turn's message, never inside it: what it replies
|
|
41
|
+
* to, who it mentions, where it was sent. See `MessageContextItem` for the shape and the
|
|
42
|
+
* bounds (8 items, an 80-character title, a 4 000-character text, 12 000 characters in
|
|
43
|
+
* all), which the server enforces by refusing the turn. Passed per `send()`/`ask()`, since
|
|
44
|
+
* it belongs to the one message; left off when empty.
|
|
45
|
+
*/
|
|
46
|
+
context?: MessageContextItem[];
|
|
47
|
+
/**
|
|
48
|
+
* Further parameters for this one turn, forwarded to the server verbatim: each entry
|
|
49
|
+
* becomes a query parameter over SSE, and a field of `extra` on the `conversation.chat`
|
|
50
|
+
* frame over a Link, which the Link service spreads into the same query. The SDK does not
|
|
51
|
+
* read them; the server validates whatever arrives, as it does its named parameters.
|
|
52
|
+
*
|
|
53
|
+
* This is how a new turn parameter reaches the server without an SDK change: the server
|
|
54
|
+
* learns to read it and the client sends it here.
|
|
55
|
+
*
|
|
56
|
+
* A key the transport already sends (`RESERVED_TURN_FIELDS`: `message`, `chatId`,
|
|
57
|
+
* `api_key`, `model`, `instructions`, `platform`, `address`, `personality`, `wake`,
|
|
58
|
+
* `context`) is refused: `send()` throws, and `ask()` rejects, before anything is sent.
|
|
59
|
+
*/
|
|
60
|
+
extra?: Record<string, string>;
|
|
38
61
|
};
|
|
39
62
|
export type DialogueRequestOptions = Omit<Omit<DialogueRequestParams, "message">, "chatId">;
|
|
40
63
|
export interface RequestResponseByVersion {
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* caller sees, including the payload shape, is identical either way.
|
|
8
8
|
*/
|
|
9
9
|
import type { ConversationAddress } from "../types/conversation/address";
|
|
10
|
+
import type { MessageContextItem } from "../types/conversation/context";
|
|
10
11
|
/** A turn in progress. */
|
|
11
12
|
export type ConversationStream = {
|
|
12
13
|
/**
|
|
@@ -60,7 +61,26 @@ export type TransportTurnRequest = {
|
|
|
60
61
|
personality?: string;
|
|
61
62
|
/** Why Alfred is speaking on this one turn: a line for its system prompt, at most 500 characters. */
|
|
62
63
|
wake?: string;
|
|
64
|
+
/** What the platform attaches beside this turn's message. Sent only when non-empty. */
|
|
65
|
+
context?: MessageContextItem[];
|
|
66
|
+
/** Further turn parameters, forwarded to the server verbatim. See `DialogueRequestParams.extra`. */
|
|
67
|
+
extra?: Record<string, string>;
|
|
63
68
|
};
|
|
69
|
+
/**
|
|
70
|
+
* The turn parameters the server reads by name, which a transport sends itself. An `extra`
|
|
71
|
+
* entry may not use one: it would replace what the transport sent, or, for `api_key`, the
|
|
72
|
+
* credential. Both transports refuse the same list, since over a Link the service spreads
|
|
73
|
+
* `extra` into the very query the SSE transport builds.
|
|
74
|
+
*/
|
|
75
|
+
export declare const RESERVED_TURN_FIELDS: readonly string[];
|
|
76
|
+
/**
|
|
77
|
+
* A turn's `extra`, checked, or nothing when there is none to send. Throws on a key that
|
|
78
|
+
* collides with a field the transport sends, and on a value that is not a string, before
|
|
79
|
+
* anything reaches the wire.
|
|
80
|
+
*/
|
|
81
|
+
export declare function turnExtra(extra: Record<string, string> | undefined): Record<string, string> | undefined;
|
|
82
|
+
/** A turn's context as it travels, JSON-encoded, or nothing when there is none. */
|
|
83
|
+
export declare function turnContext(context: MessageContextItem[] | undefined): string | undefined;
|
|
64
84
|
export type TransportHandlers = {
|
|
65
85
|
/** One payload of the stream, already in the shape callers expect. */
|
|
66
86
|
payload(payload: unknown): void;
|
|
@@ -8,10 +8,58 @@
|
|
|
8
8
|
* caller sees, including the payload shape, is identical either way.
|
|
9
9
|
*/
|
|
10
10
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.RESERVED_TURN_FIELDS = void 0;
|
|
12
|
+
exports.turnExtra = turnExtra;
|
|
13
|
+
exports.turnContext = turnContext;
|
|
11
14
|
exports.noticePayload = noticePayload;
|
|
12
15
|
exports.convoStartedPayload = convoStartedPayload;
|
|
13
16
|
exports.completedPayload = completedPayload;
|
|
14
17
|
exports.failurePayload = failurePayload;
|
|
18
|
+
/**
|
|
19
|
+
* The turn parameters the server reads by name, which a transport sends itself. An `extra`
|
|
20
|
+
* entry may not use one: it would replace what the transport sent, or, for `api_key`, the
|
|
21
|
+
* credential. Both transports refuse the same list, since over a Link the service spreads
|
|
22
|
+
* `extra` into the very query the SSE transport builds.
|
|
23
|
+
*/
|
|
24
|
+
exports.RESERVED_TURN_FIELDS = [
|
|
25
|
+
"api_key",
|
|
26
|
+
"message",
|
|
27
|
+
"chatId",
|
|
28
|
+
"model",
|
|
29
|
+
"instructions",
|
|
30
|
+
"platform",
|
|
31
|
+
"address",
|
|
32
|
+
"personality",
|
|
33
|
+
"wake",
|
|
34
|
+
"context",
|
|
35
|
+
];
|
|
36
|
+
/**
|
|
37
|
+
* A turn's `extra`, checked, or nothing when there is none to send. Throws on a key that
|
|
38
|
+
* collides with a field the transport sends, and on a value that is not a string, before
|
|
39
|
+
* anything reaches the wire.
|
|
40
|
+
*/
|
|
41
|
+
function turnExtra(extra) {
|
|
42
|
+
if (!extra)
|
|
43
|
+
return undefined;
|
|
44
|
+
const entries = Object.entries(extra);
|
|
45
|
+
if (entries.length === 0)
|
|
46
|
+
return undefined;
|
|
47
|
+
for (const [key, value] of entries) {
|
|
48
|
+
if (!key)
|
|
49
|
+
throw new Error("A turn's `extra` may not have an empty key.");
|
|
50
|
+
if (exports.RESERVED_TURN_FIELDS.includes(key)) {
|
|
51
|
+
throw new Error(`A turn's \`extra\` may not set "${key}": the transport already sends it. Reserved: ${exports.RESERVED_TURN_FIELDS.join(", ")}.`);
|
|
52
|
+
}
|
|
53
|
+
if (typeof value !== "string") {
|
|
54
|
+
throw new Error(`A turn's \`extra\` values must be strings; "${key}" is ${typeof value}.`);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return Object.fromEntries(entries);
|
|
58
|
+
}
|
|
59
|
+
/** A turn's context as it travels, JSON-encoded, or nothing when there is none. */
|
|
60
|
+
function turnContext(context) {
|
|
61
|
+
return context && context.length > 0 ? JSON.stringify(context) : undefined;
|
|
62
|
+
}
|
|
15
63
|
// =============================================
|
|
16
64
|
// PAYLOAD SHAPES
|
|
17
65
|
// =============================================
|
|
@@ -29,6 +29,8 @@ class LinkConversationTransport {
|
|
|
29
29
|
link.on("disconnect", () => { this.sessionId = undefined; });
|
|
30
30
|
}
|
|
31
31
|
send(request, handlers) {
|
|
32
|
+
// Refused here, synchronously, as the SSE transport refuses it: before anything is sent.
|
|
33
|
+
(0, transport_1.turnExtra)(request.extra);
|
|
32
34
|
const listening = { closed: false };
|
|
33
35
|
const deliver = {
|
|
34
36
|
payload: (payload) => { if (!listening.closed)
|
|
@@ -176,6 +178,8 @@ class LinkConversationTransport {
|
|
|
176
178
|
}
|
|
177
179
|
};
|
|
178
180
|
learnChatId(progress.chatId);
|
|
181
|
+
const context = (0, transport_1.turnContext)(request.context);
|
|
182
|
+
const extra = (0, transport_1.turnExtra)(request.extra);
|
|
179
183
|
let done;
|
|
180
184
|
try {
|
|
181
185
|
done = await this.link.exchange("conversation.chat", {
|
|
@@ -186,6 +190,8 @@ class LinkConversationTransport {
|
|
|
186
190
|
...(request.personality ? { personality: request.personality } : {}),
|
|
187
191
|
// Per turn, never on the session: it says why Alfred was woken for this one.
|
|
188
192
|
...(request.wake?.trim() ? { wake: request.wake.trim() } : {}),
|
|
193
|
+
...(context ? { context } : {}),
|
|
194
|
+
...(extra ? { extra } : {}),
|
|
189
195
|
}, {
|
|
190
196
|
// A turn takes as long as it takes; only the transport dying ends it early.
|
|
191
197
|
timeoutMs: 0,
|
|
@@ -4,6 +4,7 @@ exports.SSEConversationTransport = void 0;
|
|
|
4
4
|
exports.streamSSE = streamSSE;
|
|
5
5
|
const eventsource_1 = require("eventsource");
|
|
6
6
|
const url_formatter_1 = require("../util/url_formatter");
|
|
7
|
+
const transport_1 = require("./transport");
|
|
7
8
|
/**
|
|
8
9
|
* Streams a server-sent-events endpoint, closing when the server says the stream is
|
|
9
10
|
* done. Shared by turns and by the progress stream, which is SSE-only.
|
|
@@ -123,5 +124,10 @@ function asQuery(request) {
|
|
|
123
124
|
const wake = request.wake?.trim();
|
|
124
125
|
if (wake)
|
|
125
126
|
query.wake = wake;
|
|
126
|
-
|
|
127
|
+
const context = (0, transport_1.turnContext)(request.context);
|
|
128
|
+
if (context)
|
|
129
|
+
query.context = context;
|
|
130
|
+
// Checked before anything else is added, so an entry can never replace a field above.
|
|
131
|
+
const extra = (0, transport_1.turnExtra)(request.extra);
|
|
132
|
+
return extra ? { ...extra, ...query } : query;
|
|
127
133
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Something a platform attaches beside a user's message, never inside it: what the message
|
|
3
|
+
* replies to, who it mentions, where it was sent, the conversation around it.
|
|
4
|
+
*
|
|
5
|
+
* The text the user typed stays exactly what they typed. The model reads the items as a
|
|
6
|
+
* labelled block after it; a person sees them as chips under the message, titled by `title`
|
|
7
|
+
* and expandable to `text`.
|
|
8
|
+
*
|
|
9
|
+
* ```ts
|
|
10
|
+
* { kind: "reply", title: "Replying to", text: "Sam: what time does the store close?" }
|
|
11
|
+
* { kind: "mentions", title: "Mentions", text: "Sam (@sam) = <@123>, Alfred = <@456> (this is you)" }
|
|
12
|
+
* ```
|
|
13
|
+
*
|
|
14
|
+
* Bounds, enforced by the server, which refuses a request over them with what is wrong rather
|
|
15
|
+
* than clipping it: at most 8 items on a message, a `title` of at most 80 characters, a `text`
|
|
16
|
+
* of at most 4 000, and 12 000 characters in all.
|
|
17
|
+
*/
|
|
18
|
+
export type MessageContextItem = {
|
|
19
|
+
/**
|
|
20
|
+
* What the item is: `reply`, `mentions`, `place` or `channel` today. The server holds the
|
|
21
|
+
* list and refuses an unknown kind with the real ones, so a new kind needs no SDK change.
|
|
22
|
+
*/
|
|
23
|
+
kind: string;
|
|
24
|
+
/** What a person sees on the chip and the model on the block's line. At most 80 characters. */
|
|
25
|
+
title: string;
|
|
26
|
+
/** The content, as plain text. At most 4 000 characters. */
|
|
27
|
+
text: string;
|
|
28
|
+
};
|
|
@@ -4,6 +4,7 @@ export * from "./response/v5";
|
|
|
4
4
|
export * from "./state/convo_state_response";
|
|
5
5
|
export * from "./conversation/v4/conversation_v4";
|
|
6
6
|
export * from "./conversation/address";
|
|
7
|
+
export * from "./conversation/context";
|
|
7
8
|
export * from "./jobs";
|
|
8
9
|
export * from "./outreach";
|
|
9
10
|
export * from "./error";
|
|
@@ -20,6 +20,7 @@ __exportStar(require("./response/v5"), exports);
|
|
|
20
20
|
__exportStar(require("./state/convo_state_response"), exports);
|
|
21
21
|
__exportStar(require("./conversation/v4/conversation_v4"), exports);
|
|
22
22
|
__exportStar(require("./conversation/address"), exports);
|
|
23
|
+
__exportStar(require("./conversation/context"), exports);
|
|
23
24
|
__exportStar(require("./jobs"), exports);
|
|
24
25
|
__exportStar(require("./outreach"), exports);
|
|
25
26
|
__exportStar(require("./error"), exports);
|