@polycode-projects/the-mechanical-code-talker 2.10.5 → 2.11.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/README.md +2 -2
- package/corpus/sprites/src/sprite-facts.jsonl +18 -0
- package/corpus/worlds/manifest.json +5 -5
- package/corpus/worlds/shards/ashcombe-hall.jsonl.gz +0 -0
- package/corpus/worlds/src/ashcombe-hall.jsonl +27 -0
- package/data/sprites/book-icon.toml +12 -0
- package/data/sprites/cellar-icon.toml +12 -0
- package/data/sprites/drawing-room-icon.toml +13 -0
- package/data/sprites/garden-icon.toml +12 -0
- package/data/sprites/kitchen-icon.toml +13 -0
- package/data/sprites/library-icon.toml +12 -0
- package/data/sprites/pan-icon.toml +11 -0
- package/data/sprites/study-icon.toml +12 -0
- package/package.json +5 -2
- package/src/adapters/corpus/wikipedia-live.mjs +182 -26
- package/src/adapters/corpus/worlds-pack.mjs +8 -2
- package/src/adapters/toml-config.mjs +6 -0
- package/src/domain/memory/trust.mjs +11 -0
- package/src/domain/worlds-pack.mjs +50 -0
- package/src/services/adventure-autoplay.mjs +5 -2
- package/src/services/adventure-viz.mjs +301 -33
- package/src/services/adventure.mjs +162 -14
- package/src/services/chat-page-viz.mjs +265 -189
- package/src/services/chat-session.mjs +15 -5
- package/src/services/chat.mjs +286 -43
- package/src/services/code-explorer-viz.mjs +183 -75
- package/src/services/extract-facts.mjs +118 -28
- package/src/services/ingest-viz.mjs +328 -79
- package/src/services/ledger-viz.mjs +99 -0
- package/src/services/memory-panel-viz.mjs +159 -0
- package/src/services/research.mjs +266 -0
- package/src/services/sentences.mjs +19 -0
- package/src/services/spider-fly-viz.mjs +21 -5
- package/src/surfaces/web/adventure-browser-entry.mjs +9 -5
- package/src/surfaces/web/chat-browser-entry.mjs +28 -11
- package/src/surfaces/web/code-explorer-browser-entry.mjs +27 -11
- package/src/surfaces/web/ingest-browser-entry.mjs +123 -41
- package/src/surfaces/web/ledger-browser-entry.mjs +10 -4
- package/src/surfaces/web/memory-ask-browser.bundle.js +112 -112
- package/src/surfaces/web/memory-stats.mjs +53 -0
|
@@ -15,7 +15,7 @@ import { readFileSync } from "node:fs";
|
|
|
15
15
|
import { gunzipSync } from "node:zlib";
|
|
16
16
|
import { fileURLToPath } from "node:url";
|
|
17
17
|
import { dirname, join } from "node:path";
|
|
18
|
-
import { isWorldsIndexEntry, isWorldRow, isWorldFactRow, isWorldRuleRow, isWorldMetaRow } from "../../domain/worlds-pack.mjs";
|
|
18
|
+
import { isWorldsIndexEntry, isWorldRow, isWorldFactRow, isWorldRuleRow, isWorldMetaRow, expandWorldDefaultContents } from "../../domain/worlds-pack.mjs";
|
|
19
19
|
|
|
20
20
|
const PKG_ROOT = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "..");
|
|
21
21
|
|
|
@@ -84,7 +84,13 @@ export function loadWorld(dir, worldName) {
|
|
|
84
84
|
else if (isWorldMetaRow(row) && !meta) meta = row;
|
|
85
85
|
} catch { /* tolerated: a bad line loses one row, not the world */ }
|
|
86
86
|
}
|
|
87
|
-
|
|
87
|
+
// Class-default contents (library -> a book, kitchen -> a pan) are
|
|
88
|
+
// materialized here, the one choke point every loader path runs through
|
|
89
|
+
// (openAdventure, the site build, the tests) — never baked into the
|
|
90
|
+
// shipped shard, which stays a byte-copy of its hand-authored source.
|
|
91
|
+
if (facts.length || rules.length || meta) {
|
|
92
|
+
payload = { name: worldName, facts: expandWorldDefaultContents(facts), rules, meta };
|
|
93
|
+
}
|
|
88
94
|
}
|
|
89
95
|
worldCacheByKey.set(key, payload);
|
|
90
96
|
return payload;
|
|
@@ -125,6 +125,12 @@ export async function normalizeConfig(raw, { configDir } = {}) {
|
|
|
125
125
|
if (src.games !== undefined) cfg.games = src.games;
|
|
126
126
|
if (src.planning !== undefined) cfg.planning = src.planning;
|
|
127
127
|
|
|
128
|
+
// Research-lane knobs (src/services/research.mjs): sparse PASS-THROUGH,
|
|
129
|
+
// same discipline as [games.*] — the raw `[research]` table
|
|
130
|
+
// (fanout_limit / depth_limit / min_interval_ms, snake_case) rides through
|
|
131
|
+
// unmodified; clamping and default-filling is resolveResearchConfig's job.
|
|
132
|
+
if (src.research !== undefined) cfg.research = src.research;
|
|
133
|
+
|
|
128
134
|
const idx = src.index || {};
|
|
129
135
|
const index = {};
|
|
130
136
|
if (idx.languages !== undefined) index.languages = idx.languages;
|
|
@@ -77,6 +77,17 @@ export function provenanceTagToSource(tag) {
|
|
|
77
77
|
const pack = rest.slice(0, colon) || "unknown";
|
|
78
78
|
return { kind: referenceKindFor(pack), pack, article: rest.slice(colon + 1) };
|
|
79
79
|
}
|
|
80
|
+
// research:<topic>@<depth> — the research lane's Simple English Wikipedia
|
|
81
|
+
// loads. Live-fetched at query time like the wikipedia-live pack, so it
|
|
82
|
+
// scores at the same referenceLive prior, below every curated pack. Parsed
|
|
83
|
+
// from the FULL tag (a topic may contain spaces); the depth segment records
|
|
84
|
+
// how far the fan-out reached and is not part of the Source identity.
|
|
85
|
+
if (t.startsWith("research:")) {
|
|
86
|
+
const rest = t.slice("research:".length);
|
|
87
|
+
const at = rest.lastIndexOf("@");
|
|
88
|
+
const topic = (at >= 0 ? rest.slice(0, at) : rest).trim();
|
|
89
|
+
return { kind: "referenceLive", pack: "research", article: topic || "unknown" };
|
|
90
|
+
}
|
|
80
91
|
const head = t.split(/\s+/)[0]; // drop trailing " /r/IsA" etc.
|
|
81
92
|
if (head.startsWith("corpus-weak:")) return { kind: "corpusWeak", name: head.slice("corpus-weak:".length) || "unknown" };
|
|
82
93
|
if (head.startsWith("corpus:")) return { kind: "corpus", name: head.slice("corpus:".length) || "unknown" };
|
|
@@ -69,3 +69,53 @@ export function isWorldRow(row) {
|
|
|
69
69
|
export function worldProvenanceTag(worldName) {
|
|
70
70
|
return `world:${worldName}`;
|
|
71
71
|
}
|
|
72
|
+
|
|
73
|
+
const DEFAULT_CONTAINS_PREDICATE = "mgx:default-contains";
|
|
74
|
+
|
|
75
|
+
/** Materialize a world's class-default contents: for every
|
|
76
|
+
* `<room> mgx:default-contains <class>` fact, mint one placed, portable
|
|
77
|
+
* instance of that class in that room unless the room already holds one. A
|
|
78
|
+
* minted book gets `rdf:type <class>` (so it resolves its own sprite),
|
|
79
|
+
* `rdf:type portable` (so the take family accepts it), and
|
|
80
|
+
* `mgx:located-in <room>` (so it shows up in the room and can be carried
|
|
81
|
+
* out). Pure and deterministic: defaults are visited in sorted order, and a
|
|
82
|
+
* collision mints `<class>-2`, `<class>-3`… so re-running never renames an
|
|
83
|
+
* earlier instance. Rows keep whatever world/kind wrapper the input rows
|
|
84
|
+
* carry, so both a loaded shard (world rows) and a bare triple list expand
|
|
85
|
+
* the same way. */
|
|
86
|
+
export function expandWorldDefaultContents(facts) {
|
|
87
|
+
const rows = facts || [];
|
|
88
|
+
const defaults = rows
|
|
89
|
+
.filter((r) => r.predicate === DEFAULT_CONTAINS_PREDICATE)
|
|
90
|
+
.sort((a, b) => `${a.subject}\0${a.object}`.localeCompare(`${b.subject}\0${b.object}`));
|
|
91
|
+
if (!defaults.length) return rows;
|
|
92
|
+
|
|
93
|
+
const instanceIds = new Set(rows.filter((r) => r.predicate === "rdf:type").map((r) => r.subject));
|
|
94
|
+
const placedIn = new Map();
|
|
95
|
+
for (const r of rows) {
|
|
96
|
+
if (r.predicate === "mgx:located-in") placedIn.set(r.subject, r.object);
|
|
97
|
+
}
|
|
98
|
+
const roomAlreadyHas = (klass, room) =>
|
|
99
|
+
rows.some((r) => r.predicate === "rdf:type" && r.object === klass && placedIn.get(r.subject) === room);
|
|
100
|
+
|
|
101
|
+
const wrapper = rows.find((r) => typeof r.world === "string" && r.kind === "fact");
|
|
102
|
+
const wrap = (subject, predicate, object) => ({
|
|
103
|
+
...(wrapper ? { world: wrapper.world, kind: "fact" } : {}),
|
|
104
|
+
subject, predicate, object,
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
const minted = [];
|
|
108
|
+
for (const d of defaults) {
|
|
109
|
+
const room = d.subject;
|
|
110
|
+
const klass = d.object;
|
|
111
|
+
if (roomAlreadyHas(klass, room)) continue;
|
|
112
|
+
let id = klass;
|
|
113
|
+
let n = 1;
|
|
114
|
+
while (instanceIds.has(id)) { n += 1; id = `${klass}-${n}`; }
|
|
115
|
+
instanceIds.add(id);
|
|
116
|
+
minted.push(wrap(id, "rdf:type", klass));
|
|
117
|
+
minted.push(wrap(id, "rdf:type", "portable"));
|
|
118
|
+
minted.push(wrap(id, "mgx:located-in", room));
|
|
119
|
+
}
|
|
120
|
+
return minted.length ? [...rows, ...minted] : rows;
|
|
121
|
+
}
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
// fact simply has nothing for this module to infer a goal toward.
|
|
27
27
|
import { findActionPath } from "../domain/planning.mjs";
|
|
28
28
|
import { loadMemory, readFactRows } from "../adapters/memory/core.mjs";
|
|
29
|
-
import { foldWorldState, adventureTurn } from "./adventure.mjs";
|
|
29
|
+
import { foldWorldState, adventureTurn, worldActionRows } from "./adventure.mjs";
|
|
30
30
|
|
|
31
31
|
const SNAPSHOT_RE = /^(.+)@turn(\d+)$/;
|
|
32
32
|
const baseSubjectOf = (subject) => SNAPSHOT_RE.exec(subject)?.[1] ?? subject;
|
|
@@ -138,7 +138,10 @@ async function stepTowardThenAct({
|
|
|
138
138
|
*/
|
|
139
139
|
export async function runAdventureAutoplayTick(memoryDir, opts = {}) {
|
|
140
140
|
const { exposedRoomIds, planHolder, sessionId = "", env = {}, graph = null, cache = null } = opts;
|
|
141
|
-
|
|
141
|
+
// Auto-play reasons over the game world only — the same isolation the manual
|
|
142
|
+
// command path uses, so a fact the player taught mid-game never steers the
|
|
143
|
+
// planner toward a room the world never placed anything in.
|
|
144
|
+
const rows = worldActionRows(readFactRows(await loadMemory(memoryDir)));
|
|
142
145
|
const state = foldWorldState(rows);
|
|
143
146
|
const here = state.placements.get("player")?.object ?? null;
|
|
144
147
|
const exposed = new Set(exposedRoomIds || []);
|