@omelhorsite/sdk 0.16.0 → 0.18.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.
@@ -93,7 +93,7 @@ export interface TokenStore {
93
93
  * narrowest set the product actually uses: every extra scope makes the
94
94
  * approval page scarier for no benefit.
95
95
  */
96
- export declare const OMS_SCOPES: readonly ["openid", "profile", "email", "tools:read", "tools:write", "storage:read", "storage:write", "tickets:write", "llm", "blogs:read", "blogs:write", "news:read", "news:write", "cron:read", "cron:write"];
96
+ export declare const OMS_SCOPES: readonly ["openid", "profile", "email", "tools:read", "tools:write", "storage:read", "storage:write", "tickets:write", "llm", "blogs:read", "blogs:write", "news:read", "news:write", "cron:read", "cron:write", "cron:run", "bots:read", "bots:write"];
97
97
  /** One of {@link OMS_SCOPES}. */
98
98
  export type OmsScope = (typeof OMS_SCOPES)[number];
99
99
  /** Refresh this long before the real expiry unless the host says otherwise. */
@@ -20,6 +20,7 @@ import { AuthSessionsNamespace } from "./resources/auth/sessions";
20
20
  import { ChestsNamespace } from "./resources/chests";
21
21
  import { ContentNamespace } from "./resources/content";
22
22
  import { CronNamespace } from "./resources/cron";
23
+ import { BotsNamespace } from "./resources/bots";
23
24
  import { DynamicQrsNamespace } from "./resources/dynamicQrs";
24
25
  import { FormsNamespace } from "./resources/forms";
25
26
  import { IpLookupNamespace } from "./resources/ipLookup";
@@ -186,6 +187,8 @@ export declare class Oms {
186
187
  readonly llm: LlmNamespace;
187
188
  /** TypeScript scripts the server runs on a schedule as the signed-in person. */
188
189
  readonly cron: CronNamespace;
190
+ /** Messaging channels (Telegram bots): contacts, conversations, sending. */
191
+ readonly bots: BotsNamespace;
189
192
  /**
190
193
  * The WebSocket connection: playback handoff, jams, notifications, job
191
194
  * progress. Opens nothing until {@link RealtimeNamespace.connect} is called,
@@ -100,6 +100,22 @@ export interface LlmProviderTestResult {
100
100
  readonly latency_ms?: number;
101
101
  readonly error?: string;
102
102
  }
103
+ /**
104
+ * One upstream serving a model on OpenRouter: the same model at a different
105
+ * price and health per real provider. `status` is `0` when healthy and
106
+ * negative while OpenRouter steers traffic away from it.
107
+ */
108
+ export interface LlmModelEndpoint {
109
+ /** The routing tag, e.g. `"openai/flex"`; what goes in `metadata.routing.order`. */
110
+ readonly tag: string;
111
+ readonly name: string;
112
+ readonly input_price_per_million: number | null;
113
+ readonly output_price_per_million: number | null;
114
+ readonly context_window: number | null;
115
+ readonly max_output_tokens: number | null;
116
+ readonly status: number;
117
+ readonly capabilities: LlmCapabilities;
118
+ }
103
119
  export interface TestLlmProviderInput {
104
120
  /** A `model_id` of that provider; defaults to its first enabled model. */
105
121
  readonly modelId?: string;
@@ -149,6 +165,13 @@ export interface CreateLlmModelInput {
149
165
  readonly free?: boolean;
150
166
  readonly capabilities?: LlmCapabilities;
151
167
  readonly limits?: LlmLimits;
168
+ /**
169
+ * Free-form notes on the model. One key is read: `routing`, the OpenRouter
170
+ * `provider` object sent with every request to this model, for instance
171
+ * `{ order: ["openai/flex"], allow_fallbacks: false }` to pin the cheapest
172
+ * upstream. Pick a tag from {@link AdminLlmProvidersNamespace.modelEndpoints}.
173
+ */
174
+ readonly metadata?: JsonObject;
152
175
  }
153
176
  /** The provider and the `model_id` are fixed after creation. */
154
177
  export type UpdateLlmModelInput = Partial<Omit<CreateLlmModelInput, "llmProviderId" | "modelId">>;
@@ -231,6 +254,17 @@ export declare class AdminLlmProvidersNamespace extends Resource {
231
254
  availableModels(id: Id, input?: {
232
255
  fresh?: boolean;
233
256
  }, options?: RequestOptions): Promise<LlmAvailableModel[]>;
257
+ /**
258
+ * `GET /admin/llm_providers/:id/model_endpoints` - the upstreams that serve
259
+ * a model on OpenRouter, cheapest first, with their prices. Empty on any
260
+ * other kind of provider. Cached for ten minutes; `fresh` skips the cache.
261
+ *
262
+ * @throws {OmsApiError} 400 without `modelId`; 502 when OpenRouter does not answer.
263
+ */
264
+ modelEndpoints(id: Id, input: {
265
+ modelId: string;
266
+ fresh?: boolean;
267
+ }, options?: RequestOptions): Promise<LlmModelEndpoint[]>;
234
268
  /** One tiny completion, to check the key, the URL and a model. */
235
269
  test(id: Id, input?: TestLlmProviderInput, options?: RequestOptions): Promise<LlmProviderTestResult>;
236
270
  }
@@ -0,0 +1,394 @@
1
+ /**
2
+ * The `bots` namespace: messaging channels (Telegram bots for now), the
3
+ * contacts who talk to them and the conversations, plus sending.
4
+ *
5
+ * A channel is a bot token the account connected; the server validates it,
6
+ * registers a webhook and from then on every message the bot receives lands
7
+ * here as a {@link BotContact} and a {@link BotMessage}. Sending is
8
+ * {@link BotMessagesNamespace.send}: the server talks to Telegram and records
9
+ * the outgoing message with its source, so an inbox shows what went where.
10
+ *
11
+ * Needs the `bots:read` scope to read and `bots:write` to send or connect.
12
+ */
13
+ import { Resource } from "../http";
14
+ import type { ApiClient } from "../http";
15
+ import type { ListParams } from "../listing";
16
+ import type { Id, Paginated, RequestOptions, Timestamp } from "../types";
17
+ export declare const BOT_CHANNEL_KINDS: readonly ["telegram"];
18
+ export type BotChannelKind = (typeof BOT_CHANNEL_KINDS)[number];
19
+ export declare const BOT_CHANNEL_HEALTHS: readonly ["unknown", "ok", "error"];
20
+ export type BotChannelHealth = (typeof BOT_CHANNEL_HEALTHS)[number];
21
+ /** What the bot does: `inbox` keeps the conversations and lets the API send; `responder` answers on the owner's behalf. */
22
+ export declare const BOT_PLUGINS: readonly ["inbox", "responder"];
23
+ export type BotPlugin = (typeof BOT_PLUGINS)[number];
24
+ /** Telegram's own cap on a message's text. Longer is a `400`. */
25
+ export declare const BOT_MESSAGE_MAX_TEXT = 4096;
26
+ /** A connected bot. The token never comes back: only whether one is stored. */
27
+ export interface BotChannel {
28
+ readonly id: Id;
29
+ readonly created_at: Timestamp;
30
+ readonly updated_at: Timestamp;
31
+ readonly name: string;
32
+ readonly kind: BotChannelKind;
33
+ readonly plugin: BotPlugin;
34
+ /** The bot's own handle on the platform, filled from the token. */
35
+ readonly username: string | null;
36
+ /** The bot's own id on the platform. */
37
+ readonly external_id: string | null;
38
+ readonly enabled: boolean;
39
+ readonly health: BotChannelHealth;
40
+ readonly last_error: string | null;
41
+ readonly last_message_at: Timestamp | null;
42
+ readonly token_set: boolean;
43
+ /** Where the platform delivers the bot's updates. */
44
+ readonly webhook_url: string;
45
+ }
46
+ /** `GET /bot_channels/:id` adds two counters. */
47
+ export interface BotChannelDetail extends BotChannel {
48
+ readonly contacts_count: number;
49
+ readonly unread_count: number;
50
+ }
51
+ export interface CreateBotChannelInput {
52
+ readonly name: string;
53
+ /** The token the platform's bot factory gave you (Telegram: @BotFather). */
54
+ readonly token: string;
55
+ readonly kind?: BotChannelKind;
56
+ /** Defaults to `inbox`. */
57
+ readonly plugin?: BotPlugin;
58
+ readonly enabled?: boolean;
59
+ }
60
+ /** A new `token` reconnects the channel; omit it to keep the stored one. */
61
+ export type UpdateBotChannelInput = Partial<CreateBotChannelInput>;
62
+ /** What the platform reports about the bot and its webhook. */
63
+ export type BotChannelStatus = {
64
+ readonly ok: true;
65
+ readonly username: string | null;
66
+ readonly webhook_url: string;
67
+ readonly webhook_set: boolean;
68
+ readonly pending_updates: number;
69
+ readonly last_error: string | null;
70
+ } | {
71
+ readonly ok: false;
72
+ readonly error: string;
73
+ };
74
+ export declare const BOT_CHANNEL_FILTER_COLUMNS: readonly ["name", "kind", "enabled"];
75
+ export interface ListBotChannelsParams extends ListParams<(typeof BOT_CHANNEL_FILTER_COLUMNS)[number]> {
76
+ }
77
+ export declare const BOT_CONTACT_KINDS: readonly ["private", "group", "supergroup", "channel"];
78
+ export type BotContactKind = (typeof BOT_CONTACT_KINDS)[number];
79
+ /** Someone (or some group) that talked to a channel. */
80
+ export interface BotContact {
81
+ readonly id: Id;
82
+ readonly created_at: Timestamp;
83
+ readonly updated_at: Timestamp;
84
+ readonly bot_channel_id: Id;
85
+ /** The chat id on the platform. */
86
+ readonly external_id: string;
87
+ readonly kind: BotContactKind;
88
+ readonly name: string | null;
89
+ readonly username: string | null;
90
+ readonly tags: string[];
91
+ /** The contact blocked the bot or left the group: sending is refused. */
92
+ readonly blocked: boolean;
93
+ readonly last_message_at: Timestamp | null;
94
+ readonly last_direction: "in" | "out" | null;
95
+ readonly last_text: string | null;
96
+ readonly messages_count: number;
97
+ readonly unread_count: number;
98
+ /** The responder could not answer; `note` says what was missing. */
99
+ readonly needs_human: boolean;
100
+ readonly note: string | null;
101
+ readonly handled_until: Timestamp | null;
102
+ /** The name, or `@username`, or the chat id. */
103
+ readonly display_name: string;
104
+ }
105
+ export interface UpdateBotContactInput {
106
+ readonly name?: string | null;
107
+ readonly tags?: readonly string[];
108
+ readonly needs_human?: boolean;
109
+ readonly note?: string | null;
110
+ }
111
+ export declare const BOT_CONTACT_FILTER_COLUMNS: readonly ["bot_channel_id", "external_id", "username", "kind", "blocked"];
112
+ export interface ListBotContactsParams extends ListParams<(typeof BOT_CONTACT_FILTER_COLUMNS)[number]> {
113
+ /** Only contacts of one channel. */
114
+ readonly channelId?: Id;
115
+ }
116
+ export type BotMessageDirection = "in" | "out";
117
+ /** `contact` came in; `human` was sent from the inbox; `api` by a token (a script, the CLI); `bot` by the responder. */
118
+ export type BotMessageSource = "contact" | "human" | "api" | "bot";
119
+ export interface BotMessage {
120
+ readonly id: Id;
121
+ readonly created_at: Timestamp;
122
+ readonly updated_at: Timestamp;
123
+ readonly bot_channel_id: Id;
124
+ readonly bot_contact_id: Id;
125
+ readonly direction: BotMessageDirection;
126
+ readonly source: BotMessageSource;
127
+ readonly text: string;
128
+ readonly external_id: string | null;
129
+ readonly sent_at: Timestamp;
130
+ /** Set when the platform refused the send; the row stays so the thread shows it. */
131
+ readonly error: string | null;
132
+ }
133
+ export declare const BOT_MESSAGE_FILTER_COLUMNS: readonly ["bot_channel_id", "bot_contact_id", "direction", "source"];
134
+ export interface ListBotMessagesParams extends ListParams<(typeof BOT_MESSAGE_FILTER_COLUMNS)[number]> {
135
+ readonly contactId?: Id;
136
+ readonly channelId?: Id;
137
+ }
138
+ /** `text` for the text as typed; `html` for Telegram's HTML subset (bold, links, blockquote). */
139
+ export type BotMessageFormat = "text" | "html";
140
+ export type SendBotMessageInput = ({
141
+ readonly contactId: Id;
142
+ readonly channelId?: undefined;
143
+ readonly externalId?: undefined;
144
+ } | {
145
+ /** A contact that has not written yet, by channel and chat id. */
146
+ readonly channelId: Id;
147
+ readonly externalId: string;
148
+ readonly contactId?: undefined;
149
+ }) & {
150
+ readonly text: string;
151
+ readonly format?: BotMessageFormat;
152
+ };
153
+ /** The responder of a channel whose plugin is `responder`. `id` is null until it is first saved. */
154
+ export interface BotResponder {
155
+ readonly id: Id | null;
156
+ readonly created_at: Timestamp | null;
157
+ readonly updated_at: Timestamp | null;
158
+ readonly bot_channel_id: Id;
159
+ readonly enabled: boolean;
160
+ readonly system_prompt: string;
161
+ readonly knowledge: string;
162
+ readonly signature: string;
163
+ /** An LLM model id or model_id; null for the account's default. */
164
+ readonly model: string | null;
165
+ /** Runs per day, at hours drawn inside the window. */
166
+ readonly slots_per_day: number;
167
+ readonly window_start: string;
168
+ readonly window_end: string;
169
+ readonly timezone: string;
170
+ readonly history_limit: number;
171
+ readonly language: string;
172
+ readonly facts_count: number;
173
+ readonly sources_count: number;
174
+ readonly waiting_count: number;
175
+ }
176
+ export type UpdateBotResponderInput = Partial<Pick<BotResponder, "enabled" | "system_prompt" | "knowledge" | "signature" | "model" | "slots_per_day" | "window_start" | "window_end" | "timezone" | "history_limit" | "language">>;
177
+ export type BotFactSource = "manual" | "chat" | "learned";
178
+ export interface BotFact {
179
+ readonly id: Id;
180
+ readonly created_at: Timestamp;
181
+ readonly updated_at: Timestamp;
182
+ readonly bot_channel_id: Id;
183
+ readonly text: string;
184
+ readonly valid_from: string | null;
185
+ readonly valid_until: string | null;
186
+ readonly source: BotFactSource;
187
+ readonly bot_contact_id: Id | null;
188
+ readonly active: boolean;
189
+ }
190
+ export interface CreateBotFactInput {
191
+ readonly channelId: Id;
192
+ readonly text: string;
193
+ readonly valid_from?: string | null;
194
+ readonly valid_until?: string | null;
195
+ }
196
+ export type UpdateBotFactInput = Partial<Omit<CreateBotFactInput, "channelId">>;
197
+ export declare const BOT_FACT_FILTER_COLUMNS: readonly ["bot_channel_id", "source", "bot_contact_id"];
198
+ export interface ListBotFactsParams extends ListParams<(typeof BOT_FACT_FILTER_COLUMNS)[number]> {
199
+ readonly channelId?: Id;
200
+ }
201
+ export interface BotSource {
202
+ readonly id: Id;
203
+ readonly created_at: Timestamp;
204
+ readonly updated_at: Timestamp;
205
+ readonly bot_channel_id: Id;
206
+ readonly name: string;
207
+ readonly url: string;
208
+ readonly description: string | null;
209
+ }
210
+ export interface CreateBotSourceInput {
211
+ readonly channelId: Id;
212
+ readonly name: string;
213
+ readonly url: string;
214
+ readonly description?: string | null;
215
+ }
216
+ export type UpdateBotSourceInput = Partial<Omit<CreateBotSourceInput, "channelId">>;
217
+ export declare const BOT_SOURCE_FILTER_COLUMNS: readonly ["bot_channel_id"];
218
+ export interface ListBotSourcesParams extends ListParams<(typeof BOT_SOURCE_FILTER_COLUMNS)[number]> {
219
+ readonly channelId?: Id;
220
+ }
221
+ export type BotResponderRunStatus = "pending" | "running" | "done" | "failed" | "skipped";
222
+ export interface BotResponderRun {
223
+ readonly id: Id;
224
+ readonly created_at: Timestamp;
225
+ readonly updated_at: Timestamp;
226
+ readonly bot_channel_id: Id;
227
+ readonly status: BotResponderRunStatus;
228
+ readonly trigger: "schedule" | "manual";
229
+ readonly scheduled_at: Timestamp;
230
+ readonly started_at: Timestamp | null;
231
+ readonly finished_at: Timestamp | null;
232
+ readonly replied: number;
233
+ readonly escalated: number;
234
+ readonly error: string | null;
235
+ }
236
+ export declare const BOT_RUN_FILTER_COLUMNS: readonly ["bot_channel_id", "status", "trigger"];
237
+ export interface ListBotResponderRunsParams extends ListParams<(typeof BOT_RUN_FILTER_COLUMNS)[number]> {
238
+ readonly channelId?: Id;
239
+ }
240
+ /** One line of the owner's conversation with the responder; `meta` says what a reply did. */
241
+ export interface BotOwnerMessage {
242
+ readonly id: Id;
243
+ readonly created_at: Timestamp;
244
+ readonly updated_at: Timestamp;
245
+ readonly bot_channel_id: Id;
246
+ readonly role: "user" | "assistant";
247
+ readonly text: string;
248
+ readonly meta: {
249
+ readonly facts?: readonly Id[];
250
+ readonly removed?: readonly Id[];
251
+ readonly sources?: readonly Id[];
252
+ readonly retrying?: boolean;
253
+ };
254
+ }
255
+ export interface BotOwnerChat {
256
+ readonly messages: BotOwnerMessage[];
257
+ /** When the current session (no pause over two hours) started; null when there is none. */
258
+ readonly session_started_at: Timestamp | null;
259
+ /** Contacts the responder could not answer. */
260
+ readonly waiting: BotContact[];
261
+ }
262
+ export interface BotOwnerChatTurn {
263
+ readonly reply: BotOwnerMessage;
264
+ readonly facts: BotFact[];
265
+ readonly removed: Id[];
266
+ readonly sources: BotSource[];
267
+ /** Facts were saved while contacts were waiting: they are being answered in the background. */
268
+ readonly retrying: boolean;
269
+ }
270
+ export type BotReplyOutcome = "replied" | "escalated" | "skipped";
271
+ export interface BotReplyResult {
272
+ readonly result: BotReplyOutcome;
273
+ readonly contact: BotContact;
274
+ }
275
+ export interface BotTeachResult {
276
+ readonly learned: BotFact[];
277
+ readonly contact: BotContact;
278
+ }
279
+ /** `/bot_channels` - the connected bots. */
280
+ export declare class BotChannelsNamespace extends Resource {
281
+ /** `GET /bot_channels` - your channels, oldest first. */
282
+ list(params?: ListBotChannelsParams, options?: RequestOptions): Promise<Paginated<BotChannel>>;
283
+ /** `GET /bot_channels/:id`. 404 when it is not yours. */
284
+ get(id: Id, options?: RequestOptions): Promise<BotChannelDetail>;
285
+ /**
286
+ * `POST /bot_channels` - connect a bot. The server checks the token with the
287
+ * platform and registers the webhook before answering `201`.
288
+ *
289
+ * @throws {OmsApiError} 400 when the platform refuses the token, the name
290
+ * repeats, or the account is at its channel limit.
291
+ */
292
+ create(input: CreateBotChannelInput, options?: RequestOptions): Promise<BotChannelDetail>;
293
+ /** `PATCH /bot_channels/:id`. A new `token` reconnects; a blank one is ignored. */
294
+ update(id: Id, input: UpdateBotChannelInput, options?: RequestOptions): Promise<BotChannelDetail>;
295
+ /** `DELETE /bot_channels/:id` - unregisters the webhook, drops contacts and messages. `204`. */
296
+ delete(id: Id, options?: RequestOptions): Promise<void>;
297
+ /** `POST /bot_channels/:id/test` - what the platform says about the bot and the webhook. */
298
+ test(id: Id, options?: RequestOptions): Promise<BotChannelStatus>;
299
+ }
300
+ /** `/bot_contacts` - who talked to your channels. Read, tag, mark read. */
301
+ export declare class BotContactsNamespace extends Resource {
302
+ /** `GET /bot_contacts` - most recently active first. */
303
+ list(params?: ListBotContactsParams, options?: RequestOptions): Promise<Paginated<BotContact>>;
304
+ get(id: Id, options?: RequestOptions): Promise<BotContact>;
305
+ /** `PATCH /bot_contacts/:id` - the name you give them and the tags. */
306
+ update(id: Id, input: UpdateBotContactInput, options?: RequestOptions): Promise<BotContact>;
307
+ /** `POST /bot_contacts/:id/read` - the unread counter to zero. */
308
+ markRead(id: Id, options?: RequestOptions): Promise<BotContact>;
309
+ /**
310
+ * `POST /bot_contacts/:id/bot_reply` - the responder handles this conversation now.
311
+ *
312
+ * @throws {OmsApiError} 400 when the channel's plugin is not the responder or it was never saved; 502 when the model or the platform failed.
313
+ */
314
+ botReply(id: Id, options?: RequestOptions): Promise<BotReplyResult>;
315
+ /**
316
+ * `POST /bot_contacts/:id/teach` - give the responder what it was missing: the general
317
+ * part is kept as facts, the contact gets an answer, the others waiting are retried.
318
+ */
319
+ teach(id: Id, hint: string, options?: RequestOptions): Promise<BotTeachResult>;
320
+ /** `DELETE /bot_contacts/:id` - the contact and its messages. `204`. */
321
+ delete(id: Id, options?: RequestOptions): Promise<void>;
322
+ }
323
+ /** `/bot_messages` - the conversations, and sending. */
324
+ export declare class BotMessagesNamespace extends Resource {
325
+ /** `GET /bot_messages` - newest first; pass `order: "sent_at:asc"` for a thread top-down. */
326
+ list(params?: ListBotMessagesParams, options?: RequestOptions): Promise<Paginated<BotMessage>>;
327
+ get(id: Id, options?: RequestOptions): Promise<BotMessage>;
328
+ /**
329
+ * `POST /bot_messages` - send. The server talks to the platform and records
330
+ * the message with source `api` (a token) or `human` (a session).
331
+ *
332
+ * @throws {OmsApiError} 422 when the contact blocked the bot; 429 at the daily
333
+ * limit; 502 when the platform refused (the row is kept with `error`).
334
+ */
335
+ send(input: SendBotMessageInput, options?: RequestOptions): Promise<BotMessage>;
336
+ /** `DELETE /bot_messages/:id` - one row out of the thread. `204`. */
337
+ delete(id: Id, options?: RequestOptions): Promise<void>;
338
+ }
339
+ /** `/bot_channels/:id/responder` - the responder plugin of a channel. */
340
+ export declare class BotRespondersNamespace extends Resource {
341
+ /** @throws {OmsApiError} 400 when the channel's plugin is not the responder. */
342
+ get(channelId: Id, options?: RequestOptions): Promise<BotResponder>;
343
+ /** `PATCH /bot_channels/:id/responder` - creates it on first save. */
344
+ update(channelId: Id, input: UpdateBotResponderInput, options?: RequestOptions): Promise<BotResponder>;
345
+ /**
346
+ * `POST /bot_channels/:id/responder/run` - answer the pending conversations now, outside the schedule.
347
+ *
348
+ * @throws {OmsApiError} 400 when a run is already open or the responder was never saved.
349
+ */
350
+ run(channelId: Id, options?: RequestOptions): Promise<BotResponderRun>;
351
+ }
352
+ /** `/bot_channels/:id/owner_chat` - the owner talking to the responder: teach, ask, correct, delete, point to sources. */
353
+ export declare class BotOwnerChatNamespace extends Resource {
354
+ get(channelId: Id, options?: RequestOptions): Promise<BotOwnerChat>;
355
+ /**
356
+ * `POST /bot_channels/:id/owner_chat` - one turn. The model's decisions are applied before the answer comes back.
357
+ *
358
+ * @throws {OmsApiError} 400 when the channel's plugin is not the responder or it was never saved; 502 when the model failed.
359
+ */
360
+ send(channelId: Id, message: string, options?: RequestOptions): Promise<BotOwnerChatTurn>;
361
+ }
362
+ /** `/bot_facts` - what the responder knows, with optional validity dates. */
363
+ export declare class BotFactsNamespace extends Resource {
364
+ list(params?: ListBotFactsParams, options?: RequestOptions): Promise<Paginated<BotFact>>;
365
+ get(id: Id, options?: RequestOptions): Promise<BotFact>;
366
+ /** @throws {OmsApiError} 400 when the channel's plugin is not the responder. */
367
+ create(input: CreateBotFactInput, options?: RequestOptions): Promise<BotFact>;
368
+ update(id: Id, input: UpdateBotFactInput, options?: RequestOptions): Promise<BotFact>;
369
+ delete(id: Id, options?: RequestOptions): Promise<void>;
370
+ }
371
+ /** `/bot_sources` - pages the responder may read when a question calls for it. */
372
+ export declare class BotSourcesNamespace extends Resource {
373
+ list(params?: ListBotSourcesParams, options?: RequestOptions): Promise<Paginated<BotSource>>;
374
+ get(id: Id, options?: RequestOptions): Promise<BotSource>;
375
+ create(input: CreateBotSourceInput, options?: RequestOptions): Promise<BotSource>;
376
+ update(id: Id, input: UpdateBotSourceInput, options?: RequestOptions): Promise<BotSource>;
377
+ delete(id: Id, options?: RequestOptions): Promise<void>;
378
+ }
379
+ /** `/bot_responder_runs` - the responder's passes over the conversations, newest first. */
380
+ export declare class BotResponderRunsNamespace extends Resource {
381
+ list(params?: ListBotResponderRunsParams, options?: RequestOptions): Promise<Paginated<BotResponderRun>>;
382
+ get(id: Id, options?: RequestOptions): Promise<BotResponderRun>;
383
+ }
384
+ export declare class BotsNamespace extends Resource {
385
+ readonly channels: BotChannelsNamespace;
386
+ readonly contacts: BotContactsNamespace;
387
+ readonly messages: BotMessagesNamespace;
388
+ readonly responders: BotRespondersNamespace;
389
+ readonly ownerChat: BotOwnerChatNamespace;
390
+ readonly facts: BotFactsNamespace;
391
+ readonly sources: BotSourcesNamespace;
392
+ readonly runs: BotResponderRunsNamespace;
393
+ constructor(http: ApiClient);
394
+ }
@@ -10,7 +10,9 @@ export declare const NEWS_FEED_MAX_RETENTION_DAYS = 3650;
10
10
  /**
11
11
  * A feed: a named set of {@link NewsSource}s and the {@link NewsItem}s they
12
12
  * produce. Several per account, unique by name; the oldest is the default
13
- * one a source lands in when it names no feed.
13
+ * one a source lands in when it names no feed. A feed may INCLUDE other
14
+ * feeds of yours (one level): listing its items also returns theirs, so
15
+ * sources can be grouped by kind ("Newspapers", "TV news") and reused.
14
16
  */
15
17
  export interface NewsFeed {
16
18
  readonly id: Id;
@@ -24,11 +26,14 @@ export interface NewsFeed {
24
26
  readonly retention_days: number;
25
27
  /** A disabled feed's sources are not polled. */
26
28
  readonly enabled: boolean;
29
+ /** Feeds of yours whose items this feed also lists (one level, no chaining). */
30
+ readonly included_feed_ids: Id[];
27
31
  }
28
- /** `GET /news_feeds/:id` adds two live counters. */
32
+ /** `GET /news_feeds/:id` adds two live counters (this feed's own sources and items) and who includes it. */
29
33
  export interface NewsFeedDetail extends NewsFeed {
30
34
  readonly sources_count: number;
31
35
  readonly items_count: number;
36
+ readonly included_by_feed_ids: Id[];
32
37
  }
33
38
  /** Filter columns of `GET /news_feeds`, on top of {@link BASE_FILTER_COLUMNS}. */
34
39
  export declare const NEWS_FEED_FILTER_COLUMNS: readonly ["name", "enabled"];
@@ -39,6 +44,8 @@ export interface CreateNewsFeedInput {
39
44
  readonly description?: string | null;
40
45
  readonly retentionDays?: number;
41
46
  readonly enabled?: boolean;
47
+ /** REPLACES the list. Your own feeds only, the feed itself is dropped; anything else is a `400`. */
48
+ readonly includedFeedIds?: readonly Id[];
42
49
  }
43
50
  export type UpdateNewsFeedInput = Partial<CreateNewsFeedInput>;
44
51
  /** `/news_feeds` - your feeds. Needs `news:read` to read and `news:write` to change. */
@@ -1,5 +1,6 @@
1
1
  /** The `news` namespace and everything under it. */
2
2
  import { type ApiClient, Resource } from "../../../http";
3
+ import type { RequestOptions } from "../../../types";
3
4
  import { NewsFeedsNamespace } from "./feeds";
4
5
  import { NewsItemsNamespace } from "./items";
5
6
  import { NewsScriptsNamespace } from "./scripts";
@@ -8,6 +9,21 @@ export * from "./feeds";
8
9
  export * from "./items";
9
10
  export * from "./scripts";
10
11
  export * from "./sources";
12
+ /** One feed a site declares or answers on a common path, already read and measured. */
13
+ export interface DiscoveredFeed {
14
+ readonly url: string;
15
+ readonly kind: "rss" | "atom";
16
+ readonly title: string;
17
+ readonly items: number;
18
+ /** Entries carrying a date. */
19
+ readonly dated: number;
20
+ }
21
+ export interface NewsDiscovery {
22
+ readonly url: string;
23
+ readonly host: string;
24
+ readonly title: string;
25
+ readonly feeds: DiscoveredFeed[];
26
+ }
11
27
  /**
12
28
  * The `news` namespace, reachable as `oms.content.news`: the ingestion side
13
29
  * of following the web.
@@ -33,4 +49,11 @@ export declare class NewsNamespace extends Resource {
33
49
  /** What the sources produced. Read plus delete. */
34
50
  readonly items: NewsItemsNamespace;
35
51
  constructor(http: ApiClient);
52
+ /**
53
+ * `GET /news/discover?url=` - the RSS/Atom feeds of a site: the ones its page declares
54
+ * and the common paths that answer, each fetched and measured. Cached for hours server-side.
55
+ *
56
+ * @throws {OmsApiError} 422 when the site cannot be read (the message says why).
57
+ */
58
+ discover(url: string, options?: RequestOptions): Promise<NewsDiscovery>;
36
59
  }
@@ -73,6 +73,30 @@ export interface ListNewsItemsParams extends ListParams<(typeof NEWS_ITEM_FILTER
73
73
  /** Only items written at or before this instant (ISO 8601). */
74
74
  readonly until?: string;
75
75
  }
76
+ /** Parameters of {@link NewsItemsNamespace.similar}: an anchor plus optional narrowing. */
77
+ export type SimilarNewsItemsParams = ({
78
+ /** Free text to compare against. */
79
+ readonly text: string;
80
+ readonly itemId?: undefined;
81
+ } | {
82
+ /** One of your items to compare against. It never comes back in the results. */
83
+ readonly itemId: Id;
84
+ readonly text?: undefined;
85
+ }) & {
86
+ /** Only items of one feed. */
87
+ readonly feedId?: Id;
88
+ /** 1..50, default 10. */
89
+ readonly limit?: number;
90
+ /** Only items written at or after this instant (ISO 8601). */
91
+ readonly since?: string | Date;
92
+ /** Cosine distance ceiling, 0..1, default 0.35. Lower is stricter. */
93
+ readonly maxDistance?: number;
94
+ };
95
+ /** A hit of {@link NewsItemsNamespace.similar}: the item plus how far it sits from the anchor. */
96
+ export type SimilarNewsItem = NewsItem & {
97
+ /** Cosine distance to the anchor: `0` is the same text, `1` unrelated. */
98
+ readonly distance: number;
99
+ };
76
100
  /**
77
101
  * `/news_items` - the raw material.
78
102
  *
@@ -102,6 +126,22 @@ export declare class NewsItemsNamespace extends Resource {
102
126
  * @throws {OmsApiError} 404 when the item is not yours.
103
127
  */
104
128
  get(id: Id, options?: RequestOptions): Promise<NewsItem>;
129
+ /**
130
+ * `GET /news_items/similar` - your items closest in meaning to a text or to
131
+ * one of your items, nearest first, no paging.
132
+ *
133
+ * Meaning, not words: "mesquita de Lisboa" finds an item about the mosque
134
+ * that never uses the word. Every item gets its vector shortly after it is
135
+ * written, so a fresh one may still be missing from the results; videos
136
+ * have none (the news cut from them do).
137
+ *
138
+ * @throws {OmsApiError} 400 when neither `text` nor `itemId` is given, `limit`
139
+ * is outside 1..50, `maxDistance` outside 0..1, or `since` is not ISO 8601.
140
+ * @throws {OmsApiError} 404 when `itemId` is not yours.
141
+ * @throws {OmsApiError} 422 when that item has no vector yet.
142
+ * @throws {OmsApiError} 502 when `text` cannot be embedded right now.
143
+ */
144
+ similar(params: SimilarNewsItemsParams, options?: RequestOptions): Promise<SimilarNewsItem[]>;
105
145
  /**
106
146
  * `DELETE /news_items/:id`. `204`, empty body.
107
147
  *