llm-mock-server 1.0.4 → 1.0.6
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/.desloppify/query.json +1162 -62
- package/.desloppify/review_packet_blind.json +18 -18
- package/.desloppify/review_packets/holistic_packet_20260315_185401.json +1407 -0
- package/.desloppify/review_packets/holistic_packet_20260315_185613.json +1407 -0
- package/.desloppify/state-typescript.json +2530 -645
- package/.desloppify/state-typescript.json.bak +2494 -582
- package/.desloppify/subagents/runs/20260315_185401/logs/batch-1.log +384 -0
- package/.desloppify/subagents/runs/20260315_185401/logs/batch-10.log +484 -0
- package/.desloppify/subagents/runs/20260315_185401/logs/batch-2.log +408 -0
- package/.desloppify/subagents/runs/20260315_185401/logs/batch-3.log +416 -0
- package/.desloppify/subagents/runs/20260315_185401/logs/batch-4.log +360 -0
- package/.desloppify/subagents/runs/20260315_185401/logs/batch-5.log +360 -0
- package/.desloppify/subagents/runs/20260315_185401/logs/batch-6.log +364 -0
- package/.desloppify/subagents/runs/20260315_185401/logs/batch-7.log +428 -0
- package/.desloppify/subagents/runs/20260315_185401/logs/batch-8.log +388 -0
- package/.desloppify/subagents/runs/20260315_185401/logs/batch-9.log +500 -0
- package/.desloppify/subagents/runs/20260315_185401/prompts/batch-1.md +83 -0
- package/.desloppify/subagents/runs/20260315_185401/prompts/batch-10.md +108 -0
- package/.desloppify/subagents/runs/20260315_185401/prompts/batch-2.md +89 -0
- package/.desloppify/subagents/runs/20260315_185401/prompts/batch-3.md +91 -0
- package/.desloppify/subagents/runs/20260315_185401/prompts/batch-4.md +77 -0
- package/.desloppify/subagents/runs/20260315_185401/prompts/batch-5.md +77 -0
- package/.desloppify/subagents/runs/20260315_185401/prompts/batch-6.md +78 -0
- package/.desloppify/subagents/runs/20260315_185401/prompts/batch-7.md +94 -0
- package/.desloppify/subagents/runs/20260315_185401/prompts/batch-8.md +84 -0
- package/.desloppify/subagents/runs/20260315_185401/prompts/batch-9.md +112 -0
- package/.desloppify/subagents/runs/20260315_185401/results/batch-1.raw.txt +0 -0
- package/.desloppify/subagents/runs/20260315_185401/results/batch-10.raw.txt +0 -0
- package/.desloppify/subagents/runs/20260315_185401/results/batch-2.raw.txt +0 -0
- package/.desloppify/subagents/runs/20260315_185401/results/batch-3.raw.txt +0 -0
- package/.desloppify/subagents/runs/20260315_185401/results/batch-4.raw.txt +0 -0
- package/.desloppify/subagents/runs/20260315_185401/results/batch-5.raw.txt +0 -0
- package/.desloppify/subagents/runs/20260315_185401/results/batch-6.raw.txt +0 -0
- package/.desloppify/subagents/runs/20260315_185401/results/batch-7.raw.txt +0 -0
- package/.desloppify/subagents/runs/20260315_185401/results/batch-8.raw.txt +0 -0
- package/.desloppify/subagents/runs/20260315_185401/results/batch-9.raw.txt +0 -0
- package/.desloppify/subagents/runs/20260315_185401/run.log +36 -0
- package/.desloppify/subagents/runs/20260315_185401/run_summary.json +156 -0
- package/.desloppify/subagents/runs/20260315_185613/holistic_findings_merged.json +741 -0
- package/.desloppify/subagents/runs/20260315_185613/logs/batch-1.log +579 -0
- package/.desloppify/subagents/runs/20260315_185613/logs/batch-10.log +1537 -0
- package/.desloppify/subagents/runs/20260315_185613/logs/batch-2.log +829 -0
- package/.desloppify/subagents/runs/20260315_185613/logs/batch-3.log +927 -0
- package/.desloppify/subagents/runs/20260315_185613/logs/batch-4.log +429 -0
- package/.desloppify/subagents/runs/20260315_185613/logs/batch-5.log +276 -0
- package/.desloppify/subagents/runs/20260315_185613/logs/batch-6.log +450 -0
- package/.desloppify/subagents/runs/20260315_185613/logs/batch-7.log +730 -0
- package/.desloppify/subagents/runs/20260315_185613/logs/batch-8.log +698 -0
- package/.desloppify/subagents/runs/20260315_185613/logs/batch-9.log +938 -0
- package/.desloppify/subagents/runs/20260315_185613/prompts/batch-1.md +83 -0
- package/.desloppify/subagents/runs/20260315_185613/prompts/batch-10.md +108 -0
- package/.desloppify/subagents/runs/20260315_185613/prompts/batch-2.md +89 -0
- package/.desloppify/subagents/runs/20260315_185613/prompts/batch-3.md +91 -0
- package/.desloppify/subagents/runs/20260315_185613/prompts/batch-4.md +77 -0
- package/.desloppify/subagents/runs/20260315_185613/prompts/batch-5.md +77 -0
- package/.desloppify/subagents/runs/20260315_185613/prompts/batch-6.md +78 -0
- package/.desloppify/subagents/runs/20260315_185613/prompts/batch-7.md +94 -0
- package/.desloppify/subagents/runs/20260315_185613/prompts/batch-8.md +84 -0
- package/.desloppify/subagents/runs/20260315_185613/prompts/batch-9.md +112 -0
- package/.desloppify/subagents/runs/20260315_185613/results/batch-1.raw.txt +78 -0
- package/.desloppify/subagents/runs/20260315_185613/results/batch-10.raw.txt +242 -0
- package/.desloppify/subagents/runs/20260315_185613/results/batch-2.raw.txt +102 -0
- package/.desloppify/subagents/runs/20260315_185613/results/batch-3.raw.txt +94 -0
- package/.desloppify/subagents/runs/20260315_185613/results/batch-4.raw.txt +86 -0
- package/.desloppify/subagents/runs/20260315_185613/results/batch-5.raw.txt +1 -0
- package/.desloppify/subagents/runs/20260315_185613/results/batch-6.raw.txt +87 -0
- package/.desloppify/subagents/runs/20260315_185613/results/batch-7.raw.txt +1 -0
- package/.desloppify/subagents/runs/20260315_185613/results/batch-8.raw.txt +107 -0
- package/.desloppify/subagents/runs/20260315_185613/results/batch-9.raw.txt +67 -0
- package/.desloppify/subagents/runs/20260315_185613/run.log +96 -0
- package/.desloppify/subagents/runs/20260315_185613/run_summary.json +156 -0
- package/.github/workflows/docs.yml +46 -0
- package/.github/workflows/test.yml +3 -0
- package/README.md +8 -4
- package/docs/ARCHITECTURE.md +11 -11
- package/package.json +18 -11
- package/scorecard.png +0 -0
- package/src/{cli.ts → cli/cli.ts} +6 -11
- package/src/{cli-validators.ts → cli/validators.ts} +10 -9
- package/src/formats/anthropic/index.ts +2 -2
- package/src/formats/anthropic/parse.ts +5 -2
- package/src/formats/anthropic/serialize.ts +3 -3
- package/src/formats/openai/{index.ts → chat-completions/index.ts} +3 -3
- package/src/formats/openai/{parse.ts → chat-completions/parse.ts} +5 -2
- package/src/formats/openai/{serialize.ts → chat-completions/serialize.ts} +3 -3
- package/src/formats/{responses → openai/responses}/index.ts +2 -2
- package/src/formats/{responses → openai/responses}/parse.ts +5 -2
- package/src/formats/{responses → openai/responses}/serialize.ts +3 -3
- package/src/formats/request-helpers.ts +6 -1
- package/src/formats/serialize-helpers.ts +9 -4
- package/src/formats/types.ts +2 -6
- package/src/history.ts +6 -2
- package/src/loader.ts +2 -1
- package/src/mock-server.ts +55 -106
- package/src/route-handler.ts +7 -11
- package/src/rule-builder.ts +73 -0
- package/src/rule-engine.ts +3 -10
- package/src/sse-writer.ts +1 -1
- package/src/types/reply.ts +51 -8
- package/src/types/request.ts +21 -6
- package/src/types/rule.ts +65 -7
- package/test/cli-validators.test.ts +13 -5
- package/test/formats/openai.test.ts +40 -28
- package/test/formats/responses.test.ts +2 -2
- package/test/history.test.ts +1 -1
- package/test/loader.test.ts +3 -3
- package/test/logger.test.ts +2 -2
- package/test/mock-server.test.ts +1 -1
- package/test/rule-engine.test.ts +1 -1
- package/tsconfig.json +2 -4
- package/typedoc.json +9 -0
- /package/src/formats/openai/{schema.ts → chat-completions/schema.ts} +0 -0
- /package/src/formats/{responses → openai/responses}/schema.ts +0 -0
|
@@ -0,0 +1,938 @@
|
|
|
1
|
+
ATTEMPT 1/3
|
|
2
|
+
$ codex exec --ephemeral -C /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server -s workspace-write -c approval_policy="never" -c model_reasoning_effort="low" -o /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/.desloppify/subagents/runs/20260315_185613/results/batch-9.raw.txt You are a focused subagent reviewer for a single holistic investigation batch.
|
|
3
|
+
|
|
4
|
+
Repository root: /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server
|
|
5
|
+
Blind packet: /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/.desloppify/review_packet_blind.json
|
|
6
|
+
Batch index: 9
|
|
7
|
+
Batch name: Cross-cutting Sweep
|
|
8
|
+
Batch dimensions: design_coherence
|
|
9
|
+
Batch rationale: selected dimensions had no direct batch mapping; review representative cross-cutting files
|
|
10
|
+
|
|
11
|
+
Files assigned:
|
|
12
|
+
- src/types.ts
|
|
13
|
+
- src/formats/types.ts
|
|
14
|
+
- src/formats/request-helpers.ts
|
|
15
|
+
- src/logger.ts
|
|
16
|
+
- src/rule-engine.ts
|
|
17
|
+
- src/history.ts
|
|
18
|
+
- test/history.test.ts
|
|
19
|
+
- src/cli.ts
|
|
20
|
+
- src/formats/anthropic/schema.ts
|
|
21
|
+
- src/formats/openai/schema.ts
|
|
22
|
+
- src/formats/responses/schema.ts
|
|
23
|
+
- src/types/request.ts
|
|
24
|
+
- test/helpers/make-req.ts
|
|
25
|
+
- test/cli-validators.test.ts
|
|
26
|
+
- test/mock-server.test.ts
|
|
27
|
+
- test/rule-engine.test.ts
|
|
28
|
+
- src/cli-validators.ts
|
|
29
|
+
- src/mock-server.ts
|
|
30
|
+
- test/formats/anthropic.test.ts
|
|
31
|
+
- src/formats/responses/serialize.ts
|
|
32
|
+
- test/formats/responses.test.ts
|
|
33
|
+
- src/loader.ts
|
|
34
|
+
- test/formats/openai.test.ts
|
|
35
|
+
- test/loader.test.ts
|
|
36
|
+
- test/logger.test.ts
|
|
37
|
+
- src/formats/openai/serialize.ts
|
|
38
|
+
- src/types/rule.ts
|
|
39
|
+
- vitest.config.ts
|
|
40
|
+
- src/formats/anthropic/index.ts
|
|
41
|
+
- src/formats/anthropic/parse.ts
|
|
42
|
+
- src/formats/serialize-helpers.ts
|
|
43
|
+
- src/formats/openai/index.ts
|
|
44
|
+
- src/formats/openai/parse.ts
|
|
45
|
+
- src/formats/responses/index.ts
|
|
46
|
+
- src/formats/responses/parse.ts
|
|
47
|
+
- README.md
|
|
48
|
+
|
|
49
|
+
Task requirements:
|
|
50
|
+
1. Read the blind packet and follow `system_prompt` constraints exactly.
|
|
51
|
+
1a. If previously flagged issues are listed above, use them as context for your review.
|
|
52
|
+
Verify whether each still applies to the current code. Do not re-report fixed or
|
|
53
|
+
wontfix issues. Use them as starting points to look deeper — inspect adjacent code
|
|
54
|
+
and related modules for defects the prior review may have missed.
|
|
55
|
+
1c. Think structurally: when you spot multiple individual issues that share a common
|
|
56
|
+
root cause (missing abstraction, duplicated pattern, inconsistent convention),
|
|
57
|
+
explain the deeper structural issue in the finding, not just the surface symptom.
|
|
58
|
+
If the pattern is significant enough, report the structural issue as its own finding
|
|
59
|
+
with appropriate fix_scope ('multi_file_refactor' or 'architectural_change') and
|
|
60
|
+
use `root_cause_cluster` to connect related symptom findings together.
|
|
61
|
+
2. Evaluate ONLY listed files and ONLY listed dimensions for this batch.
|
|
62
|
+
3. Return 0-10 high-quality findings for this batch (empty array allowed).
|
|
63
|
+
3a. Do not suppress real defects to keep scores high; report every material issue you can support with evidence.
|
|
64
|
+
3b. Do not default to 100. Reserve 100 for genuinely exemplary evidence in this batch.
|
|
65
|
+
4. Score/finding consistency is required: broader or more severe findings MUST lower dimension scores.
|
|
66
|
+
4a. Any dimension scored below 85.0 MUST include explicit feedback: add at least one finding with the same `dimension` and a non-empty actionable `suggestion`.
|
|
67
|
+
5. Every finding must include `related_files` with at least 2 files when possible.
|
|
68
|
+
6. Every finding must include `dimension`, `identifier`, `summary`, `evidence`, `suggestion`, and `confidence`.
|
|
69
|
+
7. Every finding must include `impact_scope` and `fix_scope`.
|
|
70
|
+
8. Every scored dimension MUST include dimension_notes with concrete evidence.
|
|
71
|
+
9. If a dimension score is >85.0, include `issues_preventing_higher_score` in dimension_notes.
|
|
72
|
+
10. Use exactly one decimal place for every assessment and abstraction sub-axis score.
|
|
73
|
+
11. Ignore prior chat context and any target-threshold assumptions.
|
|
74
|
+
12. Do not edit repository files.
|
|
75
|
+
13. Return ONLY valid JSON, no markdown fences.
|
|
76
|
+
|
|
77
|
+
Scope enums:
|
|
78
|
+
- impact_scope: "local" | "module" | "subsystem" | "codebase"
|
|
79
|
+
- fix_scope: "single_edit" | "multi_file_refactor" | "architectural_change"
|
|
80
|
+
|
|
81
|
+
Output schema:
|
|
82
|
+
{
|
|
83
|
+
"batch": "Cross-cutting Sweep",
|
|
84
|
+
"batch_index": 9,
|
|
85
|
+
"assessments": {"<dimension>": <0-100 with one decimal place>},
|
|
86
|
+
"dimension_notes": {
|
|
87
|
+
"<dimension>": {
|
|
88
|
+
"evidence": ["specific code observations"],
|
|
89
|
+
"impact_scope": "local|module|subsystem|codebase",
|
|
90
|
+
"fix_scope": "single_edit|multi_file_refactor|architectural_change",
|
|
91
|
+
"confidence": "high|medium|low",
|
|
92
|
+
"issues_preventing_higher_score": "required when score >85.0",
|
|
93
|
+
"sub_axes": {"abstraction_leverage": 0-100 with one decimal place, "indirection_cost": 0-100 with one decimal place, "interface_honesty": 0-100 with one decimal place} // required for abstraction_fitness when evidence supports it
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
"findings": [{
|
|
97
|
+
"dimension": "<dimension>",
|
|
98
|
+
"identifier": "short_id",
|
|
99
|
+
"summary": "one-line defect summary",
|
|
100
|
+
"related_files": ["relative/path.py"],
|
|
101
|
+
"evidence": ["specific code observation"],
|
|
102
|
+
"suggestion": "concrete fix recommendation",
|
|
103
|
+
"confidence": "high|medium|low",
|
|
104
|
+
"impact_scope": "local|module|subsystem|codebase",
|
|
105
|
+
"fix_scope": "single_edit|multi_file_refactor|architectural_change",
|
|
106
|
+
"root_cause_cluster": "optional_cluster_name_when_supported_by_history"
|
|
107
|
+
}],
|
|
108
|
+
"retrospective": {
|
|
109
|
+
"root_causes": ["optional: concise root-cause hypotheses"],
|
|
110
|
+
"likely_symptoms": ["optional: identifiers that look symptom-level"],
|
|
111
|
+
"possible_false_positives": ["optional: prior concept keys likely mis-scoped"]
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
STDOUT:
|
|
117
|
+
{
|
|
118
|
+
"batch": "Cross-cutting Sweep",
|
|
119
|
+
"batch_index": 9,
|
|
120
|
+
"assessments": {
|
|
121
|
+
"design_coherence": 82.0
|
|
122
|
+
},
|
|
123
|
+
"dimension_notes": {
|
|
124
|
+
"design_coherence": {
|
|
125
|
+
"evidence": [
|
|
126
|
+
"Sequence rule construction is implemented in two places with similar step-mapping and resolver wiring (`MockServer.when().replySequence()` in src/mock-server.ts and `addSequenceRule()` in src/loader.ts).",
|
|
127
|
+
"The `MockServer` class mixes HTTP server lifecycle (Fastify setup/start/stop), rule authoring APIs, fallback management, and request history/logging state in one surface (src/mock-server.ts)."
|
|
128
|
+
],
|
|
129
|
+
"impact_scope": "subsystem",
|
|
130
|
+
"fix_scope": "multi_file_refactor",
|
|
131
|
+
"confidence": "medium"
|
|
132
|
+
}
|
|
133
|
+
},
|
|
134
|
+
"findings": [
|
|
135
|
+
{
|
|
136
|
+
"dimension": "design_coherence",
|
|
137
|
+
"identifier": "sequence_rule_duplication",
|
|
138
|
+
"summary": "Sequence rule normalization is duplicated in server API and loader paths",
|
|
139
|
+
"related_files": [
|
|
140
|
+
"src/mock-server.ts",
|
|
141
|
+
"src/loader.ts",
|
|
142
|
+
"src/rule-engine.ts"
|
|
143
|
+
],
|
|
144
|
+
"evidence": [
|
|
145
|
+
"`MockServer.when().replySequence()` maps `SequenceEntry` values into steps, creates a sequence resolver, assigns `rule.resolve`, and sets `rule.remaining`.",
|
|
146
|
+
"`addSequenceRule()` in `src/loader.ts` performs the same step normalization, `createSequenceResolver()` call, and `rule.remaining` setup for JSON5 rules."
|
|
147
|
+
],
|
|
148
|
+
"suggestion": "Extract a shared helper in `src/rule-engine.ts` (or a new `sequence` utility) that accepts normalized entries and returns a configured rule; use it from both `replySequence()` and `addSequenceRule()` to centralize sequence behavior.",
|
|
149
|
+
"confidence": "medium",
|
|
150
|
+
"impact_scope": "module",
|
|
151
|
+
"fix_scope": "multi_file_refactor"
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"dimension": "design_coherence",
|
|
155
|
+
"identifier": "mockserver_multi_role",
|
|
156
|
+
"summary": "`MockServer` combines server lifecycle, rule authoring, and state tracking responsibilities",
|
|
157
|
+
"related_files": [
|
|
158
|
+
"src/mock-server.ts",
|
|
159
|
+
"src/rule-engine.ts",
|
|
160
|
+
"src/history.ts"
|
|
161
|
+
],
|
|
162
|
+
"evidence": [
|
|
163
|
+
"`MockServer` constructs the Fastify server and registers format routes in the constructor, exposes rule authoring methods (`when`, `whenTool`, `nextError`), manages fallback state, and owns `RequestHistory` and logging.",
|
|
164
|
+
"This blends HTTP runtime concerns with rule registry and history concerns that already exist as separate modules (`RuleEngine`, `RequestHistory`)."
|
|
165
|
+
],
|
|
166
|
+
"suggestion": "Split `MockServer` into a runtime/server wrapper and a rule/history registry (e.g., extract a `RuleRegistry` or `MockServerCore` that exposes `when*`, `history`, `rules`, and fallback), and keep Fastify lifecycle and route wiring in a thinner server class.",
|
|
167
|
+
"confidence": "medium",
|
|
168
|
+
"impact_scope": "subsystem",
|
|
169
|
+
"fix_scope": "architectural_change"
|
|
170
|
+
}
|
|
171
|
+
],
|
|
172
|
+
"retrospective": {
|
|
173
|
+
"root_causes": [
|
|
174
|
+
"Sequence rule behavior is implemented in parallel call paths without a shared abstraction.",
|
|
175
|
+
"Top-level API class aggregates multiple subsystems to present a convenient surface, but lacks internal separation."
|
|
176
|
+
],
|
|
177
|
+
"likely_symptoms": [
|
|
178
|
+
"sequence_rule_duplication",
|
|
179
|
+
"mockserver_multi_role"
|
|
180
|
+
],
|
|
181
|
+
"possible_false_positives": []
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
STDERR:
|
|
187
|
+
OpenAI Codex v0.114.0 (research preview)
|
|
188
|
+
--------
|
|
189
|
+
workdir: /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server
|
|
190
|
+
model: gpt-5.2-codex
|
|
191
|
+
provider: openai
|
|
192
|
+
approval: never
|
|
193
|
+
sandbox: workspace-write [workdir, /tmp, $TMPDIR, /Users/suyash.x.srijan/.codex/memories]
|
|
194
|
+
reasoning effort: low
|
|
195
|
+
reasoning summaries: none
|
|
196
|
+
session id: 019cf2e4-df65-74e3-9c1d-3e0dafd872df
|
|
197
|
+
--------
|
|
198
|
+
user
|
|
199
|
+
You are a focused subagent reviewer for a single holistic investigation batch.
|
|
200
|
+
|
|
201
|
+
Repository root: /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server
|
|
202
|
+
Blind packet: /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/.desloppify/review_packet_blind.json
|
|
203
|
+
Batch index: 9
|
|
204
|
+
Batch name: Cross-cutting Sweep
|
|
205
|
+
Batch dimensions: design_coherence
|
|
206
|
+
Batch rationale: selected dimensions had no direct batch mapping; review representative cross-cutting files
|
|
207
|
+
|
|
208
|
+
Files assigned:
|
|
209
|
+
- src/types.ts
|
|
210
|
+
- src/formats/types.ts
|
|
211
|
+
- src/formats/request-helpers.ts
|
|
212
|
+
- src/logger.ts
|
|
213
|
+
- src/rule-engine.ts
|
|
214
|
+
- src/history.ts
|
|
215
|
+
- test/history.test.ts
|
|
216
|
+
- src/cli.ts
|
|
217
|
+
- src/formats/anthropic/schema.ts
|
|
218
|
+
- src/formats/openai/schema.ts
|
|
219
|
+
- src/formats/responses/schema.ts
|
|
220
|
+
- src/types/request.ts
|
|
221
|
+
- test/helpers/make-req.ts
|
|
222
|
+
- test/cli-validators.test.ts
|
|
223
|
+
- test/mock-server.test.ts
|
|
224
|
+
- test/rule-engine.test.ts
|
|
225
|
+
- src/cli-validators.ts
|
|
226
|
+
- src/mock-server.ts
|
|
227
|
+
- test/formats/anthropic.test.ts
|
|
228
|
+
- src/formats/responses/serialize.ts
|
|
229
|
+
- test/formats/responses.test.ts
|
|
230
|
+
- src/loader.ts
|
|
231
|
+
- test/formats/openai.test.ts
|
|
232
|
+
- test/loader.test.ts
|
|
233
|
+
- test/logger.test.ts
|
|
234
|
+
- src/formats/openai/serialize.ts
|
|
235
|
+
- src/types/rule.ts
|
|
236
|
+
- vitest.config.ts
|
|
237
|
+
- src/formats/anthropic/index.ts
|
|
238
|
+
- src/formats/anthropic/parse.ts
|
|
239
|
+
- src/formats/serialize-helpers.ts
|
|
240
|
+
- src/formats/openai/index.ts
|
|
241
|
+
- src/formats/openai/parse.ts
|
|
242
|
+
- src/formats/responses/index.ts
|
|
243
|
+
- src/formats/responses/parse.ts
|
|
244
|
+
- README.md
|
|
245
|
+
|
|
246
|
+
Task requirements:
|
|
247
|
+
1. Read the blind packet and follow `system_prompt` constraints exactly.
|
|
248
|
+
1a. If previously flagged issues are listed above, use them as context for your review.
|
|
249
|
+
Verify whether each still applies to the current code. Do not re-report fixed or
|
|
250
|
+
wontfix issues. Use them as starting points to look deeper — inspect adjacent code
|
|
251
|
+
and related modules for defects the prior review may have missed.
|
|
252
|
+
1c. Think structurally: when you spot multiple individual issues that share a common
|
|
253
|
+
root cause (missing abstraction, duplicated pattern, inconsistent convention),
|
|
254
|
+
explain the deeper structural issue in the finding, not just the surface symptom.
|
|
255
|
+
If the pattern is significant enough, report the structural issue as its own finding
|
|
256
|
+
with appropriate fix_scope ('multi_file_refactor' or 'architectural_change') and
|
|
257
|
+
use `root_cause_cluster` to connect related symptom findings together.
|
|
258
|
+
2. Evaluate ONLY listed files and ONLY listed dimensions for this batch.
|
|
259
|
+
3. Return 0-10 high-quality findings for this batch (empty array allowed).
|
|
260
|
+
3a. Do not suppress real defects to keep scores high; report every material issue you can support with evidence.
|
|
261
|
+
3b. Do not default to 100. Reserve 100 for genuinely exemplary evidence in this batch.
|
|
262
|
+
4. Score/finding consistency is required: broader or more severe findings MUST lower dimension scores.
|
|
263
|
+
4a. Any dimension scored below 85.0 MUST include explicit feedback: add at least one finding with the same `dimension` and a non-empty actionable `suggestion`.
|
|
264
|
+
5. Every finding must include `related_files` with at least 2 files when possible.
|
|
265
|
+
6. Every finding must include `dimension`, `identifier`, `summary`, `evidence`, `suggestion`, and `confidence`.
|
|
266
|
+
7. Every finding must include `impact_scope` and `fix_scope`.
|
|
267
|
+
8. Every scored dimension MUST include dimension_notes with concrete evidence.
|
|
268
|
+
9. If a dimension score is >85.0, include `issues_preventing_higher_score` in dimension_notes.
|
|
269
|
+
10. Use exactly one decimal place for every assessment and abstraction sub-axis score.
|
|
270
|
+
11. Ignore prior chat context and any target-threshold assumptions.
|
|
271
|
+
12. Do not edit repository files.
|
|
272
|
+
13. Return ONLY valid JSON, no markdown fences.
|
|
273
|
+
|
|
274
|
+
Scope enums:
|
|
275
|
+
- impact_scope: "local" | "module" | "subsystem" | "codebase"
|
|
276
|
+
- fix_scope: "single_edit" | "multi_file_refactor" | "architectural_change"
|
|
277
|
+
|
|
278
|
+
Output schema:
|
|
279
|
+
{
|
|
280
|
+
"batch": "Cross-cutting Sweep",
|
|
281
|
+
"batch_index": 9,
|
|
282
|
+
"assessments": {"<dimension>": <0-100 with one decimal place>},
|
|
283
|
+
"dimension_notes": {
|
|
284
|
+
"<dimension>": {
|
|
285
|
+
"evidence": ["specific code observations"],
|
|
286
|
+
"impact_scope": "local|module|subsystem|codebase",
|
|
287
|
+
"fix_scope": "single_edit|multi_file_refactor|architectural_change",
|
|
288
|
+
"confidence": "high|medium|low",
|
|
289
|
+
"issues_preventing_higher_score": "required when score >85.0",
|
|
290
|
+
"sub_axes": {"abstraction_leverage": 0-100 with one decimal place, "indirection_cost": 0-100 with one decimal place, "interface_honesty": 0-100 with one decimal place} // required for abstraction_fitness when evidence supports it
|
|
291
|
+
}
|
|
292
|
+
},
|
|
293
|
+
"findings": [{
|
|
294
|
+
"dimension": "<dimension>",
|
|
295
|
+
"identifier": "short_id",
|
|
296
|
+
"summary": "one-line defect summary",
|
|
297
|
+
"related_files": ["relative/path.py"],
|
|
298
|
+
"evidence": ["specific code observation"],
|
|
299
|
+
"suggestion": "concrete fix recommendation",
|
|
300
|
+
"confidence": "high|medium|low",
|
|
301
|
+
"impact_scope": "local|module|subsystem|codebase",
|
|
302
|
+
"fix_scope": "single_edit|multi_file_refactor|architectural_change",
|
|
303
|
+
"root_cause_cluster": "optional_cluster_name_when_supported_by_history"
|
|
304
|
+
}],
|
|
305
|
+
"retrospective": {
|
|
306
|
+
"root_causes": ["optional: concise root-cause hypotheses"],
|
|
307
|
+
"likely_symptoms": ["optional: identifiers that look symptom-level"],
|
|
308
|
+
"possible_false_positives": ["optional: prior concept keys likely mis-scoped"]
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
mcp startup: no servers
|
|
313
|
+
|
|
314
|
+
thinking
|
|
315
|
+
**Reading blind packet via exec cat**
|
|
316
|
+
exec
|
|
317
|
+
/bin/zsh -lc 'ls /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/.desloppify' in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
318
|
+
external_review_sessions
|
|
319
|
+
query.json
|
|
320
|
+
review_packet_blind.json
|
|
321
|
+
review_packets
|
|
322
|
+
state-typescript.json
|
|
323
|
+
state-typescript.json.bak
|
|
324
|
+
subagents
|
|
325
|
+
exec
|
|
326
|
+
/bin/zsh -lc 'cat /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/.desloppify/review_packet_blind.json' in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
327
|
+
{
|
|
328
|
+
"command": "review",
|
|
329
|
+
"mode": "holistic",
|
|
330
|
+
"language": "typescript",
|
|
331
|
+
"dimensions": [
|
|
332
|
+
"cross_module_architecture",
|
|
333
|
+
"convention_outlier",
|
|
334
|
+
"error_consistency",
|
|
335
|
+
"abstraction_fitness",
|
|
336
|
+
"api_surface_coherence",
|
|
337
|
+
"authorization_consistency",
|
|
338
|
+
"ai_generated_debt",
|
|
339
|
+
"incomplete_migration",
|
|
340
|
+
"package_organization",
|
|
341
|
+
"high_level_elegance",
|
|
342
|
+
"mid_level_elegance",
|
|
343
|
+
"low_level_elegance",
|
|
344
|
+
"design_coherence"
|
|
345
|
+
],
|
|
346
|
+
"dimension_prompts": {
|
|
347
|
+
|
|
348
|
+
thinking
|
|
349
|
+
**Planning targeted file review**
|
|
350
|
+
|
|
351
|
+
I'm focusing on quickly identifying and reading key files related to design coherence, using search tools to gather evidence efficiently.
|
|
352
|
+
exec
|
|
353
|
+
/bin/zsh -lc 'ls /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src' in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
354
|
+
cli-validators.ts
|
|
355
|
+
cli.ts
|
|
356
|
+
formats
|
|
357
|
+
history.ts
|
|
358
|
+
index.ts
|
|
359
|
+
loader.ts
|
|
360
|
+
logger.ts
|
|
361
|
+
mock-server.ts
|
|
362
|
+
route-handler.ts
|
|
363
|
+
rule-engine.ts
|
|
364
|
+
sse-writer.ts
|
|
365
|
+
types
|
|
366
|
+
types.ts
|
|
367
|
+
|
|
368
|
+
thinking
|
|
369
|
+
**Planning inspection of key modules**
|
|
370
|
+
|
|
371
|
+
I'm preparing to scan several core files for multi-responsibility functions to analyze design coherence, starting with cli.ts, mock-server.ts, loader.ts, rule-engine.ts, history.ts, request-helpers.ts, and serialization/parsing utilities.
|
|
372
|
+
exec
|
|
373
|
+
/bin/zsh -lc "sed -n '1,200p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/cli.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
374
|
+
#!/usr/bin/env node
|
|
375
|
+
|
|
376
|
+
import { watch } from "node:fs";
|
|
377
|
+
import { createRequire } from "node:module";
|
|
378
|
+
import { Command } from "commander";
|
|
379
|
+
import pc from "picocolors";
|
|
380
|
+
import { MockServer } from "./mock-server.js";
|
|
381
|
+
import { Logger } from "./logger.js";
|
|
382
|
+
import {
|
|
383
|
+
parsePort,
|
|
384
|
+
parseHost,
|
|
385
|
+
parseLogLevel,
|
|
386
|
+
parseChunkSize,
|
|
387
|
+
parseLatency,
|
|
388
|
+
} from "./cli-validators.js";
|
|
389
|
+
|
|
390
|
+
const require = createRequire(import.meta.url);
|
|
391
|
+
const { version } = require("../package.json") as { version: string };
|
|
392
|
+
|
|
393
|
+
const WATCH_DEBOUNCE_MS = 100;
|
|
394
|
+
|
|
395
|
+
thinking
|
|
396
|
+
**Reviewing server setup and responsibilities**
|
|
397
|
+
|
|
398
|
+
I'm assessing the start function's responsibilities, including parsing, server setup, output, watching, and signal handling, and planning to check the mock-server for further clarity.
|
|
399
|
+
exec
|
|
400
|
+
/bin/zsh -lc "sed -n '1,220p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/mock-server.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
401
|
+
import Fastify from "fastify";
|
|
402
|
+
import type { FastifyInstance } from "fastify";
|
|
403
|
+
import type {
|
|
404
|
+
Match,
|
|
405
|
+
PendingRule,
|
|
406
|
+
Reply,
|
|
407
|
+
ReplyOptions,
|
|
408
|
+
Resolver,
|
|
409
|
+
Rule,
|
|
410
|
+
RuleHandle,
|
|
411
|
+
RuleSummary,
|
|
412
|
+
SequenceEntry,
|
|
413
|
+
} from "./types.js";
|
|
414
|
+
import { RuleEngine, createSequenceResolver } from "./rule-engine.js";
|
|
415
|
+
import { RequestHistory } from "./history.js";
|
|
416
|
+
import { openaiFormat } from "./formats/openai/index.js";
|
|
417
|
+
import { anthropicFormat } from "./formats/anthropic/index.js";
|
|
418
|
+
import { responsesFormat } from "./formats/responses/index.js";
|
|
419
|
+
import type { Format } from "./formats/types.js";
|
|
420
|
+
import { Logger } from "./logger.js";
|
|
421
|
+
exec
|
|
422
|
+
/bin/zsh -lc "sed -n '220,520p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/mock-server.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
423
|
+
if (!this.listening)
|
|
424
|
+
throw new Error("Server is not running. Call start() first.");
|
|
425
|
+
const addr = this.app.server.address();
|
|
426
|
+
const port = addr !== null && typeof addr === "object" ? addr.port : 0;
|
|
427
|
+
return `http://${this.host}:${port}`;
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
get ruleCount(): number {
|
|
431
|
+
return this.engine.ruleCount;
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
/** A snapshot of all registered rules with their descriptions and remaining match counts. */
|
|
435
|
+
get rules(): readonly RuleSummary[] {
|
|
436
|
+
return this.engine.describe();
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/** Start listening. Pass `0` (the default) for a random port. */
|
|
440
|
+
async start(port = 0): Promise<void> {
|
|
441
|
+
if (this.listening) throw new Error("Server is already running.");
|
|
442
|
+
await this.app.listen({ port, host: this.host });
|
|
443
|
+
|
|
444
|
+
thinking
|
|
445
|
+
**Assessing class responsibilities**
|
|
446
|
+
|
|
447
|
+
I'm reviewing the loader to gather evidence on whether the class handles too many responsibilities, aiming to clarify design coherence.
|
|
448
|
+
exec
|
|
449
|
+
/bin/zsh -lc "sed -n '1,240p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/loader.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
450
|
+
import { readFile, readdir, stat } from "node:fs/promises";
|
|
451
|
+
import { join, extname } from "node:path";
|
|
452
|
+
import JSON5 from "json5";
|
|
453
|
+
import { z } from "zod";
|
|
454
|
+
import type { Handler, Match, MatchObject, Reply } from "./types.js";
|
|
455
|
+
import { type RuleEngine, createSequenceResolver } from "./rule-engine.js";
|
|
456
|
+
|
|
457
|
+
interface LoadContext {
|
|
458
|
+
engine: RuleEngine;
|
|
459
|
+
setFallback?: (reply: Reply) => void;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const json5MatchSchema = z.union([
|
|
463
|
+
z.string(),
|
|
464
|
+
z.object({
|
|
465
|
+
message: z.string().optional(),
|
|
466
|
+
model: z.string().optional(),
|
|
467
|
+
system: z.string().optional(),
|
|
468
|
+
format: z.enum(["openai", "anthropic", "responses"]).optional(),
|
|
469
|
+
}),
|
|
470
|
+
exec
|
|
471
|
+
/bin/zsh -lc "sed -n '240,520p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/loader.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
472
|
+
} else if (entryStat.isFile()) {
|
|
473
|
+
const loader = loaderByExtension.get(extname(fullPath));
|
|
474
|
+
if (loader) await loader(fullPath, ctx);
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
thinking
|
|
480
|
+
**Assessing rule loading and engine coherence**
|
|
481
|
+
exec
|
|
482
|
+
/bin/zsh -lc "sed -n '1,260p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/rule-engine.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
483
|
+
import type {
|
|
484
|
+
Match,
|
|
485
|
+
MatchObject,
|
|
486
|
+
MockRequest,
|
|
487
|
+
Resolver,
|
|
488
|
+
Reply,
|
|
489
|
+
ReplyOptions,
|
|
490
|
+
Rule,
|
|
491
|
+
RuleSummary,
|
|
492
|
+
} from "./types.js";
|
|
493
|
+
|
|
494
|
+
function safeRegex(re: RegExp): RegExp {
|
|
495
|
+
return re.global || re.sticky
|
|
496
|
+
? new RegExp(re.source, re.flags.replace(/[gy]/g, ""))
|
|
497
|
+
: re;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
function compilePattern(pattern: string | RegExp): (value: string) => boolean {
|
|
501
|
+
if (typeof pattern === "string") {
|
|
502
|
+
const lower = pattern.toLowerCase();
|
|
503
|
+
|
|
504
|
+
thinking
|
|
505
|
+
**Questioning mutation and responsibilities**
|
|
506
|
+
|
|
507
|
+
The createSequenceResolver function might mutate rule options and serves in both loader and mock-server, suggesting possible multiple responsibilities that merit checking in history.ts.
|
|
508
|
+
exec
|
|
509
|
+
/bin/zsh -lc "sed -n '1,220p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/history.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
510
|
+
import type { MockRequest } from "./types.js";
|
|
511
|
+
|
|
512
|
+
/** A recorded request with the rule that matched and when it happened. */
|
|
513
|
+
export interface RecordedRequest {
|
|
514
|
+
readonly request: MockRequest;
|
|
515
|
+
/** The rule that matched, or `undefined` if the fallback was used. */
|
|
516
|
+
readonly rule: string | undefined;
|
|
517
|
+
readonly timestamp: number;
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
/**
|
|
521
|
+
* Records every request the server handles.
|
|
522
|
+
* Iterable and has fluent query methods for test assertions.
|
|
523
|
+
*
|
|
524
|
+
* @example
|
|
525
|
+
* ```ts
|
|
526
|
+
* expect(server.history.count()).toBe(3);
|
|
527
|
+
* expect(server.history.last()?.request.lastMessage).toBe("hello");
|
|
528
|
+
* const matched = server.history.where(r => r.rule !== undefined);
|
|
529
|
+
* ```
|
|
530
|
+
|
|
531
|
+
thinking
|
|
532
|
+
**Identifying missing request helpers**
|
|
533
|
+
exec
|
|
534
|
+
/bin/zsh -lc "sed -n '1,220p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/formats/request-helpers.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
535
|
+
import type { FormatName, Message, MockRequest, ToolDef } from "../types.js";
|
|
536
|
+
|
|
537
|
+
function asRecord(body: unknown): Record<string, unknown> {
|
|
538
|
+
if (typeof body === "object" && body !== null)
|
|
539
|
+
return body as Record<string, unknown>;
|
|
540
|
+
return {};
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
export function isStreaming(body: unknown): boolean {
|
|
544
|
+
return asRecord(body)["stream"] !== false;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
export interface RequestMeta {
|
|
548
|
+
readonly headers: Readonly<Record<string, string | undefined>>;
|
|
549
|
+
readonly path: string;
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
const EMPTY_META: RequestMeta = { headers: {}, path: "" };
|
|
553
|
+
|
|
554
|
+
interface ParsedBody {
|
|
555
|
+
|
|
556
|
+
thinking
|
|
557
|
+
**Assessing serialization patterns**
|
|
558
|
+
|
|
559
|
+
Noting that buildMockRequest already parses data and questioning if types are necessary; planning to examine serialization and parsing formats for recurring patterns and design consistency.
|
|
560
|
+
exec
|
|
561
|
+
/bin/zsh -lc "sed -n '1,200p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/formats/openai/parse.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
562
|
+
import type { MockRequest, Message, ToolDef } from "../../types.js";
|
|
563
|
+
import { buildMockRequest, type RequestMeta } from "../request-helpers.js";
|
|
564
|
+
import { OpenAIRequestSchema, type OpenAIRequest } from "./schema.js";
|
|
565
|
+
|
|
566
|
+
function extractContent(
|
|
567
|
+
content: OpenAIRequest["messages"][number]["content"],
|
|
568
|
+
): string {
|
|
569
|
+
if (content == null) return "";
|
|
570
|
+
if (typeof content === "string") return content;
|
|
571
|
+
return content
|
|
572
|
+
.filter((p) => p.type === "text" && p.text !== undefined)
|
|
573
|
+
.map((p) => p.text!)
|
|
574
|
+
.join("\n");
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
function parseMessages(req: OpenAIRequest): readonly Message[] {
|
|
578
|
+
return req.messages.map((m) => ({
|
|
579
|
+
role: m.role === "developer" ? "system" : (m.role ?? "user"),
|
|
580
|
+
content: extractContent(m.content),
|
|
581
|
+
...(m.tool_call_id !== undefined && { toolCallId: m.tool_call_id }),
|
|
582
|
+
|
|
583
|
+
thinking
|
|
584
|
+
**Inspecting OpenAI serialize**
|
|
585
|
+
exec
|
|
586
|
+
/bin/zsh -lc "sed -n '1,200p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/formats/openai/serialize.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
587
|
+
import type { ReplyObject, ReplyOptions } from "../../types.js";
|
|
588
|
+
import type { SSEChunk } from "../types.js";
|
|
589
|
+
import {
|
|
590
|
+
splitText,
|
|
591
|
+
genId,
|
|
592
|
+
toolId,
|
|
593
|
+
finishReason,
|
|
594
|
+
MS_PER_SECOND,
|
|
595
|
+
DEFAULT_USAGE,
|
|
596
|
+
} from "../serialize-helpers.js";
|
|
597
|
+
|
|
598
|
+
function buildUsage(usage: { input: number; output: number }) {
|
|
599
|
+
return {
|
|
600
|
+
prompt_tokens: usage.input,
|
|
601
|
+
completion_tokens: usage.output,
|
|
602
|
+
total_tokens: usage.input + usage.output,
|
|
603
|
+
prompt_tokens_details: { cached_tokens: 0, audio_tokens: 0 },
|
|
604
|
+
completion_tokens_details: {
|
|
605
|
+
reasoning_tokens: 0,
|
|
606
|
+
audio_tokens: 0,
|
|
607
|
+
|
|
608
|
+
thinking
|
|
609
|
+
**Exploring serialization and parsing in Anthropic code**
|
|
610
|
+
|
|
611
|
+
I'm checking whether serialization, parsing, or both are handled in the Anthropic code by examining the parse, schema, index, and responses/serialize files to clarify their roles.
|
|
612
|
+
exec
|
|
613
|
+
/bin/zsh -lc "sed -n '1,220p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/formats/anthropic/parse.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
614
|
+
import type { MockRequest, Message, ToolDef } from "../../types.js";
|
|
615
|
+
import { buildMockRequest, type RequestMeta } from "../request-helpers.js";
|
|
616
|
+
import { AnthropicRequestSchema, type AnthropicRequest } from "./schema.js";
|
|
617
|
+
|
|
618
|
+
function extractSystem(system: AnthropicRequest["system"]): Message[] {
|
|
619
|
+
if (system == null) return [];
|
|
620
|
+
if (typeof system === "string")
|
|
621
|
+
return system ? [{ role: "system", content: system }] : [];
|
|
622
|
+
const text = system.map((b) => b.text).join("\n");
|
|
623
|
+
return text ? [{ role: "system", content: text }] : [];
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
function extractContent(
|
|
627
|
+
content: AnthropicRequest["messages"][number]["content"],
|
|
628
|
+
): {
|
|
629
|
+
content: string;
|
|
630
|
+
toolCallId?: string | undefined;
|
|
631
|
+
} {
|
|
632
|
+
if (typeof content === "string") return { content };
|
|
633
|
+
const text = content
|
|
634
|
+
|
|
635
|
+
thinking
|
|
636
|
+
**Checking if responses serialize**
|
|
637
|
+
exec
|
|
638
|
+
/bin/zsh -lc "sed -n '1,240p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/formats/responses/serialize.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
639
|
+
import type { ReplyObject, ReplyOptions, ToolCall } from "../../types.js";
|
|
640
|
+
import type { SSEChunk } from "../types.js";
|
|
641
|
+
import {
|
|
642
|
+
splitText,
|
|
643
|
+
genId,
|
|
644
|
+
toolId,
|
|
645
|
+
shouldEmitText,
|
|
646
|
+
MS_PER_SECOND,
|
|
647
|
+
DEFAULT_USAGE,
|
|
648
|
+
} from "../serialize-helpers.js";
|
|
649
|
+
|
|
650
|
+
function buildUsage(usage: { input: number; output: number }) {
|
|
651
|
+
return {
|
|
652
|
+
input_tokens: usage.input,
|
|
653
|
+
output_tokens: usage.output,
|
|
654
|
+
total_tokens: usage.input + usage.output,
|
|
655
|
+
};
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
interface StreamBlock {
|
|
659
|
+
exec
|
|
660
|
+
/bin/zsh -lc "sed -n '240,520p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/formats/responses/serialize.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
661
|
+
|
|
662
|
+
const allChunks = blocks.flatMap((b) => b.chunks);
|
|
663
|
+
const output = blocks.map((b) => b.outputItem);
|
|
664
|
+
|
|
665
|
+
return [
|
|
666
|
+
...header,
|
|
667
|
+
...allChunks,
|
|
668
|
+
c({
|
|
669
|
+
type: "response.completed",
|
|
670
|
+
response: {
|
|
671
|
+
...baseResponse,
|
|
672
|
+
status: "completed",
|
|
673
|
+
output,
|
|
674
|
+
usage: buildUsage(usage),
|
|
675
|
+
},
|
|
676
|
+
}),
|
|
677
|
+
];
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
export function serializeComplete(
|
|
681
|
+
|
|
682
|
+
thinking
|
|
683
|
+
**Noting need for response parsing**
|
|
684
|
+
exec
|
|
685
|
+
/bin/zsh -lc "sed -n '1,200p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/formats/responses/parse.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
686
|
+
import type { MockRequest, Message, ToolDef } from "../../types.js";
|
|
687
|
+
import { buildMockRequest, type RequestMeta } from "../request-helpers.js";
|
|
688
|
+
import {
|
|
689
|
+
ResponsesRequestSchema,
|
|
690
|
+
FunctionToolSchema,
|
|
691
|
+
type ResponsesRequest,
|
|
692
|
+
} from "./schema.js";
|
|
693
|
+
|
|
694
|
+
function extractInputContent(
|
|
695
|
+
content: string | Record<string, unknown>[],
|
|
696
|
+
): string {
|
|
697
|
+
if (typeof content === "string") return content;
|
|
698
|
+
return content
|
|
699
|
+
.filter((b) => b["type"] === "input_text" || b["type"] === "text")
|
|
700
|
+
.map((b) => String(b["text"] ?? ""))
|
|
701
|
+
.join("\n");
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
function parseInput(req: ResponsesRequest): readonly Message[] {
|
|
705
|
+
const instructions: Message[] = req.instructions
|
|
706
|
+
|
|
707
|
+
thinking
|
|
708
|
+
**Identifying missing dependency**
|
|
709
|
+
|
|
710
|
+
I see that the cli-validators files are needed next to proceed, so I'll locate and review those to understand their role.
|
|
711
|
+
exec
|
|
712
|
+
/bin/zsh -lc "sed -n '1,220p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/cli-validators.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
713
|
+
import { isIP } from "node:net";
|
|
714
|
+
import { lookup } from "node:dns/promises";
|
|
715
|
+
import { LEVEL_PRIORITY, type LogLevel } from "./logger.js";
|
|
716
|
+
|
|
717
|
+
const VALID_LOG_LEVELS = Object.keys(LEVEL_PRIORITY) as LogLevel[];
|
|
718
|
+
|
|
719
|
+
function isLogLevel(value: string): value is LogLevel {
|
|
720
|
+
return value in LEVEL_PRIORITY;
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
const MAX_PORT = 65535;
|
|
724
|
+
|
|
725
|
+
export function parsePort(value: string): number {
|
|
726
|
+
const port = parseInt(value, 10);
|
|
727
|
+
if (isNaN(port) || port < 1 || port > MAX_PORT) {
|
|
728
|
+
throw new Error(`Invalid port "${value}". Must be 1-${String(MAX_PORT)}.`);
|
|
729
|
+
}
|
|
730
|
+
return port;
|
|
731
|
+
}
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
thinking
|
|
735
|
+
**Reviewing serialization helpers**
|
|
736
|
+
|
|
737
|
+
I'm checking the serialize-helpers module to identify recurring patterns and assess if types or schemas are necessary for coherence.
|
|
738
|
+
exec
|
|
739
|
+
/bin/zsh -lc "sed -n '1,220p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/formats/serialize-helpers.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
740
|
+
import type { ReplyObject } from "../types.js";
|
|
741
|
+
|
|
742
|
+
export const MS_PER_SECOND = 1000;
|
|
743
|
+
const BASE_36 = 36;
|
|
744
|
+
export const DEFAULT_USAGE = { input: 10, output: 5 } as const;
|
|
745
|
+
|
|
746
|
+
export function splitText(text: string, chunkSize: number): string[] {
|
|
747
|
+
if (chunkSize <= 0 || text.length <= chunkSize) return [text];
|
|
748
|
+
const chunks: string[] = [];
|
|
749
|
+
for (let i = 0; i < text.length; i += chunkSize) {
|
|
750
|
+
chunks.push(text.slice(i, i + chunkSize));
|
|
751
|
+
}
|
|
752
|
+
return chunks;
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
export function genId(prefix: string): string {
|
|
756
|
+
return `${prefix}_${Date.now().toString(BASE_36)}`;
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
export function toolId(
|
|
760
|
+
|
|
761
|
+
thinking
|
|
762
|
+
**Noting required type files**
|
|
763
|
+
|
|
764
|
+
I'm identifying src/types/request.ts and related type files as needed for the implementation.
|
|
765
|
+
exec
|
|
766
|
+
/bin/zsh -lc "sed -n '1,220p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/types/request.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
767
|
+
/** The LLM API wire format that was detected for a request. */
|
|
768
|
+
export type FormatName = "openai" | "anthropic" | "responses";
|
|
769
|
+
|
|
770
|
+
/** A normalised view of an incoming request, regardless of the original wire format. */
|
|
771
|
+
export interface MockRequest {
|
|
772
|
+
readonly format: FormatName;
|
|
773
|
+
readonly model: string;
|
|
774
|
+
readonly streaming: boolean;
|
|
775
|
+
/** Full conversation, normalised from whatever format came in. */
|
|
776
|
+
readonly messages: readonly Message[];
|
|
777
|
+
/** The last user message's text. This is what most matchers check. */
|
|
778
|
+
readonly lastMessage: string;
|
|
779
|
+
/** Empty string if there wasn't one. */
|
|
780
|
+
readonly systemMessage: string;
|
|
781
|
+
readonly tools?: readonly ToolDef[] | undefined;
|
|
782
|
+
/** Pulled out from `tools` for quick lookups. */
|
|
783
|
+
readonly toolNames: readonly string[];
|
|
784
|
+
/** Set when the last message was a tool result. */
|
|
785
|
+
readonly lastToolCallId: string | undefined;
|
|
786
|
+
/** The raw request body, for anything we don't extract. */
|
|
787
|
+
|
|
788
|
+
thinking
|
|
789
|
+
**Reviewing types definition**
|
|
790
|
+
exec
|
|
791
|
+
/bin/zsh -lc "sed -n '1,220p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/types/rule.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
792
|
+
import type { MockRequest, FormatName } from "./request.js";
|
|
793
|
+
import type { Resolver, ReplyOptions, Reply, SequenceEntry } from "./reply.js";
|
|
794
|
+
|
|
795
|
+
/**
|
|
796
|
+
* Determines whether a rule matches an incoming request.
|
|
797
|
+
*
|
|
798
|
+
* A `string` does a case-insensitive substring match on the last user message.
|
|
799
|
+
* A `RegExp` gets tested against the last user message.
|
|
800
|
+
* A `MatchObject` checks multiple fields at once with AND logic.
|
|
801
|
+
* A function receives the normalised request and returns a boolean.
|
|
802
|
+
*/
|
|
803
|
+
export type Match =
|
|
804
|
+
| string
|
|
805
|
+
| RegExp
|
|
806
|
+
| MatchObject
|
|
807
|
+
| ((req: MockRequest) => boolean);
|
|
808
|
+
|
|
809
|
+
/** A structured matcher. Every field you set must match for the rule to fire. */
|
|
810
|
+
export interface MatchObject {
|
|
811
|
+
readonly message?: string | RegExp;
|
|
812
|
+
|
|
813
|
+
thinking
|
|
814
|
+
**Checking type exports and logger usage**
|
|
815
|
+
exec
|
|
816
|
+
/bin/zsh -lc "sed -n '1,220p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/logger.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
817
|
+
import pc from "picocolors";
|
|
818
|
+
|
|
819
|
+
export const LEVEL_PRIORITY = {
|
|
820
|
+
none: 0,
|
|
821
|
+
error: 1,
|
|
822
|
+
warning: 2,
|
|
823
|
+
info: 3,
|
|
824
|
+
debug: 4,
|
|
825
|
+
all: 5,
|
|
826
|
+
} as const satisfies Record<string, number>;
|
|
827
|
+
|
|
828
|
+
/** Log verbosity, from `"none"` (silent) through to `"all"` (everything). */
|
|
829
|
+
export type LogLevel = keyof typeof LEVEL_PRIORITY;
|
|
830
|
+
|
|
831
|
+
const LEVEL_STYLE = {
|
|
832
|
+
error: { label: pc.red(pc.bold("ERROR")), symbol: pc.red("✗") },
|
|
833
|
+
warn: { label: pc.yellow(pc.bold("WARN")), symbol: pc.yellow("!") },
|
|
834
|
+
info: { label: pc.cyan("INFO"), symbol: pc.cyan("●") },
|
|
835
|
+
debug: { label: pc.dim("DEBUG"), symbol: pc.dim("·") },
|
|
836
|
+
} as const;
|
|
837
|
+
|
|
838
|
+
thinking
|
|
839
|
+
**Considering CLI start function design**
|
|
840
|
+
|
|
841
|
+
I'm evaluating structuring the CLI start function to handle parsing, output formatting, watching, and signaling in separate helper functions for better coherence. Noting that mock-server's when() uses replySequence with transform, but this seems acceptable for now.
|
|
842
|
+
exec
|
|
843
|
+
/bin/zsh -lc "sed -n '1,200p' /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server/src/formats/openai/index.ts" in /Users/suyash.x.srijan/Documents/Personal_Projects/llm-mock-server succeeded in 0ms:
|
|
844
|
+
import type { Format } from "../types.js";
|
|
845
|
+
import { isStreaming } from "../request-helpers.js";
|
|
846
|
+
import { parseRequest } from "./parse.js";
|
|
847
|
+
import { serialize, serializeComplete, serializeError } from "./serialize.js";
|
|
848
|
+
|
|
849
|
+
export const openaiFormat: Format = {
|
|
850
|
+
name: "openai",
|
|
851
|
+
route: "/v1/chat/completions",
|
|
852
|
+
parseRequest,
|
|
853
|
+
isStreaming,
|
|
854
|
+
serialize,
|
|
855
|
+
serializeComplete,
|
|
856
|
+
serializeError,
|
|
857
|
+
};
|
|
858
|
+
|
|
859
|
+
|
|
860
|
+
thinking
|
|
861
|
+
**Identifying design coherence and duplication candidates**
|
|
862
|
+
|
|
863
|
+
The main design coherence issue is functions handling multiple responsibilities, like CLI start and loadRulesFromPath, though they may not be the best targets. Notable duplication appears in serialize logic across modules with similar patterns that could be more data-driven, but clearer evidence is needed to produce solid findings.
|
|
864
|
+
thinking
|
|
865
|
+
**Reporting design coherence findings**
|
|
866
|
+
|
|
867
|
+
Identified two moderate design coherence issues: duplicated sequence rule normalization logic in mock-server and loader modules suggesting a shared helper extraction, and the MockServer class combining server lifecycle, API for rule management, and state handling into a multi-responsibility class suggesting refactoring into separate components. Both findings include related files and actionable suggestions.
|
|
868
|
+
codex
|
|
869
|
+
{
|
|
870
|
+
"batch": "Cross-cutting Sweep",
|
|
871
|
+
"batch_index": 9,
|
|
872
|
+
"assessments": {
|
|
873
|
+
"design_coherence": 82.0
|
|
874
|
+
},
|
|
875
|
+
"dimension_notes": {
|
|
876
|
+
"design_coherence": {
|
|
877
|
+
"evidence": [
|
|
878
|
+
"Sequence rule construction is implemented in two places with similar step-mapping and resolver wiring (`MockServer.when().replySequence()` in src/mock-server.ts and `addSequenceRule()` in src/loader.ts).",
|
|
879
|
+
"The `MockServer` class mixes HTTP server lifecycle (Fastify setup/start/stop), rule authoring APIs, fallback management, and request history/logging state in one surface (src/mock-server.ts)."
|
|
880
|
+
],
|
|
881
|
+
"impact_scope": "subsystem",
|
|
882
|
+
"fix_scope": "multi_file_refactor",
|
|
883
|
+
"confidence": "medium"
|
|
884
|
+
}
|
|
885
|
+
},
|
|
886
|
+
"findings": [
|
|
887
|
+
{
|
|
888
|
+
"dimension": "design_coherence",
|
|
889
|
+
"identifier": "sequence_rule_duplication",
|
|
890
|
+
"summary": "Sequence rule normalization is duplicated in server API and loader paths",
|
|
891
|
+
"related_files": [
|
|
892
|
+
"src/mock-server.ts",
|
|
893
|
+
"src/loader.ts",
|
|
894
|
+
"src/rule-engine.ts"
|
|
895
|
+
],
|
|
896
|
+
"evidence": [
|
|
897
|
+
"`MockServer.when().replySequence()` maps `SequenceEntry` values into steps, creates a sequence resolver, assigns `rule.resolve`, and sets `rule.remaining`.",
|
|
898
|
+
"`addSequenceRule()` in `src/loader.ts` performs the same step normalization, `createSequenceResolver()` call, and `rule.remaining` setup for JSON5 rules."
|
|
899
|
+
],
|
|
900
|
+
"suggestion": "Extract a shared helper in `src/rule-engine.ts` (or a new `sequence` utility) that accepts normalized entries and returns a configured rule; use it from both `replySequence()` and `addSequenceRule()` to centralize sequence behavior.",
|
|
901
|
+
"confidence": "medium",
|
|
902
|
+
"impact_scope": "module",
|
|
903
|
+
"fix_scope": "multi_file_refactor"
|
|
904
|
+
},
|
|
905
|
+
{
|
|
906
|
+
"dimension": "design_coherence",
|
|
907
|
+
"identifier": "mockserver_multi_role",
|
|
908
|
+
"summary": "`MockServer` combines server lifecycle, rule authoring, and state tracking responsibilities",
|
|
909
|
+
"related_files": [
|
|
910
|
+
"src/mock-server.ts",
|
|
911
|
+
"src/rule-engine.ts",
|
|
912
|
+
"src/history.ts"
|
|
913
|
+
],
|
|
914
|
+
"evidence": [
|
|
915
|
+
"`MockServer` constructs the Fastify server and registers format routes in the constructor, exposes rule authoring methods (`when`, `whenTool`, `nextError`), manages fallback state, and owns `RequestHistory` and logging.",
|
|
916
|
+
"This blends HTTP runtime concerns with rule registry and history concerns that already exist as separate modules (`RuleEngine`, `RequestHistory`)."
|
|
917
|
+
],
|
|
918
|
+
"suggestion": "Split `MockServer` into a runtime/server wrapper and a rule/history registry (e.g., extract a `RuleRegistry` or `MockServerCore` that exposes `when*`, `history`, `rules`, and fallback), and keep Fastify lifecycle and route wiring in a thinner server class.",
|
|
919
|
+
"confidence": "medium",
|
|
920
|
+
"impact_scope": "subsystem",
|
|
921
|
+
"fix_scope": "architectural_change"
|
|
922
|
+
}
|
|
923
|
+
],
|
|
924
|
+
"retrospective": {
|
|
925
|
+
"root_causes": [
|
|
926
|
+
"Sequence rule behavior is implemented in parallel call paths without a shared abstraction.",
|
|
927
|
+
"Top-level API class aggregates multiple subsystems to present a convenient surface, but lacks internal separation."
|
|
928
|
+
],
|
|
929
|
+
"likely_symptoms": [
|
|
930
|
+
"sequence_rule_duplication",
|
|
931
|
+
"mockserver_multi_role"
|
|
932
|
+
],
|
|
933
|
+
"possible_false_positives": []
|
|
934
|
+
}
|
|
935
|
+
}
|
|
936
|
+
tokens used
|
|
937
|
+
39,039
|
|
938
|
+
|