@polycode-projects/the-mechanical-code-talker 4.1.1 → 4.1.2
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 +31 -18
- package/bin/tmct.mjs +3 -0
- package/data/templates/responses.jsonl +3 -0
- package/package.json +2 -1
- package/src/adapters/memory/core.mjs +1358 -196
- package/src/adapters/memory/inspect.mjs +11 -0
- package/src/adapters/memory/shacl.mjs +38 -0
- package/src/adapters/p2p/webrtc-transport.mjs +28 -5
- package/src/domain/ask-vocab.mjs +39 -0
- package/src/domain/ask.mjs +183 -34
- package/src/domain/grammar/assert.mjs +8 -2
- package/src/domain/hanoi-board.mjs +232 -0
- package/src/domain/ingest-facts.mjs +120 -0
- package/src/domain/interpret/normalize.mjs +49 -0
- package/src/domain/memory/compaction.mjs +284 -0
- package/src/domain/memory/resolution.mjs +171 -0
- package/src/domain/memory/trust.mjs +175 -5
- package/src/domain/memory-facts.mjs +139 -0
- package/src/domain/p2p/facts.mjs +21 -0
- package/src/domain/p2p/peer-id.mjs +15 -0
- package/src/domain/p2p/provenance-relabel.mjs +13 -2
- package/src/domain/p2p/sync-filter.mjs +5 -1
- package/src/domain/p2p/wire.mjs +7 -4
- package/src/domain/scene-compose.mjs +2 -2
- package/src/domain/sprite-facts.mjs +0 -0
- package/src/services/adventure-viz.mjs +5 -1
- package/src/services/adventure.mjs +70 -44
- package/src/services/chat-page-viz.mjs +381 -310
- package/src/services/chat.mjs +273 -155
- package/src/services/code-explorer-viz.mjs +141 -54
- package/src/services/index.mjs +1 -1
- package/src/services/ingest-viz.mjs +134 -9
- package/src/services/ledger-viz.mjs +7 -4
- package/src/services/memory-panel-viz.mjs +8 -3
- package/src/services/mud-turn.mjs +11 -8
- package/src/services/mud-viz.mjs +441 -206
- package/src/services/p2p-room.mjs +110 -23
- package/src/services/plan-viz.mjs +63 -4
- package/src/services/research-viz.mjs +18 -7
- package/src/services/share-overlay-viz.mjs +623 -0
- package/src/services/spider-fly-viz.mjs +2 -2
- package/src/services/sprite-catalog-viz.mjs +303 -78
- package/src/surfaces/web/adventure-browser-entry.mjs +27 -5
- package/src/surfaces/web/chat-browser-entry.mjs +37 -10
- package/src/surfaces/web/code-explorer-browser-entry.mjs +4 -3
- package/src/surfaces/web/ingest-browser-entry.mjs +73 -12
- package/src/surfaces/web/ledger-browser-entry.mjs +32 -7
- package/src/surfaces/web/memory-ask-browser.bundle.js +149 -116
- package/src/surfaces/web/mud-browser-entry.mjs +38 -7
- package/src/surfaces/web/p2p-browser-entry.mjs +1 -1
- package/src/surfaces/web/plan-browser-entry.mjs +33 -2
- package/src/surfaces/web/research-browser-entry.mjs +11 -19
- package/src/surfaces/web/sprites-browser-entry.mjs +39 -8
- package/src/surfaces/web/tmct-surface.mjs +12 -0
- package/src/surfaces/web/turn-session.mjs +10 -3
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
createInMemoryStore, appendFacts, appendRule, loadMemory, readFactRows, removeFacts,
|
|
33
33
|
} from "../../adapters/memory/core.mjs";
|
|
34
34
|
import { parseEntities } from "../../domain/codegraph.mjs";
|
|
35
|
+
import { memoryFactGraphPayload } from "../../domain/memory-facts.mjs";
|
|
35
36
|
import { loadLexicon } from "../../domain/grammar/lexicon.mjs";
|
|
36
37
|
import {
|
|
37
38
|
foldWorldState, worldActionRows, worldDigestRows, roomAffordances,
|
|
@@ -62,7 +63,10 @@ import { graphAsk, enginePlan } from "./engine-surface.mjs";
|
|
|
62
63
|
* are minted, fewer leaves the ones nobody is playing out of the world
|
|
63
64
|
* altogether.
|
|
64
65
|
*
|
|
65
|
-
* Returns `{ memoryDir, graph, windows, snapshot }`.
|
|
66
|
+
* Returns `{ memoryDir, codeGraph, graph, refreshGraph, windows, snapshot }`.
|
|
67
|
+
* `codeGraph` is the known-empty index the turn engine and a scripted
|
|
68
|
+
* autoplayTick read; `graph` is this world's own memory store projected for
|
|
69
|
+
* `ask()` (refreshGraph rebuilds it on demand). `windows` is a plain object
|
|
66
70
|
* keyed by character id, each value `{ character, turn, autoplayTick,
|
|
67
71
|
* visitedRoomIds, turnsTaken, isOutOfPlay, outOfPlayReason }`. `snapshot()` is
|
|
68
72
|
* the one OMNISCIENT read this module exposes — the central world map's own
|
|
@@ -89,7 +93,11 @@ export async function createMudSession(worldPayload, { characters = [], epoch =
|
|
|
89
93
|
// way rather than through the "play <world>" opener (which needs a
|
|
90
94
|
// shipped "player" individual mud-garden deliberately has none of).
|
|
91
95
|
const planHolder = { state: { adventure: { world: worldPayload.name } } };
|
|
92
|
-
|
|
96
|
+
// A known-empty code graph: code-structure questions get the same honest
|
|
97
|
+
// no-code-graph answer an un-pointed CLI session gives, never a crash — the
|
|
98
|
+
// turn engine (and a scripted autoplayTick) keep reading THIS one for their
|
|
99
|
+
// own in-turn code lane.
|
|
100
|
+
const codeGraph = parseEntities({ individuals: [], objectProperties: [] });
|
|
93
101
|
// The world's own minted ids ("groundhog-1", "carrot-2") are declared as
|
|
94
102
|
// vocabulary inside the adventure lane itself, for the length of one world
|
|
95
103
|
// command — see adventure.mjs's own worldLexicon. This page hands over the
|
|
@@ -101,6 +109,17 @@ export async function createMudSession(worldPayload, { characters = [], epoch =
|
|
|
101
109
|
return { rows, state: foldWorldState(worldActionRows(rows)) };
|
|
102
110
|
}
|
|
103
111
|
|
|
112
|
+
// What `tmct.ask()` traverses is a different graph: this shared world's own
|
|
113
|
+
// memory store, projected through memoryFactGraphPayload. Rebuilt on demand
|
|
114
|
+
// rather than once at open, because every character's turn grows the store.
|
|
115
|
+
// Built off readWorld()'s own rows rather than a second readFactRows call.
|
|
116
|
+
let memoryGraph = parseEntities({ individuals: [], objectProperties: [] });
|
|
117
|
+
async function refreshGraph() {
|
|
118
|
+
const { rows } = await readWorld();
|
|
119
|
+
memoryGraph = parseEntities(memoryFactGraphPayload(rows));
|
|
120
|
+
return memoryGraph;
|
|
121
|
+
}
|
|
122
|
+
|
|
104
123
|
async function roomOf(character) {
|
|
105
124
|
const { state } = await readWorld();
|
|
106
125
|
return state.placements.get(character)?.object ?? null;
|
|
@@ -126,10 +145,10 @@ export async function createMudSession(worldPayload, { characters = [], epoch =
|
|
|
126
145
|
if (startRoom) visitedRoomIds.add(startRoom);
|
|
127
146
|
|
|
128
147
|
const turnSession = createTurnSession({
|
|
129
|
-
memoryDir, graph, lexicon, sessionId: character,
|
|
148
|
+
memoryDir, graph: codeGraph, lexicon, sessionId: character,
|
|
130
149
|
vocabHint: 'Try a world command ("dig north", "eat the carrot-1"), or ask "what food do you know about".',
|
|
131
150
|
buildExtraOptions: () => ({
|
|
132
|
-
|
|
151
|
+
actingSubject: character, planState: planHolder.state,
|
|
133
152
|
}),
|
|
134
153
|
captureExtraState: async (result, state) => {
|
|
135
154
|
if ("planState" in result) planHolder.state = state.planState;
|
|
@@ -158,7 +177,7 @@ export async function createMudSession(worldPayload, { characters = [], epoch =
|
|
|
158
177
|
* note }` unmodified, so the caller can render the speech-bubble/
|
|
159
178
|
* dig-flourish triggers straight off `actions`. */
|
|
160
179
|
async autoplayTick(k) {
|
|
161
|
-
const result = await runMudTurn(character, { world: worldPayload.name, memoryDir, env: {}, graph, k });
|
|
180
|
+
const result = await runMudTurn(character, { world: worldPayload.name, memoryDir, env: {}, graph: codeGraph, k });
|
|
162
181
|
// A turn that ended in starvation still happened, and still counts —
|
|
163
182
|
// only a DECLINED turn (no room to act in) leaves the tally alone.
|
|
164
183
|
if (result.room) turnsTaken += 1;
|
|
@@ -272,7 +291,13 @@ export async function createMudSession(worldPayload, { characters = [], epoch =
|
|
|
272
291
|
return claims.length;
|
|
273
292
|
}
|
|
274
293
|
|
|
275
|
-
return {
|
|
294
|
+
return {
|
|
295
|
+
memoryDir,
|
|
296
|
+
codeGraph,
|
|
297
|
+
get graph() { return memoryGraph; },
|
|
298
|
+
refreshGraph,
|
|
299
|
+
windows, snapshot, applyEdit, wave, claimCharacters,
|
|
300
|
+
};
|
|
276
301
|
}
|
|
277
302
|
|
|
278
303
|
/** `count` entries drawn at random from `roster`, in random order, without
|
|
@@ -378,7 +403,13 @@ publishTmctSurface({
|
|
|
378
403
|
}
|
|
379
404
|
return characterWindow.turn(line);
|
|
380
405
|
},
|
|
381
|
-
ask
|
|
406
|
+
// The memory projection is rebuilt first, so a direct tmct.ask() sees every
|
|
407
|
+
// fact any character's turn has written into this shared world since the
|
|
408
|
+
// last one.
|
|
409
|
+
ask: async (request, options, session) => {
|
|
410
|
+
await session.refreshGraph();
|
|
411
|
+
return graphAsk(request, options, session);
|
|
412
|
+
},
|
|
382
413
|
plan: enginePlan,
|
|
383
414
|
page: {
|
|
384
415
|
pickMudRoster, expandMudRoster, mintedCharacterFacts, worldFactsForCast,
|
|
@@ -26,7 +26,7 @@ export {
|
|
|
26
26
|
ROOM_FAILED,
|
|
27
27
|
} from "../../services/p2p-room.mjs";
|
|
28
28
|
export { createTransport } from "../../adapters/p2p/webrtc-transport.mjs";
|
|
29
|
-
export { generatePeerId, generateWorldId, generateDisplayName } from "../../domain/p2p/peer-id.mjs";
|
|
29
|
+
export { generatePeerId, generateWorldId, generateDisplayName, generateNodeId } from "../../domain/p2p/peer-id.mjs";
|
|
30
30
|
export { chatSyncableFacts, mudSyncableFacts } from "../../domain/p2p/sync-filter.mjs";
|
|
31
31
|
export { decodeInviteBlob, encodeInviteBlob } from "../../domain/p2p/wire.mjs";
|
|
32
32
|
export {
|
|
@@ -29,6 +29,7 @@ import { parseEntities } from "../../domain/codegraph.mjs";
|
|
|
29
29
|
import { loadLexicon } from "../../domain/grammar/lexicon.mjs";
|
|
30
30
|
import { DEFAULT_GAME_CONFIG } from "../../domain/game-config.mjs";
|
|
31
31
|
import { hanoiLessonSentences } from "../../domain/hanoi-lesson.mjs";
|
|
32
|
+
import { hanoiBoardRows, hanoiBoardGraphPayload } from "../../domain/hanoi-board.mjs";
|
|
32
33
|
import { computeBlocksLayout, planToPageData, renderInputsFromPlan } from "../../services/plan-viz.mjs";
|
|
33
34
|
import { planToPddl } from "../../services/plan-pddl.mjs";
|
|
34
35
|
import { createTurnSession } from "./turn-session.mjs";
|
|
@@ -86,7 +87,29 @@ export async function createPlanSession({ diskCount = 3, maxDepth = DEFAULT_GAME
|
|
|
86
87
|
if (r.plan) plan = r.plan;
|
|
87
88
|
}
|
|
88
89
|
|
|
89
|
-
|
|
90
|
+
// The board `tmct.ask()` traverses. The plan lane's own states are rows, not
|
|
91
|
+
// a graph, so an ask over this session used to meet an empty one and miss
|
|
92
|
+
// every question about the puzzle in front of the visitor. hanoi-board.mjs
|
|
93
|
+
// projects one position into `{individuals, objectProperties}`; the page
|
|
94
|
+
// calls `showBoard` whenever it mounts a fresh plan or the transport moves
|
|
95
|
+
// the step, so what ask() reads is what the board shows.
|
|
96
|
+
let boardPlan = plan;
|
|
97
|
+
let boardStep = 0;
|
|
98
|
+
let boardGraph = null;
|
|
99
|
+
function showBoard({ plan: nextPlan = boardPlan, step = boardStep } = {}) {
|
|
100
|
+
boardPlan = nextPlan;
|
|
101
|
+
boardStep = Math.max(0, Math.floor(Number(step) || 0));
|
|
102
|
+
boardGraph = parseEntities(hanoiBoardGraphPayload(hanoiBoardRows({ plan: boardPlan, step: boardStep })));
|
|
103
|
+
return boardGraph;
|
|
104
|
+
}
|
|
105
|
+
showBoard();
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
memoryDir, sessionId, graph, diskCount, maxDepth, plan, turn: session.turn,
|
|
109
|
+
showBoard,
|
|
110
|
+
get boardGraph() { return boardGraph; },
|
|
111
|
+
get boardStep() { return boardStep; },
|
|
112
|
+
};
|
|
90
113
|
}
|
|
91
114
|
|
|
92
115
|
// `tmct.page` keeps the board layout and the PDDL/OWL-RDF formatting the
|
|
@@ -95,9 +118,17 @@ export async function createPlanSession({ diskCount = 3, maxDepth = DEFAULT_GAME
|
|
|
95
118
|
// CAPABILITY planner, not the puzzle solver: a typed "solve it" is a
|
|
96
119
|
// conversational turn like any other, so the page reaches the hanoi plan
|
|
97
120
|
// through `tmct.turn("solve it", { maxDepth })` and reads `.plan` off it.
|
|
121
|
+
//
|
|
122
|
+
// `tmct.ask(q, { step })` answers over the projected BOARD rather than the
|
|
123
|
+
// session's own (empty) code graph, so a question about the puzzle is grounded
|
|
124
|
+
// in the position on screen. Passing `step` moves the board first, which is
|
|
125
|
+
// how the page keeps the two in step while the transport scrubs.
|
|
98
126
|
publishTmctSurface({
|
|
99
127
|
open: createPlanSession,
|
|
100
|
-
ask:
|
|
128
|
+
ask: (request, options, session) => {
|
|
129
|
+
if (options?.step != null) session.showBoard({ step: options.step });
|
|
130
|
+
return graphAsk(request, options, { graph: session.boardGraph, memoryDir: session.memoryDir });
|
|
131
|
+
},
|
|
101
132
|
plan: enginePlan,
|
|
102
133
|
page: { computeBlocksLayout, planToPageData, renderInputsFromPlan, planToPddl, registerWinkModel },
|
|
103
134
|
});
|
|
@@ -43,13 +43,6 @@ import { publishTmctSurface } from "./tmct-surface.mjs";
|
|
|
43
43
|
import { enginePlan } from "./engine-surface.mjs";
|
|
44
44
|
import { exportFactsJsonl } from "./memory-stats.mjs";
|
|
45
45
|
|
|
46
|
-
// The Fact individual's first-write-wins timestamp, read straight off the
|
|
47
|
-
// stored attribute (mgx:createdAt) so a "recently learned" ordering never
|
|
48
|
-
// has to re-parse a provenance tag — the research lane's own tags carry a
|
|
49
|
-
// depth, not a timestamp, so the attribute is the one field every source
|
|
50
|
-
// shares.
|
|
51
|
-
const CREATED_AT_ATTR = "mgx:createdAt";
|
|
52
|
-
|
|
53
46
|
/**
|
|
54
47
|
* The source key ONE provenance tag folds to, for the page's per-source
|
|
55
48
|
* checkboxes/history. `sessionIds` tells a teach tag apart: a teach:chat tag
|
|
@@ -102,18 +95,17 @@ const clonePayload = (payload) => {
|
|
|
102
95
|
try { return structuredClone(payload); } catch { return JSON.parse(JSON.stringify(payload)); }
|
|
103
96
|
};
|
|
104
97
|
|
|
105
|
-
/** Fact rows plus the createdAt
|
|
106
|
-
*
|
|
107
|
-
*
|
|
98
|
+
/** Fact rows plus the createdAt readFactRows keeps per assertion rather than per
|
|
99
|
+
* row — the "recently learned" panels want the timestamp, the ask filter wants
|
|
100
|
+
* the id, both want the provenance. A triple asserted by several sources was
|
|
101
|
+
* first learned when the EARLIEST of them said it, which is the moment those
|
|
102
|
+
* panels are ordering by. */
|
|
108
103
|
async function factRowsWithCreatedAt(memoryDir) {
|
|
109
104
|
const memory = await loadMemory(memoryDir);
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
createdById.set(ind.id, at);
|
|
115
|
-
}
|
|
116
|
-
return readFactRows(memory).map((row) => ({ ...row, createdAt: createdById.get(row.id) || "" }));
|
|
105
|
+
return readFactRows(memory).map((row) => {
|
|
106
|
+
const stamps = (row.assertions || []).map((a) => a.createdAt).filter(Boolean).sort();
|
|
107
|
+
return { ...row, createdAt: stamps[0] || "" };
|
|
108
|
+
});
|
|
117
109
|
}
|
|
118
110
|
|
|
119
111
|
const SOURCE_ORDER = ["taught", "ingest", "research"];
|
|
@@ -212,7 +204,7 @@ export function createResearchSession({ seedPayload = null, vocabSeeded = false,
|
|
|
212
204
|
|
|
213
205
|
const graph = parseEntities({ individuals: [], objectProperties: [] });
|
|
214
206
|
const lexicon = loadLexicon();
|
|
215
|
-
const vocabHint = vocabExampleHint(vocabSeeded);
|
|
207
|
+
const vocabHint = vocabExampleHint(vocabSeeded, "browser");
|
|
216
208
|
// A DISTINCT id so an ingested fact's teach tag is told apart from a typed
|
|
217
209
|
// teach turn's by session id alone — the whole reason the two growth paths
|
|
218
210
|
// stay separable in the source panel.
|
|
@@ -236,7 +228,7 @@ export function createResearchSession({ seedPayload = null, vocabSeeded = false,
|
|
|
236
228
|
sessionId: globalThis.crypto?.randomUUID?.() ?? String(Date.now()),
|
|
237
229
|
buildExtraOptions: () => ({
|
|
238
230
|
researchConfig, liveReference: liveReferenceOn, onLiveLookup,
|
|
239
|
-
|
|
231
|
+
synthesisBudget: synthesisBudgetOn,
|
|
240
232
|
}),
|
|
241
233
|
captureExtraState: (result) => {
|
|
242
234
|
if (typeof result.liveReference === "boolean" || result.liveReference === "supplement" || result.liveReference === "always") {
|
|
@@ -18,36 +18,62 @@
|
|
|
18
18
|
// a typed class name through ask.mjs's resolveObject, so it needs the real
|
|
19
19
|
// resolver in the page rather than a self-contained function the page could
|
|
20
20
|
// splice in as text.
|
|
21
|
-
|
|
21
|
+
//
|
|
22
|
+
// `tmct.ask()` needs a real graph to traverse (engine-surface.mjs's graphAsk
|
|
23
|
+
// dispatches tmct_ask over `session.graph`), so this session projects its own
|
|
24
|
+
// store into one via spriteFactGraphPayload — sprite-facts.mjs's own
|
|
25
|
+
// counterpart to spider-fly-browser-entry.mjs's worldRelationGraphPayload
|
|
26
|
+
// use. `refreshGraph()` rebuilds it from the store's CURRENT rows (not just
|
|
27
|
+
// the embedded factRows), so a fact taught mid-session is visible to a later
|
|
28
|
+
// ask() the same way spider-fly's board rebuild is; `turn()` and the
|
|
29
|
+
// published `ask` route both call it first, mirroring spider-fly's exact
|
|
30
|
+
// wiring points.
|
|
31
|
+
import { createInMemoryStore, appendFacts, normFactTerm, loadMemory, readFactRows } from "../../adapters/memory/core.mjs";
|
|
22
32
|
import { extractSceneItems } from "../../domain/scene-compose.mjs";
|
|
23
33
|
import { parseEntities } from "../../domain/codegraph.mjs";
|
|
24
34
|
import { loadLexicon } from "../../domain/grammar/lexicon.mjs";
|
|
25
|
-
import { SPRITE_FACTS_PROVENANCE } from "../../domain/sprite-facts.mjs";
|
|
35
|
+
import { SPRITE_FACTS_PROVENANCE, spriteFactGraphPayload } from "../../domain/sprite-facts.mjs";
|
|
26
36
|
import { registerWinkModel } from "../../adapters/wink-model.mjs";
|
|
27
37
|
import { createTurnSession } from "./turn-session.mjs";
|
|
28
38
|
import { publishTmctSurface } from "./tmct-surface.mjs";
|
|
29
39
|
import { graphAsk, enginePlan } from "./engine-surface.mjs";
|
|
30
40
|
|
|
31
41
|
/** A live in-memory chat session seeded with the embedded sprite-facts rows.
|
|
32
|
-
* Returns { memoryDir, sessionId, graph, factCount, turn }. */
|
|
42
|
+
* Returns { memoryDir, sessionId, graph, refreshGraph, factCount, turn }. */
|
|
33
43
|
export async function createSpriteCatalogSession({ factRows = [] } = {}) {
|
|
34
44
|
const memoryDir = createInMemoryStore();
|
|
35
45
|
await appendFacts(memoryDir, factRows.map((f) => ({
|
|
36
46
|
subject: f.subject, predicate: f.predicate, object: f.object, provenance: SPRITE_FACTS_PROVENANCE,
|
|
37
47
|
})));
|
|
38
48
|
|
|
39
|
-
|
|
49
|
+
let graph = parseEntities({ individuals: [], objectProperties: [] });
|
|
50
|
+
async function refreshGraph() {
|
|
51
|
+
const rows = readFactRows(await loadMemory(memoryDir));
|
|
52
|
+
graph = parseEntities(spriteFactGraphPayload(rows));
|
|
53
|
+
}
|
|
54
|
+
await refreshGraph();
|
|
55
|
+
|
|
40
56
|
const lexicon = loadLexicon();
|
|
41
57
|
const sessionId = globalThis.crypto?.randomUUID?.() ?? String(Date.now());
|
|
42
58
|
|
|
43
|
-
|
|
59
|
+
// `graph` is re-read here, not captured once: createTurnSession binds its
|
|
60
|
+
// own copy at creation, and refreshGraph() reassigns this closure's own
|
|
61
|
+
// variable on every call.
|
|
62
|
+
const turnSession = createTurnSession({
|
|
63
|
+
memoryDir, graph, lexicon, sessionId, vocabHint: "",
|
|
64
|
+
buildExtraOptions: () => ({ graph }),
|
|
65
|
+
});
|
|
44
66
|
|
|
45
67
|
return {
|
|
46
68
|
memoryDir,
|
|
47
69
|
sessionId,
|
|
48
|
-
graph,
|
|
70
|
+
get graph() { return graph; },
|
|
71
|
+
refreshGraph,
|
|
49
72
|
factCount: factRows.length,
|
|
50
|
-
turn
|
|
73
|
+
async turn(line) {
|
|
74
|
+
await refreshGraph();
|
|
75
|
+
return turnSession.turn(line);
|
|
76
|
+
},
|
|
51
77
|
};
|
|
52
78
|
}
|
|
53
79
|
|
|
@@ -58,7 +84,12 @@ export async function createSpriteCatalogSession({ factRows = [] } = {}) {
|
|
|
58
84
|
// rather than answering anything.
|
|
59
85
|
publishTmctSurface({
|
|
60
86
|
open: createSpriteCatalogSession,
|
|
61
|
-
ask
|
|
87
|
+
// The graph is rebuilt first, so a direct tmct.ask() call (not just a
|
|
88
|
+
// typed chat turn) sees any fact taught since the last one.
|
|
89
|
+
ask: async (request, options, session) => {
|
|
90
|
+
await session.refreshGraph();
|
|
91
|
+
return graphAsk(request, options, session);
|
|
92
|
+
},
|
|
62
93
|
plan: enginePlan,
|
|
63
94
|
page: { registerWinkModel, normFactTerm, extractSceneItems },
|
|
64
95
|
});
|
|
@@ -25,6 +25,18 @@
|
|
|
25
25
|
// them apart at a glance, which is exactly what eleven flat bags made
|
|
26
26
|
// impossible.
|
|
27
27
|
//
|
|
28
|
+
// Two more members show up on some pages, by convention rather than by
|
|
29
|
+
// anything this function returns: `tmct.ready` is the page's own boot
|
|
30
|
+
// promise (chat, ingest), and `tmct.lastSave` is its last background-save
|
|
31
|
+
// record, `{at, ms}` (chat, adventure). Neither can be threaded through
|
|
32
|
+
// `publishTmctSurface(...)` itself — boot is still running when this
|
|
33
|
+
// function returns, so the page's own script sets each once it reaches
|
|
34
|
+
// that point (see chat-page-viz.mjs, ingest-viz.mjs, adventure-viz.mjs).
|
|
35
|
+
// Each page's older bare global — window.tmctChatReady, tmctIngestReady,
|
|
36
|
+
// tmctChatLastSave, tmctAdventureLastSave — keeps working unchanged;
|
|
37
|
+
// `tmct.ready` / `tmct.lastSave` just reach the same value under the one
|
|
38
|
+
// `tmct.*` name everything else on this page already uses.
|
|
39
|
+
//
|
|
28
40
|
// `ask` and `plan` are supplied per page rather than fixed here, because what
|
|
29
41
|
// a page can ground a question against genuinely differs: code-explorer holds
|
|
30
42
|
// a code graph, spider-fly holds a live board projected into one, the ledger
|
|
@@ -9,8 +9,15 @@
|
|
|
9
9
|
// capture, and a return shape covering every field one caller or another
|
|
10
10
|
// reads back.
|
|
11
11
|
//
|
|
12
|
+
// Every caller of this wrapper is a page by construction, so `uiContext:
|
|
13
|
+
// "browser"` is a DEFAULT here rather than something each entry remembers to
|
|
14
|
+
// pass. It is what makes the engine's dead-ends name an exit a page can take
|
|
15
|
+
// ("teach me a fact") instead of the CLI's `tmct index`/`--repo`/`tmct init`.
|
|
16
|
+
// Five of the nine already passed it and four had never got round to it, which
|
|
17
|
+
// is exactly the drift a shared default removes.
|
|
18
|
+
//
|
|
12
19
|
// The nine differ in what they hand `runTurn` beyond the common core
|
|
13
|
-
// (`
|
|
20
|
+
// (`synthesisBudget`, `gameConfig`, `researchConfig`,
|
|
14
21
|
// `actingSubject`, a per-character `sessionId`...) and in what they do with a
|
|
15
22
|
// turn's result besides the standard focus/last/planState/researchState fold
|
|
16
23
|
// (sync an externally-held plan holder, grow a visited-rooms set, bump a
|
|
@@ -41,7 +48,7 @@ function turnErrorFallback(message) {
|
|
|
41
48
|
*
|
|
42
49
|
* `buildExtraOptions(state, callArgs)` (optional) returns extra `runTurn`
|
|
43
50
|
* options to merge OVER the defaults below — anything a specific page needs
|
|
44
|
-
* (`
|
|
51
|
+
* (`synthesisBudget`, `gameConfig`, `researchConfig`,
|
|
45
52
|
* a per-character `actingSubject`/`sessionId`, or a `planState` read from an
|
|
46
53
|
* external holder instead of this closure's own). `state` is
|
|
47
54
|
* `{ focus, last, planState, researchState }` as this turn is about to run;
|
|
@@ -88,7 +95,7 @@ export function createTurnSession({
|
|
|
88
95
|
try {
|
|
89
96
|
result = await runTurn(line, {
|
|
90
97
|
config: null, source: null, graph, focus, last, memoryDir, sessionId,
|
|
91
|
-
env: {}, lexicon, vocabHint, planState, researchState,
|
|
98
|
+
env: {}, lexicon, vocabHint, planState, researchState, uiContext: "browser",
|
|
92
99
|
...extra,
|
|
93
100
|
});
|
|
94
101
|
} catch (e) {
|