merlion 0.1.0

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.
Files changed (162) hide show
  1. package/bin/merlion.js +2 -0
  2. package/dist/artifacts/agents.d.ts +11 -0
  3. package/dist/artifacts/agents.d.ts.map +1 -0
  4. package/dist/artifacts/agents.js +81 -0
  5. package/dist/artifacts/agents.js.map +1 -0
  6. package/dist/artifacts/codebase_index.d.ts +16 -0
  7. package/dist/artifacts/codebase_index.d.ts.map +1 -0
  8. package/dist/artifacts/codebase_index.js +193 -0
  9. package/dist/artifacts/codebase_index.js.map +1 -0
  10. package/dist/artifacts/progress.d.ts +23 -0
  11. package/dist/artifacts/progress.d.ts.map +1 -0
  12. package/dist/artifacts/progress.js +152 -0
  13. package/dist/artifacts/progress.js.map +1 -0
  14. package/dist/cli/diff.d.ts +11 -0
  15. package/dist/cli/diff.d.ts.map +1 -0
  16. package/dist/cli/diff.js +58 -0
  17. package/dist/cli/diff.js.map +1 -0
  18. package/dist/cli/experience.d.ts +71 -0
  19. package/dist/cli/experience.d.ts.map +1 -0
  20. package/dist/cli/experience.js +489 -0
  21. package/dist/cli/experience.js.map +1 -0
  22. package/dist/cli/keybindings.d.ts +3 -0
  23. package/dist/cli/keybindings.d.ts.map +1 -0
  24. package/dist/cli/keybindings.js +14 -0
  25. package/dist/cli/keybindings.js.map +1 -0
  26. package/dist/cli/markdown.d.ts +7 -0
  27. package/dist/cli/markdown.d.ts.map +1 -0
  28. package/dist/cli/markdown.js +77 -0
  29. package/dist/cli/markdown.js.map +1 -0
  30. package/dist/cli/message_content.d.ts +13 -0
  31. package/dist/cli/message_content.d.ts.map +1 -0
  32. package/dist/cli/message_content.js +23 -0
  33. package/dist/cli/message_content.js.map +1 -0
  34. package/dist/cli/render.d.ts +23 -0
  35. package/dist/cli/render.d.ts.map +1 -0
  36. package/dist/cli/render.js +44 -0
  37. package/dist/cli/render.js.map +1 -0
  38. package/dist/cli/repl.d.ts +32 -0
  39. package/dist/cli/repl.d.ts.map +1 -0
  40. package/dist/cli/repl.js +54 -0
  41. package/dist/cli/repl.js.map +1 -0
  42. package/dist/cli/sanitize.d.ts +2 -0
  43. package/dist/cli/sanitize.d.ts.map +1 -0
  44. package/dist/cli/sanitize.js +66 -0
  45. package/dist/cli/sanitize.js.map +1 -0
  46. package/dist/cli/status.d.ts +3 -0
  47. package/dist/cli/status.d.ts.map +1 -0
  48. package/dist/cli/status.js +27 -0
  49. package/dist/cli/status.js.map +1 -0
  50. package/dist/cli/tui_frame.d.ts +10 -0
  51. package/dist/cli/tui_frame.d.ts.map +1 -0
  52. package/dist/cli/tui_frame.js +44 -0
  53. package/dist/cli/tui_frame.js.map +1 -0
  54. package/dist/config/store.d.ts +27 -0
  55. package/dist/config/store.d.ts.map +1 -0
  56. package/dist/config/store.js +73 -0
  57. package/dist/config/store.js.map +1 -0
  58. package/dist/config/wizard.d.ts +27 -0
  59. package/dist/config/wizard.d.ts.map +1 -0
  60. package/dist/config/wizard.js +83 -0
  61. package/dist/config/wizard.js.map +1 -0
  62. package/dist/context/compact.d.ts +11 -0
  63. package/dist/context/compact.d.ts.map +1 -0
  64. package/dist/context/compact.js +38 -0
  65. package/dist/context/compact.js.map +1 -0
  66. package/dist/context/orientation.d.ts +19 -0
  67. package/dist/context/orientation.d.ts.map +1 -0
  68. package/dist/context/orientation.js +111 -0
  69. package/dist/context/orientation.js.map +1 -0
  70. package/dist/index.d.ts +2 -0
  71. package/dist/index.d.ts.map +1 -0
  72. package/dist/index.js +401 -0
  73. package/dist/index.js.map +1 -0
  74. package/dist/permissions/store.d.ts +3 -0
  75. package/dist/permissions/store.d.ts.map +1 -0
  76. package/dist/permissions/store.js +22 -0
  77. package/dist/permissions/store.js.map +1 -0
  78. package/dist/providers/openai.d.ts +16 -0
  79. package/dist/providers/openai.d.ts.map +1 -0
  80. package/dist/providers/openai.js +75 -0
  81. package/dist/providers/openai.js.map +1 -0
  82. package/dist/runtime/budget.d.ts +11 -0
  83. package/dist/runtime/budget.d.ts.map +1 -0
  84. package/dist/runtime/budget.js +43 -0
  85. package/dist/runtime/budget.js.map +1 -0
  86. package/dist/runtime/cost_gate.d.ts +34 -0
  87. package/dist/runtime/cost_gate.d.ts.map +1 -0
  88. package/dist/runtime/cost_gate.js +85 -0
  89. package/dist/runtime/cost_gate.js.map +1 -0
  90. package/dist/runtime/executor.d.ts +25 -0
  91. package/dist/runtime/executor.d.ts.map +1 -0
  92. package/dist/runtime/executor.js +136 -0
  93. package/dist/runtime/executor.js.map +1 -0
  94. package/dist/runtime/loop.d.ts +48 -0
  95. package/dist/runtime/loop.d.ts.map +1 -0
  96. package/dist/runtime/loop.js +184 -0
  97. package/dist/runtime/loop.js.map +1 -0
  98. package/dist/runtime/retry.d.ts +7 -0
  99. package/dist/runtime/retry.d.ts.map +1 -0
  100. package/dist/runtime/retry.js +42 -0
  101. package/dist/runtime/retry.js.map +1 -0
  102. package/dist/runtime/session.d.ts +26 -0
  103. package/dist/runtime/session.d.ts.map +1 -0
  104. package/dist/runtime/session.js +146 -0
  105. package/dist/runtime/session.js.map +1 -0
  106. package/dist/runtime/usage.d.ts +29 -0
  107. package/dist/runtime/usage.d.ts.map +1 -0
  108. package/dist/runtime/usage.js +71 -0
  109. package/dist/runtime/usage.js.map +1 -0
  110. package/dist/tools/builtin/bash.d.ts +3 -0
  111. package/dist/tools/builtin/bash.d.ts.map +1 -0
  112. package/dist/tools/builtin/bash.js +104 -0
  113. package/dist/tools/builtin/bash.js.map +1 -0
  114. package/dist/tools/builtin/create_file.d.ts +3 -0
  115. package/dist/tools/builtin/create_file.d.ts.map +1 -0
  116. package/dist/tools/builtin/create_file.js +64 -0
  117. package/dist/tools/builtin/create_file.js.map +1 -0
  118. package/dist/tools/builtin/edit_file.d.ts +3 -0
  119. package/dist/tools/builtin/edit_file.d.ts.map +1 -0
  120. package/dist/tools/builtin/edit_file.js +128 -0
  121. package/dist/tools/builtin/edit_file.js.map +1 -0
  122. package/dist/tools/builtin/fetch.d.ts +3 -0
  123. package/dist/tools/builtin/fetch.d.ts.map +1 -0
  124. package/dist/tools/builtin/fetch.js +82 -0
  125. package/dist/tools/builtin/fetch.js.map +1 -0
  126. package/dist/tools/builtin/index.d.ts +3 -0
  127. package/dist/tools/builtin/index.d.ts.map +1 -0
  128. package/dist/tools/builtin/index.js +18 -0
  129. package/dist/tools/builtin/index.js.map +1 -0
  130. package/dist/tools/builtin/read_file.d.ts +3 -0
  131. package/dist/tools/builtin/read_file.d.ts.map +1 -0
  132. package/dist/tools/builtin/read_file.js +77 -0
  133. package/dist/tools/builtin/read_file.js.map +1 -0
  134. package/dist/tools/builtin/search.d.ts +3 -0
  135. package/dist/tools/builtin/search.d.ts.map +1 -0
  136. package/dist/tools/builtin/search.js +91 -0
  137. package/dist/tools/builtin/search.js.map +1 -0
  138. package/dist/tools/registry.d.ts +8 -0
  139. package/dist/tools/registry.d.ts.map +1 -0
  140. package/dist/tools/registry.js +16 -0
  141. package/dist/tools/registry.js.map +1 -0
  142. package/dist/tools/types.d.ts +45 -0
  143. package/dist/tools/types.d.ts.map +1 -0
  144. package/dist/tools/types.js +2 -0
  145. package/dist/tools/types.js.map +1 -0
  146. package/dist/types.d.ts +56 -0
  147. package/dist/types.d.ts.map +1 -0
  148. package/dist/types.js +2 -0
  149. package/dist/types.js.map +1 -0
  150. package/dist/verification/checks.d.ts +10 -0
  151. package/dist/verification/checks.d.ts.map +1 -0
  152. package/dist/verification/checks.js +501 -0
  153. package/dist/verification/checks.js.map +1 -0
  154. package/dist/verification/fix_round.d.ts +20 -0
  155. package/dist/verification/fix_round.d.ts.map +1 -0
  156. package/dist/verification/fix_round.js +59 -0
  157. package/dist/verification/fix_round.js.map +1 -0
  158. package/dist/verification/runner.d.ts +26 -0
  159. package/dist/verification/runner.d.ts.map +1 -0
  160. package/dist/verification/runner.js +155 -0
  161. package/dist/verification/runner.js.map +1 -0
  162. package/package.json +29 -0
@@ -0,0 +1,34 @@
1
+ export type CostGateMode = 'off' | 'warn' | 'fail';
2
+ export interface CostBaselineScenario {
3
+ total_tokens: number;
4
+ threshold_pct?: number;
5
+ }
6
+ export interface CostBaseline {
7
+ default_threshold_pct: number;
8
+ scenarios: Record<string, CostBaselineScenario>;
9
+ }
10
+ export type CostGateDecision = {
11
+ status: 'skip';
12
+ message: string;
13
+ } | {
14
+ status: 'pass';
15
+ message: string;
16
+ thresholdTokens: number;
17
+ } | {
18
+ status: 'warn';
19
+ message: string;
20
+ thresholdTokens: number;
21
+ } | {
22
+ status: 'fail';
23
+ message: string;
24
+ thresholdTokens: number;
25
+ };
26
+ export declare function parseCostGateMode(raw: string | undefined): CostGateMode;
27
+ export declare function evaluateCostGate(params: {
28
+ baseline: CostBaseline | null;
29
+ scenario: string;
30
+ totalTokens: number;
31
+ mode: CostGateMode;
32
+ }): CostGateDecision;
33
+ export declare function readCostBaseline(path: string): Promise<CostBaseline | null>;
34
+ //# sourceMappingURL=cost_gate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost_gate.d.ts","sourceRoot":"","sources":["../../src/runtime/cost_gate.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,YAAY,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAA;AAElD,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAA;IACpB,aAAa,CAAC,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,qBAAqB,EAAE,MAAM,CAAA;IAC7B,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAA;CAChD;AAED,MAAM,MAAM,gBAAgB,GACxB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GACnC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,CAAA;AAEhE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,YAAY,CAKvE;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE;IACvC,QAAQ,EAAE,YAAY,GAAG,IAAI,CAAA;IAC7B,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,MAAM,CAAA;IACnB,IAAI,EAAE,YAAY,CAAA;CACnB,GAAG,gBAAgB,CAoCnB;AAMD,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAqCjF"}
@@ -0,0 +1,85 @@
1
+ import { readFile } from 'node:fs/promises';
2
+ export function parseCostGateMode(raw) {
3
+ const normalized = (raw ?? '').trim().toLowerCase();
4
+ if (normalized === 'off')
5
+ return 'off';
6
+ if (normalized === 'warn')
7
+ return 'warn';
8
+ return 'fail';
9
+ }
10
+ export function evaluateCostGate(params) {
11
+ if (params.mode === 'off') {
12
+ return { status: 'skip', message: '[cost-gate] skipped (mode=off)' };
13
+ }
14
+ if (!params.baseline) {
15
+ return { status: 'skip', message: '[cost-gate] skipped (no baseline loaded)' };
16
+ }
17
+ const scenarioBaseline = params.baseline.scenarios[params.scenario];
18
+ if (!scenarioBaseline) {
19
+ return { status: 'skip', message: `[cost-gate] skipped (no baseline for ${params.scenario})` };
20
+ }
21
+ const thresholdPct = Number.isFinite(scenarioBaseline.threshold_pct)
22
+ ? Math.max(0, scenarioBaseline.threshold_pct)
23
+ : Math.max(0, params.baseline.default_threshold_pct);
24
+ const baselineTokens = Math.max(0, Math.floor(scenarioBaseline.total_tokens));
25
+ const thresholdTokens = Math.ceil(baselineTokens * (1 + thresholdPct / 100));
26
+ const totalTokens = Math.max(0, Math.floor(params.totalTokens));
27
+ if (totalTokens <= thresholdTokens) {
28
+ return {
29
+ status: 'pass',
30
+ thresholdTokens,
31
+ message: `[cost-gate] pass ${params.scenario}: total=${totalTokens}, threshold=${thresholdTokens}`
32
+ };
33
+ }
34
+ const message = `[cost-gate] regression ${params.scenario}: total=${totalTokens} > threshold=${thresholdTokens} ` +
35
+ `(baseline=${baselineTokens}, threshold_pct=${thresholdPct})`;
36
+ if (params.mode === 'warn') {
37
+ return { status: 'warn', thresholdTokens, message };
38
+ }
39
+ return { status: 'fail', thresholdTokens, message };
40
+ }
41
+ function isObject(value) {
42
+ return typeof value === 'object' && value !== null;
43
+ }
44
+ export async function readCostBaseline(path) {
45
+ let text;
46
+ try {
47
+ text = await readFile(path, 'utf8');
48
+ }
49
+ catch {
50
+ return null;
51
+ }
52
+ let parsed;
53
+ try {
54
+ parsed = JSON.parse(text);
55
+ }
56
+ catch {
57
+ return null;
58
+ }
59
+ if (!isObject(parsed))
60
+ return null;
61
+ if (!isObject(parsed.scenarios))
62
+ return null;
63
+ const defaultThresholdRaw = parsed.default_threshold_pct;
64
+ const defaultThreshold = typeof defaultThresholdRaw === 'number' && Number.isFinite(defaultThresholdRaw)
65
+ ? defaultThresholdRaw
66
+ : 20;
67
+ const scenarios = {};
68
+ for (const [name, item] of Object.entries(parsed.scenarios)) {
69
+ if (!isObject(item))
70
+ continue;
71
+ const totalRaw = item.total_tokens;
72
+ if (typeof totalRaw !== 'number' || !Number.isFinite(totalRaw))
73
+ continue;
74
+ const thresholdRaw = item.threshold_pct;
75
+ scenarios[name] = {
76
+ total_tokens: totalRaw,
77
+ threshold_pct: typeof thresholdRaw === 'number' && Number.isFinite(thresholdRaw) ? thresholdRaw : undefined
78
+ };
79
+ }
80
+ return {
81
+ default_threshold_pct: defaultThreshold,
82
+ scenarios
83
+ };
84
+ }
85
+ //# sourceMappingURL=cost_gate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost_gate.js","sourceRoot":"","sources":["../../src/runtime/cost_gate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { ChatMessage, ToolCall } from '../types.js';
2
+ import type { ToolContext, ToolUiPayload } from '../tools/types.js';
3
+ import { ToolRegistry } from '../tools/registry.ts';
4
+ export declare function partitionToolCalls(toolCalls: ToolCall[], registry: ToolRegistry): ToolCall[][];
5
+ export interface ToolCallStartEvent {
6
+ call: ToolCall;
7
+ index: number;
8
+ total: number;
9
+ }
10
+ export interface ToolCallResultEvent extends ToolCallStartEvent {
11
+ message: ChatMessage;
12
+ isError: boolean;
13
+ durationMs: number;
14
+ uiPayload?: ToolUiPayload;
15
+ }
16
+ export interface ExecuteToolCallsOptions {
17
+ toolCalls: ToolCall[];
18
+ registry: ToolRegistry;
19
+ toolContext: ToolContext;
20
+ maxConcurrency: number;
21
+ onToolCallStart?: (event: ToolCallStartEvent) => Promise<void> | void;
22
+ onToolCallResult?: (event: ToolCallResultEvent) => Promise<void> | void;
23
+ }
24
+ export declare function executeToolCalls(options: ExecuteToolCallsOptions): Promise<ChatMessage[]>;
25
+ //# sourceMappingURL=executor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/runtime/executor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACxD,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAsBnD,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,QAAQ,EAAE,EAAE,QAAQ,EAAE,YAAY,GAAG,QAAQ,EAAE,EAAE,CAqB9F;AAqCD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,QAAQ,CAAA;IACd,KAAK,EAAE,MAAM,CAAA;IACb,KAAK,EAAE,MAAM,CAAA;CACd;AAED,MAAM,WAAW,mBAAoB,SAAQ,kBAAkB;IAC7D,OAAO,EAAE,WAAW,CAAA;IACpB,OAAO,EAAE,OAAO,CAAA;IAChB,UAAU,EAAE,MAAM,CAAA;IAClB,SAAS,CAAC,EAAE,aAAa,CAAA;CAC1B;AA4CD,MAAM,WAAW,uBAAuB;IACtC,SAAS,EAAE,QAAQ,EAAE,CAAA;IACrB,QAAQ,EAAE,YAAY,CAAA;IACtB,WAAW,EAAE,WAAW,CAAA;IACxB,cAAc,EAAE,MAAM,CAAA;IACtB,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACrE,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CACxE;AAED,wBAAsB,gBAAgB,CAAC,OAAO,EAAE,uBAAuB,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC,CAuD/F"}
@@ -0,0 +1,136 @@
1
+ import { applyToolResultBudget, resolveToolResultBudgetFromEnv } from "./budget.js";
2
+ function parseToolArgs(raw) {
3
+ try {
4
+ return JSON.parse(raw);
5
+ }
6
+ catch {
7
+ return {};
8
+ }
9
+ }
10
+ function isConcurrencySafe(call, registry) {
11
+ const tool = registry.get(call.function.name);
12
+ return tool?.concurrencySafe === true;
13
+ }
14
+ export function partitionToolCalls(toolCalls, registry) {
15
+ const batches = [];
16
+ let currentSafeBatch = [];
17
+ for (const call of toolCalls) {
18
+ if (isConcurrencySafe(call, registry)) {
19
+ currentSafeBatch.push(call);
20
+ continue;
21
+ }
22
+ if (currentSafeBatch.length > 0) {
23
+ batches.push(currentSafeBatch);
24
+ currentSafeBatch = [];
25
+ }
26
+ batches.push([call]);
27
+ }
28
+ if (currentSafeBatch.length > 0) {
29
+ batches.push(currentSafeBatch);
30
+ }
31
+ return batches;
32
+ }
33
+ async function runToolCall(call, registry, toolContext) {
34
+ const tool = registry.get(call.function.name);
35
+ if (!tool) {
36
+ return {
37
+ message: {
38
+ role: 'tool',
39
+ tool_call_id: call.id,
40
+ content: `Unknown tool: ${call.function.name}`
41
+ },
42
+ isError: true
43
+ };
44
+ }
45
+ const args = parseToolArgs(call.function.arguments);
46
+ const result = await tool.execute(args, toolContext);
47
+ const budget = resolveToolResultBudgetFromEnv();
48
+ const budgeted = applyToolResultBudget(result.content, budget);
49
+ const content = budgeted.truncated
50
+ ? `${budgeted.content}\n[tool result truncated by budget]`
51
+ : budgeted.content;
52
+ return {
53
+ message: {
54
+ role: 'tool',
55
+ tool_call_id: call.id,
56
+ content: content && content.trim() !== '' ? content : '(no output)'
57
+ },
58
+ isError: result.isError,
59
+ uiPayload: result.uiPayload
60
+ };
61
+ }
62
+ async function executeSafeBatch(batch, registry, toolContext, maxConcurrency, indexById, total, onToolCallStart, onToolCallResult) {
63
+ const results = new Array(batch.length);
64
+ let cursor = 0;
65
+ async function worker() {
66
+ for (;;) {
67
+ const index = cursor;
68
+ cursor += 1;
69
+ if (index >= batch.length)
70
+ return;
71
+ const call = batch[index];
72
+ const displayIndex = indexById.get(call.id) ?? index + 1;
73
+ await onToolCallStart?.({ call, index: displayIndex, total });
74
+ const startedAt = Date.now();
75
+ const outcome = await runToolCall(call, registry, toolContext);
76
+ const durationMs = Date.now() - startedAt;
77
+ results[index] = outcome;
78
+ await onToolCallResult?.({
79
+ call,
80
+ index: displayIndex,
81
+ total,
82
+ message: outcome.message,
83
+ isError: outcome.isError,
84
+ durationMs,
85
+ uiPayload: outcome.uiPayload
86
+ });
87
+ }
88
+ }
89
+ const workerCount = Math.max(1, Math.min(maxConcurrency, batch.length));
90
+ await Promise.all(Array.from({ length: workerCount }, () => worker()));
91
+ return results;
92
+ }
93
+ export async function executeToolCalls(options) {
94
+ const { toolCalls, registry, toolContext } = options;
95
+ const batches = partitionToolCalls(toolCalls, registry);
96
+ const total = toolCalls.length;
97
+ const indexById = new Map();
98
+ toolCalls.forEach((call, i) => indexById.set(call.id, i + 1));
99
+ const resultsById = new Map();
100
+ for (const batch of batches) {
101
+ if (batch.length === 0)
102
+ continue;
103
+ const safe = batch.every((call) => isConcurrencySafe(call, registry));
104
+ const batchResults = safe
105
+ ? await executeSafeBatch(batch, registry, toolContext, options.maxConcurrency, indexById, total, options.onToolCallStart, options.onToolCallResult)
106
+ : await (async () => {
107
+ const call = batch[0];
108
+ const index = indexById.get(call.id) ?? 1;
109
+ await options.onToolCallStart?.({ call, index, total });
110
+ const startedAt = Date.now();
111
+ const outcome = await runToolCall(call, registry, toolContext);
112
+ const durationMs = Date.now() - startedAt;
113
+ await options.onToolCallResult?.({
114
+ call,
115
+ index,
116
+ total,
117
+ message: outcome.message,
118
+ isError: outcome.isError,
119
+ durationMs,
120
+ uiPayload: outcome.uiPayload
121
+ });
122
+ return [outcome];
123
+ })();
124
+ for (const { message } of batchResults) {
125
+ if (message.tool_call_id) {
126
+ resultsById.set(message.tool_call_id, message);
127
+ }
128
+ }
129
+ }
130
+ return toolCalls.map((call) => (resultsById.get(call.id) ?? {
131
+ role: 'tool',
132
+ tool_call_id: call.id,
133
+ content: '[Tool execution missing result]'
134
+ }));
135
+ }
136
+ //# sourceMappingURL=executor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/runtime/executor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,48 @@
1
+ import type { ChatMessage, LoopState, LoopTerminal, ModelProvider } from '../types.js';
2
+ import type { PermissionStore } from '../tools/types.js';
3
+ import { type ToolCallResultEvent, type ToolCallStartEvent } from './executor.ts';
4
+ import { ToolRegistry } from '../tools/registry.ts';
5
+ export interface RunLoopOptions {
6
+ provider: ModelProvider;
7
+ registry: ToolRegistry;
8
+ systemPrompt: string;
9
+ userPrompt: string;
10
+ cwd: string;
11
+ permissions?: PermissionStore;
12
+ maxTurns?: number;
13
+ initialMessages?: ChatMessage[];
14
+ persistInitialMessages?: boolean;
15
+ onMessageAppended?: (message: ChatMessage) => Promise<void> | void;
16
+ onUsage?: (usage: {
17
+ prompt_tokens: number;
18
+ completion_tokens: number;
19
+ cached_tokens?: number | null;
20
+ provider?: string;
21
+ }) => Promise<void> | void;
22
+ onTurnStart?: (event: {
23
+ turn: number;
24
+ }) => Promise<void> | void;
25
+ onAssistantResponse?: (event: {
26
+ turn: number;
27
+ finish_reason: string;
28
+ tool_calls_count: number;
29
+ content: string | null;
30
+ }) => Promise<void> | void;
31
+ onToolCallStart?: (event: ToolCallStartEvent) => Promise<void> | void;
32
+ onToolCallResult?: (event: ToolCallResultEvent) => Promise<void> | void;
33
+ }
34
+ export interface RunLoopResult {
35
+ terminal: LoopTerminal;
36
+ finalText: string;
37
+ state: LoopState;
38
+ }
39
+ /**
40
+ * Returns true when the model's response looks like a false start:
41
+ * it promised to take action but produced no tool calls.
42
+ *
43
+ * Deliberately conservative to avoid nudging genuine short completions
44
+ * ("done", "在", "yes") or complete summaries.
45
+ */
46
+ export declare function shouldNudge(text: string, state: LoopState): boolean;
47
+ export declare function runLoop(options: RunLoopOptions): Promise<RunLoopResult>;
48
+ //# sourceMappingURL=loop.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/runtime/loop.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AACtF,OAAO,KAAK,EAAE,eAAe,EAAe,MAAM,mBAAmB,CAAA;AACrE,OAAO,EAAoB,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,eAAe,CAAA;AAEnG,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AAGnD,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,aAAa,CAAA;IACvB,QAAQ,EAAE,YAAY,CAAA;IACtB,YAAY,EAAE,MAAM,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,GAAG,EAAE,MAAM,CAAA;IACX,WAAW,CAAC,EAAE,eAAe,CAAA;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,eAAe,CAAC,EAAE,WAAW,EAAE,CAAA;IAC/B,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAClE,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE;QAChB,aAAa,EAAE,MAAM,CAAA;QACrB,iBAAiB,EAAE,MAAM,CAAA;QACzB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;QAC7B,QAAQ,CAAC,EAAE,MAAM,CAAA;KAClB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAC1B,WAAW,CAAC,EAAE,CAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAC/D,mBAAmB,CAAC,EAAE,CAAC,KAAK,EAAE;QAC5B,IAAI,EAAE,MAAM,CAAA;QACZ,aAAa,EAAE,MAAM,CAAA;QACrB,gBAAgB,EAAE,MAAM,CAAA;QACxB,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;KACvB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAC1B,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IACrE,gBAAgB,CAAC,EAAE,CAAC,KAAK,EAAE,mBAAmB,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CACxE;AAED,MAAM,WAAW,aAAa;IAC5B,QAAQ,EAAE,YAAY,CAAA;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,KAAK,EAAE,SAAS,CAAA;CACjB;AAYD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,GAAG,OAAO,CAUnE;AAmCD,wBAAsB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,OAAO,CAAC,aAAa,CAAC,CAiJ7E"}
@@ -0,0 +1,184 @@
1
+ import { executeToolCalls } from "./executor.js";
2
+ import { withRetry } from "./retry.js";
3
+ import { compactMessages, estimateMessagesChars } from "../context/compact.js";
4
+ // Patterns that signal the model promised action but made no tool calls.
5
+ // Only tested on responses ≥50 chars to avoid flagging conversational short replies.
6
+ const WILL_DO_PATTERNS = [
7
+ /\bi('ll| will)\s+(start|begin|look|check|read|analyze|examine|fix|help|try|write|create|update|run|search|find)/i,
8
+ /\blet me\s+(start|begin|look|check|read|analyze|examine|fix|help|try|write|create|update|run|search|find)/i,
9
+ /\bi('m| am) going to\s+\w/i,
10
+ /\bfirst,?\s+i('ll| will)\s+\w/i,
11
+ /\bto (start|begin|proceed),?\s+i('ll| will)\s+\w/i,
12
+ ];
13
+ /**
14
+ * Returns true when the model's response looks like a false start:
15
+ * it promised to take action but produced no tool calls.
16
+ *
17
+ * Deliberately conservative to avoid nudging genuine short completions
18
+ * ("done", "在", "yes") or complete summaries.
19
+ */
20
+ export function shouldNudge(text, state) {
21
+ // Hard cap: never nudge more than twice per session
22
+ if (state.nudgeCount >= 2)
23
+ return false;
24
+ // Very short text is always conversational — never nudge
25
+ // "在", "done", "ok", "yes", "finished", etc.
26
+ if (text.trim().length < 50)
27
+ return false;
28
+ // Core signal: contains a "will do X" promise without having done X
29
+ return WILL_DO_PATTERNS.some((p) => p.test(text));
30
+ }
31
+ function createState(systemPrompt, userPrompt, initialMessages) {
32
+ const messages = initialMessages
33
+ ? [...initialMessages]
34
+ : [
35
+ { role: 'system', content: systemPrompt },
36
+ { role: 'user', content: userPrompt },
37
+ ];
38
+ if (initialMessages && userPrompt.trim() !== '') {
39
+ messages.push({ role: 'user', content: userPrompt });
40
+ }
41
+ return {
42
+ messages,
43
+ turnCount: 0,
44
+ maxOutputTokensRecoveryCount: 0,
45
+ hasAttemptedReactiveCompact: false,
46
+ nudgeCount: 0,
47
+ };
48
+ }
49
+ function parsePositiveInt(raw, fallback) {
50
+ if (raw === undefined || raw.trim() === '')
51
+ return fallback;
52
+ const parsed = Number(raw);
53
+ if (!Number.isFinite(parsed))
54
+ return fallback;
55
+ const value = Math.floor(parsed);
56
+ return value > 0 ? value : fallback;
57
+ }
58
+ export async function runLoop(options) {
59
+ const state = createState(options.systemPrompt, options.userPrompt, options.initialMessages);
60
+ const maxTurns = options.maxTurns ?? 100;
61
+ let finalText = '';
62
+ let emptyStopRecoveryCount = 0;
63
+ let awaitingPostToolSummary = false;
64
+ const defaultPermissions = { ask: async () => 'allow' };
65
+ const toolContext = {
66
+ cwd: options.cwd,
67
+ permissions: options.permissions ?? defaultPermissions,
68
+ };
69
+ if (options.persistInitialMessages !== false) {
70
+ for (const msg of state.messages) {
71
+ await options.onMessageAppended?.(msg);
72
+ }
73
+ }
74
+ for (;;) {
75
+ if (state.turnCount >= maxTurns) {
76
+ return { terminal: 'max_turns_exceeded', finalText, state };
77
+ }
78
+ let assistant;
79
+ try {
80
+ const compactTriggerChars = parsePositiveInt(process.env.MERLION_COMPACT_TRIGGER_CHARS, 60_000);
81
+ const keepRecent = parsePositiveInt(process.env.MERLION_COMPACT_KEEP_RECENT, 10);
82
+ const chars = estimateMessagesChars(state.messages);
83
+ if (chars > compactTriggerChars && !state.hasAttemptedReactiveCompact) {
84
+ const compacted = compactMessages(state.messages, { keepRecent });
85
+ if (compacted.compacted) {
86
+ state.messages = compacted.messages;
87
+ state.hasAttemptedReactiveCompact = true;
88
+ }
89
+ }
90
+ await options.onTurnStart?.({ turn: state.turnCount + 1 });
91
+ assistant = await withRetry(() => options.provider.complete(state.messages, options.registry.getAll()), { maxAttempts: 5, baseDelayMs: 200, maxDelayMs: 32_000 });
92
+ }
93
+ catch {
94
+ return { terminal: 'model_error', finalText, state };
95
+ }
96
+ state.turnCount += 1;
97
+ const assistantMessage = {
98
+ role: 'assistant',
99
+ content: assistant.content,
100
+ tool_calls: assistant.tool_calls,
101
+ };
102
+ state.messages.push(assistantMessage);
103
+ await options.onMessageAppended?.(assistantMessage);
104
+ await options.onUsage?.(assistant.usage);
105
+ await options.onAssistantResponse?.({
106
+ turn: state.turnCount,
107
+ finish_reason: assistant.finish_reason,
108
+ tool_calls_count: assistant.tool_calls?.length ?? 0,
109
+ content: assistant.content
110
+ });
111
+ // ── tool_calls ──────────────────────────────────────────────────────────
112
+ if (assistant.finish_reason === 'tool_calls' &&
113
+ assistant.tool_calls &&
114
+ assistant.tool_calls.length > 0) {
115
+ const maxConcurrency = Number(process.env.MERLION_MAX_TOOL_CONCURRENCY ?? '10');
116
+ const toolMessages = await executeToolCalls({
117
+ toolCalls: assistant.tool_calls,
118
+ registry: options.registry,
119
+ toolContext,
120
+ maxConcurrency: Number.isFinite(maxConcurrency) ? Math.max(1, Math.floor(maxConcurrency)) : 10,
121
+ onToolCallStart: options.onToolCallStart,
122
+ onToolCallResult: options.onToolCallResult,
123
+ });
124
+ for (const toolMsg of toolMessages) {
125
+ state.messages.push(toolMsg);
126
+ await options.onMessageAppended?.(toolMsg);
127
+ }
128
+ continue;
129
+ }
130
+ // ── length (output truncated) ────────────────────────────────────────────
131
+ if (assistant.finish_reason === 'length' && state.maxOutputTokensRecoveryCount < 3) {
132
+ state.maxOutputTokensRecoveryCount += 1;
133
+ const continueMessage = {
134
+ role: 'user',
135
+ content: 'Output was cut off. Continue directly from where you stopped. No recap, no apology.',
136
+ };
137
+ state.messages.push(continueMessage);
138
+ await options.onMessageAppended?.(continueMessage);
139
+ continue;
140
+ }
141
+ // ── content_filter ───────────────────────────────────────────────────────
142
+ if (assistant.finish_reason === 'content_filter') {
143
+ return { terminal: 'model_error', finalText, state };
144
+ }
145
+ // ── stop (and length-recovery exhausted) ────────────────────────────────
146
+ const text = assistant.content ?? '';
147
+ const previousMessage = state.messages[state.messages.length - 2];
148
+ const previousWasTool = previousMessage?.role === 'tool';
149
+ const shouldRecoverEmptyStop = previousWasTool || awaitingPostToolSummary;
150
+ if (assistant.finish_reason === 'stop' && text.trim() === '' && shouldRecoverEmptyStop) {
151
+ if (emptyStopRecoveryCount < 1) {
152
+ emptyStopRecoveryCount += 1;
153
+ awaitingPostToolSummary = true;
154
+ const summaryRequest = {
155
+ role: 'user',
156
+ content: 'You just finished tool execution. Provide a concise final summary of what changed and any next steps.',
157
+ };
158
+ state.messages.push(summaryRequest);
159
+ await options.onMessageAppended?.(summaryRequest);
160
+ continue;
161
+ }
162
+ finalText = 'Task completed via tool execution, but the model returned no final summary.';
163
+ return { terminal: 'completed', finalText, state };
164
+ }
165
+ if (text.trim() !== '') {
166
+ awaitingPostToolSummary = false;
167
+ }
168
+ // Nudge: model promised action but made no tool call
169
+ if (shouldNudge(text, state)) {
170
+ const nudgeMessage = {
171
+ role: 'user',
172
+ content: 'Continue with the task. Use your tools to make progress. ' +
173
+ 'If you have completed everything, describe what was done.',
174
+ };
175
+ state.messages.push(nudgeMessage);
176
+ await options.onMessageAppended?.(nudgeMessage);
177
+ state.nudgeCount += 1;
178
+ continue;
179
+ }
180
+ finalText = text;
181
+ return { terminal: 'completed', finalText, state };
182
+ }
183
+ }
184
+ //# sourceMappingURL=loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/runtime/loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export interface RetryOptions {
2
+ maxAttempts: number;
3
+ baseDelayMs: number;
4
+ maxDelayMs: number;
5
+ }
6
+ export declare function withRetry<T>(fn: () => Promise<T>, options: RetryOptions): Promise<T>;
7
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/runtime/retry.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,YAAY;IAC3B,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;CACnB;AA4BD,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EACpB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,CAAC,CAAC,CAiBZ"}
@@ -0,0 +1,42 @@
1
+ function extractStatusCode(message) {
2
+ const match = message.match(/\b(400|401|403|429|500|502|503|529)\b/);
3
+ return match ? Number(match[1]) : null;
4
+ }
5
+ function isRetryableError(error) {
6
+ const message = String(error);
7
+ const code = extractStatusCode(message);
8
+ if (code === null) {
9
+ return /ECONNRESET|EPIPE|ENOTFOUND|ETIMEDOUT/i.test(message);
10
+ }
11
+ return code === 429 || code === 500 || code === 502 || code === 503 || code === 529;
12
+ }
13
+ function isPermanentError(error) {
14
+ const message = String(error);
15
+ const code = extractStatusCode(message);
16
+ return code === 400 || code === 401 || code === 403;
17
+ }
18
+ function delay(attempt, baseDelayMs, maxDelayMs) {
19
+ const exp = Math.min(maxDelayMs, baseDelayMs * Math.pow(2, Math.max(0, attempt - 1)));
20
+ const jitter = Math.floor(exp * 0.25 * Math.random());
21
+ return new Promise((resolve) => setTimeout(resolve, exp + jitter));
22
+ }
23
+ export async function withRetry(fn, options) {
24
+ let attempt = 0;
25
+ let lastError = undefined;
26
+ while (attempt < options.maxAttempts) {
27
+ attempt += 1;
28
+ try {
29
+ return await fn();
30
+ }
31
+ catch (error) {
32
+ lastError = error;
33
+ if (isPermanentError(error))
34
+ throw error;
35
+ if (!isRetryableError(error) || attempt >= options.maxAttempts)
36
+ throw error;
37
+ await delay(attempt, options.baseDelayMs, options.maxDelayMs);
38
+ }
39
+ }
40
+ throw lastError ?? new Error('Retry exhausted');
41
+ }
42
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/runtime/retry.ts"],"names":[],"mappings":"AAMA,SAAS,iBAAiB,CAAC,OAAe;IACxC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,uCAAuC,CAAC,CAAA;IACpE,OAAO,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;AACxC,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAC7B,MAAM,IAAI,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAA;IACvC,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;QAClB,OAAO,uCAAuC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IAC9D,CAAC;IACD,OAAO,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,CAAA;AACrF,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,MAAM,OAAO,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAC7B,MAAM,IAAI,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAA;IACvC,OAAO,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,IAAI,IAAI,KAAK,GAAG,CAAA;AACrD,CAAC;AAED,SAAS,KAAK,CAAC,OAAe,EAAE,WAAmB,EAAE,UAAkB;IACrE,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;IACrF,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,GAAG,IAAI,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;IACrD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,GAAG,MAAM,CAAC,CAAC,CAAA;AACpE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,EAAoB,EACpB,OAAqB;IAErB,IAAI,OAAO,GAAG,CAAC,CAAA;IACf,IAAI,SAAS,GAAY,SAAS,CAAA;IAElC,OAAO,OAAO,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;QACrC,OAAO,IAAI,CAAC,CAAA;QACZ,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,EAAE,CAAA;QACnB,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,SAAS,GAAG,KAAK,CAAA;YACjB,IAAI,gBAAgB,CAAC,KAAK,CAAC;gBAAE,MAAM,KAAK,CAAA;YACxC,IAAI,CAAC,gBAAgB,CAAC,KAAK,CAAC,IAAI,OAAO,IAAI,OAAO,CAAC,WAAW;gBAAE,MAAM,KAAK,CAAA;YAC3E,MAAM,KAAK,CAAC,OAAO,EAAE,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC,UAAU,CAAC,CAAA;QAC/D,CAAC;IACH,CAAC;IAED,MAAM,SAAS,IAAI,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAA;AACjD,CAAC"}
@@ -0,0 +1,26 @@
1
+ import type { ChatMessage } from '../types.js';
2
+ export interface SessionFiles {
3
+ sessionId: string;
4
+ projectHash: string;
5
+ projectDir: string;
6
+ transcriptPath: string;
7
+ usagePath: string;
8
+ }
9
+ export interface UsageEntry {
10
+ timestamp: string;
11
+ session_id: string;
12
+ model: string;
13
+ provider?: string;
14
+ prompt_tokens: number;
15
+ completion_tokens: number;
16
+ cached_tokens: number | null;
17
+ tool_schema_tokens_estimate: number;
18
+ }
19
+ export declare function redactSecrets(input: string): string;
20
+ export declare function createSessionFiles(cwd: string): Promise<SessionFiles>;
21
+ export declare function getSessionFilesForResume(cwd: string, sessionId: string): Promise<SessionFiles>;
22
+ export declare function appendSessionMeta(transcriptPath: string, sessionId: string, model: string, projectPath: string): Promise<void>;
23
+ export declare function appendTranscriptMessage(transcriptPath: string, message: ChatMessage): Promise<void>;
24
+ export declare function appendUsage(usagePath: string, entry: UsageEntry): Promise<void>;
25
+ export declare function loadSessionMessages(transcriptPath: string): Promise<ChatMessage[]>;
26
+ //# sourceMappingURL=session.d.ts.map