@butlerbot/sdk 0.0.39 → 0.0.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -54,7 +54,7 @@ export declare class ButlerBotClient {
54
54
  cancelJob(config: OptionalApiKey<CancelJobOptions>): Promise<import("./types/type_registry").JobCancelResponse>;
55
55
  /** Continues a job parked waiting for budget. Throws a `ButlerBotAPIError` with `isConflict` when it is in any other status */
56
56
  resumeJob(config: OptionalApiKey<ResumeJobOptions>): Promise<import("./types/type_registry").JobResumeResponse>;
57
- /** Changes one job's name, and its autonomy: how far it may act, until when, and what it always asks about */
57
+ /** Changes one job's name, the model it runs on, its spending cap and its autonomy: how far it may act, until when, and what it always asks about */
58
58
  updateJob(config: OptionalApiKey<UpdateJobOptions>): Promise<import("./types/type_registry").JobUpdateResponse>;
59
59
  /** Changes the model one phase of a job's plan runs on; only a phase that has not started */
60
60
  setPhaseModel(config: OptionalApiKey<SetPhaseModelOptions>): Promise<import("./types/type_registry").JobPhaseModelResponse>;
package/dist/index.js CHANGED
@@ -92,7 +92,7 @@ class ButlerBotClient {
92
92
  resumeJob(config) {
93
93
  return (0, jobs_1.resumeJob)(this.forRequest(config));
94
94
  }
95
- /** Changes one job's name, and its autonomy: how far it may act, until when, and what it always asks about */
95
+ /** Changes one job's name, the model it runs on, its spending cap and its autonomy: how far it may act, until when, and what it always asks about */
96
96
  updateJob(config) {
97
97
  return (0, jobs_1.updateJob)(this.forRequest(config));
98
98
  }
@@ -43,6 +43,13 @@ export type UpdateJobOptions = JobsRequestOptions & {
43
43
  alwaysAsk?: string[];
44
44
  /** A ceiling on what the job may spend in all, in dollars. Null clears it. */
45
45
  capUsd?: number | null;
46
+ /**
47
+ * The model or alias the whole job runs on, and the plan's default.
48
+ *
49
+ * A name sets it; null clears it, leaving the planner to pick a model per phase. One
50
+ * phase's model on its own is `setPhaseModel`.
51
+ */
52
+ model?: string | null;
46
53
  };
47
54
  export type SetPhaseModelOptions = JobsRequestOptions & {
48
55
  jobId: string;
@@ -74,7 +81,7 @@ export declare function cancelJob(options: CancelJobOptions): Promise<JobCancelR
74
81
  * is true and whose `body` still carries the job as it stands.
75
82
  */
76
83
  export declare function resumeJob(options: ResumeJobOptions): Promise<JobResumeResponse>;
77
- /** Changes one job's name, and its autonomy: how far it may act, until when, and what it always asks about. */
84
+ /** Changes one job's name, the model it runs on, its spending cap and its autonomy: how far it may act, until when, and what it always asks about. */
78
85
  export declare function updateJob(options: UpdateJobOptions): Promise<JobUpdateResponse>;
79
86
  /**
80
87
  * Changes the model one phase of a job's plan runs on.
@@ -64,13 +64,13 @@ async function resumeJob(options) {
64
64
  const url = (0, url_formatter_1.formatURL)(`${jobsBase(options)}/${encodeURIComponent(options.jobId)}/resume`, {}, { apiKey: options.apiKey, debug: options.debug });
65
65
  return (0, api_request_1.requestAPI)({ url, method: "POST", action: `resume job ${options.jobId}` });
66
66
  }
67
- /** Changes one job's name, and its autonomy: how far it may act, until when, and what it always asks about. */
67
+ /** Changes one job's name, the model it runs on, its spending cap and its autonomy: how far it may act, until when, and what it always asks about. */
68
68
  async function updateJob(options) {
69
69
  const url = (0, url_formatter_1.formatURL)(`${jobsBase(options)}/${encodeURIComponent(options.jobId)}`, {}, { apiKey: options.apiKey, debug: options.debug });
70
70
  return (0, api_request_1.requestAPI)({
71
71
  url,
72
72
  method: "PATCH",
73
- body: body({ title: options.title, autonomy: options.autonomy, autonomyUntil: options.autonomyUntil, alwaysAsk: options.alwaysAsk, capUsd: options.capUsd }),
73
+ body: body({ title: options.title, autonomy: options.autonomy, autonomyUntil: options.autonomyUntil, alwaysAsk: options.alwaysAsk, capUsd: options.capUsd, model: options.model }),
74
74
  action: `update job ${options.jobId}`,
75
75
  });
76
76
  }
@@ -52,6 +52,13 @@ export type JobView = {
52
52
  journalCardUri: string | null;
53
53
  /** The chat the job was asked for in, and where it reports back. */
54
54
  originConversationId: string | null;
55
+ /**
56
+ * The model or alias the user asked the whole job to run on, and the plan's default.
57
+ *
58
+ * Null when nobody chose one, in which case the planner picks a model per phase. A phase's
59
+ * own `model` is what that phase actually runs on either way.
60
+ */
61
+ model: string | null;
55
62
  /** What was chosen for this job, or null when nothing was. */
56
63
  autonomy: JobAutonomy | null;
57
64
  /** When `autonomy` lapses back to asking, in UTC milliseconds. */
@@ -31,6 +31,14 @@ export type DeliverySurface = {
31
31
  export declare const DELIVERY_ANSWER_VIA: readonly ["web", "discord", "chat", "tool"];
32
32
  /** Which surface the answer came back on. */
33
33
  export type DeliveryAnsweredVia = typeof DELIVERY_ANSWER_VIA[number];
34
+ export declare const DELIVERY_CLOSED_REASONS: readonly ["job_done", "job_failed", "job_cancelled"];
35
+ /** Why a delivery was closed with nobody having answered it: what became of the job that asked. */
36
+ export type DeliveryClosedReason = typeof DELIVERY_CLOSED_REASONS[number];
37
+ /** A delivery closed unanswered, and when. */
38
+ export type DeliveryClosed = {
39
+ at: number;
40
+ reason: DeliveryClosedReason;
41
+ };
34
42
  export type DeliveryAnswer = {
35
43
  at: number;
36
44
  text: string;
@@ -54,9 +62,16 @@ export type Delivery = {
54
62
  surfaces: DeliverySurface[];
55
63
  /** Null until somebody answers. Only ever set once. */
56
64
  answered: DeliveryAnswer | null;
65
+ /**
66
+ * Set when the job this belonged to ended before anyone answered, and null otherwise.
67
+ *
68
+ * A closed delivery is no longer open, and answering it is refused: the server answers a
69
+ * 409 the same way it does one already answered.
70
+ */
71
+ closed: DeliveryClosed | null;
57
72
  created: number;
58
73
  };
59
- /** Whether a delivery is still waiting on the user. */
74
+ /** Whether a delivery is still waiting on the user: unanswered, and not closed under it. */
60
75
  export declare function isDeliveryOpen(delivery: Delivery): boolean;
61
76
  export type DeliveryListResponse = {
62
77
  success: true;
@@ -7,7 +7,7 @@
7
7
  * on that job's inbox.
8
8
  */
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.DELIVERY_ANSWER_VIA = exports.DELIVERY_SURFACE_STATUSES = exports.DELIVERY_SURFACES = exports.ANSWERABLE_DELIVERY_INTENTS = exports.DELIVERY_INTENTS = void 0;
10
+ exports.DELIVERY_CLOSED_REASONS = exports.DELIVERY_ANSWER_VIA = exports.DELIVERY_SURFACE_STATUSES = exports.DELIVERY_SURFACES = exports.ANSWERABLE_DELIVERY_INTENTS = exports.DELIVERY_INTENTS = void 0;
11
11
  exports.isDeliveryOpen = isDeliveryOpen;
12
12
  exports.DELIVERY_INTENTS = ["question", "update", "approval", "statement"];
13
13
  /** The intents that leave something outstanding until the user answers. */
@@ -15,7 +15,8 @@ exports.ANSWERABLE_DELIVERY_INTENTS = ["question", "approval"];
15
15
  exports.DELIVERY_SURFACES = ["web", "discord"];
16
16
  exports.DELIVERY_SURFACE_STATUSES = ["pending", "sent", "failed"];
17
17
  exports.DELIVERY_ANSWER_VIA = ["web", "discord", "chat", "tool"];
18
- /** Whether a delivery is still waiting on the user. */
18
+ exports.DELIVERY_CLOSED_REASONS = ["job_done", "job_failed", "job_cancelled"];
19
+ /** Whether a delivery is still waiting on the user: unanswered, and not closed under it. */
19
20
  function isDeliveryOpen(delivery) {
20
- return exports.ANSWERABLE_DELIVERY_INTENTS.includes(delivery.intent) && !delivery.answered;
21
+ return exports.ANSWERABLE_DELIVERY_INTENTS.includes(delivery.intent) && !delivery.answered && !delivery.closed;
21
22
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@butlerbot/sdk",
3
- "version": "0.0.39",
3
+ "version": "0.0.40",
4
4
  "description": "The official ButlerBot SDK",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
package/readme.md CHANGED
@@ -342,8 +342,11 @@ const { resumed, reason, action, message } = await client.resumeJob({ jobId });
342
342
  newest page first, with each page in the order its entries were written and `hasMore` saying whether
343
343
  an older page exists. Each entry says which shift wrote it (`shiftIndex`, `shiftKind`) and on which
344
344
  model. A job's `title` is a few words of its own, set at start or renamed with `updateJob`, which
345
- also takes `capUsd`, a ceiling on what the job may spend in all (null clears it). `setPhaseModel`
346
- changes the model a phase that has not started runs on, to one of the detail's `phaseModels`.
345
+ also takes `capUsd`, a ceiling on what the job may spend in all (null clears it), and `model`, the
346
+ model or alias the whole job runs on and the plan's default — a name sets it, null clears it and
347
+ leaves the planner to pick per phase, and a job's own `model` reads back the same way.
348
+ `setPhaseModel` changes the model one phase that has not started runs on, to one of the detail's
349
+ `phaseModels`.
347
350
  `resumeJob` continues a job parked as `waiting_budget` when there is room for it again: it answers
348
351
  with `resumed`, a `reason` of `resumed`, `over_tier_limit`, `allowance_spent` or `refused`, an
349
352
  `action` of `raise_allowance`, `upgrade_tier` or `wait` when there is one, a `wakeAt` when the job
@@ -378,6 +381,10 @@ Answering closes the delivery, and when it belongs to a job the answer is put on
378
381
  inbox, which wakes a job that was parked waiting for it — `job.delivered` says what became of
379
382
  it. An approval takes `decision: "approve" | "deny"` alongside the text.
380
383
 
384
+ A delivery whose job ended before anyone answered is closed instead: `closed` carries the time
385
+ and a reason of `job_done`, `job_failed` or `job_cancelled`. `isDeliveryOpen` reads false for
386
+ one, and answering it is refused with a 409 just as one already answered is.
387
+
381
388
  ### When a call fails
382
389
 
383
390
  Every jobs and outreach call throws `ButlerBotAPIError` when the server does not answer with a