codex-channel-bgos 0.2.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 +114 -0
- package/dist/adapter.d.ts +96 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +677 -0
- package/dist/adapter.js.map +1 -0
- package/dist/agent-hints.d.ts +20 -0
- package/dist/agent-hints.d.ts.map +1 -0
- package/dist/agent-hints.js +92 -0
- package/dist/agent-hints.js.map +1 -0
- package/dist/agent-identity.d.ts +36 -0
- package/dist/agent-identity.d.ts.map +1 -0
- package/dist/agent-identity.js +42 -0
- package/dist/agent-identity.js.map +1 -0
- package/dist/attachment-bridge.d.ts +64 -0
- package/dist/attachment-bridge.d.ts.map +1 -0
- package/dist/attachment-bridge.js +216 -0
- package/dist/attachment-bridge.js.map +1 -0
- package/dist/auth-mode.d.ts +34 -0
- package/dist/auth-mode.d.ts.map +1 -0
- package/dist/auth-mode.js +48 -0
- package/dist/auth-mode.js.map +1 -0
- package/dist/bgos-api.d.ts +191 -0
- package/dist/bgos-api.d.ts.map +1 -0
- package/dist/bgos-api.js +225 -0
- package/dist/bgos-api.js.map +1 -0
- package/dist/bgos-ws.d.ts +94 -0
- package/dist/bgos-ws.d.ts.map +1 -0
- package/dist/bgos-ws.js +310 -0
- package/dist/bgos-ws.js.map +1 -0
- package/dist/capabilities.d.ts +28 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +44 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/catalog-sync.d.ts +26 -0
- package/dist/catalog-sync.d.ts.map +1 -0
- package/dist/catalog-sync.js +24 -0
- package/dist/catalog-sync.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +152 -0
- package/dist/cli.js.map +1 -0
- package/dist/codex-host.d.ts +44 -0
- package/dist/codex-host.d.ts.map +1 -0
- package/dist/codex-host.js +142 -0
- package/dist/codex-host.js.map +1 -0
- package/dist/commands-sync.d.ts +24 -0
- package/dist/commands-sync.d.ts.map +1 -0
- package/dist/commands-sync.js +43 -0
- package/dist/commands-sync.js.map +1 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +36 -0
- package/dist/config.js.map +1 -0
- package/dist/default-commands.d.ts +27 -0
- package/dist/default-commands.d.ts.map +1 -0
- package/dist/default-commands.js +64 -0
- package/dist/default-commands.js.map +1 -0
- package/dist/event-mapper.d.ts +43 -0
- package/dist/event-mapper.d.ts.map +1 -0
- package/dist/event-mapper.js +127 -0
- package/dist/event-mapper.js.map +1 -0
- package/dist/heartbeat.d.ts +75 -0
- package/dist/heartbeat.d.ts.map +1 -0
- package/dist/heartbeat.js +186 -0
- package/dist/heartbeat.js.map +1 -0
- package/dist/inbound-handler.d.ts +167 -0
- package/dist/inbound-handler.d.ts.map +1 -0
- package/dist/inbound-handler.js +282 -0
- package/dist/inbound-handler.js.map +1 -0
- package/dist/inbound-input.d.ts +17 -0
- package/dist/inbound-input.d.ts.map +1 -0
- package/dist/inbound-input.js +25 -0
- package/dist/inbound-input.js.map +1 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +18 -0
- package/dist/index.js.map +1 -0
- package/dist/install-service.d.ts +8 -0
- package/dist/install-service.d.ts.map +1 -0
- package/dist/install-service.js +66 -0
- package/dist/install-service.js.map +1 -0
- package/dist/last-id-store.d.ts +33 -0
- package/dist/last-id-store.d.ts.map +1 -0
- package/dist/last-id-store.js +101 -0
- package/dist/last-id-store.js.map +1 -0
- package/dist/load-config.d.ts +30 -0
- package/dist/load-config.d.ts.map +1 -0
- package/dist/load-config.js +86 -0
- package/dist/load-config.js.map +1 -0
- package/dist/media-classify.d.ts +37 -0
- package/dist/media-classify.d.ts.map +1 -0
- package/dist/media-classify.js +108 -0
- package/dist/media-classify.js.map +1 -0
- package/dist/media-guard.d.ts +13 -0
- package/dist/media-guard.d.ts.map +1 -0
- package/dist/media-guard.js +159 -0
- package/dist/media-guard.js.map +1 -0
- package/dist/outbound-retry.d.ts +24 -0
- package/dist/outbound-retry.d.ts.map +1 -0
- package/dist/outbound-retry.js +75 -0
- package/dist/outbound-retry.js.map +1 -0
- package/dist/outbound.d.ts +223 -0
- package/dist/outbound.d.ts.map +1 -0
- package/dist/outbound.js +366 -0
- package/dist/outbound.js.map +1 -0
- package/dist/outbox.d.ts +16 -0
- package/dist/outbox.d.ts.map +1 -0
- package/dist/outbox.js +88 -0
- package/dist/outbox.js.map +1 -0
- package/dist/pair-cli.d.ts +44 -0
- package/dist/pair-cli.d.ts.map +1 -0
- package/dist/pair-cli.js +182 -0
- package/dist/pair-cli.js.map +1 -0
- package/dist/pending-unknown-store.d.ts +26 -0
- package/dist/pending-unknown-store.d.ts.map +1 -0
- package/dist/pending-unknown-store.js +135 -0
- package/dist/pending-unknown-store.js.map +1 -0
- package/dist/processed-ids.d.ts +36 -0
- package/dist/processed-ids.d.ts.map +1 -0
- package/dist/processed-ids.js +55 -0
- package/dist/processed-ids.js.map +1 -0
- package/dist/reply-markers.d.ts +42 -0
- package/dist/reply-markers.d.ts.map +1 -0
- package/dist/reply-markers.js +124 -0
- package/dist/reply-markers.js.map +1 -0
- package/dist/setup/supervisor.d.ts +16 -0
- package/dist/setup/supervisor.d.ts.map +1 -0
- package/dist/setup/supervisor.js +61 -0
- package/dist/setup/supervisor.js.map +1 -0
- package/dist/thread-map.d.ts +12 -0
- package/dist/thread-map.d.ts.map +1 -0
- package/dist/thread-map.js +72 -0
- package/dist/thread-map.js.map +1 -0
- package/dist/tool-progress.d.ts +103 -0
- package/dist/tool-progress.d.ts.map +1 -0
- package/dist/tool-progress.js +216 -0
- package/dist/tool-progress.js.map +1 -0
- package/dist/types.d.ts +244 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +16 -0
- package/dist/types.js.map +1 -0
- package/dist/version.d.ts +2 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +28 -0
- package/dist/version.js.map +1 -0
- package/dist/voice-rpc.d.ts +37 -0
- package/dist/voice-rpc.d.ts.map +1 -0
- package/dist/voice-rpc.js +44 -0
- package/dist/voice-rpc.js.map +1 -0
- package/package.json +47 -0
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import type { BgosApi } from "./bgos-api.js";
|
|
2
|
+
import type { ApprovalMeta, FromAgentInput, MessageOption } from "./types.js";
|
|
3
|
+
export declare class BgosOutbound {
|
|
4
|
+
/** Public read-only handle on the underlying REST client; consumers
|
|
5
|
+
* occasionally need it (e.g. inbound-handler routes uploadFile through
|
|
6
|
+
* publishMediaPath). */
|
|
7
|
+
readonly api: BgosApi;
|
|
8
|
+
private typingEmitter;
|
|
9
|
+
private onLastError;
|
|
10
|
+
private onOutbound;
|
|
11
|
+
/** Single-flight guard for replaySpool: concurrent callers (the 60s spool
|
|
12
|
+
* timer, onReconnect, recover) await the same in-flight run instead of each
|
|
13
|
+
* loading + re-sending the same spooled entries (double-send). */
|
|
14
|
+
private spoolInFlight;
|
|
15
|
+
private sleepFn;
|
|
16
|
+
constructor(api: BgosApi);
|
|
17
|
+
/** Wire the WS typing emitter (contract C4). Without it, sendTyping no-ops. */
|
|
18
|
+
setTypingEmitter(fn: (p: {
|
|
19
|
+
chatId: number;
|
|
20
|
+
assistantId: number;
|
|
21
|
+
}) => void): void;
|
|
22
|
+
/** Report an outbound failure to the heartbeat lastError channel. */
|
|
23
|
+
setLastErrorReporter(fn: (code: string, message: string) => void): void;
|
|
24
|
+
/** Called on every successful send (drives heartbeat lastOutboundAt). */
|
|
25
|
+
setOutboundReporter(fn: () => void): void;
|
|
26
|
+
/** Test seam: override the retry sleep so specs don't wait real seconds. */
|
|
27
|
+
setSleepFn(fn: (ms: number) => Promise<void>): void;
|
|
28
|
+
private rawSend;
|
|
29
|
+
/**
|
|
30
|
+
* Pick the reply endpoint + apply the outbound retry policy (contract C3).
|
|
31
|
+
*
|
|
32
|
+
* Default `messages` (POST /api/v1/messages) is the historical path used for
|
|
33
|
+
* every normal reply, proactive send, and `/board` fan-out. `send-message`
|
|
34
|
+
* (POST /api/v1/send-message) is used ONLY for a2a peer replies.
|
|
35
|
+
*
|
|
36
|
+
* Retry (backoff 1s/5s/25s) applies ONLY to the provably-undelivered
|
|
37
|
+
* network-error class + 429 (see classifyOutboundError), because the backend
|
|
38
|
+
* insert is not idempotent. Ambiguous failures (timeouts, 5xx) are NOT
|
|
39
|
+
* retried and reject to the caller. After 3 failed retries of the safe class
|
|
40
|
+
* the payload is spooled to the outbox for later replay.
|
|
41
|
+
*/
|
|
42
|
+
private deliver;
|
|
43
|
+
/**
|
|
44
|
+
* Replay any spooled outbound payloads (contract C3). Called by the adapter
|
|
45
|
+
* on WS reconnect and every 60s while non-empty. Entries older than 24h are
|
|
46
|
+
* dropped on load; safe-class failures are re-kept, ambiguous failures on
|
|
47
|
+
* replay are dropped to avoid a non-idempotent duplicate.
|
|
48
|
+
*
|
|
49
|
+
* Single-flight: concurrent callers (the 60s spool timer racing an
|
|
50
|
+
* onReconnect racing a recover, or WS flapping spawning overlapping
|
|
51
|
+
* onReconnects) coalesce onto one in-flight run. Two overlapping runs would
|
|
52
|
+
* otherwise both load the SAME entries and each re-send them, and the backend
|
|
53
|
+
* insert is NOT idempotent, so that produces duplicate agent messages.
|
|
54
|
+
*/
|
|
55
|
+
replaySpool(): Promise<void>;
|
|
56
|
+
private runReplaySpool;
|
|
57
|
+
sendText(params: {
|
|
58
|
+
assistantId: number;
|
|
59
|
+
chatId: number;
|
|
60
|
+
text: string;
|
|
61
|
+
fromAgent?: FromAgentInput;
|
|
62
|
+
/** Anchor this reply to an earlier message - BGOS renders a slim
|
|
63
|
+
* Telegram-style quoted header inside the bubble (tap → jump to
|
|
64
|
+
* source) and persists a frozen text/sender snapshot. Use when
|
|
65
|
+
* answering a stale question, following up on a past commitment,
|
|
66
|
+
* or surfacing a cron-triggered nudge tied to an older message.
|
|
67
|
+
* Same-chat constraint enforced server-side (400 otherwise). See
|
|
68
|
+
* bgos-agent-capabilities.md §9. */
|
|
69
|
+
replyToId?: number;
|
|
70
|
+
/** Route via `/send-message` instead of `/messages`. Set only for a2a
|
|
71
|
+
* peer replies so the backend's peer-reply bridge resolves the
|
|
72
|
+
* initiator's `wait_for_reply`. Defaults to `/messages` (unchanged). */
|
|
73
|
+
replyVia?: "messages" | "send-message";
|
|
74
|
+
}): Promise<{
|
|
75
|
+
id: number;
|
|
76
|
+
}>;
|
|
77
|
+
/**
|
|
78
|
+
* Send a text message stamped with an inline-agent identity.
|
|
79
|
+
*
|
|
80
|
+
* Each call produces a distinct bubble in the BGOS UI labeled with the
|
|
81
|
+
* supplied name / color / avatar - used by Codex's `/board` so the
|
|
82
|
+
* Research, Finance, Strategy, etc. agents each render as their own
|
|
83
|
+
* sender even though they share one bound assistant.
|
|
84
|
+
*
|
|
85
|
+
* The backend's hybrid resolver tries `peerId` (registry id) →
|
|
86
|
+
* `assistantId` (cross-assistant peer) → `externalId` (string lookup),
|
|
87
|
+
* falling back to inline `{name,color,avatarUrl}` when no peer is found.
|
|
88
|
+
* For Codex, pass `name` + `color` (and optionally `avatarUrl`) - the
|
|
89
|
+
* inline path is what we need.
|
|
90
|
+
*/
|
|
91
|
+
sendAsAgent(params: {
|
|
92
|
+
assistantId: number;
|
|
93
|
+
chatId: number;
|
|
94
|
+
text: string;
|
|
95
|
+
agent: FromAgentInput;
|
|
96
|
+
options?: MessageOption[];
|
|
97
|
+
}): Promise<{
|
|
98
|
+
id: number;
|
|
99
|
+
}>;
|
|
100
|
+
sendButtons(params: {
|
|
101
|
+
assistantId: number;
|
|
102
|
+
chatId: number;
|
|
103
|
+
text: string;
|
|
104
|
+
options: MessageOption[];
|
|
105
|
+
/** See sendText.replyToId. */
|
|
106
|
+
replyToId?: number;
|
|
107
|
+
/** See sendText.replyVia. */
|
|
108
|
+
replyVia?: "messages" | "send-message";
|
|
109
|
+
}): Promise<{
|
|
110
|
+
id: number;
|
|
111
|
+
}>;
|
|
112
|
+
/**
|
|
113
|
+
* Render an approval request bubble.
|
|
114
|
+
*
|
|
115
|
+
* Callback layout: `ea:<decision>:<reqId>` matching Telegram parity
|
|
116
|
+
* (Hermes uses the same prefix). Decisions: `once|session|always|deny`.
|
|
117
|
+
*
|
|
118
|
+
* Default options cover the standard 4-button bubble. Pass `options`
|
|
119
|
+
* explicitly to override (e.g. for a smaller agreement flow).
|
|
120
|
+
*/
|
|
121
|
+
sendApprovalRequest(params: {
|
|
122
|
+
assistantId: number;
|
|
123
|
+
chatId: number;
|
|
124
|
+
text: string;
|
|
125
|
+
meta: ApprovalMeta;
|
|
126
|
+
options?: MessageOption[];
|
|
127
|
+
/** See sendText.replyToId - anchor an approval bubble to the user's
|
|
128
|
+
* earlier request the agent is now asking permission to act on. */
|
|
129
|
+
replyToId?: number;
|
|
130
|
+
/** See sendText.replyVia. */
|
|
131
|
+
replyVia?: "messages" | "send-message";
|
|
132
|
+
}): Promise<{
|
|
133
|
+
id: number;
|
|
134
|
+
}>;
|
|
135
|
+
/**
|
|
136
|
+
* Send an `ask_user_input` prompt.
|
|
137
|
+
*
|
|
138
|
+
* `modal=true` (BGOS default for `ask_user_input`) renders as a
|
|
139
|
+
* pop-over sheet. `modal=false` renders as inline buttons that don't
|
|
140
|
+
* intrude. Use modal only when the user just messaged (~2 min) - see
|
|
141
|
+
* agent hints + the canonical capability doc.
|
|
142
|
+
*
|
|
143
|
+
* Today the backend's `messageType: 'ask_user_input'` carries `options`
|
|
144
|
+
* directly. If the canonical capability doc later splits askId/askOrder
|
|
145
|
+
* out, this method gains those args - for now we keep the surface
|
|
146
|
+
* minimal.
|
|
147
|
+
*/
|
|
148
|
+
sendAskUserInput(params: {
|
|
149
|
+
assistantId: number;
|
|
150
|
+
chatId: number;
|
|
151
|
+
prompt: string;
|
|
152
|
+
options?: MessageOption[];
|
|
153
|
+
modal?: boolean;
|
|
154
|
+
}): Promise<{
|
|
155
|
+
id: number;
|
|
156
|
+
}>;
|
|
157
|
+
/** Send a file (image, video, document, audio) via the attachment-bridge. */
|
|
158
|
+
sendFile(params: {
|
|
159
|
+
assistantId: number;
|
|
160
|
+
chatId: number;
|
|
161
|
+
filePath: string;
|
|
162
|
+
caption?: string;
|
|
163
|
+
fileName?: string;
|
|
164
|
+
mimeType?: string;
|
|
165
|
+
/** See sendText.replyToId. */
|
|
166
|
+
replyToId?: number;
|
|
167
|
+
/** See sendText.replyVia. */
|
|
168
|
+
replyVia?: "messages" | "send-message";
|
|
169
|
+
}): Promise<{
|
|
170
|
+
id: number;
|
|
171
|
+
}>;
|
|
172
|
+
/** Image - enforces image/* MIME if provided; otherwise lets MIME
|
|
173
|
+
* inference handle it. */
|
|
174
|
+
sendImage(params: {
|
|
175
|
+
assistantId: number;
|
|
176
|
+
chatId: number;
|
|
177
|
+
filePath: string;
|
|
178
|
+
caption?: string;
|
|
179
|
+
fileName?: string;
|
|
180
|
+
mimeType?: string;
|
|
181
|
+
/** See sendText.replyToId. */
|
|
182
|
+
replyToId?: number;
|
|
183
|
+
/** See sendText.replyVia. */
|
|
184
|
+
replyVia?: "messages" | "send-message";
|
|
185
|
+
}): Promise<{
|
|
186
|
+
id: number;
|
|
187
|
+
}>;
|
|
188
|
+
/** Video - enforces video/* MIME if provided. */
|
|
189
|
+
sendVideo(params: {
|
|
190
|
+
assistantId: number;
|
|
191
|
+
chatId: number;
|
|
192
|
+
filePath: string;
|
|
193
|
+
caption?: string;
|
|
194
|
+
fileName?: string;
|
|
195
|
+
mimeType?: string;
|
|
196
|
+
/** See sendText.replyToId. */
|
|
197
|
+
replyToId?: number;
|
|
198
|
+
/** See sendText.replyVia. */
|
|
199
|
+
replyVia?: "messages" | "send-message";
|
|
200
|
+
}): Promise<{
|
|
201
|
+
id: number;
|
|
202
|
+
}>;
|
|
203
|
+
sendAgentError(params: {
|
|
204
|
+
assistantId: number;
|
|
205
|
+
chatId: number;
|
|
206
|
+
reason: string;
|
|
207
|
+
}): Promise<{
|
|
208
|
+
id: number;
|
|
209
|
+
}>;
|
|
210
|
+
/**
|
|
211
|
+
* Send a "typing..." indicator (contract C4). Emits the client-side WS
|
|
212
|
+
* `typing` event via the wired emitter (throttled 1/3s per chat inside
|
|
213
|
+
* BgosWs). Best-effort: no emitter wired (or an emit failure) resolves
|
|
214
|
+
* silently so a reply path is never broken over a typing indicator.
|
|
215
|
+
*/
|
|
216
|
+
sendTyping(params: {
|
|
217
|
+
assistantId: number;
|
|
218
|
+
chatId: number;
|
|
219
|
+
}): Promise<void>;
|
|
220
|
+
}
|
|
221
|
+
/** Backwards-compatible alias retained for the public API surface. */
|
|
222
|
+
export { BgosOutbound as BGOSOutbound };
|
|
223
|
+
//# sourceMappingURL=outbound.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound.d.ts","sourceRoot":"","sources":["../src/outbound.ts"],"names":[],"mappings":"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"}
|
package/dist/outbound.js
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
import { publishMediaPath } from "./attachment-bridge.js";
|
|
2
|
+
import { sanitizeFromAgent } from "./agent-identity.js";
|
|
3
|
+
import { classifyOutboundError, OUTBOUND_BACKOFFS_MS, } from "./outbound-retry.js";
|
|
4
|
+
import { appendOutbox, loadOutbox, rewriteOutbox, } from "./outbox.js";
|
|
5
|
+
/**
|
|
6
|
+
* High-level outbound adapter for the Codex channel.
|
|
7
|
+
*
|
|
8
|
+
* Wraps `BgosApi.postMessage` with the modality-specific helpers
|
|
9
|
+
* `BGOSAdapter` + the fork's reply-handle expose:
|
|
10
|
+
* - `sendText` plain assistant reply
|
|
11
|
+
* - `sendButtons` text + ≤6 inline option chips
|
|
12
|
+
* - `sendApprovalRequest` approval bubble (`ea:<decision>:<reqId>`)
|
|
13
|
+
* - `sendAskUserInput` blocking pop-under (modal or inline)
|
|
14
|
+
* - `sendFile/Image/Video` attach a local file via attachment-bridge
|
|
15
|
+
* - `sendAgentError` styled error bubble used on dispatch failure
|
|
16
|
+
* - `sendTyping` best-effort indicator (no-op on backend today)
|
|
17
|
+
*
|
|
18
|
+
* Validation is light - the backend does the authoritative checks. We
|
|
19
|
+
* enforce limits client-side only when the failure mode is silent (e.g.
|
|
20
|
+
* options>6 truncates, not 400; message-type mismatches sometimes
|
|
21
|
+
* succeed but render wrong). Limits we enforce:
|
|
22
|
+
* - inline buttons: max 6 options (matches PR #62 backend limit + the
|
|
23
|
+
* `inline_buttons_shipped` memory).
|
|
24
|
+
*
|
|
25
|
+
* `BgosOutbound` is the canonical export used everywhere; `BGOSOutbound`
|
|
26
|
+
* is kept as an alias for the brief moment in PR #82 where the scaffold
|
|
27
|
+
* named it that way (so existing imports don't break).
|
|
28
|
+
*/
|
|
29
|
+
/** Backend rejects inline messages with >6 options. */
|
|
30
|
+
const INLINE_OPTION_LIMIT = 6;
|
|
31
|
+
export class BgosOutbound {
|
|
32
|
+
/** Public read-only handle on the underlying REST client; consumers
|
|
33
|
+
* occasionally need it (e.g. inbound-handler routes uploadFile through
|
|
34
|
+
* publishMediaPath). */
|
|
35
|
+
api;
|
|
36
|
+
typingEmitter = null;
|
|
37
|
+
onLastError = null;
|
|
38
|
+
onOutbound = null;
|
|
39
|
+
/** Single-flight guard for replaySpool: concurrent callers (the 60s spool
|
|
40
|
+
* timer, onReconnect, recover) await the same in-flight run instead of each
|
|
41
|
+
* loading + re-sending the same spooled entries (double-send). */
|
|
42
|
+
spoolInFlight = null;
|
|
43
|
+
sleepFn = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
44
|
+
constructor(api) {
|
|
45
|
+
this.api = api;
|
|
46
|
+
}
|
|
47
|
+
/** Wire the WS typing emitter (contract C4). Without it, sendTyping no-ops. */
|
|
48
|
+
setTypingEmitter(fn) {
|
|
49
|
+
this.typingEmitter = fn;
|
|
50
|
+
}
|
|
51
|
+
/** Report an outbound failure to the heartbeat lastError channel. */
|
|
52
|
+
setLastErrorReporter(fn) {
|
|
53
|
+
this.onLastError = fn;
|
|
54
|
+
}
|
|
55
|
+
/** Called on every successful send (drives heartbeat lastOutboundAt). */
|
|
56
|
+
setOutboundReporter(fn) {
|
|
57
|
+
this.onOutbound = fn;
|
|
58
|
+
}
|
|
59
|
+
/** Test seam: override the retry sleep so specs don't wait real seconds. */
|
|
60
|
+
setSleepFn(fn) {
|
|
61
|
+
this.sleepFn = fn;
|
|
62
|
+
}
|
|
63
|
+
rawSend(payload, replyVia) {
|
|
64
|
+
return replyVia === "send-message"
|
|
65
|
+
? this.api.sendMessage(payload)
|
|
66
|
+
: this.api.postMessage(payload);
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Pick the reply endpoint + apply the outbound retry policy (contract C3).
|
|
70
|
+
*
|
|
71
|
+
* Default `messages` (POST /api/v1/messages) is the historical path used for
|
|
72
|
+
* every normal reply, proactive send, and `/board` fan-out. `send-message`
|
|
73
|
+
* (POST /api/v1/send-message) is used ONLY for a2a peer replies.
|
|
74
|
+
*
|
|
75
|
+
* Retry (backoff 1s/5s/25s) applies ONLY to the provably-undelivered
|
|
76
|
+
* network-error class + 429 (see classifyOutboundError), because the backend
|
|
77
|
+
* insert is not idempotent. Ambiguous failures (timeouts, 5xx) are NOT
|
|
78
|
+
* retried and reject to the caller. After 3 failed retries of the safe class
|
|
79
|
+
* the payload is spooled to the outbox for later replay.
|
|
80
|
+
*/
|
|
81
|
+
async deliver(payload, replyVia) {
|
|
82
|
+
let attempt = 0;
|
|
83
|
+
for (;;) {
|
|
84
|
+
try {
|
|
85
|
+
const r = await this.rawSend(payload, replyVia);
|
|
86
|
+
this.onOutbound?.();
|
|
87
|
+
return r;
|
|
88
|
+
}
|
|
89
|
+
catch (err) {
|
|
90
|
+
const cls = classifyOutboundError(err);
|
|
91
|
+
if (cls.retriable && attempt < OUTBOUND_BACKOFFS_MS.length) {
|
|
92
|
+
const wait = cls.retryAfterMs ?? OUTBOUND_BACKOFFS_MS[attempt];
|
|
93
|
+
attempt += 1;
|
|
94
|
+
await this.sleepFn(wait);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
98
|
+
if (cls.retriable) {
|
|
99
|
+
// Exhausted the safe class: spool for later replay.
|
|
100
|
+
appendOutbox({
|
|
101
|
+
ts: Date.now(),
|
|
102
|
+
payload,
|
|
103
|
+
...(replyVia ? { replyVia } : {}),
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
this.onLastError?.("outbound_failed", message);
|
|
107
|
+
throw err;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Replay any spooled outbound payloads (contract C3). Called by the adapter
|
|
113
|
+
* on WS reconnect and every 60s while non-empty. Entries older than 24h are
|
|
114
|
+
* dropped on load; safe-class failures are re-kept, ambiguous failures on
|
|
115
|
+
* replay are dropped to avoid a non-idempotent duplicate.
|
|
116
|
+
*
|
|
117
|
+
* Single-flight: concurrent callers (the 60s spool timer racing an
|
|
118
|
+
* onReconnect racing a recover, or WS flapping spawning overlapping
|
|
119
|
+
* onReconnects) coalesce onto one in-flight run. Two overlapping runs would
|
|
120
|
+
* otherwise both load the SAME entries and each re-send them, and the backend
|
|
121
|
+
* insert is NOT idempotent, so that produces duplicate agent messages.
|
|
122
|
+
*/
|
|
123
|
+
replaySpool() {
|
|
124
|
+
if (this.spoolInFlight)
|
|
125
|
+
return this.spoolInFlight;
|
|
126
|
+
this.spoolInFlight = this.runReplaySpool().finally(() => {
|
|
127
|
+
this.spoolInFlight = null;
|
|
128
|
+
});
|
|
129
|
+
return this.spoolInFlight;
|
|
130
|
+
}
|
|
131
|
+
async runReplaySpool() {
|
|
132
|
+
const entries = loadOutbox();
|
|
133
|
+
if (entries.length === 0)
|
|
134
|
+
return;
|
|
135
|
+
// Claim the entries by clearing the spool up-front (atomic tmp + rename).
|
|
136
|
+
// At-most-once for the non-idempotent insert: a crash mid-replay cannot
|
|
137
|
+
// double-send on restart, and a concurrent send failure re-spools below.
|
|
138
|
+
// Failed safe-class entries are re-APPENDED (not rewritten) so a
|
|
139
|
+
// concurrent deliver() spool during replay is preserved.
|
|
140
|
+
rewriteOutbox([]);
|
|
141
|
+
for (const entry of entries) {
|
|
142
|
+
try {
|
|
143
|
+
await this.rawSend(entry.payload, entry.replyVia);
|
|
144
|
+
this.onOutbound?.();
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
const cls = classifyOutboundError(err);
|
|
148
|
+
if (cls.retriable)
|
|
149
|
+
appendOutbox(entry);
|
|
150
|
+
// Ambiguous replay failures are dropped: the write may have applied.
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
// -------------------------------------------------------------------
|
|
155
|
+
// Text + buttons
|
|
156
|
+
// -------------------------------------------------------------------
|
|
157
|
+
sendText(params) {
|
|
158
|
+
const fromAgent = sanitizeFromAgent(params.fromAgent);
|
|
159
|
+
const payload = {
|
|
160
|
+
assistantId: params.assistantId,
|
|
161
|
+
chatId: params.chatId,
|
|
162
|
+
sender: "assistant",
|
|
163
|
+
text: params.text,
|
|
164
|
+
messageType: "standard",
|
|
165
|
+
...(fromAgent ? { fromAgent } : {}),
|
|
166
|
+
...(params.replyToId !== undefined && { replyToId: params.replyToId }),
|
|
167
|
+
};
|
|
168
|
+
return this.deliver(payload, params.replyVia);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Send a text message stamped with an inline-agent identity.
|
|
172
|
+
*
|
|
173
|
+
* Each call produces a distinct bubble in the BGOS UI labeled with the
|
|
174
|
+
* supplied name / color / avatar - used by Codex's `/board` so the
|
|
175
|
+
* Research, Finance, Strategy, etc. agents each render as their own
|
|
176
|
+
* sender even though they share one bound assistant.
|
|
177
|
+
*
|
|
178
|
+
* The backend's hybrid resolver tries `peerId` (registry id) →
|
|
179
|
+
* `assistantId` (cross-assistant peer) → `externalId` (string lookup),
|
|
180
|
+
* falling back to inline `{name,color,avatarUrl}` when no peer is found.
|
|
181
|
+
* For Codex, pass `name` + `color` (and optionally `avatarUrl`) - the
|
|
182
|
+
* inline path is what we need.
|
|
183
|
+
*/
|
|
184
|
+
sendAsAgent(params) {
|
|
185
|
+
if (params.options !== undefined &&
|
|
186
|
+
params.options.length > INLINE_OPTION_LIMIT) {
|
|
187
|
+
throw new Error(`sendAsAgent: ${params.options.length} options exceeds inline limit (${INLINE_OPTION_LIMIT})`);
|
|
188
|
+
}
|
|
189
|
+
const fromAgent = sanitizeFromAgent(params.agent);
|
|
190
|
+
const payload = {
|
|
191
|
+
assistantId: params.assistantId,
|
|
192
|
+
chatId: params.chatId,
|
|
193
|
+
sender: "assistant",
|
|
194
|
+
text: params.text,
|
|
195
|
+
messageType: "standard",
|
|
196
|
+
...(fromAgent ? { fromAgent } : {}),
|
|
197
|
+
...(params.options ? { options: params.options } : {}),
|
|
198
|
+
};
|
|
199
|
+
return this.api.postMessage(payload);
|
|
200
|
+
}
|
|
201
|
+
sendButtons(params) {
|
|
202
|
+
if (params.options.length > INLINE_OPTION_LIMIT) {
|
|
203
|
+
// Throw rather than truncate - the agent should be told it sent
|
|
204
|
+
// too many options so it can re-emit. (Hermes truncates with a
|
|
205
|
+
// warning because the agent gets the buttons via a regex in its
|
|
206
|
+
// text; we have a typed call here so the contract is firmer.)
|
|
207
|
+
throw new Error(`sendButtons: ${params.options.length} options exceeds inline limit (${INLINE_OPTION_LIMIT})`);
|
|
208
|
+
}
|
|
209
|
+
const payload = {
|
|
210
|
+
assistantId: params.assistantId,
|
|
211
|
+
chatId: params.chatId,
|
|
212
|
+
sender: "assistant",
|
|
213
|
+
text: params.text,
|
|
214
|
+
options: params.options,
|
|
215
|
+
messageType: "standard",
|
|
216
|
+
...(params.replyToId !== undefined && { replyToId: params.replyToId }),
|
|
217
|
+
};
|
|
218
|
+
return this.deliver(payload, params.replyVia);
|
|
219
|
+
}
|
|
220
|
+
// -------------------------------------------------------------------
|
|
221
|
+
// Approval bubbles
|
|
222
|
+
// -------------------------------------------------------------------
|
|
223
|
+
/**
|
|
224
|
+
* Render an approval request bubble.
|
|
225
|
+
*
|
|
226
|
+
* Callback layout: `ea:<decision>:<reqId>` matching Telegram parity
|
|
227
|
+
* (Hermes uses the same prefix). Decisions: `once|session|always|deny`.
|
|
228
|
+
*
|
|
229
|
+
* Default options cover the standard 4-button bubble. Pass `options`
|
|
230
|
+
* explicitly to override (e.g. for a smaller agreement flow).
|
|
231
|
+
*/
|
|
232
|
+
sendApprovalRequest(params) {
|
|
233
|
+
const reqId = params.meta.request_id;
|
|
234
|
+
const defaults = [
|
|
235
|
+
{
|
|
236
|
+
text: "Allow once",
|
|
237
|
+
callbackData: `ea:once:${reqId}`,
|
|
238
|
+
style: "success",
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
text: "Allow for session",
|
|
242
|
+
callbackData: `ea:session:${reqId}`,
|
|
243
|
+
style: "success",
|
|
244
|
+
},
|
|
245
|
+
{
|
|
246
|
+
text: "Always allow",
|
|
247
|
+
callbackData: `ea:always:${reqId}`,
|
|
248
|
+
style: "default",
|
|
249
|
+
},
|
|
250
|
+
{ text: "Deny", callbackData: `ea:deny:${reqId}`, style: "danger" },
|
|
251
|
+
];
|
|
252
|
+
const payload = {
|
|
253
|
+
assistantId: params.assistantId,
|
|
254
|
+
chatId: params.chatId,
|
|
255
|
+
sender: "assistant",
|
|
256
|
+
text: params.text,
|
|
257
|
+
options: params.options ?? defaults,
|
|
258
|
+
messageType: "approval_request",
|
|
259
|
+
approvalMeta: params.meta,
|
|
260
|
+
...(params.replyToId !== undefined && { replyToId: params.replyToId }),
|
|
261
|
+
};
|
|
262
|
+
return this.deliver(payload, params.replyVia);
|
|
263
|
+
}
|
|
264
|
+
// -------------------------------------------------------------------
|
|
265
|
+
// ask_user_input pop-under (modal or inline)
|
|
266
|
+
// -------------------------------------------------------------------
|
|
267
|
+
/**
|
|
268
|
+
* Send an `ask_user_input` prompt.
|
|
269
|
+
*
|
|
270
|
+
* `modal=true` (BGOS default for `ask_user_input`) renders as a
|
|
271
|
+
* pop-over sheet. `modal=false` renders as inline buttons that don't
|
|
272
|
+
* intrude. Use modal only when the user just messaged (~2 min) - see
|
|
273
|
+
* agent hints + the canonical capability doc.
|
|
274
|
+
*
|
|
275
|
+
* Today the backend's `messageType: 'ask_user_input'` carries `options`
|
|
276
|
+
* directly. If the canonical capability doc later splits askId/askOrder
|
|
277
|
+
* out, this method gains those args - for now we keep the surface
|
|
278
|
+
* minimal.
|
|
279
|
+
*/
|
|
280
|
+
sendAskUserInput(params) {
|
|
281
|
+
if (params.options &&
|
|
282
|
+
params.options.length > INLINE_OPTION_LIMIT &&
|
|
283
|
+
params.modal === false) {
|
|
284
|
+
throw new Error(`sendAskUserInput (inline): ${params.options.length} options exceeds inline limit (${INLINE_OPTION_LIMIT})`);
|
|
285
|
+
}
|
|
286
|
+
const payload = {
|
|
287
|
+
assistantId: params.assistantId,
|
|
288
|
+
chatId: params.chatId,
|
|
289
|
+
sender: "assistant",
|
|
290
|
+
text: params.prompt,
|
|
291
|
+
// The backend's messageType union doesn't include "ask_user_input"
|
|
292
|
+
// in the OutboundMessagePayload type today - but the wire format
|
|
293
|
+
// accepts it (the canonical capability doc documents it). Cast to
|
|
294
|
+
// sidestep the union, mirroring how Hermes handles this.
|
|
295
|
+
messageType: "ask_user_input",
|
|
296
|
+
options: params.options,
|
|
297
|
+
};
|
|
298
|
+
return this.api.postMessage(payload);
|
|
299
|
+
}
|
|
300
|
+
// -------------------------------------------------------------------
|
|
301
|
+
// Files / media
|
|
302
|
+
// -------------------------------------------------------------------
|
|
303
|
+
/** Send a file (image, video, document, audio) via the attachment-bridge. */
|
|
304
|
+
async sendFile(params) {
|
|
305
|
+
const fileRef = await publishMediaPath(this.api, params.filePath, {
|
|
306
|
+
fileName: params.fileName,
|
|
307
|
+
mimeType: params.mimeType,
|
|
308
|
+
});
|
|
309
|
+
const payload = {
|
|
310
|
+
assistantId: params.assistantId,
|
|
311
|
+
chatId: params.chatId,
|
|
312
|
+
sender: "assistant",
|
|
313
|
+
text: params.caption ?? "",
|
|
314
|
+
messageType: "standard",
|
|
315
|
+
files: [fileRef],
|
|
316
|
+
...(params.replyToId !== undefined && { replyToId: params.replyToId }),
|
|
317
|
+
};
|
|
318
|
+
return this.deliver(payload, params.replyVia);
|
|
319
|
+
}
|
|
320
|
+
/** Image - enforces image/* MIME if provided; otherwise lets MIME
|
|
321
|
+
* inference handle it. */
|
|
322
|
+
sendImage(params) {
|
|
323
|
+
if (params.mimeType && !params.mimeType.startsWith("image/")) {
|
|
324
|
+
throw new Error(`sendImage: mimeType ${params.mimeType} is not image/*`);
|
|
325
|
+
}
|
|
326
|
+
return this.sendFile(params);
|
|
327
|
+
}
|
|
328
|
+
/** Video - enforces video/* MIME if provided. */
|
|
329
|
+
sendVideo(params) {
|
|
330
|
+
if (params.mimeType && !params.mimeType.startsWith("video/")) {
|
|
331
|
+
throw new Error(`sendVideo: mimeType ${params.mimeType} is not video/*`);
|
|
332
|
+
}
|
|
333
|
+
return this.sendFile(params);
|
|
334
|
+
}
|
|
335
|
+
// -------------------------------------------------------------------
|
|
336
|
+
// Errors + typing
|
|
337
|
+
// -------------------------------------------------------------------
|
|
338
|
+
sendAgentError(params) {
|
|
339
|
+
const payload = {
|
|
340
|
+
assistantId: params.assistantId,
|
|
341
|
+
chatId: params.chatId,
|
|
342
|
+
sender: "assistant",
|
|
343
|
+
text: `⚠ Agent error: ${params.reason}`,
|
|
344
|
+
messageType: "agent_error",
|
|
345
|
+
};
|
|
346
|
+
return this.api.postMessage(payload);
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Send a "typing..." indicator (contract C4). Emits the client-side WS
|
|
350
|
+
* `typing` event via the wired emitter (throttled 1/3s per chat inside
|
|
351
|
+
* BgosWs). Best-effort: no emitter wired (or an emit failure) resolves
|
|
352
|
+
* silently so a reply path is never broken over a typing indicator.
|
|
353
|
+
*/
|
|
354
|
+
async sendTyping(params) {
|
|
355
|
+
try {
|
|
356
|
+
this.typingEmitter?.(params);
|
|
357
|
+
}
|
|
358
|
+
catch {
|
|
359
|
+
/* best-effort */
|
|
360
|
+
}
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
/** Backwards-compatible alias retained for the public API surface. */
|
|
365
|
+
export { BgosOutbound as BGOSOutbound };
|
|
366
|
+
//# sourceMappingURL=outbound.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbound.js","sourceRoot":"","sources":["../src/outbound.ts"],"names":[],"mappings":"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"}
|
package/dist/outbox.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { OutboundMessagePayload } from "./types.js";
|
|
2
|
+
export interface OutboxEntry {
|
|
3
|
+
/** Epoch ms when the entry was spooled. */
|
|
4
|
+
ts: number;
|
|
5
|
+
payload: OutboundMessagePayload;
|
|
6
|
+
replyVia?: "messages" | "send-message";
|
|
7
|
+
}
|
|
8
|
+
/** Read the spool, dropping entries older than 24h. Never throws. */
|
|
9
|
+
export declare function loadOutbox(): OutboxEntry[];
|
|
10
|
+
/** Append one entry, then compact to the newest MAX_ENTRIES. Never throws. */
|
|
11
|
+
export declare function appendOutbox(entry: OutboxEntry): void;
|
|
12
|
+
/** Atomically replace the spool with `entries` (tmp + rename). Never throws. */
|
|
13
|
+
export declare function rewriteOutbox(entries: OutboxEntry[]): void;
|
|
14
|
+
/** Empty the spool. Never throws. */
|
|
15
|
+
export declare function clearOutbox(): void;
|
|
16
|
+
//# sourceMappingURL=outbox.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"outbox.d.ts","sourceRoot":"","sources":["../src/outbox.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzD,MAAM,WAAW,WAAW;IAC1B,2CAA2C;IAC3C,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,sBAAsB,CAAC;IAChC,QAAQ,CAAC,EAAE,UAAU,GAAG,cAAc,CAAC;CACxC;AAUD,qEAAqE;AACrE,wBAAgB,UAAU,IAAI,WAAW,EAAE,CA2B1C;AAED,8EAA8E;AAC9E,wBAAgB,YAAY,CAAC,KAAK,EAAE,WAAW,GAAG,IAAI,CAarD;AAED,gFAAgF;AAChF,wBAAgB,aAAa,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,IAAI,CAW1D;AAED,qCAAqC;AACrC,wBAAgB,WAAW,IAAI,IAAI,CAElC"}
|