dyadic 1.8.1 → 1.8.2

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 CHANGED
@@ -1,140 +1,154 @@
1
- # Changelog
2
-
3
- ## 1.8.1 (2026-10-17)
4
-
5
- - `client.blackbox.overview(7 | 30)`: the Black Box overview of the last 7 days (the default) or 30. Each count is what `runs.list` gives with
6
- the same filter and range.
7
- - `runs.list` documents the `gaps` filter (`"1"`: only runs whose record has a gap).
8
-
9
- ## 1.8.0 (2026-10-17)
10
-
11
- The Black Box as an execution record.
12
-
13
- - `client.blackbox.runs.lineage(id)`: the file versions a run made (`path`, `sha256`, `previous`, the tool call), each with the plan steps under
14
- way when it was made (observed, never a claim that the step caused it), and the steps the run moved. A key needs its
15
- Black Box content switch.
16
- - A run (`runs.retrieve`) now carries `actor` (who started it, beside its owner), `costs` (from the usage ledger:
17
- credits charged and held, the provider's cost as reported or estimated, cache use; for the key that made it) and
18
- `links` (its batch, the plans and steps it moved, re-runs, simulations); its `outcome` is verification alone
19
- (`verified`, `contradicted`, `unverified`, `blocked`, `not_applicable`), apart from how it ended (`status`).
20
-
21
- ## 1.7.1 (2026-10-17)
22
-
23
- - Corrected: `anthropic.messages.batches.create` described message batches as running at half price. Dyadic runs them in the
24
- background at the usual price; nothing about the calls changed.
25
-
26
- ## 1.7.0 (2026-10-17)
27
-
28
- The Anthropic API and OpenRouter's.
29
-
30
- - `client.anthropic`: the Anthropic API at `/api/anthropic/v1`, beside the base URL, with the client's key and
31
- `anthropic-version: 2023-06-01`: `messages.create` (Anthropic's answer; with `stream: true` its events, the stream's
32
- `text` from the text blocks and `usage` from `message_start` and `message_delta`), `messages.countTokens`,
33
- `messages.batches.create/list/retrieve/cancel/results/delete` (`results` parses the JSONL), `models.list/retrieve` and
34
- `files.create/list/retrieve/content/delete`, with types (`AnthropicMessage`, `AnthropicStreamEvent`, `AnthropicBatch`, ...).
35
- - `client.openrouter`: OpenRouter's API through the AI gateway at `/api/openrouter/v1`: `chat.completions.create`,
36
- `completions.create`, `embeddings.create`, `models.list/endpoints`, `generation(id)`, `key()` and `credits()` (both
37
- answered by Dyadic). A key without the gateway throws `DyadicError` with status 403 and code `gateway_not_allowed`:
38
- Dyadic turns the gateway on for an app's key on request.
39
- - `Stream<T, U = Usage>`: a stream's usage type is its own (an Anthropic stream's is `AnthropicUsage`); existing code
40
- is unchanged.
41
- - Packaging: the package carries its MIT license text (`LICENSE`).
42
- - Tests: `npm test` runs only the mocked suite (`test/`); `npm run test:production` checks a real API with `DYADIC_LIVE_API_KEY`.
43
-
44
- ## 1.6.0 (2026-10-15)
45
-
46
- One trace per turn.
47
-
48
- - `useTrace()`: every following request carries the same W3C `traceparent`, so Dyadic shows a turn's decision, model
49
- calls and run as one in API Activity and the Black Box; `currentTraceparent()` for requests sent another way. A call's
50
- own `traceparent` header still wins.
51
-
52
- ## 1.5.0 (2026-10-14)
53
-
54
- Plans.
55
-
56
- - `client.plans` (the key's plans switch): `list({ conversation, status, limit, after })`, `create({ title, steps, summary,
57
- mode, conversation, metadata })`, `retrieve`, `update(id, { revision, ... })` (409 if the plan moved on since),
58
- `approve(id, { revision })`, `cancel`, `moveStep(id, key, { status, note, verified_by })` and `events(id, { after, limit })`.
59
- - `client.plans.stream(id, { after, signal })`: the plan live, an async generator of `{ event, id, data }`: `plan.snapshot`
60
- on each connection, then `plan.created`, `plan.approved`, `plan.step`, ... with the plan as it is then. It connects again
61
- when the service asks or the connection drops, resuming after the last event (`Last-Event-ID`), stops after `end` (the
62
- plan completed, cancelled or failed), and honors an AbortSignal.
63
- - `runs.create({ planMode: true })` investigates read-only and proposes a plan; `runs.create({ planId })` carries out an
64
- approved plan (refused with `plan_not_runnable` otherwise). Sent as `plan_mode` and `plan_id`, which `RunParams` also
65
- takes. Streamed runs send `plan.updated` (`RunEvent.plan`); a completed run lists the plans it touched (`Run.plans`).
66
- - Types: `Plan`, `PlanStep`, `PlanEvent`, `PlanStatus`, `PlanStepStatus`, `PlanStepInput`, `PlanCreateParams`,
67
- `PlanUpdateParams`, `PlanListQuery`, `PlanStreamEvent`; `BuiltinTool` includes `plans.propose`, `plans.step` and `plans.get`.
68
-
69
- ## 1.4.0 (2026-10-14)
70
-
71
- Agent Black Box.
72
-
73
- - `BlackBoxRecorder`: record your own agent's runs (model calls, tool calls, subagents, policy
74
- decisions, approvals, verified outcomes) into `POST /v1/blackbox/events`, without blocking it:
75
- bounded queue, batches with an `Idempotency-Key`, per-process sequence numbers so lost events show
76
- as gaps, metadata only unless `captureContent: true` (secrets redacted first).
77
- - W3C trace context: `span.traceparent()`, `recorder.start({ traceparent })` for remote subagents.
78
- - `instrumentMcpClient` (MCP tool calls).
79
- - `BlackBoxSpanExporter`: an OpenTelemetry `SpanExporter` (SDK 1.x and 2.x, no runtime dependency) that sends
80
- GenAI and OpenInference spans as OTLP/JSON; content attributes only with `captureContent: true`, values redacted
81
- first, batches split to fit the service. `spanToOtlp` and `toOtlpRequests` convert without sending.
82
- - `client.blackbox`: `send`, `sendOtlp`, `runs.list/retrieve/events/graph/verify/export/otlp/simulate`,
83
- `findings`, `diff`, `keys`, `verify`.
84
- - `verifyBundle`: check an evidence bundle offline (WebCrypto Ed25519; Node 18+, browsers). It also checks a bundle's
85
- anchors: the anchored checkpoint is in the bundle's log at or after the run's last checkpoint, the Merkle proof leads to
86
- the root, and the RFC 3161 token's messageImprint is that root (its genTime is reported). The authority's signature on the
87
- token is not checked in TypeScript, and the report's warnings say so. `readTimestampToken`, `anchorLeaf`, `foldProof`.
88
- - `client.blackbox` covers every route of the service: `overview`, `settings`, `runs.checkpoints/content/erase/delete`,
89
- `runs.events({ types })`, `bookmarks.list/create/delete`, `findings.list/update` (calling `findings(query)` still works),
90
- `rules.list/preview`, `sinks.list/create/retrieve/update/delete/test/rotate/deliveries/retryDelivery`; `sendOtlp(bytes)`
91
- sends OTLP protobuf.
92
- - Live streams: `client.blackbox.runs.stream(id, { after, signal })` and `client.blackbox.watch({ signal })`, async generators
93
- of `{ event, id, data }` over fetch and ReadableStream that connect again when the service asks or the connection drops
94
- (resuming after the last event), stop after `end` or `deleted`, and honor an AbortSignal.
95
- - `verifyWebhook(body, headers, secret, { tolerance })` checks a webhook sink's Standard Webhooks signature (WebCrypto HMAC,
96
- constant-time, several signatures, 5 minutes by default) and returns the message; `signWebhook`, `WebhookVerificationError`.
97
- - `RunDeletedError` (a `DyadicError`): a run of the key's that was deleted (HTTP 410, `run_deleted`), with `deletion`.
98
- - The rest of the OpenAI-compatible API: `conversations` (and `items`), stored chat completions (`chat.completions.list/
99
- retrieve/update/delete`, `messages.list`), `responses.inputTokens.count` and `responses.compact`, `containers` (and
100
- `files`), `vectorStores` (`files`, `fileBatches`, `search`) and `skills` (and `versions`).
101
- - `request()` takes `headers`, a raw `content` body and an AbortSignal (`signal`); query values may be arrays.
102
- - `BuiltinTool` includes `audio.speak` and `audio.transcribe`; `ResponseParams` has `conversation` and `background`.
103
-
104
- Fixes:
105
-
106
- - Leaving a `for await` over a stream early (`break`, `return`, a throw) only released the reader: the HTTP request, and the
107
- completion it was paying for, kept running. It now cancels the body and aborts the request.
108
- - Requests say who calls: `User-Agent: dyadic-typescript/<version>`, except in browsers (which don't allow it).
109
- - The README's connected-apps example compiles (`error.body` is `unknown`).
110
-
111
- ## 1.3.1 (2026-10-10)
112
-
113
- - The version the SDK reports (`__version__` / `VERSION`, and the User-Agent header) is the package's
114
- own: 1.3.0 still said 1.2.0.
115
-
116
- ## 1.3.0 (2026-10-10)
117
-
118
- - `decisions.create(input, questions, model?)`: typed answers (a predicate's probability, a
119
- choice or a score) from `POST /v1/decisions`.
120
-
121
- ## 1.2.0 (2026-10-07)
122
-
123
- Security release.
124
-
125
- - The API key is only ever sent to the configured API origin. `request()` with an
126
- absolute URL on another host, port or scheme, with credentials in it, or
127
- protocol-relative, now raises instead of sending the key; redirects are not
128
- followed. Plain `http://` base URLs are accepted only for local or
129
- private-network APIs.
130
- - Retries no longer repeat work that may already have run. GET, HEAD, DELETE and
131
- OPTIONS retry on busy or failing servers; other requests retry only when they
132
- never started (no connection, or Dyadic's `rate_limit_exceeded` /
133
- `concurrency_limit` refusal). `409` is no longer retried.
134
- - Every attempt of one call sends the same `Idempotency-Key` (choose it with
135
- `{ idempotencyKey }`, or mark a call safe to replay with `{ idempotent: true }`).
136
- - 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.
137
-
138
- ## 1.1.0
139
-
140
- - Runs with your own agents and functions, and connected apps (Workspace saves).
1
+ # Changelog
2
+
3
+ ## 1.8.2 (2026-10-18)
4
+
5
+ - A streamed run is no longer aborted at `timeoutMs` while it is still answering: the deadline covers the headers, and a
6
+ stream is then held to silence (`timeoutMs` between chunks; the service sends a keep-alive every 15 s). A stream that
7
+ ends before its final event throws `DyadicError` ("The stream ended before the answer finished") instead of resolving
8
+ with the text so far; a frame that isn't JSON, or a dropped connection, throws `DyadicError` instead of a bare error.
9
+ - `client.blackbox.runs.options()`, `client.blackbox.openapi()` (the platform API's description). `Run` names `blackbox`,
10
+ `audio` and `finish_reason`; `RunParams` takes `effort`; `PlanEvent.kind` includes `patched`.
11
+ - `verifyBundle` is stricter and never throws: a bundle no valid checkpoint covers is not verified (before, a warning and
12
+ `ok: true`); a cut-off tail is caught by the run's recorded head (`manifest`) and the account's checkpoint log's entries
13
+ about the run; each of the run's checkpoints is compared with the log's entry of the same number, so one signed again
14
+ later shows as a mismatch; a checkpoint issued after its key was retired doesn't count; a damaged or hostile bundle is
15
+ reported, never an exception. The contract fixture bundle now carries its `manifest`.
16
+
17
+ ## 1.8.1 (2026-10-17)
18
+
19
+ - `client.blackbox.overview(7 | 30)`: the Black Box overview of the last 7 days (the default) or 30. Each count is what `runs.list` gives with
20
+ the same filter and range.
21
+ - `runs.list` documents the `gaps` filter (`"1"`: only runs whose record has a gap).
22
+
23
+ ## 1.8.0 (2026-10-17)
24
+
25
+ The Black Box as an execution record.
26
+
27
+ - `client.blackbox.runs.lineage(id)`: the file versions a run made (`path`, `sha256`, `previous`, the tool call), each with the plan steps under
28
+ way when it was made (observed, never a claim that the step caused it), and the steps the run moved. A key needs its
29
+ Black Box content switch.
30
+ - A run (`runs.retrieve`) now carries `actor` (who started it, beside its owner), `costs` (from the usage ledger:
31
+ credits charged and held, the provider's cost as reported or estimated, cache use; for the key that made it) and
32
+ `links` (its batch, the plans and steps it moved, re-runs, simulations); its `outcome` is verification alone
33
+ (`verified`, `contradicted`, `unverified`, `blocked`, `not_applicable`), apart from how it ended (`status`).
34
+
35
+ ## 1.7.1 (2026-10-17)
36
+
37
+ - Corrected: `anthropic.messages.batches.create` described message batches as running at half price. Dyadic runs them in the
38
+ background at the usual price; nothing about the calls changed.
39
+
40
+ ## 1.7.0 (2026-10-17)
41
+
42
+ The Anthropic API and OpenRouter's.
43
+
44
+ - `client.anthropic`: the Anthropic API at `/api/anthropic/v1`, beside the base URL, with the client's key and
45
+ `anthropic-version: 2023-06-01`: `messages.create` (Anthropic's answer; with `stream: true` its events, the stream's
46
+ `text` from the text blocks and `usage` from `message_start` and `message_delta`), `messages.countTokens`,
47
+ `messages.batches.create/list/retrieve/cancel/results/delete` (`results` parses the JSONL), `models.list/retrieve` and
48
+ `files.create/list/retrieve/content/delete`, with types (`AnthropicMessage`, `AnthropicStreamEvent`, `AnthropicBatch`, ...).
49
+ - `client.openrouter`: OpenRouter's API through the AI gateway at `/api/openrouter/v1`: `chat.completions.create`,
50
+ `completions.create`, `embeddings.create`, `models.list/endpoints`, `generation(id)`, `key()` and `credits()` (both
51
+ answered by Dyadic). A key without the gateway throws `DyadicError` with status 403 and code `gateway_not_allowed`:
52
+ Dyadic turns the gateway on for an app's key on request.
53
+ - `Stream<T, U = Usage>`: a stream's usage type is its own (an Anthropic stream's is `AnthropicUsage`); existing code
54
+ is unchanged.
55
+ - Packaging: the package carries its MIT license text (`LICENSE`).
56
+ - Tests: `npm test` runs only the mocked suite (`test/`); `npm run test:production` checks a real API with `DYADIC_LIVE_API_KEY`.
57
+
58
+ ## 1.6.0 (2026-10-15)
59
+
60
+ One trace per turn.
61
+
62
+ - `useTrace()`: every following request carries the same W3C `traceparent`, so Dyadic shows a turn's decision, model
63
+ calls and run as one in API Activity and the Black Box; `currentTraceparent()` for requests sent another way. A call's
64
+ own `traceparent` header still wins.
65
+
66
+ ## 1.5.0 (2026-10-14)
67
+
68
+ Plans.
69
+
70
+ - `client.plans` (the key's plans switch): `list({ conversation, status, limit, after })`, `create({ title, steps, summary,
71
+ mode, conversation, metadata })`, `retrieve`, `update(id, { revision, ... })` (409 if the plan moved on since),
72
+ `approve(id, { revision })`, `cancel`, `moveStep(id, key, { status, note, verified_by })` and `events(id, { after, limit })`.
73
+ - `client.plans.stream(id, { after, signal })`: the plan live, an async generator of `{ event, id, data }`: `plan.snapshot`
74
+ on each connection, then `plan.created`, `plan.approved`, `plan.step`, ... with the plan as it is then. It connects again
75
+ when the service asks or the connection drops, resuming after the last event (`Last-Event-ID`), stops after `end` (the
76
+ plan completed, cancelled or failed), and honors an AbortSignal.
77
+ - `runs.create({ planMode: true })` investigates read-only and proposes a plan; `runs.create({ planId })` carries out an
78
+ approved plan (refused with `plan_not_runnable` otherwise). Sent as `plan_mode` and `plan_id`, which `RunParams` also
79
+ takes. Streamed runs send `plan.updated` (`RunEvent.plan`); a completed run lists the plans it touched (`Run.plans`).
80
+ - Types: `Plan`, `PlanStep`, `PlanEvent`, `PlanStatus`, `PlanStepStatus`, `PlanStepInput`, `PlanCreateParams`,
81
+ `PlanUpdateParams`, `PlanListQuery`, `PlanStreamEvent`; `BuiltinTool` includes `plans.propose`, `plans.step` and `plans.get`.
82
+
83
+ ## 1.4.0 (2026-10-14)
84
+
85
+ Agent Black Box.
86
+
87
+ - `BlackBoxRecorder`: record your own agent's runs (model calls, tool calls, subagents, policy
88
+ decisions, approvals, verified outcomes) into `POST /v1/blackbox/events`, without blocking it:
89
+ bounded queue, batches with an `Idempotency-Key`, per-process sequence numbers so lost events show
90
+ as gaps, metadata only unless `captureContent: true` (secrets redacted first).
91
+ - W3C trace context: `span.traceparent()`, `recorder.start({ traceparent })` for remote subagents.
92
+ - `instrumentMcpClient` (MCP tool calls).
93
+ - `BlackBoxSpanExporter`: an OpenTelemetry `SpanExporter` (SDK 1.x and 2.x, no runtime dependency) that sends
94
+ GenAI and OpenInference spans as OTLP/JSON; content attributes only with `captureContent: true`, values redacted
95
+ first, batches split to fit the service. `spanToOtlp` and `toOtlpRequests` convert without sending.
96
+ - `client.blackbox`: `send`, `sendOtlp`, `runs.list/retrieve/events/graph/verify/export/otlp/simulate`,
97
+ `findings`, `diff`, `keys`, `verify`.
98
+ - `verifyBundle`: check an evidence bundle offline (WebCrypto Ed25519; Node 18+, browsers). It also checks a bundle's
99
+ anchors: the anchored checkpoint is in the bundle's log at or after the run's last checkpoint, the Merkle proof leads to
100
+ the root, and the RFC 3161 token's messageImprint is that root (its genTime is reported). The authority's signature on the
101
+ token is not checked in TypeScript, and the report's warnings say so. `readTimestampToken`, `anchorLeaf`, `foldProof`.
102
+ - `client.blackbox` covers every route of the service: `overview`, `settings`, `runs.checkpoints/content/erase/delete`,
103
+ `runs.events({ types })`, `bookmarks.list/create/delete`, `findings.list/update` (calling `findings(query)` still works),
104
+ `rules.list/preview`, `sinks.list/create/retrieve/update/delete/test/rotate/deliveries/retryDelivery`; `sendOtlp(bytes)`
105
+ sends OTLP protobuf.
106
+ - Live streams: `client.blackbox.runs.stream(id, { after, signal })` and `client.blackbox.watch({ signal })`, async generators
107
+ of `{ event, id, data }` over fetch and ReadableStream that connect again when the service asks or the connection drops
108
+ (resuming after the last event), stop after `end` or `deleted`, and honor an AbortSignal.
109
+ - `verifyWebhook(body, headers, secret, { tolerance })` checks a webhook sink's Standard Webhooks signature (WebCrypto HMAC,
110
+ constant-time, several signatures, 5 minutes by default) and returns the message; `signWebhook`, `WebhookVerificationError`.
111
+ - `RunDeletedError` (a `DyadicError`): a run of the key's that was deleted (HTTP 410, `run_deleted`), with `deletion`.
112
+ - The rest of the OpenAI-compatible API: `conversations` (and `items`), stored chat completions (`chat.completions.list/
113
+ retrieve/update/delete`, `messages.list`), `responses.inputTokens.count` and `responses.compact`, `containers` (and
114
+ `files`), `vectorStores` (`files`, `fileBatches`, `search`) and `skills` (and `versions`).
115
+ - `request()` takes `headers`, a raw `content` body and an AbortSignal (`signal`); query values may be arrays.
116
+ - `BuiltinTool` includes `audio.speak` and `audio.transcribe`; `ResponseParams` has `conversation` and `background`.
117
+
118
+ Fixes:
119
+
120
+ - Leaving a `for await` over a stream early (`break`, `return`, a throw) only released the reader: the HTTP request, and the
121
+ completion it was paying for, kept running. It now cancels the body and aborts the request.
122
+ - Requests say who calls: `User-Agent: dyadic-typescript/<version>`, except in browsers (which don't allow it).
123
+ - The README's connected-apps example compiles (`error.body` is `unknown`).
124
+
125
+ ## 1.3.1 (2026-10-10)
126
+
127
+ - The version the SDK reports (`__version__` / `VERSION`, and the User-Agent header) is the package's
128
+ own: 1.3.0 still said 1.2.0.
129
+
130
+ ## 1.3.0 (2026-10-10)
131
+
132
+ - `decisions.create(input, questions, model?)`: typed answers (a predicate's probability, a
133
+ choice or a score) from `POST /v1/decisions`.
134
+
135
+ ## 1.2.0 (2026-10-07)
136
+
137
+ Security release.
138
+
139
+ - The API key is only ever sent to the configured API origin. `request()` with an
140
+ absolute URL on another host, port or scheme, with credentials in it, or
141
+ protocol-relative, now raises instead of sending the key; redirects are not
142
+ followed. Plain `http://` base URLs are accepted only for local or
143
+ private-network APIs.
144
+ - Retries no longer repeat work that may already have run. GET, HEAD, DELETE and
145
+ OPTIONS retry on busy or failing servers; other requests retry only when they
146
+ never started (no connection, or Dyadic's `rate_limit_exceeded` /
147
+ `concurrency_limit` refusal). `409` is no longer retried.
148
+ - Every attempt of one call sends the same `Idempotency-Key` (choose it with
149
+ `{ idempotencyKey }`, or mark a call safe to replay with `{ idempotent: true }`).
150
+ - 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.
151
+
152
+ ## 1.1.0
153
+
154
+ - Runs with your own agents and functions, and connected apps (Workspace saves).
package/LICENSE CHANGED
@@ -1,21 +1,21 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Dyadic
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Dyadic
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.