llm-mock-server 1.0.1 → 1.0.3
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/.claude/skills/desloppify/SKILL.md +308 -0
- package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/canonical_import_20260315_000801.json +242 -0
- package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/canonical_import_20260315_000905.json +248 -0
- package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/canonical_import_20260315_000917.json +248 -0
- package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/canonical_import_20260315_000950.json +311 -0
- package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/claude_launch_prompt.md +17 -0
- package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/review_result.json +255 -0
- package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/review_result.template.json +22 -0
- package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/reviewer_instructions.md +20 -0
- package/.desloppify/external_review_sessions/ext_20260315_000339_a6cdc3e6/session.json +20 -0
- package/.desloppify/query.json +284 -0
- package/.desloppify/review_packet_blind.json +1303 -0
- package/.desloppify/review_packets/holistic_packet_20260315_000339.json +1471 -0
- package/.desloppify/state-typescript.json +5114 -0
- package/.desloppify/state-typescript.json.bak +5108 -0
- package/.editorconfig +12 -0
- package/.github/workflows/test.yml +3 -0
- package/.oxfmtrc.json +9 -0
- package/dist/cli.js +5 -2
- package/dist/cli.js.map +1 -1
- package/dist/formats/anthropic/index.js +1 -1
- package/dist/formats/anthropic/index.js.map +1 -1
- package/dist/formats/anthropic/parse.d.ts +1 -1
- package/dist/formats/anthropic/parse.d.ts.map +1 -1
- package/dist/formats/anthropic/parse.js +1 -1
- package/dist/formats/anthropic/parse.js.map +1 -1
- package/dist/formats/anthropic/serialize.d.ts +2 -2
- package/dist/formats/anthropic/serialize.d.ts.map +1 -1
- package/dist/formats/anthropic/serialize.js +6 -3
- package/dist/formats/anthropic/serialize.js.map +1 -1
- package/dist/formats/openai/index.js +1 -1
- package/dist/formats/openai/index.js.map +1 -1
- package/dist/formats/openai/parse.d.ts +1 -1
- package/dist/formats/openai/parse.d.ts.map +1 -1
- package/dist/formats/openai/parse.js +1 -1
- package/dist/formats/openai/parse.js.map +1 -1
- package/dist/formats/openai/serialize.d.ts +2 -2
- package/dist/formats/openai/serialize.d.ts.map +1 -1
- package/dist/formats/openai/serialize.js +12 -15
- package/dist/formats/openai/serialize.js.map +1 -1
- package/dist/formats/request-helpers.d.ts +13 -0
- package/dist/formats/request-helpers.d.ts.map +1 -0
- package/dist/formats/request-helpers.js +28 -0
- package/dist/formats/request-helpers.js.map +1 -0
- package/dist/formats/responses/index.js +1 -1
- package/dist/formats/responses/index.js.map +1 -1
- package/dist/formats/responses/parse.d.ts +1 -1
- package/dist/formats/responses/parse.d.ts.map +1 -1
- package/dist/formats/responses/parse.js +1 -1
- package/dist/formats/responses/parse.js.map +1 -1
- package/dist/formats/responses/schema.d.ts +1 -20
- package/dist/formats/responses/schema.d.ts.map +1 -1
- package/dist/formats/responses/schema.js.map +1 -1
- package/dist/formats/responses/serialize.d.ts +2 -2
- package/dist/formats/responses/serialize.d.ts.map +1 -1
- package/dist/formats/responses/serialize.js +6 -3
- package/dist/formats/responses/serialize.js.map +1 -1
- package/dist/formats/serialize-helpers.d.ts +14 -0
- package/dist/formats/serialize-helpers.d.ts.map +1 -0
- package/dist/formats/serialize-helpers.js +25 -0
- package/dist/formats/serialize-helpers.js.map +1 -0
- package/dist/formats/types.d.ts +3 -3
- package/dist/formats/types.d.ts.map +1 -1
- package/dist/loader.d.ts +3 -2
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +6 -9
- package/dist/loader.js.map +1 -1
- package/dist/logger.d.ts +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +17 -23
- package/dist/logger.js.map +1 -1
- package/dist/mock-server.d.ts.map +1 -1
- package/dist/mock-server.js +8 -15
- package/dist/mock-server.js.map +1 -1
- package/dist/route-handler.d.ts +2 -1
- package/dist/route-handler.d.ts.map +1 -1
- package/dist/rule-engine.d.ts +12 -1
- package/dist/rule-engine.d.ts.map +1 -1
- package/dist/rule-engine.js +14 -0
- package/dist/rule-engine.js.map +1 -1
- package/dist/types/reply.d.ts +6 -10
- package/dist/types/reply.d.ts.map +1 -1
- package/dist/types/request.d.ts +7 -11
- package/dist/types/request.d.ts.map +1 -1
- package/dist/types/rule.d.ts +3 -10
- package/dist/types/rule.d.ts.map +1 -1
- package/dist/types.d.ts +3 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +5 -2
- package/scorecard.png +0 -0
- package/src/cli-validators.ts +12 -4
- package/src/cli.ts +27 -7
- package/src/formats/anthropic/index.ts +1 -1
- package/src/formats/anthropic/parse.ts +25 -6
- package/src/formats/anthropic/schema.ts +16 -8
- package/src/formats/anthropic/serialize.ts +116 -28
- package/src/formats/openai/index.ts +1 -1
- package/src/formats/openai/parse.ts +13 -3
- package/src/formats/openai/schema.ts +43 -30
- package/src/formats/openai/serialize.ts +84 -30
- package/src/formats/{parse-helpers.ts → request-helpers.ts} +4 -32
- package/src/formats/responses/index.ts +1 -1
- package/src/formats/responses/parse.ts +18 -4
- package/src/formats/responses/schema.ts +34 -22
- package/src/formats/responses/serialize.ts +237 -38
- package/src/formats/serialize-helpers.ts +38 -0
- package/src/formats/types.ts +18 -5
- package/src/index.ts +3 -1
- package/src/loader.ts +43 -20
- package/src/logger.ts +31 -19
- package/src/mock-server.ts +38 -21
- package/src/route-handler.ts +50 -15
- package/src/rule-engine.ts +64 -11
- package/src/types/reply.ts +12 -12
- package/src/types/request.ts +7 -11
- package/src/types/rule.ts +3 -10
- package/src/types.ts +23 -4
- package/test/cli-validators.test.ts +16 -4
- package/test/formats/anthropic.test.ts +84 -23
- package/test/formats/openai.test.ts +85 -24
- package/test/formats/parse-helpers.test.ts +315 -0
- package/test/formats/responses.test.ts +99 -34
- package/test/helpers/make-req.ts +18 -0
- package/test/history.test.ts +361 -0
- package/test/loader.test.ts +44 -45
- package/test/logger.test.ts +344 -0
- package/test/mock-server.test.ts +77 -23
- package/test/rule-engine.test.ts +57 -41
- package/src/types/index.ts +0 -4
package/test/rule-engine.test.ts
CHANGED
|
@@ -1,21 +1,6 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach } from "vitest";
|
|
2
2
|
import { RuleEngine } from "../src/rule-engine.js";
|
|
3
|
-
import
|
|
4
|
-
|
|
5
|
-
function makeReq(overrides: Partial<MockRequest> = {}): MockRequest {
|
|
6
|
-
return {
|
|
7
|
-
format: "openai",
|
|
8
|
-
model: "gpt-5.4",
|
|
9
|
-
streaming: true,
|
|
10
|
-
messages: [{ role: "user", content: "hello" }],
|
|
11
|
-
lastMessage: "hello",
|
|
12
|
-
systemMessage: "",
|
|
13
|
-
toolNames: [],
|
|
14
|
-
lastToolCallId: undefined,
|
|
15
|
-
raw: {},
|
|
16
|
-
...overrides,
|
|
17
|
-
};
|
|
18
|
-
}
|
|
3
|
+
import { makeReq } from "./helpers/make-req.js";
|
|
19
4
|
|
|
20
5
|
describe("RuleEngine", () => {
|
|
21
6
|
let engine: RuleEngine;
|
|
@@ -27,13 +12,15 @@ describe("RuleEngine", () => {
|
|
|
27
12
|
it("matches a string (substring, case-insensitive)", () => {
|
|
28
13
|
engine.add("hello", "Hi!");
|
|
29
14
|
const rule = engine.match(makeReq({ lastMessage: "say Hello world" }));
|
|
30
|
-
|
|
31
|
-
expect(rule
|
|
15
|
+
if (!rule) throw new Error("expected match");
|
|
16
|
+
expect(rule.description).toBe('"hello"');
|
|
32
17
|
});
|
|
33
18
|
|
|
34
19
|
it("matches a regex", () => {
|
|
35
20
|
engine.add(/explain (\w+)/i, "Here is an explanation.");
|
|
36
|
-
const rule = engine.match(
|
|
21
|
+
const rule = engine.match(
|
|
22
|
+
makeReq({ lastMessage: "Can you explain recursion?" }),
|
|
23
|
+
);
|
|
37
24
|
expect(rule).toBeDefined();
|
|
38
25
|
});
|
|
39
26
|
|
|
@@ -59,15 +46,25 @@ describe("RuleEngine", () => {
|
|
|
59
46
|
|
|
60
47
|
it("matches a MatchObject with message + model", () => {
|
|
61
48
|
engine.add({ model: "gpt-5.4", message: "hello" }, "Hi from GPT-5.4");
|
|
62
|
-
expect(
|
|
63
|
-
|
|
64
|
-
|
|
49
|
+
expect(
|
|
50
|
+
engine.match(makeReq({ model: "gpt-5.4", lastMessage: "hello" })),
|
|
51
|
+
).toBeDefined();
|
|
52
|
+
expect(
|
|
53
|
+
engine.match(makeReq({ model: "gpt-5.4", lastMessage: "bye" })),
|
|
54
|
+
).toBeUndefined();
|
|
55
|
+
expect(
|
|
56
|
+
engine.match(makeReq({ model: "claude", lastMessage: "hello" })),
|
|
57
|
+
).toBeUndefined();
|
|
65
58
|
});
|
|
66
59
|
|
|
67
60
|
it("matches a MatchObject with system", () => {
|
|
68
61
|
engine.add({ system: /pirate/i }, "Arrr!");
|
|
69
|
-
expect(
|
|
70
|
-
|
|
62
|
+
expect(
|
|
63
|
+
engine.match(makeReq({ systemMessage: "You are a pirate" })),
|
|
64
|
+
).toBeDefined();
|
|
65
|
+
expect(
|
|
66
|
+
engine.match(makeReq({ systemMessage: "You are helpful" })),
|
|
67
|
+
).toBeUndefined();
|
|
71
68
|
});
|
|
72
69
|
|
|
73
70
|
it("matches a MatchObject with format", () => {
|
|
@@ -80,7 +77,8 @@ describe("RuleEngine", () => {
|
|
|
80
77
|
engine.add("hello", "First");
|
|
81
78
|
engine.add("hello", "Second");
|
|
82
79
|
const rule = engine.match(makeReq());
|
|
83
|
-
|
|
80
|
+
if (!rule) throw new Error("expected match");
|
|
81
|
+
expect(rule.resolve).toBe("First");
|
|
84
82
|
});
|
|
85
83
|
|
|
86
84
|
it("returns undefined when no rules match", () => {
|
|
@@ -129,13 +127,17 @@ describe("RuleEngine", () => {
|
|
|
129
127
|
(req) => req.lastMessage.includes("test"),
|
|
130
128
|
"Handler reply",
|
|
131
129
|
);
|
|
132
|
-
expect(
|
|
130
|
+
expect(
|
|
131
|
+
engine.match(makeReq({ lastMessage: "this is a test" })),
|
|
132
|
+
).toBeDefined();
|
|
133
133
|
});
|
|
134
134
|
|
|
135
135
|
describe("toolName matching", () => {
|
|
136
136
|
it("matches when toolNames includes the specified tool", () => {
|
|
137
137
|
engine.add({ toolName: "get_weather" }, "Weather tool present");
|
|
138
|
-
expect(
|
|
138
|
+
expect(
|
|
139
|
+
engine.match(makeReq({ toolNames: ["get_weather", "search"] })),
|
|
140
|
+
).toBeDefined();
|
|
139
141
|
expect(engine.match(makeReq({ toolNames: ["search"] }))).toBeUndefined();
|
|
140
142
|
});
|
|
141
143
|
});
|
|
@@ -143,8 +145,12 @@ describe("RuleEngine", () => {
|
|
|
143
145
|
describe("toolCallId matching", () => {
|
|
144
146
|
it("matches when lastToolCallId equals the specified id", () => {
|
|
145
147
|
engine.add({ toolCallId: "call_abc" }, "Tool result");
|
|
146
|
-
expect(
|
|
147
|
-
|
|
148
|
+
expect(
|
|
149
|
+
engine.match(makeReq({ lastToolCallId: "call_abc" })),
|
|
150
|
+
).toBeDefined();
|
|
151
|
+
expect(
|
|
152
|
+
engine.match(makeReq({ lastToolCallId: "call_xyz" })),
|
|
153
|
+
).toBeUndefined();
|
|
148
154
|
expect(engine.match(makeReq())).toBeUndefined();
|
|
149
155
|
});
|
|
150
156
|
});
|
|
@@ -155,7 +161,8 @@ describe("RuleEngine", () => {
|
|
|
155
161
|
const rule = engine.add("hello", "Second");
|
|
156
162
|
engine.moveToFront(rule);
|
|
157
163
|
const matched = engine.match(makeReq());
|
|
158
|
-
|
|
164
|
+
if (!matched) throw new Error("expected match");
|
|
165
|
+
expect(matched.resolve).toBe("Second");
|
|
159
166
|
});
|
|
160
167
|
});
|
|
161
168
|
|
|
@@ -165,23 +172,32 @@ describe("RuleEngine", () => {
|
|
|
165
172
|
{ model: "gpt-5.4", predicate: (req) => req.messages.length > 2 },
|
|
166
173
|
"Complex match",
|
|
167
174
|
);
|
|
168
|
-
// Model matches but predicate fails (only 1 message)
|
|
169
175
|
expect(engine.match(makeReq({ model: "gpt-5.4" }))).toBeUndefined();
|
|
170
|
-
|
|
171
|
-
expect(
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
176
|
+
|
|
177
|
+
expect(
|
|
178
|
+
engine.match(
|
|
179
|
+
makeReq({
|
|
180
|
+
model: "gpt-5.4",
|
|
181
|
+
messages: [
|
|
182
|
+
{ role: "system", content: "sys" },
|
|
183
|
+
{ role: "user", content: "a" },
|
|
184
|
+
{ role: "assistant", content: "b" },
|
|
185
|
+
],
|
|
186
|
+
}),
|
|
187
|
+
),
|
|
188
|
+
).toBeDefined();
|
|
179
189
|
});
|
|
180
190
|
|
|
181
191
|
it("predicate runs after other fields (short-circuits)", () => {
|
|
182
192
|
let called = false;
|
|
183
193
|
engine.add(
|
|
184
|
-
{
|
|
194
|
+
{
|
|
195
|
+
model: "claude",
|
|
196
|
+
predicate: () => {
|
|
197
|
+
called = true;
|
|
198
|
+
return true;
|
|
199
|
+
},
|
|
200
|
+
},
|
|
185
201
|
"Never reached",
|
|
186
202
|
);
|
|
187
203
|
engine.match(makeReq({ model: "gpt-5.4" }));
|
package/src/types/index.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
export type { FormatName, MockRequest, Message, ToolDef } from "./request.js";
|
|
2
|
-
export type { Reply, ReplyObject, ErrorReply, ToolCall, Resolver, ReplyOptions, SequenceEntry } from "./reply.js";
|
|
3
|
-
export type { Match, MatchObject, PendingRule, RuleHandle, RuleSummary, Handler, Rule } from "./rule.js";
|
|
4
|
-
export type { RecordedRequest } from "../history.js";
|