@palai/sdk 0.1.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/CHANGELOG.md +65 -0
- package/LICENSE +201 -0
- package/README.md +160 -0
- package/dist/client.d.ts +94 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +296 -0
- package/dist/client.js.map +1 -0
- package/dist/errors.d.ts +40 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +143 -0
- package/dist/errors.js.map +1 -0
- package/dist/generated/tools.d.ts +39 -0
- package/dist/generated/tools.d.ts.map +1 -0
- package/dist/generated/tools.js +44 -0
- package/dist/generated/tools.js.map +1 -0
- package/dist/generated/types.d.ts +341 -0
- package/dist/generated/types.d.ts.map +1 -0
- package/dist/generated/types.js +7 -0
- package/dist/generated/types.js.map +1 -0
- package/dist/index.browser.d.ts +3 -0
- package/dist/index.browser.d.ts.map +1 -0
- package/dist/index.browser.js +6 -0
- package/dist/index.browser.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +25 -0
- package/dist/index.js.map +1 -0
- package/dist/orchestrator.d.ts +61 -0
- package/dist/orchestrator.d.ts.map +1 -0
- package/dist/orchestrator.js +159 -0
- package/dist/orchestrator.js.map +1 -0
- package/dist/resources/agents.d.ts +67 -0
- package/dist/resources/agents.d.ts.map +1 -0
- package/dist/resources/agents.js +75 -0
- package/dist/resources/agents.js.map +1 -0
- package/dist/resources/approvals.d.ts +33 -0
- package/dist/resources/approvals.d.ts.map +1 -0
- package/dist/resources/approvals.js +33 -0
- package/dist/resources/approvals.js.map +1 -0
- package/dist/resources/artifacts.d.ts +36 -0
- package/dist/resources/artifacts.d.ts.map +1 -0
- package/dist/resources/artifacts.js +70 -0
- package/dist/resources/artifacts.js.map +1 -0
- package/dist/resources/model-routes.d.ts +70 -0
- package/dist/resources/model-routes.d.ts.map +1 -0
- package/dist/resources/model-routes.js +74 -0
- package/dist/resources/model-routes.js.map +1 -0
- package/dist/resources/reads.d.ts +49 -0
- package/dist/resources/reads.d.ts.map +1 -0
- package/dist/resources/reads.js +91 -0
- package/dist/resources/reads.js.map +1 -0
- package/dist/resources/responses.d.ts +70 -0
- package/dist/resources/responses.d.ts.map +1 -0
- package/dist/resources/responses.js +147 -0
- package/dist/resources/responses.js.map +1 -0
- package/dist/resources/secret-refs.d.ts +24 -0
- package/dist/resources/secret-refs.d.ts.map +1 -0
- package/dist/resources/secret-refs.js +33 -0
- package/dist/resources/secret-refs.js.map +1 -0
- package/dist/resources/sessions.d.ts +106 -0
- package/dist/resources/sessions.d.ts.map +1 -0
- package/dist/resources/sessions.js +161 -0
- package/dist/resources/sessions.js.map +1 -0
- package/dist/resources/shared.d.ts +31 -0
- package/dist/resources/shared.d.ts.map +1 -0
- package/dist/resources/shared.js +32 -0
- package/dist/resources/shared.js.map +1 -0
- package/dist/resources/skills.d.ts +40 -0
- package/dist/resources/skills.d.ts.map +1 -0
- package/dist/resources/skills.js +40 -0
- package/dist/resources/skills.js.map +1 -0
- package/dist/schema.d.ts +35 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +30 -0
- package/dist/schema.js.map +1 -0
- package/dist/server-only.d.ts +2 -0
- package/dist/server-only.d.ts.map +1 -0
- package/dist/server-only.js +22 -0
- package/dist/server-only.js.map +1 -0
- package/dist/stream.d.ts +38 -0
- package/dist/stream.d.ts.map +1 -0
- package/dist/stream.js +314 -0
- package/dist/stream.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { Command, Session } from "../generated/types.ts";
|
|
2
|
+
import type { Palai } from "../client.ts";
|
|
3
|
+
import { type CallOptions, type ListParams, type Page } from "./shared.ts";
|
|
4
|
+
export interface SteerParams {
|
|
5
|
+
message: string;
|
|
6
|
+
commandId?: string;
|
|
7
|
+
}
|
|
8
|
+
export type InterruptParams = SteerParams;
|
|
9
|
+
export interface SessionCreateParams {
|
|
10
|
+
name?: string;
|
|
11
|
+
/**
|
|
12
|
+
* The session's DEFAULT agent pin. Every run in this session inherits it and resolves it to that
|
|
13
|
+
* agent's currently PUBLISHED revision — so updating the agent reaches the next message. A run that
|
|
14
|
+
* names its own agent overrides it for that run.
|
|
15
|
+
*
|
|
16
|
+
* Accepts what defineAgent returned or a bare profile id, because a caller holding the first should
|
|
17
|
+
* not have to reach into it for the second. The object form is deliberately open — a PublishedAgent
|
|
18
|
+
* carries more than an id, and excess-property checking would reject the very value defineAgent hands
|
|
19
|
+
* back, which is the one this field exists to take.
|
|
20
|
+
*/
|
|
21
|
+
agent?: {
|
|
22
|
+
id: string;
|
|
23
|
+
[key: string]: unknown;
|
|
24
|
+
} | string;
|
|
25
|
+
/**
|
|
26
|
+
* WHAT THIS SESSION RUNS ON. The model is chosen HERE — when the conversation starts — not when the
|
|
27
|
+
* agent was defined: an agent is an identity and a behaviour, and freezing a model into one would make
|
|
28
|
+
* "run this agent on a different model" mean "define a second agent". A single run may still name its
|
|
29
|
+
* own `model` for that one turn.
|
|
30
|
+
*/
|
|
31
|
+
model?: string;
|
|
32
|
+
/**
|
|
33
|
+
* How hard the model thinks for this session, on the canonical ladder. A separate axis from `model`:
|
|
34
|
+
* keep the model and raise the effort, or the other way round.
|
|
35
|
+
*
|
|
36
|
+
* Which rungs a given model accepts is the PROVIDER's answer — Anthropic's ladder has no `none` or
|
|
37
|
+
* `minimal` — and the plane refuses a rung the routed model cannot express rather than quietly
|
|
38
|
+
* substituting a more expensive one.
|
|
39
|
+
*/
|
|
40
|
+
effort?: Effort;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The canonical reasoning-effort ladder, ascending — as an OPEN set.
|
|
44
|
+
*
|
|
45
|
+
* ‼️ `(string & {})` IS NOT NOISE. It keeps the named rungs in autocomplete while letting an
|
|
46
|
+
* unknown one through, and the reason is measured: this ladder is not fixed. Anthropic's own rungs
|
|
47
|
+
* differ per model (`xhigh` arrived with Opus 4.7; Opus 4.5 accepts only low/medium/high), and its
|
|
48
|
+
* API declares `stop_details.category` "an open set" for the same reason. A closed union would make
|
|
49
|
+
* the server adding an eighth rung a COMPILE ERROR in every application already using this SDK —
|
|
50
|
+
* the one failure mode an SDK must never have.
|
|
51
|
+
*/
|
|
52
|
+
export type Effort = "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max" | (string & {});
|
|
53
|
+
/**
|
|
54
|
+
* SessionConfigParams changes what the REST of a session runs on.
|
|
55
|
+
*
|
|
56
|
+
* ‼️ EACH HALF IS INDEPENDENTLY OPTIONAL, AND THAT IS THE WHOLE SHAPE. Omitting a field leaves it exactly
|
|
57
|
+
* as it was — so raising the effort cannot silently reset the model — while passing an EMPTY STRING is a
|
|
58
|
+
* real value that CLEARS that choice and returns the decision to the layers below (the agent revision,
|
|
59
|
+
* then the project's published model route).
|
|
60
|
+
*
|
|
61
|
+
* CHANGING EITHER NEVER INTERRUPTS A RUN IN FLIGHT. A run resolves its configuration at each model-step
|
|
62
|
+
* boundary, so a change made while the model is answering takes effect at the next step of that same turn,
|
|
63
|
+
* or at the next turn when the current one has no further step. Nothing is cancelled and no partial answer
|
|
64
|
+
* is discarded.
|
|
65
|
+
*/
|
|
66
|
+
export interface SessionConfigParams {
|
|
67
|
+
model?: string;
|
|
68
|
+
effort?: Effort | "";
|
|
69
|
+
}
|
|
70
|
+
export declare class SessionCommands {
|
|
71
|
+
#private;
|
|
72
|
+
constructor(client: Palai);
|
|
73
|
+
steer(sessionID: string, params: SteerParams, options?: CallOptions): Promise<Command>;
|
|
74
|
+
interrupt(sessionID: string, params: InterruptParams, options?: CallOptions): Promise<Command>;
|
|
75
|
+
}
|
|
76
|
+
export declare class Sessions {
|
|
77
|
+
#private;
|
|
78
|
+
readonly commands: SessionCommands;
|
|
79
|
+
constructor(client: Palai);
|
|
80
|
+
create(params?: SessionCreateParams, options?: CallOptions): Promise<Session>;
|
|
81
|
+
/**
|
|
82
|
+
* configure changes the model and/or the reasoning effort for the REST of this session, and returns the
|
|
83
|
+
* re-read session so the caller sees what is now in effect rather than what they asked for.
|
|
84
|
+
*
|
|
85
|
+
* ‼️ IT DOES NOT INTERRUPT A RUN IN FLIGHT. A run resolves its configuration at each model-step boundary,
|
|
86
|
+
* so a change made while the model is answering lands at the next step of that same turn — or at the
|
|
87
|
+
* next turn if the current one has no further step. The answer being produced is never discarded.
|
|
88
|
+
*
|
|
89
|
+
* Omitting a field leaves it alone; passing an empty string CLEARS it and returns that decision to the
|
|
90
|
+
* layers below. Reading it back is `retrieve`, which renders both unconditionally, so a caller never has
|
|
91
|
+
* to keep its own copy of what the session is running on.
|
|
92
|
+
*
|
|
93
|
+
* await palai.sessions.configure(id, { model: "claude-sonnet-5" }); // keep the effort
|
|
94
|
+
* await palai.sessions.configure(id, { effort: "xhigh" }); // keep the model
|
|
95
|
+
* await palai.sessions.configure(id, { effort: "" }); // back to the layers below
|
|
96
|
+
*/
|
|
97
|
+
configure(sessionID: string, params: SessionConfigParams, options?: CallOptions): Promise<Session>;
|
|
98
|
+
rename(sessionID: string, name: string, options?: CallOptions): Promise<Session>;
|
|
99
|
+
setAutoApprove(sessionID: string, params: {
|
|
100
|
+
tools?: boolean;
|
|
101
|
+
publications?: boolean;
|
|
102
|
+
}, options?: CallOptions): Promise<Session>;
|
|
103
|
+
retrieve(sessionID: string, options?: CallOptions): Promise<Session>;
|
|
104
|
+
list(params?: ListParams, options?: CallOptions): Promise<Page<Session>>;
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=sessions.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/resources/sessions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAwB,OAAO,EAAE,MAAM,uBAAuB,CAAC;AACpF,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAA2B,KAAK,WAAW,EAAE,KAAK,UAAU,EAAE,KAAK,IAAI,EAAE,MAAM,aAAa,CAAC;AAMpG,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AACD,MAAM,MAAM,eAAe,GAAG,WAAW,CAAC;AAI1C,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;;;;;;;;OASG;IACH,KAAK,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;KAAE,GAAG,MAAM,CAAC;IACxD;;;;;OAKG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;GASG;AACH,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC;AAEtG;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,mBAAmB;IAClC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,GAAG,EAAE,CAAC;CACtB;AAMD,qBAAa,eAAe;;IAE1B,YAAY,MAAM,EAAE,KAAK,EAExB;IAKD,KAAK,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAEzF;IAID,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,eAAe,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAEjG;CAiBF;AAGD,qBAAa,QAAQ;;IAEnB,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IAEnC,YAAY,MAAM,EAAE,KAAK,EAGxB;IAKK,MAAM,CAAC,MAAM,GAAE,mBAAwB,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAwB1F;IAED;;;;;;;;;;;;;;;OAeG;IACG,SAAS,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,mBAAmB,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAmB3G;IASK,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAUzF;IAaK,cAAc,CAClB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,YAAY,CAAC,EAAE,OAAO,CAAA;KAAE,EACnD,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,OAAO,CAAC,CAWlB;IAIK,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,OAAO,CAAC,CAG7E;IAGK,IAAI,CAAC,MAAM,GAAE,UAAe,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAGrF;CACF"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
2
|
+
import { callArgs, enc, listPath } from "./shared.js";
|
|
3
|
+
// SessionCommands is the durable command surface of a session (spec §9.2, §22.4) — E08's steering
|
|
4
|
+
// product, used from the SDK for the first time. steer and interrupt are both send_message
|
|
5
|
+
// deliveries; the delivery mode is the only difference (queue is the default fire path and not
|
|
6
|
+
// exposed here — the plan asks for steer + interrupt).
|
|
7
|
+
export class SessionCommands {
|
|
8
|
+
#client;
|
|
9
|
+
constructor(client) {
|
|
10
|
+
this.#client = client;
|
|
11
|
+
}
|
|
12
|
+
// steer delivers a message at the next safe boundary WITHOUT interrupting the current step
|
|
13
|
+
// (delivery=steer). Acceptance is durable-queued (202), not applied; the returned Command is the
|
|
14
|
+
// queued handle, or — on a duplicate command_id — the original unchanged (idempotent).
|
|
15
|
+
steer(sessionID, params, options = {}) {
|
|
16
|
+
return this.#send(sessionID, "steer", params, options);
|
|
17
|
+
}
|
|
18
|
+
// interrupt delivers a message that preempts the current step (delivery=interrupt). Same durable,
|
|
19
|
+
// idempotent acceptance as steer.
|
|
20
|
+
interrupt(sessionID, params, options = {}) {
|
|
21
|
+
return this.#send(sessionID, "interrupt", params, options);
|
|
22
|
+
}
|
|
23
|
+
async #send(sessionID, delivery, params, options) {
|
|
24
|
+
const body = {
|
|
25
|
+
command_id: params.commandId ?? newCommandId(),
|
|
26
|
+
kind: "send_message",
|
|
27
|
+
delivery,
|
|
28
|
+
message: params.message,
|
|
29
|
+
};
|
|
30
|
+
const result = await this.#client.request("POST", `/v1/sessions/${enc(sessionID)}/commands`, {
|
|
31
|
+
body,
|
|
32
|
+
// command_id carries idempotency server-side, so a network re-send settles exactly one command.
|
|
33
|
+
idempotent: true,
|
|
34
|
+
...callArgs(options),
|
|
35
|
+
});
|
|
36
|
+
return result.body;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Sessions is the /v1/sessions resource: create, retrieve, list, and the durable command surface.
|
|
40
|
+
export class Sessions {
|
|
41
|
+
#client;
|
|
42
|
+
commands;
|
|
43
|
+
constructor(client) {
|
|
44
|
+
this.#client = client;
|
|
45
|
+
this.commands = new SessionCommands(client);
|
|
46
|
+
}
|
|
47
|
+
// create opens a standalone session (201). Creation is cheap and unkeyed — a retried create mints
|
|
48
|
+
// a new session — so it carries no idempotency key. `name` is the optional display label; without
|
|
49
|
+
// one the session's projection derives a label from its first prompt (see `rename`).
|
|
50
|
+
async create(params = {}, options = {}) {
|
|
51
|
+
const { agent, name, model, effort } = params;
|
|
52
|
+
const body = {};
|
|
53
|
+
if (name !== undefined) {
|
|
54
|
+
body.name = name;
|
|
55
|
+
}
|
|
56
|
+
if (agent !== undefined) {
|
|
57
|
+
body.agent_id = typeof agent === "string" ? agent : agent.id;
|
|
58
|
+
}
|
|
59
|
+
if (model !== undefined) {
|
|
60
|
+
body.model = model;
|
|
61
|
+
}
|
|
62
|
+
if (effort !== undefined) {
|
|
63
|
+
body.effort = effort;
|
|
64
|
+
}
|
|
65
|
+
const args = callArgs(options);
|
|
66
|
+
// A create with NOTHING to say still sends no body — the pre-existing bodyless call, unchanged, so a
|
|
67
|
+
// caller who passed no params keeps the exact request they had.
|
|
68
|
+
const result = await this.#client.request("POST", "/v1/sessions", Object.keys(body).length === 0 ? args : { body, ...args });
|
|
69
|
+
return result.body;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* configure changes the model and/or the reasoning effort for the REST of this session, and returns the
|
|
73
|
+
* re-read session so the caller sees what is now in effect rather than what they asked for.
|
|
74
|
+
*
|
|
75
|
+
* ‼️ IT DOES NOT INTERRUPT A RUN IN FLIGHT. A run resolves its configuration at each model-step boundary,
|
|
76
|
+
* so a change made while the model is answering lands at the next step of that same turn — or at the
|
|
77
|
+
* next turn if the current one has no further step. The answer being produced is never discarded.
|
|
78
|
+
*
|
|
79
|
+
* Omitting a field leaves it alone; passing an empty string CLEARS it and returns that decision to the
|
|
80
|
+
* layers below. Reading it back is `retrieve`, which renders both unconditionally, so a caller never has
|
|
81
|
+
* to keep its own copy of what the session is running on.
|
|
82
|
+
*
|
|
83
|
+
* await palai.sessions.configure(id, { model: "claude-sonnet-5" }); // keep the effort
|
|
84
|
+
* await palai.sessions.configure(id, { effort: "xhigh" }); // keep the model
|
|
85
|
+
* await palai.sessions.configure(id, { effort: "" }); // back to the layers below
|
|
86
|
+
*/
|
|
87
|
+
async configure(sessionID, params, options = {}) {
|
|
88
|
+
const body = {};
|
|
89
|
+
if (params.model !== undefined) {
|
|
90
|
+
body.model = params.model;
|
|
91
|
+
}
|
|
92
|
+
if (params.effort !== undefined) {
|
|
93
|
+
body.effort = params.effort;
|
|
94
|
+
}
|
|
95
|
+
if (Object.keys(body).length === 0) {
|
|
96
|
+
// A PATCH that names neither would be refused by the plane as a request that lost its field, and a
|
|
97
|
+
// 400 for a call the caller could not have meant is worse than a local complaint.
|
|
98
|
+
throw new TypeError("sessions.configure requires at least one of `model` or `effort`");
|
|
99
|
+
}
|
|
100
|
+
const result = await this.#client.request("PATCH", `/v1/sessions/${enc(sessionID)}`, { body, ...callArgs(options) });
|
|
101
|
+
return result.body;
|
|
102
|
+
}
|
|
103
|
+
// rename sets a session's display label and returns the re-read session, so the caller sees both
|
|
104
|
+
// the label and the `name_source` that now reads "operator".
|
|
105
|
+
//
|
|
106
|
+
// This, and not the create-time name, is the call a session list needs: most sessions are never
|
|
107
|
+
// created through `create` at all — posting a response opens one implicitly — so they reach a list
|
|
108
|
+
// screen with no label to have been given one. Passing an EMPTY string is meaningful: it clears the
|
|
109
|
+
// operator label and returns the row to its derived one.
|
|
110
|
+
async rename(sessionID, name, options = {}) {
|
|
111
|
+
const result = await this.#client.request("PATCH", `/v1/sessions/${enc(sessionID)}`, {
|
|
112
|
+
body: { name },
|
|
113
|
+
// Setting a label to X twice leaves it X, so a connection torn after the server committed is
|
|
114
|
+
// safe to re-send. That is a property of THIS call, not of PATCH, which is why it is declared
|
|
115
|
+
// here rather than in the transport's method table.
|
|
116
|
+
idempotent: true,
|
|
117
|
+
...callArgs(options),
|
|
118
|
+
});
|
|
119
|
+
return result.body;
|
|
120
|
+
}
|
|
121
|
+
// setAutoApprove arms (or disarms) this session's STANDING authorization, and returns the re-read
|
|
122
|
+
// session so the caller sees `auto_approve_set_by` — the principal the server stamped from the verified
|
|
123
|
+
// key, which is who every auto-decision will be recorded AS.
|
|
124
|
+
//
|
|
125
|
+
// ‼️ IT ANSWERS APPROVALS, IT DOES NOT SKIP THEM. The control plane still writes the approval row and
|
|
126
|
+
// still decides it through the same throat a human's POST uses, so the approvals list still shows what
|
|
127
|
+
// ran and the approver policy still applies. Armed or not, `approvals.list()` is the record.
|
|
128
|
+
//
|
|
129
|
+
// TWO FLAGS AND NEVER ONE. A gated TOOL call lands in the run's own workspace while a human watches; a
|
|
130
|
+
// PUBLICATION writes to somebody's repository and outlives the session. Omitting a field leaves it as it
|
|
131
|
+
// was, so arming tools does not quietly arm publications.
|
|
132
|
+
async setAutoApprove(sessionID, params, options = {}) {
|
|
133
|
+
const body = {};
|
|
134
|
+
if (params.tools !== undefined)
|
|
135
|
+
body.auto_approve_tools = params.tools;
|
|
136
|
+
if (params.publications !== undefined)
|
|
137
|
+
body.auto_approve_publications = params.publications;
|
|
138
|
+
const result = await this.#client.request("PATCH", `/v1/sessions/${enc(sessionID)}`, {
|
|
139
|
+
body,
|
|
140
|
+
// Setting a standing flag to X twice leaves it X.
|
|
141
|
+
idempotent: true,
|
|
142
|
+
...callArgs(options),
|
|
143
|
+
});
|
|
144
|
+
return result.body;
|
|
145
|
+
}
|
|
146
|
+
// retrieve reads a session within the verified scope; an unknown or foreign id is a 404
|
|
147
|
+
// (NotFoundError).
|
|
148
|
+
async retrieve(sessionID, options = {}) {
|
|
149
|
+
const result = await this.#client.request("GET", `/v1/sessions/${enc(sessionID)}`, callArgs(options));
|
|
150
|
+
return result.body;
|
|
151
|
+
}
|
|
152
|
+
// list returns a tenant-scoped page of sessions with the shared cursor + basic filters.
|
|
153
|
+
async list(params = {}, options = {}) {
|
|
154
|
+
const result = await this.#client.request("GET", listPath("/v1/sessions", params), callArgs(options));
|
|
155
|
+
return result.body;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function newCommandId() {
|
|
159
|
+
return `cmd_${randomUUID()}`;
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=sessions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../../src/resources/sessions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { RequestOptions } from "../client.ts";
|
|
2
|
+
export interface CallOptions {
|
|
3
|
+
signal?: AbortSignal | undefined;
|
|
4
|
+
timeoutMs?: number;
|
|
5
|
+
maxRetries?: number;
|
|
6
|
+
}
|
|
7
|
+
export interface DownloadOptions {
|
|
8
|
+
signal?: AbortSignal | undefined;
|
|
9
|
+
timeoutMs?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface ListParams {
|
|
12
|
+
after?: string;
|
|
13
|
+
limit?: number;
|
|
14
|
+
status?: string;
|
|
15
|
+
createdAfter?: string;
|
|
16
|
+
createdBefore?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface Page<T> {
|
|
19
|
+
data: T[];
|
|
20
|
+
has_more: boolean;
|
|
21
|
+
next_cursor?: string | null;
|
|
22
|
+
previous_cursor?: string | null;
|
|
23
|
+
}
|
|
24
|
+
export interface ListView<T> {
|
|
25
|
+
object: string;
|
|
26
|
+
data: T[];
|
|
27
|
+
}
|
|
28
|
+
export declare function callArgs(options?: CallOptions): RequestOptions;
|
|
29
|
+
export declare function listPath(path: string, params?: ListParams): string;
|
|
30
|
+
export declare function enc(segment: string): string;
|
|
31
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/resources/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AASnD,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD,MAAM,WAAW,eAAe;IAC9B,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAOD,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAKD,MAAM,WAAW,IAAI,CAAC,CAAC;IACrB,IAAI,EAAE,CAAC,EAAE,CAAC;IACV,QAAQ,EAAE,OAAO,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CACjC;AAID,MAAM,WAAW,QAAQ,CAAC,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,CAAC,EAAE,CAAC;CACX;AAID,wBAAgB,QAAQ,CAAC,OAAO,GAAE,WAAgB,GAAG,cAAc,CAKlE;AAID,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,UAAe,GAAG,MAAM,CAStE;AAGD,wBAAgB,GAAG,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAE3C"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
// callArgs projects CallOptions onto the client's RequestOptions, dropping absent numeric fields so
|
|
2
|
+
// exactOptionalPropertyTypes stays satisfied (a bare `timeoutMs: undefined` is not assignable).
|
|
3
|
+
export function callArgs(options = {}) {
|
|
4
|
+
const out = { signal: options.signal };
|
|
5
|
+
if (options.timeoutMs !== undefined)
|
|
6
|
+
out.timeoutMs = options.timeoutMs;
|
|
7
|
+
if (options.maxRetries !== undefined)
|
|
8
|
+
out.maxRetries = options.maxRetries;
|
|
9
|
+
return out;
|
|
10
|
+
}
|
|
11
|
+
// listPath appends the shared list query to a path. Absent params add no key, so a bare list() sends
|
|
12
|
+
// a clean path; a present param is URL-encoded by URLSearchParams.
|
|
13
|
+
export function listPath(path, params = {}) {
|
|
14
|
+
const query = new URLSearchParams();
|
|
15
|
+
if (params.after !== undefined)
|
|
16
|
+
query.set("after", params.after);
|
|
17
|
+
if (params.limit !== undefined)
|
|
18
|
+
query.set("limit", String(params.limit));
|
|
19
|
+
if (params.status !== undefined)
|
|
20
|
+
query.set("status", params.status);
|
|
21
|
+
if (params.createdAfter !== undefined)
|
|
22
|
+
query.set("created_after", params.createdAfter);
|
|
23
|
+
if (params.createdBefore !== undefined)
|
|
24
|
+
query.set("created_before", params.createdBefore);
|
|
25
|
+
const qs = query.toString();
|
|
26
|
+
return qs === "" ? path : `${path}?${qs}`;
|
|
27
|
+
}
|
|
28
|
+
// enc is the path-segment encoder every resource uses for ids (matches responses.ts).
|
|
29
|
+
export function enc(segment) {
|
|
30
|
+
return encodeURIComponent(segment);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/resources/shared.ts"],"names":[],"mappings":"AAsDA,oGAAoG;AACpG,gGAAgG;AAChG,MAAM,UAAU,QAAQ,CAAC,OAAO,GAAgB,EAAE;IAChD,MAAM,GAAG,GAAmB,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC;IACvD,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS;QAAE,GAAG,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC;IACvE,IAAI,OAAO,CAAC,UAAU,KAAK,SAAS;QAAE,GAAG,CAAC,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC;IAC1E,OAAO,GAAG,CAAC;AACb,CAAC;AAED,qGAAqG;AACrG,mEAAmE;AACnE,MAAM,UAAU,QAAQ,CAAC,IAAY,EAAE,MAAM,GAAe,EAAE;IAC5D,MAAM,KAAK,GAAG,IAAI,eAAe,EAAE,CAAC;IACpC,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IACjE,IAAI,MAAM,CAAC,KAAK,KAAK,SAAS;QAAE,KAAK,CAAC,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;IACzE,IAAI,MAAM,CAAC,MAAM,KAAK,SAAS;QAAE,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;IACpE,IAAI,MAAM,CAAC,YAAY,KAAK,SAAS;QAAE,KAAK,CAAC,GAAG,CAAC,eAAe,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC;IACvF,IAAI,MAAM,CAAC,aAAa,KAAK,SAAS;QAAE,KAAK,CAAC,GAAG,CAAC,gBAAgB,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;IAC1F,MAAM,EAAE,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;IAC5B,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,IAAI,EAAE,EAAE,CAAC;AAC5C,CAAC;AAED,sFAAsF;AACtF,MAAM,UAAU,GAAG,CAAC,OAAe;IACjC,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAC;AACrC,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { Palai } from "../client.ts";
|
|
2
|
+
import { type CallOptions, type ListView } from "./shared.ts";
|
|
3
|
+
export interface Skill {
|
|
4
|
+
id: string;
|
|
5
|
+
object: string;
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
}
|
|
8
|
+
export interface SkillRevision {
|
|
9
|
+
id: string;
|
|
10
|
+
object: string;
|
|
11
|
+
/** quarantined | approved | enabled. A revision is not runnable until it is enabled. */
|
|
12
|
+
state?: string;
|
|
13
|
+
/** sha256 over the sanitized archive — what a run PINS, never "latest". */
|
|
14
|
+
digest?: string;
|
|
15
|
+
/** Static-scan hits keeping a revision quarantined: the rule and the path, never a captured value. */
|
|
16
|
+
scan_findings?: Array<{
|
|
17
|
+
kind?: string;
|
|
18
|
+
path?: string;
|
|
19
|
+
rule?: string;
|
|
20
|
+
}>;
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
export interface SkillRevisionInstallParams {
|
|
24
|
+
/** Base64 of the skill archive. */
|
|
25
|
+
archive?: string;
|
|
26
|
+
/** A URL the control plane fetches. Vetted server-side; a private or loopback target is refused. */
|
|
27
|
+
source_url?: string;
|
|
28
|
+
[key: string]: unknown;
|
|
29
|
+
}
|
|
30
|
+
export declare class Skills {
|
|
31
|
+
#private;
|
|
32
|
+
constructor(client: Palai);
|
|
33
|
+
create(params: {
|
|
34
|
+
name: string;
|
|
35
|
+
}, options?: CallOptions): Promise<Skill>;
|
|
36
|
+
installRevision(skillID: string, params: SkillRevisionInstallParams, options?: CallOptions): Promise<SkillRevision>;
|
|
37
|
+
enable(skillID: string, revisionID: string, options?: CallOptions): Promise<SkillRevision>;
|
|
38
|
+
list(options?: CallOptions): Promise<ListView<Skill>>;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=skills.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/resources/skills.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAiB,KAAK,WAAW,EAAE,KAAK,QAAQ,EAAE,MAAM,aAAa,CAAC;AAK7E,MAAM,WAAW,KAAK;IACpB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,MAAM,CAAC;IACf,wFAAwF;IACxF,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,2EAA2E;IAC3E,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,sGAAsG;IACtG,aAAa,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvE,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAKD,MAAM,WAAW,0BAA0B;IACzC,mCAAmC;IACnC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oGAAoG;IACpG,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAUD,qBAAa,MAAM;;IAEjB,YAAY,MAAM,EAAE,KAAK,EAExB;IAIK,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,KAAK,CAAC,CAGhF;IAKK,eAAe,CACnB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,0BAA0B,EAClC,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,aAAa,CAAC,CAOxB;IAIK,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,aAAa,CAAC,CAOnG;IAGK,IAAI,CAAC,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAG9D;CACF"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { callArgs, enc } from "./shared.js";
|
|
2
|
+
// Skills is the /v1/skills resource.
|
|
3
|
+
//
|
|
4
|
+
// ‼️ THE ENGINE FOR THIS HAS SHIPPED FOR A WHILE AND NOTHING COULD REACH IT. Installation, archive
|
|
5
|
+
// sanitisation, the static scan, the quarantine lifecycle and the digest pin all existed; what was
|
|
6
|
+
// missing was the half a customer installs. A skill nobody can install is a skill nobody has.
|
|
7
|
+
//
|
|
8
|
+
// A SKILL GRANTS NO CAPABILITY. Its metadata rides the run context and its body is read on demand — it
|
|
9
|
+
// cannot let an agent call a tool it is not already permitted to use.
|
|
10
|
+
export class Skills {
|
|
11
|
+
#client;
|
|
12
|
+
constructor(client) {
|
|
13
|
+
this.#client = client;
|
|
14
|
+
}
|
|
15
|
+
// create opens a named skill lineage. Like an agent profile it carries IDENTITY only: what the skill
|
|
16
|
+
// says lives on its revisions.
|
|
17
|
+
async create(params, options = {}) {
|
|
18
|
+
const r = await this.#client.request("POST", "/v1/skills", { body: params, ...callArgs(options) });
|
|
19
|
+
return r.body;
|
|
20
|
+
}
|
|
21
|
+
// installRevision adds a revision from an archive or a URL. It arrives QUARANTINED: the static scan
|
|
22
|
+
// runs first and a revision with findings stays unrunnable until they are resolved, so installing is
|
|
23
|
+
// never the same act as enabling.
|
|
24
|
+
async installRevision(skillID, params, options = {}) {
|
|
25
|
+
const r = await this.#client.request("POST", `/v1/skills/${enc(skillID)}/revisions`, { body: params, ...callArgs(options) });
|
|
26
|
+
return r.body;
|
|
27
|
+
}
|
|
28
|
+
// enable makes a revision runnable. Separate from install because they are separate decisions: one
|
|
29
|
+
// brings untrusted content into the tenant, the other lets a run read it.
|
|
30
|
+
async enable(skillID, revisionID, options = {}) {
|
|
31
|
+
const r = await this.#client.request("POST", `/v1/skills/${enc(skillID)}/revisions/${enc(revisionID)}/enable`, callArgs(options));
|
|
32
|
+
return r.body;
|
|
33
|
+
}
|
|
34
|
+
// list returns the tenant's skill lineages.
|
|
35
|
+
async list(options = {}) {
|
|
36
|
+
const r = await this.#client.request("GET", "/v1/skills", callArgs(options));
|
|
37
|
+
return r.body;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=skills.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/resources/skills.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,GAAG,EAAmC,MAAM,aAAa,CAAC;AAkC7E,qCAAqC;AACrC,EAAE;AACF,mGAAmG;AACnG,mGAAmG;AACnG,8FAA8F;AAC9F,EAAE;AACF,uGAAuG;AACvG,sEAAsE;AACtE,MAAM,OAAO,MAAM;IACjB,OAAO,CAAQ;IACf,YAAY,MAAa;QACvB,IAAI,CAAC,OAAO,GAAG,MAAM,CAAC;IACxB,CAAC;IAED,qGAAqG;IACrG,+BAA+B;IAC/B,KAAK,CAAC,MAAM,CAAC,MAAwB,EAAE,OAAO,GAAgB,EAAE;QAC9D,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAQ,MAAM,EAAE,YAAY,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAC1G,OAAO,CAAC,CAAC,IAAI,CAAC;IAChB,CAAC;IAED,oGAAoG;IACpG,qGAAqG;IACrG,kCAAkC;IAClC,KAAK,CAAC,eAAe,CACnB,OAAe,EACf,MAAkC,EAClC,OAAO,GAAgB,EAAE;QAEzB,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAClC,MAAM,EACN,cAAc,GAAG,CAAC,OAAO,CAAC,YAAY,EACtC,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,QAAQ,CAAC,OAAO,CAAC,EAAE,CACvC,CAAC;QACF,OAAO,CAAC,CAAC,IAAI,CAAC;IAChB,CAAC;IAED,mGAAmG;IACnG,0EAA0E;IAC1E,KAAK,CAAC,MAAM,CAAC,OAAe,EAAE,UAAkB,EAAE,OAAO,GAAgB,EAAE;QACzE,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAClC,MAAM,EACN,cAAc,GAAG,CAAC,OAAO,CAAC,cAAc,GAAG,CAAC,UAAU,CAAC,SAAS,EAChE,QAAQ,CAAC,OAAO,CAAC,CAClB,CAAC;QACF,OAAO,CAAC,CAAC,IAAI,CAAC;IAChB,CAAC;IAED,4CAA4C;IAC5C,KAAK,CAAC,IAAI,CAAC,OAAO,GAAgB,EAAE;QAClC,MAAM,CAAC,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAkB,KAAK,EAAE,YAAY,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;QAC9F,OAAO,CAAC,CAAC,IAAI,CAAC;IAChB,CAAC;CACF"}
|
package/dist/schema.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** A JSON Schema node the output contract will carry. */
|
|
2
|
+
export type JSONSchema = {
|
|
3
|
+
type: "string" | "number" | "integer" | "boolean";
|
|
4
|
+
} | {
|
|
5
|
+
type: "array";
|
|
6
|
+
items: JSONSchema;
|
|
7
|
+
} | {
|
|
8
|
+
type: "object";
|
|
9
|
+
properties: Record<string, JSONSchema>;
|
|
10
|
+
required: string[];
|
|
11
|
+
additionalProperties: false;
|
|
12
|
+
} | {
|
|
13
|
+
enum: string[];
|
|
14
|
+
};
|
|
15
|
+
/** Builders, so a schema reads as a schema rather than as a wall of braces. */
|
|
16
|
+
export declare const s: {
|
|
17
|
+
string: {
|
|
18
|
+
readonly type: "string";
|
|
19
|
+
};
|
|
20
|
+
number: {
|
|
21
|
+
readonly type: "number";
|
|
22
|
+
};
|
|
23
|
+
integer: {
|
|
24
|
+
readonly type: "integer";
|
|
25
|
+
};
|
|
26
|
+
boolean: {
|
|
27
|
+
readonly type: "boolean";
|
|
28
|
+
};
|
|
29
|
+
array(items: JSONSchema): JSONSchema;
|
|
30
|
+
/** `additionalProperties` is always false: the server wants a strict schema, and an undeclared
|
|
31
|
+
* field slipping through is the defect strictness exists to prevent. */
|
|
32
|
+
object(properties: Record<string, JSONSchema>, required: string[]): JSONSchema;
|
|
33
|
+
enum(values: string[]): JSONSchema;
|
|
34
|
+
};
|
|
35
|
+
//# sourceMappingURL=schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAYA,yDAAyD;AACzD,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAA;CAAE,GACrD;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,GACpC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IAAC,QAAQ,EAAE,MAAM,EAAE,CAAC;IAAC,oBAAoB,EAAE,KAAK,CAAA;CAAE,GAC3G;IAAE,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC;AAEvB,+EAA+E;AAC/E,eAAO,MAAM,CAAC;;uBACI,QAAQ;;;uBACR,QAAQ;;;uBACP,SAAS;;;uBACT,SAAS;;iBAEb,UAAU,GAAG,UAAU;IAIpC;6EACyE;uBACtD,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,YAAY,MAAM,EAAE,GAAG,UAAU;iBAIjE,MAAM,EAAE,GAAG,UAAU;CAGnC,CAAC"}
|
package/dist/schema.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// JSON Schema, written by the caller.
|
|
2
|
+
//
|
|
3
|
+
// ‼️ THERE IS NO ZOD DEPENDENCY HERE, AND THAT IS DELIBERATE. `@palai/sdk` ships with an empty
|
|
4
|
+
// `dependencies` list, and a schema library is not worth ending that: every consumer would inherit
|
|
5
|
+
// it, including ones that already use a different validator. OpenAI solves the same problem with an
|
|
6
|
+
// optional subpath (`openai/helpers/zod`) that only works if you installed zod; this is the
|
|
7
|
+
// zero-dependency half of that idea — you hand over a schema, and if you happen to use zod you can
|
|
8
|
+
// produce one with `z.toJSONSchema(...)` yourself.
|
|
9
|
+
//
|
|
10
|
+
// The server is the only validator. `output.format` is READ: an unrecognised value answers 400
|
|
11
|
+
// (measured 2026-08-26), so a second validator here would be a second definition of "invalid".
|
|
12
|
+
/** Builders, so a schema reads as a schema rather than as a wall of braces. */
|
|
13
|
+
export const s = {
|
|
14
|
+
string: { type: "string" },
|
|
15
|
+
number: { type: "number" },
|
|
16
|
+
integer: { type: "integer" },
|
|
17
|
+
boolean: { type: "boolean" },
|
|
18
|
+
array(items) {
|
|
19
|
+
return { type: "array", items };
|
|
20
|
+
},
|
|
21
|
+
/** `additionalProperties` is always false: the server wants a strict schema, and an undeclared
|
|
22
|
+
* field slipping through is the defect strictness exists to prevent. */
|
|
23
|
+
object(properties, required) {
|
|
24
|
+
return { type: "object", properties, required: [...required].sort(), additionalProperties: false };
|
|
25
|
+
},
|
|
26
|
+
enum(values) {
|
|
27
|
+
return { enum: values };
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../src/schema.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,EAAE;AACF,+FAA+F;AAC/F,mGAAmG;AACnG,oGAAoG;AACpG,4FAA4F;AAC5F,mGAAmG;AACnG,mDAAmD;AACnD,EAAE;AACF,+FAA+F;AAC/F,+FAA+F;AAS/F,+EAA+E;AAC/E,MAAM,CAAC,MAAM,CAAC,GAAG;IACf,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAgC;IACxD,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAgC;IACxD,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAgC;IAC1D,OAAO,EAAE,EAAE,IAAI,EAAE,SAAS,EAAgC;IAE1D,KAAK,CAAC,KAAiB;QACrB,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IAClC,CAAC;IAED;6EACyE;IACzE,MAAM,CAAC,UAAsC,EAAE,QAAkB;QAC/D,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,GAAG,QAAQ,CAAC,CAAC,IAAI,EAAE,EAAE,oBAAoB,EAAE,KAAK,EAAE,CAAC;IACrG,CAAC;IAED,IAAI,CAAC,MAAgB;QACnB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;IAC1B,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-only.d.ts","sourceRoot":"","sources":["../src/server-only.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAE,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// The API key path is server-only. Importing this module marks its importer as
|
|
2
|
+
// server-only: if the module is ever evaluated in a browser bundle, it throws instead of
|
|
3
|
+
// silently shipping the secret to the client. Bundlers that honor the package's "browser"
|
|
4
|
+
// export condition never reach a credential module (they resolve ./index.browser, which
|
|
5
|
+
// carries no key); this runtime check is the framework-agnostic backstop for bundlers and
|
|
6
|
+
// runtimes that do not. It is a no-op in Node and other server runtimes, where there is no
|
|
7
|
+
// window/document, so the SDK stays usable and unit-testable off any single framework.
|
|
8
|
+
//
|
|
9
|
+
// This is deliberately NOT the `server-only` npm package: that package throws on import in
|
|
10
|
+
// plain Node (its default export throws outside the React `react-server` condition), which
|
|
11
|
+
// would make the SDK Next.js-only and untestable in a Node test runner. A browser-shaped
|
|
12
|
+
// global check gives the same protection without that coupling.
|
|
13
|
+
const inBrowser = typeof globalThis.window !== "undefined" ||
|
|
14
|
+
typeof globalThis.document !== "undefined";
|
|
15
|
+
if (inBrowser) {
|
|
16
|
+
throw new Error("@palai/sdk: a Palai client configured with an API key must never be bundled for the " +
|
|
17
|
+
"browser — that would ship your secret to every visitor. Import it only from server " +
|
|
18
|
+
"code (route handlers, server actions, server components), or use the browser-safe " +
|
|
19
|
+
"'@palai/sdk/browser' entrypoint, which carries no credential.");
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=server-only.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-only.js","sourceRoot":"","sources":["../src/server-only.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAC/E,yFAAyF;AACzF,0FAA0F;AAC1F,wFAAwF;AACxF,0FAA0F;AAC1F,2FAA2F;AAC3F,uFAAuF;AACvF,EAAE;AACF,2FAA2F;AAC3F,2FAA2F;AAC3F,yFAAyF;AACzF,gEAAgE;AAEhE,MAAM,SAAS,GACb,OAAQ,UAAmC,CAAC,MAAM,KAAK,WAAW;IAClE,OAAQ,UAAqC,CAAC,QAAQ,KAAK,WAAW,CAAC;AAEzE,IAAI,SAAS,EAAE,CAAC;IACd,MAAM,IAAI,KAAK,CACb,sFAAsF;QACpF,qFAAqF;QACrF,oFAAoF;QACpF,+DAA+D,CAClE,CAAC;AACJ,CAAC;AAED,OAAO,EAAE,CAAC"}
|
package/dist/stream.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Event, Response as PalaiResponse } from "./generated/types.ts";
|
|
2
|
+
export interface SSEFrame {
|
|
3
|
+
id: string | undefined;
|
|
4
|
+
event: string | undefined;
|
|
5
|
+
data: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function parseEventStream(body: ReadableStream<Uint8Array>): AsyncGenerator<SSEFrame>;
|
|
8
|
+
export declare function isTerminalEvent(event: Event): boolean;
|
|
9
|
+
export interface StreamTransport {
|
|
10
|
+
openEventStream(sessionID: string, lastEventId: string | null, signal: AbortSignal | undefined): Promise<globalThis.Response>;
|
|
11
|
+
retrieveResponse(responseID: string): Promise<PalaiResponse>;
|
|
12
|
+
}
|
|
13
|
+
export interface StreamStart {
|
|
14
|
+
responseID: string;
|
|
15
|
+
sessionID: string;
|
|
16
|
+
}
|
|
17
|
+
export interface ResponseStreamInit {
|
|
18
|
+
transport: StreamTransport;
|
|
19
|
+
/** Runs once, lazily, on first consumption — typically the create POST. */
|
|
20
|
+
start: () => Promise<StreamStart>;
|
|
21
|
+
signal?: AbortSignal | undefined;
|
|
22
|
+
lastEventId?: string | null;
|
|
23
|
+
maxReconnects?: number;
|
|
24
|
+
backoffBaseMs?: number;
|
|
25
|
+
backoffMaxMs?: number;
|
|
26
|
+
}
|
|
27
|
+
export declare class ResponseStream implements AsyncIterable<Event> {
|
|
28
|
+
#private;
|
|
29
|
+
constructor(init: ResponseStreamInit);
|
|
30
|
+
get responseID(): string | undefined;
|
|
31
|
+
get sessionID(): string | undefined;
|
|
32
|
+
get lastEventId(): string | null;
|
|
33
|
+
[Symbol.asyncIterator](): AsyncGenerator<Event>;
|
|
34
|
+
finalResponse(): Promise<PalaiResponse>;
|
|
35
|
+
}
|
|
36
|
+
export declare function fullJitterBackoff(attempt: number, baseMs: number, maxMs: number): number;
|
|
37
|
+
export declare function delay(ms: number, signal?: AbortSignal | undefined): Promise<void>;
|
|
38
|
+
//# sourceMappingURL=stream.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stream.d.ts","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,QAAQ,IAAI,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAM7E,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,GAAG,SAAS,CAAC;IACvB,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;CACd;AAOD,wBAAuB,gBAAgB,CACrC,IAAI,EAAE,cAAc,CAAC,UAAU,CAAC,GAC/B,cAAc,CAAC,QAAQ,CAAC,CAkC1B;AA4CD,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAErD;AAKD,MAAM,WAAW,eAAe;IAC9B,eAAe,CACb,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAAG,IAAI,EAC1B,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,OAAO,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC;IAChC,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CAC9D;AAKD,MAAM,WAAW,WAAW;IAC1B,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,eAAe,CAAC;IAC3B,2EAA2E;IAC3E,KAAK,EAAE,MAAM,OAAO,CAAC,WAAW,CAAC,CAAC;IAClC,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAOD,qBAAa,cAAe,YAAW,aAAa,CAAC,KAAK,CAAC;;IAYzD,YAAY,IAAI,EAAE,kBAAkB,EAQnC;IAID,IAAI,UAAU,IAAI,MAAM,GAAG,SAAS,CAEnC;IACD,IAAI,SAAS,IAAI,MAAM,GAAG,SAAS,CAElC;IAID,IAAI,WAAW,IAAI,MAAM,GAAG,IAAI,CAE/B;IASD,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,cAAc,CAAC,KAAK,CAAC,CAM9C;IAMK,aAAa,IAAI,OAAO,CAAC,aAAa,CAAC,CAc5C;CA4GF;AAoCD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAMxF;AAID,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBjF"}
|