@omelhorsite/sdk 0.15.1 → 0.17.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/README.md +26 -3
- package/dist/index.js +385 -146
- package/dist/types/auth/tokens.d.ts +1 -1
- package/dist/types/client.d.ts +3 -0
- package/dist/types/resources/admin/llm.d.ts +9 -1
- package/dist/types/resources/admin/quotas.d.ts +14 -0
- package/dist/types/resources/content/blogs.d.ts +111 -31
- package/dist/types/resources/content/index.d.ts +4 -4
- package/dist/types/resources/content/news/feeds.d.ts +56 -0
- package/dist/types/resources/content/news/index.d.ts +36 -0
- package/dist/types/resources/content/news/items.d.ts +155 -0
- package/dist/types/resources/content/{intel → news}/scripts.d.ts +35 -35
- package/dist/types/resources/content/{intel → news}/sources.d.ts +62 -59
- package/dist/types/resources/content/notifications.d.ts +2 -2
- package/dist/types/resources/cron.d.ts +225 -0
- package/dist/types/resources/index.d.ts +1 -0
- package/dist/types/resources/llm.d.ts +71 -0
- package/dist/types/resources/quotas.d.ts +8 -5
- package/dist/types/resources/search.d.ts +36 -0
- package/package.json +1 -1
- package/dist/types/resources/content/intel/articles.d.ts +0 -230
- package/dist/types/resources/content/intel/config.d.ts +0 -135
- package/dist/types/resources/content/intel/index.d.ts +0 -53
- package/dist/types/resources/content/intel/items.d.ts +0 -91
- package/dist/types/resources/content/intel/reports.d.ts +0 -108
- package/dist/types/resources/content/intel/stats.d.ts +0 -105
- package/dist/types/resources/content/intel/types.d.ts +0 -86
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The `cron` namespace: TypeScript scripts of the signed-in person that the
|
|
3
|
+
* server runs on a schedule.
|
|
4
|
+
*
|
|
5
|
+
* A script is an ES module exporting `run(ctx)`. It runs with nothing but the
|
|
6
|
+
* API: no filesystem, no environment, no processes, and no network beyond
|
|
7
|
+
* this SDK (`ctx.oms`, authenticated as the owner with the job's scopes) and,
|
|
8
|
+
* when the job has `network` on, a `ctx.fetch` that goes through the server's
|
|
9
|
+
* guard against private addresses. What it keeps in `ctx.state` is stored
|
|
10
|
+
* when a run ends well and handed back on the next one; what it returns is
|
|
11
|
+
* the run's `result`, and `result.summary` is what the listing shows.
|
|
12
|
+
*
|
|
13
|
+
* Needs the `cron:read` scope to read and `cron:write` to change anything.
|
|
14
|
+
* A job's own token never carries either: a script cannot edit jobs.
|
|
15
|
+
*/
|
|
16
|
+
import { Resource, type ApiClient } from "../http";
|
|
17
|
+
import type { ListParams } from "../listing";
|
|
18
|
+
import type { Id, Json, Paginated, RequestOptions, Timestamp } from "../types";
|
|
19
|
+
/** Scopes a job may ask for its token. Anything else answers `400`. */
|
|
20
|
+
export declare const CRON_JOB_SCOPES: readonly ["profile", "news:read", "news:write", "storage:read", "storage:write", "llm", "tools:read", "tools:write", "blogs:read", "blogs:write"];
|
|
21
|
+
export type CronJobScope = (typeof CRON_JOB_SCOPES)[number];
|
|
22
|
+
export declare const CRON_JOB_HEALTHS: readonly ["unknown", "ok", "error"];
|
|
23
|
+
export type CronJobHealth = (typeof CRON_JOB_HEALTHS)[number];
|
|
24
|
+
/** Consecutive failures after which a job switches itself off. Turn `enabled` back on to revive it. */
|
|
25
|
+
export declare const CRON_JOB_DISABLE_AFTER_FAILURES = 10;
|
|
26
|
+
/** Code longer than this answers `400`. */
|
|
27
|
+
export declare const CRON_JOB_MAX_CODE_BYTES: number;
|
|
28
|
+
/** `state` and `config` ceilings. A run whose state grows past this fails and the state is not stored. */
|
|
29
|
+
export declare const CRON_JOB_MAX_STATE_BYTES: number;
|
|
30
|
+
export declare const CRON_JOB_MAX_CONFIG_BYTES: number;
|
|
31
|
+
/** Two runs of one job must be at least this far apart. */
|
|
32
|
+
export declare const CRON_JOB_MIN_INTERVAL_MINUTES = 5;
|
|
33
|
+
/** `timeout_seconds` range; above 120 the account needs a trusted tier, like `network`. */
|
|
34
|
+
export declare const CRON_JOB_MIN_TIMEOUT_SECONDS = 5;
|
|
35
|
+
export declare const CRON_JOB_MAX_TIMEOUT_SECONDS = 1200;
|
|
36
|
+
export declare const CRON_JOB_BASE_MAX_TIMEOUT_SECONDS = 120;
|
|
37
|
+
export interface CronJob {
|
|
38
|
+
readonly id: Id;
|
|
39
|
+
readonly created_at: Timestamp;
|
|
40
|
+
readonly updated_at: Timestamp;
|
|
41
|
+
/** Up to 120 characters, unique per account. */
|
|
42
|
+
readonly name: string;
|
|
43
|
+
readonly description: string | null;
|
|
44
|
+
/** Five-field cron expression, read in `timezone`. */
|
|
45
|
+
readonly schedule: string;
|
|
46
|
+
/** An IANA zone such as `"Europe/Lisbon"` (the default). */
|
|
47
|
+
readonly timezone: string;
|
|
48
|
+
/** The scopes the run's token carries. */
|
|
49
|
+
readonly scopes: CronJobScope[];
|
|
50
|
+
/** Names of the stored secrets. The values never leave the server. */
|
|
51
|
+
readonly secret_keys: string[];
|
|
52
|
+
/** Whether `ctx.fetch` exists in the script. */
|
|
53
|
+
readonly network: boolean;
|
|
54
|
+
readonly timeout_seconds: number;
|
|
55
|
+
/** A folder of the owner's storage handed to the script as `ctx.job.outputDirId`. */
|
|
56
|
+
readonly output_dir_id: Id | null;
|
|
57
|
+
readonly enabled: boolean;
|
|
58
|
+
readonly next_run_at: Timestamp | null;
|
|
59
|
+
readonly last_run_at: Timestamp | null;
|
|
60
|
+
readonly last_success_at: Timestamp | null;
|
|
61
|
+
readonly health: CronJobHealth;
|
|
62
|
+
readonly consecutive_failures: number;
|
|
63
|
+
readonly notify_on_failure: boolean;
|
|
64
|
+
readonly notify_on_success: boolean;
|
|
65
|
+
/** The template the job was created from, if any. */
|
|
66
|
+
readonly template_slug: string | null;
|
|
67
|
+
/** Whether a run is queued or running right now. */
|
|
68
|
+
readonly running: boolean;
|
|
69
|
+
}
|
|
70
|
+
/** The types a script may give a variable it declares with `// @var key type Label | description`. */
|
|
71
|
+
export declare const CRON_VAR_TYPES: readonly ["string", "text", "number", "boolean", "list", "json"];
|
|
72
|
+
export type CronVarType = (typeof CRON_VAR_TYPES)[number];
|
|
73
|
+
/**
|
|
74
|
+
* A variable a script declares as editable, parsed by the server from the
|
|
75
|
+
* `// @var` lines at the top of the code. Its value lives in `config[key]`.
|
|
76
|
+
*/
|
|
77
|
+
export interface CronVar {
|
|
78
|
+
readonly key: string;
|
|
79
|
+
readonly type: CronVarType;
|
|
80
|
+
readonly label: string;
|
|
81
|
+
readonly description: string | null;
|
|
82
|
+
}
|
|
83
|
+
/** `GET /cron_jobs/:id` (and every write) adds the code, the config, the state and the declared variables. */
|
|
84
|
+
export interface CronJobDetail extends CronJob {
|
|
85
|
+
readonly code: string;
|
|
86
|
+
readonly config: Record<string, Json>;
|
|
87
|
+
readonly state: Record<string, Json>;
|
|
88
|
+
readonly vars: CronVar[];
|
|
89
|
+
}
|
|
90
|
+
export declare const CRON_JOB_FILTER_COLUMNS: readonly ["name", "enabled", "health", "template_slug"];
|
|
91
|
+
export interface ListCronJobsParams extends ListParams<(typeof CRON_JOB_FILTER_COLUMNS)[number]> {
|
|
92
|
+
}
|
|
93
|
+
export interface CreateCronJobInput {
|
|
94
|
+
readonly name: string;
|
|
95
|
+
readonly description?: string | null;
|
|
96
|
+
/** Five fields. Two runs must be at least {@link CRON_JOB_MIN_INTERVAL_MINUTES} apart. */
|
|
97
|
+
readonly schedule: string;
|
|
98
|
+
readonly timezone?: string;
|
|
99
|
+
/** TypeScript. Checked for syntax on the server before it is stored. */
|
|
100
|
+
readonly code: string;
|
|
101
|
+
/** Defaults to every scope but `news:write` and `tools:write`. */
|
|
102
|
+
readonly scopes?: readonly CronJobScope[];
|
|
103
|
+
readonly config?: Record<string, Json>;
|
|
104
|
+
/** Stored encrypted; on update the object is MERGED, and a `null` value removes that key. */
|
|
105
|
+
readonly secrets?: Record<string, string | null>;
|
|
106
|
+
readonly state?: Record<string, Json>;
|
|
107
|
+
readonly network?: boolean;
|
|
108
|
+
readonly timeoutSeconds?: number;
|
|
109
|
+
readonly outputDirId?: Id | null;
|
|
110
|
+
readonly enabled?: boolean;
|
|
111
|
+
readonly notifyOnFailure?: boolean;
|
|
112
|
+
readonly notifyOnSuccess?: boolean;
|
|
113
|
+
readonly templateSlug?: string | null;
|
|
114
|
+
}
|
|
115
|
+
export type UpdateCronJobInput = Partial<Omit<CreateCronJobInput, "templateSlug">>;
|
|
116
|
+
export declare const CRON_RUN_STATUSES: readonly ["queued", "running", "ok", "error", "timeout", "skipped"];
|
|
117
|
+
export type CronRunStatus = (typeof CRON_RUN_STATUSES)[number];
|
|
118
|
+
export declare const CRON_RUN_TRIGGERS: readonly ["schedule", "manual", "test"];
|
|
119
|
+
export type CronRunTrigger = (typeof CRON_RUN_TRIGGERS)[number];
|
|
120
|
+
export interface CronRun {
|
|
121
|
+
readonly id: Id;
|
|
122
|
+
readonly created_at: Timestamp;
|
|
123
|
+
readonly updated_at: Timestamp;
|
|
124
|
+
readonly cron_job_id: Id;
|
|
125
|
+
readonly status: CronRunStatus;
|
|
126
|
+
/** `test` runs never write the state back and never count as failures. */
|
|
127
|
+
readonly trigger: CronRunTrigger;
|
|
128
|
+
readonly scheduled_at: Timestamp;
|
|
129
|
+
readonly started_at: Timestamp | null;
|
|
130
|
+
readonly finished_at: Timestamp | null;
|
|
131
|
+
readonly duration_ms: number | null;
|
|
132
|
+
readonly error: string | null;
|
|
133
|
+
readonly error_name: string | null;
|
|
134
|
+
/** Model calls made with the run's token, and what they cost. */
|
|
135
|
+
readonly llm_requests: number;
|
|
136
|
+
readonly llm_cost: number;
|
|
137
|
+
/** Requests the script made, through the SDK and `ctx.fetch`. */
|
|
138
|
+
readonly http_calls: number;
|
|
139
|
+
/** `result.summary`, when the script returned one. */
|
|
140
|
+
readonly summary: string | null;
|
|
141
|
+
}
|
|
142
|
+
/** `GET /cron_runs/:id` adds the logs and the whole result. */
|
|
143
|
+
export interface CronRunDetail extends CronRun {
|
|
144
|
+
/** What `ctx.log` and `console.log` wrote, one line per entry, capped at 64 KB. */
|
|
145
|
+
readonly logs: string | null;
|
|
146
|
+
readonly result: Json | null;
|
|
147
|
+
}
|
|
148
|
+
export declare const CRON_RUN_FILTER_COLUMNS: readonly ["cron_job_id", "status", "trigger"];
|
|
149
|
+
export interface ListCronRunsParams extends ListParams<(typeof CRON_RUN_FILTER_COLUMNS)[number]> {
|
|
150
|
+
readonly jobId?: Id;
|
|
151
|
+
readonly status?: CronRunStatus;
|
|
152
|
+
}
|
|
153
|
+
/** A ready-made script: copy it into a job with {@link CronJobsNamespace.create}. */
|
|
154
|
+
export interface CronTemplate {
|
|
155
|
+
readonly slug: string;
|
|
156
|
+
readonly name: string;
|
|
157
|
+
readonly description: string;
|
|
158
|
+
/** The schedule the template expects. */
|
|
159
|
+
readonly schedule: string;
|
|
160
|
+
readonly scopes: CronJobScope[];
|
|
161
|
+
readonly network: boolean;
|
|
162
|
+
/** The config the script reads, with defaults. */
|
|
163
|
+
readonly config: Record<string, Json>;
|
|
164
|
+
/** The variables the template declares as editable (`// @var`). */
|
|
165
|
+
readonly vars: CronVar[];
|
|
166
|
+
/** SHA-256 of the code, so a client can tell an edited copy from a pristine one. */
|
|
167
|
+
readonly hash: string;
|
|
168
|
+
}
|
|
169
|
+
export interface CronTemplateDetail extends CronTemplate {
|
|
170
|
+
readonly code: string;
|
|
171
|
+
}
|
|
172
|
+
/** What the syntax check answers. */
|
|
173
|
+
export interface CronCheckResult {
|
|
174
|
+
readonly ok: boolean;
|
|
175
|
+
readonly error?: string;
|
|
176
|
+
}
|
|
177
|
+
export declare class CronJobsNamespace extends Resource {
|
|
178
|
+
list(params?: ListCronJobsParams, options?: RequestOptions): Promise<Paginated<CronJob>>;
|
|
179
|
+
get(id: Id, options?: RequestOptions): Promise<CronJobDetail>;
|
|
180
|
+
/**
|
|
181
|
+
* `POST /cron_jobs`. `201` with the full job.
|
|
182
|
+
*
|
|
183
|
+
* @throws {OmsApiError} 400 with the validation sentence: a bad or too
|
|
184
|
+
* frequent schedule, an unknown timezone, a scope outside
|
|
185
|
+
* {@link CRON_JOB_SCOPES}, `network` or a timeout above 120 s on an
|
|
186
|
+
* account without a trusted tier, an `Invalid script: ...` syntax error,
|
|
187
|
+
* or `job limit reached (N)` (the `cron_jobs` quota).
|
|
188
|
+
*/
|
|
189
|
+
create(input: CreateCronJobInput, options?: RequestOptions): Promise<CronJobDetail>;
|
|
190
|
+
/** `PATCH /cron_jobs/:id`. Secrets merge; a `null` value removes a key. Changing the schedule recomputes `next_run_at`. */
|
|
191
|
+
update(id: Id, input: UpdateCronJobInput, options?: RequestOptions): Promise<CronJobDetail>;
|
|
192
|
+
/** `DELETE /cron_jobs/:id` - the job and its runs. `204`. */
|
|
193
|
+
delete(id: Id, options?: RequestOptions): Promise<void>;
|
|
194
|
+
/**
|
|
195
|
+
* `POST /cron_jobs/:id/run` - runs now, outside the schedule, as a normal
|
|
196
|
+
* run (the state is stored). `202` with the queued run.
|
|
197
|
+
*
|
|
198
|
+
* @throws {OmsApiError} 400 `this job is already running`; 429
|
|
199
|
+
* `error: "limit"` when the day's `cron_run_seconds` are spent.
|
|
200
|
+
*/
|
|
201
|
+
run(id: Id, options?: RequestOptions): Promise<CronRun>;
|
|
202
|
+
/** `POST /cron_jobs/:id/test` - runs now WITHOUT storing the state or counting a failure. `202`. */
|
|
203
|
+
test(id: Id, options?: RequestOptions): Promise<CronRun>;
|
|
204
|
+
/** `POST /cron_jobs/check` - the syntax check the server runs before storing code, on its own. */
|
|
205
|
+
check(code: string, options?: RequestOptions): Promise<CronCheckResult>;
|
|
206
|
+
}
|
|
207
|
+
export declare class CronRunsNamespace extends Resource {
|
|
208
|
+
/** `GET /cron_runs` - newest first. */
|
|
209
|
+
list(params?: ListCronRunsParams, options?: RequestOptions): Promise<Paginated<CronRun>>;
|
|
210
|
+
get(id: Id, options?: RequestOptions): Promise<CronRunDetail>;
|
|
211
|
+
delete(id: Id, options?: RequestOptions): Promise<void>;
|
|
212
|
+
}
|
|
213
|
+
export declare class CronTemplatesNamespace extends Resource {
|
|
214
|
+
/** `GET /cron_templates` - the built-in scripts, without their code. */
|
|
215
|
+
list(options?: RequestOptions): Promise<CronTemplate[]>;
|
|
216
|
+
/** `GET /cron_templates/:slug` - one template with its code. */
|
|
217
|
+
get(slug: string, options?: RequestOptions): Promise<CronTemplateDetail>;
|
|
218
|
+
}
|
|
219
|
+
/** The `cron` namespace, reachable as `oms.cron`. */
|
|
220
|
+
export declare class CronNamespace extends Resource {
|
|
221
|
+
readonly jobs: CronJobsNamespace;
|
|
222
|
+
readonly runs: CronRunsNamespace;
|
|
223
|
+
readonly templates: CronTemplatesNamespace;
|
|
224
|
+
constructor(http: ApiClient);
|
|
225
|
+
}
|
|
@@ -41,6 +41,8 @@ export interface LlmModelChoice {
|
|
|
41
41
|
readonly name: string;
|
|
42
42
|
readonly provider_slug: string;
|
|
43
43
|
readonly free: boolean;
|
|
44
|
+
/** `0` everyone, `1` trusted accounts, `2` administrators. Only models at or below the account's tier are listed. */
|
|
45
|
+
readonly tier: number;
|
|
44
46
|
readonly context_window: number | null;
|
|
45
47
|
readonly max_output_tokens: number | null;
|
|
46
48
|
readonly input_price_per_million: number | null;
|
|
@@ -285,12 +287,81 @@ export declare class LlmChatsNamespace extends Resource {
|
|
|
285
287
|
/** Removes the chat and every message in it. */
|
|
286
288
|
delete(id: Id, options?: RequestOptions): Promise<void>;
|
|
287
289
|
}
|
|
290
|
+
/** The tools a completion may hand the model. Each call the model makes counts as one search or one page read. */
|
|
291
|
+
export declare const LLM_COMPLETION_TOOLS: readonly ["web_search", "read_url"];
|
|
292
|
+
export type LlmCompletionTool = (typeof LLM_COMPLETION_TOOLS)[number];
|
|
293
|
+
/** At most this many messages in one completion. */
|
|
294
|
+
export declare const LLM_COMPLETION_MAX_MESSAGES = 200;
|
|
295
|
+
/** Longer contents answer `400`. */
|
|
296
|
+
export declare const LLM_COMPLETION_MAX_MESSAGE_CHARS = 100000;
|
|
297
|
+
/** All contents together. */
|
|
298
|
+
export declare const LLM_COMPLETION_MAX_TOTAL_CHARS = 400000;
|
|
299
|
+
/** `maxTokens` above this answers `400`. */
|
|
300
|
+
export declare const LLM_COMPLETION_MAX_OUTPUT_TOKENS = 16000;
|
|
301
|
+
/** How many tool calls one completion may make before the model is told to answer with what it has. */
|
|
302
|
+
export declare const LLM_COMPLETION_MAX_TOOL_CALLS = 6;
|
|
303
|
+
export type LlmCompletionRole = "system" | "user" | "assistant";
|
|
304
|
+
export interface LlmCompletionMessage {
|
|
305
|
+
readonly role: LlmCompletionRole;
|
|
306
|
+
/** Plain text. Images and audio are not accepted here. */
|
|
307
|
+
readonly content: string;
|
|
308
|
+
}
|
|
309
|
+
export interface LlmCompletionInput {
|
|
310
|
+
/** In order. At least one `user` or `assistant` turn; `system` turns alone are a `400`. */
|
|
311
|
+
readonly messages: readonly LlmCompletionMessage[];
|
|
312
|
+
/**
|
|
313
|
+
* A model the caller may choose (an `id` or a `model_id` from {@link LlmNamespace.models}).
|
|
314
|
+
* Omitted, the server's own choice for API completions answers, with its fallbacks.
|
|
315
|
+
*/
|
|
316
|
+
readonly model?: string;
|
|
317
|
+
/** Ask for a JSON object. A request, not a guarantee: parse defensively. */
|
|
318
|
+
readonly json?: boolean;
|
|
319
|
+
/** `0` to `2`. */
|
|
320
|
+
readonly temperature?: number;
|
|
321
|
+
/** `1` to {@link LLM_COMPLETION_MAX_OUTPUT_TOKENS}. */
|
|
322
|
+
readonly maxTokens?: number;
|
|
323
|
+
/** Tools the model may use while answering. Their calls come back in {@link LlmCompletion.tool_calls}. */
|
|
324
|
+
readonly tools?: readonly LlmCompletionTool[];
|
|
325
|
+
/** Language of the web searches the model runs (`"pt-PT"`, `"en"`); defaults to Portuguese. */
|
|
326
|
+
readonly language?: string;
|
|
327
|
+
}
|
|
328
|
+
/** One finished completion. Tokens and cost are `null` when the provider did not report them. */
|
|
329
|
+
export interface LlmCompletion {
|
|
330
|
+
readonly text: string;
|
|
331
|
+
/** The provider's identifier of the model that answered (a fallback may differ from the one asked for). */
|
|
332
|
+
readonly model_id: string | null;
|
|
333
|
+
readonly input_tokens: number | null;
|
|
334
|
+
readonly output_tokens: number | null;
|
|
335
|
+
/** In the provider's currency (USD for the hosted ones). */
|
|
336
|
+
readonly cost: number | null;
|
|
337
|
+
/** What the model did with its tools, in order. Empty without `tools`. */
|
|
338
|
+
readonly tool_calls: readonly LlmToolCall[];
|
|
339
|
+
/** From the request to the answer, in milliseconds. */
|
|
340
|
+
readonly duration_ms: number;
|
|
341
|
+
}
|
|
288
342
|
export declare class LlmNamespace extends Resource {
|
|
289
343
|
/** Conversations with the assistant. */
|
|
290
344
|
readonly chats: LlmChatsNamespace;
|
|
291
345
|
constructor(http: ApiClient);
|
|
292
346
|
/** The models the caller may choose, with today's remaining allowance on each. */
|
|
293
347
|
models(options?: RequestOptions): Promise<LlmModelChoice[]>;
|
|
348
|
+
/**
|
|
349
|
+
* `POST /llm/completions` - one answer to a list of messages, with nothing
|
|
350
|
+
* remembered between calls. For programs; people talk to the assistant
|
|
351
|
+
* through {@link chats}.
|
|
352
|
+
*
|
|
353
|
+
* Every completion counts on the account's daily ceilings (`llm_requests`
|
|
354
|
+
* and `llm_cost_microusd` in `oms.quotas.list()`) and on the chosen model's
|
|
355
|
+
* own daily limits. Needs the `llm` scope on an OAuth token.
|
|
356
|
+
*
|
|
357
|
+
* @throws {OmsApiError} 400 for malformed messages, an unknown model
|
|
358
|
+
* (`error: "unknown_model"`) or an unknown tool; 403 `error: "model_not_allowed"`
|
|
359
|
+
* for a model above the account's tier; 429 `error: "limit"` when a
|
|
360
|
+
* daily ceiling is reached, or above 30 completions a minute; 502
|
|
361
|
+
* `error: "unavailable"` when no model answered; 503 `error: "busy"`
|
|
362
|
+
* when the provider has no free slot, worth a retry in a moment.
|
|
363
|
+
*/
|
|
364
|
+
complete(input: LlmCompletionInput, options?: RequestOptions): Promise<LlmCompletion>;
|
|
294
365
|
/** The caller's own usage. */
|
|
295
366
|
usage(input?: LlmUsageQuery, options?: RequestOptions): Promise<LlmUsageSummary>;
|
|
296
367
|
}
|
|
@@ -19,8 +19,9 @@
|
|
|
19
19
|
* what is stored RIGHT NOW and only falls when something is deleted; waiting
|
|
20
20
|
* does not give it back.
|
|
21
21
|
* - **Anonymous callers get a shorter list.** Without a credential the server
|
|
22
|
-
* answers with the daily resources only, counted per IP, because an
|
|
23
|
-
* anonymous caller has no file tree
|
|
22
|
+
* answers with the daily tool resources only, counted per IP, because an
|
|
23
|
+
* anonymous caller has no file tree, no music library and no way to reach
|
|
24
|
+
* a model or the search engines. Never index the
|
|
24
25
|
* array by position - look the resource up by name, or use
|
|
25
26
|
* {@link quotaFor}, which returns `undefined` rather than lying.
|
|
26
27
|
*
|
|
@@ -44,14 +45,16 @@ import type { RequestOptions } from "../types";
|
|
|
44
45
|
* widened to `string` on purpose, so an unknown name arrives as data rather
|
|
45
46
|
* than as a type error in a client nobody has rebuilt.
|
|
46
47
|
*/
|
|
47
|
-
export declare const QUOTA_RESOURCES: readonly ["vocal_separation_seconds", "transcription_seconds", "caption_seconds", "jumpstyle_edits", "storage_nodes", "music_storage_bytes"];
|
|
48
|
+
export declare const QUOTA_RESOURCES: readonly ["vocal_separation_seconds", "transcription_seconds", "caption_seconds", "jumpstyle_edits", "storage_nodes", "music_storage_bytes", "llm_requests", "llm_cost_microusd", "search_requests"];
|
|
48
49
|
/** One of {@link QUOTA_RESOURCES}. */
|
|
49
50
|
export type QuotaResource = (typeof QUOTA_RESOURCES)[number];
|
|
50
51
|
/**
|
|
51
52
|
* What the numbers count. `"seconds"` of media, `"count"` of whole things
|
|
52
|
-
* (edits, files and folders), `"bytes"` of stored
|
|
53
|
+
* (edits, files and folders, model calls, searches), `"bytes"` of stored
|
|
54
|
+
* media, `"microusd"` of model spend (millionths of a US dollar, so
|
|
55
|
+
* `200_000` is 0.20 USD).
|
|
53
56
|
*/
|
|
54
|
-
export type QuotaUnit = "seconds" | "count" | "bytes";
|
|
57
|
+
export type QuotaUnit = "seconds" | "count" | "bytes" | "microusd";
|
|
55
58
|
/**
|
|
56
59
|
* `"daily"` spends and resets at midnight, server time. `"total"` is what is
|
|
57
60
|
* stored right now and only falls when something is deleted.
|
|
@@ -103,8 +103,44 @@ export interface SearchResponse {
|
|
|
103
103
|
/** Whether asking for `page + 1` is likely to return anything. */
|
|
104
104
|
readonly has_more: boolean;
|
|
105
105
|
}
|
|
106
|
+
/** Longer values answer `400`. */
|
|
107
|
+
export declare const SEARCH_PAGE_MAX_URL_LENGTH = 2000;
|
|
108
|
+
/** `maxChars` outside this range answers `400`. */
|
|
109
|
+
export declare const SEARCH_PAGE_MIN_CHARS = 200;
|
|
110
|
+
export declare const SEARCH_PAGE_MAX_CHARS = 20000;
|
|
111
|
+
export interface SearchPageInput {
|
|
112
|
+
/** A public `http(s)` URL. Private, loopback and link-local addresses answer `422`. */
|
|
113
|
+
readonly url: string;
|
|
114
|
+
/** How much text to return, {@link SEARCH_PAGE_MIN_CHARS} to {@link SEARCH_PAGE_MAX_CHARS}; defaults to 8000. */
|
|
115
|
+
readonly maxChars?: number;
|
|
116
|
+
}
|
|
117
|
+
/** The readable part of one page: scripts, navigation, footers and forms stripped. */
|
|
118
|
+
export interface SearchPage {
|
|
119
|
+
/** Where the page was actually read from, after redirects. */
|
|
120
|
+
readonly url: string;
|
|
121
|
+
readonly host: string;
|
|
122
|
+
/** Plain text, at most 200 characters; empty when the page has no title. */
|
|
123
|
+
readonly title: string;
|
|
124
|
+
/** Plain text, whitespace collapsed, cut at `maxChars`. Never empty: a page with nothing readable is a `422`. */
|
|
125
|
+
readonly text: string;
|
|
126
|
+
}
|
|
106
127
|
/** The `search` namespace, reachable as `oms.search`. */
|
|
107
128
|
export declare class SearchNamespace extends Resource {
|
|
129
|
+
/**
|
|
130
|
+
* `GET /search/page` - reads one public web page and returns its main text.
|
|
131
|
+
* The natural follow-up to {@link query}: search first, then read the hits
|
|
132
|
+
* worth reading in full.
|
|
133
|
+
*
|
|
134
|
+
* Only `http` and `https`, only public addresses, at most three redirects,
|
|
135
|
+
* and pages that are not HTML or text are refused. The server keeps the
|
|
136
|
+
* answer for ten minutes, so reading the same page twice is cheap.
|
|
137
|
+
*
|
|
138
|
+
* @throws {OmsApiError} 400 for a missing or overlong URL or a `maxChars`
|
|
139
|
+
* out of range; 401 without a credential; 422 with `error: "unreadable"`
|
|
140
|
+
* and a `message` saying why (private address, not HTML, unreachable,
|
|
141
|
+
* HTTP error, nothing readable); 429 above 60 reads a minute.
|
|
142
|
+
*/
|
|
143
|
+
readPage(input: SearchPageInput, options?: RequestOptions): Promise<SearchPage>;
|
|
108
144
|
/**
|
|
109
145
|
* `GET /search` - runs one search and returns one page of merged results.
|
|
110
146
|
*
|
package/package.json
CHANGED
|
@@ -1,230 +0,0 @@
|
|
|
1
|
-
/** Intel stories: the analysed, grouped, scored output. */
|
|
2
|
-
import { Resource } from "../../../http";
|
|
3
|
-
import type { ListParams } from "../../../listing";
|
|
4
|
-
import type { Id, Paginated, RequestOptions, Timestamp } from "../../../types";
|
|
5
|
-
import type { IntelArticleCategory, IntelReportKind } from "./types";
|
|
6
|
-
/**
|
|
7
|
-
* A story: several raw items about the same event, grouped, scored and
|
|
8
|
-
* categorised by the analysis pipeline.
|
|
9
|
-
*
|
|
10
|
-
* This is the shape an INDEX row has. `GET /intel_articles/:id` renders
|
|
11
|
-
* `:extended`, which is this plus four more keys - see
|
|
12
|
-
* {@link IntelArticleDetail}. The detail is always a superset, never a
|
|
13
|
-
* different record.
|
|
14
|
-
*/
|
|
15
|
-
export interface IntelArticle {
|
|
16
|
-
readonly id: Id;
|
|
17
|
-
readonly created_at: Timestamp;
|
|
18
|
-
readonly updated_at: Timestamp;
|
|
19
|
-
/** Headline the model wrote. Nullable: the column has no `NOT NULL`. */
|
|
20
|
-
readonly title: string | null;
|
|
21
|
-
/** One-paragraph summary. Nullable for the same reason. */
|
|
22
|
-
readonly summary: string | null;
|
|
23
|
-
/**
|
|
24
|
-
* 0-10, validated `only_integer, in: 0..10`. The buckets the dashboard uses
|
|
25
|
-
* are in {@link IntelStats.by_importance} and they are NOT evenly spaced:
|
|
26
|
-
* >=9 critical, 7-8 high, 5-6 medium, 3-4 low, <3 noise.
|
|
27
|
-
*/
|
|
28
|
-
readonly importance: number;
|
|
29
|
-
/** See {@link IntelArticleCategory}. `null` when unclassified. */
|
|
30
|
-
readonly category: IntelArticleCategory | null;
|
|
31
|
-
/**
|
|
32
|
-
* Free-form tags. The column defaults to `[]`, but it is nullable, so a row
|
|
33
|
-
* written before the default landed can still hand you `null`. Do not map
|
|
34
|
-
* over it without a guard.
|
|
35
|
-
*/
|
|
36
|
-
readonly tags: string[] | null;
|
|
37
|
-
/**
|
|
38
|
-
* The `og:image` of one of the story's sources, stored RAW and uncompressed
|
|
39
|
-
* - it points at whatever news site published it, not at this API. Render it
|
|
40
|
-
* through {@link intelArticleImageUrl} rather than directly; that helper
|
|
41
|
-
* explains the trade it makes.
|
|
42
|
-
*/
|
|
43
|
-
readonly image_url: string | null;
|
|
44
|
-
/**
|
|
45
|
-
* Whether the web-search enrichment pass has run on this story.
|
|
46
|
-
*
|
|
47
|
-
* `false` is not a failure, it is a queue position: `AnalyzeUserJob` enriches
|
|
48
|
-
* at most three stories per run, only those at or above
|
|
49
|
-
* {@link IntelConfig.enrich_min_importance}, and only while
|
|
50
|
-
* {@link IntelConfig.web_search} is on. A low-importance story stays `false`
|
|
51
|
-
* for ever, by design.
|
|
52
|
-
*/
|
|
53
|
-
readonly enriched: boolean;
|
|
54
|
-
/** When the story was first built. */
|
|
55
|
-
readonly first_seen_at: Timestamp;
|
|
56
|
-
/** Touched every time a new item joins the story. This is the "recency" clock. */
|
|
57
|
-
readonly last_seen_at: Timestamp;
|
|
58
|
-
/**
|
|
59
|
-
* How many raw items back this story.
|
|
60
|
-
*
|
|
61
|
-
* Costs one COUNT query per row on the listing. A page of 500 stories is
|
|
62
|
-
* 500 extra queries. This is the reason to keep `pageSize` modest on
|
|
63
|
-
* {@link IntelArticlesNamespace.list}.
|
|
64
|
-
*/
|
|
65
|
-
readonly n_sources: number;
|
|
66
|
-
}
|
|
67
|
-
/** One raw item cited by a story, as `:extended` inlines it. */
|
|
68
|
-
export interface IntelArticleSourceRef {
|
|
69
|
-
/** Id of the {@link IntelItem}. Fetch the full row with `items.get(id)`. */
|
|
70
|
-
readonly id: Id;
|
|
71
|
-
/** Name of the {@link IntelSource} the item came from, or `null` if it was deleted. */
|
|
72
|
-
readonly source_name: string | null;
|
|
73
|
-
readonly title: string | null;
|
|
74
|
-
readonly url: string | null;
|
|
75
|
-
readonly published_at: Timestamp | null;
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* A story related to this one, as `:extended` inlines it.
|
|
79
|
-
*
|
|
80
|
-
* "Related" is not "duplicate": duplicates are merged during dedup and never
|
|
81
|
-
* become two rows. `IntelArticleLink` is an undirected edge between two
|
|
82
|
-
* DISTINCT stories, which is why {@link relation} is one label describing the
|
|
83
|
-
* pair rather than a direction.
|
|
84
|
-
*/
|
|
85
|
-
export interface IntelRelatedArticleRef {
|
|
86
|
-
readonly id: Id;
|
|
87
|
-
readonly title: string | null;
|
|
88
|
-
readonly importance: number;
|
|
89
|
-
readonly category: IntelArticleCategory | null;
|
|
90
|
-
/** Free text the model wrote for the edge, e.g. a pattern name. Nullable. */
|
|
91
|
-
readonly relation: string | null;
|
|
92
|
-
}
|
|
93
|
-
/** A report this story appears in, as `:extended` inlines it. Newest period first. */
|
|
94
|
-
export interface IntelArticleReportRef {
|
|
95
|
-
readonly id: Id;
|
|
96
|
-
readonly kind: IntelReportKind;
|
|
97
|
-
readonly title: string | null;
|
|
98
|
-
readonly period_end: Timestamp;
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* `GET /intel_articles/:id` - the `:extended` view.
|
|
102
|
-
*
|
|
103
|
-
* Four keys the listing does not carry, and all four are joins run inline:
|
|
104
|
-
* `sources` walks `intel_items`, `related` walks the link table in
|
|
105
|
-
* BOTH directions, `reports` orders the report join by `period_end`. There is
|
|
106
|
-
* no paging on any of them, so a story that has been running for a week can
|
|
107
|
-
* inline a lot of rows.
|
|
108
|
-
*/
|
|
109
|
-
export interface IntelArticleDetail extends IntelArticle {
|
|
110
|
-
/** The long body. `null` until the enrichment pass writes one. */
|
|
111
|
-
readonly details: string | null;
|
|
112
|
-
/** Every raw item behind the story. Length matches {@link IntelArticle.n_sources}. */
|
|
113
|
-
readonly sources: IntelArticleSourceRef[];
|
|
114
|
-
/** Stories linked to this one. `[]` when the linker found nothing. */
|
|
115
|
-
readonly related: IntelRelatedArticleRef[];
|
|
116
|
-
/** Reports that cited this story, newest period first. */
|
|
117
|
-
readonly reports: IntelArticleReportRef[];
|
|
118
|
-
}
|
|
119
|
-
/** Filter columns of `GET /intel_articles`, on top of {@link BASE_FILTER_COLUMNS}. */
|
|
120
|
-
export declare const INTEL_ARTICLE_FILTER_COLUMNS: readonly ["title", "summary", "category", "importance", "enriched"];
|
|
121
|
-
/** Filters for {@link IntelArticlesNamespace.list}. */
|
|
122
|
-
export interface ListIntelArticlesParams extends ListParams<(typeof INTEL_ARTICLE_FILTER_COLUMNS)[number]> {
|
|
123
|
-
/**
|
|
124
|
-
* Free-text search over `title`, `summary` AND `details`.
|
|
125
|
-
*
|
|
126
|
-
* A TOP-LEVEL parameter, not a `search` key: the controller reads
|
|
127
|
-
* `params[:q]` itself, which is why it can reach `details` (a column that is
|
|
128
|
-
* not in `search_params` at all) and why an unknown-filter 400 cannot
|
|
129
|
-
* happen for it.
|
|
130
|
-
*
|
|
131
|
-
* Three ways it differs from {@link ListParams.search}:
|
|
132
|
-
*
|
|
133
|
-
* - it is **accent-SENSITIVE**. The controller does `LOWER(col) LIKE
|
|
134
|
-
* LOWER(term)`, with no unaccenting, while the list DSL's `search` strips
|
|
135
|
-
* accents on both sides. `"policia"` will not find `"polícia"` here.
|
|
136
|
-
* - `%` and `_` in your term are **not escaped**. The controller wraps the
|
|
137
|
-
* term as `"%#{q}%"` and binds it, so a term containing `%` is a wildcard,
|
|
138
|
-
* not a literal percent sign. Not an injection - it is a bound parameter -
|
|
139
|
-
* but a surprise. Strip them if you are passing user input through.
|
|
140
|
-
* - it is an unanchored `LIKE` over three text columns with no index, so it
|
|
141
|
-
* is a sequential scan of your stories. Fine for thousands, not for
|
|
142
|
-
* millions.
|
|
143
|
-
*/
|
|
144
|
-
readonly q?: string;
|
|
145
|
-
/**
|
|
146
|
-
* Keep only stories at or above this importance. Also top-level.
|
|
147
|
-
*
|
|
148
|
-
* Sent through Ruby's `String#to_i`, which does NOT raise: `"high"` becomes
|
|
149
|
-
* `0` and the filter silently matches everything. Pass a number and let the
|
|
150
|
-
* SDK stringify it.
|
|
151
|
-
*/
|
|
152
|
-
readonly minImportance?: number;
|
|
153
|
-
/**
|
|
154
|
-
* `"recent"` orders by `last_seen_at` descending. Anything else - including
|
|
155
|
-
* omitting it - orders by `importance` descending, then `last_seen_at`
|
|
156
|
-
* descending. There is no third value and no ascending variant.
|
|
157
|
-
*
|
|
158
|
-
* If you ALSO pass {@link PageParams.order}, both apply and yours wins: the
|
|
159
|
-
* controller appends its ordering after the list DSL has applied
|
|
160
|
-
* `modifiers[order]`, so your column becomes the primary sort key and the
|
|
161
|
-
* controller's becomes the tie-breaker. That is the opposite of what the
|
|
162
|
-
* parameter names suggest.
|
|
163
|
-
*/
|
|
164
|
-
readonly sort?: "recent" | "importance";
|
|
165
|
-
}
|
|
166
|
-
/**
|
|
167
|
-
* `GET /intel_articles` and friends: the stories the pipeline built.
|
|
168
|
-
*
|
|
169
|
-
* Read-only plus a delete. There is no create and no update route -
|
|
170
|
-
* `IntelArticle#creatable_by?` and `#updatable_by?` both return `false`
|
|
171
|
-
* unconditionally, and the route is `only: [:index, :show, :destroy]`. Stories
|
|
172
|
-
* come from `Intel::ArticleBuilder`, never from a client.
|
|
173
|
-
*/
|
|
174
|
-
export declare class IntelArticlesNamespace extends Resource {
|
|
175
|
-
/**
|
|
176
|
-
* `GET /intel_articles` - your stories, most important first.
|
|
177
|
-
*
|
|
178
|
-
* Ordering is the controller's, not yours by default: `importance DESC,
|
|
179
|
-
* last_seen_at DESC`, or `last_seen_at DESC` alone with `sort: "recent"`.
|
|
180
|
-
* See {@link ListIntelArticlesParams.sort} for what happens when you pass
|
|
181
|
-
* `order` as well - it is not what the names imply.
|
|
182
|
-
*
|
|
183
|
-
* Filter keys this controller declares for `search` / `exactSearch`:
|
|
184
|
-
* `title`, `summary`, `category`, `importance`, `enriched`, plus the
|
|
185
|
-
* inherited `id`, `created_at`, `updated_at`. Anything else is
|
|
186
|
-
* `400 "Unknown search filter: x"` - fail-closed, never a wider result. The
|
|
187
|
-
* free-text and importance filters are top-level instead: `q` and
|
|
188
|
-
* `minImportance`.
|
|
189
|
-
*
|
|
190
|
-
* **Cost.** Every row runs its own `COUNT` for
|
|
191
|
-
* {@link IntelArticle.n_sources}. Keep `pageSize` in the tens, not at 500.
|
|
192
|
-
*
|
|
193
|
-
* The response carries an `ETag` and can answer `304` - except when
|
|
194
|
-
* `random` is set, which short-circuits `resources_stale?`.
|
|
195
|
-
*
|
|
196
|
-
* @throws {OmsAuthError} 401 when anonymous.
|
|
197
|
-
* @throws {OmsApiError} 403 `"Intel access is restricted."` for a signed-in
|
|
198
|
-
* account outside the allowlist; 400 for an unrecognised filter key.
|
|
199
|
-
*/
|
|
200
|
-
list(params?: ListIntelArticlesParams, options?: RequestOptions): Promise<Paginated<IntelArticle>>;
|
|
201
|
-
/**
|
|
202
|
-
* `GET /intel_articles/:id` - one story with its body, its sources, its
|
|
203
|
-
* related stories and the reports that cited it.
|
|
204
|
-
*
|
|
205
|
-
* The `:extended` view, so it is a strict superset of the listing row. All
|
|
206
|
-
* four extras are inlined without paging; see {@link IntelArticleDetail}.
|
|
207
|
-
*
|
|
208
|
-
* @throws {OmsApiError} 404 `"Resource not found"` when the id is not one of
|
|
209
|
-
* yours - the lookup is `viewable_by(Current.user).find_by(id:)`, so
|
|
210
|
-
* somebody else's story is indistinguishable from a typo, which is the
|
|
211
|
-
* point.
|
|
212
|
-
*/
|
|
213
|
-
get(id: Id, options?: RequestOptions): Promise<IntelArticleDetail>;
|
|
214
|
-
/**
|
|
215
|
-
* `DELETE /intel_articles/:id` - drops a story. `204`, empty body.
|
|
216
|
-
*
|
|
217
|
-
* The story's links to items are removed with it (`dependent: :destroy` on
|
|
218
|
-
* `intel_article_sources`), but the {@link IntelItem} rows themselves SURVIVE
|
|
219
|
-
* - they belong to the source, not to the story. They are also still marked
|
|
220
|
-
* `processed_at`, so deleting a story does not make the pipeline rebuild it.
|
|
221
|
-
* This is a hide, not an undo.
|
|
222
|
-
*
|
|
223
|
-
* @throws {OmsApiError} 404 when the story is not yours. 401
|
|
224
|
-
* `"You are not authorized to destroy this resource"` cannot happen here -
|
|
225
|
-
* `destroyable_by?` is `user == self.user` and the lookup already scoped it
|
|
226
|
-
* - but note the API's habit of answering 401 rather than 403 for a failed
|
|
227
|
-
* authorisation check, which the scripts routes DO hit.
|
|
228
|
-
*/
|
|
229
|
-
delete(id: Id, options?: RequestOptions): Promise<void>;
|
|
230
|
-
}
|