@onlyworlds/sdk 4.18.0 → 4.19.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/AGENTS.md +9 -3
- package/CHANGELOG.md +28 -0
- package/README.md +8 -0
- package/SCHEMA.md +1 -1
- package/dist/index.d.ts +13 -3
- package/dist/index.js +111 -8
- package/package.json +1 -1
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.
|
|
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
|
|
|
@@ -43,8 +43,14 @@ against live data). The v1 surface (`OnlyWorldsClient`, the `ElementType` enum)
|
|
|
43
43
|
to the edge with a single-use ticket from keel, never with the API key. `removeImage(urlOrKey)`
|
|
44
44
|
takes one back (its uploader or the world's owner); it leaves `image_url` on elements as is.
|
|
45
45
|
- Ask (since 4.13.0, account token): `buildAskContext(hits, index)` then
|
|
46
|
-
`account.ask({ worldId, question, context })`; answers only from the context.
|
|
47
|
-
account (`
|
|
46
|
+
`account.ask({ worldId, question, context })`; answers only from the context. Spends from the
|
|
47
|
+
account's daily token rating (`tokens_remaining`, `token_rating`; `remaining` counts answers of
|
|
48
|
+
this size still in it); used up → `err.isQuotaExceeded`. `isAskUnavailable`, `isAskFailed`
|
|
49
|
+
count nothing. Custom fields (`x_*`) are in the lookup and the context; `atlas_*` is not.
|
|
50
|
+
- Sort (since 4.18.0, account token): `account.sort({ worldId, notes, slice })` turns unsorted
|
|
51
|
+
notes (text, or a picture already uploaded into the world) into rows to review: `make`,
|
|
52
|
+
`add_to`, `link`, `ask`, plus `not_proposed` with reasons. Ids come only from your `slice`
|
|
53
|
+
(up to 100 elements your own lookup found); nothing is written. Counts as one ask.
|
|
48
54
|
- Invite links (since 4.12.0): `previewJoin(code)` (no credential sent) shows who invites, to
|
|
49
55
|
which world, in what role; `acceptJoin(code)` with an `ow_a_` account token joins. Bad code:
|
|
50
56
|
`err.isNotFound`; `err.isAlreadyMember`, `err.isPinRequired` for the two 409s.
|
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,34 @@ earlier history lives in git log only.
|
|
|
5
5
|
|
|
6
6
|
## [Unreleased]
|
|
7
7
|
|
|
8
|
+
## [4.19.0] — 2026-10-14
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **`tokens_remaining` and `token_rating` on `OwAskAnswer` and `OwSortAnswer`**: since keel
|
|
12
|
+
a6244db (Skeld, h37 #4233) ask and sort spend from the account's daily token rating, one
|
|
13
|
+
meter with the Council. `remaining` stays a count of answers: how many more calls of this
|
|
14
|
+
size fit in what is left today (keel 504437b), never tokens. Typed from keel's code
|
|
15
|
+
(`accounts/ask.py`), since its OpenAPI document gives these answers no schema.
|
|
16
|
+
|
|
17
|
+
### Changed
|
|
18
|
+
- **Custom fields (`x_*`) are in the lookup and on the card.** `buildWorldIndex` finds an
|
|
19
|
+
element by its custom text and numbers, and `renderElement` (so `buildAskContext`) shows
|
|
20
|
+
each one by its own name: `x_eye_colour` reads `eye colour: grey`; an id in one is a link,
|
|
21
|
+
by name; a long value is cut like a description. `atlas_*` machinery stays out, and so do
|
|
22
|
+
object values (a tool's state). Lantern shows and edits custom fields now, so Ask can answer
|
|
23
|
+
what find already could (Temper, h37 #4069). The trial's lookup (`dossiers/lantern-ask`)
|
|
24
|
+
still skips them; parity holds on its ten questions, whose fixture has no custom text.
|
|
25
|
+
- The lookup's stopword set is an array literal, so bundlers mark it pure and drop it from
|
|
26
|
+
apps that never call the lookup (451 bytes; Temper, h17 #4247).
|
|
27
|
+
|
|
28
|
+
## [4.18.1] — 2026-10-12
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
- **Schema repinned to schema-dist v0.32.0-dist.23** (same canonical 00.32.00). The one
|
|
32
|
+
generated change is the `id` doc comment: a UUID, new ids minted as uuidv7, earlier uuidv4
|
|
33
|
+
ids still valid. No type changes. The vendored dist gains `walk/lint_folder.py`.
|
|
34
|
+
- README and AGENTS.md describe `sort()`.
|
|
35
|
+
|
|
8
36
|
## [4.18.0] — 2026-10-12
|
|
9
37
|
|
|
10
38
|
### 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.
|
|
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
|
|
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;
|
|
@@ -2009,8 +2009,13 @@ interface OwAskAnswer {
|
|
|
2009
2009
|
input_tokens: number;
|
|
2010
2010
|
output_tokens: number;
|
|
2011
2011
|
};
|
|
2012
|
-
/**
|
|
2012
|
+
/** How many more calls of this one's size fit in what the account has left today (a count of
|
|
2013
|
+
* answers, never tokens; it never over-promises). */
|
|
2013
2014
|
remaining: number;
|
|
2015
|
+
/** The account's tokens left today after this call (since keel a6244db, 2026-10-14). */
|
|
2016
|
+
tokens_remaining: number;
|
|
2017
|
+
/** The account's daily allowance in tokens, one meter with the Council (since keel a6244db). */
|
|
2018
|
+
token_rating: number;
|
|
2014
2019
|
[k: string]: unknown;
|
|
2015
2020
|
}
|
|
2016
2021
|
/**
|
|
@@ -2090,8 +2095,13 @@ interface OwSortAnswer {
|
|
|
2090
2095
|
input_tokens: number;
|
|
2091
2096
|
output_tokens: number;
|
|
2092
2097
|
};
|
|
2093
|
-
/**
|
|
2098
|
+
/** How many more calls of this one's size fit in what the account has left today; ask and
|
|
2099
|
+
* sort spend from one allowance. */
|
|
2094
2100
|
remaining: number;
|
|
2101
|
+
/** The account's tokens left today after this call (since keel a6244db, 2026-10-14). */
|
|
2102
|
+
tokens_remaining: number;
|
|
2103
|
+
/** The account's daily allowance in tokens, one meter with the Council (since keel a6244db). */
|
|
2104
|
+
token_rating: number;
|
|
2095
2105
|
[k: string]: unknown;
|
|
2096
2106
|
}
|
|
2097
2107
|
/** POST /join/preview: what a join code holds, read without using it (keel #212). */
|
package/dist/index.js
CHANGED
|
@@ -1571,7 +1571,107 @@ function writeWorldFile(files, topDir) {
|
|
|
1571
1571
|
}
|
|
1572
1572
|
|
|
1573
1573
|
// src/lookup.ts
|
|
1574
|
-
var STOP =
|
|
1574
|
+
var STOP = /* @__PURE__ */ new Set([
|
|
1575
|
+
"a",
|
|
1576
|
+
"an",
|
|
1577
|
+
"the",
|
|
1578
|
+
"of",
|
|
1579
|
+
"in",
|
|
1580
|
+
"on",
|
|
1581
|
+
"at",
|
|
1582
|
+
"to",
|
|
1583
|
+
"for",
|
|
1584
|
+
"from",
|
|
1585
|
+
"by",
|
|
1586
|
+
"with",
|
|
1587
|
+
"and",
|
|
1588
|
+
"or",
|
|
1589
|
+
"is",
|
|
1590
|
+
"are",
|
|
1591
|
+
"was",
|
|
1592
|
+
"were",
|
|
1593
|
+
"be",
|
|
1594
|
+
"been",
|
|
1595
|
+
"who",
|
|
1596
|
+
"whom",
|
|
1597
|
+
"whose",
|
|
1598
|
+
"what",
|
|
1599
|
+
"which",
|
|
1600
|
+
"where",
|
|
1601
|
+
"when",
|
|
1602
|
+
"why",
|
|
1603
|
+
"how",
|
|
1604
|
+
"does",
|
|
1605
|
+
"do",
|
|
1606
|
+
"did",
|
|
1607
|
+
"doesn",
|
|
1608
|
+
"has",
|
|
1609
|
+
"have",
|
|
1610
|
+
"had",
|
|
1611
|
+
"it",
|
|
1612
|
+
"its",
|
|
1613
|
+
"this",
|
|
1614
|
+
"that",
|
|
1615
|
+
"these",
|
|
1616
|
+
"those",
|
|
1617
|
+
"there",
|
|
1618
|
+
"their",
|
|
1619
|
+
"they",
|
|
1620
|
+
"them",
|
|
1621
|
+
"he",
|
|
1622
|
+
"she",
|
|
1623
|
+
"his",
|
|
1624
|
+
"her",
|
|
1625
|
+
"him",
|
|
1626
|
+
"i",
|
|
1627
|
+
"me",
|
|
1628
|
+
"my",
|
|
1629
|
+
"we",
|
|
1630
|
+
"our",
|
|
1631
|
+
"you",
|
|
1632
|
+
"your",
|
|
1633
|
+
"about",
|
|
1634
|
+
"tell",
|
|
1635
|
+
"know",
|
|
1636
|
+
"any",
|
|
1637
|
+
"some",
|
|
1638
|
+
"all",
|
|
1639
|
+
"can",
|
|
1640
|
+
"could",
|
|
1641
|
+
"would",
|
|
1642
|
+
"should",
|
|
1643
|
+
"will",
|
|
1644
|
+
"not",
|
|
1645
|
+
"no",
|
|
1646
|
+
"yes",
|
|
1647
|
+
"than",
|
|
1648
|
+
"then",
|
|
1649
|
+
"so",
|
|
1650
|
+
"if",
|
|
1651
|
+
"into",
|
|
1652
|
+
"out",
|
|
1653
|
+
"up",
|
|
1654
|
+
"down",
|
|
1655
|
+
"over",
|
|
1656
|
+
"under",
|
|
1657
|
+
"one",
|
|
1658
|
+
"two",
|
|
1659
|
+
"own",
|
|
1660
|
+
"same",
|
|
1661
|
+
"other",
|
|
1662
|
+
"more",
|
|
1663
|
+
"most",
|
|
1664
|
+
"much",
|
|
1665
|
+
"many",
|
|
1666
|
+
"very",
|
|
1667
|
+
"just",
|
|
1668
|
+
"also",
|
|
1669
|
+
"only",
|
|
1670
|
+
"s",
|
|
1671
|
+
"t",
|
|
1672
|
+
"don",
|
|
1673
|
+
"isn"
|
|
1674
|
+
]);
|
|
1575
1675
|
var SPATIAL = /* @__PURE__ */ new Set(["pin", "marker", "zone", "map"]);
|
|
1576
1676
|
var FIELD_HINTS = {
|
|
1577
1677
|
where: ["location", "parent_location", "birthplace", "locations", "estates", "element_id"],
|
|
@@ -1730,7 +1830,7 @@ function buildWorldIndex(elements) {
|
|
|
1730
1830
|
if (!SPATIAL.has(el.type)) {
|
|
1731
1831
|
const tw = /* @__PURE__ */ new Set();
|
|
1732
1832
|
for (const [field, v] of Object.entries(el)) {
|
|
1733
|
-
if (TEXT_SKIP.has(field) || linkFields.has(field) || field.startsWith("
|
|
1833
|
+
if (TEXT_SKIP.has(field) || linkFields.has(field) || field.startsWith("atlas_")) continue;
|
|
1734
1834
|
const vals = Array.isArray(v) ? v : [v];
|
|
1735
1835
|
for (const x of vals) {
|
|
1736
1836
|
if (typeof x === "number" && Number.isFinite(x)) tw.add(String(x));
|
|
@@ -1908,18 +2008,21 @@ function renderElement(element, index, { descMax = 500, linkMax = 12, incomingMa
|
|
|
1908
2008
|
const unres = /* @__PURE__ */ new Map();
|
|
1909
2009
|
for (const { field } of index.unresolved.get(el.id) || []) unres.set(field, (unres.get(field) || 0) + 1);
|
|
1910
2010
|
for (const [field, v] of Object.entries(el)) {
|
|
1911
|
-
if (RENDER_SKIP.has(field) || field.startsWith("
|
|
2011
|
+
if (RENDER_SKIP.has(field) || field.startsWith("atlas_")) continue;
|
|
2012
|
+
const custom = field.startsWith("x_");
|
|
2013
|
+
const label = custom ? field.slice(2).replace(/_/g, " ") : field;
|
|
1912
2014
|
if (outBy.has(field) || unres.has(field)) {
|
|
1913
2015
|
const names = outBy.get(field) || [];
|
|
1914
|
-
let
|
|
1915
|
-
if (names.length > linkMax)
|
|
2016
|
+
let s2 = names.slice(0, linkMax).join(", ");
|
|
2017
|
+
if (names.length > linkMax) s2 += ` (+${names.length - linkMax} more)`;
|
|
1916
2018
|
const u = unres.get(field);
|
|
1917
|
-
if (u)
|
|
1918
|
-
lines.push(`${
|
|
2019
|
+
if (u) s2 += `${s2 ? "; " : ""}${u} linked element(s) not present in the world data`;
|
|
2020
|
+
lines.push(`${label}: ${s2}`);
|
|
1919
2021
|
continue;
|
|
1920
2022
|
}
|
|
1921
2023
|
if (v === null || v === void 0 || v === "" || Array.isArray(v) && !v.length || typeof v === "object" && !Array.isArray(v)) continue;
|
|
1922
|
-
|
|
2024
|
+
const s = Array.isArray(v) ? v.join(", ") : String(v);
|
|
2025
|
+
lines.push(`${label}: ${custom && s.length > descMax ? s.slice(0, descMax) + "..." : s}`);
|
|
1923
2026
|
}
|
|
1924
2027
|
const inBy = /* @__PURE__ */ new Map();
|
|
1925
2028
|
for (const { field, id } of index.inn.get(el.id) || []) {
|