dyadic 1.2.0 → 1.3.1
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 +32 -22
- package/README.md +114 -94
- package/dist/index.d.ts +65 -1
- package/dist/index.js +5 -1
- package/package.json +15 -15
package/CHANGELOG.md
CHANGED
|
@@ -1,22 +1,32 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## 1.
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
-
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 1.3.1 (2026-10-10)
|
|
4
|
+
|
|
5
|
+
- The version the SDK reports (`__version__` / `VERSION`, and the User-Agent header) is the package's
|
|
6
|
+
own: 1.3.0 still said 1.2.0.
|
|
7
|
+
|
|
8
|
+
## 1.3.0 (2026-10-10)
|
|
9
|
+
|
|
10
|
+
- `decisions.create(input, questions, model?)`: typed answers (a predicate's probability, a
|
|
11
|
+
choice or a score) from `POST /v1/decisions`.
|
|
12
|
+
|
|
13
|
+
## 1.2.0 (2026-10-07)
|
|
14
|
+
|
|
15
|
+
Security release.
|
|
16
|
+
|
|
17
|
+
- The API key is only ever sent to the configured API origin. `request()` with an
|
|
18
|
+
absolute URL on another host, port or scheme, with credentials in it, or
|
|
19
|
+
protocol-relative, now raises instead of sending the key; redirects are not
|
|
20
|
+
followed. Plain `http://` base URLs are accepted only for local or
|
|
21
|
+
private-network APIs.
|
|
22
|
+
- Retries no longer repeat work that may already have run. GET, HEAD, DELETE and
|
|
23
|
+
OPTIONS retry on busy or failing servers; other requests retry only when they
|
|
24
|
+
never started (no connection, or Dyadic's `rate_limit_exceeded` /
|
|
25
|
+
`concurrency_limit` refusal). `409` is no longer retried.
|
|
26
|
+
- Every attempt of one call sends the same `Idempotency-Key` (choose it with
|
|
27
|
+
`{ idempotencyKey }`, or mark a call safe to replay with `{ idempotent: true }`).
|
|
28
|
+
- The package documents server-side use only (a key must never ship to a browser), builds before `npm test` and `npm pack`, and has a lockfile.
|
|
29
|
+
|
|
30
|
+
## 1.1.0
|
|
31
|
+
|
|
32
|
+
- Runs with your own agents and functions, and connected apps (Workspace saves).
|
package/README.md
CHANGED
|
@@ -1,94 +1,114 @@
|
|
|
1
|
-
# dyadic
|
|
2
|
-
|
|
3
|
-
```sh
|
|
4
|
-
npm install dyadic
|
|
5
|
-
```
|
|
6
|
-
|
|
7
|
-
The official TypeScript and JavaScript SDK for the [Dyadic API](https://dyadic.app/developers/): Iris with streaming, function calling, images and typed errors. No dependencies; for server-side code on Node 18+, Deno and Bun (keep your key off the browser, see below).
|
|
8
|
-
|
|
9
|
-
```ts
|
|
10
|
-
import { Dyadic } from "dyadic";
|
|
11
|
-
|
|
12
|
-
const client = new Dyadic({ apiKey: process.env.DYADIC_API_KEY });
|
|
13
|
-
console.log(await client.ask("Hello!", { model: "iris" }));
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
## Keep your key on the server
|
|
17
|
-
|
|
18
|
-
**A Dyadic API key is a long-lived secret that spends your credits. Never ship it
|
|
19
|
-
to a browser**: not in a bundle, page source, local storage or a request your
|
|
20
|
-
front end makes, where any visitor or extension can copy it. Use the SDK in
|
|
21
|
-
server-side code (Node 18+, Deno, Bun, edge functions) and have your front end
|
|
22
|
-
call your own server:
|
|
23
|
-
|
|
24
|
-
```ts
|
|
25
|
-
// server.ts: the key stays here
|
|
26
|
-
import { Dyadic } from "dyadic";
|
|
27
|
-
const client = new Dyadic({ apiKey: process.env.DYADIC_API_KEY });
|
|
28
|
-
|
|
29
|
-
export async function POST(request: Request) {
|
|
30
|
-
const { question } = await request.json();
|
|
31
|
-
// Check your own user's session and limits here before spending credits.
|
|
32
|
-
return Response.json({ answer: await client.ask(String(question).slice(0, 4000), { model: "iris" }) });
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
`request()` only ever sends the key to the API you configured: a relative path
|
|
37
|
-
joins `baseURL`, and an absolute URL on any other host, port or scheme (or with
|
|
38
|
-
credentials in it) throws `DyadicError` instead of being sent. Redirects are not
|
|
39
|
-
followed. Plain `http://` is accepted only for a local or private-network API.
|
|
40
|
-
|
|
41
|
-
## Retries
|
|
42
|
-
|
|
43
|
-
GET, HEAD, DELETE and OPTIONS are retried on busy or failing servers. Anything
|
|
44
|
-
else (a completion, an upload, a run) may already have run, and been billed,
|
|
45
|
-
when it fails, so it is retried only if it provably never started: the
|
|
46
|
-
connection was never made, or Dyadic refused it with `rate_limit_exceeded` or
|
|
47
|
-
`concurrency_limit`. Every attempt of one call carries the same
|
|
48
|
-
`Idempotency-Key`; pass `{ idempotencyKey }` to choose it, or `{ idempotent: true }`
|
|
49
|
-
for a call that is safe to send twice.
|
|
50
|
-
|
|
51
|
-
## Runs: your own agent, Dyadic's tools, your functions
|
|
52
|
-
|
|
53
|
-
```ts
|
|
54
|
-
const run = await client.runs.run({
|
|
55
|
-
agent: { id: "helpdesk", name: "Helpdesk", instructions: "You answer customers of a small shop." },
|
|
56
|
-
messages: [{ role: "user", content: "Where is order 1042?" }],
|
|
57
|
-
builtin_tools: ["data.web_search"],
|
|
58
|
-
functions: {
|
|
59
|
-
lookup_order: {
|
|
60
|
-
description: "Look up an order by id.",
|
|
61
|
-
parameters: { type: "object", properties: { order_id: { type: "string" } }, required: ["order_id"] },
|
|
62
|
-
handler: async ({ order_id }) => ({ order_id, status: "shipped" }),
|
|
63
|
-
},
|
|
64
|
-
},
|
|
65
|
-
end_user: "customer-17",
|
|
66
|
-
});
|
|
67
|
-
console.log(run.output_text);
|
|
68
|
-
```
|
|
69
|
-
|
|
70
|
-
`client.runs.create({ ..., stream: true })` streams the run's events.
|
|
71
|
-
|
|
72
|
-
##
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
1
|
+
# dyadic
|
|
2
|
+
|
|
3
|
+
```sh
|
|
4
|
+
npm install dyadic
|
|
5
|
+
```
|
|
6
|
+
|
|
7
|
+
The official TypeScript and JavaScript SDK for the [Dyadic API](https://dyadic.app/developers/): Iris with streaming, function calling, images and typed errors. No dependencies; for server-side code on Node 18+, Deno and Bun (keep your key off the browser, see below).
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { Dyadic } from "dyadic";
|
|
11
|
+
|
|
12
|
+
const client = new Dyadic({ apiKey: process.env.DYADIC_API_KEY });
|
|
13
|
+
console.log(await client.ask("Hello!", { model: "iris" }));
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Keep your key on the server
|
|
17
|
+
|
|
18
|
+
**A Dyadic API key is a long-lived secret that spends your credits. Never ship it
|
|
19
|
+
to a browser**: not in a bundle, page source, local storage or a request your
|
|
20
|
+
front end makes, where any visitor or extension can copy it. Use the SDK in
|
|
21
|
+
server-side code (Node 18+, Deno, Bun, edge functions) and have your front end
|
|
22
|
+
call your own server:
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
// server.ts: the key stays here
|
|
26
|
+
import { Dyadic } from "dyadic";
|
|
27
|
+
const client = new Dyadic({ apiKey: process.env.DYADIC_API_KEY });
|
|
28
|
+
|
|
29
|
+
export async function POST(request: Request) {
|
|
30
|
+
const { question } = await request.json();
|
|
31
|
+
// Check your own user's session and limits here before spending credits.
|
|
32
|
+
return Response.json({ answer: await client.ask(String(question).slice(0, 4000), { model: "iris" }) });
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
`request()` only ever sends the key to the API you configured: a relative path
|
|
37
|
+
joins `baseURL`, and an absolute URL on any other host, port or scheme (or with
|
|
38
|
+
credentials in it) throws `DyadicError` instead of being sent. Redirects are not
|
|
39
|
+
followed. Plain `http://` is accepted only for a local or private-network API.
|
|
40
|
+
|
|
41
|
+
## Retries
|
|
42
|
+
|
|
43
|
+
GET, HEAD, DELETE and OPTIONS are retried on busy or failing servers. Anything
|
|
44
|
+
else (a completion, an upload, a run) may already have run, and been billed,
|
|
45
|
+
when it fails, so it is retried only if it provably never started: the
|
|
46
|
+
connection was never made, or Dyadic refused it with `rate_limit_exceeded` or
|
|
47
|
+
`concurrency_limit`. Every attempt of one call carries the same
|
|
48
|
+
`Idempotency-Key`; pass `{ idempotencyKey }` to choose it, or `{ idempotent: true }`
|
|
49
|
+
for a call that is safe to send twice.
|
|
50
|
+
|
|
51
|
+
## Runs: your own agent, Dyadic's tools, your functions
|
|
52
|
+
|
|
53
|
+
```ts
|
|
54
|
+
const run = await client.runs.run({
|
|
55
|
+
agent: { id: "helpdesk", name: "Helpdesk", instructions: "You answer customers of a small shop." },
|
|
56
|
+
messages: [{ role: "user", content: "Where is order 1042?" }],
|
|
57
|
+
builtin_tools: ["data.web_search"],
|
|
58
|
+
functions: {
|
|
59
|
+
lookup_order: {
|
|
60
|
+
description: "Look up an order by id.",
|
|
61
|
+
parameters: { type: "object", properties: { order_id: { type: "string" } }, required: ["order_id"] },
|
|
62
|
+
handler: async ({ order_id }) => ({ order_id, status: "shipped" }),
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
end_user: "customer-17",
|
|
66
|
+
});
|
|
67
|
+
console.log(run.output_text);
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
`client.runs.create({ ..., stream: true })` streams the run's events.
|
|
71
|
+
|
|
72
|
+
## Decisions: typed answers, fast and cheap
|
|
73
|
+
|
|
74
|
+
Ask one or more questions about some text (or text and images) and get typed answers
|
|
75
|
+
back: a probability (`predicate`), one of your values (`choice`) or a rubric level
|
|
76
|
+
(`score`). A fraction of a second and a fraction of a cent; billed at cost.
|
|
77
|
+
|
|
78
|
+
```ts
|
|
79
|
+
const decision = await client.decisions.create({
|
|
80
|
+
input: "I can't log in after resetting my password.",
|
|
81
|
+
questions: [
|
|
82
|
+
{ type: "predicate", name: "urgent", instructions: "The customer is blocked from using the product." },
|
|
83
|
+
{ type: "choice", name: "team", instructions: "Which team should handle this.", choices: [
|
|
84
|
+
{ value: "account", description: "Sign-in and account access" },
|
|
85
|
+
{ value: "billing", description: "Payments and invoices" },
|
|
86
|
+
{ value: "other", description: "Anything else" },
|
|
87
|
+
] },
|
|
88
|
+
],
|
|
89
|
+
});
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
## Connected apps: saving into a person's Workspace
|
|
93
|
+
|
|
94
|
+
With the person's approval, an application can save into their Dyadic
|
|
95
|
+
Workspace, naming them by the Discord account linked to their Dyadic account.
|
|
96
|
+
|
|
97
|
+
```ts
|
|
98
|
+
const status = await client.connections.discord(discordId);
|
|
99
|
+
if (!status.authorized) console.log("Allow this app:", status.authorize_url); // show the person this link
|
|
100
|
+
|
|
101
|
+
try {
|
|
102
|
+
const saved = await client.workspace.saves.create({ discord_id: discordId, kind: "message", title: "From #general",
|
|
103
|
+
text: "Worth keeping", url: "https://discord.com/channels/1/2/3" });
|
|
104
|
+
console.log(saved.url);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
if (error instanceof DyadicError && error.code === "authorization_required") console.log("Allow this app:", error.body.authorize_url);
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
`kind` is `message`, `conversation` (with `messages`, saved as a chat the
|
|
111
|
+
person can continue unless `as_chat: false`), `image` or `file` (with `files`:
|
|
112
|
+
base64, up to 10 of 8 MB).
|
|
113
|
+
|
|
114
|
+
Full guide: https://dyadic.app/developers/
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const VERSION = "1.
|
|
1
|
+
export declare const VERSION = "1.3.1";
|
|
2
2
|
export declare const DEFAULT_BASE_URL = "https://dyadic.app/api/openai/v1";
|
|
3
3
|
export type Model = "iris" | "iris-think" | (string & {});
|
|
4
4
|
export type Role = "system" | "developer" | "user" | "assistant" | "tool";
|
|
@@ -310,6 +310,59 @@ export interface Moderation {
|
|
|
310
310
|
category_applied_input_types: Record<string, string[]>;
|
|
311
311
|
}[];
|
|
312
312
|
}
|
|
313
|
+
export type DecisionQuestion = {
|
|
314
|
+
type: "predicate";
|
|
315
|
+
name: string;
|
|
316
|
+
instructions: string;
|
|
317
|
+
} | {
|
|
318
|
+
type: "choice";
|
|
319
|
+
name: string;
|
|
320
|
+
instructions: string;
|
|
321
|
+
choices: {
|
|
322
|
+
value: string;
|
|
323
|
+
description: string;
|
|
324
|
+
}[];
|
|
325
|
+
} | {
|
|
326
|
+
type: "score";
|
|
327
|
+
name: string;
|
|
328
|
+
instructions: string;
|
|
329
|
+
levels: {
|
|
330
|
+
label: string;
|
|
331
|
+
description: string;
|
|
332
|
+
}[];
|
|
333
|
+
};
|
|
334
|
+
export type DecisionAnswer = {
|
|
335
|
+
type: "predicate";
|
|
336
|
+
name: string;
|
|
337
|
+
probability: number;
|
|
338
|
+
} | {
|
|
339
|
+
type: "choice";
|
|
340
|
+
name: string;
|
|
341
|
+
choice: string;
|
|
342
|
+
probabilities: {
|
|
343
|
+
value: string;
|
|
344
|
+
probability: number;
|
|
345
|
+
}[];
|
|
346
|
+
confidence: number;
|
|
347
|
+
} | {
|
|
348
|
+
type: "score";
|
|
349
|
+
name: string;
|
|
350
|
+
score: number;
|
|
351
|
+
probabilities: {
|
|
352
|
+
value: number;
|
|
353
|
+
label: string;
|
|
354
|
+
probability: number;
|
|
355
|
+
}[];
|
|
356
|
+
confidence: number;
|
|
357
|
+
} | {
|
|
358
|
+
type: "refusal";
|
|
359
|
+
name: string;
|
|
360
|
+
};
|
|
361
|
+
export interface Decision {
|
|
362
|
+
id: string | null;
|
|
363
|
+
model: string;
|
|
364
|
+
answers: DecisionAnswer[];
|
|
365
|
+
}
|
|
313
366
|
export interface FileObject {
|
|
314
367
|
id: string;
|
|
315
368
|
object: "file";
|
|
@@ -631,6 +684,17 @@ export declare class Dyadic {
|
|
|
631
684
|
model?: string;
|
|
632
685
|
}) => Promise<Moderation>;
|
|
633
686
|
};
|
|
687
|
+
/** Typed answers: each question a predicate (a probability), a choice or a score, about the input. */
|
|
688
|
+
readonly decisions: {
|
|
689
|
+
create: (params: {
|
|
690
|
+
input: string | {
|
|
691
|
+
role: "user";
|
|
692
|
+
content: unknown[];
|
|
693
|
+
}[];
|
|
694
|
+
questions: DecisionQuestion[];
|
|
695
|
+
model?: string;
|
|
696
|
+
}) => Promise<Decision>;
|
|
697
|
+
};
|
|
634
698
|
readonly images: {
|
|
635
699
|
generate: (params: ImageParams) => Promise<ImageResponse>;
|
|
636
700
|
edit: ({ image, ...params }: Omit<ImageParams, "model"> & {
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// The official TypeScript SDK for the Dyadic API: Iris
|
|
2
2
|
// through the OpenAI-compatible endpoints at https://dyadic.app/api/openai/v1.
|
|
3
|
-
export const VERSION = "1.
|
|
3
|
+
export const VERSION = "1.3.1";
|
|
4
4
|
export const DEFAULT_BASE_URL = "https://dyadic.app/api/openai/v1";
|
|
5
5
|
/** Bytes from the API (speech audio, file downloads). */
|
|
6
6
|
export class Binary {
|
|
@@ -221,6 +221,10 @@ export class Dyadic {
|
|
|
221
221
|
this.moderations = {
|
|
222
222
|
create: (params) => this.request("POST", "/moderations", params),
|
|
223
223
|
};
|
|
224
|
+
/** Typed answers: each question a predicate (a probability), a choice or a score, about the input. */
|
|
225
|
+
this.decisions = {
|
|
226
|
+
create: (params) => this.request("POST", "/decisions", params),
|
|
227
|
+
};
|
|
224
228
|
this.images = {
|
|
225
229
|
generate: (params) => this.request("POST", "/images/generations", params),
|
|
226
230
|
edit: ({ image, ...params }) => this.request("POST", "/images/edits", undefined, false, { form: form(params, { image: [image, "image.png"] }) }),
|
package/package.json
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "dyadic",
|
|
3
|
-
"version": "1.
|
|
4
|
-
"description": "The official TypeScript and JavaScript SDK for the Dyadic API: runs with your own agents and functions, plus the OpenAI-compatible API.",
|
|
5
|
-
"type": "module",
|
|
6
|
-
"main": "./dist/index.js",
|
|
7
|
-
"types": "./dist/index.d.ts",
|
|
8
|
-
"exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } },
|
|
9
|
-
"files": ["dist", "README.md", "CHANGELOG.md"],
|
|
10
|
-
"engines": { "node": ">=18" },
|
|
11
|
-
"license": "MIT",
|
|
12
|
-
"homepage": "https://dyadic.app/developers/",
|
|
13
|
-
"scripts": { "build": "tsc", "pretest": "tsc", "test": "node --test test/client.test.js test/transport.test.js", "prepack": "tsc" },
|
|
14
|
-
"devDependencies": { "typescript": "5.6.3" }
|
|
15
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "dyadic",
|
|
3
|
+
"version": "1.3.1",
|
|
4
|
+
"description": "The official TypeScript and JavaScript SDK for the Dyadic API: runs with your own agents and functions, plus the OpenAI-compatible API.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } },
|
|
9
|
+
"files": ["dist", "README.md", "CHANGELOG.md"],
|
|
10
|
+
"engines": { "node": ">=18" },
|
|
11
|
+
"license": "MIT",
|
|
12
|
+
"homepage": "https://dyadic.app/developers/",
|
|
13
|
+
"scripts": { "build": "tsc", "pretest": "tsc", "test": "node --test test/client.test.js test/transport.test.js", "prepack": "tsc" },
|
|
14
|
+
"devDependencies": { "typescript": "5.6.3" }
|
|
15
|
+
}
|