Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,26 @@
# Changelog

## [1.6.0] - 2026-10-04

### Changed

- Sync the bundled OpenAPI spec and regenerate the types. Existing responses gain properties, among them `attachments` on `AgentRunResponse` and `AgentRunStepResponse`, `trace_purged_at` on a run, `warnings` on a step, `strip_quoted_reply_chains` on memory banks, `effort` on playground experiments, `effort_options` and `chat_capable` on `PromptModelResponse`, and `embedder_warning` on `ContentFileUploadResponse`
- Move `SeclaiApiVersion.Latest` to `2026-10-03`. Nothing is sent unless `apiVersion` is set, so a client that passes `SeclaiApiVersion.Latest` now opts into the five versions added below
- Send an array passed in the `query` of `request()` or `requestRaw()` as a repeated parameter, one pair per element. It was joined with commas into a single value

### Added

- Add the cloud-drive methods `listCloudDriveProviders()`, `listCloudDrives()`, `getCloudDrive()`, `updateCloudDrive()`, `disconnectCloudDrive()`, `deleteCloudDrive()`, `getAgentsUsingCloudDrive()` and `listCloudDriveRejections()`. The four listings return the items as an array whether the endpoint answers with a bare array or, from `apiVersion` `2026-07-27`, the `{data, pagination}` envelope
- Add `listSourceContents()` and `getSourceContentStatus()` for the indexing status of a source's content. `contentVersionIds` polls a batch of uploads in one request, and an empty array returns an empty page without calling the API
- Add `listEmbeddingModels()` and `listRerankerModels()`. The list is under `models` on every API version, with the defaults and pricing beside it
- Add the `SeclaiApiVersion` constants `V2026_08_03`, `V2026_08_21`, `V2026_09_28`, `V2026_09_30` and `V2026_10_03`, so those versions are accepted as `apiVersion`. The README lists what each one changes
- Add the type exports for those endpoints, including `CloudDriveResponse`, `CloudDriveProviderResponse`, `CloudDriveRejectionResponse`, `CloudDriveUpdateRequest`, `AgentUsingCloudDriveResponse`, `SourceContentStatusResponse`, `SourceContentStatusListResponse`, `ListSourceContentsOptions`, `EmbeddingModelListResponse` and `RerankerModelListResponse`, plus `AgentRunFileResponse` and `EffortOptionsResponse`

### Fixed

- Make `paginate()` work with the list methods. It read `items` and `pagination.total_pages`, while they return `data` and `pagination.pages`, so `client.paginate((opts) => client.listSources(opts))` threw `TypeError: result.items is not iterable`. It now reads the `{data, pagination}` envelope and stops on `has_next`, walks the flat `{data, total, page, limit}` shape of the evaluation listings by `total`, yields a bare array once, still accepts a custom fetcher's `{items, pagination: {total_pages}}`, and throws `SeclaiError` on anything else. The fetcher's page type is exported as `PaginatedPage`
- Correct the `Seclai` class example, which destructured an `items` property `listAgents()` does not return

## [1.5.0] - 2026-07-27

### Changed
Expand Down Expand Up @@ -185,6 +206,7 @@ _Stable release. No functional changes since 0.0.1._

_Initial release._

[1.6.0]: https://github.com/seclai/seclai-javascript/releases/tag/1.6.0
[1.5.0]: https://github.com/seclai/seclai-javascript/releases/tag/1.5.0
[1.4.0]: https://github.com/seclai/seclai-javascript/releases/tag/1.4.0
[1.3.0]: https://github.com/seclai/seclai-javascript/releases/tag/1.3.0
Expand Down
63 changes: 60 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ Leave `apiVersion` unset and the header is omitted, so the account's pinned
baseline applies and responses keep their current shapes. Upgrading this package
alone never changes the wire contract.

Known versions are on `SeclaiApiVersion` (`V2026_07_01`, `V2026_07_27`, plus
`Default` and `Latest`), imported from `@seclai/sdk`. A version this release was
Known versions are on `SeclaiApiVersion` (`V2026_07_01` through `V2026_10_03`,
plus `Default` and `Latest`), imported from `@seclai/sdk`. A version this release was
**not** built against throws at construction: a newer version can reshape
responses, and this client would decode them incorrectly rather than reject them.
Upgrade the package to adopt a new version, or set `allowUnknownApiVersion` if
Expand Down Expand Up @@ -156,6 +156,23 @@ last two with `res.data ?? res.configs` / `res.data ?? res.alerts`. The legacy
keys will be deprecated and then removed once the canonical envelope is the
default.

The cloud-drive listings (`listCloudDriveProviders()`, `listCloudDrives()`,
`getAgentsUsingCloudDrive()`, `listCloudDriveRejections()`) follow the same rule
and return the items as an array on either shape. `listEmbeddingModels()` and
`listRerankerModels()` move their list from `models` to `data`; both methods
populate `models` on either shape, with the defaults and pricing beside it.

**Later versions.** Each is cumulative, and none changes a response shape this
client decodes:

| Version | What it changes |
| --- | --- |
| `2026-08-03` | `createMemoryBank()` rejects `max_age_days` with a 400, and an omitted `retention_days` resolves per bank type instead of to 30 |
| `2026-08-21` | `createSource()` rejects an embedding dimension its embedder does not support with a 400 — `listEmbeddingModels()` reports the supported ones |
| `2026-09-28` | Agent-definition writes use the current file-list grammar: an omitted `attachments` keeps the stored list and `[]` means no files |
| `2026-09-30` | A run's and a step's `output`, and a step's `input`, are the text rather than a JSON manifest; files are in `attachments` on every version |
| `2026-10-03` | A new LLM step written without `attachments` takes its parent's files, and a new retrieval step's matched media are its files |

## Resources

### Identity
Expand Down Expand Up @@ -427,6 +444,40 @@ await client.updateSource("source_id", { name: "Renamed" });
await client.deleteSource("source_id");
```

Indexing status of a source's content, keyed by the `content_version_id` the
upload methods return:

<!-- sdksync:check -->
```ts
const failed = await client.listSourceContents("source_id", { status: "failed" });
const batch = await client.listSourceContents("source_id", {
contentVersionIds: ["cv_1", "cv_2"],
});
console.log(batch.pagination.total, failed.data.map((item) => item.error));

const one = await client.getSourceContentStatus("source_id", "cv_1");
console.log(one.content_status);
```

### Cloud drives

<!-- sdksync:check -->
```ts
const providers = await client.listCloudDriveProviders();
const drives = await client.listCloudDrives();
const drive = await client.getCloudDrive(drives[0].id);
await client.updateCloudDrive(drive.id, { name: "Contracts" });

// Which agents depend on it, and which files it skipped and why
const agents = await client.getAgentsUsingCloudDrive(drive.id);
const skipped = await client.listCloudDriveRejections(drive.id, { limit: 20 });
console.log(providers.length, agents.length, skipped.map((r) => r.reason));

const disconnected = await client.disconnectCloudDrive(drive.id); // keeps the connection
console.log(disconnected.connected);
await client.deleteCloudDrive(drive.id);
```

### File uploads

Upload a file to a source (max 200 MiB). The SDK infers MIME type from the file extension when `mimeType` is not provided.
Expand Down Expand Up @@ -575,6 +626,11 @@ const model = await client.getModel("model_id");
// Media-generation quality tiers (fast/balanced/thorough) and what each resolves to
const tiers = await client.getGenerationTiers();

// Embedding and reranker models, with their pricing
const embedders = await client.listEmbeddingModels({ supportsInputMedia: "image" });
const rerankers = await client.listRerankerModels();
console.log(embedders.models, embedders.default_model_type, rerankers.models);

const alerts = await client.listModelAlerts();
await client.markModelAlertRead("alert_id");
await client.markAllModelAlertsRead();
Expand Down Expand Up @@ -674,8 +730,9 @@ await client.submitAiFeedback({ ... });

## Pagination helper

Automatically iterate through all pages:
Automatically iterate through all pages of a list method:

<!-- sdksync:check -->
```ts
for await (const source of client.paginate(
(opts) => client.listSources(opts),
Expand Down
Loading
Loading