@polycode-projects/the-mechanical-code-talker 2.10.3 → 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 +68 -12
- package/bin/tmct.mjs +5 -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 +7 -2
- package/src/adapters/corpus/wikipedia-live.mjs +182 -26
- package/src/adapters/corpus/worlds-pack.mjs +8 -2
- package/src/adapters/memory/core.mjs +8 -1
- package/src/adapters/toml-config.mjs +6 -0
- package/src/domain/cli-verbs.mjs +2 -0
- package/src/domain/memory/trust.mjs +32 -2
- package/src/domain/sense-split.mjs +203 -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 +341 -197
- package/src/services/chat-session.mjs +24 -9
- package/src/services/chat.mjs +580 -47
- package/src/services/code-explorer-viz.mjs +198 -76
- package/src/services/extract-facts.mjs +384 -82
- package/src/services/fold.mjs +1 -1
- package/src/services/ingest-viz.mjs +637 -0
- package/src/services/ledger-viz.mjs +209 -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/session-log-format.mjs +64 -0
- package/src/services/sessions.mjs +56 -22
- package/src/services/spider-fly-turn.mjs +54 -1
- package/src/services/spider-fly-viz.mjs +41 -23
- package/src/surfaces/web/adventure-browser-entry.mjs +9 -5
- package/src/surfaces/web/chat-browser-entry.mjs +32 -11
- package/src/surfaces/web/code-explorer-browser-entry.mjs +27 -11
- package/src/surfaces/web/ingest-browser-entry.mjs +208 -0
- package/src/surfaces/web/ledger-browser-entry.mjs +24 -5
- package/src/surfaces/web/memory-ask-browser.bundle.js +134 -125
- package/src/surfaces/web/memory-stats.mjs +53 -0
- package/src/tools/definitions.mjs +14 -0
- package/src/tools/handlers/index.mjs +2 -0
- package/src/tools/handlers/tmct-ingest.mjs +43 -0
- package/src/tools/server.mjs +5 -2
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
// memory-stats.mjs — the "what does this session's memory hold" reader,
|
|
2
|
+
// shared by chat-browser-entry.mjs and ingest-browser-entry.mjs so both
|
|
3
|
+
// bundles' stats panels read the exact same breakdown for the exact same
|
|
4
|
+
// store shape.
|
|
5
|
+
import { loadMemory, readFactRows } from "../../adapters/memory/core.mjs";
|
|
6
|
+
import { provenanceTagToSource } from "../../domain/memory/trust.mjs";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* The memory a running session holds, broken down by where each fact came
|
|
10
|
+
* from: the seed corpus bands it booted with (keyed by the SAME band name
|
|
11
|
+
* build-chat-seed.mjs/extensions.mjs seed under — "human", "seon",
|
|
12
|
+
* "conceptnet" today, whichever bands a future seed adds tomorrow) plus
|
|
13
|
+
* whatever has been taught THIS session. Reuses memory/trust.mjs's own
|
|
14
|
+
* `provenanceTagToSource` against each fact's already-stored provenance
|
|
15
|
+
* tag(s) (readFactRows' `provenance`, the ' | '-joined compat string) rather
|
|
16
|
+
* than inventing a second provenance parse — the same tag chat.mjs's own
|
|
17
|
+
* "(source: ...)" citation already carries, so this panel and a turn's
|
|
18
|
+
* citation always agree on where a fact came from.
|
|
19
|
+
*
|
|
20
|
+
* Returns { total, bandCounts, taught }: `bandCounts` maps a band label to
|
|
21
|
+
* its fact count ("taught this session" for a teach/operator-sourced fact
|
|
22
|
+
* with no corpus band, "other" for anything provenance can't place);
|
|
23
|
+
* `taught` lists every session-taught fact (subject/predicate/object + its
|
|
24
|
+
* own provenance tag), most-recently-taught last — a stats panel's
|
|
25
|
+
* provenance column reads straight off this, no further lookup needed.
|
|
26
|
+
*/
|
|
27
|
+
export async function memoryStats(memoryDir) {
|
|
28
|
+
const memory = await loadMemory(memoryDir);
|
|
29
|
+
const rows = readFactRows(memory);
|
|
30
|
+
const bandCounts = {};
|
|
31
|
+
const taught = [];
|
|
32
|
+
for (const row of rows) {
|
|
33
|
+
const tags = String(row.provenance || "").split(" | ").filter(Boolean);
|
|
34
|
+
let band = null;
|
|
35
|
+
let isTaught = false;
|
|
36
|
+
let taughtTag = "";
|
|
37
|
+
for (const tag of tags) {
|
|
38
|
+
const src = provenanceTagToSource(tag);
|
|
39
|
+
if (!src) continue;
|
|
40
|
+
// corpusWeak (a /r/RelatedTo-strength triple, e.g. ConceptNet's or
|
|
41
|
+
// SEON's own weaker associations) names the SAME band as corpus (a
|
|
42
|
+
// /r/IsA-strength one) — both carry `src.name`, and a band count that
|
|
43
|
+
// dropped the weak tier would undercount a corpus by exactly its
|
|
44
|
+
// weak-relation facts (SEON: 19 of them, all `corpus-weak:seon`).
|
|
45
|
+
if ((src.kind === "corpus" || src.kind === "corpusWeak") && src.name) band = src.name;
|
|
46
|
+
if (src.kind === "teach" || src.kind === "operator") { isTaught = true; taughtTag = tag; }
|
|
47
|
+
}
|
|
48
|
+
const label = band || (isTaught ? "taught this session" : "other");
|
|
49
|
+
bandCounts[label] = (bandCounts[label] || 0) + 1;
|
|
50
|
+
if (isTaught) taught.push({ subject: row.subject, predicate: row.predicate, object: row.object, tag: taughtTag });
|
|
51
|
+
}
|
|
52
|
+
return { total: rows.length, bandCounts, taught };
|
|
53
|
+
}
|
|
@@ -297,6 +297,20 @@ export const TOOL_DEFINITIONS = Object.freeze([
|
|
|
297
297
|
inputSchema: { type: "object", required: [], properties: {} },
|
|
298
298
|
example: {},
|
|
299
299
|
},
|
|
300
|
+
{
|
|
301
|
+
name: "tmct_ingest",
|
|
302
|
+
tier: "cold",
|
|
303
|
+
summary: "Ground plain text into memory facts with the same deterministic recognizer the chat teach lane uses — the strict tier, plus an optional lower-trust fuzzy tier — and report the canonical triples.",
|
|
304
|
+
inputSchema: {
|
|
305
|
+
type: "object",
|
|
306
|
+
required: ["text"],
|
|
307
|
+
properties: {
|
|
308
|
+
text: { type: "string", description: "The plain text to ground into facts." },
|
|
309
|
+
optimistic: { type: "boolean", description: "Also run the lower-trust fuzzy tier over sentences the strict recognizer skips." },
|
|
310
|
+
},
|
|
311
|
+
},
|
|
312
|
+
example: { text: "A kettle is a container. An otter is a mammal.", optimistic: true },
|
|
313
|
+
},
|
|
300
314
|
]);
|
|
301
315
|
|
|
302
316
|
export const HOT_TOOLS = TOOL_DEFINITIONS.filter((t) => t.tier === "hot");
|
|
@@ -29,6 +29,7 @@ import { tmct_callees } from "./tmct-callees.mjs";
|
|
|
29
29
|
import { tmct_calls } from "./tmct-calls.mjs";
|
|
30
30
|
import { tmct_cochanges } from "./tmct-cochanges.mjs";
|
|
31
31
|
import { tmct_export } from "./tmct-export.mjs";
|
|
32
|
+
import { tmct_ingest } from "./tmct-ingest.mjs";
|
|
32
33
|
|
|
33
34
|
export const HANDLERS = Object.freeze({
|
|
34
35
|
tmct_context,
|
|
@@ -55,4 +56,5 @@ export const HANDLERS = Object.freeze({
|
|
|
55
56
|
tmct_calls,
|
|
56
57
|
tmct_cochanges,
|
|
57
58
|
tmct_export,
|
|
59
|
+
tmct_ingest,
|
|
58
60
|
});
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// tmct_ingest — ground plain text into the conversational-memory store with the
|
|
2
|
+
// same deterministic recognizer the chat teach lane uses. The strict tier keeps
|
|
3
|
+
// only sentences the recognizer turns into stored facts; with optimistic:true the
|
|
4
|
+
// lower-trust fuzzy tier also reaches the sentences it skips. Answers with the
|
|
5
|
+
// canonical triples it grounded and an honest recognized/skipped summary — no
|
|
6
|
+
// LLM, no guessing.
|
|
7
|
+
//
|
|
8
|
+
// The recognizer (ingestText, src/services/extract-facts.mjs) lives in the SERVICE
|
|
9
|
+
// layer, above the tool layer, so this handler never imports it: a service-layer
|
|
10
|
+
// caller injects it as `ingest` through dispatchTool's ctx (bin/tmct.mjs's `cli`
|
|
11
|
+
// route and the chat surface both hold it). Called without that seam wired, the
|
|
12
|
+
// tool says so honestly rather than guessing.
|
|
13
|
+
//
|
|
14
|
+
// Reads the conversational-memory store (not the code-map graph), so it owns its
|
|
15
|
+
// own load and writes with or without a code graph present.
|
|
16
|
+
|
|
17
|
+
import { dirname } from "node:path";
|
|
18
|
+
import { openConfiguredMemoryBackend } from "../../adapters/memory/core.mjs";
|
|
19
|
+
|
|
20
|
+
export async function tmct_ingest(args, { config, ingest }) {
|
|
21
|
+
const text = String(args?.text ?? "");
|
|
22
|
+
if (!text.trim()) return "(nothing to ingest — pass some text)";
|
|
23
|
+
if (typeof ingest !== "function") {
|
|
24
|
+
return "(ingest isn't wired into this context — invoke tmct_ingest through the CLI `cli` route or the chat surface)";
|
|
25
|
+
}
|
|
26
|
+
const optimistic = args?.optimistic === true;
|
|
27
|
+
const { dir, close } = await openConfiguredMemoryBackend(dirname(dirname(config.graphFile)));
|
|
28
|
+
try {
|
|
29
|
+
const result = await ingest(text, { memoryDir: dir, config, sourceTag: "tool", optimistic, canonical: true });
|
|
30
|
+
const grounded = result.extracted.length + result.optimistic.length;
|
|
31
|
+
const header = `${result.sentences} sentence(s), ${result.recognized} recognized`
|
|
32
|
+
+ (optimistic ? `, ${result.optimistic.length} optimistic candidate(s)` : "")
|
|
33
|
+
+ `, ${result.skipped} skipped — ${grounded} fact(s) grounded.`;
|
|
34
|
+
return grounded ? `${header}\n${result.canonical.join("\n")}` : header;
|
|
35
|
+
} finally {
|
|
36
|
+
await close();
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// The memory store is this tool's only source — it writes with or without a
|
|
41
|
+
// code-map graph, so the shared code-graph load (which refuses an empty graph)
|
|
42
|
+
// must not gate it.
|
|
43
|
+
tmct_ingest.ownsGraphLoad = true;
|
package/src/tools/server.mjs
CHANGED
|
@@ -44,13 +44,16 @@ export const TOOLS = HOT_TOOLS.map(({ name, agentDescription, inputSchema }) =>
|
|
|
44
44
|
inputSchema,
|
|
45
45
|
}));
|
|
46
46
|
|
|
47
|
-
export async function dispatchTool(name, args, { config, source = defaultSource, tel = null } = {}) {
|
|
47
|
+
export async function dispatchTool(name, args, { config, source = defaultSource, tel = null, ingest = null } = {}) {
|
|
48
48
|
// Reject an unknown tool BEFORE touching the graph — an unknown name never
|
|
49
49
|
// triggers a load. hasOwn, so an inherited name ("constructor", "toString")
|
|
50
50
|
// is unknown rather than a callable found on the prototype chain.
|
|
51
51
|
if (!Object.hasOwn(HANDLERS, name)) throw new ToolError(`unknown tool: ${name}`);
|
|
52
52
|
const handle = HANDLERS[name];
|
|
53
|
-
|
|
53
|
+
// `ingest` is the recognizer seam a caller in the service layer injects (the
|
|
54
|
+
// tool layer sits UNDER services and must not import one, so a tool that needs
|
|
55
|
+
// the chat recognizer receives it here rather than importing it).
|
|
56
|
+
if (handle.ownsGraphLoad) return handle(args, { config, source, tel, ingest });
|
|
54
57
|
const graph = await loadGraph(config, source);
|
|
55
58
|
// repo root = the dir containing .tmct/ (graphFile = <repo>/.tmct/graph.json). Passed to
|
|
56
59
|
// createGraphService so svc.snippet()/svc.context() are usable directly, and on to the
|