reasonix 0.0.2 → 0.0.4

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/index.d.ts CHANGED
@@ -82,6 +82,10 @@ interface ChatRequestOptions {
82
82
  maxTokens?: number;
83
83
  stream?: boolean;
84
84
  signal?: AbortSignal;
85
+ /** DeepSeek response_format — use { type: "json_object" } to force valid JSON. */
86
+ responseFormat?: {
87
+ type: "json_object" | "text";
88
+ };
85
89
  }
86
90
 
87
91
  declare class Usage {
@@ -137,20 +141,36 @@ declare class DeepSeekClient {
137
141
  /**
138
142
  * Pillar 2 — R1 Thought Harvesting.
139
143
  *
140
- * v0.0.1 stub. Real implementation lands in v0.2 as a constrained V3 call
141
- * against a strict JSON schema. The shape below is the public contract that
142
- * downstream code may already depend on.
144
+ * Takes the `reasoning_content` emitted by a thinking model (deepseek-reasoner
145
+ * / R1) and extracts a structured plan state by making a cheap secondary call
146
+ * to V3 in JSON mode. The typed state is intended for the orchestrator to
147
+ * branch on — e.g. trigger self-consistency sampling when `uncertainties.length
148
+ * > 2`, or surface the subgoals to the user.
149
+ *
150
+ * Opt-in: loops disable harvesting by default. Failures (bad JSON, API error,
151
+ * empty reasoning) return an empty TypedPlanState — the main turn is never
152
+ * aborted because of a harvest hiccup.
143
153
  */
154
+
144
155
  interface TypedPlanState {
145
156
  subgoals: string[];
146
157
  hypotheses: string[];
147
158
  uncertainties: string[];
148
159
  rejectedPaths: string[];
149
160
  }
161
+ interface HarvestOptions {
162
+ /** Model used for the extraction call. Defaults to the cheap chat model. */
163
+ model?: string;
164
+ /** Cap on how many items land in each array. Default 5. */
165
+ maxItems?: number;
166
+ /** Per-item character cap. Default 80. */
167
+ maxItemLen?: number;
168
+ /** Abort the extraction if R1 reasoning is shorter than this. Default 40. */
169
+ minReasoningLen?: number;
170
+ }
150
171
  declare function emptyPlanState(): TypedPlanState;
151
- declare function isPlanStateEmpty(s: TypedPlanState): boolean;
152
- /** v0.0.1 stub returns empty state. */
153
- declare function harvest(_reasoningContent: string | null): Promise<TypedPlanState>;
172
+ declare function isPlanStateEmpty(s: TypedPlanState | null | undefined): boolean;
173
+ declare function harvest(reasoningContent: string | null | undefined, client?: DeepSeekClient, options?: HarvestOptions): Promise<TypedPlanState>;
154
174
 
155
175
  interface ImmutablePrefixOptions {
156
176
  system: string;
@@ -322,12 +342,24 @@ interface ToolDefinition<A = any, R = any> {
322
342
  parameters?: JSONSchema;
323
343
  fn: (args: A) => R | Promise<R>;
324
344
  }
345
+ interface ToolRegistryOptions {
346
+ /**
347
+ * Auto-flatten schemas that exceed depth/width thresholds before sending
348
+ * them to the model. Re-nests arguments transparently on dispatch.
349
+ * Default: true. Pass false to opt out.
350
+ */
351
+ autoFlatten?: boolean;
352
+ }
325
353
  declare class ToolRegistry {
326
354
  private readonly _tools;
355
+ private readonly _autoFlatten;
356
+ constructor(opts?: ToolRegistryOptions);
327
357
  register<A, R>(def: ToolDefinition<A, R>): this;
328
358
  has(name: string): boolean;
329
359
  get(name: string): ToolDefinition | undefined;
330
360
  get size(): number;
361
+ /** True if a registered tool's schema was flattened for the model. */
362
+ wasFlattened(name: string): boolean;
331
363
  specs(): ToolSpec[];
332
364
  dispatch(name: string, argumentsRaw: string | Record<string, unknown>): Promise<string>;
333
365
  }
@@ -351,6 +383,12 @@ interface CacheFirstLoopOptions {
351
383
  model?: string;
352
384
  maxToolIters?: number;
353
385
  stream?: boolean;
386
+ /**
387
+ * Pillar 2 — structured harvesting of R1 reasoning into a typed plan state.
388
+ * Pass `true` for defaults or an options object. Off by default (adds a
389
+ * cheap but non-zero V3 call per turn).
390
+ */
391
+ harvest?: boolean | HarvestOptions;
354
392
  }
355
393
  /**
356
394
  * Pillar 1 — Cache-First Loop.
@@ -368,6 +406,8 @@ declare class CacheFirstLoop {
368
406
  readonly model: string;
369
407
  readonly maxToolIters: number;
370
408
  readonly stream: boolean;
409
+ readonly harvestEnabled: boolean;
410
+ readonly harvestOptions: HarvestOptions;
371
411
  readonly log: AppendOnlyLog;
372
412
  readonly scratch: VolatileScratch;
373
413
  readonly stats: SessionStats;
@@ -418,4 +458,4 @@ declare function redactKey(key: string): string;
418
458
 
419
459
  declare const VERSION = "0.0.1";
420
460
 
421
- export { AppendOnlyLog, CacheFirstLoop, type CacheFirstLoopOptions, type ChatMessage, type ChatResponse, DeepSeekClient, type DeepSeekClientOptions, type EventRole, type FlattenDecision, ImmutablePrefix, type ImmutablePrefixOptions, type JSONSchema, type LoopEvent, type ReasonixConfig, type RepairReport, type RetryInfo, type RetryOptions, type Role, type ScavengeOptions, type ScavengeResult, SessionStats, type SessionSummary, StormBreaker, type StreamChunk, type ToolCall, ToolCallRepair, type ToolCallRepairOptions, type ToolDefinition, type ToolFunctionSpec, ToolRegistry, type ToolSpec, type TruncationRepairResult, type TurnStats, type TypedPlanState, Usage, VERSION, VolatileScratch, analyzeSchema, claudeEquivalentCost, costUsd, defaultConfigPath, emptyPlanState, fetchWithRetry, flattenSchema, harvest, isPlanStateEmpty, isPlausibleKey, loadApiKey, loadDotenv, nestArguments, readConfig, redactKey, repairTruncatedJson, saveApiKey, scavengeToolCalls, writeConfig };
461
+ export { AppendOnlyLog, CacheFirstLoop, type CacheFirstLoopOptions, type ChatMessage, type ChatResponse, DeepSeekClient, type DeepSeekClientOptions, type EventRole, type FlattenDecision, type HarvestOptions, ImmutablePrefix, type ImmutablePrefixOptions, type JSONSchema, type LoopEvent, type ReasonixConfig, type RepairReport, type RetryInfo, type RetryOptions, type Role, type ScavengeOptions, type ScavengeResult, SessionStats, type SessionSummary, StormBreaker, type StreamChunk, type ToolCall, ToolCallRepair, type ToolCallRepairOptions, type ToolDefinition, type ToolFunctionSpec, ToolRegistry, type ToolSpec, type TruncationRepairResult, type TurnStats, type TypedPlanState, Usage, VERSION, VolatileScratch, analyzeSchema, claudeEquivalentCost, costUsd, defaultConfigPath, emptyPlanState, fetchWithRetry, flattenSchema, harvest, isPlanStateEmpty, isPlausibleKey, loadApiKey, loadDotenv, nestArguments, readConfig, redactKey, repairTruncatedJson, saveApiKey, scavengeToolCalls, writeConfig };
package/dist/index.js CHANGED
@@ -2,17 +2,96 @@ import {
2
2
  DeepSeekClient,
3
3
  Usage,
4
4
  fetchWithRetry
5
- } from "./chunk-XILYSYPT.js";
5
+ } from "./chunk-Y7L6L5QS.js";
6
6
 
7
7
  // src/harvest.ts
8
8
  function emptyPlanState() {
9
9
  return { subgoals: [], hypotheses: [], uncertainties: [], rejectedPaths: [] };
10
10
  }
11
11
  function isPlanStateEmpty(s) {
12
+ if (!s) return true;
12
13
  return s.subgoals.length === 0 && s.hypotheses.length === 0 && s.uncertainties.length === 0 && s.rejectedPaths.length === 0;
13
14
  }
14
- async function harvest(_reasoningContent) {
15
- return emptyPlanState();
15
+ var SYSTEM_PROMPT = `You extract a typed plan state from a reasoning trace produced by another LLM.
16
+ Output ONLY a JSON object. No markdown, no prose, no backticks.
17
+
18
+ Schema:
19
+ {
20
+ "subgoals": string[], // concrete intermediate objectives the trace identifies
21
+ "hypotheses": string[], // candidate approaches or assumptions being weighed
22
+ "uncertainties": string[], // facts the trace flags as unclear / to verify
23
+ "rejectedPaths": string[] // approaches the trace considered and then abandoned
24
+ }
25
+
26
+ Constraints:
27
+ - Every field must be present. Use [] if not applicable.
28
+ - Each array has at most {maxItems} items.
29
+ - Each item is plain text, at most {maxItemLen} characters, no markdown.
30
+ - Write in the same language as the trace (Chinese in \u2192 Chinese out, etc.).
31
+ - Do not quote back the trace; write short, specific phrases.`;
32
+ async function harvest(reasoningContent, client, options = {}) {
33
+ if (!client || !reasoningContent) return emptyPlanState();
34
+ const minLen = options.minReasoningLen ?? 40;
35
+ const trimmed = reasoningContent.trim();
36
+ if (trimmed.length < minLen) return emptyPlanState();
37
+ const model = options.model ?? "deepseek-chat";
38
+ const maxItems = options.maxItems ?? 5;
39
+ const maxItemLen = options.maxItemLen ?? 80;
40
+ const system = SYSTEM_PROMPT.replace("{maxItems}", String(maxItems)).replace(
41
+ "{maxItemLen}",
42
+ String(maxItemLen)
43
+ );
44
+ try {
45
+ const resp = await client.chat({
46
+ model,
47
+ messages: [
48
+ { role: "system", content: system },
49
+ { role: "user", content: trimmed }
50
+ ],
51
+ responseFormat: { type: "json_object" },
52
+ temperature: 0,
53
+ maxTokens: 600
54
+ });
55
+ return parsePlanState(resp.content, maxItems, maxItemLen);
56
+ } catch {
57
+ return emptyPlanState();
58
+ }
59
+ }
60
+ function parsePlanState(raw, maxItems, maxItemLen) {
61
+ const text = (raw ?? "").trim();
62
+ if (!text) return emptyPlanState();
63
+ let parsed;
64
+ try {
65
+ parsed = JSON.parse(text);
66
+ } catch {
67
+ const match = text.match(/\{[\s\S]*\}/);
68
+ if (!match) return emptyPlanState();
69
+ try {
70
+ parsed = JSON.parse(match[0]);
71
+ } catch {
72
+ return emptyPlanState();
73
+ }
74
+ }
75
+ if (!parsed || typeof parsed !== "object") return emptyPlanState();
76
+ const obj = parsed;
77
+ return {
78
+ subgoals: sanitizeArray(obj.subgoals, maxItems, maxItemLen),
79
+ hypotheses: sanitizeArray(obj.hypotheses, maxItems, maxItemLen),
80
+ uncertainties: sanitizeArray(obj.uncertainties, maxItems, maxItemLen),
81
+ rejectedPaths: sanitizeArray(obj.rejectedPaths ?? obj.rejected_paths, maxItems, maxItemLen)
82
+ };
83
+ }
84
+ function sanitizeArray(raw, maxItems, maxItemLen) {
85
+ if (!Array.isArray(raw)) return [];
86
+ const out = [];
87
+ for (const item of raw) {
88
+ if (out.length >= maxItems) break;
89
+ if (typeof item !== "string") continue;
90
+ const cleaned = item.trim().replace(/\s+/g, " ");
91
+ if (!cleaned) continue;
92
+ out.push(cleaned.length <= maxItemLen ? cleaned : `${cleaned.slice(0, maxItemLen - 1)}\u2026`);
93
+ }
94
+ return out;
16
95
  }
17
96
 
18
97
  // src/memory.ts
@@ -455,9 +534,20 @@ function round(n, digits) {
455
534
  // src/tools.ts
456
535
  var ToolRegistry = class {
457
536
  _tools = /* @__PURE__ */ new Map();
537
+ _autoFlatten;
538
+ constructor(opts = {}) {
539
+ this._autoFlatten = opts.autoFlatten !== false;
540
+ }
458
541
  register(def) {
459
542
  if (!def.name) throw new Error("tool requires a name");
460
- this._tools.set(def.name, def);
543
+ const internal = { ...def };
544
+ if (this._autoFlatten && def.parameters) {
545
+ const decision = analyzeSchema(def.parameters);
546
+ if (decision.shouldFlatten) {
547
+ internal.flatSchema = flattenSchema(def.parameters);
548
+ }
549
+ }
550
+ this._tools.set(def.name, internal);
461
551
  return this;
462
552
  }
463
553
  has(name) {
@@ -469,13 +559,17 @@ var ToolRegistry = class {
469
559
  get size() {
470
560
  return this._tools.size;
471
561
  }
562
+ /** True if a registered tool's schema was flattened for the model. */
563
+ wasFlattened(name) {
564
+ return Boolean(this._tools.get(name)?.flatSchema);
565
+ }
472
566
  specs() {
473
567
  return [...this._tools.values()].map((t) => ({
474
568
  type: "function",
475
569
  function: {
476
570
  name: t.name,
477
571
  description: t.description ?? "",
478
- parameters: t.parameters ?? { type: "object", properties: {} }
572
+ parameters: t.flatSchema ?? t.parameters ?? { type: "object", properties: {} }
479
573
  }
480
574
  }));
481
575
  }
@@ -486,12 +580,15 @@ var ToolRegistry = class {
486
580
  }
487
581
  let args;
488
582
  try {
489
- args = typeof argumentsRaw === "string" ? argumentsRaw.trim() ? JSON.parse(argumentsRaw) : {} : argumentsRaw ?? {};
583
+ args = typeof argumentsRaw === "string" ? argumentsRaw.trim() ? JSON.parse(argumentsRaw) ?? {} : {} : argumentsRaw ?? {};
490
584
  } catch (err) {
491
585
  return JSON.stringify({
492
586
  error: `invalid tool arguments JSON: ${err.message}`
493
587
  });
494
588
  }
589
+ if (tool.flatSchema && args && typeof args === "object" && hasDotKey(args)) {
590
+ args = nestArguments(args);
591
+ }
495
592
  try {
496
593
  const result = await tool.fn(args);
497
594
  return typeof result === "string" ? result : JSON.stringify(result);
@@ -502,6 +599,12 @@ var ToolRegistry = class {
502
599
  }
503
600
  }
504
601
  };
602
+ function hasDotKey(obj) {
603
+ for (const k of Object.keys(obj)) {
604
+ if (k.includes(".")) return true;
605
+ }
606
+ return false;
607
+ }
505
608
 
506
609
  // src/loop.ts
507
610
  var CacheFirstLoop = class {
@@ -511,6 +614,8 @@ var CacheFirstLoop = class {
511
614
  model;
512
615
  maxToolIters;
513
616
  stream;
617
+ harvestEnabled;
618
+ harvestOptions;
514
619
  log = new AppendOnlyLog();
515
620
  scratch = new VolatileScratch();
516
621
  stats = new SessionStats();
@@ -523,6 +628,8 @@ var CacheFirstLoop = class {
523
628
  this.model = opts.model ?? "deepseek-chat";
524
629
  this.maxToolIters = opts.maxToolIters ?? 8;
525
630
  this.stream = opts.stream ?? true;
631
+ this.harvestEnabled = opts.harvest === true || typeof opts.harvest === "object" && opts.harvest !== null;
632
+ this.harvestOptions = typeof opts.harvest === "object" && opts.harvest !== null ? opts.harvest : {};
526
633
  const allowedNames = /* @__PURE__ */ new Set([...this.prefix.toolSpecs.map((s) => s.function.name)]);
527
634
  this.repair = new ToolCallRepair({ allowedToolNames: allowedNames });
528
635
  }
@@ -606,14 +713,14 @@ var CacheFirstLoop = class {
606
713
  const turnStats = this.stats.record(
607
714
  this._turn,
608
715
  this.model,
609
- usage ?? new (await import("./client-4JTJKRDV.js")).Usage()
716
+ usage ?? new (await import("./client-KEA2D52Q.js")).Usage()
610
717
  );
611
718
  if (pendingUser !== null) {
612
719
  this.log.append({ role: "user", content: pendingUser });
613
720
  pendingUser = null;
614
721
  }
615
722
  this.scratch.reasoning = reasoningContent || null;
616
- const planState = await harvest(reasoningContent || null);
723
+ const planState = this.harvestEnabled ? await harvest(reasoningContent || null, this.client, this.harvestOptions) : emptyPlanState();
617
724
  const { calls: repairedCalls, report } = this.repair.process(
618
725
  toolCalls,
619
726
  reasoningContent || null
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/harvest.ts","../src/memory.ts","../src/repair/scavenge.ts","../src/repair/storm.ts","../src/repair/truncation.ts","../src/repair/flatten.ts","../src/repair/index.ts","../src/telemetry.ts","../src/tools.ts","../src/loop.ts","../src/env.ts","../src/config.ts","../src/index.ts"],"sourcesContent":["/**\n * Pillar 2 — R1 Thought Harvesting.\n *\n * v0.0.1 stub. Real implementation lands in v0.2 as a constrained V3 call\n * against a strict JSON schema. The shape below is the public contract that\n * downstream code may already depend on.\n */\n\nexport interface TypedPlanState {\n subgoals: string[];\n hypotheses: string[];\n uncertainties: string[];\n rejectedPaths: string[];\n}\n\nexport function emptyPlanState(): TypedPlanState {\n return { subgoals: [], hypotheses: [], uncertainties: [], rejectedPaths: [] };\n}\n\nexport function isPlanStateEmpty(s: TypedPlanState): boolean {\n return (\n s.subgoals.length === 0 &&\n s.hypotheses.length === 0 &&\n s.uncertainties.length === 0 &&\n s.rejectedPaths.length === 0\n );\n}\n\n/** v0.0.1 stub — returns empty state. */\nexport async function harvest(_reasoningContent: string | null): Promise<TypedPlanState> {\n return emptyPlanState();\n}\n","import { createHash } from \"node:crypto\";\nimport type { ChatMessage, ToolSpec } from \"./types.js\";\n\nexport interface ImmutablePrefixOptions {\n system: string;\n toolSpecs?: readonly ToolSpec[];\n fewShots?: readonly ChatMessage[];\n}\n\nexport class ImmutablePrefix {\n readonly system: string;\n readonly toolSpecs: readonly ToolSpec[];\n readonly fewShots: readonly ChatMessage[];\n\n constructor(opts: ImmutablePrefixOptions) {\n this.system = opts.system;\n this.toolSpecs = Object.freeze([...(opts.toolSpecs ?? [])]);\n this.fewShots = Object.freeze([...(opts.fewShots ?? [])]);\n }\n\n toMessages(): ChatMessage[] {\n return [{ role: \"system\", content: this.system }, ...this.fewShots.map((m) => ({ ...m }))];\n }\n\n tools(): ToolSpec[] {\n return this.toolSpecs.map((t) => structuredClone(t) as ToolSpec);\n }\n\n get fingerprint(): string {\n const blob = JSON.stringify({\n system: this.system,\n tools: this.toolSpecs,\n shots: this.fewShots,\n });\n return createHash(\"sha256\").update(blob).digest(\"hex\").slice(0, 16);\n }\n}\n\nexport class AppendOnlyLog {\n private _entries: ChatMessage[] = [];\n\n append(message: ChatMessage): void {\n if (!message || typeof message !== \"object\" || !(\"role\" in message)) {\n throw new Error(`invalid log entry: ${JSON.stringify(message)}`);\n }\n this._entries.push(message);\n }\n\n extend(messages: ChatMessage[]): void {\n for (const m of messages) this.append(m);\n }\n\n get entries(): readonly ChatMessage[] {\n return this._entries;\n }\n\n toMessages(): ChatMessage[] {\n return this._entries.map((e) => ({ ...e }));\n }\n\n get length(): number {\n return this._entries.length;\n }\n}\n\nexport class VolatileScratch {\n reasoning: string | null = null;\n planState: Record<string, unknown> | null = null;\n notes: string[] = [];\n\n reset(): void {\n this.reasoning = null;\n this.planState = null;\n this.notes = [];\n }\n}\n","/**\n * Scavenge tool calls leaked into reasoning_content.\n *\n * R1 sometimes emits tool-call JSON inside <think>…</think> and then forgets\n * to surface it in `tool_calls`. This pass extracts plausible calls and\n * proposes them to the loop, which decides whether to merge them with the\n * declared calls.\n */\n\nimport type { ToolCall } from \"../types.js\";\n\nexport interface ScavengeOptions {\n /** Names of tools the model may legitimately call. Other names are ignored. */\n allowedNames: ReadonlySet<string>;\n /** Maximum number of calls to scavenge per pass (defence against runaway). */\n maxCalls?: number;\n}\n\nexport interface ScavengeResult {\n calls: ToolCall[];\n notes: string[];\n}\n\nexport function scavengeToolCalls(\n reasoningContent: string | null | undefined,\n opts: ScavengeOptions,\n): ScavengeResult {\n if (!reasoningContent) return { calls: [], notes: [] };\n const max = opts.maxCalls ?? 4;\n const notes: string[] = [];\n const out: ToolCall[] = [];\n\n for (const candidate of iterateJsonObjects(reasoningContent)) {\n if (out.length >= max) break;\n const call = coerceToToolCall(candidate, opts.allowedNames);\n if (call) {\n out.push(call);\n notes.push(`scavenged call: ${call.function.name}`);\n }\n }\n return { calls: out, notes };\n}\n\n/** Yield every top-level JSON object substring in `text`. */\nfunction* iterateJsonObjects(text: string): Generator<string> {\n for (let i = 0; i < text.length; i++) {\n if (text[i] !== \"{\") continue;\n let depth = 0;\n let inString = false;\n let escaped = false;\n for (let j = i; j < text.length; j++) {\n const c = text[j]!;\n if (escaped) {\n escaped = false;\n continue;\n }\n if (inString) {\n if (c === \"\\\\\") {\n escaped = true;\n continue;\n }\n if (c === '\"') inString = false;\n continue;\n }\n if (c === '\"') inString = true;\n else if (c === \"{\") depth++;\n else if (c === \"}\") {\n depth--;\n if (depth === 0) {\n yield text.slice(i, j + 1);\n i = j;\n break;\n }\n }\n }\n }\n}\n\nfunction coerceToToolCall(\n candidateJson: string,\n allowedNames: ReadonlySet<string>,\n): ToolCall | null {\n let parsed: any;\n try {\n parsed = JSON.parse(candidateJson);\n } catch {\n return null;\n }\n if (!parsed || typeof parsed !== \"object\") return null;\n\n // Pattern 1: { name, arguments }\n if (typeof parsed.name === \"string\" && allowedNames.has(parsed.name)) {\n const args = parsed.arguments;\n return {\n function: {\n name: parsed.name,\n arguments: typeof args === \"string\" ? args : JSON.stringify(args ?? {}),\n },\n };\n }\n\n // Pattern 2: OpenAI-style { type: \"function\", function: { name, arguments } }\n if (\n parsed.type === \"function\" &&\n parsed.function &&\n typeof parsed.function.name === \"string\" &&\n allowedNames.has(parsed.function.name)\n ) {\n const args = parsed.function.arguments;\n return {\n type: \"function\",\n function: {\n name: parsed.function.name,\n arguments: typeof args === \"string\" ? args : JSON.stringify(args ?? {}),\n },\n };\n }\n\n // Pattern 3: { tool_name, tool_args } (R1 free-form variant)\n if (typeof parsed.tool_name === \"string\" && allowedNames.has(parsed.tool_name)) {\n return {\n function: {\n name: parsed.tool_name,\n arguments: JSON.stringify(parsed.tool_args ?? {}),\n },\n };\n }\n\n return null;\n}\n","import type { ToolCall } from \"../types.js\";\n\n/**\n * Call-storm breaker.\n *\n * Detects (tool, args) tuples repeating within a sliding window and suppresses\n * the offending call. Surfaces a synthetic tool_result advising the model to\n * change strategy on its next turn.\n */\nexport class StormBreaker {\n private readonly windowSize: number;\n private readonly threshold: number;\n private readonly recent: Array<readonly [string, string]> = [];\n\n constructor(windowSize = 6, threshold = 3) {\n this.windowSize = windowSize;\n this.threshold = threshold;\n }\n\n inspect(call: ToolCall): { suppress: boolean; reason?: string } {\n const sig = signature(call);\n if (!sig) return { suppress: false };\n const count = this.recent.reduce(\n (n, [name, args]) => (name === sig[0] && args === sig[1] ? n + 1 : n),\n 0,\n );\n if (count >= this.threshold - 1) {\n return {\n suppress: true,\n reason: `call-storm suppressed: ${sig[0]} called with identical args ${count + 1} times within window=${this.windowSize}`,\n };\n }\n this.recent.push(sig);\n while (this.recent.length > this.windowSize) this.recent.shift();\n return { suppress: false };\n }\n\n reset(): void {\n this.recent.length = 0;\n }\n}\n\nfunction signature(call: ToolCall): readonly [string, string] | null {\n const name = call.function?.name;\n if (!name) return null;\n return [name, call.function?.arguments ?? \"\"] as const;\n}\n","/**\n * Truncation recovery for tool-call argument JSON cut off mid-structure\n * (typically when the model hits max_tokens before finishing the JSON object).\n *\n * Strategy is purely local: balance braces, close strings, fill missing values\n * with `null`. We deliberately do NOT make a continuation API call here — that\n * decision belongs to the loop, which knows about budgets.\n */\n\nexport interface TruncationRepairResult {\n repaired: string;\n changed: boolean;\n notes: string[];\n}\n\nexport function repairTruncatedJson(input: string): TruncationRepairResult {\n const notes: string[] = [];\n if (!input || !input.trim()) {\n return { repaired: \"{}\", changed: input !== \"{}\", notes: [\"empty input → {}\"] };\n }\n // Fast path: already parseable.\n try {\n JSON.parse(input);\n return { repaired: input, changed: false, notes: [] };\n } catch {\n /* fall through */\n }\n\n const stack: (\"{\" | \"[\" | '\"')[] = [];\n let escaped = false;\n let inString = false;\n let lastSignificant = -1;\n\n for (let i = 0; i < input.length; i++) {\n const c = input[i]!;\n if (!/\\s/.test(c)) lastSignificant = i;\n if (escaped) {\n escaped = false;\n continue;\n }\n if (inString) {\n if (c === \"\\\\\") {\n escaped = true;\n continue;\n }\n if (c === '\"') {\n inString = false;\n stack.pop();\n }\n continue;\n }\n if (c === '\"') {\n inString = true;\n stack.push('\"');\n continue;\n }\n if (c === \"{\" || c === \"[\") stack.push(c);\n else if (c === \"}\" || c === \"]\") stack.pop();\n }\n\n let s = input.slice(0, lastSignificant + 1);\n\n // Trim a trailing comma which would block re-parse.\n if (/,$/.test(s)) {\n s = s.replace(/,$/, \"\");\n notes.push(\"trimmed trailing comma\");\n }\n\n // If we ended on a key without a value: \"foo\": → \"foo\": null\n if (/\"\\s*:\\s*$/.test(s)) {\n s += \" null\";\n notes.push(\"filled dangling key with null\");\n }\n\n // If we ended inside a string, close it.\n if (inString) {\n s += '\"';\n stack.pop();\n notes.push(\"closed unterminated string\");\n }\n\n // Pop remaining open structures in reverse order.\n while (stack.length > 0) {\n const top = stack.pop();\n if (top === \"{\") s += \"}\";\n else if (top === \"[\") s += \"]\";\n else if (top === '\"') s += '\"';\n }\n\n try {\n JSON.parse(s);\n return { repaired: s, changed: true, notes };\n } catch (err) {\n notes.push(`fallback to {}: ${(err as Error).message}`);\n return { repaired: \"{}\", changed: true, notes };\n }\n}\n","/**\n * Schema flattening for DeepSeek tool calls.\n *\n * DeepSeek loses arguments on schemas that are deep (>2 levels of nesting) or\n * wide (>10 leaf parameters). This module transforms such schemas into a\n * dot-notation flat schema and re-nests the model's arguments before dispatch.\n *\n * Example:\n * { user: { profile: { name, age } } } ⇄ \"user.profile.name\", \"user.profile.age\"\n */\n\nimport type { JSONSchema } from \"../types.js\";\n\nexport interface FlattenDecision {\n shouldFlatten: boolean;\n leafCount: number;\n maxDepth: number;\n}\n\nexport function analyzeSchema(schema: JSONSchema | undefined): FlattenDecision {\n if (!schema) return { shouldFlatten: false, leafCount: 0, maxDepth: 0 };\n let leafCount = 0;\n let maxDepth = 0;\n walk(schema, 0, (depth, isLeaf) => {\n if (isLeaf) leafCount++;\n if (depth > maxDepth) maxDepth = depth;\n });\n return {\n shouldFlatten: leafCount > 10 || maxDepth > 2,\n leafCount,\n maxDepth,\n };\n}\n\nexport function flattenSchema(schema: JSONSchema): JSONSchema {\n const flatProps: Record<string, JSONSchema> = {};\n const required: string[] = [];\n collect(\"\", schema, flatProps, required, true);\n return {\n type: \"object\",\n properties: flatProps,\n required,\n };\n}\n\nexport function nestArguments(flatArgs: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(flatArgs)) {\n setByPath(out, key.split(\".\"), value);\n }\n return out;\n}\n\nfunction walk(\n schema: JSONSchema,\n depth: number,\n visit: (depth: number, isLeaf: boolean) => void,\n): void {\n if (schema.type === \"object\" && schema.properties) {\n for (const child of Object.values(schema.properties)) {\n walk(child, depth + 1, visit);\n }\n return;\n }\n if (schema.type === \"array\" && schema.items) {\n walk(schema.items, depth + 1, visit);\n return;\n }\n visit(depth, true);\n}\n\nfunction collect(\n prefix: string,\n schema: JSONSchema,\n out: Record<string, JSONSchema>,\n required: string[],\n isRootRequired: boolean,\n): void {\n if (schema.type === \"object\" && schema.properties) {\n const requiredSet = new Set(schema.required ?? []);\n for (const [key, child] of Object.entries(schema.properties)) {\n const nextPrefix = prefix ? `${prefix}.${key}` : key;\n const childRequired = isRootRequired && requiredSet.has(key);\n collect(nextPrefix, child, out, required, childRequired);\n }\n return;\n }\n // Treat anything non-object (including arrays) as a leaf for flattening purposes.\n out[prefix] = schema;\n if (isRootRequired) required.push(prefix);\n}\n\nfunction setByPath(target: Record<string, unknown>, path: string[], value: unknown): void {\n let cur: any = target;\n for (let i = 0; i < path.length - 1; i++) {\n const key = path[i]!;\n if (typeof cur[key] !== \"object\" || cur[key] === null) cur[key] = {};\n cur = cur[key];\n }\n cur[path[path.length - 1]!] = value;\n}\n","/**\n * Pillar 3 — Tool-Call Repair pipeline.\n *\n * Order of passes per turn:\n * 1. scavenge — recover tool calls leaked into <think>\n * 2. truncation — close any half-emitted argument JSON\n * 3. storm breaker — drop call-storm repeats\n *\n * Schema flattening is applied during loop construction (it changes what we\n * advertise to the model), not per-turn.\n */\n\nimport type { ToolCall } from \"../types.js\";\nimport { scavengeToolCalls } from \"./scavenge.js\";\nimport { StormBreaker } from \"./storm.js\";\nimport { repairTruncatedJson } from \"./truncation.js\";\n\nexport { analyzeSchema, flattenSchema, nestArguments } from \"./flatten.js\";\nexport type { FlattenDecision } from \"./flatten.js\";\nexport { repairTruncatedJson } from \"./truncation.js\";\nexport type { TruncationRepairResult } from \"./truncation.js\";\nexport { scavengeToolCalls } from \"./scavenge.js\";\nexport type { ScavengeOptions, ScavengeResult } from \"./scavenge.js\";\nexport { StormBreaker } from \"./storm.js\";\n\nexport interface RepairReport {\n scavenged: number;\n truncationsFixed: number;\n stormsBroken: number;\n notes: string[];\n}\n\nexport interface ToolCallRepairOptions {\n allowedToolNames: ReadonlySet<string>;\n stormWindow?: number;\n stormThreshold?: number;\n maxScavenge?: number;\n}\n\nexport class ToolCallRepair {\n private readonly storm: StormBreaker;\n private readonly opts: ToolCallRepairOptions;\n\n constructor(opts: ToolCallRepairOptions) {\n this.opts = opts;\n this.storm = new StormBreaker(opts.stormWindow ?? 6, opts.stormThreshold ?? 3);\n }\n\n process(\n declaredCalls: ToolCall[],\n reasoningContent: string | null,\n ): { calls: ToolCall[]; report: RepairReport } {\n const report: RepairReport = {\n scavenged: 0,\n truncationsFixed: 0,\n stormsBroken: 0,\n notes: [],\n };\n\n // 1. Scavenge — only add calls whose (name,args) signature is novel.\n const scavenged = scavengeToolCalls(reasoningContent, {\n allowedNames: this.opts.allowedToolNames,\n maxCalls: this.opts.maxScavenge ?? 4,\n });\n const seenSignatures = new Set(declaredCalls.map(signature));\n const merged = [...declaredCalls];\n for (const sc of scavenged.calls) {\n if (!seenSignatures.has(signature(sc))) {\n merged.push(sc);\n report.scavenged++;\n seenSignatures.add(signature(sc));\n }\n }\n report.notes.push(...scavenged.notes);\n\n // 2. Truncation repair on argument JSON.\n for (const call of merged) {\n const args = call.function?.arguments ?? \"\";\n const r = repairTruncatedJson(args);\n if (r.changed) {\n call.function.arguments = r.repaired;\n report.truncationsFixed++;\n report.notes.push(...r.notes.map((n) => `[${call.function.name}] ${n}`));\n }\n }\n\n // 3. Storm breaker.\n const filtered: ToolCall[] = [];\n for (const call of merged) {\n const verdict = this.storm.inspect(call);\n if (verdict.suppress) {\n report.stormsBroken++;\n if (verdict.reason) report.notes.push(verdict.reason);\n continue;\n }\n filtered.push(call);\n }\n\n return { calls: filtered, report };\n }\n}\n\nfunction signature(call: ToolCall): string {\n return `${call.function?.name ?? \"\"}::${call.function?.arguments ?? \"\"}`;\n}\n","import type { Usage } from \"./client.js\";\n\n/** USD per 1M tokens. Update as DeepSeek pricing changes. */\nexport const DEEPSEEK_PRICING: Record<\n string,\n { inputCacheHit: number; inputCacheMiss: number; output: number }\n> = {\n \"deepseek-chat\": { inputCacheHit: 0.07, inputCacheMiss: 0.27, output: 1.1 },\n \"deepseek-reasoner\": { inputCacheHit: 0.14, inputCacheMiss: 0.55, output: 2.19 },\n};\n\n/** Reference Claude Sonnet 4.6 pricing (USD per 1M tokens). */\nexport const CLAUDE_SONNET_PRICING = { input: 3.0, output: 15.0 };\n\nexport function costUsd(model: string, usage: Usage): number {\n const p = DEEPSEEK_PRICING[model];\n if (!p) return 0;\n return (\n (usage.promptCacheHitTokens * p.inputCacheHit +\n usage.promptCacheMissTokens * p.inputCacheMiss +\n usage.completionTokens * p.output) /\n 1_000_000\n );\n}\n\nexport function claudeEquivalentCost(usage: Usage): number {\n return (\n (usage.promptTokens * CLAUDE_SONNET_PRICING.input +\n usage.completionTokens * CLAUDE_SONNET_PRICING.output) /\n 1_000_000\n );\n}\n\nexport interface TurnStats {\n turn: number;\n model: string;\n usage: Usage;\n cost: number;\n cacheHitRatio: number;\n}\n\nexport interface SessionSummary {\n turns: number;\n totalCostUsd: number;\n claudeEquivalentUsd: number;\n savingsVsClaudePct: number;\n cacheHitRatio: number;\n}\n\nexport class SessionStats {\n readonly turns: TurnStats[] = [];\n\n record(turn: number, model: string, usage: Usage): TurnStats {\n const cost = costUsd(model, usage);\n const stats: TurnStats = {\n turn,\n model,\n usage,\n cost,\n cacheHitRatio: usage.cacheHitRatio,\n };\n this.turns.push(stats);\n return stats;\n }\n\n get totalCost(): number {\n return this.turns.reduce((sum, t) => sum + t.cost, 0);\n }\n\n get totalClaudeEquivalent(): number {\n return this.turns.reduce((sum, t) => sum + claudeEquivalentCost(t.usage), 0);\n }\n\n get savingsVsClaude(): number {\n const c = this.totalClaudeEquivalent;\n return c > 0 ? 1 - this.totalCost / c : 0;\n }\n\n get aggregateCacheHitRatio(): number {\n let hit = 0;\n let miss = 0;\n for (const t of this.turns) {\n hit += t.usage.promptCacheHitTokens;\n miss += t.usage.promptCacheMissTokens;\n }\n const denom = hit + miss;\n return denom > 0 ? hit / denom : 0;\n }\n\n summary(): SessionSummary {\n return {\n turns: this.turns.length,\n totalCostUsd: round(this.totalCost, 6),\n claudeEquivalentUsd: round(this.totalClaudeEquivalent, 6),\n savingsVsClaudePct: round(this.savingsVsClaude * 100, 2),\n cacheHitRatio: round(this.aggregateCacheHitRatio, 4),\n };\n }\n}\n\nfunction round(n: number, digits: number): number {\n const f = 10 ** digits;\n return Math.round(n * f) / f;\n}\n","import type { JSONSchema, ToolSpec } from \"./types.js\";\n\nexport interface ToolDefinition<A = any, R = any> {\n name: string;\n description?: string;\n parameters?: JSONSchema;\n fn: (args: A) => R | Promise<R>;\n}\n\nexport class ToolRegistry {\n private readonly _tools = new Map<string, ToolDefinition>();\n\n register<A, R>(def: ToolDefinition<A, R>): this {\n if (!def.name) throw new Error(\"tool requires a name\");\n this._tools.set(def.name, def as ToolDefinition);\n return this;\n }\n\n has(name: string): boolean {\n return this._tools.has(name);\n }\n\n get(name: string): ToolDefinition | undefined {\n return this._tools.get(name);\n }\n\n get size(): number {\n return this._tools.size;\n }\n\n specs(): ToolSpec[] {\n return [...this._tools.values()].map((t) => ({\n type: \"function\",\n function: {\n name: t.name,\n description: t.description ?? \"\",\n parameters: t.parameters ?? { type: \"object\", properties: {} },\n },\n }));\n }\n\n async dispatch(name: string, argumentsRaw: string | Record<string, unknown>): Promise<string> {\n const tool = this._tools.get(name);\n if (!tool) {\n return JSON.stringify({ error: `unknown tool: ${name}` });\n }\n let args: any;\n try {\n args =\n typeof argumentsRaw === \"string\"\n ? argumentsRaw.trim()\n ? JSON.parse(argumentsRaw)\n : {}\n : (argumentsRaw ?? {});\n } catch (err) {\n return JSON.stringify({\n error: `invalid tool arguments JSON: ${(err as Error).message}`,\n });\n }\n try {\n const result = await tool.fn(args);\n return typeof result === \"string\" ? result : JSON.stringify(result);\n } catch (err) {\n return JSON.stringify({\n error: `${(err as Error).name}: ${(err as Error).message}`,\n });\n }\n }\n}\n","import type { DeepSeekClient } from \"./client.js\";\nimport { type TypedPlanState, harvest } from \"./harvest.js\";\nimport { AppendOnlyLog, type ImmutablePrefix, VolatileScratch } from \"./memory.js\";\nimport { type RepairReport, ToolCallRepair } from \"./repair/index.js\";\nimport { SessionStats, type TurnStats } from \"./telemetry.js\";\nimport { ToolRegistry } from \"./tools.js\";\nimport type { ChatMessage, ToolCall } from \"./types.js\";\n\nexport type EventRole = \"assistant_delta\" | \"assistant_final\" | \"tool\" | \"done\" | \"error\";\n\nexport interface LoopEvent {\n turn: number;\n role: EventRole;\n content: string;\n reasoningDelta?: string;\n toolName?: string;\n stats?: TurnStats;\n planState?: TypedPlanState;\n repair?: RepairReport;\n error?: string;\n}\n\nexport interface CacheFirstLoopOptions {\n client: DeepSeekClient;\n prefix: ImmutablePrefix;\n tools?: ToolRegistry;\n model?: string;\n maxToolIters?: number;\n stream?: boolean;\n}\n\n/**\n * Pillar 1 — Cache-First Loop.\n *\n * - prefix is immutable (cache target)\n * - log is append-only (preserves prior-turn prefix)\n * - scratch is per-turn volatile (never sent upstream)\n *\n * Yields a stream of events so a TUI can render progressively.\n */\nexport class CacheFirstLoop {\n readonly client: DeepSeekClient;\n readonly prefix: ImmutablePrefix;\n readonly tools: ToolRegistry;\n readonly model: string;\n readonly maxToolIters: number;\n readonly stream: boolean;\n readonly log = new AppendOnlyLog();\n readonly scratch = new VolatileScratch();\n readonly stats = new SessionStats();\n readonly repair: ToolCallRepair;\n private _turn = 0;\n\n constructor(opts: CacheFirstLoopOptions) {\n this.client = opts.client;\n this.prefix = opts.prefix;\n this.tools = opts.tools ?? new ToolRegistry();\n this.model = opts.model ?? \"deepseek-chat\";\n this.maxToolIters = opts.maxToolIters ?? 8;\n this.stream = opts.stream ?? true;\n const allowedNames = new Set([...this.prefix.toolSpecs.map((s) => s.function.name)]);\n this.repair = new ToolCallRepair({ allowedToolNames: allowedNames });\n }\n\n private buildMessages(pendingUser: string | null): ChatMessage[] {\n const msgs: ChatMessage[] = [...this.prefix.toMessages(), ...this.log.toMessages()];\n if (pendingUser !== null) msgs.push({ role: \"user\", content: pendingUser });\n return msgs;\n }\n\n async *step(userInput: string): AsyncGenerator<LoopEvent> {\n this._turn++;\n this.scratch.reset();\n let pendingUser: string | null = userInput;\n const toolSpecs = this.prefix.tools();\n\n for (let iter = 0; iter < this.maxToolIters; iter++) {\n const messages = this.buildMessages(pendingUser);\n\n let assistantContent = \"\";\n let reasoningContent = \"\";\n let toolCalls: ToolCall[] = [];\n let usage: TurnStats[\"usage\"] | null = null;\n\n try {\n if (this.stream) {\n const callBuf: Map<number, ToolCall> = new Map();\n for await (const chunk of this.client.stream({\n model: this.model,\n messages,\n tools: toolSpecs.length ? toolSpecs : undefined,\n })) {\n if (chunk.contentDelta) {\n assistantContent += chunk.contentDelta;\n yield {\n turn: this._turn,\n role: \"assistant_delta\",\n content: chunk.contentDelta,\n };\n }\n if (chunk.reasoningDelta) {\n reasoningContent += chunk.reasoningDelta;\n yield {\n turn: this._turn,\n role: \"assistant_delta\",\n content: \"\",\n reasoningDelta: chunk.reasoningDelta,\n };\n }\n if (chunk.toolCallDelta) {\n const d = chunk.toolCallDelta;\n const cur = callBuf.get(d.index) ?? {\n id: d.id,\n type: \"function\" as const,\n function: { name: \"\", arguments: \"\" },\n };\n if (d.id) cur.id = d.id;\n if (d.name) cur.function.name = (cur.function.name ?? \"\") + d.name;\n if (d.argumentsDelta)\n cur.function.arguments = (cur.function.arguments ?? \"\") + d.argumentsDelta;\n callBuf.set(d.index, cur);\n }\n if (chunk.usage) usage = chunk.usage;\n }\n toolCalls = [...callBuf.values()];\n } else {\n const resp = await this.client.chat({\n model: this.model,\n messages,\n tools: toolSpecs.length ? toolSpecs : undefined,\n });\n assistantContent = resp.content;\n reasoningContent = resp.reasoningContent ?? \"\";\n toolCalls = resp.toolCalls;\n usage = resp.usage;\n }\n } catch (err) {\n yield {\n turn: this._turn,\n role: \"error\",\n content: \"\",\n error: (err as Error).message,\n };\n return;\n }\n\n const turnStats = this.stats.record(\n this._turn,\n this.model,\n usage ?? new (await import(\"./client.js\")).Usage(),\n );\n\n // Commit the user turn to the log only on success of the first round-trip.\n if (pendingUser !== null) {\n this.log.append({ role: \"user\", content: pendingUser });\n pendingUser = null;\n }\n\n this.scratch.reasoning = reasoningContent || null;\n const planState = await harvest(reasoningContent || null);\n\n const { calls: repairedCalls, report } = this.repair.process(\n toolCalls,\n reasoningContent || null,\n );\n\n this.log.append(this.assistantMessage(assistantContent, repairedCalls));\n\n yield {\n turn: this._turn,\n role: \"assistant_final\",\n content: assistantContent,\n stats: turnStats,\n planState,\n repair: report,\n };\n\n if (repairedCalls.length === 0) {\n yield { turn: this._turn, role: \"done\", content: assistantContent };\n return;\n }\n\n for (const call of repairedCalls) {\n const name = call.function?.name ?? \"\";\n const args = call.function?.arguments ?? \"{}\";\n const result = await this.tools.dispatch(name, args);\n this.log.append({\n role: \"tool\",\n tool_call_id: call.id ?? \"\",\n name,\n content: result,\n });\n yield { turn: this._turn, role: \"tool\", content: result, toolName: name };\n }\n }\n\n yield { turn: this._turn, role: \"done\", content: \"[max_tool_iters reached]\" };\n }\n\n async run(userInput: string, onEvent?: (ev: LoopEvent) => void): Promise<string> {\n let final = \"\";\n for await (const ev of this.step(userInput)) {\n onEvent?.(ev);\n if (ev.role === \"assistant_final\") final = ev.content;\n if (ev.role === \"done\") break;\n }\n return final;\n }\n\n private assistantMessage(content: string, toolCalls: ToolCall[]): ChatMessage {\n const msg: ChatMessage = { role: \"assistant\", content };\n if (toolCalls.length > 0) msg.tool_calls = toolCalls;\n return msg;\n }\n}\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\n/**\n * Minimal `.env` loader; no dependency on dotenv.\n *\n * Reads KEY=VALUE lines and populates `process.env` for keys not already set.\n * Silently no-ops if the file is missing. Safe to call from library entry\n * points, CLI commands, examples, and benchmark runners.\n */\nexport function loadDotenv(path = \".env\"): void {\n let raw: string;\n try {\n raw = readFileSync(resolve(process.cwd(), path), \"utf8\");\n } catch {\n return;\n }\n for (const line of raw.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) continue;\n const eq = trimmed.indexOf(\"=\");\n if (eq === -1) continue;\n const key = trimmed.slice(0, eq).trim();\n let value = trimmed.slice(eq + 1).trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n if (process.env[key] === undefined) process.env[key] = value;\n }\n}\n","/**\n * User-level config storage for the Reasonix CLI.\n *\n * Lookup order for the API key:\n * 1. `DEEPSEEK_API_KEY` env var (highest priority — for CI / power users)\n * 2. `~/.reasonix/config.json` (set by the first-run setup flow)\n *\n * The library itself never touches the config file — it only reads\n * `DEEPSEEK_API_KEY` from the environment. The CLI is responsible for\n * pulling from the config file and exposing it via env var to the loop.\n */\n\nimport { chmodSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nexport interface ReasonixConfig {\n apiKey?: string;\n baseUrl?: string;\n}\n\nexport function defaultConfigPath(): string {\n return join(homedir(), \".reasonix\", \"config.json\");\n}\n\nexport function readConfig(path: string = defaultConfigPath()): ReasonixConfig {\n try {\n const raw = readFileSync(path, \"utf8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") return parsed as ReasonixConfig;\n } catch {\n /* missing or malformed → empty config */\n }\n return {};\n}\n\nexport function writeConfig(cfg: ReasonixConfig, path: string = defaultConfigPath()): void {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, JSON.stringify(cfg, null, 2), \"utf8\");\n // Restrict permissions on Unix; chmod is a no-op on Windows but won't throw.\n try {\n chmodSync(path, 0o600);\n } catch {\n /* ignore on platforms without chmod */\n }\n}\n\n/** Resolve the API key from env var first, then the config file. */\nexport function loadApiKey(path: string = defaultConfigPath()): string | undefined {\n if (process.env.DEEPSEEK_API_KEY) return process.env.DEEPSEEK_API_KEY;\n return readConfig(path).apiKey;\n}\n\nexport function saveApiKey(key: string, path: string = defaultConfigPath()): void {\n const cfg = readConfig(path);\n cfg.apiKey = key.trim();\n writeConfig(cfg, path);\n}\n\nexport function isPlausibleKey(key: string): boolean {\n const trimmed = key.trim();\n return /^sk-[A-Za-z0-9_-]{16,}$/.test(trimmed);\n}\n\n/** Mask a key for display: `sk-abcd...wxyz`. */\nexport function redactKey(key: string): string {\n if (!key) return \"\";\n if (key.length <= 12) return \"****\";\n return `${key.slice(0, 6)}…${key.slice(-4)}`;\n}\n","/** Reasonix — DeepSeek-native agent framework. Library entry point. */\n\nexport { DeepSeekClient, Usage } from \"./client.js\";\nexport type { ChatResponse, StreamChunk, DeepSeekClientOptions } from \"./client.js\";\n\nexport { CacheFirstLoop } from \"./loop.js\";\nexport type { CacheFirstLoopOptions, LoopEvent, EventRole } from \"./loop.js\";\n\nexport { ImmutablePrefix, AppendOnlyLog, VolatileScratch } from \"./memory.js\";\nexport type { ImmutablePrefixOptions } from \"./memory.js\";\n\nexport { ToolRegistry } from \"./tools.js\";\nexport type { ToolDefinition } from \"./tools.js\";\n\nexport { SessionStats, costUsd, claudeEquivalentCost } from \"./telemetry.js\";\nexport type { TurnStats, SessionSummary } from \"./telemetry.js\";\n\nexport {\n ToolCallRepair,\n scavengeToolCalls,\n repairTruncatedJson,\n StormBreaker,\n analyzeSchema,\n flattenSchema,\n nestArguments,\n} from \"./repair/index.js\";\nexport type {\n RepairReport,\n ToolCallRepairOptions,\n ScavengeOptions,\n ScavengeResult,\n TruncationRepairResult,\n FlattenDecision,\n} from \"./repair/index.js\";\n\nexport { harvest, emptyPlanState, isPlanStateEmpty } from \"./harvest.js\";\nexport type { TypedPlanState } from \"./harvest.js\";\n\nexport { loadDotenv } from \"./env.js\";\n\nexport { fetchWithRetry } from \"./retry.js\";\nexport type { RetryOptions, RetryInfo } from \"./retry.js\";\n\nexport {\n defaultConfigPath,\n isPlausibleKey,\n loadApiKey,\n readConfig,\n redactKey,\n saveApiKey,\n writeConfig,\n} from \"./config.js\";\nexport type { ReasonixConfig } from \"./config.js\";\n\nexport type {\n ChatMessage,\n ToolCall,\n ToolSpec,\n ToolFunctionSpec,\n Role,\n JSONSchema,\n} from \"./types.js\";\n\nexport const VERSION = \"0.0.1\";\n"],"mappings":"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","names":["signature","readFileSync"]}
1
+ {"version":3,"sources":["../src/harvest.ts","../src/memory.ts","../src/repair/scavenge.ts","../src/repair/storm.ts","../src/repair/truncation.ts","../src/repair/flatten.ts","../src/repair/index.ts","../src/telemetry.ts","../src/tools.ts","../src/loop.ts","../src/env.ts","../src/config.ts","../src/index.ts"],"sourcesContent":["/**\n * Pillar 2 — R1 Thought Harvesting.\n *\n * Takes the `reasoning_content` emitted by a thinking model (deepseek-reasoner\n * / R1) and extracts a structured plan state by making a cheap secondary call\n * to V3 in JSON mode. The typed state is intended for the orchestrator to\n * branch on — e.g. trigger self-consistency sampling when `uncertainties.length\n * > 2`, or surface the subgoals to the user.\n *\n * Opt-in: loops disable harvesting by default. Failures (bad JSON, API error,\n * empty reasoning) return an empty TypedPlanState — the main turn is never\n * aborted because of a harvest hiccup.\n */\n\nimport type { DeepSeekClient } from \"./client.js\";\n\nexport interface TypedPlanState {\n subgoals: string[];\n hypotheses: string[];\n uncertainties: string[];\n rejectedPaths: string[];\n}\n\nexport interface HarvestOptions {\n /** Model used for the extraction call. Defaults to the cheap chat model. */\n model?: string;\n /** Cap on how many items land in each array. Default 5. */\n maxItems?: number;\n /** Per-item character cap. Default 80. */\n maxItemLen?: number;\n /** Abort the extraction if R1 reasoning is shorter than this. Default 40. */\n minReasoningLen?: number;\n}\n\nexport function emptyPlanState(): TypedPlanState {\n return { subgoals: [], hypotheses: [], uncertainties: [], rejectedPaths: [] };\n}\n\nexport function isPlanStateEmpty(s: TypedPlanState | null | undefined): boolean {\n if (!s) return true;\n return (\n s.subgoals.length === 0 &&\n s.hypotheses.length === 0 &&\n s.uncertainties.length === 0 &&\n s.rejectedPaths.length === 0\n );\n}\n\nconst SYSTEM_PROMPT = `You extract a typed plan state from a reasoning trace produced by another LLM.\nOutput ONLY a JSON object. No markdown, no prose, no backticks.\n\nSchema:\n{\n \"subgoals\": string[], // concrete intermediate objectives the trace identifies\n \"hypotheses\": string[], // candidate approaches or assumptions being weighed\n \"uncertainties\": string[], // facts the trace flags as unclear / to verify\n \"rejectedPaths\": string[] // approaches the trace considered and then abandoned\n}\n\nConstraints:\n- Every field must be present. Use [] if not applicable.\n- Each array has at most {maxItems} items.\n- Each item is plain text, at most {maxItemLen} characters, no markdown.\n- Write in the same language as the trace (Chinese in → Chinese out, etc.).\n- Do not quote back the trace; write short, specific phrases.`;\n\nexport async function harvest(\n reasoningContent: string | null | undefined,\n client?: DeepSeekClient,\n options: HarvestOptions = {},\n): Promise<TypedPlanState> {\n if (!client || !reasoningContent) return emptyPlanState();\n const minLen = options.minReasoningLen ?? 40;\n const trimmed = reasoningContent.trim();\n if (trimmed.length < minLen) return emptyPlanState();\n\n const model = options.model ?? \"deepseek-chat\";\n const maxItems = options.maxItems ?? 5;\n const maxItemLen = options.maxItemLen ?? 80;\n const system = SYSTEM_PROMPT.replace(\"{maxItems}\", String(maxItems)).replace(\n \"{maxItemLen}\",\n String(maxItemLen),\n );\n\n try {\n const resp = await client.chat({\n model,\n messages: [\n { role: \"system\", content: system },\n { role: \"user\", content: trimmed },\n ],\n responseFormat: { type: \"json_object\" },\n temperature: 0,\n maxTokens: 600,\n });\n return parsePlanState(resp.content, maxItems, maxItemLen);\n } catch {\n return emptyPlanState();\n }\n}\n\nfunction parsePlanState(raw: string, maxItems: number, maxItemLen: number): TypedPlanState {\n const text = (raw ?? \"\").trim();\n if (!text) return emptyPlanState();\n let parsed: unknown;\n try {\n parsed = JSON.parse(text);\n } catch {\n // Occasionally a model wraps JSON in fences despite instructions.\n const match = text.match(/\\{[\\s\\S]*\\}/);\n if (!match) return emptyPlanState();\n try {\n parsed = JSON.parse(match[0]);\n } catch {\n return emptyPlanState();\n }\n }\n if (!parsed || typeof parsed !== \"object\") return emptyPlanState();\n const obj = parsed as Record<string, unknown>;\n return {\n subgoals: sanitizeArray(obj.subgoals, maxItems, maxItemLen),\n hypotheses: sanitizeArray(obj.hypotheses, maxItems, maxItemLen),\n uncertainties: sanitizeArray(obj.uncertainties, maxItems, maxItemLen),\n rejectedPaths: sanitizeArray(obj.rejectedPaths ?? obj.rejected_paths, maxItems, maxItemLen),\n };\n}\n\nfunction sanitizeArray(raw: unknown, maxItems: number, maxItemLen: number): string[] {\n if (!Array.isArray(raw)) return [];\n const out: string[] = [];\n for (const item of raw) {\n if (out.length >= maxItems) break;\n if (typeof item !== \"string\") continue;\n const cleaned = item.trim().replace(/\\s+/g, \" \");\n if (!cleaned) continue;\n out.push(cleaned.length <= maxItemLen ? cleaned : `${cleaned.slice(0, maxItemLen - 1)}…`);\n }\n return out;\n}\n","import { createHash } from \"node:crypto\";\nimport type { ChatMessage, ToolSpec } from \"./types.js\";\n\nexport interface ImmutablePrefixOptions {\n system: string;\n toolSpecs?: readonly ToolSpec[];\n fewShots?: readonly ChatMessage[];\n}\n\nexport class ImmutablePrefix {\n readonly system: string;\n readonly toolSpecs: readonly ToolSpec[];\n readonly fewShots: readonly ChatMessage[];\n\n constructor(opts: ImmutablePrefixOptions) {\n this.system = opts.system;\n this.toolSpecs = Object.freeze([...(opts.toolSpecs ?? [])]);\n this.fewShots = Object.freeze([...(opts.fewShots ?? [])]);\n }\n\n toMessages(): ChatMessage[] {\n return [{ role: \"system\", content: this.system }, ...this.fewShots.map((m) => ({ ...m }))];\n }\n\n tools(): ToolSpec[] {\n return this.toolSpecs.map((t) => structuredClone(t) as ToolSpec);\n }\n\n get fingerprint(): string {\n const blob = JSON.stringify({\n system: this.system,\n tools: this.toolSpecs,\n shots: this.fewShots,\n });\n return createHash(\"sha256\").update(blob).digest(\"hex\").slice(0, 16);\n }\n}\n\nexport class AppendOnlyLog {\n private _entries: ChatMessage[] = [];\n\n append(message: ChatMessage): void {\n if (!message || typeof message !== \"object\" || !(\"role\" in message)) {\n throw new Error(`invalid log entry: ${JSON.stringify(message)}`);\n }\n this._entries.push(message);\n }\n\n extend(messages: ChatMessage[]): void {\n for (const m of messages) this.append(m);\n }\n\n get entries(): readonly ChatMessage[] {\n return this._entries;\n }\n\n toMessages(): ChatMessage[] {\n return this._entries.map((e) => ({ ...e }));\n }\n\n get length(): number {\n return this._entries.length;\n }\n}\n\nexport class VolatileScratch {\n reasoning: string | null = null;\n planState: Record<string, unknown> | null = null;\n notes: string[] = [];\n\n reset(): void {\n this.reasoning = null;\n this.planState = null;\n this.notes = [];\n }\n}\n","/**\n * Scavenge tool calls leaked into reasoning_content.\n *\n * R1 sometimes emits tool-call JSON inside <think>…</think> and then forgets\n * to surface it in `tool_calls`. This pass extracts plausible calls and\n * proposes them to the loop, which decides whether to merge them with the\n * declared calls.\n */\n\nimport type { ToolCall } from \"../types.js\";\n\nexport interface ScavengeOptions {\n /** Names of tools the model may legitimately call. Other names are ignored. */\n allowedNames: ReadonlySet<string>;\n /** Maximum number of calls to scavenge per pass (defence against runaway). */\n maxCalls?: number;\n}\n\nexport interface ScavengeResult {\n calls: ToolCall[];\n notes: string[];\n}\n\nexport function scavengeToolCalls(\n reasoningContent: string | null | undefined,\n opts: ScavengeOptions,\n): ScavengeResult {\n if (!reasoningContent) return { calls: [], notes: [] };\n const max = opts.maxCalls ?? 4;\n const notes: string[] = [];\n const out: ToolCall[] = [];\n\n for (const candidate of iterateJsonObjects(reasoningContent)) {\n if (out.length >= max) break;\n const call = coerceToToolCall(candidate, opts.allowedNames);\n if (call) {\n out.push(call);\n notes.push(`scavenged call: ${call.function.name}`);\n }\n }\n return { calls: out, notes };\n}\n\n/** Yield every top-level JSON object substring in `text`. */\nfunction* iterateJsonObjects(text: string): Generator<string> {\n for (let i = 0; i < text.length; i++) {\n if (text[i] !== \"{\") continue;\n let depth = 0;\n let inString = false;\n let escaped = false;\n for (let j = i; j < text.length; j++) {\n const c = text[j]!;\n if (escaped) {\n escaped = false;\n continue;\n }\n if (inString) {\n if (c === \"\\\\\") {\n escaped = true;\n continue;\n }\n if (c === '\"') inString = false;\n continue;\n }\n if (c === '\"') inString = true;\n else if (c === \"{\") depth++;\n else if (c === \"}\") {\n depth--;\n if (depth === 0) {\n yield text.slice(i, j + 1);\n i = j;\n break;\n }\n }\n }\n }\n}\n\nfunction coerceToToolCall(\n candidateJson: string,\n allowedNames: ReadonlySet<string>,\n): ToolCall | null {\n let parsed: any;\n try {\n parsed = JSON.parse(candidateJson);\n } catch {\n return null;\n }\n if (!parsed || typeof parsed !== \"object\") return null;\n\n // Pattern 1: { name, arguments }\n if (typeof parsed.name === \"string\" && allowedNames.has(parsed.name)) {\n const args = parsed.arguments;\n return {\n function: {\n name: parsed.name,\n arguments: typeof args === \"string\" ? args : JSON.stringify(args ?? {}),\n },\n };\n }\n\n // Pattern 2: OpenAI-style { type: \"function\", function: { name, arguments } }\n if (\n parsed.type === \"function\" &&\n parsed.function &&\n typeof parsed.function.name === \"string\" &&\n allowedNames.has(parsed.function.name)\n ) {\n const args = parsed.function.arguments;\n return {\n type: \"function\",\n function: {\n name: parsed.function.name,\n arguments: typeof args === \"string\" ? args : JSON.stringify(args ?? {}),\n },\n };\n }\n\n // Pattern 3: { tool_name, tool_args } (R1 free-form variant)\n if (typeof parsed.tool_name === \"string\" && allowedNames.has(parsed.tool_name)) {\n return {\n function: {\n name: parsed.tool_name,\n arguments: JSON.stringify(parsed.tool_args ?? {}),\n },\n };\n }\n\n return null;\n}\n","import type { ToolCall } from \"../types.js\";\n\n/**\n * Call-storm breaker.\n *\n * Detects (tool, args) tuples repeating within a sliding window and suppresses\n * the offending call. Surfaces a synthetic tool_result advising the model to\n * change strategy on its next turn.\n */\nexport class StormBreaker {\n private readonly windowSize: number;\n private readonly threshold: number;\n private readonly recent: Array<readonly [string, string]> = [];\n\n constructor(windowSize = 6, threshold = 3) {\n this.windowSize = windowSize;\n this.threshold = threshold;\n }\n\n inspect(call: ToolCall): { suppress: boolean; reason?: string } {\n const sig = signature(call);\n if (!sig) return { suppress: false };\n const count = this.recent.reduce(\n (n, [name, args]) => (name === sig[0] && args === sig[1] ? n + 1 : n),\n 0,\n );\n if (count >= this.threshold - 1) {\n return {\n suppress: true,\n reason: `call-storm suppressed: ${sig[0]} called with identical args ${count + 1} times within window=${this.windowSize}`,\n };\n }\n this.recent.push(sig);\n while (this.recent.length > this.windowSize) this.recent.shift();\n return { suppress: false };\n }\n\n reset(): void {\n this.recent.length = 0;\n }\n}\n\nfunction signature(call: ToolCall): readonly [string, string] | null {\n const name = call.function?.name;\n if (!name) return null;\n return [name, call.function?.arguments ?? \"\"] as const;\n}\n","/**\n * Truncation recovery for tool-call argument JSON cut off mid-structure\n * (typically when the model hits max_tokens before finishing the JSON object).\n *\n * Strategy is purely local: balance braces, close strings, fill missing values\n * with `null`. We deliberately do NOT make a continuation API call here — that\n * decision belongs to the loop, which knows about budgets.\n */\n\nexport interface TruncationRepairResult {\n repaired: string;\n changed: boolean;\n notes: string[];\n}\n\nexport function repairTruncatedJson(input: string): TruncationRepairResult {\n const notes: string[] = [];\n if (!input || !input.trim()) {\n return { repaired: \"{}\", changed: input !== \"{}\", notes: [\"empty input → {}\"] };\n }\n // Fast path: already parseable.\n try {\n JSON.parse(input);\n return { repaired: input, changed: false, notes: [] };\n } catch {\n /* fall through */\n }\n\n const stack: (\"{\" | \"[\" | '\"')[] = [];\n let escaped = false;\n let inString = false;\n let lastSignificant = -1;\n\n for (let i = 0; i < input.length; i++) {\n const c = input[i]!;\n if (!/\\s/.test(c)) lastSignificant = i;\n if (escaped) {\n escaped = false;\n continue;\n }\n if (inString) {\n if (c === \"\\\\\") {\n escaped = true;\n continue;\n }\n if (c === '\"') {\n inString = false;\n stack.pop();\n }\n continue;\n }\n if (c === '\"') {\n inString = true;\n stack.push('\"');\n continue;\n }\n if (c === \"{\" || c === \"[\") stack.push(c);\n else if (c === \"}\" || c === \"]\") stack.pop();\n }\n\n let s = input.slice(0, lastSignificant + 1);\n\n // Trim a trailing comma which would block re-parse.\n if (/,$/.test(s)) {\n s = s.replace(/,$/, \"\");\n notes.push(\"trimmed trailing comma\");\n }\n\n // If we ended on a key without a value: \"foo\": → \"foo\": null\n if (/\"\\s*:\\s*$/.test(s)) {\n s += \" null\";\n notes.push(\"filled dangling key with null\");\n }\n\n // If we ended inside a string, close it.\n if (inString) {\n s += '\"';\n stack.pop();\n notes.push(\"closed unterminated string\");\n }\n\n // Pop remaining open structures in reverse order.\n while (stack.length > 0) {\n const top = stack.pop();\n if (top === \"{\") s += \"}\";\n else if (top === \"[\") s += \"]\";\n else if (top === '\"') s += '\"';\n }\n\n try {\n JSON.parse(s);\n return { repaired: s, changed: true, notes };\n } catch (err) {\n notes.push(`fallback to {}: ${(err as Error).message}`);\n return { repaired: \"{}\", changed: true, notes };\n }\n}\n","/**\n * Schema flattening for DeepSeek tool calls.\n *\n * DeepSeek loses arguments on schemas that are deep (>2 levels of nesting) or\n * wide (>10 leaf parameters). This module transforms such schemas into a\n * dot-notation flat schema and re-nests the model's arguments before dispatch.\n *\n * Example:\n * { user: { profile: { name, age } } } ⇄ \"user.profile.name\", \"user.profile.age\"\n */\n\nimport type { JSONSchema } from \"../types.js\";\n\nexport interface FlattenDecision {\n shouldFlatten: boolean;\n leafCount: number;\n maxDepth: number;\n}\n\nexport function analyzeSchema(schema: JSONSchema | undefined): FlattenDecision {\n if (!schema) return { shouldFlatten: false, leafCount: 0, maxDepth: 0 };\n let leafCount = 0;\n let maxDepth = 0;\n walk(schema, 0, (depth, isLeaf) => {\n if (isLeaf) leafCount++;\n if (depth > maxDepth) maxDepth = depth;\n });\n return {\n shouldFlatten: leafCount > 10 || maxDepth > 2,\n leafCount,\n maxDepth,\n };\n}\n\nexport function flattenSchema(schema: JSONSchema): JSONSchema {\n const flatProps: Record<string, JSONSchema> = {};\n const required: string[] = [];\n collect(\"\", schema, flatProps, required, true);\n return {\n type: \"object\",\n properties: flatProps,\n required,\n };\n}\n\nexport function nestArguments(flatArgs: Record<string, unknown>): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(flatArgs)) {\n setByPath(out, key.split(\".\"), value);\n }\n return out;\n}\n\nfunction walk(\n schema: JSONSchema,\n depth: number,\n visit: (depth: number, isLeaf: boolean) => void,\n): void {\n if (schema.type === \"object\" && schema.properties) {\n for (const child of Object.values(schema.properties)) {\n walk(child, depth + 1, visit);\n }\n return;\n }\n if (schema.type === \"array\" && schema.items) {\n walk(schema.items, depth + 1, visit);\n return;\n }\n visit(depth, true);\n}\n\nfunction collect(\n prefix: string,\n schema: JSONSchema,\n out: Record<string, JSONSchema>,\n required: string[],\n isRootRequired: boolean,\n): void {\n if (schema.type === \"object\" && schema.properties) {\n const requiredSet = new Set(schema.required ?? []);\n for (const [key, child] of Object.entries(schema.properties)) {\n const nextPrefix = prefix ? `${prefix}.${key}` : key;\n const childRequired = isRootRequired && requiredSet.has(key);\n collect(nextPrefix, child, out, required, childRequired);\n }\n return;\n }\n // Treat anything non-object (including arrays) as a leaf for flattening purposes.\n out[prefix] = schema;\n if (isRootRequired) required.push(prefix);\n}\n\nfunction setByPath(target: Record<string, unknown>, path: string[], value: unknown): void {\n let cur: any = target;\n for (let i = 0; i < path.length - 1; i++) {\n const key = path[i]!;\n if (typeof cur[key] !== \"object\" || cur[key] === null) cur[key] = {};\n cur = cur[key];\n }\n cur[path[path.length - 1]!] = value;\n}\n","/**\n * Pillar 3 — Tool-Call Repair pipeline.\n *\n * Order of passes per turn:\n * 1. scavenge — recover tool calls leaked into <think>\n * 2. truncation — close any half-emitted argument JSON\n * 3. storm breaker — drop call-storm repeats\n *\n * Schema flattening is applied during loop construction (it changes what we\n * advertise to the model), not per-turn.\n */\n\nimport type { ToolCall } from \"../types.js\";\nimport { scavengeToolCalls } from \"./scavenge.js\";\nimport { StormBreaker } from \"./storm.js\";\nimport { repairTruncatedJson } from \"./truncation.js\";\n\nexport { analyzeSchema, flattenSchema, nestArguments } from \"./flatten.js\";\nexport type { FlattenDecision } from \"./flatten.js\";\nexport { repairTruncatedJson } from \"./truncation.js\";\nexport type { TruncationRepairResult } from \"./truncation.js\";\nexport { scavengeToolCalls } from \"./scavenge.js\";\nexport type { ScavengeOptions, ScavengeResult } from \"./scavenge.js\";\nexport { StormBreaker } from \"./storm.js\";\n\nexport interface RepairReport {\n scavenged: number;\n truncationsFixed: number;\n stormsBroken: number;\n notes: string[];\n}\n\nexport interface ToolCallRepairOptions {\n allowedToolNames: ReadonlySet<string>;\n stormWindow?: number;\n stormThreshold?: number;\n maxScavenge?: number;\n}\n\nexport class ToolCallRepair {\n private readonly storm: StormBreaker;\n private readonly opts: ToolCallRepairOptions;\n\n constructor(opts: ToolCallRepairOptions) {\n this.opts = opts;\n this.storm = new StormBreaker(opts.stormWindow ?? 6, opts.stormThreshold ?? 3);\n }\n\n process(\n declaredCalls: ToolCall[],\n reasoningContent: string | null,\n ): { calls: ToolCall[]; report: RepairReport } {\n const report: RepairReport = {\n scavenged: 0,\n truncationsFixed: 0,\n stormsBroken: 0,\n notes: [],\n };\n\n // 1. Scavenge — only add calls whose (name,args) signature is novel.\n const scavenged = scavengeToolCalls(reasoningContent, {\n allowedNames: this.opts.allowedToolNames,\n maxCalls: this.opts.maxScavenge ?? 4,\n });\n const seenSignatures = new Set(declaredCalls.map(signature));\n const merged = [...declaredCalls];\n for (const sc of scavenged.calls) {\n if (!seenSignatures.has(signature(sc))) {\n merged.push(sc);\n report.scavenged++;\n seenSignatures.add(signature(sc));\n }\n }\n report.notes.push(...scavenged.notes);\n\n // 2. Truncation repair on argument JSON.\n for (const call of merged) {\n const args = call.function?.arguments ?? \"\";\n const r = repairTruncatedJson(args);\n if (r.changed) {\n call.function.arguments = r.repaired;\n report.truncationsFixed++;\n report.notes.push(...r.notes.map((n) => `[${call.function.name}] ${n}`));\n }\n }\n\n // 3. Storm breaker.\n const filtered: ToolCall[] = [];\n for (const call of merged) {\n const verdict = this.storm.inspect(call);\n if (verdict.suppress) {\n report.stormsBroken++;\n if (verdict.reason) report.notes.push(verdict.reason);\n continue;\n }\n filtered.push(call);\n }\n\n return { calls: filtered, report };\n }\n}\n\nfunction signature(call: ToolCall): string {\n return `${call.function?.name ?? \"\"}::${call.function?.arguments ?? \"\"}`;\n}\n","import type { Usage } from \"./client.js\";\n\n/** USD per 1M tokens. Update as DeepSeek pricing changes. */\nexport const DEEPSEEK_PRICING: Record<\n string,\n { inputCacheHit: number; inputCacheMiss: number; output: number }\n> = {\n \"deepseek-chat\": { inputCacheHit: 0.07, inputCacheMiss: 0.27, output: 1.1 },\n \"deepseek-reasoner\": { inputCacheHit: 0.14, inputCacheMiss: 0.55, output: 2.19 },\n};\n\n/** Reference Claude Sonnet 4.6 pricing (USD per 1M tokens). */\nexport const CLAUDE_SONNET_PRICING = { input: 3.0, output: 15.0 };\n\nexport function costUsd(model: string, usage: Usage): number {\n const p = DEEPSEEK_PRICING[model];\n if (!p) return 0;\n return (\n (usage.promptCacheHitTokens * p.inputCacheHit +\n usage.promptCacheMissTokens * p.inputCacheMiss +\n usage.completionTokens * p.output) /\n 1_000_000\n );\n}\n\nexport function claudeEquivalentCost(usage: Usage): number {\n return (\n (usage.promptTokens * CLAUDE_SONNET_PRICING.input +\n usage.completionTokens * CLAUDE_SONNET_PRICING.output) /\n 1_000_000\n );\n}\n\nexport interface TurnStats {\n turn: number;\n model: string;\n usage: Usage;\n cost: number;\n cacheHitRatio: number;\n}\n\nexport interface SessionSummary {\n turns: number;\n totalCostUsd: number;\n claudeEquivalentUsd: number;\n savingsVsClaudePct: number;\n cacheHitRatio: number;\n}\n\nexport class SessionStats {\n readonly turns: TurnStats[] = [];\n\n record(turn: number, model: string, usage: Usage): TurnStats {\n const cost = costUsd(model, usage);\n const stats: TurnStats = {\n turn,\n model,\n usage,\n cost,\n cacheHitRatio: usage.cacheHitRatio,\n };\n this.turns.push(stats);\n return stats;\n }\n\n get totalCost(): number {\n return this.turns.reduce((sum, t) => sum + t.cost, 0);\n }\n\n get totalClaudeEquivalent(): number {\n return this.turns.reduce((sum, t) => sum + claudeEquivalentCost(t.usage), 0);\n }\n\n get savingsVsClaude(): number {\n const c = this.totalClaudeEquivalent;\n return c > 0 ? 1 - this.totalCost / c : 0;\n }\n\n get aggregateCacheHitRatio(): number {\n let hit = 0;\n let miss = 0;\n for (const t of this.turns) {\n hit += t.usage.promptCacheHitTokens;\n miss += t.usage.promptCacheMissTokens;\n }\n const denom = hit + miss;\n return denom > 0 ? hit / denom : 0;\n }\n\n summary(): SessionSummary {\n return {\n turns: this.turns.length,\n totalCostUsd: round(this.totalCost, 6),\n claudeEquivalentUsd: round(this.totalClaudeEquivalent, 6),\n savingsVsClaudePct: round(this.savingsVsClaude * 100, 2),\n cacheHitRatio: round(this.aggregateCacheHitRatio, 4),\n };\n }\n}\n\nfunction round(n: number, digits: number): number {\n const f = 10 ** digits;\n return Math.round(n * f) / f;\n}\n","import { analyzeSchema, flattenSchema, nestArguments } from \"./repair/flatten.js\";\nimport type { JSONSchema, ToolSpec } from \"./types.js\";\n\nexport interface ToolDefinition<A = any, R = any> {\n name: string;\n description?: string;\n parameters?: JSONSchema;\n fn: (args: A) => R | Promise<R>;\n}\n\ninterface InternalTool extends ToolDefinition {\n /**\n * Pillar 3 — flatten metadata. Set when the registered schema is deep\n * (>2 levels) or wide (>10 leaf params), conditions on which DeepSeek\n * V3/R1 are known to drop arguments. We advertise the flattened schema\n * to the model, then re-nest the model's args before calling fn.\n */\n flatSchema?: JSONSchema;\n}\n\nexport interface ToolRegistryOptions {\n /**\n * Auto-flatten schemas that exceed depth/width thresholds before sending\n * them to the model. Re-nests arguments transparently on dispatch.\n * Default: true. Pass false to opt out.\n */\n autoFlatten?: boolean;\n}\n\nexport class ToolRegistry {\n private readonly _tools = new Map<string, InternalTool>();\n private readonly _autoFlatten: boolean;\n\n constructor(opts: ToolRegistryOptions = {}) {\n this._autoFlatten = opts.autoFlatten !== false;\n }\n\n register<A, R>(def: ToolDefinition<A, R>): this {\n if (!def.name) throw new Error(\"tool requires a name\");\n const internal: InternalTool = { ...(def as ToolDefinition) };\n if (this._autoFlatten && def.parameters) {\n const decision = analyzeSchema(def.parameters);\n if (decision.shouldFlatten) {\n internal.flatSchema = flattenSchema(def.parameters);\n }\n }\n this._tools.set(def.name, internal);\n return this;\n }\n\n has(name: string): boolean {\n return this._tools.has(name);\n }\n\n get(name: string): ToolDefinition | undefined {\n return this._tools.get(name);\n }\n\n get size(): number {\n return this._tools.size;\n }\n\n /** True if a registered tool's schema was flattened for the model. */\n wasFlattened(name: string): boolean {\n return Boolean(this._tools.get(name)?.flatSchema);\n }\n\n specs(): ToolSpec[] {\n return [...this._tools.values()].map((t) => ({\n type: \"function\",\n function: {\n name: t.name,\n description: t.description ?? \"\",\n parameters: t.flatSchema ?? t.parameters ?? { type: \"object\", properties: {} },\n },\n }));\n }\n\n async dispatch(name: string, argumentsRaw: string | Record<string, unknown>): Promise<string> {\n const tool = this._tools.get(name);\n if (!tool) {\n return JSON.stringify({ error: `unknown tool: ${name}` });\n }\n let args: Record<string, unknown>;\n try {\n args =\n typeof argumentsRaw === \"string\"\n ? argumentsRaw.trim()\n ? (JSON.parse(argumentsRaw) ?? {})\n : {}\n : (argumentsRaw ?? {});\n } catch (err) {\n return JSON.stringify({\n error: `invalid tool arguments JSON: ${(err as Error).message}`,\n });\n }\n\n // Re-nest dot-notation args back to the original shape, but only when\n // (a) we flattened this tool's schema, AND\n // (b) the incoming args actually use dot keys.\n // The second condition handles the case where a model ignores the flat\n // spec and emits nested args anyway — we shouldn't double-process them.\n if (tool.flatSchema && args && typeof args === \"object\" && hasDotKey(args)) {\n args = nestArguments(args);\n }\n\n try {\n const result = await tool.fn(args);\n return typeof result === \"string\" ? result : JSON.stringify(result);\n } catch (err) {\n return JSON.stringify({\n error: `${(err as Error).name}: ${(err as Error).message}`,\n });\n }\n }\n}\n\nfunction hasDotKey(obj: Record<string, unknown>): boolean {\n for (const k of Object.keys(obj)) {\n if (k.includes(\".\")) return true;\n }\n return false;\n}\n","import type { DeepSeekClient } from \"./client.js\";\nimport { type HarvestOptions, type TypedPlanState, emptyPlanState, harvest } from \"./harvest.js\";\nimport { AppendOnlyLog, type ImmutablePrefix, VolatileScratch } from \"./memory.js\";\nimport { type RepairReport, ToolCallRepair } from \"./repair/index.js\";\nimport { SessionStats, type TurnStats } from \"./telemetry.js\";\nimport { ToolRegistry } from \"./tools.js\";\nimport type { ChatMessage, ToolCall } from \"./types.js\";\n\nexport type EventRole = \"assistant_delta\" | \"assistant_final\" | \"tool\" | \"done\" | \"error\";\n\nexport interface LoopEvent {\n turn: number;\n role: EventRole;\n content: string;\n reasoningDelta?: string;\n toolName?: string;\n stats?: TurnStats;\n planState?: TypedPlanState;\n repair?: RepairReport;\n error?: string;\n}\n\nexport interface CacheFirstLoopOptions {\n client: DeepSeekClient;\n prefix: ImmutablePrefix;\n tools?: ToolRegistry;\n model?: string;\n maxToolIters?: number;\n stream?: boolean;\n /**\n * Pillar 2 — structured harvesting of R1 reasoning into a typed plan state.\n * Pass `true` for defaults or an options object. Off by default (adds a\n * cheap but non-zero V3 call per turn).\n */\n harvest?: boolean | HarvestOptions;\n}\n\n/**\n * Pillar 1 — Cache-First Loop.\n *\n * - prefix is immutable (cache target)\n * - log is append-only (preserves prior-turn prefix)\n * - scratch is per-turn volatile (never sent upstream)\n *\n * Yields a stream of events so a TUI can render progressively.\n */\nexport class CacheFirstLoop {\n readonly client: DeepSeekClient;\n readonly prefix: ImmutablePrefix;\n readonly tools: ToolRegistry;\n readonly model: string;\n readonly maxToolIters: number;\n readonly stream: boolean;\n readonly harvestEnabled: boolean;\n readonly harvestOptions: HarvestOptions;\n readonly log = new AppendOnlyLog();\n readonly scratch = new VolatileScratch();\n readonly stats = new SessionStats();\n readonly repair: ToolCallRepair;\n private _turn = 0;\n\n constructor(opts: CacheFirstLoopOptions) {\n this.client = opts.client;\n this.prefix = opts.prefix;\n this.tools = opts.tools ?? new ToolRegistry();\n this.model = opts.model ?? \"deepseek-chat\";\n this.maxToolIters = opts.maxToolIters ?? 8;\n this.stream = opts.stream ?? true;\n this.harvestEnabled =\n opts.harvest === true || (typeof opts.harvest === \"object\" && opts.harvest !== null);\n this.harvestOptions =\n typeof opts.harvest === \"object\" && opts.harvest !== null ? opts.harvest : {};\n const allowedNames = new Set([...this.prefix.toolSpecs.map((s) => s.function.name)]);\n this.repair = new ToolCallRepair({ allowedToolNames: allowedNames });\n }\n\n private buildMessages(pendingUser: string | null): ChatMessage[] {\n const msgs: ChatMessage[] = [...this.prefix.toMessages(), ...this.log.toMessages()];\n if (pendingUser !== null) msgs.push({ role: \"user\", content: pendingUser });\n return msgs;\n }\n\n async *step(userInput: string): AsyncGenerator<LoopEvent> {\n this._turn++;\n this.scratch.reset();\n let pendingUser: string | null = userInput;\n const toolSpecs = this.prefix.tools();\n\n for (let iter = 0; iter < this.maxToolIters; iter++) {\n const messages = this.buildMessages(pendingUser);\n\n let assistantContent = \"\";\n let reasoningContent = \"\";\n let toolCalls: ToolCall[] = [];\n let usage: TurnStats[\"usage\"] | null = null;\n\n try {\n if (this.stream) {\n const callBuf: Map<number, ToolCall> = new Map();\n for await (const chunk of this.client.stream({\n model: this.model,\n messages,\n tools: toolSpecs.length ? toolSpecs : undefined,\n })) {\n if (chunk.contentDelta) {\n assistantContent += chunk.contentDelta;\n yield {\n turn: this._turn,\n role: \"assistant_delta\",\n content: chunk.contentDelta,\n };\n }\n if (chunk.reasoningDelta) {\n reasoningContent += chunk.reasoningDelta;\n yield {\n turn: this._turn,\n role: \"assistant_delta\",\n content: \"\",\n reasoningDelta: chunk.reasoningDelta,\n };\n }\n if (chunk.toolCallDelta) {\n const d = chunk.toolCallDelta;\n const cur = callBuf.get(d.index) ?? {\n id: d.id,\n type: \"function\" as const,\n function: { name: \"\", arguments: \"\" },\n };\n if (d.id) cur.id = d.id;\n if (d.name) cur.function.name = (cur.function.name ?? \"\") + d.name;\n if (d.argumentsDelta)\n cur.function.arguments = (cur.function.arguments ?? \"\") + d.argumentsDelta;\n callBuf.set(d.index, cur);\n }\n if (chunk.usage) usage = chunk.usage;\n }\n toolCalls = [...callBuf.values()];\n } else {\n const resp = await this.client.chat({\n model: this.model,\n messages,\n tools: toolSpecs.length ? toolSpecs : undefined,\n });\n assistantContent = resp.content;\n reasoningContent = resp.reasoningContent ?? \"\";\n toolCalls = resp.toolCalls;\n usage = resp.usage;\n }\n } catch (err) {\n yield {\n turn: this._turn,\n role: \"error\",\n content: \"\",\n error: (err as Error).message,\n };\n return;\n }\n\n const turnStats = this.stats.record(\n this._turn,\n this.model,\n usage ?? new (await import(\"./client.js\")).Usage(),\n );\n\n // Commit the user turn to the log only on success of the first round-trip.\n if (pendingUser !== null) {\n this.log.append({ role: \"user\", content: pendingUser });\n pendingUser = null;\n }\n\n this.scratch.reasoning = reasoningContent || null;\n const planState = this.harvestEnabled\n ? await harvest(reasoningContent || null, this.client, this.harvestOptions)\n : emptyPlanState();\n\n const { calls: repairedCalls, report } = this.repair.process(\n toolCalls,\n reasoningContent || null,\n );\n\n this.log.append(this.assistantMessage(assistantContent, repairedCalls));\n\n yield {\n turn: this._turn,\n role: \"assistant_final\",\n content: assistantContent,\n stats: turnStats,\n planState,\n repair: report,\n };\n\n if (repairedCalls.length === 0) {\n yield { turn: this._turn, role: \"done\", content: assistantContent };\n return;\n }\n\n for (const call of repairedCalls) {\n const name = call.function?.name ?? \"\";\n const args = call.function?.arguments ?? \"{}\";\n const result = await this.tools.dispatch(name, args);\n this.log.append({\n role: \"tool\",\n tool_call_id: call.id ?? \"\",\n name,\n content: result,\n });\n yield { turn: this._turn, role: \"tool\", content: result, toolName: name };\n }\n }\n\n yield { turn: this._turn, role: \"done\", content: \"[max_tool_iters reached]\" };\n }\n\n async run(userInput: string, onEvent?: (ev: LoopEvent) => void): Promise<string> {\n let final = \"\";\n for await (const ev of this.step(userInput)) {\n onEvent?.(ev);\n if (ev.role === \"assistant_final\") final = ev.content;\n if (ev.role === \"done\") break;\n }\n return final;\n }\n\n private assistantMessage(content: string, toolCalls: ToolCall[]): ChatMessage {\n const msg: ChatMessage = { role: \"assistant\", content };\n if (toolCalls.length > 0) msg.tool_calls = toolCalls;\n return msg;\n }\n}\n","import { readFileSync } from \"node:fs\";\nimport { resolve } from \"node:path\";\n\n/**\n * Minimal `.env` loader; no dependency on dotenv.\n *\n * Reads KEY=VALUE lines and populates `process.env` for keys not already set.\n * Silently no-ops if the file is missing. Safe to call from library entry\n * points, CLI commands, examples, and benchmark runners.\n */\nexport function loadDotenv(path = \".env\"): void {\n let raw: string;\n try {\n raw = readFileSync(resolve(process.cwd(), path), \"utf8\");\n } catch {\n return;\n }\n for (const line of raw.split(/\\r?\\n/)) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith(\"#\")) continue;\n const eq = trimmed.indexOf(\"=\");\n if (eq === -1) continue;\n const key = trimmed.slice(0, eq).trim();\n let value = trimmed.slice(eq + 1).trim();\n if (\n (value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))\n ) {\n value = value.slice(1, -1);\n }\n if (process.env[key] === undefined) process.env[key] = value;\n }\n}\n","/**\n * User-level config storage for the Reasonix CLI.\n *\n * Lookup order for the API key:\n * 1. `DEEPSEEK_API_KEY` env var (highest priority — for CI / power users)\n * 2. `~/.reasonix/config.json` (set by the first-run setup flow)\n *\n * The library itself never touches the config file — it only reads\n * `DEEPSEEK_API_KEY` from the environment. The CLI is responsible for\n * pulling from the config file and exposing it via env var to the loop.\n */\n\nimport { chmodSync, mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { dirname, join } from \"node:path\";\n\nexport interface ReasonixConfig {\n apiKey?: string;\n baseUrl?: string;\n}\n\nexport function defaultConfigPath(): string {\n return join(homedir(), \".reasonix\", \"config.json\");\n}\n\nexport function readConfig(path: string = defaultConfigPath()): ReasonixConfig {\n try {\n const raw = readFileSync(path, \"utf8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\") return parsed as ReasonixConfig;\n } catch {\n /* missing or malformed → empty config */\n }\n return {};\n}\n\nexport function writeConfig(cfg: ReasonixConfig, path: string = defaultConfigPath()): void {\n mkdirSync(dirname(path), { recursive: true });\n writeFileSync(path, JSON.stringify(cfg, null, 2), \"utf8\");\n // Restrict permissions on Unix; chmod is a no-op on Windows but won't throw.\n try {\n chmodSync(path, 0o600);\n } catch {\n /* ignore on platforms without chmod */\n }\n}\n\n/** Resolve the API key from env var first, then the config file. */\nexport function loadApiKey(path: string = defaultConfigPath()): string | undefined {\n if (process.env.DEEPSEEK_API_KEY) return process.env.DEEPSEEK_API_KEY;\n return readConfig(path).apiKey;\n}\n\nexport function saveApiKey(key: string, path: string = defaultConfigPath()): void {\n const cfg = readConfig(path);\n cfg.apiKey = key.trim();\n writeConfig(cfg, path);\n}\n\nexport function isPlausibleKey(key: string): boolean {\n const trimmed = key.trim();\n return /^sk-[A-Za-z0-9_-]{16,}$/.test(trimmed);\n}\n\n/** Mask a key for display: `sk-abcd...wxyz`. */\nexport function redactKey(key: string): string {\n if (!key) return \"\";\n if (key.length <= 12) return \"****\";\n return `${key.slice(0, 6)}…${key.slice(-4)}`;\n}\n","/** Reasonix — DeepSeek-native agent framework. Library entry point. */\n\nexport { DeepSeekClient, Usage } from \"./client.js\";\nexport type { ChatResponse, StreamChunk, DeepSeekClientOptions } from \"./client.js\";\n\nexport { CacheFirstLoop } from \"./loop.js\";\nexport type { CacheFirstLoopOptions, LoopEvent, EventRole } from \"./loop.js\";\n\nexport { ImmutablePrefix, AppendOnlyLog, VolatileScratch } from \"./memory.js\";\nexport type { ImmutablePrefixOptions } from \"./memory.js\";\n\nexport { ToolRegistry } from \"./tools.js\";\nexport type { ToolDefinition } from \"./tools.js\";\n\nexport { SessionStats, costUsd, claudeEquivalentCost } from \"./telemetry.js\";\nexport type { TurnStats, SessionSummary } from \"./telemetry.js\";\n\nexport {\n ToolCallRepair,\n scavengeToolCalls,\n repairTruncatedJson,\n StormBreaker,\n analyzeSchema,\n flattenSchema,\n nestArguments,\n} from \"./repair/index.js\";\nexport type {\n RepairReport,\n ToolCallRepairOptions,\n ScavengeOptions,\n ScavengeResult,\n TruncationRepairResult,\n FlattenDecision,\n} from \"./repair/index.js\";\n\nexport { harvest, emptyPlanState, isPlanStateEmpty } from \"./harvest.js\";\nexport type { TypedPlanState, HarvestOptions } from \"./harvest.js\";\n\nexport { loadDotenv } from \"./env.js\";\n\nexport { fetchWithRetry } from \"./retry.js\";\nexport type { RetryOptions, RetryInfo } from \"./retry.js\";\n\nexport {\n defaultConfigPath,\n isPlausibleKey,\n loadApiKey,\n readConfig,\n redactKey,\n saveApiKey,\n writeConfig,\n} from \"./config.js\";\nexport type { ReasonixConfig } from \"./config.js\";\n\nexport type {\n ChatMessage,\n ToolCall,\n ToolSpec,\n ToolFunctionSpec,\n Role,\n JSONSchema,\n} from \"./types.js\";\n\nexport const VERSION = \"0.0.1\";\n"],"mappings":";;;;;;;AAkCO,SAAS,iBAAiC;AAC/C,SAAO,EAAE,UAAU,CAAC,GAAG,YAAY,CAAC,GAAG,eAAe,CAAC,GAAG,eAAe,CAAC,EAAE;AAC9E;AAEO,SAAS,iBAAiB,GAA+C;AAC9E,MAAI,CAAC,EAAG,QAAO;AACf,SACE,EAAE,SAAS,WAAW,KACtB,EAAE,WAAW,WAAW,KACxB,EAAE,cAAc,WAAW,KAC3B,EAAE,cAAc,WAAW;AAE/B;AAEA,IAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkBtB,eAAsB,QACpB,kBACA,QACA,UAA0B,CAAC,GACF;AACzB,MAAI,CAAC,UAAU,CAAC,iBAAkB,QAAO,eAAe;AACxD,QAAM,SAAS,QAAQ,mBAAmB;AAC1C,QAAM,UAAU,iBAAiB,KAAK;AACtC,MAAI,QAAQ,SAAS,OAAQ,QAAO,eAAe;AAEnD,QAAM,QAAQ,QAAQ,SAAS;AAC/B,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,aAAa,QAAQ,cAAc;AACzC,QAAM,SAAS,cAAc,QAAQ,cAAc,OAAO,QAAQ,CAAC,EAAE;AAAA,IACnE;AAAA,IACA,OAAO,UAAU;AAAA,EACnB;AAEA,MAAI;AACF,UAAM,OAAO,MAAM,OAAO,KAAK;AAAA,MAC7B;AAAA,MACA,UAAU;AAAA,QACR,EAAE,MAAM,UAAU,SAAS,OAAO;AAAA,QAClC,EAAE,MAAM,QAAQ,SAAS,QAAQ;AAAA,MACnC;AAAA,MACA,gBAAgB,EAAE,MAAM,cAAc;AAAA,MACtC,aAAa;AAAA,MACb,WAAW;AAAA,IACb,CAAC;AACD,WAAO,eAAe,KAAK,SAAS,UAAU,UAAU;AAAA,EAC1D,QAAQ;AACN,WAAO,eAAe;AAAA,EACxB;AACF;AAEA,SAAS,eAAe,KAAa,UAAkB,YAAoC;AACzF,QAAM,QAAQ,OAAO,IAAI,KAAK;AAC9B,MAAI,CAAC,KAAM,QAAO,eAAe;AACjC,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,IAAI;AAAA,EAC1B,QAAQ;AAEN,UAAM,QAAQ,KAAK,MAAM,aAAa;AACtC,QAAI,CAAC,MAAO,QAAO,eAAe;AAClC,QAAI;AACF,eAAS,KAAK,MAAM,MAAM,CAAC,CAAC;AAAA,IAC9B,QAAQ;AACN,aAAO,eAAe;AAAA,IACxB;AAAA,EACF;AACA,MAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO,eAAe;AACjE,QAAM,MAAM;AACZ,SAAO;AAAA,IACL,UAAU,cAAc,IAAI,UAAU,UAAU,UAAU;AAAA,IAC1D,YAAY,cAAc,IAAI,YAAY,UAAU,UAAU;AAAA,IAC9D,eAAe,cAAc,IAAI,eAAe,UAAU,UAAU;AAAA,IACpE,eAAe,cAAc,IAAI,iBAAiB,IAAI,gBAAgB,UAAU,UAAU;AAAA,EAC5F;AACF;AAEA,SAAS,cAAc,KAAc,UAAkB,YAA8B;AACnF,MAAI,CAAC,MAAM,QAAQ,GAAG,EAAG,QAAO,CAAC;AACjC,QAAM,MAAgB,CAAC;AACvB,aAAW,QAAQ,KAAK;AACtB,QAAI,IAAI,UAAU,SAAU;AAC5B,QAAI,OAAO,SAAS,SAAU;AAC9B,UAAM,UAAU,KAAK,KAAK,EAAE,QAAQ,QAAQ,GAAG;AAC/C,QAAI,CAAC,QAAS;AACd,QAAI,KAAK,QAAQ,UAAU,aAAa,UAAU,GAAG,QAAQ,MAAM,GAAG,aAAa,CAAC,CAAC,QAAG;AAAA,EAC1F;AACA,SAAO;AACT;;;AC1IA,SAAS,kBAAkB;AASpB,IAAM,kBAAN,MAAsB;AAAA,EAClB;AAAA,EACA;AAAA,EACA;AAAA,EAET,YAAY,MAA8B;AACxC,SAAK,SAAS,KAAK;AACnB,SAAK,YAAY,OAAO,OAAO,CAAC,GAAI,KAAK,aAAa,CAAC,CAAE,CAAC;AAC1D,SAAK,WAAW,OAAO,OAAO,CAAC,GAAI,KAAK,YAAY,CAAC,CAAE,CAAC;AAAA,EAC1D;AAAA,EAEA,aAA4B;AAC1B,WAAO,CAAC,EAAE,MAAM,UAAU,SAAS,KAAK,OAAO,GAAG,GAAG,KAAK,SAAS,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC;AAAA,EAC3F;AAAA,EAEA,QAAoB;AAClB,WAAO,KAAK,UAAU,IAAI,CAAC,MAAM,gBAAgB,CAAC,CAAa;AAAA,EACjE;AAAA,EAEA,IAAI,cAAsB;AACxB,UAAM,OAAO,KAAK,UAAU;AAAA,MAC1B,QAAQ,KAAK;AAAA,MACb,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK;AAAA,IACd,CAAC;AACD,WAAO,WAAW,QAAQ,EAAE,OAAO,IAAI,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AAAA,EACpE;AACF;AAEO,IAAM,gBAAN,MAAoB;AAAA,EACjB,WAA0B,CAAC;AAAA,EAEnC,OAAO,SAA4B;AACjC,QAAI,CAAC,WAAW,OAAO,YAAY,YAAY,EAAE,UAAU,UAAU;AACnE,YAAM,IAAI,MAAM,sBAAsB,KAAK,UAAU,OAAO,CAAC,EAAE;AAAA,IACjE;AACA,SAAK,SAAS,KAAK,OAAO;AAAA,EAC5B;AAAA,EAEA,OAAO,UAA+B;AACpC,eAAW,KAAK,SAAU,MAAK,OAAO,CAAC;AAAA,EACzC;AAAA,EAEA,IAAI,UAAkC;AACpC,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,aAA4B;AAC1B,WAAO,KAAK,SAAS,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE;AAAA,EAC5C;AAAA,EAEA,IAAI,SAAiB;AACnB,WAAO,KAAK,SAAS;AAAA,EACvB;AACF;AAEO,IAAM,kBAAN,MAAsB;AAAA,EAC3B,YAA2B;AAAA,EAC3B,YAA4C;AAAA,EAC5C,QAAkB,CAAC;AAAA,EAEnB,QAAc;AACZ,SAAK,YAAY;AACjB,SAAK,YAAY;AACjB,SAAK,QAAQ,CAAC;AAAA,EAChB;AACF;;;ACpDO,SAAS,kBACd,kBACA,MACgB;AAChB,MAAI,CAAC,iBAAkB,QAAO,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,EAAE;AACrD,QAAM,MAAM,KAAK,YAAY;AAC7B,QAAM,QAAkB,CAAC;AACzB,QAAM,MAAkB,CAAC;AAEzB,aAAW,aAAa,mBAAmB,gBAAgB,GAAG;AAC5D,QAAI,IAAI,UAAU,IAAK;AACvB,UAAM,OAAO,iBAAiB,WAAW,KAAK,YAAY;AAC1D,QAAI,MAAM;AACR,UAAI,KAAK,IAAI;AACb,YAAM,KAAK,mBAAmB,KAAK,SAAS,IAAI,EAAE;AAAA,IACpD;AAAA,EACF;AACA,SAAO,EAAE,OAAO,KAAK,MAAM;AAC7B;AAGA,UAAU,mBAAmB,MAAiC;AAC5D,WAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,QAAI,KAAK,CAAC,MAAM,IAAK;AACrB,QAAI,QAAQ;AACZ,QAAI,WAAW;AACf,QAAI,UAAU;AACd,aAAS,IAAI,GAAG,IAAI,KAAK,QAAQ,KAAK;AACpC,YAAM,IAAI,KAAK,CAAC;AAChB,UAAI,SAAS;AACX,kBAAU;AACV;AAAA,MACF;AACA,UAAI,UAAU;AACZ,YAAI,MAAM,MAAM;AACd,oBAAU;AACV;AAAA,QACF;AACA,YAAI,MAAM,IAAK,YAAW;AAC1B;AAAA,MACF;AACA,UAAI,MAAM,IAAK,YAAW;AAAA,eACjB,MAAM,IAAK;AAAA,eACX,MAAM,KAAK;AAClB;AACA,YAAI,UAAU,GAAG;AACf,gBAAM,KAAK,MAAM,GAAG,IAAI,CAAC;AACzB,cAAI;AACJ;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,iBACP,eACA,cACiB;AACjB,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,aAAa;AAAA,EACnC,QAAQ;AACN,WAAO;AAAA,EACT;AACA,MAAI,CAAC,UAAU,OAAO,WAAW,SAAU,QAAO;AAGlD,MAAI,OAAO,OAAO,SAAS,YAAY,aAAa,IAAI,OAAO,IAAI,GAAG;AACpE,UAAM,OAAO,OAAO;AACpB,WAAO;AAAA,MACL,UAAU;AAAA,QACR,MAAM,OAAO;AAAA,QACb,WAAW,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,QAAQ,CAAC,CAAC;AAAA,MACxE;AAAA,IACF;AAAA,EACF;AAGA,MACE,OAAO,SAAS,cAChB,OAAO,YACP,OAAO,OAAO,SAAS,SAAS,YAChC,aAAa,IAAI,OAAO,SAAS,IAAI,GACrC;AACA,UAAM,OAAO,OAAO,SAAS;AAC7B,WAAO;AAAA,MACL,MAAM;AAAA,MACN,UAAU;AAAA,QACR,MAAM,OAAO,SAAS;AAAA,QACtB,WAAW,OAAO,SAAS,WAAW,OAAO,KAAK,UAAU,QAAQ,CAAC,CAAC;AAAA,MACxE;AAAA,IACF;AAAA,EACF;AAGA,MAAI,OAAO,OAAO,cAAc,YAAY,aAAa,IAAI,OAAO,SAAS,GAAG;AAC9E,WAAO;AAAA,MACL,UAAU;AAAA,QACR,MAAM,OAAO;AAAA,QACb,WAAW,KAAK,UAAU,OAAO,aAAa,CAAC,CAAC;AAAA,MAClD;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;;;ACxHO,IAAM,eAAN,MAAmB;AAAA,EACP;AAAA,EACA;AAAA,EACA,SAA2C,CAAC;AAAA,EAE7D,YAAY,aAAa,GAAG,YAAY,GAAG;AACzC,SAAK,aAAa;AAClB,SAAK,YAAY;AAAA,EACnB;AAAA,EAEA,QAAQ,MAAwD;AAC9D,UAAM,MAAM,UAAU,IAAI;AAC1B,QAAI,CAAC,IAAK,QAAO,EAAE,UAAU,MAAM;AACnC,UAAM,QAAQ,KAAK,OAAO;AAAA,MACxB,CAAC,GAAG,CAAC,MAAM,IAAI,MAAO,SAAS,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,IAAI,IAAI,IAAI;AAAA,MACnE;AAAA,IACF;AACA,QAAI,SAAS,KAAK,YAAY,GAAG;AAC/B,aAAO;AAAA,QACL,UAAU;AAAA,QACV,QAAQ,0BAA0B,IAAI,CAAC,CAAC,+BAA+B,QAAQ,CAAC,wBAAwB,KAAK,UAAU;AAAA,MACzH;AAAA,IACF;AACA,SAAK,OAAO,KAAK,GAAG;AACpB,WAAO,KAAK,OAAO,SAAS,KAAK,WAAY,MAAK,OAAO,MAAM;AAC/D,WAAO,EAAE,UAAU,MAAM;AAAA,EAC3B;AAAA,EAEA,QAAc;AACZ,SAAK,OAAO,SAAS;AAAA,EACvB;AACF;AAEA,SAAS,UAAU,MAAkD;AACnE,QAAM,OAAO,KAAK,UAAU;AAC5B,MAAI,CAAC,KAAM,QAAO;AAClB,SAAO,CAAC,MAAM,KAAK,UAAU,aAAa,EAAE;AAC9C;;;AC/BO,SAAS,oBAAoB,OAAuC;AACzE,QAAM,QAAkB,CAAC;AACzB,MAAI,CAAC,SAAS,CAAC,MAAM,KAAK,GAAG;AAC3B,WAAO,EAAE,UAAU,MAAM,SAAS,UAAU,MAAM,OAAO,CAAC,uBAAkB,EAAE;AAAA,EAChF;AAEA,MAAI;AACF,SAAK,MAAM,KAAK;AAChB,WAAO,EAAE,UAAU,OAAO,SAAS,OAAO,OAAO,CAAC,EAAE;AAAA,EACtD,QAAQ;AAAA,EAER;AAEA,QAAM,QAA6B,CAAC;AACpC,MAAI,UAAU;AACd,MAAI,WAAW;AACf,MAAI,kBAAkB;AAEtB,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,IAAI,MAAM,CAAC;AACjB,QAAI,CAAC,KAAK,KAAK,CAAC,EAAG,mBAAkB;AACrC,QAAI,SAAS;AACX,gBAAU;AACV;AAAA,IACF;AACA,QAAI,UAAU;AACZ,UAAI,MAAM,MAAM;AACd,kBAAU;AACV;AAAA,MACF;AACA,UAAI,MAAM,KAAK;AACb,mBAAW;AACX,cAAM,IAAI;AAAA,MACZ;AACA;AAAA,IACF;AACA,QAAI,MAAM,KAAK;AACb,iBAAW;AACX,YAAM,KAAK,GAAG;AACd;AAAA,IACF;AACA,QAAI,MAAM,OAAO,MAAM,IAAK,OAAM,KAAK,CAAC;AAAA,aAC/B,MAAM,OAAO,MAAM,IAAK,OAAM,IAAI;AAAA,EAC7C;AAEA,MAAI,IAAI,MAAM,MAAM,GAAG,kBAAkB,CAAC;AAG1C,MAAI,KAAK,KAAK,CAAC,GAAG;AAChB,QAAI,EAAE,QAAQ,MAAM,EAAE;AACtB,UAAM,KAAK,wBAAwB;AAAA,EACrC;AAGA,MAAI,YAAY,KAAK,CAAC,GAAG;AACvB,SAAK;AACL,UAAM,KAAK,+BAA+B;AAAA,EAC5C;AAGA,MAAI,UAAU;AACZ,SAAK;AACL,UAAM,IAAI;AACV,UAAM,KAAK,4BAA4B;AAAA,EACzC;AAGA,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,MAAM,MAAM,IAAI;AACtB,QAAI,QAAQ,IAAK,MAAK;AAAA,aACb,QAAQ,IAAK,MAAK;AAAA,aAClB,QAAQ,IAAK,MAAK;AAAA,EAC7B;AAEA,MAAI;AACF,SAAK,MAAM,CAAC;AACZ,WAAO,EAAE,UAAU,GAAG,SAAS,MAAM,MAAM;AAAA,EAC7C,SAAS,KAAK;AACZ,UAAM,KAAK,mBAAoB,IAAc,OAAO,EAAE;AACtD,WAAO,EAAE,UAAU,MAAM,SAAS,MAAM,MAAM;AAAA,EAChD;AACF;;;AC7EO,SAAS,cAAc,QAAiD;AAC7E,MAAI,CAAC,OAAQ,QAAO,EAAE,eAAe,OAAO,WAAW,GAAG,UAAU,EAAE;AACtE,MAAI,YAAY;AAChB,MAAI,WAAW;AACf,OAAK,QAAQ,GAAG,CAAC,OAAO,WAAW;AACjC,QAAI,OAAQ;AACZ,QAAI,QAAQ,SAAU,YAAW;AAAA,EACnC,CAAC;AACD,SAAO;AAAA,IACL,eAAe,YAAY,MAAM,WAAW;AAAA,IAC5C;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,cAAc,QAAgC;AAC5D,QAAM,YAAwC,CAAC;AAC/C,QAAM,WAAqB,CAAC;AAC5B,UAAQ,IAAI,QAAQ,WAAW,UAAU,IAAI;AAC7C,SAAO;AAAA,IACL,MAAM;AAAA,IACN,YAAY;AAAA,IACZ;AAAA,EACF;AACF;AAEO,SAAS,cAAc,UAA4D;AACxF,QAAM,MAA+B,CAAC;AACtC,aAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,QAAQ,GAAG;AACnD,cAAU,KAAK,IAAI,MAAM,GAAG,GAAG,KAAK;AAAA,EACtC;AACA,SAAO;AACT;AAEA,SAAS,KACP,QACA,OACA,OACM;AACN,MAAI,OAAO,SAAS,YAAY,OAAO,YAAY;AACjD,eAAW,SAAS,OAAO,OAAO,OAAO,UAAU,GAAG;AACpD,WAAK,OAAO,QAAQ,GAAG,KAAK;AAAA,IAC9B;AACA;AAAA,EACF;AACA,MAAI,OAAO,SAAS,WAAW,OAAO,OAAO;AAC3C,SAAK,OAAO,OAAO,QAAQ,GAAG,KAAK;AACnC;AAAA,EACF;AACA,QAAM,OAAO,IAAI;AACnB;AAEA,SAAS,QACP,QACA,QACA,KACA,UACA,gBACM;AACN,MAAI,OAAO,SAAS,YAAY,OAAO,YAAY;AACjD,UAAM,cAAc,IAAI,IAAI,OAAO,YAAY,CAAC,CAAC;AACjD,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,UAAU,GAAG;AAC5D,YAAM,aAAa,SAAS,GAAG,MAAM,IAAI,GAAG,KAAK;AACjD,YAAM,gBAAgB,kBAAkB,YAAY,IAAI,GAAG;AAC3D,cAAQ,YAAY,OAAO,KAAK,UAAU,aAAa;AAAA,IACzD;AACA;AAAA,EACF;AAEA,MAAI,MAAM,IAAI;AACd,MAAI,eAAgB,UAAS,KAAK,MAAM;AAC1C;AAEA,SAAS,UAAU,QAAiC,MAAgB,OAAsB;AACxF,MAAI,MAAW;AACf,WAAS,IAAI,GAAG,IAAI,KAAK,SAAS,GAAG,KAAK;AACxC,UAAM,MAAM,KAAK,CAAC;AAClB,QAAI,OAAO,IAAI,GAAG,MAAM,YAAY,IAAI,GAAG,MAAM,KAAM,KAAI,GAAG,IAAI,CAAC;AACnE,UAAM,IAAI,GAAG;AAAA,EACf;AACA,MAAI,KAAK,KAAK,SAAS,CAAC,CAAE,IAAI;AAChC;;;AC7DO,IAAM,iBAAN,MAAqB;AAAA,EACT;AAAA,EACA;AAAA,EAEjB,YAAY,MAA6B;AACvC,SAAK,OAAO;AACZ,SAAK,QAAQ,IAAI,aAAa,KAAK,eAAe,GAAG,KAAK,kBAAkB,CAAC;AAAA,EAC/E;AAAA,EAEA,QACE,eACA,kBAC6C;AAC7C,UAAM,SAAuB;AAAA,MAC3B,WAAW;AAAA,MACX,kBAAkB;AAAA,MAClB,cAAc;AAAA,MACd,OAAO,CAAC;AAAA,IACV;AAGA,UAAM,YAAY,kBAAkB,kBAAkB;AAAA,MACpD,cAAc,KAAK,KAAK;AAAA,MACxB,UAAU,KAAK,KAAK,eAAe;AAAA,IACrC,CAAC;AACD,UAAM,iBAAiB,IAAI,IAAI,cAAc,IAAIA,UAAS,CAAC;AAC3D,UAAM,SAAS,CAAC,GAAG,aAAa;AAChC,eAAW,MAAM,UAAU,OAAO;AAChC,UAAI,CAAC,eAAe,IAAIA,WAAU,EAAE,CAAC,GAAG;AACtC,eAAO,KAAK,EAAE;AACd,eAAO;AACP,uBAAe,IAAIA,WAAU,EAAE,CAAC;AAAA,MAClC;AAAA,IACF;AACA,WAAO,MAAM,KAAK,GAAG,UAAU,KAAK;AAGpC,eAAW,QAAQ,QAAQ;AACzB,YAAM,OAAO,KAAK,UAAU,aAAa;AACzC,YAAM,IAAI,oBAAoB,IAAI;AAClC,UAAI,EAAE,SAAS;AACb,aAAK,SAAS,YAAY,EAAE;AAC5B,eAAO;AACP,eAAO,MAAM,KAAK,GAAG,EAAE,MAAM,IAAI,CAAC,MAAM,IAAI,KAAK,SAAS,IAAI,KAAK,CAAC,EAAE,CAAC;AAAA,MACzE;AAAA,IACF;AAGA,UAAM,WAAuB,CAAC;AAC9B,eAAW,QAAQ,QAAQ;AACzB,YAAM,UAAU,KAAK,MAAM,QAAQ,IAAI;AACvC,UAAI,QAAQ,UAAU;AACpB,eAAO;AACP,YAAI,QAAQ,OAAQ,QAAO,MAAM,KAAK,QAAQ,MAAM;AACpD;AAAA,MACF;AACA,eAAS,KAAK,IAAI;AAAA,IACpB;AAEA,WAAO,EAAE,OAAO,UAAU,OAAO;AAAA,EACnC;AACF;AAEA,SAASA,WAAU,MAAwB;AACzC,SAAO,GAAG,KAAK,UAAU,QAAQ,EAAE,KAAK,KAAK,UAAU,aAAa,EAAE;AACxE;;;ACrGO,IAAM,mBAGT;AAAA,EACF,iBAAiB,EAAE,eAAe,MAAM,gBAAgB,MAAM,QAAQ,IAAI;AAAA,EAC1E,qBAAqB,EAAE,eAAe,MAAM,gBAAgB,MAAM,QAAQ,KAAK;AACjF;AAGO,IAAM,wBAAwB,EAAE,OAAO,GAAK,QAAQ,GAAK;AAEzD,SAAS,QAAQ,OAAe,OAAsB;AAC3D,QAAM,IAAI,iBAAiB,KAAK;AAChC,MAAI,CAAC,EAAG,QAAO;AACf,UACG,MAAM,uBAAuB,EAAE,gBAC9B,MAAM,wBAAwB,EAAE,iBAChC,MAAM,mBAAmB,EAAE,UAC7B;AAEJ;AAEO,SAAS,qBAAqB,OAAsB;AACzD,UACG,MAAM,eAAe,sBAAsB,QAC1C,MAAM,mBAAmB,sBAAsB,UACjD;AAEJ;AAkBO,IAAM,eAAN,MAAmB;AAAA,EACf,QAAqB,CAAC;AAAA,EAE/B,OAAO,MAAc,OAAe,OAAyB;AAC3D,UAAM,OAAO,QAAQ,OAAO,KAAK;AACjC,UAAM,QAAmB;AAAA,MACvB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,eAAe,MAAM;AAAA,IACvB;AACA,SAAK,MAAM,KAAK,KAAK;AACrB,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,YAAoB;AACtB,WAAO,KAAK,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,MAAM,CAAC;AAAA,EACtD;AAAA,EAEA,IAAI,wBAAgC;AAClC,WAAO,KAAK,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,qBAAqB,EAAE,KAAK,GAAG,CAAC;AAAA,EAC7E;AAAA,EAEA,IAAI,kBAA0B;AAC5B,UAAM,IAAI,KAAK;AACf,WAAO,IAAI,IAAI,IAAI,KAAK,YAAY,IAAI;AAAA,EAC1C;AAAA,EAEA,IAAI,yBAAiC;AACnC,QAAI,MAAM;AACV,QAAI,OAAO;AACX,eAAW,KAAK,KAAK,OAAO;AAC1B,aAAO,EAAE,MAAM;AACf,cAAQ,EAAE,MAAM;AAAA,IAClB;AACA,UAAM,QAAQ,MAAM;AACpB,WAAO,QAAQ,IAAI,MAAM,QAAQ;AAAA,EACnC;AAAA,EAEA,UAA0B;AACxB,WAAO;AAAA,MACL,OAAO,KAAK,MAAM;AAAA,MAClB,cAAc,MAAM,KAAK,WAAW,CAAC;AAAA,MACrC,qBAAqB,MAAM,KAAK,uBAAuB,CAAC;AAAA,MACxD,oBAAoB,MAAM,KAAK,kBAAkB,KAAK,CAAC;AAAA,MACvD,eAAe,MAAM,KAAK,wBAAwB,CAAC;AAAA,IACrD;AAAA,EACF;AACF;AAEA,SAAS,MAAM,GAAW,QAAwB;AAChD,QAAM,IAAI,MAAM;AAChB,SAAO,KAAK,MAAM,IAAI,CAAC,IAAI;AAC7B;;;AC1EO,IAAM,eAAN,MAAmB;AAAA,EACP,SAAS,oBAAI,IAA0B;AAAA,EACvC;AAAA,EAEjB,YAAY,OAA4B,CAAC,GAAG;AAC1C,SAAK,eAAe,KAAK,gBAAgB;AAAA,EAC3C;AAAA,EAEA,SAAe,KAAiC;AAC9C,QAAI,CAAC,IAAI,KAAM,OAAM,IAAI,MAAM,sBAAsB;AACrD,UAAM,WAAyB,EAAE,GAAI,IAAuB;AAC5D,QAAI,KAAK,gBAAgB,IAAI,YAAY;AACvC,YAAM,WAAW,cAAc,IAAI,UAAU;AAC7C,UAAI,SAAS,eAAe;AAC1B,iBAAS,aAAa,cAAc,IAAI,UAAU;AAAA,MACpD;AAAA,IACF;AACA,SAAK,OAAO,IAAI,IAAI,MAAM,QAAQ;AAClC,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,MAAuB;AACzB,WAAO,KAAK,OAAO,IAAI,IAAI;AAAA,EAC7B;AAAA,EAEA,IAAI,MAA0C;AAC5C,WAAO,KAAK,OAAO,IAAI,IAAI;AAAA,EAC7B;AAAA,EAEA,IAAI,OAAe;AACjB,WAAO,KAAK,OAAO;AAAA,EACrB;AAAA;AAAA,EAGA,aAAa,MAAuB;AAClC,WAAO,QAAQ,KAAK,OAAO,IAAI,IAAI,GAAG,UAAU;AAAA,EAClD;AAAA,EAEA,QAAoB;AAClB,WAAO,CAAC,GAAG,KAAK,OAAO,OAAO,CAAC,EAAE,IAAI,CAAC,OAAO;AAAA,MAC3C,MAAM;AAAA,MACN,UAAU;AAAA,QACR,MAAM,EAAE;AAAA,QACR,aAAa,EAAE,eAAe;AAAA,QAC9B,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,UAAU,YAAY,CAAC,EAAE;AAAA,MAC/E;AAAA,IACF,EAAE;AAAA,EACJ;AAAA,EAEA,MAAM,SAAS,MAAc,cAAiE;AAC5F,UAAM,OAAO,KAAK,OAAO,IAAI,IAAI;AACjC,QAAI,CAAC,MAAM;AACT,aAAO,KAAK,UAAU,EAAE,OAAO,iBAAiB,IAAI,GAAG,CAAC;AAAA,IAC1D;AACA,QAAI;AACJ,QAAI;AACF,aACE,OAAO,iBAAiB,WACpB,aAAa,KAAK,IACf,KAAK,MAAM,YAAY,KAAK,CAAC,IAC9B,CAAC,IACF,gBAAgB,CAAC;AAAA,IAC1B,SAAS,KAAK;AACZ,aAAO,KAAK,UAAU;AAAA,QACpB,OAAO,gCAAiC,IAAc,OAAO;AAAA,MAC/D,CAAC;AAAA,IACH;AAOA,QAAI,KAAK,cAAc,QAAQ,OAAO,SAAS,YAAY,UAAU,IAAI,GAAG;AAC1E,aAAO,cAAc,IAAI;AAAA,IAC3B;AAEA,QAAI;AACF,YAAM,SAAS,MAAM,KAAK,GAAG,IAAI;AACjC,aAAO,OAAO,WAAW,WAAW,SAAS,KAAK,UAAU,MAAM;AAAA,IACpE,SAAS,KAAK;AACZ,aAAO,KAAK,UAAU;AAAA,QACpB,OAAO,GAAI,IAAc,IAAI,KAAM,IAAc,OAAO;AAAA,MAC1D,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAEA,SAAS,UAAU,KAAuC;AACxD,aAAW,KAAK,OAAO,KAAK,GAAG,GAAG;AAChC,QAAI,EAAE,SAAS,GAAG,EAAG,QAAO;AAAA,EAC9B;AACA,SAAO;AACT;;;AC5EO,IAAM,iBAAN,MAAqB;AAAA,EACjB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,MAAM,IAAI,cAAc;AAAA,EACxB,UAAU,IAAI,gBAAgB;AAAA,EAC9B,QAAQ,IAAI,aAAa;AAAA,EACzB;AAAA,EACD,QAAQ;AAAA,EAEhB,YAAY,MAA6B;AACvC,SAAK,SAAS,KAAK;AACnB,SAAK,SAAS,KAAK;AACnB,SAAK,QAAQ,KAAK,SAAS,IAAI,aAAa;AAC5C,SAAK,QAAQ,KAAK,SAAS;AAC3B,SAAK,eAAe,KAAK,gBAAgB;AACzC,SAAK,SAAS,KAAK,UAAU;AAC7B,SAAK,iBACH,KAAK,YAAY,QAAS,OAAO,KAAK,YAAY,YAAY,KAAK,YAAY;AACjF,SAAK,iBACH,OAAO,KAAK,YAAY,YAAY,KAAK,YAAY,OAAO,KAAK,UAAU,CAAC;AAC9E,UAAM,eAAe,oBAAI,IAAI,CAAC,GAAG,KAAK,OAAO,UAAU,IAAI,CAAC,MAAM,EAAE,SAAS,IAAI,CAAC,CAAC;AACnF,SAAK,SAAS,IAAI,eAAe,EAAE,kBAAkB,aAAa,CAAC;AAAA,EACrE;AAAA,EAEQ,cAAc,aAA2C;AAC/D,UAAM,OAAsB,CAAC,GAAG,KAAK,OAAO,WAAW,GAAG,GAAG,KAAK,IAAI,WAAW,CAAC;AAClF,QAAI,gBAAgB,KAAM,MAAK,KAAK,EAAE,MAAM,QAAQ,SAAS,YAAY,CAAC;AAC1E,WAAO;AAAA,EACT;AAAA,EAEA,OAAO,KAAK,WAA8C;AACxD,SAAK;AACL,SAAK,QAAQ,MAAM;AACnB,QAAI,cAA6B;AACjC,UAAM,YAAY,KAAK,OAAO,MAAM;AAEpC,aAAS,OAAO,GAAG,OAAO,KAAK,cAAc,QAAQ;AACnD,YAAM,WAAW,KAAK,cAAc,WAAW;AAE/C,UAAI,mBAAmB;AACvB,UAAI,mBAAmB;AACvB,UAAI,YAAwB,CAAC;AAC7B,UAAI,QAAmC;AAEvC,UAAI;AACF,YAAI,KAAK,QAAQ;AACf,gBAAM,UAAiC,oBAAI,IAAI;AAC/C,2BAAiB,SAAS,KAAK,OAAO,OAAO;AAAA,YAC3C,OAAO,KAAK;AAAA,YACZ;AAAA,YACA,OAAO,UAAU,SAAS,YAAY;AAAA,UACxC,CAAC,GAAG;AACF,gBAAI,MAAM,cAAc;AACtB,kCAAoB,MAAM;AAC1B,oBAAM;AAAA,gBACJ,MAAM,KAAK;AAAA,gBACX,MAAM;AAAA,gBACN,SAAS,MAAM;AAAA,cACjB;AAAA,YACF;AACA,gBAAI,MAAM,gBAAgB;AACxB,kCAAoB,MAAM;AAC1B,oBAAM;AAAA,gBACJ,MAAM,KAAK;AAAA,gBACX,MAAM;AAAA,gBACN,SAAS;AAAA,gBACT,gBAAgB,MAAM;AAAA,cACxB;AAAA,YACF;AACA,gBAAI,MAAM,eAAe;AACvB,oBAAM,IAAI,MAAM;AAChB,oBAAM,MAAM,QAAQ,IAAI,EAAE,KAAK,KAAK;AAAA,gBAClC,IAAI,EAAE;AAAA,gBACN,MAAM;AAAA,gBACN,UAAU,EAAE,MAAM,IAAI,WAAW,GAAG;AAAA,cACtC;AACA,kBAAI,EAAE,GAAI,KAAI,KAAK,EAAE;AACrB,kBAAI,EAAE,KAAM,KAAI,SAAS,QAAQ,IAAI,SAAS,QAAQ,MAAM,EAAE;AAC9D,kBAAI,EAAE;AACJ,oBAAI,SAAS,aAAa,IAAI,SAAS,aAAa,MAAM,EAAE;AAC9D,sBAAQ,IAAI,EAAE,OAAO,GAAG;AAAA,YAC1B;AACA,gBAAI,MAAM,MAAO,SAAQ,MAAM;AAAA,UACjC;AACA,sBAAY,CAAC,GAAG,QAAQ,OAAO,CAAC;AAAA,QAClC,OAAO;AACL,gBAAM,OAAO,MAAM,KAAK,OAAO,KAAK;AAAA,YAClC,OAAO,KAAK;AAAA,YACZ;AAAA,YACA,OAAO,UAAU,SAAS,YAAY;AAAA,UACxC,CAAC;AACD,6BAAmB,KAAK;AACxB,6BAAmB,KAAK,oBAAoB;AAC5C,sBAAY,KAAK;AACjB,kBAAQ,KAAK;AAAA,QACf;AAAA,MACF,SAAS,KAAK;AACZ,cAAM;AAAA,UACJ,MAAM,KAAK;AAAA,UACX,MAAM;AAAA,UACN,SAAS;AAAA,UACT,OAAQ,IAAc;AAAA,QACxB;AACA;AAAA,MACF;AAEA,YAAM,YAAY,KAAK,MAAM;AAAA,QAC3B,KAAK;AAAA,QACL,KAAK;AAAA,QACL,SAAS,KAAK,MAAM,OAAO,sBAAa,GAAG,MAAM;AAAA,MACnD;AAGA,UAAI,gBAAgB,MAAM;AACxB,aAAK,IAAI,OAAO,EAAE,MAAM,QAAQ,SAAS,YAAY,CAAC;AACtD,sBAAc;AAAA,MAChB;AAEA,WAAK,QAAQ,YAAY,oBAAoB;AAC7C,YAAM,YAAY,KAAK,iBACnB,MAAM,QAAQ,oBAAoB,MAAM,KAAK,QAAQ,KAAK,cAAc,IACxE,eAAe;AAEnB,YAAM,EAAE,OAAO,eAAe,OAAO,IAAI,KAAK,OAAO;AAAA,QACnD;AAAA,QACA,oBAAoB;AAAA,MACtB;AAEA,WAAK,IAAI,OAAO,KAAK,iBAAiB,kBAAkB,aAAa,CAAC;AAEtE,YAAM;AAAA,QACJ,MAAM,KAAK;AAAA,QACX,MAAM;AAAA,QACN,SAAS;AAAA,QACT,OAAO;AAAA,QACP;AAAA,QACA,QAAQ;AAAA,MACV;AAEA,UAAI,cAAc,WAAW,GAAG;AAC9B,cAAM,EAAE,MAAM,KAAK,OAAO,MAAM,QAAQ,SAAS,iBAAiB;AAClE;AAAA,MACF;AAEA,iBAAW,QAAQ,eAAe;AAChC,cAAM,OAAO,KAAK,UAAU,QAAQ;AACpC,cAAM,OAAO,KAAK,UAAU,aAAa;AACzC,cAAM,SAAS,MAAM,KAAK,MAAM,SAAS,MAAM,IAAI;AACnD,aAAK,IAAI,OAAO;AAAA,UACd,MAAM;AAAA,UACN,cAAc,KAAK,MAAM;AAAA,UACzB;AAAA,UACA,SAAS;AAAA,QACX,CAAC;AACD,cAAM,EAAE,MAAM,KAAK,OAAO,MAAM,QAAQ,SAAS,QAAQ,UAAU,KAAK;AAAA,MAC1E;AAAA,IACF;AAEA,UAAM,EAAE,MAAM,KAAK,OAAO,MAAM,QAAQ,SAAS,2BAA2B;AAAA,EAC9E;AAAA,EAEA,MAAM,IAAI,WAAmB,SAAoD;AAC/E,QAAI,QAAQ;AACZ,qBAAiB,MAAM,KAAK,KAAK,SAAS,GAAG;AAC3C,gBAAU,EAAE;AACZ,UAAI,GAAG,SAAS,kBAAmB,SAAQ,GAAG;AAC9C,UAAI,GAAG,SAAS,OAAQ;AAAA,IAC1B;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,iBAAiB,SAAiB,WAAoC;AAC5E,UAAM,MAAmB,EAAE,MAAM,aAAa,QAAQ;AACtD,QAAI,UAAU,SAAS,EAAG,KAAI,aAAa;AAC3C,WAAO;AAAA,EACT;AACF;;;ACpOA,SAAS,oBAAoB;AAC7B,SAAS,eAAe;AASjB,SAAS,WAAW,OAAO,QAAc;AAC9C,MAAI;AACJ,MAAI;AACF,UAAM,aAAa,QAAQ,QAAQ,IAAI,GAAG,IAAI,GAAG,MAAM;AAAA,EACzD,QAAQ;AACN;AAAA,EACF;AACA,aAAW,QAAQ,IAAI,MAAM,OAAO,GAAG;AACrC,UAAM,UAAU,KAAK,KAAK;AAC1B,QAAI,CAAC,WAAW,QAAQ,WAAW,GAAG,EAAG;AACzC,UAAM,KAAK,QAAQ,QAAQ,GAAG;AAC9B,QAAI,OAAO,GAAI;AACf,UAAM,MAAM,QAAQ,MAAM,GAAG,EAAE,EAAE,KAAK;AACtC,QAAI,QAAQ,QAAQ,MAAM,KAAK,CAAC,EAAE,KAAK;AACvC,QACG,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,KAC3C,MAAM,WAAW,GAAG,KAAK,MAAM,SAAS,GAAG,GAC5C;AACA,cAAQ,MAAM,MAAM,GAAG,EAAE;AAAA,IAC3B;AACA,QAAI,QAAQ,IAAI,GAAG,MAAM,OAAW,SAAQ,IAAI,GAAG,IAAI;AAAA,EACzD;AACF;;;ACpBA,SAAS,WAAW,WAAW,gBAAAC,eAAc,qBAAqB;AAClE,SAAS,eAAe;AACxB,SAAS,SAAS,YAAY;AAOvB,SAAS,oBAA4B;AAC1C,SAAO,KAAK,QAAQ,GAAG,aAAa,aAAa;AACnD;AAEO,SAAS,WAAW,OAAe,kBAAkB,GAAmB;AAC7E,MAAI;AACF,UAAM,MAAMA,cAAa,MAAM,MAAM;AACrC,UAAM,SAAS,KAAK,MAAM,GAAG;AAC7B,QAAI,UAAU,OAAO,WAAW,SAAU,QAAO;AAAA,EACnD,QAAQ;AAAA,EAER;AACA,SAAO,CAAC;AACV;AAEO,SAAS,YAAY,KAAqB,OAAe,kBAAkB,GAAS;AACzF,YAAU,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;AAC5C,gBAAc,MAAM,KAAK,UAAU,KAAK,MAAM,CAAC,GAAG,MAAM;AAExD,MAAI;AACF,cAAU,MAAM,GAAK;AAAA,EACvB,QAAQ;AAAA,EAER;AACF;AAGO,SAAS,WAAW,OAAe,kBAAkB,GAAuB;AACjF,MAAI,QAAQ,IAAI,iBAAkB,QAAO,QAAQ,IAAI;AACrD,SAAO,WAAW,IAAI,EAAE;AAC1B;AAEO,SAAS,WAAW,KAAa,OAAe,kBAAkB,GAAS;AAChF,QAAM,MAAM,WAAW,IAAI;AAC3B,MAAI,SAAS,IAAI,KAAK;AACtB,cAAY,KAAK,IAAI;AACvB;AAEO,SAAS,eAAe,KAAsB;AACnD,QAAM,UAAU,IAAI,KAAK;AACzB,SAAO,0BAA0B,KAAK,OAAO;AAC/C;AAGO,SAAS,UAAU,KAAqB;AAC7C,MAAI,CAAC,IAAK,QAAO;AACjB,MAAI,IAAI,UAAU,GAAI,QAAO;AAC7B,SAAO,GAAG,IAAI,MAAM,GAAG,CAAC,CAAC,SAAI,IAAI,MAAM,EAAE,CAAC;AAC5C;;;ACNO,IAAM,UAAU;","names":["signature","readFileSync"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "reasonix",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "description": "DeepSeek-native agent framework: cache-first loop, R1 thought harvesting, tool-call repair.",
5
5
  "type": "module",
6
6
  "bin": {