indusagi 0.12.33 → 0.13.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.
- package/CHANGELOG.md +11 -0
- package/dist/agent.js +1247 -184
- package/dist/ai.js +72 -4
- package/dist/capabilities.js +69 -2
- package/dist/cli.js +1353 -29
- package/dist/connectors-saas.js +66 -0
- package/dist/index.js +1353 -29
- package/dist/interop.js +66 -0
- package/dist/mcp.js +270 -363
- package/dist/react-ink.js +1391 -41
- package/dist/shell-app.js +1353 -29
- package/dist/smithy.js +69 -2
- package/dist/swarm.js +69 -2
- package/dist/types/capabilities/backends/node-backends.d.ts +3 -1
- package/dist/types/capabilities/files/read-state-gate.d.ts +69 -0
- package/dist/types/capabilities/files/read-state-gate.test.d.ts +14 -0
- package/dist/types/capabilities/kernel/context.d.ts +4 -0
- package/dist/types/capabilities/kernel/index.d.ts +2 -2
- package/dist/types/capabilities/kernel/spec.d.ts +55 -0
- package/dist/types/facade/bot/actions/bash.d.ts +15 -0
- package/dist/types/facade/bot/actions/bash.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/checkpoint.d.ts +49 -0
- package/dist/types/facade/bot/actions/checkpoint.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/edit-utils.d.ts +86 -0
- package/dist/types/facade/bot/actions/edit.d.ts +18 -0
- package/dist/types/facade/bot/actions/edit.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/find.d.ts +2 -0
- package/dist/types/facade/bot/actions/find.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/grep.d.ts +10 -0
- package/dist/types/facade/bot/actions/grep.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/index.d.ts +16 -0
- package/dist/types/facade/bot/actions/read-state.d.ts +83 -0
- package/dist/types/facade/bot/actions/read-state.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/read.d.ts +7 -0
- package/dist/types/facade/bot/actions/read.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/sandbox-backend.d.ts +99 -0
- package/dist/types/facade/bot/actions/sandbox-backend.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/websearch.d.ts +5 -2
- package/dist/types/facade/bot/actions/websearch.test.d.ts +1 -0
- package/dist/types/facade/bot/actions/write.d.ts +15 -0
- package/dist/types/facade/bot/agent-loop.d.ts +10 -0
- package/dist/types/facade/bot/agent-loop.test.d.ts +1 -0
- package/dist/types/facade/bot/agent.d.ts +9 -1
- package/dist/types/facade/bot/permission-gate.test.d.ts +1 -0
- package/dist/types/facade/bot/types.d.ts +60 -0
- package/dist/types/facade/mcp-core/client.d.ts +71 -15
- package/dist/types/facade/mcp-core/client.test.d.ts +18 -0
- package/dist/types/facade/mcp-core/types.d.ts +10 -0
- package/dist/types/facade/ml/adapters/anthropic-retry.test.d.ts +1 -0
- package/dist/types/facade/ml/adapters/anthropic.d.ts +17 -0
- package/dist/types/facade/ml/adapters/simple-options.d.ts +13 -0
- package/dist/types/facade/ml/adapters/simple-options.test.d.ts +1 -0
- package/dist/types/react-ink/components/StatusLine.d.ts +10 -1
- package/dist/types/react-ink/components/ToolEventBlock.d.ts +9 -1
- package/dist/types/react-ink/components/ToolEventBlock.test.d.ts +1 -0
- package/dist/types/react-ink/components/dialogs/SelectableDialog.d.ts +7 -1
- package/dist/types/react-ink/components/dialogs/ThemeDialog.d.ts +21 -2
- package/dist/types/react-ink/diff/Diff.d.ts +22 -0
- package/dist/types/react-ink/diff/diff.test.d.ts +1 -0
- package/dist/types/react-ink/diff/structured.d.ts +41 -0
- package/dist/types/react-ink/diff/word-diff.d.ts +27 -0
- package/dist/types/react-ink/index.d.ts +8 -0
- package/dist/types/react-ink/markdown/Markdown.d.ts +23 -0
- package/dist/types/react-ink/markdown/MarkdownTable.d.ts +19 -0
- package/dist/types/react-ink/markdown/StreamingMarkdown.d.ts +34 -0
- package/dist/types/react-ink/markdown/format-token.d.ts +39 -0
- package/dist/types/react-ink/markdown/highlight.d.ts +31 -0
- package/dist/types/react-ink/theme-adapter.d.ts +58 -1
- package/dist/types/react-ink/utils/tool-display.d.ts +17 -1
- package/package.json +5 -1
package/dist/ai.js
CHANGED
|
@@ -13199,24 +13199,58 @@ function normalizeProviderError(error) {
|
|
|
13199
13199
|
}
|
|
13200
13200
|
return new SimpleOptionsProviderError("Unknown provider error", "unknown", error);
|
|
13201
13201
|
}
|
|
13202
|
+
function abortReason(signal) {
|
|
13203
|
+
const reason = signal.reason;
|
|
13204
|
+
if (reason instanceof SimpleOptionsProviderError) return reason;
|
|
13205
|
+
if (reason instanceof Error) return new SimpleOptionsProviderError(reason.message, "unknown", reason);
|
|
13206
|
+
return new SimpleOptionsProviderError("Request was aborted", "unknown", reason);
|
|
13207
|
+
}
|
|
13208
|
+
function abortableSleep(ms, signal) {
|
|
13209
|
+
return new Promise((resolve, reject) => {
|
|
13210
|
+
if (signal?.aborted) {
|
|
13211
|
+
reject(abortReason(signal));
|
|
13212
|
+
return;
|
|
13213
|
+
}
|
|
13214
|
+
let onAbort;
|
|
13215
|
+
const timer = setTimeout(() => {
|
|
13216
|
+
if (signal && onAbort) signal.removeEventListener("abort", onAbort);
|
|
13217
|
+
resolve();
|
|
13218
|
+
}, ms);
|
|
13219
|
+
if (signal) {
|
|
13220
|
+
onAbort = () => {
|
|
13221
|
+
clearTimeout(timer);
|
|
13222
|
+
signal.removeEventListener("abort", onAbort);
|
|
13223
|
+
reject(abortReason(signal));
|
|
13224
|
+
};
|
|
13225
|
+
signal.addEventListener("abort", onAbort, { once: true });
|
|
13226
|
+
}
|
|
13227
|
+
});
|
|
13228
|
+
}
|
|
13202
13229
|
async function executeWithRetry(operation, policy) {
|
|
13203
13230
|
let attempt = 0;
|
|
13204
13231
|
let lastError;
|
|
13205
13232
|
while (attempt < policy.maxAttempts) {
|
|
13233
|
+
if (policy.signal?.aborted) {
|
|
13234
|
+
throw abortReason(policy.signal);
|
|
13235
|
+
}
|
|
13206
13236
|
attempt++;
|
|
13207
13237
|
try {
|
|
13208
13238
|
return await operation();
|
|
13209
13239
|
} catch (error) {
|
|
13210
13240
|
lastError = error;
|
|
13211
13241
|
const normalized = normalizeProviderError(error);
|
|
13242
|
+
if (policy.signal?.aborted) {
|
|
13243
|
+
throw normalized;
|
|
13244
|
+
}
|
|
13212
13245
|
const defaultRetryable = normalized.code === "rate_limit" || normalized.code === "timeout" || normalized.code === "network";
|
|
13213
13246
|
const retryable = policy.shouldRetry ? policy.shouldRetry(error, attempt) : defaultRetryable;
|
|
13214
13247
|
if (!retryable || attempt >= policy.maxAttempts) {
|
|
13215
13248
|
throw normalized;
|
|
13216
13249
|
}
|
|
13217
13250
|
const maxDelay = policy.maxDelayMs ?? Number.MAX_SAFE_INTEGER;
|
|
13218
|
-
const
|
|
13219
|
-
|
|
13251
|
+
const retryAfterMs = policy.getRetryAfterMs?.(error) ?? null;
|
|
13252
|
+
const backoff = retryAfterMs != null ? Math.min(retryAfterMs, maxDelay) : Math.min(policy.baseDelayMs * 2 ** (attempt - 1), maxDelay);
|
|
13253
|
+
await abortableSleep(backoff, policy.signal);
|
|
13220
13254
|
}
|
|
13221
13255
|
}
|
|
13222
13256
|
throw normalizeProviderError(lastError);
|
|
@@ -13692,6 +13726,30 @@ var AnthropicEventReducer = class {
|
|
|
13692
13726
|
calculateCost(this.model, this.output.usage);
|
|
13693
13727
|
}
|
|
13694
13728
|
};
|
|
13729
|
+
function parseAnthropicRetryAfterMs(error) {
|
|
13730
|
+
if (error instanceof Anthropic.APIError) {
|
|
13731
|
+
const header = error.headers?.get?.("retry-after");
|
|
13732
|
+
const seconds = header ? parseInt(header, 10) : Number.NaN;
|
|
13733
|
+
if (!Number.isNaN(seconds) && seconds >= 0) return seconds * 1e3;
|
|
13734
|
+
}
|
|
13735
|
+
return null;
|
|
13736
|
+
}
|
|
13737
|
+
function shouldRetryAnthropic(error, _attempt) {
|
|
13738
|
+
if (error instanceof Anthropic.APIError) {
|
|
13739
|
+
const status = error.status;
|
|
13740
|
+
if (status === 408 || status === 409 || status === 429 || status === 529) return true;
|
|
13741
|
+
if (typeof status === "number" && status >= 500) return true;
|
|
13742
|
+
if (typeof status === "number" && status >= 400 && status < 500) return false;
|
|
13743
|
+
const body = `${error.message} ${JSON.stringify(error.error ?? "")}`.toLowerCase();
|
|
13744
|
+
if (body.includes('"type":"overloaded_error"') || body.includes("overloaded")) return true;
|
|
13745
|
+
return false;
|
|
13746
|
+
}
|
|
13747
|
+
if (error instanceof Error) {
|
|
13748
|
+
const msg = error.message.toLowerCase();
|
|
13749
|
+
return msg.includes("rate limit") || msg.includes("rate_limit") || msg.includes("timeout") || msg.includes("timed out") || msg.includes("network") || msg.includes("econnreset") || msg.includes("etimedout") || msg.includes("overloaded");
|
|
13750
|
+
}
|
|
13751
|
+
return false;
|
|
13752
|
+
}
|
|
13695
13753
|
var streamAnthropic = (model, context, options) => {
|
|
13696
13754
|
const stream2 = new AssistantMessageEventStream();
|
|
13697
13755
|
const output = createAssistantMessageOutput(model);
|
|
@@ -13719,8 +13777,16 @@ var streamAnthropic = (model, context, options) => {
|
|
|
13719
13777
|
});
|
|
13720
13778
|
},
|
|
13721
13779
|
{
|
|
13722
|
-
|
|
13723
|
-
|
|
13780
|
+
// Transient retries are NO LONGER gated on signal presence:
|
|
13781
|
+
// the live path always carries a signal, so the old ternary
|
|
13782
|
+
// collapsed to a single attempt = zero retries on 429/529/5xx.
|
|
13783
|
+
// Abort still short-circuits immediately (see executeWithRetry).
|
|
13784
|
+
maxAttempts: 3,
|
|
13785
|
+
baseDelayMs: 500,
|
|
13786
|
+
maxDelayMs: 32e3,
|
|
13787
|
+
signal: options?.signal,
|
|
13788
|
+
shouldRetry: shouldRetryAnthropic,
|
|
13789
|
+
getRetryAfterMs: parseAnthropicRetryAfterMs
|
|
13724
13790
|
}
|
|
13725
13791
|
);
|
|
13726
13792
|
if (options?.signal?.aborted) {
|
|
@@ -19700,6 +19766,7 @@ export {
|
|
|
19700
19766
|
normalizeToolCallId,
|
|
19701
19767
|
normalizeToolName,
|
|
19702
19768
|
openaiCodexOAuthProvider,
|
|
19769
|
+
parseAnthropicRetryAfterMs,
|
|
19703
19770
|
parseStreamingJson,
|
|
19704
19771
|
parseStreamingJsonWithDiagnostics,
|
|
19705
19772
|
processResponsesStream,
|
|
@@ -19719,6 +19786,7 @@ export {
|
|
|
19719
19786
|
retainThoughtSignature,
|
|
19720
19787
|
rotateEnvApiKey,
|
|
19721
19788
|
sanitizeContentString,
|
|
19789
|
+
shouldRetryAnthropic,
|
|
19722
19790
|
stream,
|
|
19723
19791
|
streamAnthropic,
|
|
19724
19792
|
streamAzureOpenAIResponses,
|
package/dist/capabilities.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
// src/capabilities/kernel/spec.ts
|
|
2
|
+
var READ_STATE_HANDLE_KEY = "readState";
|
|
2
3
|
function coerceInput(raw) {
|
|
3
4
|
if (typeof raw === "string") {
|
|
4
5
|
const trimmed = raw.trim();
|
|
@@ -452,7 +453,7 @@ var standardBudget = {
|
|
|
452
453
|
[${omitted} bytes elided to stay within the output ceiling]
|
|
453
454
|
`
|
|
454
455
|
};
|
|
455
|
-
function makeNodeContext(cwd, signal, budget) {
|
|
456
|
+
function makeNodeContext(cwd, signal, budget, framework) {
|
|
456
457
|
if (typeof cwd !== "string" || cwd.length === 0) {
|
|
457
458
|
throw new Error("makeNodeContext requires a non-empty working directory.");
|
|
458
459
|
}
|
|
@@ -461,10 +462,60 @@ function makeNodeContext(cwd, signal, budget) {
|
|
|
461
462
|
fs: nodeFs,
|
|
462
463
|
shell: nodeShell,
|
|
463
464
|
signal: signal ?? neverAborts(),
|
|
464
|
-
budget: budget ?? standardBudget
|
|
465
|
+
budget: budget ?? standardBudget,
|
|
466
|
+
...framework ? { framework } : {}
|
|
465
467
|
};
|
|
466
468
|
}
|
|
467
469
|
|
|
470
|
+
// src/capabilities/files/read-state-gate.ts
|
|
471
|
+
var READ_BEFORE_EDIT_MESSAGE = "File has not been read yet. Read it first before writing to it.";
|
|
472
|
+
var MODIFIED_SINCE_READ_MESSAGE = "File has been modified since read, either by the user or by a linter. Read it again before attempting to write it.";
|
|
473
|
+
function getReadStateHandle(ctx) {
|
|
474
|
+
const bag = ctx.framework;
|
|
475
|
+
if (!bag || typeof bag !== "object") return void 0;
|
|
476
|
+
const candidate = bag[READ_STATE_HANDLE_KEY];
|
|
477
|
+
if (!candidate || typeof candidate !== "object") return void 0;
|
|
478
|
+
const handle = candidate;
|
|
479
|
+
if (typeof handle.get !== "function" || typeof handle.set !== "function" || typeof handle.has !== "function") {
|
|
480
|
+
return void 0;
|
|
481
|
+
}
|
|
482
|
+
return handle;
|
|
483
|
+
}
|
|
484
|
+
async function recordReadState(ctx, absPath, handle) {
|
|
485
|
+
if (!handle) return;
|
|
486
|
+
try {
|
|
487
|
+
const info = await ctx.fs.stat(absPath);
|
|
488
|
+
const record = {
|
|
489
|
+
mtimeMs: Math.floor(info.modifiedMs),
|
|
490
|
+
size: info.size,
|
|
491
|
+
readAt: Date.now()
|
|
492
|
+
};
|
|
493
|
+
handle.set(absPath, record);
|
|
494
|
+
} catch {
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
async function enforceReadGate(ctx, absPath, handle) {
|
|
498
|
+
if (!handle) return { ok: true };
|
|
499
|
+
if (!handle.has(absPath)) {
|
|
500
|
+
return { ok: false, message: READ_BEFORE_EDIT_MESSAGE };
|
|
501
|
+
}
|
|
502
|
+
const recorded = handle.get(absPath);
|
|
503
|
+
if (!recorded) {
|
|
504
|
+
return { ok: false, message: READ_BEFORE_EDIT_MESSAGE };
|
|
505
|
+
}
|
|
506
|
+
let info;
|
|
507
|
+
try {
|
|
508
|
+
info = await ctx.fs.stat(absPath);
|
|
509
|
+
} catch {
|
|
510
|
+
return { ok: true };
|
|
511
|
+
}
|
|
512
|
+
const currentMtime = Math.floor(info.modifiedMs);
|
|
513
|
+
if (currentMtime > recorded.mtimeMs || info.size !== recorded.size) {
|
|
514
|
+
return { ok: false, message: MODIFIED_SINCE_READ_MESSAGE };
|
|
515
|
+
}
|
|
516
|
+
return { ok: true };
|
|
517
|
+
}
|
|
518
|
+
|
|
468
519
|
// src/capabilities/files/read.ts
|
|
469
520
|
var GUTTER_WIDTH = 6;
|
|
470
521
|
var DESCRIPTION = [
|
|
@@ -567,6 +618,7 @@ var readTool = defineTool({
|
|
|
567
618
|
const detail = err instanceof Error ? err.message : String(err);
|
|
568
619
|
return failure(`Could not read ${path}: ${detail}`);
|
|
569
620
|
}
|
|
621
|
+
await recordReadState(ctx, path, getReadStateHandle(ctx));
|
|
570
622
|
const allLines = toLines(text);
|
|
571
623
|
const totalLines = allLines.length;
|
|
572
624
|
if (totalLines === 0) {
|
|
@@ -674,11 +726,19 @@ var writeTool = defineTool({
|
|
|
674
726
|
async run(input, ctx) {
|
|
675
727
|
const path = readPath(input?.path);
|
|
676
728
|
const content = readContent(input?.content);
|
|
729
|
+
const handle = getReadStateHandle(ctx);
|
|
730
|
+
if (handle && await ctx.fs.exists(path)) {
|
|
731
|
+
const gate = await enforceReadGate(ctx, path, handle);
|
|
732
|
+
if (!gate.ok) {
|
|
733
|
+
return asText(gate.message, true);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
677
736
|
const folder = parentDir(path);
|
|
678
737
|
if (folder.length > 0) {
|
|
679
738
|
await ctx.fs.mkdir(folder, { recursive: true });
|
|
680
739
|
}
|
|
681
740
|
await ctx.fs.writeFile(path, content, "utf8");
|
|
741
|
+
await recordReadState(ctx, path, handle);
|
|
682
742
|
const bytes = Buffer.byteLength(content, "utf8");
|
|
683
743
|
const unit = bytes === 1 ? "byte" : "bytes";
|
|
684
744
|
return asText(`Saved ${bytes} ${unit} to ${path}.`);
|
|
@@ -968,6 +1028,11 @@ async function runEdit(input, ctx) {
|
|
|
968
1028
|
if (!info.isFile) {
|
|
969
1029
|
return failure2(`${path} is not a regular file, so it cannot be edited.`);
|
|
970
1030
|
}
|
|
1031
|
+
const handle = getReadStateHandle(ctx);
|
|
1032
|
+
const gate = await enforceReadGate(ctx, path, handle);
|
|
1033
|
+
if (!gate.ok) {
|
|
1034
|
+
return failure2(gate.message);
|
|
1035
|
+
}
|
|
971
1036
|
const before = await ctx.fs.readFile(path, "utf8");
|
|
972
1037
|
const literalHits = countLiteral(before, oldText);
|
|
973
1038
|
if (literalHits > 0) {
|
|
@@ -981,6 +1046,7 @@ async function runEdit(input, ctx) {
|
|
|
981
1046
|
return failure2(`The replacement left ${path} unchanged.`);
|
|
982
1047
|
}
|
|
983
1048
|
await ctx.fs.writeFile(path, after2, "utf8");
|
|
1049
|
+
await recordReadState(ctx, path, handle);
|
|
984
1050
|
return success(path, before, after2, replaceAll ? literalHits : 1);
|
|
985
1051
|
}
|
|
986
1052
|
const spans = findFuzzySpans(before, oldText);
|
|
@@ -1004,6 +1070,7 @@ async function runEdit(input, ctx) {
|
|
|
1004
1070
|
return failure2(`The fuzzy replacement left ${path} unchanged.`);
|
|
1005
1071
|
}
|
|
1006
1072
|
await ctx.fs.writeFile(path, after, "utf8");
|
|
1073
|
+
await recordReadState(ctx, path, handle);
|
|
1007
1074
|
return success(path, before, after, targets.length);
|
|
1008
1075
|
}
|
|
1009
1076
|
var editTool = defineTool({
|