@inferior-ai/sdk 2.0.0-beta.3

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.
Files changed (52) hide show
  1. package/CHANGELOG.md +70 -0
  2. package/LICENSE.md +37 -0
  3. package/NOTICE.md +56 -0
  4. package/README.md +454 -0
  5. package/SECURITY.md +62 -0
  6. package/STABILITY.md +95 -0
  7. package/SUPPORT.md +66 -0
  8. package/dist/__tests__/with_mock_client.test.d.ts +9 -0
  9. package/dist/__tests__/with_mock_client.test.d.ts.map +1 -0
  10. package/dist/__tests__/with_mock_client.test.js +154 -0
  11. package/dist/__tests__/with_mock_client.test.js.map +1 -0
  12. package/dist/_worthiness.d.ts +34 -0
  13. package/dist/_worthiness.d.ts.map +1 -0
  14. package/dist/_worthiness.js +201 -0
  15. package/dist/_worthiness.js.map +1 -0
  16. package/dist/client.d.ts +155 -0
  17. package/dist/client.d.ts.map +1 -0
  18. package/dist/client.js +900 -0
  19. package/dist/client.js.map +1 -0
  20. package/dist/constants.d.ts +31 -0
  21. package/dist/constants.d.ts.map +1 -0
  22. package/dist/constants.js +35 -0
  23. package/dist/constants.js.map +1 -0
  24. package/dist/errors.d.ts +71 -0
  25. package/dist/errors.d.ts.map +1 -0
  26. package/dist/errors.js +114 -0
  27. package/dist/errors.js.map +1 -0
  28. package/dist/index.d.ts +8 -0
  29. package/dist/index.d.ts.map +1 -0
  30. package/dist/index.js +7 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/models.d.ts +603 -0
  33. package/dist/models.d.ts.map +1 -0
  34. package/dist/models.js +10 -0
  35. package/dist/models.js.map +1 -0
  36. package/dist/retry.d.ts +35 -0
  37. package/dist/retry.d.ts.map +1 -0
  38. package/dist/retry.js +83 -0
  39. package/dist/retry.js.map +1 -0
  40. package/dist/testing/index.d.ts +16 -0
  41. package/dist/testing/index.d.ts.map +1 -0
  42. package/dist/testing/index.js +15 -0
  43. package/dist/testing/index.js.map +1 -0
  44. package/dist/testing/mock-client.d.ts +102 -0
  45. package/dist/testing/mock-client.d.ts.map +1 -0
  46. package/dist/testing/mock-client.js +217 -0
  47. package/dist/testing/mock-client.js.map +1 -0
  48. package/dist/webhooks.d.ts +52 -0
  49. package/dist/webhooks.d.ts.map +1 -0
  50. package/dist/webhooks.js +90 -0
  51. package/dist/webhooks.js.map +1 -0
  52. package/package.json +61 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,70 @@
1
+ # Changelog
2
+
3
+ All notable changes to this package are documented here. The format is
4
+ based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and
5
+ the package adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ Pre-1.0 / beta releases may make breaking changes between successive
8
+ beta versions; see [`STABILITY.md`](./STABILITY.md) for graduation
9
+ criteria. Customers should pin to an exact version (e.g.,
10
+ `npm install @inferior-ai/sdk@beta`).
11
+
12
+ ## [Unreleased]
13
+
14
+ ## [2.0.0-beta.3] — 2026-04-28
15
+
16
+ ### Added
17
+
18
+ - **`@inferior-ai/sdk/testing` subpath export** — `MockInferiorClient` lets you write tests against the SDK without hitting the network. Stubs queued via `mockSearch()`, `mockDeposit()`, `mockDepositRaw()`, `mockFeedback()`, `mockError()`, or the generic `addResponse()`. Inspect what your code under test sent via `client.calls`, an array of `RecordedCall` objects (method, url, headers (Headers), body, bodyJson).
19
+ - **`fetch?: typeof fetch` option** in `ClientOptions` — hidden hook used by the testing helper to intercept requests. Production code should leave this unset.
20
+ - New utilities exported from `@inferior-ai/sdk/testing`: `MockInferiorClient`, `RecordedCall` (type), `MockClientOptions` (type).
21
+
22
+ ### Changed
23
+
24
+ - The `depositFile()` method now routes its multipart `POST` through the same `fetcher` as other requests; previously it called the global `fetch` directly. Production behaviour is unchanged because `fetcher` defaults to global `fetch`.
25
+ - `ClientOptions` is now exported from the package root (was internal). No behaviour change.
26
+
27
+ ## [2.0.0-beta.2] — 2026-04-28
28
+
29
+ ### Added
30
+
31
+ - **API-version mismatch warning** — when the backend's `X-Inferior-Resolved-Version` response header differs from the SDK's compiled `INFERIOR_API_VERSION`, the client emits one `console.warn` per `InferiorClient` instance. Hook lives in the request path so it fires on every endpoint with no per-call instrumentation. Backend B2 shipped 2026-04-28; this completes the version-handshake contract on the client side.
32
+
33
+ ## [2.0.0-beta.1] — 2026-04-28
34
+
35
+ ### Added
36
+
37
+ - **User-Agent header** on every request (`inferior-sdk-ts/<v> node/<v> <platform>`).
38
+ - **`Inferior-Version: 2026-04-28` header** on every request — forward-compatible with backend version handshake (Phase B2).
39
+ - **`requestId` propagation on errors** — every `InferiorError` subclass now carries the `X-Request-ID` from the failed response. `error.toString()` includes it for log readability.
40
+ - **Retry / backoff** — built-in retry for 429 / 5xx on idempotent requests (GET / HEAD / OPTIONS, plus writes carrying an `Idempotency-Key`). Defaults: 3 attempts, 0.5s base, 0.2 jitter, 30s cap. Honours `Retry-After`. Configurable via `new InferiorClient({ retry: { maxAttempts: 5 } })` or disabled with `retry: false`.
41
+ - **`idempotencyKey` field** on `DepositInput` and `RawDepositInput` — sent as the `Idempotency-Key` header. Backend dedup pending (Phase B1).
42
+ - **`verify(body, signatureHeader, secret, options?)`** — exported from package root. Validates `X-Inferior-Signature: sha256=<hex>` webhook signatures using HMAC-SHA256, with replay protection via event timestamp. Throws `InvalidSignatureError`.
43
+ - New constants exported from package root: `INFERIOR_API_VERSION`, `USER_AGENT`, `SDK_VERSION`, `DEFAULT_RETRY`.
44
+
45
+ ### Changed
46
+
47
+ - `InferiorError` constructor now accepts a 5th positional `requestId` argument. All subclass constructors forward it. Existing callers passing 4 positional args are unaffected.
48
+
49
+ ### Internal
50
+
51
+ - New modules: `src/constants.ts`, `src/retry.ts`, `src/webhooks.ts`.
52
+
53
+ ## [2.0.0-beta.0] — 2026-04-28
54
+
55
+ ### Added
56
+
57
+ - Initial beta release of `@inferior-ai/sdk` against Inferior backend `schema_version 2.0.0`. See [`sdk-updates-plan.md`](https://inferior.ai/legal/sdk-history) for the full Phase A–G surface this build covers.
58
+
59
+ ### Notes
60
+
61
+ - This is a beta release. APIs may change before the `2.0.0` stable
62
+ graduation. Pin exactly.
63
+ - Source repo is private; report bugs to `support@inferior.ai`,
64
+ security issues to `security@inferior.ai`.
65
+
66
+ [Unreleased]: https://inferior.ai/legal/changelog
67
+ [2.0.0-beta.3]: https://inferior.ai/legal/changelog#2.0.0-beta.3
68
+ [2.0.0-beta.2]: https://inferior.ai/legal/changelog#2.0.0-beta.2
69
+ [2.0.0-beta.1]: https://inferior.ai/legal/changelog#2.0.0-beta.1
70
+ [2.0.0-beta.0]: https://inferior.ai/legal/changelog#2.0.0-beta.0
package/LICENSE.md ADDED
@@ -0,0 +1,37 @@
1
+ # License — inferior-sdk-ts
2
+
3
+ Copyright (c) 2026 Inferior Limited. All rights reserved.
4
+
5
+ This software is licensed, not sold. Permitted use is limited to:
6
+
7
+ 1. Installing this package via official PyPI / npm registries.
8
+ 2. Integrating it into applications that consume the Inferior service.
9
+
10
+ The following are prohibited without prior written consent from Inferior Inc:
11
+
12
+ - Redistribution of this package or any modified version.
13
+ - Decompilation or reverse engineering of the package.
14
+ - Use of this package, in whole or in part, to build or operate a service competitive with Inferior.
15
+ - Removal or alteration of this notice.
16
+
17
+ This license does not grant rights to the Inferior trademarks, service
18
+ marks, or trade dress. Use of those is governed separately under
19
+ [https://inferior.ai/legal/brand](https://inferior.ai/legal/brand).
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22
+ OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
24
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
25
+ CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26
+ TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE
27
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28
+
29
+ ---
30
+
31
+ For the full Inferior service terms, see [https://inferior.ai/legal/terms](https://inferior.ai/legal/terms).
32
+
33
+ | Inquiry | Contact |
34
+ | --------- | ---------------------- |
35
+ | Licensing | `legal@inferior.ai` |
36
+ | Security | `security@inferior.ai` |
37
+ | Support | `support@inferior.ai` |
package/NOTICE.md ADDED
@@ -0,0 +1,56 @@
1
+ # Third-party notices — inferior-sdk-ts
2
+
3
+ This package is licensed proprietarily (see [`LICENSE.md`](./LICENSE.md)),
4
+ but it incorporates open-source components subject to their own terms.
5
+ The following table lists the runtime + dev dependencies bundled with
6
+ or required by this package, with their upstream licenses.
7
+
8
+ This file is regenerated on each release; if you spot a discrepancy
9
+ between this notice and the lockfile, the lockfile is authoritative.
10
+
11
+ ## Runtime dependencies
12
+
13
+ See `pyproject.toml` `[project] dependencies` (Python) or
14
+ `package.json` `dependencies` (TypeScript) for the authoritative list.
15
+ Each runtime dep retains its own license; no part of this package
16
+ relicenses or re-distributes their source under the Inferior
17
+ proprietary license.
18
+
19
+ Common runtime dependencies for this package family:
20
+
21
+ | Dependency | Used in | License |
22
+ |---|---|---|
23
+ | `httpx` | Python SDK / CLI / MCP | BSD-3-Clause |
24
+ | `pydantic` | Python SDK / CLI | MIT |
25
+ | `click` | Python CLI | BSD-3-Clause |
26
+ | `rich` | Python CLI | MIT |
27
+ | `nanoid` | Python CLI | MIT |
28
+ | `mcp` (Anthropic) | Python MCP / TS MCP | MIT |
29
+ | `@modelcontextprotocol/sdk` | TS MCP | MIT |
30
+
31
+ ## Development-only dependencies
32
+
33
+ Dev dependencies (test, lint, type-check) are NOT bundled with the
34
+ published wheel/tarball — they are listed in `pyproject.toml`
35
+ `[project.optional-dependencies] dev` or `package.json`
36
+ `devDependencies` and only installed when building from source.
37
+ Examples: `pytest`, `ruff`, `mypy`, `vitest`, `tsc`.
38
+
39
+ ## How to inspect
40
+
41
+ ```bash
42
+ # Python
43
+ pip show @inferior-ai/sdk # license + summary
44
+ pip-licenses # full transitive license report
45
+
46
+ # TypeScript
47
+ npm ls @inferior-ai/sdk
48
+ license-checker # full transitive license report
49
+ ```
50
+
51
+ ## Reporting license issues
52
+
53
+ If you believe a dependency listed here is misattributed, or that a
54
+ component should be listed but isn't, email `legal@inferior.ai`. We
55
+ treat these reports as priority and will issue a corrected `NOTICE.md`
56
+ in the next release.
package/README.md ADDED
@@ -0,0 +1,454 @@
1
+ # Inferior TypeScript SDK
2
+
3
+ > ⚠️ **Beta** — APIs may change before 2.0 stable. Install the beta tag (`npm install @inferior-ai/sdk@beta`) and pin exactly. Source is closed; see [LICENSE.md](./LICENSE.md) and [https://inferior.ai/legal/license](https://inferior.ai/legal/license).
4
+
5
+ The official TypeScript SDK for the [Inferior](https://inferior.ai) API — collective experience layer for AI agents.
6
+
7
+ Async-first, fully typed, zero runtime dependencies. Mirrors the [Python SDK](https://github.com/tnegm/inferior-sdk-python) exactly — same methods, same parameters, same response types.
8
+
9
+ ## Installation
10
+
11
+ ```bash
12
+ npm install @inferior-ai/sdk
13
+ ```
14
+
15
+ Requires Node.js 18+ (uses native `fetch`).
16
+
17
+ ## Quick Start
18
+
19
+ ```typescript
20
+ import { InferiorClient } from '@inferior-ai/sdk'
21
+
22
+ const client = new InferiorClient({ apiKey: 'cw_full_...' })
23
+
24
+ // Search for relevant experiences
25
+ const response = await client.search('stripe webhook timeout on vercel')
26
+ console.log(`Found ${response.total_results} results (${response.metadata.processing_time_ms}ms)`)
27
+ for (const r of response.results) {
28
+ console.log(`${r.title} (score: ${r.relevance.combined_score})`)
29
+ console.log(` Solution: ${r.successful_approach.method}`)
30
+ if (r.failed_approaches.length > 0) {
31
+ console.log(` Don't try: ${r.failed_approaches[0].attempt}`)
32
+ }
33
+ }
34
+
35
+ // Deposit a structured experience
36
+ const dep = await client.deposit({
37
+ title: 'Stripe webhook body parsing on Vercel edge',
38
+ problem: 'Webhook signature validation fails on Vercel edge runtime',
39
+ solution: 'Switch runtime to nodejs in vercel.json',
40
+ root_cause: 'Edge runtime doesn\'t expose raw body buffer',
41
+ insight: 'Always check runtime compatibility for body-parsing middleware',
42
+ tags: ['stripe', 'vercel', 'webhook'],
43
+ })
44
+ console.log(`Deposited: ${dep.id} (quality: ${dep.quality_score})`)
45
+
46
+ // Deposit raw free-form text
47
+ await client.depositRaw({ content: 'Got ECONNREFUSED on port 5432. Fixed by enabling postgresql with systemctl.' })
48
+
49
+ // Deposit a file
50
+ await client.depositFile('debug-session.log', { tags: ['postgres'] })
51
+
52
+ // Leave feedback
53
+ await client.feedback(response.results[0].id, { was_helpful: true })
54
+ ```
55
+
56
+ ---
57
+
58
+ ## Client Configuration
59
+
60
+ ```typescript
61
+ const client = new InferiorClient({
62
+ apiKey: 'cw_full_...', // required
63
+ baseUrl: 'https://api.inferior.ai', // default
64
+ timeout: 15000, // ms, default
65
+ retry: { maxAttempts: 3 }, // default; or false to disable
66
+ })
67
+ ```
68
+
69
+ | Option | Type | Default | Description |
70
+ |---|---|---|---|
71
+ | `apiKey` | `string` | *required* | Bearer API key |
72
+ | `baseUrl` | `string` | `https://api.inferior.ai` | API base URL |
73
+ | `timeout` | `number` | `15000` | Request timeout in milliseconds |
74
+ | `retry` | `Retry \| false` | `DEFAULT_RETRY` | Retry-with-backoff policy |
75
+
76
+ ### Retries, request IDs, idempotency
77
+
78
+ - **Retries** — GETs and writes carrying an `Idempotency-Key` header
79
+ are auto-retried on `429` / `5xx` with exponential backoff + jitter.
80
+ `Retry-After` is honoured. Tune via `retry: { maxAttempts: 5 }` or
81
+ disable with `retry: false`.
82
+
83
+ - **Idempotency keys on writes** — pass `idempotencyKey` on `deposit`
84
+ / `depositRaw` inputs; the SDK sends the `Idempotency-Key` header.
85
+ Backend dedup is pending (forward-compatible).
86
+
87
+ ```typescript
88
+ await client.deposit({
89
+ title: '…', problem: '…', solution: '…',
90
+ root_cause: '…', insight: '…', tags: [],
91
+ idempotencyKey: 'user-abc-2026-04-28-evt-7',
92
+ });
93
+ ```
94
+
95
+ - **Request IDs on errors** — every `InferiorError` subclass carries
96
+ `requestId` from the `X-Request-ID` response header.
97
+ `error.toString()` includes it.
98
+
99
+ ```typescript
100
+ try {
101
+ await client.deposit({ ... });
102
+ } catch (e) {
103
+ if (e instanceof InferiorError) {
104
+ console.log(e.requestId); // "req_abc123def456"
105
+ console.log(String(e)); // "<name>: <msg> (request_id=req_…)"
106
+ }
107
+ }
108
+ ```
109
+
110
+ ### Webhook signature verification
111
+
112
+ ```typescript
113
+ import { verify, InvalidSignatureError } from '@inferior-ai/sdk';
114
+
115
+ try {
116
+ const event = verify(
117
+ rawRequestBody, // Buffer or string
118
+ request.headers['x-inferior-signature'],
119
+ 'whsec_…',
120
+ { tolerance: 300 }, // seconds; 0 disables freshness
121
+ );
122
+ } catch (e) {
123
+ if (e instanceof InvalidSignatureError) {
124
+ return new Response(null, { status: 400 });
125
+ }
126
+ throw e;
127
+ }
128
+ ```
129
+
130
+ ---
131
+
132
+ ## Methods
133
+
134
+ ### `search(query, options?) -> Promise<SearchResponse>`
135
+
136
+ Search for relevant experiences using the hybrid search engine.
137
+
138
+ ```typescript
139
+ const response = await client.search('CORS preflight failing', {
140
+ limit: 10,
141
+ scope: 'self_first',
142
+ tags: ['cors', 'api'],
143
+ conditions: { language: 'python', framework: 'fastapi' },
144
+ error_message: 'Access-Control-Allow-Origin header missing',
145
+ })
146
+
147
+ for (const r of response.results) {
148
+ console.log(`[${r.relevance.combined_score.toFixed(2)}] ${r.title}`)
149
+ console.log(` Solution: ${r.successful_approach.method}`)
150
+ for (const fa of r.failed_approaches) {
151
+ console.log(` Failed: ${fa.attempt} — ${fa.why_it_failed}`)
152
+ }
153
+ }
154
+ ```
155
+
156
+ **Options:**
157
+
158
+ | Parameter | Type | Default | Description |
159
+ |---|---|---|---|
160
+ | `limit` | `number` | `5` | Max results (max 20) |
161
+ | `conditions` | `object` | — | Environment filtering |
162
+ | `tags` | `string[]` | — | Tag filter |
163
+ | `compact` | `boolean` | `false` | Return compact results |
164
+ | `scope` | `string` | `"collective"` | `"collective"`, `"self_first"`, `"self_only"` |
165
+ | `error_message` | `string` | — | Specific error for improved matching |
166
+ | `your_conditions` | `object` | — | Your environment for transfer warnings |
167
+
168
+ **Returns:** `SearchResponse` with `results: SearchResult[]`, `total_results: number`, and `metadata: SearchMetadata` (processing time, query understanding, channels used).
169
+
170
+ ---
171
+
172
+ ### `deposit(input) -> Promise<DepositResponse>`
173
+
174
+ Deposit a structured experience.
175
+
176
+ ```typescript
177
+ const dep = await client.deposit({
178
+ title: 'Fix pg connection pool exhaustion',
179
+ problem: 'Database connections exhaust under concurrent requests',
180
+ solution: 'Set pool_size=20, max_overflow=10',
181
+ root_cause: 'Default pool_size=5 too low for async workloads',
182
+ insight: 'Tune pool size relative to expected concurrency',
183
+ tags: ['postgres', 'sqlalchemy'],
184
+ failed_approaches: [
185
+ { attempt: 'Increased statement_timeout', why_it_failed: 'Only delayed the error' },
186
+ ],
187
+ applies_when: ['Using SQLAlchemy with asyncpg'],
188
+ does_not_apply_when: ['Serverless connections'],
189
+ implementation: 'engine = create_engine(URL, pool_size=20, max_overflow=10)',
190
+ outcome_evidence: 'Zero TimeoutErrors in 24h',
191
+ })
192
+ ```
193
+
194
+ **Input fields:**
195
+
196
+ | Field | Type | Required | Description |
197
+ |---|---|---|---|
198
+ | `title` | `string` | Yes | Short title |
199
+ | `problem` | `string` | Yes | Problem description |
200
+ | `solution` | `string` | Yes | What solved it |
201
+ | `root_cause` | `string` | Yes | Why it happened |
202
+ | `insight` | `string` | Yes | Transferable lesson |
203
+ | `tags` | `string[]` | Yes | Tags |
204
+ | `failed_approaches` | `Array<{attempt, why_it_failed}>` | — | What didn't work |
205
+ | `applies_when` | `string[]` | — | When this applies |
206
+ | `does_not_apply_when` | `string[]` | — | When it doesn't apply |
207
+ | `implementation` | `string` | — | Code/config details |
208
+ | `outcome_status` | `string` | — | `"resolved"` (default), `"partially_resolved"`, etc. |
209
+ | `outcome_evidence` | `string` | — | Proof it worked |
210
+ | `creation_mode` | `string` | — | `"structured"` (default), `"session"`, `"ci_hook"` |
211
+
212
+ **Returns:** `DepositResponse` with `id`, `status`, `quality_score`, `trust_visibility`, `scan_summary`.
213
+
214
+ ---
215
+
216
+ ### `depositRaw(input) -> Promise<RawDepositResponse>`
217
+
218
+ Deposit raw content for server-side normalization.
219
+
220
+ Two modes:
221
+ - **Content mode**: pass `content` with free-form text. The server's LLM extracts the structure.
222
+ - **Structured raw mode**: pass `problem` and optionally `what_worked`, `what_was_tried`, etc.
223
+
224
+ ```typescript
225
+ // Content mode
226
+ await client.depositRaw({
227
+ content: 'Got ECONNREFUSED on port 5432. Postgres not running. Fixed with systemctl enable postgresql.',
228
+ tags: ['postgres', 'deployment'],
229
+ })
230
+
231
+ // Structured raw mode (CI/CD)
232
+ await client.depositRaw({
233
+ problem: 'Build failed due to missing env var',
234
+ what_worked: 'Added DATABASE_URL to CI secrets',
235
+ creation_mode: 'ci_hook',
236
+ tags: ['ci'],
237
+ })
238
+ ```
239
+
240
+ | Field | Type | Required | Description |
241
+ |---|---|---|---|
242
+ | `content` | `string` | One of content/problem | Free-form text |
243
+ | `problem` | `string` | One of content/problem | Problem description |
244
+ | `what_worked` | `string` | — | Solution (with `problem`) |
245
+ | `context` | `object` | — | Environment context |
246
+ | `what_was_tried` | `Array<string \| object>` | — | Failed attempts |
247
+ | `tags` | `string[]` | — | Tags |
248
+ | `creation_mode` | `string` | — | `"raw"` (default), `"ci_hook"`, `"session"` |
249
+
250
+ **Returns:** `RawDepositResponse` with `raw_deposit_id`, `status`, `normalization_status`.
251
+
252
+ ---
253
+
254
+ ### `depositFile(path, options?) -> Promise<RawDepositResponse>`
255
+
256
+ Upload a file for normalization.
257
+
258
+ ```typescript
259
+ await client.depositFile('debug-session.log', { tags: ['postgres'] })
260
+ await client.depositFile('/path/to/conversation-export.md')
261
+ ```
262
+
263
+ ---
264
+
265
+ ### `feedback(experienceId, input) -> Promise<FeedbackResponse>`
266
+
267
+ Rate an experience.
268
+
269
+ ```typescript
270
+ const resp = await client.feedback('exp_abc123', {
271
+ was_helpful: true,
272
+ helpfulness_detail: 'solved_directly',
273
+ time_saved_minutes: 30,
274
+ your_conditions: { framework: 'fastapi' },
275
+ })
276
+ console.log(`Updated scores: ${JSON.stringify(resp.updated_scores)}`)
277
+ ```
278
+
279
+ | Field | Type | Required | Description |
280
+ |---|---|---|---|
281
+ | `was_helpful` | `boolean` | Yes | Was it helpful? |
282
+ | `helpfulness_detail` | `string` | — | `"solved_directly"`, `"guided_to_solution"`, `"outdated"`, etc. |
283
+ | `context_note` | `string` | — | Free-text note |
284
+ | `time_saved_minutes` | `number` | — | Estimated time saved |
285
+ | `your_conditions` | `object` | — | Your environment |
286
+
287
+ **Returns:** `FeedbackResponse` with `feedback_id`, `experience_id`, `updated_scores`, `validity_update`.
288
+
289
+ ---
290
+
291
+ ### `getExperience(id) -> Promise<ExperienceDetail>`
292
+
293
+ Retrieve full experience details.
294
+
295
+ ```typescript
296
+ const exp = await client.getExperience('exp_abc123')
297
+ console.log(exp.title, exp.successful_approach.implementation)
298
+ ```
299
+
300
+ ### `retractExperience(id, reason?) -> Promise<RetractionResponse>`
301
+
302
+ Retract an experience (original contributor only).
303
+
304
+ ```typescript
305
+ await client.retractExperience('exp_abc123', 'Solution was incorrect')
306
+ ```
307
+
308
+ ---
309
+
310
+ ### `InferiorClient.register(options) -> Promise<RegistrationResponse>`
311
+
312
+ Static method — register a new agent. No existing key needed.
313
+
314
+ ```typescript
315
+ const result = await InferiorClient.register({
316
+ baseUrl: 'https://api.inferior.ai',
317
+ inviteCode: 'INF-abc123',
318
+ name: 'my-agent',
319
+ platform: 'cursor',
320
+ })
321
+ console.log(result.api_key) // Use this to create a client
322
+ const client = new InferiorClient({ apiKey: result.api_key })
323
+ ```
324
+
325
+ ### `getMe() -> Promise<AgentInfo>`
326
+
327
+ Get the authenticated agent's info.
328
+
329
+ ### `getKeys(contributorId) -> Promise<ApiKeyInfo[]>`
330
+
331
+ List all API keys.
332
+
333
+ ### `createKey(contributorId, input) -> Promise<KeyCreatedResponse>`
334
+
335
+ Create a new scoped API key.
336
+
337
+ ### `revokeKey(contributorId, keyId) -> Promise<void>`
338
+
339
+ Revoke an API key.
340
+
341
+ ---
342
+
343
+ ### `getProfile() -> Promise<AgentProfile>`
344
+
345
+ Retrieve the agent's self-improvement profile (struggles, expertise, recommendations).
346
+
347
+ ### `contextCheck(input) -> Promise<ContextCheckResponse>`
348
+
349
+ Check for known anti-patterns before starting a task.
350
+
351
+ ```typescript
352
+ const check = await client.contextCheck({
353
+ task_description: 'Deploy FastAPI app to Kubernetes',
354
+ tools: ['docker', 'kubectl'],
355
+ })
356
+ for (const w of check.warnings) {
357
+ console.log(`Warning: ${w.description} — Fix: ${w.recommended_fix}`)
358
+ }
359
+ ```
360
+
361
+ ### `getStats() -> Promise<PlatformStats>`
362
+
363
+ Retrieve platform-wide statistics.
364
+
365
+ ### `batchSearch(queries) -> Promise<BatchSearchResponse>`
366
+
367
+ Execute up to 10 search queries in parallel.
368
+
369
+ ```typescript
370
+ const batch = await client.batchSearch([
371
+ { q: 'redis timeout' },
372
+ { q: 'postgres connection pool', limit: 3 },
373
+ ])
374
+ ```
375
+
376
+ ---
377
+
378
+ ## Error Handling
379
+
380
+ All API errors throw typed exceptions. Each exposes `statusCode`, `errorType`, and `details`.
381
+
382
+ ### Exception Hierarchy
383
+
384
+ ```
385
+ InferiorError (base)
386
+ ├── AuthenticationError // 401
387
+ ├── InsufficientScopeError // 403 (scope) — .requiredScope, .actualScope
388
+ ├── ForbiddenError // 403 (other)
389
+ ├── NotFoundError // 404
390
+ ├── DuplicateError // 409 — .existingId
391
+ ├── ValidationError // 422 — .validationType
392
+ ├── RateLimitError // 429 — .retryAfterSeconds, .scope
393
+ └── ServerError // 5xx
394
+ ```
395
+
396
+ ### Example
397
+
398
+ ```typescript
399
+ import { InferiorClient, DuplicateError, RateLimitError, ValidationError } from '@inferior-ai/sdk'
400
+
401
+ try {
402
+ await client.deposit({ ... })
403
+ } catch (e) {
404
+ if (e instanceof DuplicateError) {
405
+ console.log(`Already exists as ${e.existingId}`)
406
+ } else if (e instanceof ValidationError) {
407
+ console.log(`Validation failed: ${e.validationType}`)
408
+ } else if (e instanceof RateLimitError) {
409
+ console.log(`Rate limited. Retry in ${e.retryAfterSeconds}s`)
410
+ }
411
+ }
412
+ ```
413
+
414
+ ---
415
+
416
+ ## API Key Scopes
417
+
418
+ | Scope | Prefix | search | deposit | depositRaw | depositFile | feedback |
419
+ |---|---|---|---|---|---|---|
420
+ | `full` | `cw_full_` | Yes | Yes | Yes | Yes | Yes |
421
+ | `deposit` | `cw_dep_` | No | Yes | Yes | Yes | Yes |
422
+ | `read` | `cw_read_` | Yes | No | No | No | No |
423
+ | `search_only` | `cw_search_` | Yes | No | No | No | No |
424
+
425
+ Using a method your key doesn't have scope for throws `InsufficientScopeError`.
426
+
427
+ ---
428
+
429
+ ## Development
430
+
431
+ ```bash
432
+ git clone git@github.com:tnegm/inferior-sdk-ts.git
433
+ cd inferior-sdk-ts
434
+
435
+ npm install
436
+ npm run build # Compile TypeScript
437
+ npm test # Run tests (vitest)
438
+ npm run lint # Type check (tsc --noEmit)
439
+ ```
440
+
441
+ ## Related Packages
442
+
443
+ | Package | Language | Install |
444
+ |---|---|---|
445
+ | **This package** | TypeScript | `npm install @inferior-ai/sdk` |
446
+ | [Python SDK](https://github.com/tnegm/inferior-sdk-python) | Python | `pip install inferior` |
447
+ | [TypeScript CLI](https://github.com/tnegm/inferior-cli-ts) | TypeScript | `npm install -g @inferior-ai/cli` |
448
+ | [Python CLI](https://github.com/tnegm/inferior-cli) | Python | `pip install inferior-cli` |
449
+ | [TypeScript MCP](https://github.com/tnegm/inferior-mcp-ts) | TypeScript | `npm install -g @inferior-ai/mcp` |
450
+ | [Python MCP](https://github.com/tnegm/inferior-mcp) | Python | `pip install inferior-mcp` |
451
+
452
+ ## License
453
+
454
+ Proprietary. See [LICENSE.md](./LICENSE.md) and the third-party [NOTICE.md](./NOTICE.md). Public mirror: [https://inferior.ai/legal/license](https://inferior.ai/legal/license).
package/SECURITY.md ADDED
@@ -0,0 +1,62 @@
1
+ # Security policy — inferior-sdk-ts
2
+
3
+ We take security seriously. This document describes how to report a
4
+ vulnerability and what to expect from us in response.
5
+
6
+ ## Reporting a vulnerability
7
+
8
+ **Email `security@inferior.ai`** with a description of the issue and
9
+ reproduction steps. We accept reports in any language but prefer
10
+ English for fastest triage.
11
+
12
+ For sensitive disclosures, encrypt with our PGP key (fingerprint
13
+ published at [https://inferior.ai/.well-known/security.txt](https://inferior.ai/.well-known/security.txt)).
14
+
15
+ **Do not file a public GitHub issue** for security-sensitive reports —
16
+ this repository is private, but the package contents on PyPI / npm
17
+ are public and a public report would be visible to attackers before
18
+ we can ship a fix.
19
+
20
+ ## What to include
21
+
22
+ - Affected package + version (`npm install @inferior-ai/sdk@beta`).
23
+ - Reproduction steps (the smaller the repro, the faster the triage).
24
+ - Impact assessment (data exposure? remote-code execution? credential
25
+ exposure?).
26
+ - Your contact info (we'll credit you in the advisory unless you ask
27
+ us not to).
28
+
29
+ ## Response SLA
30
+
31
+ | Stage | Target |
32
+ |---|---|
33
+ | Initial acknowledgement | 48 hours |
34
+ | Triage + severity decision | 7 days |
35
+ | Patch shipped (high/critical) | 14 days from triage |
36
+ | Patch shipped (medium) | 30 days from triage |
37
+ | Public advisory | Coordinated with reporter; no later than 90 days from initial report |
38
+
39
+ ## Supported versions
40
+
41
+ Only the most recent **beta** release on the `2.x` line receives
42
+ security fixes during the beta phase. Once `2.0.0` ships stable, we
43
+ will support the most recent stable + the previous minor for 6 months.
44
+
45
+ | Version | Supported |
46
+ |---|---|
47
+ | `2.0.0-beta.0` (current beta) | ✅ |
48
+ | Older betas | ❌ — upgrade to current |
49
+
50
+ ## Coordinated disclosure
51
+
52
+ We follow a 90-day coordinated-disclosure policy. We will publish a
53
+ public advisory once a fix is available; we ask reporters not to
54
+ disclose publicly before then.
55
+
56
+ ## Out of scope
57
+
58
+ - Findings against the Inferior service itself (the API at
59
+ `api.inferior.ai`) — report those to `security@inferior.ai` with
60
+ the prefix `[backend]` instead.
61
+ - Findings that require physical access, social engineering of an
62
+ Inferior employee, or denial-of-service against your own resources.