reasonix 0.3.2 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -0
- package/dist/cli/chunk-2P2MZLCE.js +81 -0
- package/dist/cli/chunk-2P2MZLCE.js.map +1 -0
- package/dist/cli/index.js +661 -55
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/prompt-MMANQ36Z.js +10 -0
- package/dist/cli/prompt-MMANQ36Z.js.map +1 -0
- package/dist/index.d.ts +151 -3
- package/dist/index.js +327 -28
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/index.d.ts
CHANGED
|
@@ -433,7 +433,15 @@ declare class ToolRegistry {
|
|
|
433
433
|
dispatch(name: string, argumentsRaw: string | Record<string, unknown>): Promise<string>;
|
|
434
434
|
}
|
|
435
435
|
|
|
436
|
-
type EventRole = "assistant_delta" | "assistant_final"
|
|
436
|
+
type EventRole = "assistant_delta" | "assistant_final"
|
|
437
|
+
/**
|
|
438
|
+
* Yielded immediately before a tool is dispatched. Lets the TUI put
|
|
439
|
+
* up a "▸ tool<X> running…" spinner while the tool's Promise is
|
|
440
|
+
* pending — otherwise the UI looks frozen whenever a tool call
|
|
441
|
+
* takes more than a few hundred ms (a big `filesystem_edit_file`
|
|
442
|
+
* is a typical trigger).
|
|
443
|
+
*/
|
|
444
|
+
| "tool_start" | "tool" | "done" | "error" | "warning" | "branch_start" | "branch_progress" | "branch_done";
|
|
437
445
|
interface BranchSummary {
|
|
438
446
|
budget: number;
|
|
439
447
|
chosenIndex: number;
|
|
@@ -465,6 +473,16 @@ interface LoopEvent {
|
|
|
465
473
|
branch?: BranchSummary;
|
|
466
474
|
branchProgress?: BranchProgress;
|
|
467
475
|
error?: string;
|
|
476
|
+
/**
|
|
477
|
+
* True on `assistant_final` events emitted by the no-tools fallback
|
|
478
|
+
* when the loop hit its budget, was aborted, or tripped the
|
|
479
|
+
* token-context guard. Consumers that act on assistant text (notably
|
|
480
|
+
* the code-mode edit applier) MUST treat these as display-only —
|
|
481
|
+
* the model is "wrapping up," not proposing new work. Applying
|
|
482
|
+
* SEARCH/REPLACE blocks found in a forced summary caused the
|
|
483
|
+
* "analysis became edits" bug in v0.4.1 and earlier.
|
|
484
|
+
*/
|
|
485
|
+
forcedSummary?: boolean;
|
|
468
486
|
}
|
|
469
487
|
interface CacheFirstLoopOptions {
|
|
470
488
|
client: DeepSeekClient;
|
|
@@ -567,11 +585,34 @@ declare class CacheFirstLoop {
|
|
|
567
585
|
* answer instead of a cliff. Called by the TUI on Esc.
|
|
568
586
|
*/
|
|
569
587
|
abort(): void;
|
|
588
|
+
/**
|
|
589
|
+
* Drop everything in the log after (and including) the most recent
|
|
590
|
+
* user message. Used by `/retry` so the caller can re-send that
|
|
591
|
+
* message with a fresh turn instead of layering another response on
|
|
592
|
+
* top of the prior exchange. Returns the content of the dropped user
|
|
593
|
+
* message, or `null` if there isn't one yet.
|
|
594
|
+
*
|
|
595
|
+
* Persists by rewriting the session file — otherwise the next
|
|
596
|
+
* launch would rehydrate the old exchange and `/retry` would seem
|
|
597
|
+
* to have done nothing.
|
|
598
|
+
*/
|
|
599
|
+
retryLastUser(): string | null;
|
|
570
600
|
step(userInput: string): AsyncGenerator<LoopEvent>;
|
|
571
601
|
private forceSummaryAfterIterLimit;
|
|
572
602
|
run(userInput: string, onEvent?: (ev: LoopEvent) => void): Promise<string>;
|
|
573
603
|
private assistantMessage;
|
|
574
604
|
}
|
|
605
|
+
/**
|
|
606
|
+
* R1 occasionally hallucinates tool-call markup as plain text when the
|
|
607
|
+
* real tool channel has been closed — typically our forced-summary
|
|
608
|
+
* path, where `tools: undefined` is supposed to force prose but isn't
|
|
609
|
+
* always respected. The markup isn't parsed by our tool-call path
|
|
610
|
+
* (the API response's structured `tool_calls` field is empty), so
|
|
611
|
+
* it's just noise in the user's view. Strip known envelope shapes.
|
|
612
|
+
*
|
|
613
|
+
* Exported so tests can exercise it against concrete R1 outputs.
|
|
614
|
+
*/
|
|
615
|
+
declare function stripHallucinatedToolMarkup(s: string): string;
|
|
575
616
|
/**
|
|
576
617
|
* Truncate any tool-role message whose content exceeds the cap. User
|
|
577
618
|
* and assistant messages are left alone because (a) they're almost
|
|
@@ -1238,6 +1279,113 @@ interface SseMcpSpec {
|
|
|
1238
1279
|
type McpSpec = StdioMcpSpec | SseMcpSpec;
|
|
1239
1280
|
declare function parseMcpSpec(input: string): McpSpec;
|
|
1240
1281
|
|
|
1282
|
+
/**
|
|
1283
|
+
* Aider-style SEARCH/REPLACE edit blocks.
|
|
1284
|
+
*
|
|
1285
|
+
* The model emits blocks in this exact shape, one or more per response:
|
|
1286
|
+
*
|
|
1287
|
+
* path/to/file.ts
|
|
1288
|
+
* <<<<<<< SEARCH
|
|
1289
|
+
* exact existing lines (whitespace-sensitive)
|
|
1290
|
+
* =======
|
|
1291
|
+
* replacement lines
|
|
1292
|
+
* >>>>>>> REPLACE
|
|
1293
|
+
*
|
|
1294
|
+
* We chose this over unified diffs because:
|
|
1295
|
+
* - Models produce it reliably — no line-number drift.
|
|
1296
|
+
* - It tolerates multi-edit responses without ambiguity over which
|
|
1297
|
+
* hunk belongs to which file.
|
|
1298
|
+
* - Aider has years of evidence that this format works even against
|
|
1299
|
+
* weaker models than DeepSeek R1, so it's a conservative pick.
|
|
1300
|
+
*
|
|
1301
|
+
* The SEARCH text must match the file byte-for-byte. Empty SEARCH is a
|
|
1302
|
+
* sentinel for "create new file" — the REPLACE becomes the whole file.
|
|
1303
|
+
* If SEARCH doesn't match we refuse the edit and surface the failure;
|
|
1304
|
+
* we do NOT guess or fuzzy-match. A wrong silent edit is worse than a
|
|
1305
|
+
* missing one — the user can re-ask with the exact current content.
|
|
1306
|
+
*/
|
|
1307
|
+
interface EditBlock {
|
|
1308
|
+
/** Path as written by the model — relative to rootDir, or absolute. */
|
|
1309
|
+
path: string;
|
|
1310
|
+
/** Literal text to match in the target file. Empty → create new file. */
|
|
1311
|
+
search: string;
|
|
1312
|
+
/** Replacement text to write in place of `search`. */
|
|
1313
|
+
replace: string;
|
|
1314
|
+
/** Char offset in the source message where this block started. */
|
|
1315
|
+
offset: number;
|
|
1316
|
+
}
|
|
1317
|
+
type ApplyStatus =
|
|
1318
|
+
/** Edit landed on disk. */
|
|
1319
|
+
"applied"
|
|
1320
|
+
/** New file created (SEARCH was empty and file didn't exist). */
|
|
1321
|
+
| "created"
|
|
1322
|
+
/** File exists but SEARCH block wasn't found in its content. */
|
|
1323
|
+
| "not-found"
|
|
1324
|
+
/** File doesn't exist and SEARCH was non-empty (can't create without content). */
|
|
1325
|
+
| "file-missing"
|
|
1326
|
+
/** Path escapes rootDir — refused on safety grounds. */
|
|
1327
|
+
| "path-escape"
|
|
1328
|
+
/** fs write / read threw. */
|
|
1329
|
+
| "error";
|
|
1330
|
+
interface ApplyResult {
|
|
1331
|
+
path: string;
|
|
1332
|
+
status: ApplyStatus;
|
|
1333
|
+
/** Extra detail (e.g. error message) for logs. */
|
|
1334
|
+
message?: string;
|
|
1335
|
+
}
|
|
1336
|
+
declare function parseEditBlocks(text: string): EditBlock[];
|
|
1337
|
+
declare function applyEditBlock(block: EditBlock, rootDir: string): ApplyResult;
|
|
1338
|
+
declare function applyEditBlocks(blocks: EditBlock[], rootDir: string): ApplyResult[];
|
|
1339
|
+
interface EditSnapshot {
|
|
1340
|
+
/** Path relative to rootDir, as the block named it. */
|
|
1341
|
+
path: string;
|
|
1342
|
+
/**
|
|
1343
|
+
* File content before the edit batch was applied. `null` means the
|
|
1344
|
+
* file didn't exist yet — restoring that means deleting whatever the
|
|
1345
|
+
* edit created.
|
|
1346
|
+
*/
|
|
1347
|
+
prevContent: string | null;
|
|
1348
|
+
}
|
|
1349
|
+
/**
|
|
1350
|
+
* Capture the current state of every file an edit batch is about to
|
|
1351
|
+
* touch, so `/undo` can roll back if the user doesn't like the result.
|
|
1352
|
+
* De-duplicates by path because one batch can contain multiple blocks
|
|
1353
|
+
* for the same file, and we only want one "before" snapshot per file.
|
|
1354
|
+
*/
|
|
1355
|
+
declare function snapshotBeforeEdits(blocks: EditBlock[], rootDir: string): EditSnapshot[];
|
|
1356
|
+
/**
|
|
1357
|
+
* Restore files to their snapshotted state. Snapshots with
|
|
1358
|
+
* `prevContent === null` were created by the edit, so undo = delete.
|
|
1359
|
+
* Otherwise the prior content is written back, replacing whatever the
|
|
1360
|
+
* edit left behind.
|
|
1361
|
+
*/
|
|
1362
|
+
declare function restoreSnapshots(snapshots: EditSnapshot[], rootDir: string): ApplyResult[];
|
|
1363
|
+
|
|
1364
|
+
/**
|
|
1365
|
+
* System prompt used by `reasonix code`. Teaches the model:
|
|
1366
|
+
*
|
|
1367
|
+
* 1. It has a filesystem MCP bridge rooted at the user's CWD.
|
|
1368
|
+
* 2. To modify files it emits SEARCH/REPLACE blocks (not
|
|
1369
|
+
* `write_file` — that would whole-file rewrite and kill diff
|
|
1370
|
+
* reviewability).
|
|
1371
|
+
* 3. Read first, edit second — SEARCH must match byte-for-byte.
|
|
1372
|
+
* 4. Be concise. The user can read a diff faster than prose.
|
|
1373
|
+
*
|
|
1374
|
+
* Kept short on purpose. Long system prompts eat context budget that
|
|
1375
|
+
* the Cache-First Loop is trying to conserve. The SEARCH/REPLACE spec
|
|
1376
|
+
* is the one unavoidable bloat; we trim everything else.
|
|
1377
|
+
*/
|
|
1378
|
+
declare const CODE_SYSTEM_PROMPT = "You are Reasonix Code, a coding assistant. You have filesystem tools (read_file, write_file, list_directory, search_files, etc.) rooted at the user's working directory.\n\n# When to edit vs. when to explore\n\nOnly propose edits when the user explicitly asks you to change, fix, add, remove, refactor, or write something. Do NOT propose edits when the user asks you to:\n- analyze, read, explore, describe, or summarize a project\n- explain how something works\n- answer a question about the code\n\nIn those cases, use tools to gather what you need, then reply in prose. No SEARCH/REPLACE blocks, no file changes. If you're unsure what the user wants, ask.\n\nWhen you do propose edits, the user will review them and decide whether to `/apply` or `/discard`. Don't assume they'll accept \u2014 write as if each edit will be audited, because it will.\n\n# Editing files\n\nWhen you've been asked to change a file, output one or more SEARCH/REPLACE blocks in this exact format:\n\npath/to/file.ext\n<<<<<<< SEARCH\nexact existing lines from the file, including whitespace\n=======\nthe new lines\n>>>>>>> REPLACE\n\nRules:\n- Always read_file first so your SEARCH matches byte-for-byte. If it doesn't match, the edit is rejected and you'll have to retry with the exact current content.\n- One edit per block. Multiple blocks in one response are fine.\n- To create a new file, leave SEARCH empty:\n path/to/new.ts\n <<<<<<< SEARCH\n =======\n (whole file content here)\n >>>>>>> REPLACE\n- Do NOT use write_file to change existing files \u2014 the user reviews your edits as SEARCH/REPLACE. write_file is only for files you explicitly want to overwrite wholesale (rare).\n- Paths are relative to the working directory. Don't use absolute paths.\n\n# Exploration\n\n- Avoid listing or reading inside these common dependency / build directories unless the user explicitly asks about them: node_modules, dist, build, out, .next, .nuxt, .svelte-kit, .git, .venv, venv, __pycache__, target, coverage, .turbo, .cache. They're expensive and usually irrelevant.\n- Prefer search_files / grep over list_directory when you know roughly what you're looking for \u2014 it saves context and avoids enumerating huge trees.\n\n# Style\n\n- Show edits; don't narrate them in prose. \"Here's the fix:\" is enough.\n- One short paragraph explaining *why*, then the blocks.\n- If you need to explore first (list / grep / read), do it with tool calls before writing any prose \u2014 silence while exploring is fine.\n";
|
|
1379
|
+
/**
|
|
1380
|
+
* Inject the project's `.gitignore` content into the system prompt as a
|
|
1381
|
+
* "respect this on top of the built-in denylist" hint. We don't parse
|
|
1382
|
+
* the file — we hand it to the model as-is. Truncate long ones so we
|
|
1383
|
+
* don't eat context budget on huge generated ignore lists.
|
|
1384
|
+
*
|
|
1385
|
+
* Missing or unreadable .gitignore → returns the base prompt unchanged.
|
|
1386
|
+
*/
|
|
1387
|
+
declare function codeSystemPrompt(rootDir: string): string;
|
|
1388
|
+
|
|
1241
1389
|
/**
|
|
1242
1390
|
* User-level config storage for the Reasonix CLI.
|
|
1243
1391
|
*
|
|
@@ -1291,6 +1439,6 @@ declare function redactKey(key: string): string;
|
|
|
1291
1439
|
|
|
1292
1440
|
/** Reasonix — DeepSeek-native agent framework. Library entry point. */
|
|
1293
1441
|
|
|
1294
|
-
declare const VERSION = "0.3
|
|
1442
|
+
declare const VERSION = "0.4.3";
|
|
1295
1443
|
|
|
1296
|
-
export { AppendOnlyLog, type BranchOptions, type BranchProgress, type BranchResult, type BranchSample, type BranchSelector, type BranchSummary, type BridgeOptions, type BridgeResult, CacheFirstLoop, type CacheFirstLoopOptions, type CallToolResult, type ChatMessage, type ChatResponse, DEFAULT_MAX_RESULT_CHARS, DeepSeekClient, type DeepSeekClientOptions, type RenderOptions as DiffRenderOptions, type DiffReport, type DiffSide, type EventRole, type FlattenDecision, type FlattenOptions, type HarvestOptions, ImmutablePrefix, type ImmutablePrefixOptions, type InitializeResult, type JSONSchema, type JsonRpcMessage, type JsonRpcRequest, type JsonRpcResponse, type ListToolsResult, type LoopEvent, MCP_PROTOCOL_VERSION, McpClient, type McpClientOptions, type McpContentBlock, type McpSpec, type McpTool, type McpToolSchema, type McpTransport, type ReadTranscriptResult, type ReasonixConfig, type ReconfigurableOptions, type RepairReport, type ReplayStats, type RetryInfo, type RetryOptions, type Role, type ScavengeOptions, type ScavengeResult, type SessionInfo, SessionStats, type SessionSummary, type SseMcpSpec, SseTransport, type SseTransportOptions, type StdioMcpSpec, StdioTransport, type StdioTransportOptions, StormBreaker, type StreamChunk, type ToolCall, ToolCallRepair, type ToolCallRepairOptions, type ToolDefinition, type ToolFunctionSpec, ToolRegistry, type ToolSpec, type TranscriptMeta, type TranscriptRecord, type TruncationRepairResult, type TurnPair, type TurnStats, type TypedPlanState, Usage, VERSION, VolatileScratch, aggregateBranchUsage, analyzeSchema, appendSessionMessage, bridgeMcpTools, claudeEquivalentCost, computeReplayStats, costUsd, defaultConfigPath, defaultSelector, deleteSession, diffTranscripts, emptyPlanState, fetchWithRetry, flattenMcpResult, flattenSchema, formatLoopError, harvest, healLoadedMessages, isJsonRpcError, isPlanStateEmpty, isPlausibleKey, listSessions, loadApiKey, loadDotenv, loadSessionMessages, nestArguments, openTranscriptFile, parseMcpSpec, parseTranscript, readConfig, readTranscript, recordFromLoopEvent, redactKey, renderMarkdown as renderDiffMarkdown, renderSummaryTable as renderDiffSummary, repairTruncatedJson, replayFromFile, runBranches, sanitizeName as sanitizeSessionName, saveApiKey, scavengeToolCalls, sessionPath, sessionsDir, similarity, truncateForModel, writeConfig, writeMeta, writeRecord };
|
|
1444
|
+
export { AppendOnlyLog, type ApplyResult, type ApplyStatus, type BranchOptions, type BranchProgress, type BranchResult, type BranchSample, type BranchSelector, type BranchSummary, type BridgeOptions, type BridgeResult, CODE_SYSTEM_PROMPT, CacheFirstLoop, type CacheFirstLoopOptions, type CallToolResult, type ChatMessage, type ChatResponse, DEFAULT_MAX_RESULT_CHARS, DeepSeekClient, type DeepSeekClientOptions, type RenderOptions as DiffRenderOptions, type DiffReport, type DiffSide, type EditBlock, type EditSnapshot, type EventRole, type FlattenDecision, type FlattenOptions, type HarvestOptions, ImmutablePrefix, type ImmutablePrefixOptions, type InitializeResult, type JSONSchema, type JsonRpcMessage, type JsonRpcRequest, type JsonRpcResponse, type ListToolsResult, type LoopEvent, MCP_PROTOCOL_VERSION, McpClient, type McpClientOptions, type McpContentBlock, type McpSpec, type McpTool, type McpToolSchema, type McpTransport, type ReadTranscriptResult, type ReasonixConfig, type ReconfigurableOptions, type RepairReport, type ReplayStats, type RetryInfo, type RetryOptions, type Role, type ScavengeOptions, type ScavengeResult, type SessionInfo, SessionStats, type SessionSummary, type SseMcpSpec, SseTransport, type SseTransportOptions, type StdioMcpSpec, StdioTransport, type StdioTransportOptions, StormBreaker, type StreamChunk, type ToolCall, ToolCallRepair, type ToolCallRepairOptions, type ToolDefinition, type ToolFunctionSpec, ToolRegistry, type ToolSpec, type TranscriptMeta, type TranscriptRecord, type TruncationRepairResult, type TurnPair, type TurnStats, type TypedPlanState, Usage, VERSION, VolatileScratch, aggregateBranchUsage, analyzeSchema, appendSessionMessage, applyEditBlock, applyEditBlocks, bridgeMcpTools, claudeEquivalentCost, codeSystemPrompt, computeReplayStats, costUsd, defaultConfigPath, defaultSelector, deleteSession, diffTranscripts, emptyPlanState, fetchWithRetry, flattenMcpResult, flattenSchema, formatLoopError, harvest, healLoadedMessages, isJsonRpcError, isPlanStateEmpty, isPlausibleKey, listSessions, loadApiKey, loadDotenv, loadSessionMessages, nestArguments, openTranscriptFile, parseEditBlocks, parseMcpSpec, parseTranscript, readConfig, readTranscript, recordFromLoopEvent, redactKey, renderMarkdown as renderDiffMarkdown, renderSummaryTable as renderDiffSummary, repairTruncatedJson, replayFromFile, restoreSnapshots, runBranches, sanitizeName as sanitizeSessionName, saveApiKey, scavengeToolCalls, sessionPath, sessionsDir, similarity, snapshotBeforeEdits, stripHallucinatedToolMarkup, truncateForModel, writeConfig, writeMeta, writeRecord };
|