@onlyworlds/sdk 4.17.0 → 4.18.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/AGENTS.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # For AI agents using @onlyworlds/sdk
2
2
 
3
- **Current as of**: SDK **4.x** · schema-dist **v0.32.0-dist.20** (canonical 00.32.00).
3
+ **Current as of**: SDK **4.x** · schema-dist **v0.32.0-dist.23** (canonical 00.32.00).
4
4
  This line is asserted by `codegen:check` in CI — if the pin moves and this file is not
5
5
  re-read against it, the check fails rather than letting this document rot quietly.
6
6
 
@@ -45,6 +45,10 @@ against live data). The v1 surface (`OnlyWorldsClient`, the `ElementType` enum)
45
45
  - Ask (since 4.13.0, account token): `buildAskContext(hits, index)` then
46
46
  `account.ask({ worldId, question, context })`; answers only from the context. 50 a day per
47
47
  account (`err.isQuotaExceeded`); `isAskUnavailable`, `isAskFailed` count nothing.
48
+ - Sort (since 4.18.0, account token): `account.sort({ worldId, notes, slice })` turns unsorted
49
+ notes (text, or a picture already uploaded into the world) into rows to review: `make`,
50
+ `add_to`, `link`, `ask`, plus `not_proposed` with reasons. Ids come only from your `slice`
51
+ (up to 100 elements your own lookup found); nothing is written. Counts as one ask.
48
52
  - Invite links (since 4.12.0): `previewJoin(code)` (no credential sent) shows who invites, to
49
53
  which world, in what role; `acceptJoin(code)` with an `ow_a_` account token joins. Bad code:
50
54
  `err.isNotFound`; `err.isAlreadyMember`, `err.isPinRequired` for the two 409s.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,26 @@ earlier history lives in git log only.
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [4.18.1] — 2026-10-12
9
+
10
+ ### Changed
11
+ - **Schema repinned to schema-dist v0.32.0-dist.23** (same canonical 00.32.00). The one
12
+ generated change is the `id` doc comment: a UUID, new ids minted as uuidv7, earlier uuidv4
13
+ ids still valid. No type changes. The vendored dist gains `walk/lint_folder.py`.
14
+ - README and AGENTS.md describe `sort()`.
15
+
16
+ ## [4.18.0] — 2026-10-12
17
+
18
+ ### Added
19
+ - **`client.sort({ worldId, notes, slice })`**: POST /account/sort, ask's sibling (Temper for
20
+ Lantern, h37 #3599; Skeld's route, #3591, #3594, #3596, #3597). Notes as words or
21
+ `{ text, image_url }`; the slice is the app's own lookup. Rows of four kinds come back to
22
+ review (`make`, `add_to`, `link`, `ask` with an optional `then`) and `not_proposed` with
23
+ reasons; nothing is written. One allowance with `ask`, and the same refusals. Types
24
+ `OwSortRef`, `OwSortNote`, `OwSortRow` and its four kinds, `OwSortAnswer`. Built against
25
+ keel PR #4 (90961fa, Skeld's final for the types, #3618), released once it was on keel
26
+ main and in production (#3663): verify-sdk-wire PASS 1,111 against production's document.
27
+
8
28
  ## [4.17.0] — 2026-10-12
9
29
 
10
30
  ### Added
package/README.md CHANGED
@@ -174,6 +174,14 @@ const reply = await account.ask({ worldId, question, context }); // account: a c
174
174
  reply.answer; // from those elements only, or "The world doesn't say."
175
175
  ```
176
176
 
177
+ The same proxy sorts loose notes into changes for the user to review. Send the elements your own lookup found for them as the `slice`; every id in a row comes from it, and nothing is written until your app applies what the user accepts. A sort counts as one question.
178
+
179
+ ```typescript
180
+ const slice = hits.slice(0, 100).map(({ element: e }) => ({ id: e.id, type: e.type, name: e.name }));
181
+ const { rows, not_proposed } = await account.sort({ worldId, notes: ['Mira moved to Ostvik.'], slice });
182
+ // rows: make (a new element), add_to (text for a field), link (one element to another), ask (which one?)
183
+ ```
184
+
177
185
  ## World files
178
186
 
179
187
  A world file is one `.zip` holding a whole world folder (`world.json` and `elements/<type>/*.json`, as Atlas keeps a world on disk), the way Atlas downloads and opens one. It needs no account and works in the browser and in Node.
package/SCHEMA.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # OnlyWorlds Schema Reference
2
2
 
3
- **Source**: https://github.com/OnlyWorlds/schema-dist @ **v0.32.0-dist.20** — canonical schema **00.32.00**, published 2026-10-11.
3
+ **Source**: https://github.com/OnlyWorlds/schema-dist @ **v0.32.0-dist.23** — canonical schema **00.32.00**, published 2026-10-12.
4
4
 
5
5
  GENERATED from the canonical schema YAML — do not hand-edit (regenerate: `python codegen/generate_types.py`).
6
6
  Written for both humans and AI agents reading this package locally.
package/dist/index.d.ts CHANGED
@@ -6,7 +6,7 @@
6
6
  interface OwElementBase {
7
7
  /** Element type slug (server-managed, read-only). */
8
8
  type: string;
9
- /** Unique identifier for the element, uuidv7 format. */
9
+ /** Unique identifier for the element, a UUID. New ids are minted as uuidv7; ids minted earlier as uuidv4 remain valid. */
10
10
  id: string;
11
11
  /** Name of the element. */
12
12
  name: string;
@@ -2013,6 +2013,87 @@ interface OwAskAnswer {
2013
2013
  remaining: number;
2014
2014
  [k: string]: unknown;
2015
2015
  }
2016
+ /**
2017
+ * One element the notes may be about, as POST /account/sort takes it (the slice), and as a
2018
+ * row names it back: keel copies a target's name, type and anchor from the slice, never
2019
+ * from the model. `type` is lowercase going in; keel answers with its own spelling.
2020
+ */
2021
+ interface OwSortRef {
2022
+ id: string;
2023
+ type: string;
2024
+ name: string;
2025
+ /** A short phrase that tells two same-named elements apart (up to 120 characters). */
2026
+ anchor?: string;
2027
+ }
2028
+ /**
2029
+ * A note for sorting: its words, or an object with words and/or a picture already uploaded
2030
+ * into this world (`https://media.onlyworlds.com/u/<world id>/<name>`, no query). An object
2031
+ * needs at least one of the two; the picture is read as a photographed note.
2032
+ */
2033
+ type OwSortNote = string | {
2034
+ text?: string;
2035
+ image_url?: string | null;
2036
+ };
2037
+ /** A new element the notes describe. */
2038
+ interface OwSortMakeRow {
2039
+ kind: 'make';
2040
+ source_line: string;
2041
+ proposal: {
2042
+ type: string;
2043
+ name: string;
2044
+ description: string;
2045
+ };
2046
+ }
2047
+ /** Text to append to a field of a slice element. */
2048
+ interface OwSortAddToRow {
2049
+ kind: 'add_to';
2050
+ source_line: string;
2051
+ target: OwSortRef;
2052
+ field: string;
2053
+ op: 'append';
2054
+ value: string;
2055
+ }
2056
+ /** A link from one slice element to another, through a named field. */
2057
+ interface OwSortLinkRow {
2058
+ kind: 'link';
2059
+ source_line: string;
2060
+ target: OwSortRef;
2061
+ field: string;
2062
+ value_id: string;
2063
+ value_name: string;
2064
+ }
2065
+ /**
2066
+ * A question for the user: a name matches two or more slice elements, or the sorter is
2067
+ * unsure a thing exists. `then`, when sent, is the add_to or link the question stands for,
2068
+ * its target left out: the user's pick fills it.
2069
+ */
2070
+ interface OwSortAskRow {
2071
+ kind: 'ask';
2072
+ source_line: string;
2073
+ question: string;
2074
+ candidates: OwSortRef[];
2075
+ then?: Omit<OwSortAddToRow, 'source_line' | 'target'> | Omit<OwSortLinkRow, 'source_line' | 'target'>;
2076
+ }
2077
+ type OwSortRow = OwSortMakeRow | OwSortAddToRow | OwSortLinkRow | OwSortAskRow;
2078
+ /** POST /account/sort: proposed changes for the user to review. Nothing is written to the world. */
2079
+ interface OwSortAnswer {
2080
+ /** Every id in a row is from the request's slice. */
2081
+ rows: OwSortRow[];
2082
+ /** The lines the sorter could not place, and rows keel refused, each with a reason. */
2083
+ not_proposed: {
2084
+ source_line: string;
2085
+ reason: string;
2086
+ }[];
2087
+ model: string;
2088
+ stop_reason: string | null;
2089
+ usage: {
2090
+ input_tokens: number;
2091
+ output_tokens: number;
2092
+ };
2093
+ /** Questions the account has left today: a sort counts as one ask. */
2094
+ remaining: number;
2095
+ [k: string]: unknown;
2096
+ }
2016
2097
  /** POST /join/preview: what a join code holds, read without using it (keel #212). */
2017
2098
  interface OwJoinPreview {
2018
2099
  /** `person`: an invite link, accepted with acceptJoin. `agent`: redeemed by an AI agent at POST /join. */
@@ -2486,6 +2567,22 @@ declare class OwV2Client {
2486
2567
  question: string;
2487
2568
  context: string[];
2488
2569
  }): Promise<OwAskAnswer>;
2570
+ /**
2571
+ * POST /account/sort -- the user's unsorted notes, and the elements the app's own search
2572
+ * found for them (`slice`: id, lowercase type, name, optional anchor; build it from
2573
+ * lookupWorld's hits), sorted by the same proxy as ask into rows to review: `make`, `add_to`,
2574
+ * `link`, `ask`. Nothing is written; the app applies what the user accepts. Every id in a
2575
+ * row is from the slice; keel moves any other row to `not_proposed` with its reason.
2576
+ * A sort counts as one ask: the same account token, allowance and refusals as ask. 422
2577
+ * names the param: notes 1 to 8, each up to 4,000 characters and 16,000 in all (text
2578
+ * only), at most four pictures, each uploaded into this world; slice up to 100, names up
2579
+ * to 200 characters, anchors up to 120.
2580
+ */
2581
+ sort(req: {
2582
+ worldId: string;
2583
+ notes: OwSortNote[];
2584
+ slice: OwSortRef[];
2585
+ }): Promise<OwSortAnswer>;
2489
2586
  /**
2490
2587
  * Raw authenticated request against this client's baseUrl. Public since 4.0
2491
2588
  * so auxiliary resources can ride the same transport — it structurally
@@ -3166,4 +3263,4 @@ declare class TokenResource {
3166
3263
  getEncryptionInfo(): Promise<EncryptionInfo>;
3167
3264
  }
3168
3265
 
3169
- export { ASK_LIMITS, type AccessKeyResponse, ELEMENT_FAMILIES, ELEMENT_ICONS, ELEMENT_LABELS, ELEMENT_SECTIONS, ELEMENT_TYPES, type ElementFamily, type ElementType, type EncryptionInfo, FAMILY_COLORS, FAMILY_ORDER, FIELD_SCHEMA, type FieldInfo, type FieldType, GameTier, type ListParams, ONLYWORLDS_VERSION, OwApiError, type OwAskAnswer, type OwAskContext, type OwAuthErrorCode, type OwBulkItem, type OwBulkItemResult, type OwBulkResponse, type OwChange, type OwChangesPage, type OwClientConfig, type OwElement, type OwElementBase, type OwErrorBody, type OwJoinPreview, type OwJoinedMembership, type OwKeyKind, type OwLinkEdit, type OwLookupElement, type OwLookupHit, type OwLookupLink, type OwLookupOptions, type OwLookupReason, type OwMediaTicket, type OwMemberRole, OwNetworkError, type OwPage, type OwPhotoOptions, type OwPhotoPlan, OwPreconditionFailedError, type OwPreparedPhoto, type OwReadWorldFile, type OwReadWorldFileOptions, type OwRemovalTicket, type OwRemovedImage, type OwRenderOptions, type OwUploadedImage, OwV2Client, type OwWorldFileEntry, OwWorldFileError, type OwWorldFileReason, type OwWorldIndex, type OwWorldMeta, PHOTO_MAX_BYTES, PHOTO_TYPES, type RevokeAllSessionsResponse, type RevokeSessionResponse, SPATIAL_TYPES, type SectionInfo, type TokenConsumeParams, type TokenConsumeResponse, TokenResource, type TokenStatus, type TokenTransport, WORLD_FILE_MAX_BYTES, WORLD_FILE_MAX_ENTRIES, buildAskContext, buildWorldIndex, detectKeyKind, elementColor, errorFromResponse, familyOf, getElementIcon, getElementLabel, isDemoKey, kindCanWrite, lookupWorld, parseErrorEnvelope, pinExpectation, planPhoto, preparePhoto, readWorldFile, renderElement, writeWorldFile };
3266
+ export { ASK_LIMITS, type AccessKeyResponse, ELEMENT_FAMILIES, ELEMENT_ICONS, ELEMENT_LABELS, ELEMENT_SECTIONS, ELEMENT_TYPES, type ElementFamily, type ElementType, type EncryptionInfo, FAMILY_COLORS, FAMILY_ORDER, FIELD_SCHEMA, type FieldInfo, type FieldType, GameTier, type ListParams, ONLYWORLDS_VERSION, OwApiError, type OwAskAnswer, type OwAskContext, type OwAuthErrorCode, type OwBulkItem, type OwBulkItemResult, type OwBulkResponse, type OwChange, type OwChangesPage, type OwClientConfig, type OwElement, type OwElementBase, type OwErrorBody, type OwJoinPreview, type OwJoinedMembership, type OwKeyKind, type OwLinkEdit, type OwLookupElement, type OwLookupHit, type OwLookupLink, type OwLookupOptions, type OwLookupReason, type OwMediaTicket, type OwMemberRole, OwNetworkError, type OwPage, type OwPhotoOptions, type OwPhotoPlan, OwPreconditionFailedError, type OwPreparedPhoto, type OwReadWorldFile, type OwReadWorldFileOptions, type OwRemovalTicket, type OwRemovedImage, type OwRenderOptions, type OwSortAddToRow, type OwSortAnswer, type OwSortAskRow, type OwSortLinkRow, type OwSortMakeRow, type OwSortNote, type OwSortRef, type OwSortRow, type OwUploadedImage, OwV2Client, type OwWorldFileEntry, OwWorldFileError, type OwWorldFileReason, type OwWorldIndex, type OwWorldMeta, PHOTO_MAX_BYTES, PHOTO_TYPES, type RevokeAllSessionsResponse, type RevokeSessionResponse, SPATIAL_TYPES, type SectionInfo, type TokenConsumeParams, type TokenConsumeResponse, TokenResource, type TokenStatus, type TokenTransport, WORLD_FILE_MAX_BYTES, WORLD_FILE_MAX_ENTRIES, buildAskContext, buildWorldIndex, detectKeyKind, elementColor, errorFromResponse, familyOf, getElementIcon, getElementLabel, isDemoKey, kindCanWrite, lookupWorld, parseErrorEnvelope, pinExpectation, planPhoto, preparePhoto, readWorldFile, renderElement, writeWorldFile };
package/dist/index.js CHANGED
@@ -494,6 +494,25 @@ var OwV2Client = class {
494
494
  body: { world_id: req.worldId, question: req.question, context: req.context }
495
495
  });
496
496
  }
497
+ /**
498
+ * POST /account/sort -- the user's unsorted notes, and the elements the app's own search
499
+ * found for them (`slice`: id, lowercase type, name, optional anchor; build it from
500
+ * lookupWorld's hits), sorted by the same proxy as ask into rows to review: `make`, `add_to`,
501
+ * `link`, `ask`. Nothing is written; the app applies what the user accepts. Every id in a
502
+ * row is from the slice; keel moves any other row to `not_proposed` with its reason.
503
+ * A sort counts as one ask: the same account token, allowance and refusals as ask. 422
504
+ * names the param: notes 1 to 8, each up to 4,000 characters and 16,000 in all (text
505
+ * only), at most four pictures, each uploaded into this world; slice up to 100, names up
506
+ * to 200 characters, anchors up to 120.
507
+ */
508
+ async sort(req) {
509
+ if (this.keyKind !== "account") {
510
+ throw new TypeError("sort needs an account token (ow_a_): the proxy meters per account");
511
+ }
512
+ return this.request("POST", "/account/sort", {
513
+ body: { world_id: req.worldId, notes: req.notes, slice: req.slice }
514
+ });
515
+ }
497
516
  // -- Core request machinery ----------------------------------------------
498
517
  /**
499
518
  * Raw authenticated request against this client's baseUrl. Public since 4.0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlyworlds/sdk",
3
- "version": "4.17.0",
3
+ "version": "4.18.1",
4
4
  "description": "TypeScript SDK for the OnlyWorlds API - build world-building applications with type safety",
5
5
  "type": "module",
6
6
  "exports": {