@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 +119 -0
- package/dist/demo/mcp-memory-server.d.ts +1 -0
- package/dist/demo/mcp-memory-server.js +129 -0
- package/dist/index.d.ts +451 -7
- package/dist/index.js +3978 -718
- package/package.json +7 -4
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());
|