@aexol/spectral 0.9.10 → 0.9.13
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/dist/memory/hooks/compaction-hook.d.ts.map +1 -1
- package/dist/memory/hooks/compaction-hook.js +69 -3
- package/dist/memory/observer.d.ts +2 -1
- package/dist/memory/observer.d.ts.map +1 -1
- package/dist/memory/observer.js +2 -1
- package/dist/memory/testing/index.d.ts +12 -0
- package/dist/memory/testing/index.d.ts.map +1 -0
- package/dist/memory/testing/index.js +11 -0
- package/dist/memory/testing/populate.d.ts +93 -0
- package/dist/memory/testing/populate.d.ts.map +1 -0
- package/dist/memory/testing/populate.js +177 -0
- package/dist/memory/testing/random-model.d.ts +75 -0
- package/dist/memory/testing/random-model.d.ts.map +1 -0
- package/dist/memory/testing/random-model.js +237 -0
- package/dist/memory/testing/random-text.d.ts +27 -0
- package/dist/memory/testing/random-text.d.ts.map +1 -0
- package/dist/memory/testing/random-text.js +216 -0
- package/dist/memory/testing/seeded-random.d.ts +26 -0
- package/dist/memory/testing/seeded-random.d.ts.map +1 -0
- package/dist/memory/testing/seeded-random.js +57 -0
- package/dist/relay/dispatcher.d.ts.map +1 -1
- package/dist/relay/dispatcher.js +2 -0
- package/dist/sdk/agent-core/harness/types.d.ts +2 -0
- package/dist/sdk/agent-core/harness/types.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/agent-session.d.ts +4 -0
- package/dist/sdk/coding-agent/core/agent-session.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/agent-session.js +74 -1
- package/dist/sdk/coding-agent/core/extensions/types.d.ts +6 -0
- package/dist/sdk/coding-agent/core/extensions/types.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/system-prompt.d.ts.map +1 -1
- package/dist/sdk/coding-agent/core/system-prompt.js +1 -0
- package/dist/server/agent-bridge.d.ts +0 -1
- package/dist/server/agent-bridge.d.ts.map +1 -1
- package/dist/server/agent-bridge.js +13 -8
- package/dist/server/session-stream.d.ts +2 -0
- package/dist/server/session-stream.d.ts.map +1 -1
- package/dist/server/session-stream.js +6 -0
- package/dist/server/wire.d.ts +15 -0
- package/dist/server/wire.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Random testing model built on the faux provider.
|
|
3
|
+
*
|
|
4
|
+
* Generates deterministic, structured LLM-like responses that exercise the
|
|
5
|
+
* full observational memory pipeline (observer → reflector → pruner → compaction)
|
|
6
|
+
* without real LLM API calls.
|
|
7
|
+
*
|
|
8
|
+
* The model inspects the tool definitions in the context to decide what kind
|
|
9
|
+
* of response to generate:
|
|
10
|
+
* - `record_observations` → generates observation batches with source entry IDs
|
|
11
|
+
* - `record_reflections` → generates reflection proposals with supporting IDs
|
|
12
|
+
* - `drop_observations` → generates drop-lists with observation IDs
|
|
13
|
+
* - No tool / unknown → generates plain text
|
|
14
|
+
*/
|
|
15
|
+
import { fauxAssistantMessage, fauxText, fauxThinking, fauxToolCall, registerFauxProvider, } from "../../sdk/ai/providers/faux.js";
|
|
16
|
+
import { SeededRandom } from "./seeded-random.js";
|
|
17
|
+
import { generateRandomText, generateObservationContent, generateReflectionContent, generateTimestamp, } from "./random-text.js";
|
|
18
|
+
/**
|
|
19
|
+
* Pick `count` random IDs from `availableIds`. If fewer available than count,
|
|
20
|
+
* returns all available.
|
|
21
|
+
*/
|
|
22
|
+
function pickRandomIds(rng, availableIds, count) {
|
|
23
|
+
if (availableIds.length === 0)
|
|
24
|
+
return [];
|
|
25
|
+
const pool = [...availableIds];
|
|
26
|
+
rng.shuffle(pool);
|
|
27
|
+
return pool.slice(0, Math.min(count, pool.length));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Extract observation IDs from the context messages.
|
|
31
|
+
* Looks for source entry IDs in user messages or observation lists.
|
|
32
|
+
*/
|
|
33
|
+
function extractObservationIds(context) {
|
|
34
|
+
const ids = new Set();
|
|
35
|
+
for (const msg of context.messages) {
|
|
36
|
+
const text = typeof msg.content === "string"
|
|
37
|
+
? msg.content
|
|
38
|
+
: Array.isArray(msg.content)
|
|
39
|
+
? msg.content
|
|
40
|
+
.filter((b) => b.type === "text")
|
|
41
|
+
.map((b) => b.text)
|
|
42
|
+
.join("\n")
|
|
43
|
+
: "";
|
|
44
|
+
// Match 12-char hex IDs from observation lists or source entry labels
|
|
45
|
+
const matches = text.matchAll(/\b([a-f0-9]{12})\b/g);
|
|
46
|
+
for (const m of matches)
|
|
47
|
+
ids.add(m[1]);
|
|
48
|
+
}
|
|
49
|
+
return Array.from(ids);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Extract available source entry IDs from the user prompt.
|
|
53
|
+
*/
|
|
54
|
+
function extractSourceEntryIds(context) {
|
|
55
|
+
const ids = new Set();
|
|
56
|
+
for (const msg of context.messages) {
|
|
57
|
+
if (msg.role !== "user")
|
|
58
|
+
continue;
|
|
59
|
+
const text = typeof msg.content === "string"
|
|
60
|
+
? msg.content
|
|
61
|
+
: Array.isArray(msg.content)
|
|
62
|
+
? msg.content.filter((b) => b.type === "text").map((b) => b.text).join("\n")
|
|
63
|
+
: "";
|
|
64
|
+
// Match "[Source entry id: <id>]" — the id can contain any chars except brackets
|
|
65
|
+
const matches = text.matchAll(/\[?Source entry id:\s*([^\]]+)\]?/gi);
|
|
66
|
+
for (const m of matches) {
|
|
67
|
+
const id = m[1].trim();
|
|
68
|
+
if (id)
|
|
69
|
+
ids.add(id);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return Array.from(ids);
|
|
73
|
+
}
|
|
74
|
+
function hasToolNamed(context, name) {
|
|
75
|
+
return context.tools?.some((t) => t.name === name) ?? false;
|
|
76
|
+
}
|
|
77
|
+
// ── Response factories per tool set ───────────────────────────────────────────
|
|
78
|
+
/**
|
|
79
|
+
* Generate observer-like responses: one or more `record_observations` tool calls
|
|
80
|
+
* followed by a short confirmation text.
|
|
81
|
+
*/
|
|
82
|
+
function createObserverResponse(ctx, _options, state, model, factoryState) {
|
|
83
|
+
const { rng, config } = factoryState;
|
|
84
|
+
const sourceIds = extractSourceEntryIds(ctx);
|
|
85
|
+
const batches = rng.nextInt(config.observationBatches.min, config.observationBatches.max);
|
|
86
|
+
// If we have no source IDs, generate some synthetic ones
|
|
87
|
+
if (sourceIds.length === 0) {
|
|
88
|
+
for (let i = 0; i < 10; i++)
|
|
89
|
+
sourceIds.push(rng.hexId(12));
|
|
90
|
+
}
|
|
91
|
+
const content = [];
|
|
92
|
+
for (let b = 0; b < batches; b++) {
|
|
93
|
+
const obsCount = rng.nextInt(config.observationsPerBatch.min, config.observationsPerBatch.max);
|
|
94
|
+
const observations = Array.from({ length: obsCount }, () => ({
|
|
95
|
+
timestamp: generateTimestamp(rng),
|
|
96
|
+
content: generateObservationContent(rng),
|
|
97
|
+
relevance: rng.pick(["low", "medium", "high", "critical"]),
|
|
98
|
+
sourceEntryIds: pickRandomIds(rng, sourceIds, rng.nextInt(1, Math.min(3, sourceIds.length))),
|
|
99
|
+
}));
|
|
100
|
+
content.push(fauxToolCall("record_observations", { observations: observations.length > 0 ? observations : [] }, { id: rng.hexId(8) }));
|
|
101
|
+
}
|
|
102
|
+
// Final confirmation text
|
|
103
|
+
content.push(fauxText(generateRandomText(rng, { targetChars: Math.min(config.textTargetChars, 200), includeCode: false, includeMarkdown: false })));
|
|
104
|
+
return fauxAssistantMessage(content, { stopReason: "stop" });
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Generate reflector-like responses: one or more `record_reflections` tool calls
|
|
108
|
+
* followed by a short confirmation.
|
|
109
|
+
*/
|
|
110
|
+
function createReflectorResponse(ctx, _options, state, model, factoryState) {
|
|
111
|
+
const { rng, config } = factoryState;
|
|
112
|
+
const observationIds = extractObservationIds(ctx);
|
|
113
|
+
const batches = rng.nextInt(config.reflectionBatches.min, config.reflectionBatches.max);
|
|
114
|
+
if (observationIds.length === 0) {
|
|
115
|
+
for (let i = 0; i < 10; i++)
|
|
116
|
+
observationIds.push(rng.hexId(12));
|
|
117
|
+
}
|
|
118
|
+
const content = [];
|
|
119
|
+
for (let b = 0; b < batches; b++) {
|
|
120
|
+
const refCount = rng.nextInt(config.reflectionsPerBatch.min, config.reflectionsPerBatch.max);
|
|
121
|
+
const reflections = Array.from({ length: refCount }, () => ({
|
|
122
|
+
content: generateReflectionContent(rng),
|
|
123
|
+
supportingObservationIds: pickRandomIds(rng, observationIds, rng.nextInt(1, Math.min(3, observationIds.length))),
|
|
124
|
+
}));
|
|
125
|
+
content.push(fauxToolCall("record_reflections", { reflections: reflections.length > 0 ? reflections : [] }, { id: rng.hexId(8) }));
|
|
126
|
+
}
|
|
127
|
+
content.push(fauxText("Reflection pass complete. All stable patterns crystallized."));
|
|
128
|
+
return fauxAssistantMessage(content, { stopReason: "stop" });
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Generate pruner-like responses: one or more `drop_observations` tool calls
|
|
132
|
+
* followed by a short confirmation.
|
|
133
|
+
*/
|
|
134
|
+
function createPrunerResponse(ctx, _options, state, model, factoryState) {
|
|
135
|
+
const { rng, config } = factoryState;
|
|
136
|
+
const observationIds = extractObservationIds(ctx);
|
|
137
|
+
const calls = rng.nextInt(config.prunerDropCalls.min, config.prunerDropCalls.max);
|
|
138
|
+
if (observationIds.length === 0) {
|
|
139
|
+
for (let i = 0; i < 10; i++)
|
|
140
|
+
observationIds.push(rng.hexId(12));
|
|
141
|
+
}
|
|
142
|
+
const content = [];
|
|
143
|
+
// Only make drop calls if we have enough IDs
|
|
144
|
+
if (observationIds.length > 3) {
|
|
145
|
+
const remaining = [...observationIds];
|
|
146
|
+
for (let c = 0; c < calls && remaining.length > 0; c++) {
|
|
147
|
+
const dropCount = Math.min(rng.nextInt(config.prunerIdsPerCall.min, config.prunerIdsPerCall.max), remaining.length);
|
|
148
|
+
const dropIds = pickRandomIds(rng, remaining, dropCount);
|
|
149
|
+
// Remove dropped IDs from remaining pool
|
|
150
|
+
for (const id of dropIds) {
|
|
151
|
+
const idx = remaining.indexOf(id);
|
|
152
|
+
if (idx >= 0)
|
|
153
|
+
remaining.splice(idx, 1);
|
|
154
|
+
}
|
|
155
|
+
content.push(fauxToolCall("drop_observations", { ids: dropIds, reason: "Redundant or low-relevance observation" }, { id: rng.hexId(8) }));
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
content.push(fauxText("Pruning complete. Kept observations are within budget."));
|
|
159
|
+
return fauxAssistantMessage(content, { stopReason: "stop" });
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Generate a generic assistant response (no tool calls).
|
|
163
|
+
*/
|
|
164
|
+
function createGenericResponse(ctx, _options, state, model, factoryState) {
|
|
165
|
+
const { rng, config } = factoryState;
|
|
166
|
+
const text = generateRandomText(rng, { targetChars: config.textTargetChars });
|
|
167
|
+
// Occasionally add thinking blocks
|
|
168
|
+
if (rng.chance(0.3)) {
|
|
169
|
+
const thinkingText = generateRandomText(rng, { targetChars: Math.min(config.textTargetChars / 2, 300), includeCode: false, includeMarkdown: false });
|
|
170
|
+
return fauxAssistantMessage([fauxThinking(thinkingText), fauxText(text)], { stopReason: "stop" });
|
|
171
|
+
}
|
|
172
|
+
return fauxAssistantMessage(text, { stopReason: "stop" });
|
|
173
|
+
}
|
|
174
|
+
// ── Public API ────────────────────────────────────────────────────────────────
|
|
175
|
+
const DEFAULT_CONFIG = {
|
|
176
|
+
seed: 42,
|
|
177
|
+
textTargetChars: 500,
|
|
178
|
+
observationBatches: { min: 2, max: 4 },
|
|
179
|
+
observationsPerBatch: { min: 2, max: 5 },
|
|
180
|
+
reflectionBatches: { min: 1, max: 3 },
|
|
181
|
+
reflectionsPerBatch: { min: 1, max: 3 },
|
|
182
|
+
prunerDropCalls: { min: 1, max: 3 },
|
|
183
|
+
prunerIdsPerCall: { min: 1, max: 5 },
|
|
184
|
+
tokensPerSecond: 0,
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* Register a deterministic random model as a faux provider.
|
|
188
|
+
*
|
|
189
|
+
* The model automatically detects which tools are in the context and generates
|
|
190
|
+
* appropriate structured responses for the observer, reflector, and pruner.
|
|
191
|
+
*
|
|
192
|
+
* @example
|
|
193
|
+
* ```typescript
|
|
194
|
+
* const testModel = createRandomModel({ seed: 123 });
|
|
195
|
+
* // Use testModel.provider.getModel() in agentLoop calls
|
|
196
|
+
* // After testing: testModel.provider.unregister()
|
|
197
|
+
* ```
|
|
198
|
+
*/
|
|
199
|
+
export function createRandomModel(config = {}) {
|
|
200
|
+
const merged = { ...DEFAULT_CONFIG, ...config };
|
|
201
|
+
const rng = new SeededRandom(merged.seed);
|
|
202
|
+
const factoryState = { rng, callCount: 0, config: merged };
|
|
203
|
+
const responseFactory = (ctx, opts, state, model) => {
|
|
204
|
+
factoryState.callCount = state.callCount;
|
|
205
|
+
// Detect tool set from context
|
|
206
|
+
const isObserver = hasToolNamed(ctx, "record_observations") && !hasToolNamed(ctx, "record_reflections") && !hasToolNamed(ctx, "drop_observations");
|
|
207
|
+
const isReflector = hasToolNamed(ctx, "record_reflections");
|
|
208
|
+
const isPruner = hasToolNamed(ctx, "drop_observations");
|
|
209
|
+
if (isPruner) {
|
|
210
|
+
return createPrunerResponse(ctx, opts, state, model, factoryState);
|
|
211
|
+
}
|
|
212
|
+
if (isReflector) {
|
|
213
|
+
return createReflectorResponse(ctx, opts, state, model, factoryState);
|
|
214
|
+
}
|
|
215
|
+
if (isObserver) {
|
|
216
|
+
return createObserverResponse(ctx, opts, state, model, factoryState);
|
|
217
|
+
}
|
|
218
|
+
return createGenericResponse(ctx, opts, state, model, factoryState);
|
|
219
|
+
};
|
|
220
|
+
const provider = registerFauxProvider({
|
|
221
|
+
api: "random-test",
|
|
222
|
+
provider: "random-test",
|
|
223
|
+
models: [
|
|
224
|
+
{
|
|
225
|
+
id: "random-test-1",
|
|
226
|
+
name: "Random Test Model",
|
|
227
|
+
reasoning: false,
|
|
228
|
+
input: ["text"],
|
|
229
|
+
contextWindow: 128000,
|
|
230
|
+
maxTokens: 16384,
|
|
231
|
+
},
|
|
232
|
+
],
|
|
233
|
+
tokensPerSecond: merged.tokensPerSecond,
|
|
234
|
+
});
|
|
235
|
+
provider.setResponses([responseFactory]);
|
|
236
|
+
return { provider, config: merged, rng };
|
|
237
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { SeededRandom } from "./seeded-random.js";
|
|
2
|
+
export interface RandomTextOptions {
|
|
3
|
+
/** Approximate target in characters (4 chars ≈ 1 token). Default: 1000. */
|
|
4
|
+
targetChars?: number;
|
|
5
|
+
/** Include code blocks. Default: true. */
|
|
6
|
+
includeCode?: boolean;
|
|
7
|
+
/** Include markdown formatting. Default: true. */
|
|
8
|
+
includeMarkdown?: boolean;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Generate realistic-looking coding conversation text of approximately
|
|
12
|
+
* `targetChars` length using a seeded PRNG.
|
|
13
|
+
*/
|
|
14
|
+
export declare function generateRandomText(rng: SeededRandom, options?: RandomTextOptions): string;
|
|
15
|
+
/**
|
|
16
|
+
* Generate a short observation-like sentence (single line, plain prose).
|
|
17
|
+
*/
|
|
18
|
+
export declare function generateObservationContent(rng: SeededRandom): string;
|
|
19
|
+
/**
|
|
20
|
+
* Generate a short reflection-like sentence (single line, plain prose, no markdown).
|
|
21
|
+
*/
|
|
22
|
+
export declare function generateReflectionContent(rng: SeededRandom): string;
|
|
23
|
+
/**
|
|
24
|
+
* Generate a random timestamp in "YYYY-MM-DD HH:MM" format within the last 30 days.
|
|
25
|
+
*/
|
|
26
|
+
export declare function generateTimestamp(rng: SeededRandom): string;
|
|
27
|
+
//# sourceMappingURL=random-text.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"random-text.d.ts","sourceRoot":"","sources":["../../../src/memory/testing/random-text.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAiKlD,MAAM,WAAW,iBAAiB;IACjC,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,kDAAkD;IAClD,eAAe,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,YAAY,EAAE,OAAO,GAAE,iBAAsB,GAAG,MAAM,CAsC7F;AAED;;GAEG;AACH,wBAAgB,0BAA0B,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAWpE;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CASnE;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,YAAY,GAAG,MAAM,CAU3D"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
// ── Vocabulary pools ──────────────────────────────────────────────────────────
|
|
2
|
+
const ADJECTIVES = [
|
|
3
|
+
"scalable", "robust", "efficient", "optimized", "modular", "reactive",
|
|
4
|
+
"asynchronous", "declarative", "immutable", "lazy", "composable", "resilient",
|
|
5
|
+
"distributed", "event-driven", "type-safe", "concurrent", "atomic", "idempotent",
|
|
6
|
+
"deterministic", "pluggable", "extensible", "portable", "minimal", "pragmatic",
|
|
7
|
+
];
|
|
8
|
+
const VERBS = [
|
|
9
|
+
"implement", "refactor", "optimize", "extract", "introduce", "migrate",
|
|
10
|
+
"configure", "integrate", "expose", "consume", "validate", "serialize",
|
|
11
|
+
"normalize", "delegate", "compose", "resolve", "intercept", "propagate",
|
|
12
|
+
"coalesce", "deduplicate", "authorize", "authenticate", "transform", "stream",
|
|
13
|
+
];
|
|
14
|
+
const NOUNS = [
|
|
15
|
+
"handler", "middleware", "resolver", "provider", "adapter", "factory",
|
|
16
|
+
"registry", "pipeline", "orchestrator", "dispatcher", "serializer", "validator",
|
|
17
|
+
"cache layer", "event bus", "message queue", "connection pool", "rate limiter",
|
|
18
|
+
"circuit breaker", "feature flag", "policy engine", "auth gateway", "data mapper",
|
|
19
|
+
"task scheduler", "log aggregator",
|
|
20
|
+
];
|
|
21
|
+
const FILE_NAMES = [
|
|
22
|
+
"auth-service.ts", "database-client.ts", "api-gateway.ts", "event-handler.ts",
|
|
23
|
+
"cache-manager.ts", "config-loader.ts", "schema-validator.ts", "rate-limiter.ts",
|
|
24
|
+
"task-queue.ts", "websocket-manager.ts", "session-store.ts", "token-refresher.ts",
|
|
25
|
+
"metrics-collector.ts", "feature-flags.ts", "logging-middleware.ts",
|
|
26
|
+
"error-boundary.tsx", "use-auth.ts", "data-table.tsx", "form-validator.ts",
|
|
27
|
+
"app-router.ts", "query-builder.ts", "connection-pool.ts", "migration-runner.ts",
|
|
28
|
+
];
|
|
29
|
+
const FILE_PATHS = [
|
|
30
|
+
"src/services", "src/middleware", "src/handlers", "src/utils",
|
|
31
|
+
"packages/core/src", "packages/shared/src", "lib/infrastructure",
|
|
32
|
+
"app/api", "app/components", "app/hooks", "src/integrations",
|
|
33
|
+
"src/database/migrations", "src/queue", "src/cache",
|
|
34
|
+
];
|
|
35
|
+
const TECH_TERMS = [
|
|
36
|
+
"TypeScript", "GraphQL", "Prisma", "PostgreSQL", "Redis",
|
|
37
|
+
"Next.js", "React", "Node.js", "Deno", "WebSocket",
|
|
38
|
+
"REST", "gRPC", "Protobuf", "JWT", "OAuth2",
|
|
39
|
+
"Kubernetes", "Docker", "Terraform", "Prometheus", "Grafana",
|
|
40
|
+
"Kafka", "RabbitMQ", "S3", "CDN", "Edge Functions",
|
|
41
|
+
];
|
|
42
|
+
const ERROR_MESSAGES = [
|
|
43
|
+
"Cannot read properties of undefined",
|
|
44
|
+
"Connection refused",
|
|
45
|
+
"Request timeout after 30s",
|
|
46
|
+
"Unauthorized: invalid token",
|
|
47
|
+
"Rate limit exceeded",
|
|
48
|
+
"Database deadlock detected",
|
|
49
|
+
"Circuit breaker open",
|
|
50
|
+
"Cache miss on hot key",
|
|
51
|
+
"Schema validation failed",
|
|
52
|
+
"Out of memory",
|
|
53
|
+
];
|
|
54
|
+
const PUNCTUATION = [".", ".", ".", "!", "?"];
|
|
55
|
+
// ── Code snippet generation ───────────────────────────────────────────────────
|
|
56
|
+
function generateFunction(rng) {
|
|
57
|
+
const name = rng.pick(["handle", "process", "transform", "resolve", "validate", "execute", "create", "update", "delete", "fetch"])
|
|
58
|
+
+ rng.pick(NOUNS).replace(/ /g, "").replace(/-/g, "");
|
|
59
|
+
const paramCount = rng.nextInt(1, 3);
|
|
60
|
+
const params = rng.pickN(["input", "context", "options", "config", "payload", "request", "id", "key"], paramCount)
|
|
61
|
+
.map((p, i) => `${p}: ${rng.pick(["string", "number", "Record<string, unknown>", "Promise<void>"])}`)
|
|
62
|
+
.join(", ");
|
|
63
|
+
const returnType = rng.chance(0.6) ? `: ${rng.pick(["Promise<void>", "string", "boolean", "Result", "void"])}` : "";
|
|
64
|
+
const bodyLines = rng.nextInt(2, 5);
|
|
65
|
+
const body = Array.from({ length: bodyLines }, () => {
|
|
66
|
+
const pattern = rng.nextInt(0, 3);
|
|
67
|
+
if (pattern === 0)
|
|
68
|
+
return ` const ${rng.pick(["result", "data", "entry", "value", "key"])} = await ${rng.pick(["fetch", "read", "query", "resolve", "validate"])}(${rng.pick(["input", "config", "options", "context"])});`;
|
|
69
|
+
if (pattern === 1)
|
|
70
|
+
return ` if (!${rng.pick(["result", "data", "input", "config"])}) throw new Error("${rng.pick(ERROR_MESSAGES)}");`;
|
|
71
|
+
return ` return ${rng.pick(["result", "data", "{ ...input, processed: true }", "undefined", "null"])};`;
|
|
72
|
+
}).join("\n");
|
|
73
|
+
return `async function ${name}(${params})${returnType} {\n${body}\n}`;
|
|
74
|
+
}
|
|
75
|
+
function generateInterface(rng) {
|
|
76
|
+
const name = "I" + rng.pick(["Config", "Options", "Context", "Result", "Payload", "State", "Props"]);
|
|
77
|
+
const fieldCount = rng.nextInt(2, 5);
|
|
78
|
+
const fields = Array.from({ length: fieldCount }, () => {
|
|
79
|
+
const fieldName = rng.pick(["id", "name", "type", "value", "config", "options", "enabled", "timeout", "url", "key"]);
|
|
80
|
+
const fieldType = rng.pick(["string", "number", "boolean", "Record<string, unknown>", "string[]", "Partial<Config>"]);
|
|
81
|
+
const optional = rng.chance(0.4) ? "?" : "";
|
|
82
|
+
return ` ${fieldName}${optional}: ${fieldType};`;
|
|
83
|
+
}).join("\n");
|
|
84
|
+
return `interface ${name} {\n${fields}\n}`;
|
|
85
|
+
}
|
|
86
|
+
function generateImportBlock(rng) {
|
|
87
|
+
const count = rng.nextInt(1, 4);
|
|
88
|
+
return Array.from({ length: count }, () => {
|
|
89
|
+
const module = rng.pick(FILE_PATHS) + "/" + rng.pick(FILE_NAMES).replace(".ts", "");
|
|
90
|
+
const imports = rng.pickN(["parse", "validate", "createClient", "configure", "resolve", "serialize", "normalize", "buildContext"], rng.nextInt(1, 3));
|
|
91
|
+
return `import { ${imports.join(", ")} } from "${module}";`;
|
|
92
|
+
}).join("\n");
|
|
93
|
+
}
|
|
94
|
+
// ── Prose generation ──────────────────────────────────────────────────────────
|
|
95
|
+
function generateSentence(rng) {
|
|
96
|
+
const templates = [
|
|
97
|
+
() => `We should ${rng.pick(VERBS)} the ${rng.pick(NOUNS)} to make it more ${rng.pick(ADJECTIVES)}.`,
|
|
98
|
+
() => `The ${rng.pick(NOUNS)} currently ${rng.pick(["lacks", "needs", "requires", "would benefit from"])} a ${rng.pick(ADJECTIVES)} ${rng.pick(["approach", "design", "implementation", "refactor", "strategy"])}.`,
|
|
99
|
+
() => `After reviewing the ${rng.pick(FILE_NAMES)}, I think we need to ${rng.pick(VERBS)} ${rng.pick(["the", "our", "this", "the core"])} ${rng.pick(NOUNS)}.`,
|
|
100
|
+
() => `${rng.pick(TECH_TERMS)} integration with the ${rng.pick(NOUNS)} ${rng.pick(["is", "seems", "looks", "appears"])} ${rng.pick(["straightforward", "tricky", "promising", "problematic", "well-designed"])}.`,
|
|
101
|
+
() => `Consider using ${rng.pick(TECH_TERMS)} for ${rng.pick(["caching", "messaging", "logging", "monitoring", "authentication", "scheduling"])} instead of the current ${rng.pick(["approach", "solution", "implementation", "pattern"])}.`,
|
|
102
|
+
() => `The ${rng.pick(["performance", "reliability", "maintainability", "testability"])} of ${rng.pick(FILE_NAMES)} could be improved by ${rng.pick(["adding", "removing", "refactoring", "extracting", "caching"])} the ${rng.pick(NOUNS)}.`,
|
|
103
|
+
() => `One concern is ${rng.pick(["error handling", "state management", "type safety", "concurrency", "data consistency"])} in the ${rng.pick(NOUNS)} when ${rng.pick(["dealing with", "handling", "processing", "transforming"])} ${rng.pick(["large payloads", "edge cases", "concurrent requests", "nested data", "streaming responses"])}.`,
|
|
104
|
+
];
|
|
105
|
+
return rng.pick(templates)();
|
|
106
|
+
}
|
|
107
|
+
function generateParagraph(rng, sentenceCount = 0) {
|
|
108
|
+
const count = sentenceCount || rng.nextInt(2, 5);
|
|
109
|
+
return Array.from({ length: count }, () => generateSentence(rng)).join(" ");
|
|
110
|
+
}
|
|
111
|
+
function generateMarkdownSection(rng) {
|
|
112
|
+
const headingLevel = rng.nextInt(1, 3);
|
|
113
|
+
const headingText = rng.pick([
|
|
114
|
+
"Architecture Overview",
|
|
115
|
+
"Implementation Details",
|
|
116
|
+
"Error Handling",
|
|
117
|
+
"Performance Considerations",
|
|
118
|
+
"Testing Strategy",
|
|
119
|
+
"Migration Plan",
|
|
120
|
+
"Configuration",
|
|
121
|
+
"API Design",
|
|
122
|
+
"Security Model",
|
|
123
|
+
"Data Flow",
|
|
124
|
+
]);
|
|
125
|
+
const heading = "#".repeat(headingLevel) + " " + headingText;
|
|
126
|
+
const paragraphs = rng.nextInt(1, 3);
|
|
127
|
+
const body = Array.from({ length: paragraphs }, () => generateParagraph(rng)).join("\n\n");
|
|
128
|
+
const includeCode = rng.chance(0.7);
|
|
129
|
+
const codeBlock = includeCode
|
|
130
|
+
? "\n\n```typescript\n" + (rng.chance(0.5) ? generateFunction(rng) : generateInterface(rng)) + "\n```"
|
|
131
|
+
: "";
|
|
132
|
+
const includeList = rng.chance(0.4);
|
|
133
|
+
const listBlock = includeList
|
|
134
|
+
? "\n\n" + Array.from({ length: rng.nextInt(2, 4) }, () => `- ${generateSentence(rng)}`).join("\n")
|
|
135
|
+
: "";
|
|
136
|
+
return heading + "\n\n" + body + codeBlock + listBlock;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Generate realistic-looking coding conversation text of approximately
|
|
140
|
+
* `targetChars` length using a seeded PRNG.
|
|
141
|
+
*/
|
|
142
|
+
export function generateRandomText(rng, options = {}) {
|
|
143
|
+
const targetChars = options.targetChars ?? 1000;
|
|
144
|
+
const includeMarkdown = options.includeMarkdown ?? true;
|
|
145
|
+
const includeCode = options.includeCode ?? true;
|
|
146
|
+
const parts = [];
|
|
147
|
+
// Start with imports if code is included
|
|
148
|
+
if (includeCode && rng.chance(0.6)) {
|
|
149
|
+
parts.push(generateImportBlock(rng));
|
|
150
|
+
}
|
|
151
|
+
// Generate content until we hit the target
|
|
152
|
+
let charCount = parts.join("\n\n").length;
|
|
153
|
+
let iterations = 0;
|
|
154
|
+
const maxIterations = 500;
|
|
155
|
+
while (charCount < targetChars && iterations < maxIterations) {
|
|
156
|
+
iterations++;
|
|
157
|
+
if (includeMarkdown && rng.chance(0.4)) {
|
|
158
|
+
parts.push(generateMarkdownSection(rng));
|
|
159
|
+
}
|
|
160
|
+
else if (includeCode && rng.chance(0.5)) {
|
|
161
|
+
parts.push("```typescript\n" + (rng.chance(0.5) ? generateFunction(rng) : generateInterface(rng)) + "\n```");
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
parts.push(generateParagraph(rng, rng.nextInt(1, 4)));
|
|
165
|
+
}
|
|
166
|
+
charCount = parts.join("\n\n").length;
|
|
167
|
+
}
|
|
168
|
+
// Trim if we overshot
|
|
169
|
+
let result = parts.join("\n\n");
|
|
170
|
+
if (result.length > targetChars * 1.2) {
|
|
171
|
+
result = result.slice(0, targetChars);
|
|
172
|
+
}
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Generate a short observation-like sentence (single line, plain prose).
|
|
177
|
+
*/
|
|
178
|
+
export function generateObservationContent(rng) {
|
|
179
|
+
const templates = [
|
|
180
|
+
() => `The ${rng.pick(NOUNS)} was ${rng.pick(VERBS)}ed using a ${rng.pick(ADJECTIVES)} approach with ${rng.pick(TECH_TERMS)}.`,
|
|
181
|
+
() => `User requested ${rng.pick(VERBS)}ing the ${rng.pick(NOUNS)} to support ${rng.pick(TECH_TERMS)} integration.`,
|
|
182
|
+
() => `Assistant identified ${rng.pick(["a bug", "a performance issue", "a type error", "a race condition", "a memory leak"])} in ${rng.pick(FILE_NAMES)}.`,
|
|
183
|
+
() => `Codebase uses ${rng.pick(TECH_TERMS)} for ${rng.pick(["caching", "state management", "data fetching", "authentication", "logging"])}.`,
|
|
184
|
+
() => `Configuration for ${rng.pick(NOUNS)} is stored in ${rng.pick([".env", "config.ts", "settings.json", "deno.json", "tsconfig.json"])}.`,
|
|
185
|
+
() => `Test suite for ${rng.pick(FILE_NAMES)} covers ${rng.pick(["unit", "integration", "e2e", "snapshot", "performance"])} scenarios.`,
|
|
186
|
+
() => `Migration from ${rng.pick(TECH_TERMS)} to ${rng.pick(TECH_TERMS)} ${rng.pick(["is in progress", "was completed", "is planned", "was discussed"])}.`,
|
|
187
|
+
];
|
|
188
|
+
return rng.pick(templates)();
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Generate a short reflection-like sentence (single line, plain prose, no markdown).
|
|
192
|
+
*/
|
|
193
|
+
export function generateReflectionContent(rng) {
|
|
194
|
+
const templates = [
|
|
195
|
+
() => `The project uses a ${rng.pick(ADJECTIVES)} ${rng.pick(NOUNS)} pattern with ${rng.pick(TECH_TERMS)} for ${rng.pick(["caching", "messaging", "scheduling", "validation", "serialization"])}.`,
|
|
196
|
+
() => `${rng.pick(TECH_TERMS)} is the ${rng.pick(["primary", "secondary", "recommended", "preferred"])} ${rng.pick(["database", "cache", "queue", "storage", "runtime"])} for this ${rng.pick(["project", "service", "module", "pipeline"])}.`,
|
|
197
|
+
() => `All ${rng.pick(["API routes", "database queries", "file operations", "network calls", "user inputs"])} must be ${rng.pick(["validated", "authorized", "sanitized", "logged", "metered"])} before ${rng.pick(["processing", "execution", "storage", "propagation", "transmission"])}.`,
|
|
198
|
+
() => `The ${rng.pick(["frontend", "backend", "CLI", "SDK", "worker"])} communicates with the ${rng.pick(["API", "database", "cache", "queue", "file system"])} via ${rng.pick(["REST", "GraphQL", "gRPC", "WebSocket", "direct connection"])}.`,
|
|
199
|
+
() => `Error handling follows a ${rng.pick(["centralized", "distributed", "layered", "domain-specific", "functional"])} pattern using ${rng.pick(["custom error classes", "result types", "error boundaries", "middleware", "try-catch blocks"])}.`,
|
|
200
|
+
];
|
|
201
|
+
return rng.pick(templates)();
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Generate a random timestamp in "YYYY-MM-DD HH:MM" format within the last 30 days.
|
|
205
|
+
*/
|
|
206
|
+
export function generateTimestamp(rng) {
|
|
207
|
+
const now = Date.now();
|
|
208
|
+
const offset = rng.nextInt(0, 30 * 24 * 60 * 60 * 1000);
|
|
209
|
+
const date = new Date(now - offset);
|
|
210
|
+
const yyyy = date.getFullYear();
|
|
211
|
+
const mm = String(date.getMonth() + 1).padStart(2, "0");
|
|
212
|
+
const dd = String(date.getDate()).padStart(2, "0");
|
|
213
|
+
const hh = String(date.getHours()).padStart(2, "0");
|
|
214
|
+
const min = String(date.getMinutes()).padStart(2, "0");
|
|
215
|
+
return `${yyyy}-${mm}-${dd} ${hh}:${min}`;
|
|
216
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seeded pseudo-random number generator using the mulberry32 algorithm.
|
|
3
|
+
* Produces deterministic sequences for reproducible test runs.
|
|
4
|
+
*/
|
|
5
|
+
export declare class SeededRandom {
|
|
6
|
+
private state;
|
|
7
|
+
constructor(seed: number);
|
|
8
|
+
/** Returns a float in [0, 1). */
|
|
9
|
+
next(): number;
|
|
10
|
+
/** Returns an integer in [min, max] inclusive. */
|
|
11
|
+
nextInt(min: number, max: number): number;
|
|
12
|
+
/** Pick a random element from an array. */
|
|
13
|
+
pick<T>(items: readonly T[]): T;
|
|
14
|
+
/** Pick `count` random elements from an array (with replacement). */
|
|
15
|
+
pickN<T>(items: readonly T[], count: number): T[];
|
|
16
|
+
/** Shuffle array in place (Fisher-Yates). */
|
|
17
|
+
shuffle<T>(items: T[]): T[];
|
|
18
|
+
/** Returns true with probability p (0-1). */
|
|
19
|
+
chance(p: number): boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Generate a hex id of the given length.
|
|
22
|
+
* By default produces 12-char ids matching the MEMORY_ID_PATTERN.
|
|
23
|
+
*/
|
|
24
|
+
hexId(length?: number): string;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=seeded-random.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"seeded-random.d.ts","sourceRoot":"","sources":["../../../src/memory/testing/seeded-random.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,qBAAa,YAAY;IACxB,OAAO,CAAC,KAAK,CAAS;gBAEV,IAAI,EAAE,MAAM;IAIxB,iCAAiC;IACjC,IAAI,IAAI,MAAM;IAQd,kDAAkD;IAClD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM;IAIzC,2CAA2C;IAC3C,IAAI,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,GAAG,CAAC;IAI/B,qEAAqE;IACrE,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,SAAS,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,GAAG,CAAC,EAAE;IAQjD,6CAA6C;IAC7C,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,CAAC,EAAE;IAQ3B,6CAA6C;IAC7C,MAAM,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO;IAI1B;;;OAGG;IACH,KAAK,CAAC,MAAM,SAAK,GAAG,MAAM;CAO1B"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Seeded pseudo-random number generator using the mulberry32 algorithm.
|
|
3
|
+
* Produces deterministic sequences for reproducible test runs.
|
|
4
|
+
*/
|
|
5
|
+
export class SeededRandom {
|
|
6
|
+
state;
|
|
7
|
+
constructor(seed) {
|
|
8
|
+
this.state = seed | 0;
|
|
9
|
+
}
|
|
10
|
+
/** Returns a float in [0, 1). */
|
|
11
|
+
next() {
|
|
12
|
+
this.state |= 0;
|
|
13
|
+
this.state = (this.state + 0x6d2b79f5) | 0;
|
|
14
|
+
let t = Math.imul(this.state ^ (this.state >>> 15), 1 | this.state);
|
|
15
|
+
t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
|
|
16
|
+
return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
|
|
17
|
+
}
|
|
18
|
+
/** Returns an integer in [min, max] inclusive. */
|
|
19
|
+
nextInt(min, max) {
|
|
20
|
+
return Math.floor(this.next() * (max - min + 1)) + min;
|
|
21
|
+
}
|
|
22
|
+
/** Pick a random element from an array. */
|
|
23
|
+
pick(items) {
|
|
24
|
+
return items[this.nextInt(0, items.length - 1)];
|
|
25
|
+
}
|
|
26
|
+
/** Pick `count` random elements from an array (with replacement). */
|
|
27
|
+
pickN(items, count) {
|
|
28
|
+
const result = [];
|
|
29
|
+
for (let i = 0; i < count; i++) {
|
|
30
|
+
result.push(this.pick(items));
|
|
31
|
+
}
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
/** Shuffle array in place (Fisher-Yates). */
|
|
35
|
+
shuffle(items) {
|
|
36
|
+
for (let i = items.length - 1; i > 0; i--) {
|
|
37
|
+
const j = this.nextInt(0, i);
|
|
38
|
+
[items[i], items[j]] = [items[j], items[i]];
|
|
39
|
+
}
|
|
40
|
+
return items;
|
|
41
|
+
}
|
|
42
|
+
/** Returns true with probability p (0-1). */
|
|
43
|
+
chance(p) {
|
|
44
|
+
return this.next() < p;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Generate a hex id of the given length.
|
|
48
|
+
* By default produces 12-char ids matching the MEMORY_ID_PATTERN.
|
|
49
|
+
*/
|
|
50
|
+
hexId(length = 12) {
|
|
51
|
+
let result = "";
|
|
52
|
+
for (let i = 0; i < length; i++) {
|
|
53
|
+
result += "0123456789abcdef"[this.nextInt(0, 15)];
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/relay/dispatcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AAIH,OAAO,KAAK,EACV,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,SAAS,EACT,gBAAgB,EAChB,iBAAiB,EACjB,cAAc,EACf,MAAM,uBAAuB,CAAC;AAI/B,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAgCzD,OAAO,KAAK,EACV,oBAAoB,EACpB,UAAU,EACX,MAAM,6BAA6B,CAAC;AAErC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAO/C;;;GAGG;AACH,UAAU,UAAU;IAClB,KAAK,EACD,eAAe,GACf,gBAAgB,GAChB,gBAAgB,GAChB,gBAAgB,GAChB,aAAa,GACb,uBAAuB,GACvB,gBAAgB,GAChB,aAAa,GACb,gBAAgB,GAChB,gBAAgB,GAChB,oBAAoB,GACpB,4BAA4B,GAC5B,iBAAiB,GACjB,6BAA6B,GAC7B,cAAc,GACd,wBAAwB,GACxB,gBAAgB,GAChB,gBAAgB,GAChB,kBAAkB,GAClB,eAAe,GACf,oBAAoB,GACpB,iBAAiB,GACjB,cAAc,GACd,cAAc,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,gEAAgE;IAChE,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,sEAAsE;IACtE,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,MAAM,GACX,UAAU,GAAG,IAAI,CAuHnB;AAMD;;;;;;;;;GASG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;AAE1D,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,YAAY,CAAC;IACpB,OAAO,EAAE,oBAAoB,CAAC;IAC9B,6FAA6F;IAC7F,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,wEAAwE;IACxE,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE,CAAC;IACjD;;;;OAIG;IACH,QAAQ,CAAC,EAAE,iBAAiB,CAAC;IAC7B;;;;;;;;;OASG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;CACrC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,iBAAiB,CACrC,KAAK,EAAE,gBAAgB,EACvB,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,iBAAiB,CAAC,CAiD5B;AAwSD,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,oBAAoB,CAAC;IAC9B,2DAA2D;IAC3D,KAAK,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;IACjC;;;;;;;;;OASG;IACH,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;IACrC,yEAAyE;IACzE,MAAM,CAAC,EAAE;QAAE,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,IAAI,CAAA;KAAE,CAAC;CAClD;AA8BD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,kBAAkB,EACzB,IAAI,EAAE,iBAAiB,GACtB,IAAI,
|
|
1
|
+
{"version":3,"file":"dispatcher.d.ts","sourceRoot":"","sources":["../../src/relay/dispatcher.ts"],"names":[],"mappings":"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"}
|
package/dist/relay/dispatcher.js
CHANGED
|
@@ -623,6 +623,7 @@ export function handleClientMessage(frame, deps) {
|
|
|
623
623
|
forkCompactPending: attachResult.forkCompactPending || undefined,
|
|
624
624
|
contextWindowUsed: attachResult.contextWindowUsed,
|
|
625
625
|
contextWindowMax: attachResult.contextWindowMax,
|
|
626
|
+
compacting: attachResult.compacting || undefined,
|
|
626
627
|
},
|
|
627
628
|
});
|
|
628
629
|
// Surface bridge-start failures as `error` events; otherwise the
|
|
@@ -697,6 +698,7 @@ export function handleSubscribe(frame, deps) {
|
|
|
697
698
|
forkCompactPending: attachResult.forkCompactPending || undefined,
|
|
698
699
|
contextWindowUsed: attachResult.contextWindowUsed,
|
|
699
700
|
contextWindowMax: attachResult.contextWindowMax,
|
|
701
|
+
compacting: attachResult.compacting || undefined,
|
|
700
702
|
},
|
|
701
703
|
});
|
|
702
704
|
if (isNewSubscriber) {
|
|
@@ -413,6 +413,8 @@ export interface SessionBeforeCompactEvent {
|
|
|
413
413
|
branchEntries: SessionTreeEntry[];
|
|
414
414
|
customInstructions?: string;
|
|
415
415
|
signal: AbortSignal;
|
|
416
|
+
/** Emit live compaction progress to the host UI while custom hooks run. */
|
|
417
|
+
emitProgress?: (delta: string, content?: string) => void;
|
|
416
418
|
}
|
|
417
419
|
export interface SessionCompactEvent {
|
|
418
420
|
type: "session_compact";
|