mira-harness 0.2.0 → 0.2.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 +38 -2
- package/dist/assert.d.ts +41 -0
- package/dist/catalog.d.ts +3 -0
- package/dist/cli.js +398 -153
- package/dist/commands/report.d.ts +2 -0
- package/dist/index.js +108 -20
- package/dist/log.d.ts +3 -0
- package/dist/mcp.js +123 -35
- package/llms.txt +2 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -101,11 +101,12 @@ a "typing…" fallback for a slow bot — replies run 5–62s) and capture, per
|
|
|
101
101
|
| `login` | One-time interactive login → prints `TG_SESSION` |
|
|
102
102
|
| `doctor` | Check `.env` / session / connectivity / @mira resolution (read-only) |
|
|
103
103
|
| `send [message...]` | One probe → full reply as JSON (message via arg or stdin). `--quiet --settle --timeout --no-log` |
|
|
104
|
-
| `loop` | Run the catalog paced. `--category --max --confirm --peer --gap --settle --timeout --list --catalog --quiet` |
|
|
104
|
+
| `loop` | Run the catalog paced; grades `expect` probes (exit 1 on failure). `--category --max --confirm --peer --gap --settle --timeout --list --catalog --no-fail --quiet` |
|
|
105
105
|
| `catalog` | List the catalog (no sends). `--category --catalog --json` |
|
|
106
106
|
| `watch` | Live-tail @mira's messages (observe-only). `--peer` |
|
|
107
107
|
| `report` | Distill the run log into Markdown. `--in --out --category` |
|
|
108
108
|
| `stats` | At-a-glance dashboard: totals, latency records, sparkline. `--in --category --json` |
|
|
109
|
+
| `diff` | Compare two run logs for @mira behavioral drift (exit 1 on a regression). `--json --no-fail` |
|
|
109
110
|
|
|
110
111
|
Run `mira-harness --help` (or `<command> --help`) for full options.
|
|
111
112
|
|
|
@@ -130,13 +131,48 @@ per-feature flags — `MIRA_NO_BANNER=1` (mascot + tip), `MIRA_NO_NOTIFY=1` (com
|
|
|
130
131
|
The built-in catalog (27 probes: `core` / `skills` / `generation` / `wallet`) is just a
|
|
131
132
|
default. Point `--catalog <file.json>` (CLI) or `catalogFile` (MCP) at your own probe set
|
|
132
133
|
to probe any bot — each entry needs `id` + `send` (`category` / `hypothesis` / `slow` /
|
|
133
|
-
`confirm` / `note` optional). See [`examples/catalog.sample.json`](examples/catalog.sample.json):
|
|
134
|
+
`confirm` / `note` / `expect` optional). See [`examples/catalog.sample.json`](examples/catalog.sample.json):
|
|
134
135
|
|
|
135
136
|
```bash
|
|
136
137
|
mira-harness loop --catalog ./examples/catalog.sample.json
|
|
137
138
|
mira-harness catalog --catalog ./examples/catalog.sample.json --json
|
|
138
139
|
```
|
|
139
140
|
|
|
141
|
+
### Assertions (PASS/FAIL)
|
|
142
|
+
|
|
143
|
+
Give a probe an optional `expect` block and `loop` grades it ✓/✗. The checks are **structural**
|
|
144
|
+
— @mira is an LLM (non-deterministic), so exact-text matches would flake:
|
|
145
|
+
|
|
146
|
+
| Check | Means |
|
|
147
|
+
|---|---|
|
|
148
|
+
| `replies: true` | a reply arrived (no timeout) |
|
|
149
|
+
| `textMatches: "<regex>"` | some message text matches (case-insensitive) |
|
|
150
|
+
| `minButtons` / `minLinks` | at least N inline buttons / links across messages |
|
|
151
|
+
| `hasWebApp: true` | a Mini App (`web_app` / startapp) "Launch" button is present |
|
|
152
|
+
| `media: "photo"` | a message carries media of that kind (`photo`/`video`/`audio`/…) |
|
|
153
|
+
| `maxFirstReplyMs` | first-reply latency within the bound |
|
|
154
|
+
| `json: true` | the first message text parses as JSON |
|
|
155
|
+
|
|
156
|
+
```json
|
|
157
|
+
{ "id": "json-strict", "send": "Reply with ONLY {\"ok\":true}", "expect": { "json": true } }
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
Probes without `expect` stay observe-only (informational). `loop` **exits non-zero** if any
|
|
161
|
+
graded probe fails — so it drops straight into CI. Add `--no-fail` to report without failing.
|
|
162
|
+
|
|
163
|
+
### Drift detection
|
|
164
|
+
|
|
165
|
+
`diff` compares two run logs and flags how @mira's behavior **changed** (structural, not
|
|
166
|
+
exact text). **Regressions** — an assertion that flipped ✓→✗, a probe that now times out, a
|
|
167
|
+
>2× latency blow-up — exit non-zero; surface changes (buttons / links / media) and
|
|
168
|
+
improvements are reported but pass. Snapshot a baseline, re-run later, diff:
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
MIRA_RUNS_FILE=baseline.jsonl mira-harness loop --category core # snapshot a baseline
|
|
172
|
+
mira-harness loop --category core # a later run -> mira-runs.jsonl
|
|
173
|
+
mira-harness diff baseline.jsonl # vs the current run log
|
|
174
|
+
```
|
|
175
|
+
|
|
140
176
|
## Use as a library
|
|
141
177
|
|
|
142
178
|
The CLI is a thin frontend over an exported core:
|
package/dist/assert.d.ts
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Probe assertions — turn an observed reply into a PASS/FAIL verdict.
|
|
3
|
+
*
|
|
4
|
+
* A probe's optional `expect` declares machine-checkable expectations; `evaluate`
|
|
5
|
+
* runs them against the captured ProbeResult. @mira is an LLM (non-deterministic),
|
|
6
|
+
* so the checks are deliberately STRUCTURAL and loose — a reply arrived, >= N
|
|
7
|
+
* links, valid JSON, a latency bound — never exact text, which would flake.
|
|
8
|
+
*
|
|
9
|
+
* Probes WITHOUT `expect` are not graded: they stay observe-only / informational.
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import type { ProbeResult } from "./capture.js";
|
|
13
|
+
export declare const ExpectSchema: z.ZodObject<{
|
|
14
|
+
replies: z.ZodOptional<z.ZodBoolean>;
|
|
15
|
+
textMatches: z.ZodOptional<z.ZodString>;
|
|
16
|
+
minButtons: z.ZodOptional<z.ZodNumber>;
|
|
17
|
+
minLinks: z.ZodOptional<z.ZodNumber>;
|
|
18
|
+
hasWebApp: z.ZodOptional<z.ZodBoolean>;
|
|
19
|
+
media: z.ZodOptional<z.ZodEnum<{
|
|
20
|
+
photo: "photo";
|
|
21
|
+
video: "video";
|
|
22
|
+
audio: "audio";
|
|
23
|
+
document: "document";
|
|
24
|
+
webpage: "webpage";
|
|
25
|
+
other: "other";
|
|
26
|
+
}>>;
|
|
27
|
+
maxFirstReplyMs: z.ZodOptional<z.ZodNumber>;
|
|
28
|
+
json: z.ZodOptional<z.ZodBoolean>;
|
|
29
|
+
}, z.core.$strip>;
|
|
30
|
+
export type Expect = z.infer<typeof ExpectSchema>;
|
|
31
|
+
export interface Check {
|
|
32
|
+
name: string;
|
|
33
|
+
ok: boolean;
|
|
34
|
+
detail: string;
|
|
35
|
+
}
|
|
36
|
+
export interface Verdict {
|
|
37
|
+
ok: boolean;
|
|
38
|
+
checks: Check[];
|
|
39
|
+
}
|
|
40
|
+
/** Run a probe's expectations against its captured result. Pure — no network. */
|
|
41
|
+
export declare function evaluate(expect: Expect, result: ProbeResult): Verdict;
|
package/dist/catalog.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type Expect } from "./assert.js";
|
|
1
2
|
/** Built-in categories. Custom catalogs may use any category string. */
|
|
2
3
|
export type ProbeCategory = "core" | "skills" | "generation" | "wallet";
|
|
3
4
|
export interface Probe {
|
|
@@ -15,6 +16,8 @@ export interface Probe {
|
|
|
15
16
|
*/
|
|
16
17
|
confirm?: boolean;
|
|
17
18
|
note?: string;
|
|
19
|
+
/** Optional machine-checkable expectations — graded by `loop` (PASS/FAIL). */
|
|
20
|
+
expect?: Expect;
|
|
18
21
|
}
|
|
19
22
|
export declare const CATEGORIES: ProbeCategory[];
|
|
20
23
|
/**
|