@telemai/sdk 0.2.3 → 0.2.5

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 CHANGED
@@ -198,6 +198,24 @@ console.log(summary.query, summary.goal, summary.context)
198
198
  `results` returns the query, the goal and the context of the session, plus the
199
199
  results of each search step.
200
200
 
201
+ ## Monitors
202
+
203
+ A monitor runs a query on a schedule. Poll it to get the results that are new since
204
+ your last poll. `poll` returns a `SearchResponse`:
205
+
206
+ ```ts
207
+ const monitor = await telem.monitors.create("Nvidia files a new 8-K with the SEC", {
208
+ providers: ["exa", "parallel"],
209
+ frequency: "1h",
210
+ })
211
+ const response = await telem.monitors.poll(monitor.id)
212
+ await telem.monitors.update(monitor.id, { status: "paused" })
213
+ await telem.monitors.delete(monitor.id)
214
+ ```
215
+
216
+ `telem.monitors` also has `get` and `list`. See [Monitors](https://docs.telem.ai/resources/monitors/)
217
+ for the fields, the costs and the errors.
218
+
201
219
  ## Vercel AI SDK
202
220
 
203
221
  If your agent runs on the Vercel AI SDK, `@telemai/sdk/vercel` gives it
@@ -107,7 +107,7 @@ function retryDelay(retryAfter, attempt) {
107
107
  }
108
108
  return backoff(attempt);
109
109
  }
110
- async function request(config, method, path, body, abort) {
110
+ async function request(config, method, path, body, abort, retry = "all") {
111
111
  const url = `${config.baseUrl}/${path.replace(/^\/+/, "")}`;
112
112
  const headers = { "User-Agent": config.userAgent };
113
113
  if (config.apiKey) headers.Authorization = `Bearer ${config.apiKey}`;
@@ -172,14 +172,15 @@ async function request(config, method, path, body, abort) {
172
172
  if (signal?.aborted) {
173
173
  throw new TimeoutError(`request to ${url} timed out after ${config.timeoutMs}ms`, cause);
174
174
  }
175
- if (attempt >= config.maxRetries) throw connectionError(url, cause);
175
+ if (retry === "rate_limit" || attempt >= config.maxRetries) throw connectionError(url, cause);
176
176
  await pause(backoff(attempt));
177
177
  continue;
178
178
  } finally {
179
179
  signal?.removeEventListener("abort", onAbort2);
180
180
  }
181
181
  if (received.status >= 200 && received.status < 300) return received.body;
182
- if (isRetryable(received.status) && attempt < config.maxRetries) {
182
+ const retryable = retry === "rate_limit" ? received.status === 429 : isRetryable(received.status);
183
+ if (retryable && attempt < config.maxRetries) {
183
184
  await pause(retryDelay(received.retryAfter, attempt));
184
185
  continue;
185
186
  }
package/dist/index.cjs CHANGED
@@ -59,7 +59,7 @@ var TimeoutError = class extends TelemError {
59
59
  };
60
60
 
61
61
  // src/version.ts
62
- var VERSION = "0.2.3";
62
+ var VERSION = "0.2.5";
63
63
 
64
64
  // src/config.ts
65
65
  var DEFAULT_BASE_URL = "https://router.telem.ai";
@@ -250,7 +250,7 @@ function retryDelay(retryAfter, attempt) {
250
250
  }
251
251
  return backoff(attempt);
252
252
  }
253
- async function request(config, method, path, body, abort) {
253
+ async function request(config, method, path, body, abort, retry = "all") {
254
254
  const url = `${config.baseUrl}/${path.replace(/^\/+/, "")}`;
255
255
  const headers = { "User-Agent": config.userAgent };
256
256
  if (config.apiKey) headers.Authorization = `Bearer ${config.apiKey}`;
@@ -315,14 +315,15 @@ async function request(config, method, path, body, abort) {
315
315
  if (signal?.aborted) {
316
316
  throw new TimeoutError(`request to ${url} timed out after ${config.timeoutMs}ms`, cause);
317
317
  }
318
- if (attempt >= config.maxRetries) throw connectionError(url, cause);
318
+ if (retry === "rate_limit" || attempt >= config.maxRetries) throw connectionError(url, cause);
319
319
  await pause(backoff(attempt));
320
320
  continue;
321
321
  } finally {
322
322
  signal?.removeEventListener("abort", onAbort2);
323
323
  }
324
324
  if (received.status >= 200 && received.status < 300) return received.body;
325
- if (isRetryable(received.status) && attempt < config.maxRetries) {
325
+ const retryable = retry === "rate_limit" ? received.status === 429 : isRetryable(received.status);
326
+ if (retryable && attempt < config.maxRetries) {
326
327
  await pause(retryDelay(received.retryAfter, attempt));
327
328
  continue;
328
329
  }
@@ -547,21 +548,6 @@ async function fetchUrls(config, url, options) {
547
548
  return buildFetchResponse(await request(config, "POST", "/v1/fetch", body, options.signal));
548
549
  }
549
550
 
550
- // src/methods/providers.ts
551
- async function providers(config) {
552
- const body = await request(config, "GET", "/v1/preprocessors");
553
- return asArray(asObject(body).preprocessors).filter(isObject).map((entry) => ({
554
- name: entry.name ?? "",
555
- type: entry.type ?? "",
556
- activeByDefault: entry.active_by_default ?? false,
557
- description: entry.description ?? null,
558
- method: entry.method ?? null,
559
- url: entry.url ?? null,
560
- normalized: entry.normalized ?? false,
561
- tiers: asArray(entry.tiers)
562
- }));
563
- }
564
-
565
551
  // src/methods/search.ts
566
552
  var MIN_SCHEMA_VERSION = 2;
567
553
  function searchBlock(defaults, options) {
@@ -599,8 +585,13 @@ function searchBlock(defaults, options) {
599
585
  if (maxRoutingProviders !== void 0) block.max_routing_providers = maxRoutingProviders;
600
586
  const topic = options.topic ?? defaults.topic;
601
587
  if (topic !== void 0) block.topic = topic;
588
+ if (options.publishedAfter !== void 0) block.published_after = isoDate(options.publishedAfter);
589
+ if (options.publishedBefore !== void 0) block.published_before = isoDate(options.publishedBefore);
602
590
  return block;
603
591
  }
592
+ function isoDate(value) {
593
+ return typeof value === "string" ? value : value.toISOString();
594
+ }
604
595
  function userInput(query) {
605
596
  if (typeof query === "string") {
606
597
  if (query === "") throw invalidRequest("search() requires a non-empty query");
@@ -704,6 +695,89 @@ async function search(config, query, options) {
704
695
  return buildSearchResponse(data);
705
696
  }
706
697
 
698
+ // src/methods/monitors.ts
699
+ function monitorFrom(body) {
700
+ const data = asObject(body);
701
+ return {
702
+ id: String(data.id ?? ""),
703
+ query: data.query ?? "",
704
+ frequency: data.frequency ?? "",
705
+ providers: asArray(data.providers).filter(isObject).map((p) => ({ name: String(p.name ?? ""), status: String(p.status ?? "") })),
706
+ sessionId: String(data.session_id ?? ""),
707
+ createdAt: data.created_at ?? "",
708
+ lastPolledAt: data.last_polled_at ?? null,
709
+ raw: data
710
+ };
711
+ }
712
+ function createMonitors(config) {
713
+ const path = (monitorId, suffix = "") => {
714
+ if (!monitorId || /^\.+$/.test(monitorId)) throw invalidRequest("a monitor id is required");
715
+ return `/v1/monitors/${encodeURIComponent(monitorId)}${suffix}`;
716
+ };
717
+ return {
718
+ /** Create a monitor. Each provider runs `query` on the schedule. */
719
+ async create(query, options) {
720
+ const body = {
721
+ query,
722
+ options: { providers: { include: options.providers }, frequency: options.frequency }
723
+ };
724
+ if (options.providerOverrides !== void 0) {
725
+ body.options.provider_overrides = options.providerOverrides;
726
+ }
727
+ if (options.metadata !== void 0) body.metadata = options.metadata;
728
+ const data = await request(config, "POST", "/v1/monitors", body, options.signal, "rate_limit");
729
+ return monitorFrom(data);
730
+ },
731
+ /** List your monitors, newest first (server default 50, maximum 200). */
732
+ async list(options = {}) {
733
+ const query = options.limit === void 0 ? "" : `?limit=${options.limit}`;
734
+ const body = await request(config, "GET", `/v1/monitors${query}`, void 0, options.signal);
735
+ return asArray(asObject(body).monitors).map(monitorFrom);
736
+ },
737
+ /** Get one monitor. */
738
+ async get(monitorId, options = {}) {
739
+ return monitorFrom(await request(config, "GET", path(monitorId), void 0, options.signal));
740
+ },
741
+ /** Pause, resume or change a monitor. Only the fields given are sent. */
742
+ async update(monitorId, options) {
743
+ const body = {};
744
+ if (options.status !== void 0) body.status = options.status;
745
+ if (options.frequency !== void 0) body.frequency = options.frequency;
746
+ if (options.providerOverrides !== void 0) body.provider_overrides = options.providerOverrides;
747
+ const route = path(monitorId);
748
+ return monitorFrom(await request(config, "PATCH", route, body, options.signal));
749
+ },
750
+ /** Get the results that are new since the last poll, one entry per provider. */
751
+ async poll(monitorId, options = {}) {
752
+ const body = {};
753
+ if (options.session !== void 0) body.session_id = options.session;
754
+ if (options.metadata !== void 0) body.metadata = options.metadata;
755
+ const route = path(monitorId, "/poll");
756
+ const data = await request(config, "POST", route, body, options.signal, "rate_limit");
757
+ return buildSearchResponse(data);
758
+ },
759
+ /** Delete a monitor. A repeat deletes what a failed delete left. */
760
+ async delete(monitorId, options = {}) {
761
+ await request(config, "DELETE", path(monitorId), void 0, options.signal);
762
+ }
763
+ };
764
+ }
765
+
766
+ // src/methods/providers.ts
767
+ async function providers(config) {
768
+ const body = await request(config, "GET", "/v1/preprocessors");
769
+ return asArray(asObject(body).preprocessors).filter(isObject).map((entry) => ({
770
+ name: entry.name ?? "",
771
+ type: entry.type ?? "",
772
+ activeByDefault: entry.active_by_default ?? false,
773
+ description: entry.description ?? null,
774
+ method: entry.method ?? null,
775
+ url: entry.url ?? null,
776
+ normalized: entry.normalized ?? false,
777
+ tiers: asArray(entry.tiers)
778
+ }));
779
+ }
780
+
707
781
  // src/methods/sessions.ts
708
782
  function sessionsFrom(body) {
709
783
  return asArray(asObject(body).sessions).filter(isObject).map((entry) => ({
@@ -769,6 +843,8 @@ var Telem = class {
769
843
  maxRetries;
770
844
  /** The session read surface: `list` and `results(id)`. */
771
845
  sessions;
846
+ /** Monitors: `create`, `list`, `get`, `update`, `poll`, `delete`. */
847
+ monitors;
772
848
  #config;
773
849
  /**
774
850
  * @param options - An API key string, or an options object. Anything left unset
@@ -783,6 +859,7 @@ var Telem = class {
783
859
  this.timeoutMs = config.timeoutMs;
784
860
  this.maxRetries = config.maxRetries;
785
861
  this.sessions = createSessions(config);
862
+ this.monitors = createMonitors(config);
786
863
  }
787
864
  /**
788
865
  * Run a web search.
package/dist/index.d.cts CHANGED
@@ -64,6 +64,14 @@ type SearchOptions = {
64
64
  autoRouting?: string;
65
65
  maxRoutingProviders?: number;
66
66
  topic?: string;
67
+ /** Only results published on or after this date or date-time: an ISO 8601 string
68
+ * (no time zone means UTC) or a `Date`. Results with no known date are kept.
69
+ * Per-call only, like the two below. */
70
+ publishedAfter?: string | Date;
71
+ /** Only results published before this date or date-time. A date with no time
72
+ * includes that whole day. A `Date` is an exact instant; pass a "YYYY-MM-DD"
73
+ * string to include the whole day. */
74
+ publishedBefore?: string | Date;
67
75
  /** Opt this request into the server's rerank stage. It is the only path where
68
76
  * `context`, the reasoning on the last assistant entry of the lineage history
69
77
  * (that entry only), and `goal` change result ORDER (in that precedence) —
@@ -214,6 +222,68 @@ type SessionsResource = {
214
222
  list(): Promise<SessionSummary[]>;
215
223
  results(sessionId: string): Promise<SessionResults>;
216
224
  };
225
+ /** Options for `monitors.create`. */
226
+ type MonitorCreateOptions = {
227
+ /** One or more provider names, for example `["exa", "parallel"]`. */
228
+ providers: string[];
229
+ /** `"1h"`, `"6h"`, `"1d"` or `"7d"`. */
230
+ frequency: string;
231
+ /** Per-provider create fields, keyed by provider name. */
232
+ providerOverrides?: Record<string, Json>;
233
+ /** Request metadata (query lineage keys), sent as given. */
234
+ metadata?: Json;
235
+ signal?: AbortSignal;
236
+ };
237
+ /** Options for `monitors.update`. Send at least one of the three fields. */
238
+ type MonitorUpdateOptions = {
239
+ /** `"paused"` or `"active"`. */
240
+ status?: string;
241
+ frequency?: string;
242
+ /** New overrides for the providers named. They replace the ones sent before. */
243
+ providerOverrides?: Record<string, Json>;
244
+ signal?: AbortSignal;
245
+ };
246
+ /** Options for `monitors.poll`. */
247
+ type MonitorPollOptions = {
248
+ /** Record this poll in another session (default: the monitor's own). */
249
+ session?: string;
250
+ /** Request metadata (query lineage keys), sent as given. */
251
+ metadata?: Json;
252
+ signal?: AbortSignal;
253
+ };
254
+ /** One provider of a monitor. `status` is `active`, `paused` (you paused it) or
255
+ * `idle` (paused because nobody polled; the next poll resumes it). */
256
+ type MonitorProvider = {
257
+ name: string;
258
+ status: string;
259
+ };
260
+ /** A monitor: a query that providers run on a schedule. */
261
+ type Monitor = {
262
+ id: string;
263
+ query: string;
264
+ frequency: string;
265
+ providers: MonitorProvider[];
266
+ sessionId: string;
267
+ createdAt: string;
268
+ lastPolledAt: string | null;
269
+ raw: Json;
270
+ };
271
+ /** The `telem.monitors` namespace. */
272
+ type MonitorsResource = {
273
+ create(query: string, options: MonitorCreateOptions): Promise<Monitor>;
274
+ list(options?: {
275
+ limit?: number;
276
+ signal?: AbortSignal;
277
+ }): Promise<Monitor[]>;
278
+ get(monitorId: string, options?: {
279
+ signal?: AbortSignal;
280
+ }): Promise<Monitor>;
281
+ update(monitorId: string, options: MonitorUpdateOptions): Promise<Monitor>;
282
+ poll(monitorId: string, options?: MonitorPollOptions): Promise<SearchResponse>;
283
+ delete(monitorId: string, options?: {
284
+ signal?: AbortSignal;
285
+ }): Promise<void>;
286
+ };
217
287
 
218
288
  /**
219
289
  * The CLOSED set of codes the client itself assigns, for failures that never
@@ -350,6 +420,8 @@ declare class Telem {
350
420
  readonly maxRetries: number;
351
421
  /** The session read surface: `list` and `results(id)`. */
352
422
  readonly sessions: SessionsResource;
423
+ /** Monitors: `create`, `list`, `get`, `update`, `poll`, `delete`. */
424
+ readonly monitors: MonitorsResource;
353
425
  /**
354
426
  * @param options - An API key string, or an options object. Anything left unset
355
427
  * resolves from `TELEM_*` env vars, then `~/.telem/credentials.json` (credentials
@@ -381,4 +453,4 @@ declare class Telem {
381
453
  providers(): Promise<ProviderInfo[]>;
382
454
  }
383
455
 
384
- export { type FetchOptions, type FetchResponse, type FetchResult, type Json, type ProviderInfo, type ProviderRun, RESERVED_METADATA, type SearchDefaults, type SearchOptions, type SearchResponse, type SearchResult, type SessionResults, type SessionSummary, type SessionsResource, type SnapshotArgs, Telem, type TelemClientErrorCode, TelemError, type TelemErrorOptions, type TelemOptions, TimeoutError, type TrajectoryArgs, type TrajectoryEnvelope, type TrajectorySnapshot, buildMetadata, buildSnapshot, contentAnchor, Telem as default, eventNodeKey, fingerprint, sessionKey, snapshotNodeKey, toolMarker, windowAnchor, withTrajectory };
456
+ export { type FetchOptions, type FetchResponse, type FetchResult, type Json, type Monitor, type MonitorCreateOptions, type MonitorPollOptions, type MonitorProvider, type MonitorUpdateOptions, type MonitorsResource, type ProviderInfo, type ProviderRun, RESERVED_METADATA, type SearchDefaults, type SearchOptions, type SearchResponse, type SearchResult, type SessionResults, type SessionSummary, type SessionsResource, type SnapshotArgs, Telem, type TelemClientErrorCode, TelemError, type TelemErrorOptions, type TelemOptions, TimeoutError, type TrajectoryArgs, type TrajectoryEnvelope, type TrajectorySnapshot, buildMetadata, buildSnapshot, contentAnchor, Telem as default, eventNodeKey, fingerprint, sessionKey, snapshotNodeKey, toolMarker, windowAnchor, withTrajectory };
package/dist/index.d.ts CHANGED
@@ -64,6 +64,14 @@ type SearchOptions = {
64
64
  autoRouting?: string;
65
65
  maxRoutingProviders?: number;
66
66
  topic?: string;
67
+ /** Only results published on or after this date or date-time: an ISO 8601 string
68
+ * (no time zone means UTC) or a `Date`. Results with no known date are kept.
69
+ * Per-call only, like the two below. */
70
+ publishedAfter?: string | Date;
71
+ /** Only results published before this date or date-time. A date with no time
72
+ * includes that whole day. A `Date` is an exact instant; pass a "YYYY-MM-DD"
73
+ * string to include the whole day. */
74
+ publishedBefore?: string | Date;
67
75
  /** Opt this request into the server's rerank stage. It is the only path where
68
76
  * `context`, the reasoning on the last assistant entry of the lineage history
69
77
  * (that entry only), and `goal` change result ORDER (in that precedence) —
@@ -214,6 +222,68 @@ type SessionsResource = {
214
222
  list(): Promise<SessionSummary[]>;
215
223
  results(sessionId: string): Promise<SessionResults>;
216
224
  };
225
+ /** Options for `monitors.create`. */
226
+ type MonitorCreateOptions = {
227
+ /** One or more provider names, for example `["exa", "parallel"]`. */
228
+ providers: string[];
229
+ /** `"1h"`, `"6h"`, `"1d"` or `"7d"`. */
230
+ frequency: string;
231
+ /** Per-provider create fields, keyed by provider name. */
232
+ providerOverrides?: Record<string, Json>;
233
+ /** Request metadata (query lineage keys), sent as given. */
234
+ metadata?: Json;
235
+ signal?: AbortSignal;
236
+ };
237
+ /** Options for `monitors.update`. Send at least one of the three fields. */
238
+ type MonitorUpdateOptions = {
239
+ /** `"paused"` or `"active"`. */
240
+ status?: string;
241
+ frequency?: string;
242
+ /** New overrides for the providers named. They replace the ones sent before. */
243
+ providerOverrides?: Record<string, Json>;
244
+ signal?: AbortSignal;
245
+ };
246
+ /** Options for `monitors.poll`. */
247
+ type MonitorPollOptions = {
248
+ /** Record this poll in another session (default: the monitor's own). */
249
+ session?: string;
250
+ /** Request metadata (query lineage keys), sent as given. */
251
+ metadata?: Json;
252
+ signal?: AbortSignal;
253
+ };
254
+ /** One provider of a monitor. `status` is `active`, `paused` (you paused it) or
255
+ * `idle` (paused because nobody polled; the next poll resumes it). */
256
+ type MonitorProvider = {
257
+ name: string;
258
+ status: string;
259
+ };
260
+ /** A monitor: a query that providers run on a schedule. */
261
+ type Monitor = {
262
+ id: string;
263
+ query: string;
264
+ frequency: string;
265
+ providers: MonitorProvider[];
266
+ sessionId: string;
267
+ createdAt: string;
268
+ lastPolledAt: string | null;
269
+ raw: Json;
270
+ };
271
+ /** The `telem.monitors` namespace. */
272
+ type MonitorsResource = {
273
+ create(query: string, options: MonitorCreateOptions): Promise<Monitor>;
274
+ list(options?: {
275
+ limit?: number;
276
+ signal?: AbortSignal;
277
+ }): Promise<Monitor[]>;
278
+ get(monitorId: string, options?: {
279
+ signal?: AbortSignal;
280
+ }): Promise<Monitor>;
281
+ update(monitorId: string, options: MonitorUpdateOptions): Promise<Monitor>;
282
+ poll(monitorId: string, options?: MonitorPollOptions): Promise<SearchResponse>;
283
+ delete(monitorId: string, options?: {
284
+ signal?: AbortSignal;
285
+ }): Promise<void>;
286
+ };
217
287
 
218
288
  /**
219
289
  * The CLOSED set of codes the client itself assigns, for failures that never
@@ -350,6 +420,8 @@ declare class Telem {
350
420
  readonly maxRetries: number;
351
421
  /** The session read surface: `list` and `results(id)`. */
352
422
  readonly sessions: SessionsResource;
423
+ /** Monitors: `create`, `list`, `get`, `update`, `poll`, `delete`. */
424
+ readonly monitors: MonitorsResource;
353
425
  /**
354
426
  * @param options - An API key string, or an options object. Anything left unset
355
427
  * resolves from `TELEM_*` env vars, then `~/.telem/credentials.json` (credentials
@@ -381,4 +453,4 @@ declare class Telem {
381
453
  providers(): Promise<ProviderInfo[]>;
382
454
  }
383
455
 
384
- export { type FetchOptions, type FetchResponse, type FetchResult, type Json, type ProviderInfo, type ProviderRun, RESERVED_METADATA, type SearchDefaults, type SearchOptions, type SearchResponse, type SearchResult, type SessionResults, type SessionSummary, type SessionsResource, type SnapshotArgs, Telem, type TelemClientErrorCode, TelemError, type TelemErrorOptions, type TelemOptions, TimeoutError, type TrajectoryArgs, type TrajectoryEnvelope, type TrajectorySnapshot, buildMetadata, buildSnapshot, contentAnchor, Telem as default, eventNodeKey, fingerprint, sessionKey, snapshotNodeKey, toolMarker, windowAnchor, withTrajectory };
456
+ export { type FetchOptions, type FetchResponse, type FetchResult, type Json, type Monitor, type MonitorCreateOptions, type MonitorPollOptions, type MonitorProvider, type MonitorUpdateOptions, type MonitorsResource, type ProviderInfo, type ProviderRun, RESERVED_METADATA, type SearchDefaults, type SearchOptions, type SearchResponse, type SearchResult, type SessionResults, type SessionSummary, type SessionsResource, type SnapshotArgs, Telem, type TelemClientErrorCode, TelemError, type TelemErrorOptions, type TelemOptions, TimeoutError, type TrajectoryArgs, type TrajectoryEnvelope, type TrajectorySnapshot, buildMetadata, buildSnapshot, contentAnchor, Telem as default, eventNodeKey, fingerprint, sessionKey, snapshotNodeKey, toolMarker, windowAnchor, withTrajectory };
package/dist/index.js CHANGED
@@ -19,10 +19,10 @@ import {
19
19
  windowAnchor,
20
20
  wireMetadata,
21
21
  withTrajectory
22
- } from "./chunk-RYY4S5LP.js";
22
+ } from "./chunk-DKTEG7EY.js";
23
23
 
24
24
  // src/version.ts
25
- var VERSION = "0.2.3";
25
+ var VERSION = "0.2.5";
26
26
 
27
27
  // src/config.ts
28
28
  var DEFAULT_BASE_URL = "https://router.telem.ai";
@@ -182,21 +182,6 @@ async function fetchUrls(config, url, options) {
182
182
  return buildFetchResponse(await request(config, "POST", "/v1/fetch", body, options.signal));
183
183
  }
184
184
 
185
- // src/methods/providers.ts
186
- async function providers(config) {
187
- const body = await request(config, "GET", "/v1/preprocessors");
188
- return asArray(asObject(body).preprocessors).filter(isObject).map((entry) => ({
189
- name: entry.name ?? "",
190
- type: entry.type ?? "",
191
- activeByDefault: entry.active_by_default ?? false,
192
- description: entry.description ?? null,
193
- method: entry.method ?? null,
194
- url: entry.url ?? null,
195
- normalized: entry.normalized ?? false,
196
- tiers: asArray(entry.tiers)
197
- }));
198
- }
199
-
200
185
  // src/methods/search.ts
201
186
  var MIN_SCHEMA_VERSION = 2;
202
187
  function searchBlock(defaults, options) {
@@ -234,8 +219,13 @@ function searchBlock(defaults, options) {
234
219
  if (maxRoutingProviders !== void 0) block.max_routing_providers = maxRoutingProviders;
235
220
  const topic = options.topic ?? defaults.topic;
236
221
  if (topic !== void 0) block.topic = topic;
222
+ if (options.publishedAfter !== void 0) block.published_after = isoDate(options.publishedAfter);
223
+ if (options.publishedBefore !== void 0) block.published_before = isoDate(options.publishedBefore);
237
224
  return block;
238
225
  }
226
+ function isoDate(value) {
227
+ return typeof value === "string" ? value : value.toISOString();
228
+ }
239
229
  function userInput(query) {
240
230
  if (typeof query === "string") {
241
231
  if (query === "") throw invalidRequest("search() requires a non-empty query");
@@ -339,6 +329,89 @@ async function search(config, query, options) {
339
329
  return buildSearchResponse(data);
340
330
  }
341
331
 
332
+ // src/methods/monitors.ts
333
+ function monitorFrom(body) {
334
+ const data = asObject(body);
335
+ return {
336
+ id: String(data.id ?? ""),
337
+ query: data.query ?? "",
338
+ frequency: data.frequency ?? "",
339
+ providers: asArray(data.providers).filter(isObject).map((p) => ({ name: String(p.name ?? ""), status: String(p.status ?? "") })),
340
+ sessionId: String(data.session_id ?? ""),
341
+ createdAt: data.created_at ?? "",
342
+ lastPolledAt: data.last_polled_at ?? null,
343
+ raw: data
344
+ };
345
+ }
346
+ function createMonitors(config) {
347
+ const path = (monitorId, suffix = "") => {
348
+ if (!monitorId || /^\.+$/.test(monitorId)) throw invalidRequest("a monitor id is required");
349
+ return `/v1/monitors/${encodeURIComponent(monitorId)}${suffix}`;
350
+ };
351
+ return {
352
+ /** Create a monitor. Each provider runs `query` on the schedule. */
353
+ async create(query, options) {
354
+ const body = {
355
+ query,
356
+ options: { providers: { include: options.providers }, frequency: options.frequency }
357
+ };
358
+ if (options.providerOverrides !== void 0) {
359
+ body.options.provider_overrides = options.providerOverrides;
360
+ }
361
+ if (options.metadata !== void 0) body.metadata = options.metadata;
362
+ const data = await request(config, "POST", "/v1/monitors", body, options.signal, "rate_limit");
363
+ return monitorFrom(data);
364
+ },
365
+ /** List your monitors, newest first (server default 50, maximum 200). */
366
+ async list(options = {}) {
367
+ const query = options.limit === void 0 ? "" : `?limit=${options.limit}`;
368
+ const body = await request(config, "GET", `/v1/monitors${query}`, void 0, options.signal);
369
+ return asArray(asObject(body).monitors).map(monitorFrom);
370
+ },
371
+ /** Get one monitor. */
372
+ async get(monitorId, options = {}) {
373
+ return monitorFrom(await request(config, "GET", path(monitorId), void 0, options.signal));
374
+ },
375
+ /** Pause, resume or change a monitor. Only the fields given are sent. */
376
+ async update(monitorId, options) {
377
+ const body = {};
378
+ if (options.status !== void 0) body.status = options.status;
379
+ if (options.frequency !== void 0) body.frequency = options.frequency;
380
+ if (options.providerOverrides !== void 0) body.provider_overrides = options.providerOverrides;
381
+ const route = path(monitorId);
382
+ return monitorFrom(await request(config, "PATCH", route, body, options.signal));
383
+ },
384
+ /** Get the results that are new since the last poll, one entry per provider. */
385
+ async poll(monitorId, options = {}) {
386
+ const body = {};
387
+ if (options.session !== void 0) body.session_id = options.session;
388
+ if (options.metadata !== void 0) body.metadata = options.metadata;
389
+ const route = path(monitorId, "/poll");
390
+ const data = await request(config, "POST", route, body, options.signal, "rate_limit");
391
+ return buildSearchResponse(data);
392
+ },
393
+ /** Delete a monitor. A repeat deletes what a failed delete left. */
394
+ async delete(monitorId, options = {}) {
395
+ await request(config, "DELETE", path(monitorId), void 0, options.signal);
396
+ }
397
+ };
398
+ }
399
+
400
+ // src/methods/providers.ts
401
+ async function providers(config) {
402
+ const body = await request(config, "GET", "/v1/preprocessors");
403
+ return asArray(asObject(body).preprocessors).filter(isObject).map((entry) => ({
404
+ name: entry.name ?? "",
405
+ type: entry.type ?? "",
406
+ activeByDefault: entry.active_by_default ?? false,
407
+ description: entry.description ?? null,
408
+ method: entry.method ?? null,
409
+ url: entry.url ?? null,
410
+ normalized: entry.normalized ?? false,
411
+ tiers: asArray(entry.tiers)
412
+ }));
413
+ }
414
+
342
415
  // src/methods/sessions.ts
343
416
  function sessionsFrom(body) {
344
417
  return asArray(asObject(body).sessions).filter(isObject).map((entry) => ({
@@ -404,6 +477,8 @@ var Telem = class {
404
477
  maxRetries;
405
478
  /** The session read surface: `list` and `results(id)`. */
406
479
  sessions;
480
+ /** Monitors: `create`, `list`, `get`, `update`, `poll`, `delete`. */
481
+ monitors;
407
482
  #config;
408
483
  /**
409
484
  * @param options - An API key string, or an options object. Anything left unset
@@ -418,6 +493,7 @@ var Telem = class {
418
493
  this.timeoutMs = config.timeoutMs;
419
494
  this.maxRetries = config.maxRetries;
420
495
  this.sessions = createSessions(config);
496
+ this.monitors = createMonitors(config);
421
497
  }
422
498
  /**
423
499
  * Run a web search.
@@ -452,7 +452,10 @@ async function turnAnchor(messages, windowId) {
452
452
  return await contentAnchor(String(messages.length), windowId, text);
453
453
  }
454
454
  function compact(response) {
455
- return response.results.slice(0, RESULT_CAP).map(({ provider, title, url, summary }) => ({ provider, title, url, summary }));
455
+ return response.results.slice(0, RESULT_CAP).map(({ provider, title, url, summary, publishDate }) => {
456
+ const published = publishDate?.trim();
457
+ return published ? { provider, title, url, summary, published } : { provider, title, url, summary };
458
+ });
456
459
  }
457
460
  function page(response) {
458
461
  const first = response.results[0];
@@ -477,6 +480,14 @@ var SEARCH_SCHEMA = (0, import_ai.jsonSchema)({
477
480
  topic: {
478
481
  type: "string",
479
482
  description: "Optional. Set it only when the answer must come from one site: linkedin, reddit, or x (twitter is also accepted). Leave it unset otherwise."
483
+ },
484
+ published_after: {
485
+ type: "string",
486
+ description: "Optional. Only return results published on or after this date or date-time, in ISO 8601 (for example 2026-10-01 or 2026-10-01T09:00:00Z). A value with no time zone is read as UTC. Results with no known publication date are kept. Set it only when the task needs sources from a time period; leave it unset otherwise."
487
+ },
488
+ published_before: {
489
+ type: "string",
490
+ description: "Optional. Only return results published before this date or date-time, in ISO 8601. A value with no time zone is read as UTC, and a date with no time includes that whole day. Results with no known publication date are kept. Set it only when the task needs sources from a time period; leave it unset otherwise."
480
491
  }
481
492
  },
482
493
  required: ["query"],
@@ -567,7 +578,14 @@ function createTelemVercelAgent(options) {
567
578
  const opts = { ...searchOptions ?? {}, signal: signalFor(execution, searchOptions?.signal) };
568
579
  const { envelope, plan } = await lineage(execution, {
569
580
  name: SEARCH_TOOL,
570
- input: { query, goal: opts.goal, context: opts.context, topic: opts.topic }
581
+ input: {
582
+ query,
583
+ goal: opts.goal,
584
+ context: opts.context,
585
+ topic: opts.topic,
586
+ published_after: opts.publishedAfter,
587
+ published_before: opts.publishedBefore
588
+ }
571
589
  });
572
590
  const response = await state.sendWithOmissionRetry(
573
591
  plan,
@@ -624,12 +642,18 @@ function createTelemVercelAgent(options) {
624
642
  }
625
643
  const tools = {
626
644
  telem_search: {
627
- description: "Search the public web. One query per call; returns the top results with provider, title, url and summary. Use telem_fetch to read a page in full.",
645
+ description: "Search the public web. One query per call; returns the top results with provider, title, url, summary and, when known, publication date. Use telem_fetch to read a page in full.",
628
646
  inputSchema: SEARCH_SCHEMA,
629
647
  execute: async (input, execution) => {
630
648
  const topic = input.topic?.trim() || void 0;
649
+ const publishedAfter = input.published_after?.trim() || void 0;
650
+ const publishedBefore = input.published_before?.trim() || void 0;
631
651
  return renderSearch(
632
- await search(input.query, { goal: input.goal, context: input.context, topic }, execution)
652
+ await search(
653
+ input.query,
654
+ { goal: input.goal, context: input.context, topic, publishedAfter, publishedBefore },
655
+ execution
656
+ )
633
657
  );
634
658
  }
635
659
  },
@@ -142,17 +142,21 @@ type TelemVercelSearchInput = {
142
142
  goal?: string;
143
143
  context?: string;
144
144
  topic?: string;
145
+ published_after?: string;
146
+ published_before?: string;
145
147
  };
146
148
  type TelemVercelFetchInput = {
147
149
  url: string;
148
150
  goal?: string;
149
151
  };
150
- /** The default `render.search`: the top results, compact. */
152
+ /** The default `render.search`: the top results, compact. `published` is there only
153
+ * when the result has a publication date. */
151
154
  type TelemVercelSearchOutput = Array<{
152
155
  provider: string;
153
156
  title: string;
154
157
  url: string;
155
158
  summary: string | null;
159
+ published?: string;
156
160
  }>;
157
161
  /** The default `render.fetch`: one page's status, error and text. */
158
162
  type TelemVercelFetchOutput = {
@@ -142,17 +142,21 @@ type TelemVercelSearchInput = {
142
142
  goal?: string;
143
143
  context?: string;
144
144
  topic?: string;
145
+ published_after?: string;
146
+ published_before?: string;
145
147
  };
146
148
  type TelemVercelFetchInput = {
147
149
  url: string;
148
150
  goal?: string;
149
151
  };
150
- /** The default `render.search`: the top results, compact. */
152
+ /** The default `render.search`: the top results, compact. `published` is there only
153
+ * when the result has a publication date. */
151
154
  type TelemVercelSearchOutput = Array<{
152
155
  provider: string;
153
156
  title: string;
154
157
  url: string;
155
158
  summary: string | null;
159
+ published?: string;
156
160
  }>;
157
161
  /** The default `render.fetch`: one page's status, error and text. */
158
162
  type TelemVercelFetchOutput = {
@@ -9,7 +9,7 @@ import {
9
9
  toolMarker,
10
10
  windowAnchor,
11
11
  withTrajectory
12
- } from "../chunk-RYY4S5LP.js";
12
+ } from "../chunk-DKTEG7EY.js";
13
13
 
14
14
  // src/vercel/index.ts
15
15
  import { jsonSchema } from "ai";
@@ -290,7 +290,10 @@ async function turnAnchor(messages, windowId) {
290
290
  return await contentAnchor(String(messages.length), windowId, text);
291
291
  }
292
292
  function compact(response) {
293
- return response.results.slice(0, RESULT_CAP).map(({ provider, title, url, summary }) => ({ provider, title, url, summary }));
293
+ return response.results.slice(0, RESULT_CAP).map(({ provider, title, url, summary, publishDate }) => {
294
+ const published = publishDate?.trim();
295
+ return published ? { provider, title, url, summary, published } : { provider, title, url, summary };
296
+ });
294
297
  }
295
298
  function page(response) {
296
299
  const first = response.results[0];
@@ -315,6 +318,14 @@ var SEARCH_SCHEMA = jsonSchema({
315
318
  topic: {
316
319
  type: "string",
317
320
  description: "Optional. Set it only when the answer must come from one site: linkedin, reddit, or x (twitter is also accepted). Leave it unset otherwise."
321
+ },
322
+ published_after: {
323
+ type: "string",
324
+ description: "Optional. Only return results published on or after this date or date-time, in ISO 8601 (for example 2026-10-01 or 2026-10-01T09:00:00Z). A value with no time zone is read as UTC. Results with no known publication date are kept. Set it only when the task needs sources from a time period; leave it unset otherwise."
325
+ },
326
+ published_before: {
327
+ type: "string",
328
+ description: "Optional. Only return results published before this date or date-time, in ISO 8601. A value with no time zone is read as UTC, and a date with no time includes that whole day. Results with no known publication date are kept. Set it only when the task needs sources from a time period; leave it unset otherwise."
318
329
  }
319
330
  },
320
331
  required: ["query"],
@@ -405,7 +416,14 @@ function createTelemVercelAgent(options) {
405
416
  const opts = { ...searchOptions ?? {}, signal: signalFor(execution, searchOptions?.signal) };
406
417
  const { envelope, plan } = await lineage(execution, {
407
418
  name: SEARCH_TOOL,
408
- input: { query, goal: opts.goal, context: opts.context, topic: opts.topic }
419
+ input: {
420
+ query,
421
+ goal: opts.goal,
422
+ context: opts.context,
423
+ topic: opts.topic,
424
+ published_after: opts.publishedAfter,
425
+ published_before: opts.publishedBefore
426
+ }
409
427
  });
410
428
  const response = await state.sendWithOmissionRetry(
411
429
  plan,
@@ -462,12 +480,18 @@ function createTelemVercelAgent(options) {
462
480
  }
463
481
  const tools = {
464
482
  telem_search: {
465
- description: "Search the public web. One query per call; returns the top results with provider, title, url and summary. Use telem_fetch to read a page in full.",
483
+ description: "Search the public web. One query per call; returns the top results with provider, title, url, summary and, when known, publication date. Use telem_fetch to read a page in full.",
466
484
  inputSchema: SEARCH_SCHEMA,
467
485
  execute: async (input, execution) => {
468
486
  const topic = input.topic?.trim() || void 0;
487
+ const publishedAfter = input.published_after?.trim() || void 0;
488
+ const publishedBefore = input.published_before?.trim() || void 0;
469
489
  return renderSearch(
470
- await search(input.query, { goal: input.goal, context: input.context, topic }, execution)
490
+ await search(
491
+ input.query,
492
+ { goal: input.goal, context: input.context, topic, publishedAfter, publishedBefore },
493
+ execution
494
+ )
471
495
  );
472
496
  }
473
497
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@telemai/sdk",
3
- "version": "0.2.3",
3
+ "version": "0.2.5",
4
4
  "description": "Telem web search and fetch for JavaScript and TypeScript.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",