@polycode-projects/the-mechanical-code-talker 4.1.0 → 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/domain/sprite-request.mjs +1 -1
- package/src/services/adventure-viz.mjs +43 -39
- package/src/services/adventure.mjs +70 -44
- package/src/services/chat-page-viz.mjs +403 -332
- package/src/services/chat.mjs +274 -156
- package/src/services/code-explorer-viz.mjs +142 -55
- package/src/services/index.mjs +1 -1
- package/src/services/ingest-viz.mjs +153 -28
- package/src/services/ledger-viz.mjs +47 -47
- package/src/services/memory-panel-viz.mjs +8 -3
- package/src/services/mud-turn.mjs +11 -8
- package/src/services/mud-viz.mjs +474 -234
- package/src/services/p2p-room.mjs +110 -23
- package/src/services/plan-viz.mjs +72 -13
- package/src/services/research-viz.mjs +35 -24
- package/src/services/share-overlay-viz.mjs +623 -0
- package/src/services/spider-fly-viz.mjs +24 -24
- package/src/services/sprite-catalog-viz.mjs +307 -82
- package/src/surfaces/web/adventure-browser-entry.mjs +46 -25
- package/src/surfaces/web/chat-browser-entry.mjs +55 -9
- package/src/surfaces/web/code-explorer-browser-entry.mjs +30 -16
- package/src/surfaces/web/engine-surface.mjs +82 -0
- package/src/surfaces/web/ingest-browser-entry.mjs +81 -11
- package/src/surfaces/web/ledger-browser-entry.mjs +47 -14
- package/src/surfaces/web/memory-ask-browser-entry.mjs +55 -13
- package/src/surfaces/web/memory-ask-browser.bundle.js +149 -116
- package/src/surfaces/web/mud-browser-entry.mjs +77 -25
- package/src/surfaces/web/p2p-browser-entry.mjs +1 -1
- package/src/surfaces/web/plan-browser-entry.mjs +49 -11
- package/src/surfaces/web/research-browser-entry.mjs +33 -24
- package/src/surfaces/web/spider-fly-browser-entry.mjs +32 -13
- package/src/surfaces/web/sprites-browser-entry.mjs +51 -11
- package/src/surfaces/web/tmct-surface.mjs +159 -0
- package/src/surfaces/web/turn-session.mjs +16 -5
- package/src/tools/server.mjs +13 -6
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
// tmct-surface.mjs — the one contract every demo page has with the engine.
|
|
2
|
+
//
|
|
3
|
+
// Each browser entry used to publish its own bag of primitives under its own
|
|
4
|
+
// name (tmctChat, tmctMud, tmctLedger, tmctSpiderFly, ...), so a visitor
|
|
5
|
+
// reading one page's source met a different wall of raw functions on every
|
|
6
|
+
// page, wired together by hand. mud-browser-entry.mjs's own header stated the
|
|
7
|
+
// reason for its 25: "so mud-viz.mjs's own inlined script never duplicates
|
|
8
|
+
// sprite resolution or the digest/affordance/knowledge readers". Right
|
|
9
|
+
// instinct, wrong unit — the page still had to know 25 names to say one
|
|
10
|
+
// sentence.
|
|
11
|
+
//
|
|
12
|
+
// This publishes ONE `globalThis.tmct` instead, and every page reaches the
|
|
13
|
+
// engine the same way:
|
|
14
|
+
//
|
|
15
|
+
// await tmct.open(...) open this page's session
|
|
16
|
+
// tmct.session the live session, once opened
|
|
17
|
+
// await tmct.turn(line) one conversational turn, the dock's entry point
|
|
18
|
+
// await tmct.ask(request) one grounded question, prose plus its evidence
|
|
19
|
+
// await tmct.plan(request) one compound request, planned over what's loaded
|
|
20
|
+
//
|
|
21
|
+
// Whatever a page still needs that has NO plain-English form lives on
|
|
22
|
+
// `tmct.page` — canvas geometry, sprite templates, a wink model to register, a
|
|
23
|
+
// digest structure table. The split is the point: `tmct.ask(...)` is tmct
|
|
24
|
+
// answering, `tmct.page.cellId(...)` is this page drawing. A reader can tell
|
|
25
|
+
// them apart at a glance, which is exactly what eleven flat bags made
|
|
26
|
+
// impossible.
|
|
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
|
+
//
|
|
40
|
+
// `ask` and `plan` are supplied per page rather than fixed here, because what
|
|
41
|
+
// a page can ground a question against genuinely differs: code-explorer holds
|
|
42
|
+
// a code graph, spider-fly holds a live board projected into one, the ledger
|
|
43
|
+
// dock holds a memory store and no graph at all. A page that supplies neither
|
|
44
|
+
// gets an honest refusal naming why, never a guess — the same promise the
|
|
45
|
+
// engine itself makes.
|
|
46
|
+
|
|
47
|
+
const NO_SESSION = "no session is open on this page yet — await tmct.open() first";
|
|
48
|
+
|
|
49
|
+
// The demo ledger page carries TWO bundles at once: the committed
|
|
50
|
+
// question-only one inlined into the HTML (memory-ask-browser-entry.mjs) and
|
|
51
|
+
// the demo site's own full turn engine as a separate script tag
|
|
52
|
+
// (ledger-browser-entry.mjs). Both publish this surface, and which one the
|
|
53
|
+
// browser runs first is not something either can promise. So the
|
|
54
|
+
// question-only one publishes as a `fallback` and the full engine always
|
|
55
|
+
// wins, whichever order they load in. Registered globally rather than
|
|
56
|
+
// module-locally because the two bundles carry their own copy of this module.
|
|
57
|
+
const FALLBACK = Symbol.for("tmct.surface.fallback");
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* `publishTmctSurface({ open, ask, plan, turn, page, target })` installs
|
|
61
|
+
* `target.tmct` (default `globalThis`) and returns it.
|
|
62
|
+
*
|
|
63
|
+
* `open(...args)` is the page's own session factory and is the only required
|
|
64
|
+
* argument — `createChatSession`, `createMudSession`, `createPlanSession` and
|
|
65
|
+
* the rest, called with whatever arguments they already take. Its result
|
|
66
|
+
* becomes `tmct.session`.
|
|
67
|
+
*
|
|
68
|
+
* `turn(line, options, session)` (optional) overrides how a line reaches the
|
|
69
|
+
* session. The default calls `session.turn(line, options)`, which is every
|
|
70
|
+
* page but mud — mud runs several characters over one world, so it routes on
|
|
71
|
+
* `{ as: character }` to that character's own window.
|
|
72
|
+
*
|
|
73
|
+
* `ask(request, options, session)` and `plan(request, options, session)`
|
|
74
|
+
* (optional) are the page's grounded-question and capability-planner routes.
|
|
75
|
+
* Left out, the matching verb refuses and says which route the page does have.
|
|
76
|
+
* Every verb takes the same `(what, options)` shape, so the research page's
|
|
77
|
+
* source-scoped `tmct.ask(q, { sources })` reads like the plan page's
|
|
78
|
+
* `tmct.turn("solve it", { maxDepth })`.
|
|
79
|
+
*
|
|
80
|
+
* `page` is the residual bag: this page's own rendering helpers, reachable as
|
|
81
|
+
* `tmct.page.*`.
|
|
82
|
+
*
|
|
83
|
+
* `fallback: true` publishes only where no fuller surface is standing, and
|
|
84
|
+
* yields to one that arrives later — the ledger page's two bundles.
|
|
85
|
+
*/
|
|
86
|
+
export function publishTmctSurface({
|
|
87
|
+
open, ask = null, plan = null, turn = null, page = {}, fallback = false, target = globalThis,
|
|
88
|
+
} = {}) {
|
|
89
|
+
if (typeof open !== "function") {
|
|
90
|
+
throw new Error("publishTmctSurface: `open` must be this page's session factory");
|
|
91
|
+
}
|
|
92
|
+
const standing = target.tmct;
|
|
93
|
+
if (fallback && standing && !standing[FALLBACK]) return standing;
|
|
94
|
+
let session = null;
|
|
95
|
+
|
|
96
|
+
const liveSession = () => {
|
|
97
|
+
if (!session) throw new Error(NO_SESSION);
|
|
98
|
+
return session;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const surface = {
|
|
102
|
+
// Variadic, so each page's factory keeps the signature it already has —
|
|
103
|
+
// adventure and mud both take the world payload first, then their options.
|
|
104
|
+
async open(...args) {
|
|
105
|
+
session = await open(...args);
|
|
106
|
+
return session;
|
|
107
|
+
},
|
|
108
|
+
|
|
109
|
+
get session() { return session; },
|
|
110
|
+
|
|
111
|
+
async turn(line, options) {
|
|
112
|
+
const live = liveSession();
|
|
113
|
+
if (turn) return turn(line, options, live);
|
|
114
|
+
// Not every page holds a conversation. The ingest page grounds pasted
|
|
115
|
+
// prose into facts and answers nothing, so it says so rather than
|
|
116
|
+
// failing on a method it never had.
|
|
117
|
+
if (typeof live.turn !== "function") {
|
|
118
|
+
return {
|
|
119
|
+
answer: "this page runs no conversational turn — see tmct.session for what it does run",
|
|
120
|
+
end: false, record: null, plan: null, research: null,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
return live.turn(line, options);
|
|
124
|
+
},
|
|
125
|
+
|
|
126
|
+
async ask(request, options) {
|
|
127
|
+
if (!ask) {
|
|
128
|
+
return {
|
|
129
|
+
answer: "this page has no separate ask route — it answers questions through tmct.turn()",
|
|
130
|
+
data: undefined,
|
|
131
|
+
miss: true,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
return ask(request, options, liveSession());
|
|
135
|
+
},
|
|
136
|
+
|
|
137
|
+
async plan(request, options) {
|
|
138
|
+
if (!plan) {
|
|
139
|
+
return {
|
|
140
|
+
refused: true,
|
|
141
|
+
why: "this page's bundle carries no capability planner",
|
|
142
|
+
driver: null, calls: [], composed: null, observed: null,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
return plan(request, options, liveSession());
|
|
146
|
+
},
|
|
147
|
+
|
|
148
|
+
page,
|
|
149
|
+
|
|
150
|
+
/** True where this is the question-only stand-in rather than a page's full
|
|
151
|
+
* engine. The ledger page reads it to tell its two docks apart: the live
|
|
152
|
+
* one teaches, the stand-in only answers. */
|
|
153
|
+
fallback,
|
|
154
|
+
};
|
|
155
|
+
|
|
156
|
+
surface[FALLBACK] = fallback;
|
|
157
|
+
target.tmct = surface;
|
|
158
|
+
return surface;
|
|
159
|
+
}
|
|
@@ -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;
|
|
@@ -55,8 +62,11 @@ function turnErrorFallback(message) {
|
|
|
55
62
|
* grow a visited-rooms set, bump a turn tally). Never runs on a throw: none
|
|
56
63
|
* of the nine originals touch their own state when `runTurn` itself failed.
|
|
57
64
|
*
|
|
58
|
-
* Returns `{ memoryDir, sessionId, turn, focus, last, planState,
|
|
59
|
-
* setPlanState, researchState, setResearchState }`. `
|
|
65
|
+
* Returns `{ memoryDir, sessionId, graph, turn, focus, last, planState,
|
|
66
|
+
* setPlanState, researchState, setResearchState }`. `graph` is the one this
|
|
67
|
+
* session was built over, exposed so a caller can put a question to the same
|
|
68
|
+
* graph its turns run against (engine-surface.mjs's `graphAsk`) without
|
|
69
|
+
* holding a second reference to it. `turn(line, callArgs)`
|
|
60
70
|
* resolves to `{ answer, end, record, plan, research }` — the union of every
|
|
61
71
|
* field any of the nine originals reads; a caller ignores what it doesn't
|
|
62
72
|
* need. `research` is passed through undefined/null/a queue snapshot exactly
|
|
@@ -85,7 +95,7 @@ export function createTurnSession({
|
|
|
85
95
|
try {
|
|
86
96
|
result = await runTurn(line, {
|
|
87
97
|
config: null, source: null, graph, focus, last, memoryDir, sessionId,
|
|
88
|
-
env: {}, lexicon, vocabHint, planState, researchState,
|
|
98
|
+
env: {}, lexicon, vocabHint, planState, researchState, uiContext: "browser",
|
|
89
99
|
...extra,
|
|
90
100
|
});
|
|
91
101
|
} catch (e) {
|
|
@@ -109,6 +119,7 @@ export function createTurnSession({
|
|
|
109
119
|
return {
|
|
110
120
|
memoryDir,
|
|
111
121
|
sessionId,
|
|
122
|
+
graph,
|
|
112
123
|
get focus() { return focus; },
|
|
113
124
|
get last() { return last; },
|
|
114
125
|
get planState() { return planState; },
|
package/src/tools/server.mjs
CHANGED
|
@@ -50,7 +50,7 @@ export const TOOLS = HOT_TOOLS.map(({ name, agentDescription, inputSchema }) =>
|
|
|
50
50
|
inputSchema,
|
|
51
51
|
}));
|
|
52
52
|
|
|
53
|
-
async function runHandler(name, args, { config, source = defaultSource, tel = null, ingest = null, memoryBackend = null } = {}) {
|
|
53
|
+
async function runHandler(name, args, { config, source = defaultSource, tel = null, ingest = null, memoryBackend = null, graph: suppliedGraph = null } = {}) {
|
|
54
54
|
// Reject an unknown tool BEFORE touching the graph — an unknown name never
|
|
55
55
|
// triggers a load. hasOwn, so an inherited name ("constructor", "toString")
|
|
56
56
|
// is unknown rather than a callable found on the prototype chain.
|
|
@@ -64,13 +64,20 @@ async function runHandler(name, args, { config, source = defaultSource, tel = nu
|
|
|
64
64
|
// conversational memory store (tmct_export) prefers it over re-deriving a
|
|
65
65
|
// backend from config when one is supplied; every other caller leaves it null
|
|
66
66
|
// and gets today's re-derive-from-config behaviour unchanged.
|
|
67
|
-
if (handle.ownsGraphLoad) return handle(args, { config, source, tel, ingest, memoryBackend });
|
|
68
|
-
|
|
67
|
+
if (handle.ownsGraphLoad) return handle(args, { config, source, tel, ingest, memoryBackend, graph: suppliedGraph });
|
|
68
|
+
// `graph` is the third seam of the same kind: a caller that ALREADY holds a
|
|
69
|
+
// parsed graph hands it over instead of making the tool layer load one. A
|
|
70
|
+
// browser session is the case that needs it — its graph is built in memory
|
|
71
|
+
// (a seed payload, or a live board projected through worldRelationGraphPayload)
|
|
72
|
+
// and there is no config or file behind it to load from.
|
|
73
|
+
const graph = suppliedGraph || await loadGraph(config, source);
|
|
69
74
|
// repo root = the dir containing .tmct/ (graphFile = <repo>/.tmct/graph.json). Passed to
|
|
70
75
|
// createGraphService so svc.snippet()/svc.context() are usable directly, and on to the
|
|
71
|
-
// handlers that do their own safe source reads.
|
|
72
|
-
|
|
73
|
-
|
|
76
|
+
// handlers that do their own safe source reads. A supplied graph has no repo on
|
|
77
|
+
// disk behind it, so those reads are off rather than pointed at a path that
|
|
78
|
+
// isn't there.
|
|
79
|
+
const repoRoot = config?.graphFile ? dirname(dirname(config.graphFile)) : null;
|
|
80
|
+
const svc = createGraphService(graph, { sourceAccess: Boolean(repoRoot), repoRoot, readFile, tel, ask });
|
|
74
81
|
return handle(args, { graph, svc, config, repoRoot, memoryBackend });
|
|
75
82
|
}
|
|
76
83
|
|