@remnic/bench 9.6.18 → 9.6.20

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 CHANGED
@@ -16,6 +16,125 @@ pnpm add @remnic/bench
16
16
 
17
17
  The CLI loads `@remnic/bench` via a computed-specifier dynamic import. If it's not installed, `remnic bench *` prints a clear install hint; the rest of the CLI keeps working.
18
18
 
19
+ ## OpenAI Build Week: five-minute MemCorrect path
20
+
21
+ MemCorrect scores correction uptake and stale-memory harm through the same
22
+ `remnic bench` surface. This keyless smoke path uses the packaged stdio MCP
23
+ server, so it tests the actual MCP adapter rather than the in-memory baseline:
24
+
25
+ ```bash
26
+ remnic bench run --quick memcorrect-v1 --adapter mcp --mcp-demo
27
+ remnic bench runs list
28
+ remnic bench export <run-id> --format html --output ./memcorrect-report.html
29
+ ```
30
+
31
+ The run itself is deterministic and offline. It needs no dataset or API key.
32
+ The generated HTML is self-contained and includes the correction ledger,
33
+ per-dimension evidence, task drill-down, and reproducibility provenance. Treat
34
+ the packaged demo as a transport and product smoke test, not a publishable
35
+ backend-quality result.
36
+
37
+ From a source checkout, build the optional companion before invoking the CLI:
38
+
39
+ ```bash
40
+ pnpm install --frozen-lockfile
41
+ pnpm --filter @remnic/bench build
42
+ pnpm exec tsx packages/remnic-cli/src/index.ts bench run \
43
+ --quick memcorrect-v1 --adapter mcp --mcp-demo
44
+ ```
45
+
46
+ An external MCP server can replace `--mcp-demo` with exactly one of:
47
+
48
+ ```bash
49
+ # stdio
50
+ remnic bench run --quick memcorrect-v1 --adapter mcp \
51
+ --mcp-command memory-server --mcp-args '["--stdio"]' \
52
+ --mcp-tool-map '{"store":"memory_store","recall":"memory_recall","correct":"memory_correct","reset":"memory_reset"}'
53
+
54
+ # Streamable HTTP; set REMNIC_BENCH_MCP_BEARER_TOKEN if authentication is required
55
+ remnic bench run --quick memcorrect-v1 --adapter mcp \
56
+ --mcp-url https://memory.example/mcp \
57
+ --mcp-tool-map '{"store":"memory_store","recall":"memory_recall","correct":"memory_correct","reset":"memory_reset"}'
58
+ ```
59
+
60
+ Tool names alone may not be enough for a non-canonical server. The mapping can
61
+ also describe argument semantics; see `remnic bench --help` for the current CLI
62
+ surface and use preflight failures as conformance errors rather than empty
63
+ recall scores.
64
+
65
+ GPT-5.6 judging is explicit and uses the OpenAI Responses API:
66
+
67
+ ```bash
68
+ export OPENAI_API_KEY=...
69
+ remnic bench run --quick memcorrect-v1 --adapter mcp --mcp-demo \
70
+ --judge-provider openai --judge-model gpt-5.6
71
+ ```
72
+
73
+ The credit-backed Codex CLI path is a distinct provider and model namespace.
74
+ Use `gpt-5.6-luna` for bulk responder and internal work and
75
+ `gpt-5.6-terra` for quality-critical judging. The exact API id `gpt-5.6`
76
+ above is not a CLI alias. Confirm the authenticated catalog before a run with
77
+ `codex debug models`. `gpt-5.6-sol` is opt-in only and is disabled in the
78
+ bounded plan.
79
+
80
+ Each Codex completion is a fresh, non-interactive `codex exec` in a new empty
81
+ temporary workspace. It ignores user configuration and project rules,
82
+ disables hooks, and keeps no session. The sandbox is read-only, approvals are
83
+ denied, and the benchmark prompt instructs the model not to use tools. The
84
+ Build Week plan uses normal service, not fast mode.
85
+
86
+ The Build Week grant has 2,473 Codex credits. Use the account exclusively for
87
+ this one harness process during a bounded run because Codex CLI exposes no
88
+ machine-readable account balance. Bounded mode also requires `codex login
89
+ status` to report ChatGPT authentication. A 473-credit safety reserve leaves
90
+ 2,000 usable credits. Configure the atomic completed-turn ledger and guards,
91
+ then measure a quick task before choosing a workload bound:
92
+
93
+ ```bash
94
+ export REMNIC_BENCH_CODEX_CREDIT_BUDGET=2473
95
+ export REMNIC_BENCH_CODEX_CREDIT_RESERVE=473
96
+ export REMNIC_BENCH_CODEX_CREDIT_LEDGER="$PWD/.bench-private/codex-credit-ledger.json"
97
+
98
+ remnic bench run --quick longmemeval \
99
+ --runtime-profile real \
100
+ --system-provider codex-cli --system-model gpt-5.6-luna \
101
+ --system-codex-reasoning-effort medium \
102
+ --internal-provider codex-cli --internal-model gpt-5.6-luna \
103
+ --internal-codex-reasoning-effort medium \
104
+ --judge-provider codex-cli --judge-model gpt-5.6-terra \
105
+ --judge-codex-reasoning-effort high
106
+
107
+ remnic bench run longmemeval \
108
+ --runtime-profile real --limit <LEDGER_DERIVED_LIMIT> \
109
+ --system-provider codex-cli --system-model gpt-5.6-luna \
110
+ --system-codex-reasoning-effort medium \
111
+ --internal-provider codex-cli --internal-model gpt-5.6-luna \
112
+ --internal-codex-reasoning-effort medium \
113
+ --judge-provider codex-cli --judge-model gpt-5.6-terra \
114
+ --judge-codex-reasoning-effort high
115
+ ```
116
+
117
+ The placeholder is intentional. `--limit` and LoCoMo/MemoryAgentBench's
118
+ `--trial-limit` bound tasks, not token credits. Derive each next batch from
119
+ actual `turn.completed` JSONL usage. Stop dispatching at 2,000 spent; the
120
+ 473-credit reserve absorbs only a final in-flight call whose exact cost becomes
121
+ known after completion. Missing exact terminal usage blocks the ledger pending
122
+ manual account reconciliation.
123
+ Rates per one million tokens are Luna: 25 input, 2.5 cached input, 150 output;
124
+ Terra: 62.5 input, 6.25 cached input, 375 output. A bounded result is a trial,
125
+ not a full leaderboard artifact.
126
+
127
+ Codex built and adversarially reviewed the Build Week adapter, Responses
128
+ provider, and report card. The underlying Remnic engine and original benchmark
129
+ harness are prior work. The evidence ledger, credit-backed frontier-run
130
+ placeholder, and release status live in the root [`HACKATHON.md`](../../HACKATHON.md).
131
+
132
+ The claimed judge path requires Node.js 22.12+. It is verified from source and
133
+ from packed tarballs installed into a clean global prefix on Linux; macOS is
134
+ supported with the same Node CLI but still needs a release-install receipt.
135
+ Windows judges should use WSL2; native Windows is not currently claimed as
136
+ Build Week-verified.
137
+
19
138
  ## What it does
20
139
 
21
140
  - **Benchmark runners** for a growing set of memory-oriented evals: `longmemeval`, `locomo`, `memory-arena`, `amemgym`, `ama-bench`, plus a lightweight smoke fixture.
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,129 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/demo/mcp-memory-server.ts
4
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
5
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
6
+ import { z } from "zod";
7
+
8
+ // src/demo/mcp-memory-correction.ts
9
+ function parseSyntheticCorrection(content) {
10
+ const trimmed = content.trim();
11
+ const patterns = [
12
+ {
13
+ expression: /^Correction: replace (.+) with (.+)\.$/s,
14
+ oldValueIndex: 1,
15
+ newValueIndex: 2
16
+ },
17
+ {
18
+ expression: /^Correction: my .+? record saying (.+?) is wrong\. It is now (.+)\.$/s,
19
+ oldValueIndex: 1,
20
+ newValueIndex: 2
21
+ },
22
+ {
23
+ expression: /^Oh by the way, we switched .+? from (.+?) to (.+) last month\.$/s,
24
+ oldValueIndex: 1,
25
+ newValueIndex: 2
26
+ },
27
+ {
28
+ expression: /^For this project, .+? is (.+?) now, not (.+)\.$/s,
29
+ oldValueIndex: 2,
30
+ newValueIndex: 1
31
+ },
32
+ {
33
+ expression: /^Update: .+? is (.+?) going forward instead of (.+)\.$/s,
34
+ oldValueIndex: 2,
35
+ newValueIndex: 1
36
+ }
37
+ ];
38
+ for (const pattern of patterns) {
39
+ const match = pattern.expression.exec(trimmed);
40
+ const oldValue = match?.[pattern.oldValueIndex];
41
+ const newValue = match?.[pattern.newValueIndex];
42
+ if (oldValue !== void 0 && newValue !== void 0) return { oldValue, newValue };
43
+ }
44
+ return void 0;
45
+ }
46
+
47
+ // src/demo/mcp-memory-server.ts
48
+ var memories = /* @__PURE__ */ new Map();
49
+ var server = new McpServer({
50
+ name: "remnic-bench-demo-memory",
51
+ version: "1.0.0"
52
+ });
53
+ server.registerTool(
54
+ "store_memory",
55
+ {
56
+ description: "Store one synthetic benchmark memory in an isolated session.",
57
+ inputSchema: {
58
+ namespace: z.string(),
59
+ sessionId: z.string(),
60
+ content: z.string(),
61
+ role: z.string().optional(),
62
+ timestamp: z.string().optional()
63
+ }
64
+ },
65
+ async ({ sessionId, content }) => {
66
+ memories.set(sessionId, [...memories.get(sessionId) ?? [], content]);
67
+ return { content: [{ type: "text", text: JSON.stringify({ stored: true }) }] };
68
+ }
69
+ );
70
+ server.registerTool(
71
+ "search_memory",
72
+ {
73
+ description: "Recall memories from one isolated benchmark session.",
74
+ inputSchema: {
75
+ namespace: z.string(),
76
+ sessionId: z.string(),
77
+ query: z.string(),
78
+ limit: z.number().int().positive().optional()
79
+ }
80
+ },
81
+ async ({ sessionId, limit }) => ({
82
+ content: [
83
+ {
84
+ type: "text",
85
+ text: JSON.stringify({ memories: (memories.get(sessionId) ?? []).slice(0, limit) })
86
+ }
87
+ ]
88
+ })
89
+ );
90
+ server.registerTool(
91
+ "correct_memory",
92
+ {
93
+ description: "Apply a synthetic natural-language correction to one session.",
94
+ inputSchema: {
95
+ namespace: z.string(),
96
+ sessionId: z.string(),
97
+ content: z.string(),
98
+ timestamp: z.string().optional()
99
+ }
100
+ },
101
+ async ({ sessionId, content }) => {
102
+ const replacement = parseSyntheticCorrection(content);
103
+ const current = memories.get(sessionId) ?? [];
104
+ if (replacement) {
105
+ memories.set(
106
+ sessionId,
107
+ current.map((item) => item.replaceAll(replacement.oldValue, replacement.newValue))
108
+ );
109
+ } else {
110
+ memories.set(sessionId, [...current, content]);
111
+ }
112
+ return { content: [{ type: "text", text: JSON.stringify({ applied: true }) }] };
113
+ }
114
+ );
115
+ server.registerTool(
116
+ "delete_memory",
117
+ {
118
+ description: "Delete only the requested isolated benchmark session.",
119
+ inputSchema: {
120
+ namespace: z.string(),
121
+ sessionId: z.string()
122
+ }
123
+ },
124
+ async ({ sessionId }) => {
125
+ memories.delete(sessionId);
126
+ return { content: [{ type: "text", text: JSON.stringify({ deleted: true }) }] };
127
+ }
128
+ );
129
+ await server.connect(new StdioServerTransport());