reasonix 0.4.1 → 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/dist/cli/index.js +209 -24
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +25 -2
- package/dist/index.js +60 -4
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -585,11 +585,34 @@ declare class CacheFirstLoop {
|
|
|
585
585
|
* answer instead of a cliff. Called by the TUI on Esc.
|
|
586
586
|
*/
|
|
587
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;
|
|
588
600
|
step(userInput: string): AsyncGenerator<LoopEvent>;
|
|
589
601
|
private forceSummaryAfterIterLimit;
|
|
590
602
|
run(userInput: string, onEvent?: (ev: LoopEvent) => void): Promise<string>;
|
|
591
603
|
private assistantMessage;
|
|
592
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;
|
|
593
616
|
/**
|
|
594
617
|
* Truncate any tool-role message whose content exceeds the cap. User
|
|
595
618
|
* and assistant messages are left alone because (a) they're almost
|
|
@@ -1416,6 +1439,6 @@ declare function redactKey(key: string): string;
|
|
|
1416
1439
|
|
|
1417
1440
|
/** Reasonix — DeepSeek-native agent framework. Library entry point. */
|
|
1418
1441
|
|
|
1419
|
-
declare const VERSION = "0.4.
|
|
1442
|
+
declare const VERSION = "0.4.3";
|
|
1420
1443
|
|
|
1421
|
-
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, 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 };
|
package/dist/index.js
CHANGED
|
@@ -1234,6 +1234,39 @@ var CacheFirstLoop = class {
|
|
|
1234
1234
|
abort() {
|
|
1235
1235
|
this._aborted = true;
|
|
1236
1236
|
}
|
|
1237
|
+
/**
|
|
1238
|
+
* Drop everything in the log after (and including) the most recent
|
|
1239
|
+
* user message. Used by `/retry` so the caller can re-send that
|
|
1240
|
+
* message with a fresh turn instead of layering another response on
|
|
1241
|
+
* top of the prior exchange. Returns the content of the dropped user
|
|
1242
|
+
* message, or `null` if there isn't one yet.
|
|
1243
|
+
*
|
|
1244
|
+
* Persists by rewriting the session file — otherwise the next
|
|
1245
|
+
* launch would rehydrate the old exchange and `/retry` would seem
|
|
1246
|
+
* to have done nothing.
|
|
1247
|
+
*/
|
|
1248
|
+
retryLastUser() {
|
|
1249
|
+
const entries = this.log.entries;
|
|
1250
|
+
let lastUserIdx = -1;
|
|
1251
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
1252
|
+
if (entries[i].role === "user") {
|
|
1253
|
+
lastUserIdx = i;
|
|
1254
|
+
break;
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
if (lastUserIdx < 0) return null;
|
|
1258
|
+
const raw = entries[lastUserIdx].content;
|
|
1259
|
+
const userText = typeof raw === "string" ? raw : "";
|
|
1260
|
+
const preserved = entries.slice(0, lastUserIdx).map((m) => ({ ...m }));
|
|
1261
|
+
this.log.compactInPlace(preserved);
|
|
1262
|
+
if (this.sessionName) {
|
|
1263
|
+
try {
|
|
1264
|
+
rewriteSession(this.sessionName, preserved);
|
|
1265
|
+
} catch {
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
return userText;
|
|
1269
|
+
}
|
|
1237
1270
|
async *step(userInput) {
|
|
1238
1271
|
this._turn++;
|
|
1239
1272
|
this.scratch.reset();
|
|
@@ -1247,9 +1280,17 @@ var CacheFirstLoop = class {
|
|
|
1247
1280
|
yield {
|
|
1248
1281
|
turn: this._turn,
|
|
1249
1282
|
role: "warning",
|
|
1250
|
-
content: `aborted at iter ${iter}/${this.maxToolIters} \u2014
|
|
1283
|
+
content: `aborted at iter ${iter}/${this.maxToolIters} \u2014 stopped without producing a summary (press \u2191 + Enter or /retry to resume)`
|
|
1284
|
+
};
|
|
1285
|
+
const stoppedMsg = "[aborted by user (Esc) \u2014 no summary produced. Ask again or /retry when ready; prior tool output is still in the log.]";
|
|
1286
|
+
this.appendAndPersist({ role: "assistant", content: stoppedMsg });
|
|
1287
|
+
yield {
|
|
1288
|
+
turn: this._turn,
|
|
1289
|
+
role: "assistant_final",
|
|
1290
|
+
content: stoppedMsg,
|
|
1291
|
+
forcedSummary: true
|
|
1251
1292
|
};
|
|
1252
|
-
yield
|
|
1293
|
+
yield { turn: this._turn, role: "done", content: stoppedMsg };
|
|
1253
1294
|
return;
|
|
1254
1295
|
}
|
|
1255
1296
|
if (!warnedForIterBudget && iter >= warnAt) {
|
|
@@ -1471,12 +1512,18 @@ var CacheFirstLoop = class {
|
|
|
1471
1512
|
async *forceSummaryAfterIterLimit(opts = { reason: "budget" }) {
|
|
1472
1513
|
try {
|
|
1473
1514
|
const messages = this.buildMessages(null);
|
|
1515
|
+
messages.push({
|
|
1516
|
+
role: "user",
|
|
1517
|
+
content: "I'm out of tool-call budget for this turn. Summarize in plain prose what you learned from the tool results above. Do NOT emit any tool calls, function-call markup, DSML invocations, or SEARCH/REPLACE edit blocks \u2014 they will be silently discarded. Just plain text."
|
|
1518
|
+
});
|
|
1474
1519
|
const resp = await this.client.chat({
|
|
1475
1520
|
model: this.model,
|
|
1476
1521
|
messages
|
|
1477
1522
|
// no tools → model is forced to answer in text
|
|
1478
1523
|
});
|
|
1479
|
-
const
|
|
1524
|
+
const rawContent = resp.content?.trim() ?? "";
|
|
1525
|
+
const cleaned = stripHallucinatedToolMarkup(rawContent);
|
|
1526
|
+
const summary = cleaned || "(model emitted fake tool-call markup instead of a prose summary \u2014 try /retry with a narrower question, or /think to inspect R1's reasoning)";
|
|
1480
1527
|
const reasonPrefix = reasonPrefixFor(opts.reason, this.maxToolIters);
|
|
1481
1528
|
const annotated = `${reasonPrefix}
|
|
1482
1529
|
|
|
@@ -1517,6 +1564,14 @@ ${summary}`;
|
|
|
1517
1564
|
return msg;
|
|
1518
1565
|
}
|
|
1519
1566
|
};
|
|
1567
|
+
function stripHallucinatedToolMarkup(s) {
|
|
1568
|
+
let out = s;
|
|
1569
|
+
out = out.replace(/<|DSML|function_calls>[\s\S]*?<\/?|DSML|function_calls>/g, "");
|
|
1570
|
+
out = out.replace(/<\|DSML\|function_calls>[\s\S]*?<\/?\|DSML\|function_calls>/g, "");
|
|
1571
|
+
out = out.replace(/<function_calls>[\s\S]*?<\/function_calls>/g, "");
|
|
1572
|
+
out = out.replace(/<|DSML|[\s\S]*$/g, "");
|
|
1573
|
+
return out.trim();
|
|
1574
|
+
}
|
|
1520
1575
|
function reasonPrefixFor(reason, iterCap) {
|
|
1521
1576
|
if (reason === "aborted") return "[aborted by user (Esc) \u2014 summarizing what I found so far]";
|
|
1522
1577
|
if (reason === "context-guard") {
|
|
@@ -2766,7 +2821,7 @@ function redactKey(key) {
|
|
|
2766
2821
|
}
|
|
2767
2822
|
|
|
2768
2823
|
// src/index.ts
|
|
2769
|
-
var VERSION = "0.4.
|
|
2824
|
+
var VERSION = "0.4.3";
|
|
2770
2825
|
export {
|
|
2771
2826
|
AppendOnlyLog,
|
|
2772
2827
|
CODE_SYSTEM_PROMPT,
|
|
@@ -2835,6 +2890,7 @@ export {
|
|
|
2835
2890
|
sessionsDir,
|
|
2836
2891
|
similarity,
|
|
2837
2892
|
snapshotBeforeEdits,
|
|
2893
|
+
stripHallucinatedToolMarkup,
|
|
2838
2894
|
truncateForModel,
|
|
2839
2895
|
writeConfig,
|
|
2840
2896
|
writeMeta,
|