@onlyworlds/sdk 4.18.1 → 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 CHANGED
@@ -43,8 +43,10 @@ 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. 50 a day per
47
- account (`err.isQuotaExceeded`); `isAskUnavailable`, `isAskFailed` count nothing.
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.
48
50
  - Sort (since 4.18.0, account token): `account.sort({ worldId, notes, slice })` turns unsorted
49
51
  notes (text, or a picture already uploaded into the world) into rows to review: `make`,
50
52
  `add_to`, `link`, `ask`, plus `not_proposed` with reasons. Ids come only from your `slice`
package/CHANGELOG.md CHANGED
@@ -5,6 +5,26 @@ 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
+
8
28
  ## [4.18.1] — 2026-10-12
9
29
 
10
30
  ### Changed
package/dist/index.d.ts CHANGED
@@ -2009,8 +2009,13 @@ interface OwAskAnswer {
2009
2009
  input_tokens: number;
2010
2010
  output_tokens: number;
2011
2011
  };
2012
- /** Questions the account has left today. */
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
- /** Questions the account has left today: a sort counts as one ask. */
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 = new Set("a an the of in on at to for from by with and or is are was were be been who whom whose what which where when why how does do did doesn has have had it its this that these those there their they them he she his her him i me my we our you your about tell know any some all can could would should will not no yes than then so if into out up down over under one two own same other more most much many very just also only s t don isn".split(" "));
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("x_") || field.startsWith("atlas_")) continue;
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("x_") || field.startsWith("atlas_")) continue;
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 s = names.slice(0, linkMax).join(", ");
1915
- if (names.length > linkMax) s += ` (+${names.length - linkMax} more)`;
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) s += `${s ? "; " : ""}${u} linked element(s) not present in the world data`;
1918
- lines.push(`${field}: ${s}`);
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
- lines.push(`${field}: ${Array.isArray(v) ? v.join(", ") : v}`);
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) || []) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlyworlds/sdk",
3
- "version": "4.18.1",
3
+ "version": "4.19.0",
4
4
  "description": "TypeScript SDK for the OnlyWorlds API - build world-building applications with type safety",
5
5
  "type": "module",
6
6
  "exports": {