@neurosquad/card-sdk 1.0.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/LICENSE +21 -0
- package/README.md +431 -0
- package/dist/card-sdk.js +5266 -0
- package/dist/cli.js +2838 -0
- package/dist/react.js +257 -0
- package/dist/testing.js +1150 -0
- package/dist/types/client/base64.d.ts +7 -0
- package/dist/types/client/card.d.ts +653 -0
- package/dist/types/client/channel.d.ts +49 -0
- package/dist/types/client/coalesce.d.ts +14 -0
- package/dist/types/client/connect.d.ts +39 -0
- package/dist/types/client/errors.d.ts +46 -0
- package/dist/types/client/helpers.d.ts +25 -0
- package/dist/types/client/net.d.ts +111 -0
- package/dist/types/client/theme.d.ts +31 -0
- package/dist/types/client/toolResult.d.ts +16 -0
- package/dist/types/contract/api.d.ts +812 -0
- package/dist/types/contract/index.d.ts +11 -0
- package/dist/types/contract/jsonSchema.d.ts +88 -0
- package/dist/types/contract/localized.d.ts +10 -0
- package/dist/types/contract/manifest.d.ts +179 -0
- package/dist/types/contract/network.d.ts +48 -0
- package/dist/types/contract/permissions.d.ts +180 -0
- package/dist/types/contract/ports.d.ts +237 -0
- package/dist/types/contract/protocol.d.ts +74 -0
- package/dist/types/contract/source.d.ts +111 -0
- package/dist/types/contract/theme.d.ts +21 -0
- package/dist/types/contract/version.d.ts +126 -0
- package/dist/types/i18n.d.ts +50 -0
- package/dist/types/index.d.ts +28 -0
- package/dist/types/react/index.d.ts +132 -0
- package/dist/types/testing/index.d.ts +7 -0
- package/dist/types/testing/mockHost.d.ts +315 -0
- package/dist/types/version.d.ts +2 -0
- package/dist/ui.css +581 -0
- package/package.json +77 -0
- package/schema/neurosquad-card.v1.json +434 -0
- package/templates/react/README.md +34 -0
- package/templates/react/_gitignore +10 -0
- package/templates/react/icon.png +0 -0
- package/templates/react/index.html +12 -0
- package/templates/react/neurosquad-card.json +94 -0
- package/templates/react/package.json +25 -0
- package/templates/react/src/App.tsx +131 -0
- package/templates/react/src/i18n.ts +61 -0
- package/templates/react/src/main.tsx +77 -0
- package/templates/react/src/styles.css +42 -0
- package/templates/react/tsconfig.json +18 -0
- package/templates/react/vite.config.ts +19 -0
- package/templates/vanilla/README.md +37 -0
- package/templates/vanilla/_gitignore +6 -0
- package/templates/vanilla/icon.png +0 -0
- package/templates/vanilla/index.html +41 -0
- package/templates/vanilla/main.js +256 -0
- package/templates/vanilla/neurosquad-card.json +94 -0
- package/templates/vanilla/style.css +41 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { CardSdkError } from './errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Requests main parses with LIMITS.largeMessageBytes instead of messageBytes —
|
|
4
|
+
* their params schemas admit bodies over 1 MB (docs/card-sdk/requests/A-contract-log.md, 2026-09-24).
|
|
5
|
+
*/
|
|
6
|
+
export declare const LARGE_REQUEST_METHODS: ReadonlySet<string>;
|
|
7
|
+
/**
|
|
8
|
+
* The minimal MessagePort surface the SDK uses. A real `MessagePort` fits;
|
|
9
|
+
* tests may pass any object with these members.
|
|
10
|
+
*/
|
|
11
|
+
export interface CardPort {
|
|
12
|
+
postMessage(message: unknown): void;
|
|
13
|
+
onmessage: ((event: MessageEvent) => void) | null;
|
|
14
|
+
close(): void;
|
|
15
|
+
start?(): void;
|
|
16
|
+
}
|
|
17
|
+
/** Per-call options accepted by `card.call()` and most helpers. */
|
|
18
|
+
export interface CallOptions {
|
|
19
|
+
/** Rejects locally with TIMEOUT after this long (the host may still finish the work). */
|
|
20
|
+
timeoutMs?: number;
|
|
21
|
+
/** Rejects with the signal's reason when aborted. */
|
|
22
|
+
signal?: AbortSignal;
|
|
23
|
+
/** Skip the local params check against METHOD_SPECS (the host always checks). Default false. */
|
|
24
|
+
skipValidation?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export type EventSink = (event: string, data: unknown) => void;
|
|
27
|
+
/** @internal RPC over one port. The Card wraps it; authors use `card.call()`. */
|
|
28
|
+
export declare class Channel {
|
|
29
|
+
private readonly port;
|
|
30
|
+
private nextId;
|
|
31
|
+
private readonly pending;
|
|
32
|
+
private readonly queue;
|
|
33
|
+
private sink;
|
|
34
|
+
private early;
|
|
35
|
+
private closedError;
|
|
36
|
+
private readonly closeListeners;
|
|
37
|
+
constructor(port: CardPort);
|
|
38
|
+
/** True after close() or a fatal error. */
|
|
39
|
+
get closed(): boolean;
|
|
40
|
+
/** Where events go. Events that arrive before a sink is set are kept and replayed. */
|
|
41
|
+
setEventSink(sink: EventSink): void;
|
|
42
|
+
onClose(listener: (error: CardSdkError) => void): () => void;
|
|
43
|
+
request(method: string, params: unknown, options?: CallOptions): Promise<unknown>;
|
|
44
|
+
/** Fire-and-forget request: failures are reported to `onError` (default: ignored). */
|
|
45
|
+
notify(method: string, params: unknown, onError?: (error: unknown) => void): void;
|
|
46
|
+
close(reason?: string): void;
|
|
47
|
+
private pump;
|
|
48
|
+
private receive;
|
|
49
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** One latest-wins lane per method. */
|
|
2
|
+
export declare class Coalescer<A> {
|
|
3
|
+
private readonly send;
|
|
4
|
+
private busy;
|
|
5
|
+
private next;
|
|
6
|
+
private timer;
|
|
7
|
+
private closed;
|
|
8
|
+
constructor(send: (args: A) => Promise<unknown>);
|
|
9
|
+
push(args: A): Promise<void>;
|
|
10
|
+
/** Drops what is waiting (the card is closing); its callers resolve. */
|
|
11
|
+
cancel(): void;
|
|
12
|
+
private fire;
|
|
13
|
+
private drain;
|
|
14
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { Card, type CardOptions } from './card.js';
|
|
2
|
+
import { type CardPort } from './channel.js';
|
|
3
|
+
/** The bits of `window` the handshake uses — a real window, or a stand-in in tests. */
|
|
4
|
+
export interface HandshakeWindow {
|
|
5
|
+
readonly parent: unknown;
|
|
6
|
+
addEventListener(type: 'message', listener: (event: MessageEvent) => void): void;
|
|
7
|
+
removeEventListener(type: 'message', listener: (event: MessageEvent) => void): void;
|
|
8
|
+
}
|
|
9
|
+
/** Options of {@link connect}. */
|
|
10
|
+
export interface ConnectOptions extends CardOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Use this port instead of waiting for the host's handshake — for
|
|
13
|
+
* `createMockHost()` and custom setups.
|
|
14
|
+
*/
|
|
15
|
+
port?: CardPort;
|
|
16
|
+
/** The window to listen on (tests). Default: the global `window`. */
|
|
17
|
+
window?: HandshakeWindow;
|
|
18
|
+
/** How long to wait for the host's port, then for `host.ready`. Default 10 000 ms. */
|
|
19
|
+
timeoutMs?: number;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Connects the card to NeuroSquad and resolves with the typed {@link Card}.
|
|
23
|
+
*
|
|
24
|
+
* Waits for the host to hand over the card's private channel (only the
|
|
25
|
+
* embedding app can), sends `host.ready`, and applies the app theme to
|
|
26
|
+
* `<html>` as `--ns-*` variables. Calling it again returns the same card.
|
|
27
|
+
*
|
|
28
|
+
* Fails with a {@link CardSdkError}:
|
|
29
|
+
* - `UNAVAILABLE` when the page is not inside a NeuroSquad card frame (for a
|
|
30
|
+
* standalone preview or tests use `createMockHost()` from
|
|
31
|
+
* `@neurosquad/card-sdk/testing`);
|
|
32
|
+
* - `PROTOCOL_MISMATCH` when the app is older than this SDK's protocol.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* import { connect } from '@neurosquad/card-sdk'
|
|
36
|
+
* const card = await connect()
|
|
37
|
+
* document.querySelector('h1')!.textContent = card.instance.displayName
|
|
38
|
+
*/
|
|
39
|
+
export declare function connect(options?: ConnectOptions): Promise<Card>;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { CardErrorCode, CardErrorPayload, PermissionId, SchemaIssue } from '../contract/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* The error every SDK call rejects with when the host refuses a request, or
|
|
4
|
+
* when the SDK catches a problem before sending it (bad params, a message
|
|
5
|
+
* over the size limit, a closed connection).
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* try {
|
|
9
|
+
* await card.agents.prompt(agentId, 'Run the tests')
|
|
10
|
+
* } catch (error) {
|
|
11
|
+
* if (isCardSdkError(error, 'NOT_CONNECTED')) card.ui.toast('Connect me to an agent first')
|
|
12
|
+
* else throw error
|
|
13
|
+
* }
|
|
14
|
+
*/
|
|
15
|
+
export declare class CardSdkError extends Error {
|
|
16
|
+
/** Machine-readable reason — one of `CARD_ERROR_CODES`. */
|
|
17
|
+
readonly code: CardErrorCode;
|
|
18
|
+
/** Extra details from the host (issues for INVALID_PARAMS, `{ permission }`, `{ retryAfterMs }`…). */
|
|
19
|
+
readonly data: unknown;
|
|
20
|
+
/** The API method that failed, when the error came from a call. */
|
|
21
|
+
readonly method: string | undefined;
|
|
22
|
+
/** The host's own message, without the method prefix and hint. */
|
|
23
|
+
readonly hostMessage: string;
|
|
24
|
+
/** A one-line suggestion for the developer, when there is one for this code. */
|
|
25
|
+
readonly hint: string | undefined;
|
|
26
|
+
constructor(code: CardErrorCode, message: string, data?: unknown, method?: string);
|
|
27
|
+
/** Builds the error from a wire error payload. */
|
|
28
|
+
static fromPayload(payload: CardErrorPayload, method?: string): CardSdkError;
|
|
29
|
+
/** For RATE_LIMITED: how long to wait before retrying, in ms. */
|
|
30
|
+
get retryAfterMs(): number | undefined;
|
|
31
|
+
/** For PERMISSION_DENIED: the permission that was missing. */
|
|
32
|
+
get permission(): PermissionId | undefined;
|
|
33
|
+
/** For INVALID_PARAMS / BAD_REQUEST: where the params did not match the method's schema. */
|
|
34
|
+
get issues(): SchemaIssue[] | undefined;
|
|
35
|
+
/** The wire form (`{ code, message, data? }`). */
|
|
36
|
+
toJSON(): CardErrorPayload;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Type guard for {@link CardSdkError}, optionally for one code.
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* if (isCardSdkError(error, 'RATE_LIMITED')) await sleep(error.retryAfterMs ?? 1000)
|
|
43
|
+
*/
|
|
44
|
+
export declare function isCardSdkError(error: unknown, code?: CardErrorCode): error is CardSdkError;
|
|
45
|
+
/** Short text of anything thrown, for logs and error replies. */
|
|
46
|
+
export declare function describeError(error: unknown): string;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type PeerInfo, type PermissionId, type PortTypeId } from '../contract/index.js';
|
|
2
|
+
import type { Card } from './card.js';
|
|
3
|
+
/** True when at least one arrow goes from this card to another (something can receive an emit). */
|
|
4
|
+
export declare function hasDownstreamPeer(peers: readonly PeerInfo[]): boolean;
|
|
5
|
+
/**
|
|
6
|
+
* The permission this card needs to send to `peer`: the permission of the
|
|
7
|
+
* input `input` (by id), or of the input an output of type `outputType`
|
|
8
|
+
* would land on, or of the peer's default input. `null` when none is needed
|
|
9
|
+
* (custom cards) or the peer has no such input.
|
|
10
|
+
*/
|
|
11
|
+
export declare function permissionForPeer(peer: PeerInfo, target?: {
|
|
12
|
+
input?: string;
|
|
13
|
+
outputType?: PortTypeId;
|
|
14
|
+
}): PermissionId | null;
|
|
15
|
+
/**
|
|
16
|
+
* Asks for the optional permissions not granted yet and resolves with the
|
|
17
|
+
* ids from `ids` that are usable now. Never throws: a refusal, a card that is
|
|
18
|
+
* not on screen (NOT_VISIBLE) or a closed connection all resolve with what
|
|
19
|
+
* is granted already.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* if ((await requestPermissions(card, 'cards.connected')).includes('cards.connected'))
|
|
23
|
+
* await card.ports.emit('summary', text)
|
|
24
|
+
*/
|
|
25
|
+
export declare function requestPermissions(card: Card, ...ids: PermissionId[]): Promise<PermissionId[]>;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { CardEvents, JsonValue, NetResponse } from '../contract/index.js';
|
|
2
|
+
/** How the host returns the body. `stream` resolves at headers and delivers chunks as they arrive. */
|
|
3
|
+
export type NetResponseType = 'text' | 'json' | 'base64' | 'stream';
|
|
4
|
+
/** Options of {@link CardNet.fetch}, modelled on `RequestInit`. */
|
|
5
|
+
export interface CardFetchInit {
|
|
6
|
+
method?: 'GET' | 'HEAD' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
7
|
+
/**
|
|
8
|
+
* Request headers. Values may contain `{{secret:<key>}}` — main substitutes
|
|
9
|
+
* the card's secret setting of that key (the card never sees the value).
|
|
10
|
+
*/
|
|
11
|
+
headers?: Record<string, string> | Iterable<readonly [string, string]>;
|
|
12
|
+
/**
|
|
13
|
+
* A string is sent as is; bytes (`Uint8Array`, `ArrayBuffer`) are sent as
|
|
14
|
+
* binary; any other JSON value is serialized and gets
|
|
15
|
+
* `content-type: application/json` unless you set one.
|
|
16
|
+
*/
|
|
17
|
+
body?: string | ArrayBuffer | ArrayBufferView | JsonValue;
|
|
18
|
+
/**
|
|
19
|
+
* `text` (default), `json` (parsed by the host; > 10 MB fails with TOO_LARGE),
|
|
20
|
+
* `base64` (binary), or `stream` (chunks as they arrive — SSE, NDJSON, long downloads).
|
|
21
|
+
*/
|
|
22
|
+
responseType?: NetResponseType;
|
|
23
|
+
/** Default 30 000, max 120 000. */
|
|
24
|
+
timeoutMs?: number;
|
|
25
|
+
/** Aborting cancels the request in the host (`net.abort`). */
|
|
26
|
+
signal?: AbortSignal;
|
|
27
|
+
}
|
|
28
|
+
/** Read-only response headers (names lowercased; `set-cookie` is never returned). */
|
|
29
|
+
export declare class CardHeaders implements Iterable<[string, string]> {
|
|
30
|
+
private readonly map;
|
|
31
|
+
constructor(headers: Record<string, string>);
|
|
32
|
+
/** The value of a header, case-insensitive, or null. */
|
|
33
|
+
get(name: string): string | null;
|
|
34
|
+
has(name: string): boolean;
|
|
35
|
+
forEach(callback: (value: string, name: string) => void): void;
|
|
36
|
+
entries(): IterableIterator<[string, string]>;
|
|
37
|
+
[Symbol.iterator](): IterableIterator<[string, string]>;
|
|
38
|
+
/** A plain object copy. */
|
|
39
|
+
toJSON(): Record<string, string>;
|
|
40
|
+
}
|
|
41
|
+
type Chunk = CardEvents['net.chunk'];
|
|
42
|
+
/** @internal Collects `net.chunk` events of one streamed request. */
|
|
43
|
+
export declare class ChunkQueue {
|
|
44
|
+
private readonly items;
|
|
45
|
+
private waiter;
|
|
46
|
+
private finished;
|
|
47
|
+
private failure;
|
|
48
|
+
push(chunk: Chunk): void;
|
|
49
|
+
fail(error: Error): void;
|
|
50
|
+
drain(): AsyncGenerator<Chunk>;
|
|
51
|
+
private wake;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* The result of `card.net.fetch()`: the familiar parts of `Response`.
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* const res = await card.net.fetch('https://api.github.com/repos/acme/app/issues')
|
|
58
|
+
* if (!res.ok) throw new Error(`GitHub said ${res.status}`)
|
|
59
|
+
* const issues = await res.json<{ title: string }[]>()
|
|
60
|
+
*
|
|
61
|
+
* @example Streaming (server-sent events)
|
|
62
|
+
* const res = await card.net.fetch(url, { responseType: 'stream' })
|
|
63
|
+
* for await (const line of res.lines()) if (line.startsWith('data: ')) render(line.slice(6))
|
|
64
|
+
*/
|
|
65
|
+
export declare class CardResponse {
|
|
66
|
+
private readonly raw;
|
|
67
|
+
private readonly stream;
|
|
68
|
+
/** HTTP status code. */
|
|
69
|
+
readonly status: number;
|
|
70
|
+
readonly statusText: string;
|
|
71
|
+
/** `status` in 200–299. */
|
|
72
|
+
readonly ok: boolean;
|
|
73
|
+
/** Final URL after redirects. */
|
|
74
|
+
readonly url: string;
|
|
75
|
+
readonly headers: CardHeaders;
|
|
76
|
+
/** The body was longer than the limit and was cut (text/base64 only). */
|
|
77
|
+
readonly truncated: boolean;
|
|
78
|
+
/** The id `net.abort` and stream chunks use. */
|
|
79
|
+
readonly requestId: string;
|
|
80
|
+
/** How the body was requested. */
|
|
81
|
+
readonly type: NetResponseType;
|
|
82
|
+
private used;
|
|
83
|
+
/** @internal */
|
|
84
|
+
constructor(raw: NetResponse, type: NetResponseType, stream: ChunkQueue | null);
|
|
85
|
+
/** True once a body method was called (a body can be read once, like `Response`). */
|
|
86
|
+
get bodyUsed(): boolean;
|
|
87
|
+
/** The body as text (base64 bodies are decoded as UTF-8). */
|
|
88
|
+
text(): Promise<string>;
|
|
89
|
+
/** The body parsed as JSON. Throws a SyntaxError for a body that is not JSON. */
|
|
90
|
+
json<T = JsonValue>(): Promise<T>;
|
|
91
|
+
/** The body as bytes. */
|
|
92
|
+
bytes(): Promise<Uint8Array>;
|
|
93
|
+
/** The body as an ArrayBuffer. */
|
|
94
|
+
arrayBuffer(): Promise<ArrayBuffer>;
|
|
95
|
+
/**
|
|
96
|
+
* Chunks of a `responseType: 'stream'` response as they arrive: strings for
|
|
97
|
+
* text chunks, `Uint8Array` for binary ones. Ends when the host sends the
|
|
98
|
+
* last chunk; throws a CardSdkError (NETWORK_ERROR) if the stream fails.
|
|
99
|
+
*/
|
|
100
|
+
chunks(): AsyncGenerator<string | Uint8Array>;
|
|
101
|
+
/** Lines of the body (`\n` or `\r\n`), streamed when the response is a stream. */
|
|
102
|
+
lines(): AsyncGenerator<string>;
|
|
103
|
+
/** Same as {@link chunks}: `for await (const chunk of response)`. */
|
|
104
|
+
[Symbol.asyncIterator](): AsyncGenerator<string | Uint8Array>;
|
|
105
|
+
private consume;
|
|
106
|
+
}
|
|
107
|
+
/** @internal Converts init into net.fetch params. */
|
|
108
|
+
export declare function fetchParams(url: string, init: CardFetchInit, requestId: string): Record<string, JsonValue>;
|
|
109
|
+
/** @internal Unique enough request ids for net.fetch. */
|
|
110
|
+
export declare function newRequestId(): string;
|
|
111
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { type ThemeSnapshot } from '../contract/index.js';
|
|
2
|
+
/** Anything with an inline style — `document.documentElement` by default. */
|
|
3
|
+
export interface ThemeTarget {
|
|
4
|
+
style: {
|
|
5
|
+
setProperty(name: string, value: string): void;
|
|
6
|
+
colorScheme?: string;
|
|
7
|
+
};
|
|
8
|
+
dataset?: Record<string, string | undefined>;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Writes the app's theme onto an element as CSS variables, so a card can look
|
|
12
|
+
* native without guessing colours:
|
|
13
|
+
*
|
|
14
|
+
* - `--ns-<token>` for every {@link THEME_TOKENS} entry (`--ns-accent`, `--ns-surface`, `--ns-radius`…)
|
|
15
|
+
* - `--ns-font-sans`, `--ns-font-mono`
|
|
16
|
+
* - `color-scheme` and `data-ns-scheme="dark|light"`
|
|
17
|
+
*
|
|
18
|
+
* `connect()` calls it for you on start and on every `theme.changed` (pass
|
|
19
|
+
* `{ theme: false }` to opt out). The optional `ui.css` kit reads these
|
|
20
|
+
* variables.
|
|
21
|
+
*
|
|
22
|
+
* @param theme The snapshot from `card.context.theme`, `card.theme.get()` or a `theme.changed` event.
|
|
23
|
+
* @param target Where to write the variables. Default: `document.documentElement`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function applyTheme(theme: ThemeSnapshot, target?: ThemeTarget): void;
|
|
26
|
+
/**
|
|
27
|
+
* The app's dark theme as it ships (HeroUI v3 dark tokens, resolved). Used by
|
|
28
|
+
* the mock host and as the fallback values baked into `ui.css`; a live card
|
|
29
|
+
* always gets the real computed values from the host.
|
|
30
|
+
*/
|
|
31
|
+
export declare const DEFAULT_DARK_THEME: ThemeSnapshot;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { ToolResultPayload } from '../contract/index.js';
|
|
2
|
+
/** A text tool result. Same as returning the string from a tool handler. */
|
|
3
|
+
export declare function toolText(text: string): ToolResultPayload;
|
|
4
|
+
/**
|
|
5
|
+
* An image tool result (base64 data), optionally with a caption.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* return toolImage(bytesToBase64(png), 'image/png', 'Current chart')
|
|
9
|
+
*/
|
|
10
|
+
export declare function toolImage(data: string, mimeType: 'image/png' | 'image/jpeg' | 'image/webp' | 'image/gif', caption?: string): ToolResultPayload;
|
|
11
|
+
/**
|
|
12
|
+
* A result the agent sees as a failed tool call (`isError: true`) — for
|
|
13
|
+
* expected failures you want to explain to the model. Throwing from a
|
|
14
|
+
* handler does the same with the error's message.
|
|
15
|
+
*/
|
|
16
|
+
export declare function toolError(message: string): ToolResultPayload;
|