archymedes-cli 3.2.0 → 3.4.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/bin/archymedes.mjs +0 -0
- package/dist/{archymedes-qm9bwbe7.mjs → archymedes-cfwtgnjx.mjs} +3 -3
- package/dist/{archymedes-0jxzsh4z.mjs → archymedes-d5wqcmdr.mjs} +97 -97
- package/dist/{archymedes-95xvcvww.mjs → archymedes-ds224xzf.mjs} +989 -151
- package/dist/{archymedes-1g1y6q74.mjs → archymedes-h13ap0za.mjs} +1 -1
- package/dist/archymedes-main.mjs +808 -1006
- package/dist/{factory-8xk6y60m.mjs → factory-xpqqcyqq.mjs} +326 -326
- package/dist/{index-teq1cta4.mjs → index-qvgcwsvm.mjs} +1 -1
- package/dist/{node-0fh63p8z.mjs → node-mdgzx68h.mjs} +7 -7
- package/dist/{projection-4jjdaf41.mjs → projection-ndr3t77h.mjs} +2 -2
- package/dist/{sandbox-templates-8sd1psez.mjs → sandbox-templates-9jcjws23.mjs} +2 -2
- package/package.json +8 -8
package/dist/archymedes-main.mjs
CHANGED
|
@@ -7,9 +7,10 @@ import {
|
|
|
7
7
|
eventJournalPath,
|
|
8
8
|
readEventJournal,
|
|
9
9
|
runtimeEventForJournal
|
|
10
|
-
} from "./archymedes-
|
|
10
|
+
} from "./archymedes-cfwtgnjx.mjs";
|
|
11
11
|
import {
|
|
12
12
|
APIConnectionError,
|
|
13
|
+
BoundedAgentRuntime,
|
|
13
14
|
DEFAULT_OUTPUT_CEILING,
|
|
14
15
|
DEFAULT_TOTAL_TIMEOUT_MS,
|
|
15
16
|
OpenAI,
|
|
@@ -19,9 +20,8 @@ import {
|
|
|
19
20
|
WANDER_GRADES,
|
|
20
21
|
WANDER_LAB_FILES,
|
|
21
22
|
WANDER_MARKER,
|
|
22
|
-
addPart,
|
|
23
23
|
affordableOutputTokens,
|
|
24
|
-
|
|
24
|
+
agentMessagePromptParts,
|
|
25
25
|
approximateInputTokens,
|
|
26
26
|
buildTaskProfile,
|
|
27
27
|
buildWanderObjective,
|
|
@@ -31,29 +31,31 @@ import {
|
|
|
31
31
|
isWanderObjective,
|
|
32
32
|
isWanderRandomScheduleObjective,
|
|
33
33
|
mergeRoutingReceipts,
|
|
34
|
-
newPartTotals,
|
|
35
34
|
parseWanderResults,
|
|
36
35
|
pickWanderTopic,
|
|
36
|
+
predictEffort,
|
|
37
37
|
priceActualModelUsage,
|
|
38
|
+
providerEffort,
|
|
39
|
+
providerRetryAfterMs,
|
|
40
|
+
reasoningFromEnvironment,
|
|
38
41
|
streamTimeoutsFor,
|
|
39
42
|
toWireMessages,
|
|
40
|
-
tokenEstimateFrom,
|
|
41
43
|
turnFromChatResponse,
|
|
42
44
|
wanderGradeCounts,
|
|
43
45
|
wanderPlannerInstructions,
|
|
44
46
|
withOpenRouterCacheControl
|
|
45
|
-
} from "./archymedes-
|
|
47
|
+
} from "./archymedes-ds224xzf.mjs";
|
|
46
48
|
import {
|
|
47
49
|
__require
|
|
48
50
|
} from "./archymedes-x67v3n58.mjs";
|
|
49
51
|
|
|
50
|
-
//
|
|
52
|
+
// src/archymedes.ts
|
|
51
53
|
import { createInterface as createInterface5 } from "readline/promises";
|
|
52
54
|
import path30 from "path";
|
|
53
55
|
import { realpathSync } from "fs";
|
|
54
56
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
55
57
|
|
|
56
|
-
//
|
|
58
|
+
// ../core/src/cli/acp.ts
|
|
57
59
|
var ACP_PROTOCOL_VERSION = 1;
|
|
58
60
|
var JSON_RPC = { parseError: -32700, invalidRequest: -32600, methodNotFound: -32601, invalidParams: -32602, internalError: -32603 };
|
|
59
61
|
var ARCHYMEDES_EVENT_METHOD = "_archymedes/event";
|
|
@@ -402,7 +404,7 @@ function toolCallTitle(toolName, argumentsValue) {
|
|
|
402
404
|
return subject ? `${label}: ${String(subject).slice(0, 120)}` : label;
|
|
403
405
|
}
|
|
404
406
|
|
|
405
|
-
//
|
|
407
|
+
// ../core/src/cli/image-attachments.ts
|
|
406
408
|
var MAX_IMAGES_PER_TURN = 4;
|
|
407
409
|
var MAX_IMAGE_BYTES = 5 * 1024 * 1024;
|
|
408
410
|
var MENTION = /(?:^|\s)@((?:[\w.-]+\/)*[\w.-]+\.(?:png|jpe?g|gif|webp))(?=$|[\s,;:!?)])/gi;
|
|
@@ -467,7 +469,7 @@ function withoutImageData(messages) {
|
|
|
467
469
|
});
|
|
468
470
|
}
|
|
469
471
|
|
|
470
|
-
//
|
|
472
|
+
// ../core/src/cli/hosted-recovery.ts
|
|
471
473
|
import { createHash, randomUUID } from "node:crypto";
|
|
472
474
|
import { promises as fs } from "node:fs";
|
|
473
475
|
import path from "node:path";
|
|
@@ -726,677 +728,14 @@ ${entry.response.content}` });
|
|
|
726
728
|
}
|
|
727
729
|
}
|
|
728
730
|
|
|
729
|
-
//
|
|
730
|
-
import { randomUUID as
|
|
731
|
+
// ../core/src/cli/agent.ts
|
|
732
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
731
733
|
import path15 from "node:path";
|
|
732
734
|
import { access as access3 } from "node:fs/promises";
|
|
733
735
|
|
|
734
|
-
//
|
|
735
|
-
import { createHash as createHash2, randomUUID as randomUUID2 } from "node:crypto";
|
|
736
|
-
var IMAGE_TOKEN_ESTIMATE = 1600;
|
|
737
|
-
var IMAGE_CHAR_ESTIMATE = IMAGE_TOKEN_ESTIMATE * 4;
|
|
738
|
-
function agentMessagePromptParts(message) {
|
|
739
|
-
const parts = [message.content ?? ""];
|
|
740
|
-
if ("images" in message)
|
|
741
|
-
for (const _image of message.images ?? [])
|
|
742
|
-
parts.push(" ".repeat(IMAGE_CHAR_ESTIMATE));
|
|
743
|
-
if ("toolCalls" in message && Array.isArray(message.toolCalls)) {
|
|
744
|
-
for (const call of message.toolCalls)
|
|
745
|
-
parts.push(call.id, call.name, JSON.stringify(call.arguments ?? {}));
|
|
746
|
-
} else if (message.role === "tool") {
|
|
747
|
-
parts.push(message.toolCallId, message.name);
|
|
748
|
-
}
|
|
749
|
-
return parts;
|
|
750
|
-
}
|
|
751
|
-
var EVIDENCE_RANK = { check: 1, tests: 2, smoke: 3, behavior: 4 };
|
|
752
|
-
var MAX_VERIFICATION_NUDGES = 1;
|
|
753
|
-
var MAX_UNAVAILABLE_TOOL_RECOVERIES = 1;
|
|
754
|
-
var PROVIDER_BACKOFF_BASE_MS = 1000;
|
|
755
|
-
var PROVIDER_BACKOFF_CAP_MS = 30000;
|
|
756
|
-
var PROVIDER_RETRY_AFTER_CAP_MS = 60000;
|
|
757
|
-
var MAX_TOOL_TURN_RECOVERIES = 2;
|
|
758
|
-
var RETRY_POLICIES = {
|
|
759
|
-
server: { maxAttempts: 4, baseDelayMs: 1000, maxDelayMs: 15000 },
|
|
760
|
-
rate_limit: { maxAttempts: 6, baseDelayMs: 2000, maxDelayMs: 60000 },
|
|
761
|
-
timeout: { maxAttempts: 2, baseDelayMs: 1000, maxDelayMs: 8000 },
|
|
762
|
-
network: { maxAttempts: 3, baseDelayMs: 250, maxDelayMs: 4000 },
|
|
763
|
-
unknown: { maxAttempts: 3, baseDelayMs: 1000, maxDelayMs: 8000 }
|
|
764
|
-
};
|
|
765
|
-
|
|
766
|
-
class ProviderRequestError extends Error {
|
|
767
|
-
attempts;
|
|
768
|
-
kind;
|
|
769
|
-
waitedMs;
|
|
770
|
-
retrySuppressed;
|
|
771
|
-
constructor(cause, options) {
|
|
772
|
-
const original = cause instanceof Error ? cause.message : String(cause);
|
|
773
|
-
const kind = options.kind ? ` (${options.kind.replace("_", " ")} error)` : "";
|
|
774
|
-
const waited = options.waitedMs && options.waitedMs > 0 ? ` over ${(options.waitedMs / 1000).toFixed(1)}s of retries` : "";
|
|
775
|
-
const detail = options.retrySuppressed === "output_started" ? "The model connection failed after output began, so Archymedes did not retry to avoid duplicated output, charges, or tool actions." : `The model request failed after ${options.attempts} attempt${options.attempts === 1 ? "" : "s"}${kind}${waited}.`;
|
|
776
|
-
super(`${detail} Provider message: ${original}`, { cause });
|
|
777
|
-
this.name = "ProviderRequestError";
|
|
778
|
-
this.attempts = options.attempts;
|
|
779
|
-
if (options.kind)
|
|
780
|
-
this.kind = options.kind;
|
|
781
|
-
if (options.waitedMs !== undefined)
|
|
782
|
-
this.waitedMs = options.waitedMs;
|
|
783
|
-
this.retrySuppressed = options.retrySuppressed ?? null;
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
|
-
var MAX_LENGTH_CONTINUATIONS = 3;
|
|
787
|
-
var LENGTH_CONTINUATION_NUDGE = "Your previous message hit the output token limit and was cut off mid-answer. Continue from exactly where it stopped — do not repeat what you already wrote, and do not restart. If you were part-way through a tool call, send that tool call again from the beginning, since the truncated one was discarded. If the remaining work does not fit in one reply, do the part that fits and keep each reply shorter.";
|
|
788
|
-
var VERIFICATION_NUDGE = "You changed the workspace but ended the turn without running anything that verifies it. Run the smallest relevant existing test, check, or smoke command and report the real result. Add a regression test only when the change would otherwise be unprotected. If this project genuinely has nothing relevant to run, say so explicitly instead of stopping silently.";
|
|
789
|
-
var TEST_EVIDENCE_NUDGE = "That build/typecheck passing shows the code compiles, not that it behaves correctly. Run the smallest relevant existing test or smoke command for the changed behaviour and report the real result. Add a regression test only when the change would otherwise be unprotected. If the change genuinely has no behaviour to assert (documentation, formatting, configuration), say so explicitly and stop.";
|
|
790
|
-
var TRANSIENT_PROVIDER_CODES = new Set([
|
|
791
|
-
"ABORT_ERR",
|
|
792
|
-
"ECONNREFUSED",
|
|
793
|
-
"ECONNRESET",
|
|
794
|
-
"EAI_AGAIN",
|
|
795
|
-
"ENETDOWN",
|
|
796
|
-
"ENETUNREACH",
|
|
797
|
-
"ETIMEDOUT",
|
|
798
|
-
"UND_ERR_CONNECT_TIMEOUT",
|
|
799
|
-
"UND_ERR_HEADERS_TIMEOUT",
|
|
800
|
-
"UND_ERR_SOCKET"
|
|
801
|
-
]);
|
|
802
|
-
function errorRecord(value) {
|
|
803
|
-
return typeof value === "object" && value !== null ? value : undefined;
|
|
804
|
-
}
|
|
805
|
-
function isRetryableProviderError(error) {
|
|
806
|
-
let current = error;
|
|
807
|
-
const visited = new Set;
|
|
808
|
-
const messages = [];
|
|
809
|
-
for (let depth = 0;current !== undefined && current !== null && depth < 5 && !visited.has(current); depth += 1) {
|
|
810
|
-
visited.add(current);
|
|
811
|
-
const record = errorRecord(current);
|
|
812
|
-
if (current instanceof Error)
|
|
813
|
-
messages.push(current.message);
|
|
814
|
-
else if (typeof current === "string")
|
|
815
|
-
messages.push(current);
|
|
816
|
-
if (!record)
|
|
817
|
-
break;
|
|
818
|
-
if (typeof record.retryable === "boolean")
|
|
819
|
-
return record.retryable;
|
|
820
|
-
const status = Number(record.status ?? record.statusCode);
|
|
821
|
-
if (Number.isInteger(status)) {
|
|
822
|
-
if (status === 408 || status === 409 || status === 425 || status === 429 || status === 500 || status === 502 || status === 503 || status === 504)
|
|
823
|
-
return true;
|
|
824
|
-
if (status >= 400 && status < 600)
|
|
825
|
-
return false;
|
|
826
|
-
}
|
|
827
|
-
const code = typeof record.code === "string" ? record.code.toUpperCase() : "";
|
|
828
|
-
if (TRANSIENT_PROVIDER_CODES.has(code))
|
|
829
|
-
return true;
|
|
830
|
-
current = record.cause;
|
|
831
|
-
}
|
|
832
|
-
return messages.some((message) => /\b(?:timed?\s*out|timeout|rate\s*limit|overload(?:ed)?|temporar(?:y|ily)|connection\s*reset|socket\s*hang\s*up|fetch\s*failed|network\s*error)\b/i.test(message));
|
|
833
|
-
}
|
|
834
|
-
function providerFailureKind(error) {
|
|
835
|
-
let current = error;
|
|
836
|
-
const visited = new Set;
|
|
837
|
-
const messages = [];
|
|
838
|
-
for (let depth = 0;current !== undefined && current !== null && depth < 5 && !visited.has(current); depth += 1) {
|
|
839
|
-
visited.add(current);
|
|
840
|
-
const record = errorRecord(current);
|
|
841
|
-
if (current instanceof Error)
|
|
842
|
-
messages.push(current.message);
|
|
843
|
-
else if (typeof current === "string")
|
|
844
|
-
messages.push(current);
|
|
845
|
-
if (!record)
|
|
846
|
-
break;
|
|
847
|
-
const status = Number(record.status ?? record.statusCode);
|
|
848
|
-
if (status === 408)
|
|
849
|
-
return "timeout";
|
|
850
|
-
if (status === 429)
|
|
851
|
-
return "rate_limit";
|
|
852
|
-
if (status >= 500 && status < 600)
|
|
853
|
-
return "server";
|
|
854
|
-
const code = typeof record.code === "string" ? record.code.toUpperCase() : "";
|
|
855
|
-
if (/TIMEOUT/.test(code) || code === "ETIMEDOUT")
|
|
856
|
-
return "timeout";
|
|
857
|
-
if (TRANSIENT_PROVIDER_CODES.has(code))
|
|
858
|
-
return "network";
|
|
859
|
-
current = record.cause;
|
|
860
|
-
}
|
|
861
|
-
const message = messages.join(" ");
|
|
862
|
-
if (/rate\s*limit|too many requests/i.test(message))
|
|
863
|
-
return "rate_limit";
|
|
864
|
-
if (/timed?\s*out|timeout/i.test(message))
|
|
865
|
-
return "timeout";
|
|
866
|
-
if (/overload|service unavailable|bad gateway|gateway timeout/i.test(message))
|
|
867
|
-
return "server";
|
|
868
|
-
if (/connection|socket|fetch failed|network/i.test(message))
|
|
869
|
-
return "network";
|
|
870
|
-
return "unknown";
|
|
871
|
-
}
|
|
872
|
-
function providerRetryDelayMs(error, attempt, random = Math.random, policy = { baseDelayMs: PROVIDER_BACKOFF_BASE_MS, maxDelayMs: PROVIDER_BACKOFF_CAP_MS }) {
|
|
873
|
-
const retryAfter = providerRetryAfterMs(error);
|
|
874
|
-
const base = Math.min(policy.maxDelayMs, policy.baseDelayMs * 2 ** Math.min(10, Math.max(0, attempt)));
|
|
875
|
-
const jitter = 0.75 + 0.5 * Math.min(1, Math.max(0, random()));
|
|
876
|
-
const backoff = Math.min(policy.maxDelayMs, Math.round(base * jitter));
|
|
877
|
-
return retryAfter !== undefined ? Math.max(backoff, Math.min(PROVIDER_RETRY_AFTER_CAP_MS, Math.round(retryAfter))) : backoff;
|
|
878
|
-
}
|
|
879
|
-
function providerRetryAfterMs(error) {
|
|
880
|
-
let current = error;
|
|
881
|
-
const visited = new Set;
|
|
882
|
-
for (let depth = 0;depth < 5 && current !== undefined && current !== null && !visited.has(current); depth += 1) {
|
|
883
|
-
visited.add(current);
|
|
884
|
-
const record = errorRecord(current);
|
|
885
|
-
if (!record)
|
|
886
|
-
break;
|
|
887
|
-
const explicit = record.retryAfterMs;
|
|
888
|
-
if (typeof explicit === "number" && Number.isFinite(explicit) && explicit >= 0)
|
|
889
|
-
return explicit;
|
|
890
|
-
const headers = record.headers;
|
|
891
|
-
const raw = typeof headers?.get === "function" ? headers.get("retry-after") : headers?.["retry-after"];
|
|
892
|
-
if (typeof raw === "string" && raw.trim() !== "") {
|
|
893
|
-
const text = raw.trim();
|
|
894
|
-
if (/^\d+(?:\.\d+)?$/.test(text))
|
|
895
|
-
return Number(text) * 1000;
|
|
896
|
-
const at = Date.parse(text);
|
|
897
|
-
if (Number.isFinite(at))
|
|
898
|
-
return Math.max(0, at - Date.now());
|
|
899
|
-
}
|
|
900
|
-
current = record.cause;
|
|
901
|
-
}
|
|
902
|
-
return;
|
|
903
|
-
}
|
|
904
|
-
function providerRetryDelay(delayMs, signal) {
|
|
905
|
-
if (signal?.aborted)
|
|
906
|
-
return Promise.resolve(false);
|
|
907
|
-
return new Promise((resolve) => {
|
|
908
|
-
const abort = () => finish(false);
|
|
909
|
-
const finish = (elapsed) => {
|
|
910
|
-
clearTimeout(timer);
|
|
911
|
-
signal?.removeEventListener("abort", abort);
|
|
912
|
-
resolve(elapsed);
|
|
913
|
-
};
|
|
914
|
-
const timer = setTimeout(() => finish(true), delayMs);
|
|
915
|
-
signal?.addEventListener("abort", abort, { once: true });
|
|
916
|
-
});
|
|
917
|
-
}
|
|
918
|
-
var emptyUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0, cachedInputTokens: 0, cacheWriteTokens: 0, reasoningTokens: 0 };
|
|
919
|
-
function addUsage(total, next) {
|
|
920
|
-
const values = Object.values(next);
|
|
921
|
-
if (values.some((value) => !Number.isSafeInteger(value) || value < 0))
|
|
922
|
-
throw new Error("Model returned invalid usage accounting");
|
|
923
|
-
return {
|
|
924
|
-
inputTokens: total.inputTokens + next.inputTokens,
|
|
925
|
-
outputTokens: total.outputTokens + next.outputTokens,
|
|
926
|
-
totalTokens: total.totalTokens + next.totalTokens,
|
|
927
|
-
cachedInputTokens: total.cachedInputTokens + next.cachedInputTokens,
|
|
928
|
-
cacheWriteTokens: total.cacheWriteTokens + next.cacheWriteTokens,
|
|
929
|
-
reasoningTokens: total.reasoningTokens + next.reasoningTokens
|
|
930
|
-
};
|
|
931
|
-
}
|
|
932
|
-
function validateRequest(request) {
|
|
933
|
-
if (!request.taskId.trim() || !request.runId.trim() || !request.stepId.trim())
|
|
934
|
-
throw new Error("Task, run, and step identity are required");
|
|
935
|
-
if (!request.objective.trim() || !request.systemPrompt.trim())
|
|
936
|
-
throw new Error("Objective and systemPrompt are required");
|
|
937
|
-
const bounded = [
|
|
938
|
-
[request.maxIterations, 1, 100, "maxIterations"],
|
|
939
|
-
[request.maxToolCalls, 0, 500, "maxToolCalls"],
|
|
940
|
-
[request.maxToolCallsPerTurn, 1, 16, "maxToolCallsPerTurn"],
|
|
941
|
-
[request.maxToolResultChars, 128, 1e6, "maxToolResultChars"],
|
|
942
|
-
[request.maxTotalToolResultChars, 128, 4000000, "maxTotalToolResultChars"],
|
|
943
|
-
[request.maxOutputTokens, 256, 128000, "maxOutputTokens"]
|
|
944
|
-
];
|
|
945
|
-
for (const [value, minimum, maximum, name] of bounded) {
|
|
946
|
-
if (!Number.isInteger(value) || value < minimum || value > maximum)
|
|
947
|
-
throw new Error(`${name} must be between ${minimum} and ${maximum}`);
|
|
948
|
-
}
|
|
949
|
-
if (!Number.isSafeInteger(request.modelReservationRwf) || request.modelReservationRwf < 0)
|
|
950
|
-
throw new Error("modelReservationRwf must be a non-negative integer");
|
|
951
|
-
validateHistory(request.history ?? []);
|
|
952
|
-
}
|
|
953
|
-
function validateHistory(history) {
|
|
954
|
-
const pending = new Map;
|
|
955
|
-
const seen = new Set;
|
|
956
|
-
for (const message of history) {
|
|
957
|
-
if (message.role === "system")
|
|
958
|
-
throw new Error("Runtime history must not contain system messages");
|
|
959
|
-
if (message.role === "tool") {
|
|
960
|
-
const expectedName = pending.get(message.toolCallId);
|
|
961
|
-
if (!expectedName)
|
|
962
|
-
throw new Error(`Runtime history contains orphaned tool result ${message.toolCallId}`);
|
|
963
|
-
if (expectedName !== message.name)
|
|
964
|
-
throw new Error(`Runtime history tool result ${message.toolCallId} does not match ${expectedName}`);
|
|
965
|
-
pending.delete(message.toolCallId);
|
|
966
|
-
continue;
|
|
967
|
-
}
|
|
968
|
-
if (pending.size > 0)
|
|
969
|
-
throw new Error("Runtime history contains unresolved tool calls before the next message");
|
|
970
|
-
if (message.role === "assistant" && "toolCalls" in message) {
|
|
971
|
-
for (const call of message.toolCalls) {
|
|
972
|
-
if (!call.id.trim() || seen.has(call.id))
|
|
973
|
-
throw new Error(`Runtime history contains missing or duplicate tool-call id ${call.id}`);
|
|
974
|
-
seen.add(call.id);
|
|
975
|
-
pending.set(call.id, call.name);
|
|
976
|
-
}
|
|
977
|
-
}
|
|
978
|
-
}
|
|
979
|
-
if (pending.size > 0)
|
|
980
|
-
throw new Error("Runtime history ends with unresolved tool calls");
|
|
981
|
-
}
|
|
982
|
-
function normalizeArguments(value) {
|
|
983
|
-
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : undefined;
|
|
984
|
-
}
|
|
985
|
-
function truncate(value, maximum) {
|
|
986
|
-
if (maximum <= 0)
|
|
987
|
-
return "";
|
|
988
|
-
if (maximum <= 32)
|
|
989
|
-
return value.slice(0, maximum);
|
|
990
|
-
return value.length <= maximum ? value : `${value.slice(0, Math.max(0, maximum - 32))}
|
|
991
|
-
...[tool result truncated]`;
|
|
992
|
-
}
|
|
993
|
-
var MAX_IN_TURN_COMPACTIONS = 8;
|
|
994
|
-
var COMPACTION_MIN_CHARS = 400;
|
|
995
|
-
function compactedToolResult(toolName, chars, artifactPath, images = []) {
|
|
996
|
-
if (images.length > 0) {
|
|
997
|
-
const note = `[elided: ${images.length} image${images.length === 1 ? "" : "s"} (${images.map((image) => image.path).join(", ")}) from earlier ${toolName} output, to keep the conversation within its context budget; view ${images.length === 1 ? "it" : "them"} again if you need to]`;
|
|
998
|
-
return chars > 0 ? `${compactedToolResult(toolName, chars, artifactPath)}
|
|
999
|
-
${note}` : note;
|
|
1000
|
-
}
|
|
1001
|
-
return artifactPath ? `[elided: ${chars} chars of earlier ${toolName} output, to keep the conversation within its context budget; see artifact ${artifactPath} (read it with read_file if you need it again)]` : `[elided: ${chars} chars of earlier ${toolName} output, to keep the conversation within its context budget; run the tool again if you need it]`;
|
|
1002
|
-
}
|
|
1003
|
-
var EVICTION_MIN_BUDGET = 400;
|
|
1004
|
-
var ELISION_MARKER_BUDGET = 96;
|
|
1005
|
-
var EXCERPT_SHARE = 0.1;
|
|
1006
|
-
var EXCERPT_FLOOR = 1200;
|
|
1007
|
-
var DEDUPE_MIN_CHARS = 2000;
|
|
1008
|
-
function takeWithinBudget(lines, budget, fromEnd) {
|
|
1009
|
-
const taken = [];
|
|
1010
|
-
let used = 0;
|
|
1011
|
-
for (let step = 0;step < lines.length; step += 1) {
|
|
1012
|
-
const line = lines[fromEnd ? lines.length - 1 - step : step];
|
|
1013
|
-
const cost = line.length + 1;
|
|
1014
|
-
if (used + cost > budget)
|
|
1015
|
-
break;
|
|
1016
|
-
used += cost;
|
|
1017
|
-
taken.push(line);
|
|
1018
|
-
}
|
|
1019
|
-
return fromEnd ? taken.reverse() : taken;
|
|
1020
|
-
}
|
|
1021
|
-
function evictedToolResult(content, artifact, budget) {
|
|
1022
|
-
const header = `[Output too large for the transcript: ${artifact.lines} lines, ${artifact.bytes} bytes.` + ` The whole thing is saved at ${artifact.path} — read any window of it with read_file(path, offset, limit),` + ` or search it with run_command. The beginning and end are below.]`;
|
|
1023
|
-
if (budget < EVICTION_MIN_BUDGET || header.length + ELISION_MARKER_BUDGET + 64 > budget)
|
|
1024
|
-
return truncate(content, budget);
|
|
1025
|
-
const lines = content.split(`
|
|
1026
|
-
`);
|
|
1027
|
-
const bodyBudget = budget - header.length - 2 - ELISION_MARKER_BUDGET;
|
|
1028
|
-
const headBudget = Math.floor(bodyBudget * 0.6);
|
|
1029
|
-
const head = takeWithinBudget(lines, headBudget, false);
|
|
1030
|
-
const tail = takeWithinBudget(lines.slice(head.length), bodyBudget - headBudget, true);
|
|
1031
|
-
const elided = lines.length - head.length - tail.length;
|
|
1032
|
-
const marker = `...[${elided} line${elided === 1 ? "" : "s"} elided — full output at ${artifact.path}]...`;
|
|
1033
|
-
const assembled = [header, "", ...head, marker, ...tail].join(`
|
|
1034
|
-
`);
|
|
1035
|
-
return assembled.length <= budget ? assembled : assembled.slice(0, budget);
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
class BoundedAgentRuntime {
|
|
1039
|
-
dependencies;
|
|
1040
|
-
toolsByName;
|
|
1041
|
-
constructor(dependencies) {
|
|
1042
|
-
this.dependencies = dependencies;
|
|
1043
|
-
this.toolsByName = new Map;
|
|
1044
|
-
for (const tool of dependencies.tools) {
|
|
1045
|
-
if (this.toolsByName.has(tool.name))
|
|
1046
|
-
throw new Error(`Duplicate tool name: ${tool.name}`);
|
|
1047
|
-
if (tool.effect === "external" && !tool.requiresApproval)
|
|
1048
|
-
throw new Error(`External tool ${tool.name} must require approval`);
|
|
1049
|
-
if (tool.effect !== "none" && tool.parallelSafe)
|
|
1050
|
-
throw new Error(`Effectful tool ${tool.name} cannot be marked parallel-safe`);
|
|
1051
|
-
this.toolsByName.set(tool.name, tool);
|
|
1052
|
-
}
|
|
1053
|
-
}
|
|
1054
|
-
async execute(request) {
|
|
1055
|
-
validateRequest(request);
|
|
1056
|
-
const capabilities = new Set(request.allowedCapabilityIds);
|
|
1057
|
-
const tools = [...this.toolsByName.values()].filter((tool) => capabilities.has(tool.capabilityId));
|
|
1058
|
-
const definitions = tools.map(({ name, description, inputSchema }) => ({ name, description, inputSchema }));
|
|
1059
|
-
const messages = [
|
|
1060
|
-
{ role: "system", content: request.systemPrompt },
|
|
1061
|
-
...request.history ?? [],
|
|
1062
|
-
{ role: "user", content: request.objective, ...request.images?.length ? { images: request.images } : {} }
|
|
1063
|
-
];
|
|
1064
|
-
let usage = { ...emptyUsage };
|
|
1065
|
-
let actualModelRwf = 0;
|
|
1066
|
-
let toolCallsExecuted = 0;
|
|
1067
|
-
let totalToolResultChars = 0;
|
|
1068
|
-
const sentResults = new Map;
|
|
1069
|
-
const runToolResults = [];
|
|
1070
|
-
let inTurnCompactions = 0;
|
|
1071
|
-
let workspaceNeedsVerification = false;
|
|
1072
|
-
let verificationNudges = 0;
|
|
1073
|
-
let unavailableToolRecoveries = 0;
|
|
1074
|
-
let toolTurnRecoveries = 0;
|
|
1075
|
-
let lengthContinuations = 0;
|
|
1076
|
-
let strongestEvidence = 0;
|
|
1077
|
-
let askedForTestEvidence = false;
|
|
1078
|
-
const routingReceipts = [];
|
|
1079
|
-
let promptTotals = addPart(newPartTotals(), JSON.stringify(definitions));
|
|
1080
|
-
let measured = 0;
|
|
1081
|
-
const compactOlderToolResults = async (currentIteration, incoming = 0) => {
|
|
1082
|
-
if (inTurnCompactions >= MAX_IN_TURN_COMPACTIONS)
|
|
1083
|
-
return false;
|
|
1084
|
-
const target = Math.min(Math.floor(request.maxTotalToolResultChars / 2), request.maxTotalToolResultChars - incoming);
|
|
1085
|
-
let changed = false;
|
|
1086
|
-
for (const entry of runToolResults) {
|
|
1087
|
-
if (totalToolResultChars <= target)
|
|
1088
|
-
break;
|
|
1089
|
-
if (entry.compacted || entry.iteration >= currentIteration || entry.chars < COMPACTION_MIN_CHARS)
|
|
1090
|
-
continue;
|
|
1091
|
-
const message = messages[entry.index];
|
|
1092
|
-
if (message?.role !== "tool" || message.toolCallId !== entry.toolCallId)
|
|
1093
|
-
continue;
|
|
1094
|
-
const images = message.images ?? [];
|
|
1095
|
-
const stubText = message.content.length >= COMPACTION_MIN_CHARS;
|
|
1096
|
-
let path2 = entry.artifactPath;
|
|
1097
|
-
if (stubText && !path2 && this.dependencies.artifacts) {
|
|
1098
|
-
path2 = (await this.dependencies.artifacts.put({ toolName: entry.name, toolCallId: entry.toolCallId, content: message.content }).catch(() => {
|
|
1099
|
-
return;
|
|
1100
|
-
}))?.path;
|
|
1101
|
-
}
|
|
1102
|
-
const stub = images.length > 0 ? `${stubText ? compactedToolResult(entry.name, message.content.length, path2) : message.content}
|
|
1103
|
-
${compactedToolResult(entry.name, 0, undefined, images)}` : compactedToolResult(entry.name, message.content.length, path2);
|
|
1104
|
-
if (images.length === 0 && stub.length >= message.content.length)
|
|
1105
|
-
continue;
|
|
1106
|
-
const { images: _dropped, ...withoutImages } = message;
|
|
1107
|
-
messages[entry.index] = { ...withoutImages, content: stub };
|
|
1108
|
-
totalToolResultChars -= entry.chars - stub.length;
|
|
1109
|
-
entry.chars = stub.length;
|
|
1110
|
-
entry.images = 0;
|
|
1111
|
-
entry.compacted = true;
|
|
1112
|
-
changed = true;
|
|
1113
|
-
if (entry.digest) {
|
|
1114
|
-
const sent = sentResults.get(entry.digest);
|
|
1115
|
-
if (sent && !sent.path) {
|
|
1116
|
-
if (path2)
|
|
1117
|
-
sentResults.set(entry.digest, { ...sent, path: path2 });
|
|
1118
|
-
else
|
|
1119
|
-
sentResults.delete(entry.digest);
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1122
|
-
}
|
|
1123
|
-
if (changed) {
|
|
1124
|
-
inTurnCompactions += 1;
|
|
1125
|
-
promptTotals = addPart(newPartTotals(), JSON.stringify(definitions));
|
|
1126
|
-
measured = 0;
|
|
1127
|
-
}
|
|
1128
|
-
return changed;
|
|
1129
|
-
};
|
|
1130
|
-
const stop = async (status, summary, iterations) => {
|
|
1131
|
-
await this.dependencies.control.persistEvent({ type: "runtime_stop", status, summary });
|
|
1132
|
-
return {
|
|
1133
|
-
status,
|
|
1134
|
-
summary,
|
|
1135
|
-
messages,
|
|
1136
|
-
usage,
|
|
1137
|
-
actualModelRwf,
|
|
1138
|
-
iterations,
|
|
1139
|
-
toolCallsExecuted,
|
|
1140
|
-
...routingReceipts.length > 0 ? { routingReceipts: [...routingReceipts] } : {}
|
|
1141
|
-
};
|
|
1142
|
-
};
|
|
1143
|
-
for (let iteration = 1;iteration <= request.maxIterations; iteration += 1) {
|
|
1144
|
-
await this.dependencies.control.heartbeat();
|
|
1145
|
-
if (request.signal?.aborted || await this.dependencies.control.isCancellationRequested())
|
|
1146
|
-
return stop("cancelled", "Run cancelled at a safe checkpoint.", iteration - 1);
|
|
1147
|
-
const approvedRemaining = request.modelReservationRwf - actualModelRwf;
|
|
1148
|
-
for (;measured < messages.length; measured += 1) {
|
|
1149
|
-
for (const part of agentMessagePromptParts(messages[measured]))
|
|
1150
|
-
addPart(promptTotals, part);
|
|
1151
|
-
}
|
|
1152
|
-
const maximumOutputTokens = affordableOutputTokensFor(tokenEstimateFrom(promptTotals), request.maxOutputTokens, Math.max(0, approvedRemaining), this.dependencies.prices);
|
|
1153
|
-
if (maximumOutputTokens < 1)
|
|
1154
|
-
return stop("iteration_limit", "Run reached its approved model budget before another provider call.", iteration - 1);
|
|
1155
|
-
const modelRequest = {
|
|
1156
|
-
requestId: `cli_${randomUUID2()}`,
|
|
1157
|
-
...request.effort ? { effort: request.effort } : {},
|
|
1158
|
-
messages: [...messages],
|
|
1159
|
-
tools: definitions,
|
|
1160
|
-
maxOutputTokens: maximumOutputTokens,
|
|
1161
|
-
safetyIdentifier: request.safetyIdentifier,
|
|
1162
|
-
signal: request.signal,
|
|
1163
|
-
onTextDelta: (text) => void this.dependencies.control.persistEvent({ type: "assistant_delta", iteration, text })
|
|
1164
|
-
};
|
|
1165
|
-
let turn;
|
|
1166
|
-
let waitedMs = 0;
|
|
1167
|
-
for (let attempt = 0;; attempt += 1) {
|
|
1168
|
-
let emittedOutput = false;
|
|
1169
|
-
const attemptRequest = {
|
|
1170
|
-
...modelRequest,
|
|
1171
|
-
onTextDelta: modelRequest.onTextDelta ? (text) => {
|
|
1172
|
-
emittedOutput = true;
|
|
1173
|
-
modelRequest.onTextDelta(text);
|
|
1174
|
-
} : undefined,
|
|
1175
|
-
onOutputProgress: (kind) => {
|
|
1176
|
-
emittedOutput = true;
|
|
1177
|
-
modelRequest.onOutputProgress?.(kind);
|
|
1178
|
-
}
|
|
1179
|
-
};
|
|
1180
|
-
try {
|
|
1181
|
-
turn = await this.dependencies.model.complete(attemptRequest);
|
|
1182
|
-
break;
|
|
1183
|
-
} catch (error) {
|
|
1184
|
-
if (request.signal?.aborted || await this.dependencies.control.isCancellationRequested()) {
|
|
1185
|
-
return stop("cancelled", "Run cancelled while waiting for the model provider.", iteration - 1);
|
|
1186
|
-
}
|
|
1187
|
-
if (emittedOutput)
|
|
1188
|
-
throw new ProviderRequestError(error, { attempts: attempt + 1, retrySuppressed: "output_started" });
|
|
1189
|
-
if (!isRetryableProviderError(error))
|
|
1190
|
-
throw error;
|
|
1191
|
-
const reason = providerFailureKind(error);
|
|
1192
|
-
const policy = RETRY_POLICIES[reason];
|
|
1193
|
-
if (attempt + 1 >= policy.maxAttempts) {
|
|
1194
|
-
throw new ProviderRequestError(error, { attempts: attempt + 1, kind: reason, waitedMs });
|
|
1195
|
-
}
|
|
1196
|
-
const delayMs = providerRetryDelayMs(error, attempt, this.dependencies.retry?.random, policy);
|
|
1197
|
-
waitedMs += delayMs;
|
|
1198
|
-
await this.dependencies.control.persistEvent({
|
|
1199
|
-
type: "provider_retry",
|
|
1200
|
-
iteration,
|
|
1201
|
-
nextAttempt: attempt + 2,
|
|
1202
|
-
maxAttempts: policy.maxAttempts,
|
|
1203
|
-
delayMs,
|
|
1204
|
-
reason
|
|
1205
|
-
});
|
|
1206
|
-
if (!await (this.dependencies.retry?.sleep ?? providerRetryDelay)(delayMs, request.signal)) {
|
|
1207
|
-
return stop("cancelled", "Run cancelled while waiting to retry the model provider.", iteration - 1);
|
|
1208
|
-
}
|
|
1209
|
-
if (request.signal?.aborted || await this.dependencies.control.isCancellationRequested()) {
|
|
1210
|
-
return stop("cancelled", "Run cancelled while waiting to retry the model provider.", iteration - 1);
|
|
1211
|
-
}
|
|
1212
|
-
}
|
|
1213
|
-
}
|
|
1214
|
-
if (!turn)
|
|
1215
|
-
throw new Error("Model provider retry loop ended without a response");
|
|
1216
|
-
if (turn.routingReceipt)
|
|
1217
|
-
routingReceipts.push({ ...turn.routingReceipt, taskId: turn.routingReceipt.taskId ?? modelRequest.requestId });
|
|
1218
|
-
usage = addUsage(usage, turn.usage);
|
|
1219
|
-
actualModelRwf = priceActualModelUsage(usage.inputTokens, usage.outputTokens, this.dependencies.prices);
|
|
1220
|
-
if (actualModelRwf > request.modelReservationRwf)
|
|
1221
|
-
throw new Error("Actual model usage exceeds the reserved model budget");
|
|
1222
|
-
await this.dependencies.control.persistEvent({ type: "model_turn", requestId: modelRequest.requestId, iteration, responseId: turn.responseId, model: turn.model, toolCallCount: turn.toolCalls.length, usage: turn.usage, ...turn.allowance ? { allowance: turn.allowance } : {} });
|
|
1223
|
-
if (turn.finishReason === "refusal")
|
|
1224
|
-
return stop("blocked", turn.refusal?.trim() || "Model refused the task.", iteration);
|
|
1225
|
-
if (turn.finishReason === "length") {
|
|
1226
|
-
const partial = turn.content.trim();
|
|
1227
|
-
if (lengthContinuations >= MAX_LENGTH_CONTINUATIONS) {
|
|
1228
|
-
return stop("iteration_limit", `Model kept exceeding its output limit: ${MAX_LENGTH_CONTINUATIONS} continuations were not enough to finish the answer.`, iteration);
|
|
1229
|
-
}
|
|
1230
|
-
lengthContinuations += 1;
|
|
1231
|
-
messages.push({ role: "assistant", content: partial || "(no output before the limit was reached)" });
|
|
1232
|
-
messages.push({ role: "user", content: LENGTH_CONTINUATION_NUDGE });
|
|
1233
|
-
continue;
|
|
1234
|
-
}
|
|
1235
|
-
if (turn.finishReason === "stop") {
|
|
1236
|
-
const summary = turn.content.trim() || "Model completed without a summary.";
|
|
1237
|
-
messages.push({ role: "assistant", content: summary });
|
|
1238
|
-
if (workspaceNeedsVerification && verificationNudges < MAX_VERIFICATION_NUDGES) {
|
|
1239
|
-
verificationNudges += 1;
|
|
1240
|
-
messages.push({ role: "user", content: VERIFICATION_NUDGE, internal: true });
|
|
1241
|
-
continue;
|
|
1242
|
-
}
|
|
1243
|
-
if (strongestEvidence === EVIDENCE_RANK.check && !askedForTestEvidence) {
|
|
1244
|
-
askedForTestEvidence = true;
|
|
1245
|
-
messages.push({ role: "user", content: TEST_EVIDENCE_NUDGE, internal: true });
|
|
1246
|
-
continue;
|
|
1247
|
-
}
|
|
1248
|
-
return workspaceNeedsVerification ? stop("needs_verification", `Workspace changes were made without passing verification evidence. The agent reported: ${summary}`, iteration) : stop("completed", summary, iteration);
|
|
1249
|
-
}
|
|
1250
|
-
const recoverToolTurn = (reason, instruction) => {
|
|
1251
|
-
if (toolTurnRecoveries >= MAX_TOOL_TURN_RECOVERIES)
|
|
1252
|
-
return false;
|
|
1253
|
-
toolTurnRecoveries += 1;
|
|
1254
|
-
messages.push({ role: "user", content: `${reason} ${instruction}`, internal: true });
|
|
1255
|
-
return true;
|
|
1256
|
-
};
|
|
1257
|
-
if (turn.finishReason !== "tool_calls" || turn.toolCalls.length === 0) {
|
|
1258
|
-
if (recoverToolTurn("Your previous response declared tool use but contained no usable tool calls.", "Try again with a valid tool call, or answer normally if no tool is needed."))
|
|
1259
|
-
continue;
|
|
1260
|
-
return stop("failed", "Model repeatedly returned an invalid tool-call turn.", iteration);
|
|
1261
|
-
}
|
|
1262
|
-
if (turn.toolCalls.length > request.maxToolCallsPerTurn) {
|
|
1263
|
-
if (recoverToolTurn(`Your previous response requested ${turn.toolCalls.length} tools, above the per-turn limit of ${request.maxToolCallsPerTurn}; none were executed.`, `Retry with at most ${request.maxToolCallsPerTurn} calls, prioritizing the calls needed to make progress.`))
|
|
1264
|
-
continue;
|
|
1265
|
-
return stop("failed", `Model repeatedly exceeded the per-turn tool-call limit of ${request.maxToolCallsPerTurn}.`, iteration);
|
|
1266
|
-
}
|
|
1267
|
-
if (toolCallsExecuted + turn.toolCalls.length > request.maxToolCalls)
|
|
1268
|
-
return stop("iteration_limit", "Run reached its tool-call budget.", iteration);
|
|
1269
|
-
const seenCallIds = new Set;
|
|
1270
|
-
const malformed = turn.toolCalls.find((call) => {
|
|
1271
|
-
if (!call.id.trim() || seenCallIds.has(call.id))
|
|
1272
|
-
return true;
|
|
1273
|
-
seenCallIds.add(call.id);
|
|
1274
|
-
return !normalizeArguments(call.arguments);
|
|
1275
|
-
});
|
|
1276
|
-
if (malformed) {
|
|
1277
|
-
if (recoverToolTurn(`Your previous tool-call response was malformed (the ${JSON.stringify(malformed.name).slice(0, 80)} call); no tools were executed.`, 'Retry with a unique non-empty id for every call and a JSON object for every arguments value, for example {"path": "src/a.ts"}: double quotes, no trailing commas, no code fences.'))
|
|
1278
|
-
continue;
|
|
1279
|
-
return stop("failed", "Model repeatedly returned malformed tool calls.", iteration);
|
|
1280
|
-
}
|
|
1281
|
-
const unavailable = turn.toolCalls.find((call) => {
|
|
1282
|
-
const tool = this.toolsByName.get(call.name);
|
|
1283
|
-
return !tool || !capabilities.has(tool.capabilityId);
|
|
1284
|
-
});
|
|
1285
|
-
if (unavailable) {
|
|
1286
|
-
if (unavailableToolRecoveries >= MAX_UNAVAILABLE_TOOL_RECOVERIES) {
|
|
1287
|
-
return stop("failed", `Tool ${unavailable.name} is outside the run capability scope.`, iteration);
|
|
1288
|
-
}
|
|
1289
|
-
unavailableToolRecoveries += 1;
|
|
1290
|
-
messages.push({ role: "assistant", content: turn.content, toolCalls: turn.toolCalls });
|
|
1291
|
-
for (const call of turn.toolCalls) {
|
|
1292
|
-
messages.push({
|
|
1293
|
-
role: "tool",
|
|
1294
|
-
toolCallId: call.id,
|
|
1295
|
-
name: call.name,
|
|
1296
|
-
internal: true,
|
|
1297
|
-
content: call.id === unavailable.id ? `Tool ${call.name} is unavailable in the current mode. Continue with the listed tools, or answer without it.` : "This batch was not executed because another call was unavailable. Retry any still-needed available call separately."
|
|
1298
|
-
});
|
|
1299
|
-
}
|
|
1300
|
-
continue;
|
|
1301
|
-
}
|
|
1302
|
-
const prepared = [];
|
|
1303
|
-
for (const call of turn.toolCalls) {
|
|
1304
|
-
const tool = this.toolsByName.get(call.name);
|
|
1305
|
-
const argumentsValue = normalizeArguments(call.arguments);
|
|
1306
|
-
if (tool.requiresApproval) {
|
|
1307
|
-
const approval = await this.dependencies.control.isToolCallApproved(call, tool);
|
|
1308
|
-
if (approval !== true && approval !== "approved") {
|
|
1309
|
-
return approval === "denied" ? stop("blocked", `Tool ${call.name} was rejected by the user.`, iteration) : stop("needs_approval", `Tool ${call.name} requires approval before execution.`, iteration);
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
prepared.push({ call, tool, argumentsValue });
|
|
1313
|
-
}
|
|
1314
|
-
messages.push({ role: "assistant", content: turn.content, toolCalls: turn.toolCalls });
|
|
1315
|
-
const runOne = async ({ call, tool, argumentsValue }) => {
|
|
1316
|
-
if (request.signal?.aborted || await this.dependencies.control.isCancellationRequested())
|
|
1317
|
-
return { call, tool, result: { content: "Tool execution cancelled before start.", isError: true } };
|
|
1318
|
-
await this.dependencies.control.persistEvent({ type: "tool_call", toolCallId: call.id, toolName: call.name, effect: tool.effect, arguments: argumentsValue });
|
|
1319
|
-
try {
|
|
1320
|
-
return { call, tool, result: await tool.execute(argumentsValue, request) };
|
|
1321
|
-
} catch (error) {
|
|
1322
|
-
return { call, tool, result: { content: error instanceof Error ? error.message : "Tool execution failed", isError: true } };
|
|
1323
|
-
}
|
|
1324
|
-
};
|
|
1325
|
-
const groups = [];
|
|
1326
|
-
for (const item of prepared) {
|
|
1327
|
-
const concurrent = item.tool.parallelSafe && item.tool.effect === "none";
|
|
1328
|
-
const last = groups.at(-1);
|
|
1329
|
-
const lastIsConcurrent = last !== undefined && last[0].tool.parallelSafe && last[0].tool.effect === "none";
|
|
1330
|
-
if (concurrent && lastIsConcurrent)
|
|
1331
|
-
last.push(item);
|
|
1332
|
-
else
|
|
1333
|
-
groups.push([item]);
|
|
1334
|
-
}
|
|
1335
|
-
const results = [];
|
|
1336
|
-
for (const group of groups) {
|
|
1337
|
-
if (group.length === 1)
|
|
1338
|
-
results.push(await runOne(group[0]));
|
|
1339
|
-
else
|
|
1340
|
-
results.push(...await Promise.all(group.map(runOne)));
|
|
1341
|
-
}
|
|
1342
|
-
const iterationCharBudget = Math.max(request.maxToolResultChars, Math.floor(request.maxTotalToolResultChars / 4));
|
|
1343
|
-
let iterationChars = 0;
|
|
1344
|
-
const incoming = Math.min(iterationCharBudget, results.reduce((sum, { result }) => sum + Math.min((result.content || " ").length, request.maxToolResultChars) + (result.images?.length ?? 0) * IMAGE_CHAR_ESTIMATE, 0));
|
|
1345
|
-
if (totalToolResultChars + incoming > request.maxTotalToolResultChars)
|
|
1346
|
-
await compactOlderToolResults(iteration, incoming);
|
|
1347
|
-
for (const { call, tool, result } of results) {
|
|
1348
|
-
toolCallsExecuted += 1;
|
|
1349
|
-
const remaining = request.maxTotalToolResultChars - totalToolResultChars;
|
|
1350
|
-
const budget = Math.max(0, Math.min(request.maxToolResultChars, remaining, iterationCharBudget - iterationChars));
|
|
1351
|
-
const raw = result.content || "(empty tool result)";
|
|
1352
|
-
let artifact;
|
|
1353
|
-
let content = truncate(raw, budget);
|
|
1354
|
-
const withinTwiceBudget = raw.length <= budget * 2 && raw.length <= remaining;
|
|
1355
|
-
const images = result.images?.length ? result.images : undefined;
|
|
1356
|
-
const digest2 = !images && raw.length >= DEDUPE_MIN_CHARS ? createHash2("sha256").update(raw).digest("hex") : undefined;
|
|
1357
|
-
const alreadySent = digest2 ? sentResults.get(digest2) : undefined;
|
|
1358
|
-
if (alreadySent) {
|
|
1359
|
-
content = `[Identical to the earlier ${alreadySent.toolName} result in this conversation${alreadySent.path ? `, saved at ${alreadySent.path}` : ""}. Unchanged since then; re-read it there if you need it again.]`;
|
|
1360
|
-
} else if (withinTwiceBudget) {
|
|
1361
|
-
content = raw;
|
|
1362
|
-
} else if (this.dependencies.artifacts && raw.length > budget && budget > 0) {
|
|
1363
|
-
const stored = await this.dependencies.artifacts.put({ toolName: call.name, toolCallId: call.id, content: raw }).catch(() => {
|
|
1364
|
-
return;
|
|
1365
|
-
});
|
|
1366
|
-
if (stored) {
|
|
1367
|
-
artifact = stored;
|
|
1368
|
-
content = evictedToolResult(raw, stored, Math.min(budget, Math.max(EXCERPT_FLOOR, Math.round(budget * EXCERPT_SHARE))));
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
if (digest2 && !alreadySent)
|
|
1372
|
-
sentResults.set(digest2, { toolName: call.name, path: artifact?.path });
|
|
1373
|
-
const imageChars = (images?.length ?? 0) * IMAGE_CHAR_ESTIMATE;
|
|
1374
|
-
totalToolResultChars += content.length + imageChars;
|
|
1375
|
-
iterationChars += content.length + imageChars;
|
|
1376
|
-
runToolResults.push({ index: messages.length, iteration, toolCallId: call.id, name: call.name, chars: content.length + imageChars, compacted: false, images: images?.length ?? 0, ...artifact ? { artifactPath: artifact.path } : {}, ...digest2 ? { digest: digest2 } : {} });
|
|
1377
|
-
messages.push({ role: "tool", content, toolCallId: call.id, name: call.name, ...images ? { images } : {} });
|
|
1378
|
-
const effect = tool.effect === "external" ? "external" : result.effect ?? tool.effect;
|
|
1379
|
-
if (!result.isError && effect === "workspace")
|
|
1380
|
-
workspaceNeedsVerification = true;
|
|
1381
|
-
if (!result.isError && result.verification?.passed) {
|
|
1382
|
-
workspaceNeedsVerification = false;
|
|
1383
|
-
strongestEvidence = Math.max(strongestEvidence, EVIDENCE_RANK[result.verification.kind ?? "check"]);
|
|
1384
|
-
}
|
|
1385
|
-
await this.dependencies.control.persistEvent({ type: "tool_result", toolCallId: call.id, toolName: call.name, isError: result.isError ?? false, effect, content, ...result.data ? { data: result.data } : {}, ...artifact ? { artifact } : {} });
|
|
1386
|
-
}
|
|
1387
|
-
if (totalToolResultChars >= request.maxTotalToolResultChars)
|
|
1388
|
-
await compactOlderToolResults(iteration);
|
|
1389
|
-
await this.dependencies.control.checkpointMessages?.(messages);
|
|
1390
|
-
if (totalToolResultChars >= request.maxTotalToolResultChars)
|
|
1391
|
-
return stop("iteration_limit", "Run reached its total tool-result context budget.", iteration);
|
|
1392
|
-
}
|
|
1393
|
-
return stop("iteration_limit", "Run reached its model iteration budget.", request.maxIterations);
|
|
1394
|
-
}
|
|
1395
|
-
}
|
|
1396
|
-
|
|
1397
|
-
// packages/core/src/cli/checkpoints.ts
|
|
736
|
+
// ../core/src/cli/checkpoints.ts
|
|
1398
737
|
import { spawn } from "node:child_process";
|
|
1399
|
-
import { randomUUID as
|
|
738
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
1400
739
|
import { promises as fs2 } from "node:fs";
|
|
1401
740
|
import path2 from "node:path";
|
|
1402
741
|
var EXCLUDE_ARCHYMEDES = [".", ":(exclude).archymedes"];
|
|
@@ -1501,7 +840,7 @@ class CheckpointStore {
|
|
|
1501
840
|
const checkpoint = this.latest();
|
|
1502
841
|
if (!checkpoint)
|
|
1503
842
|
return "";
|
|
1504
|
-
const index = `${this.indexFile}.diff-${
|
|
843
|
+
const index = `${this.indexFile}.diff-${randomUUID2()}`;
|
|
1505
844
|
const options = { cwd: this.root, env: { GIT_INDEX_FILE: index } };
|
|
1506
845
|
try {
|
|
1507
846
|
if ((await this.git(["read-tree", checkpoint.tree], options)).exitCode !== 0)
|
|
@@ -1518,10 +857,10 @@ class CheckpointStore {
|
|
|
1518
857
|
}
|
|
1519
858
|
}
|
|
1520
859
|
|
|
1521
|
-
//
|
|
1522
|
-
import { createHash as
|
|
860
|
+
// ../core/src/cli/permissions.ts
|
|
861
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
1523
862
|
|
|
1524
|
-
//
|
|
863
|
+
// ../core/src/cli/command.ts
|
|
1525
864
|
import { spawn as spawn2 } from "node:child_process";
|
|
1526
865
|
import { constants } from "node:os";
|
|
1527
866
|
var ARCHYMEDES_CREDENTIAL_ENV_NAMES = [
|
|
@@ -1876,7 +1215,7 @@ Command exceeded ${options.timeoutMs}ms and was killed.`;
|
|
|
1876
1215
|
});
|
|
1877
1216
|
};
|
|
1878
1217
|
|
|
1879
|
-
//
|
|
1218
|
+
// ../core/src/cli/safety.ts
|
|
1880
1219
|
var TASK_RULES = [
|
|
1881
1220
|
{ category: "credentials", reason: "credential disclosure or high-impact credential change", pattern: /\b(?:export|expose|reveal|print|show|share|send|upload|publish|rotate|revoke)\b.{0,60}\b(?:api[ _-]?key|api[ _-]?token|access[ _-]?token|auth[ _-]?token|password|private[ _-]?key|secret|credential)s?\b|\b(?:set|add|store|save|replace)\b.{0,45}\b(?:production|prod|live)\b.{0,45}\b(?:api[ _-]?key|api[ _-]?token|access[ _-]?token|auth[ _-]?token|password|private[ _-]?key|secret|credential)s?\b/i },
|
|
1882
1221
|
{ category: "destructive", reason: "destructive data or repository operation", pattern: /(?:(?<!git\s)\brm\s+[^\n]*(?:-[^\n]*[rf]\b|--recursive|--force)|\bfind\s+[^\n]*-delete\b|\b(?:delete|drop|erase|purge|truncate|wipe|destroy|reset)\b.{0,45}\b(?:all|database|table|records?|history|account|branch|repository|production|live)\b)/i },
|
|
@@ -1938,7 +1277,7 @@ function assessToolSafety(call, tool) {
|
|
|
1938
1277
|
};
|
|
1939
1278
|
}
|
|
1940
1279
|
|
|
1941
|
-
//
|
|
1280
|
+
// ../core/src/cli/permissions.ts
|
|
1942
1281
|
var ARCHYMEDES_CAPABILITIES = {
|
|
1943
1282
|
read: "workspace.files.read",
|
|
1944
1283
|
write: "workspace.files",
|
|
@@ -1991,7 +1330,7 @@ function actionDigest(call, tool) {
|
|
|
1991
1330
|
provenance: tool.provenance ?? { kind: "built-in" },
|
|
1992
1331
|
arguments: call.arguments ?? {}
|
|
1993
1332
|
}));
|
|
1994
|
-
return
|
|
1333
|
+
return createHash2("sha256").update(action).digest("hex");
|
|
1995
1334
|
}
|
|
1996
1335
|
var SHELL_OPERATORS = /[;&|`$<>(){}\r\n]/;
|
|
1997
1336
|
var NEVER_GENERALIZE = new Set([
|
|
@@ -2383,7 +1722,7 @@ function describeToolCall(call, tool) {
|
|
|
2383
1722
|
}
|
|
2384
1723
|
}
|
|
2385
1724
|
|
|
2386
|
-
//
|
|
1725
|
+
// ../core/src/cli/memory.ts
|
|
2387
1726
|
import { promises as fs3 } from "node:fs";
|
|
2388
1727
|
import os from "node:os";
|
|
2389
1728
|
import path3 from "node:path";
|
|
@@ -2494,6 +1833,20 @@ async function addMemory(scope, text, root, environment, options = {}) {
|
|
|
2494
1833
|
}
|
|
2495
1834
|
return { entries: next, file: await writeScope(scope, next, root, environment), changed: true };
|
|
2496
1835
|
}
|
|
1836
|
+
async function forgetMemory(scope, index, root, environment) {
|
|
1837
|
+
const existing = await readScope(scope, root, environment);
|
|
1838
|
+
const removed = existing.find((entry) => entry.index === index);
|
|
1839
|
+
if (!removed)
|
|
1840
|
+
return { entries: existing, file: memoryFile(scope, root, environment), changed: false };
|
|
1841
|
+
const next = existing.filter((entry) => entry.index !== index).map((entry, position) => ({ ...entry, index: position + 1 }));
|
|
1842
|
+
return { entries: next, file: await writeScope(scope, next, root, environment), changed: true, removed };
|
|
1843
|
+
}
|
|
1844
|
+
async function clearMemories(scope, root, environment) {
|
|
1845
|
+
const existing = await readScope(scope, root, environment);
|
|
1846
|
+
if (existing.length === 0)
|
|
1847
|
+
return { entries: [], file: memoryFile(scope, root, environment), changed: false };
|
|
1848
|
+
return { entries: [], file: await writeScope(scope, [], root, environment), changed: true };
|
|
1849
|
+
}
|
|
2497
1850
|
function terms(text) {
|
|
2498
1851
|
return new Set(text.toLowerCase().match(/[\p{L}\p{N}_-]{3,}/gu) ?? []);
|
|
2499
1852
|
}
|
|
@@ -2535,7 +1888,7 @@ function memoryPromptBlock(entries) {
|
|
|
2535
1888
|
`);
|
|
2536
1889
|
}
|
|
2537
1890
|
|
|
2538
|
-
//
|
|
1891
|
+
// ../core/src/cli/environment.ts
|
|
2539
1892
|
import os2 from "node:os";
|
|
2540
1893
|
var BASE_PROBES = ["git", "node", "bun", "npm", "pnpm", "yarn", "rg", "python3"];
|
|
2541
1894
|
var MARKER_PROBES = [
|
|
@@ -2633,16 +1986,16 @@ function describeEnvironment(report) {
|
|
|
2633
1986
|
`);
|
|
2634
1987
|
}
|
|
2635
1988
|
|
|
2636
|
-
//
|
|
2637
|
-
import { createHash as
|
|
1989
|
+
// ../core/src/cli/prompt.ts
|
|
1990
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
2638
1991
|
import { promises as fs5 } from "node:fs";
|
|
2639
1992
|
import os3 from "node:os";
|
|
2640
1993
|
import path5 from "node:path";
|
|
2641
1994
|
|
|
2642
|
-
//
|
|
1995
|
+
// ../core/src/cli/workspace.ts
|
|
2643
1996
|
import { constants as fsConstants, promises as fs4 } from "node:fs";
|
|
2644
1997
|
import { spawn as spawn3 } from "node:child_process";
|
|
2645
|
-
import { createHash as
|
|
1998
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
2646
1999
|
import path4 from "node:path";
|
|
2647
2000
|
var DEFAULT_WORKSPACE_LIMITS = {
|
|
2648
2001
|
maxReadBytes: 512000,
|
|
@@ -2662,7 +2015,7 @@ function resolveInWorkspace(root, candidate) {
|
|
|
2662
2015
|
const absoluteRoot = path4.resolve(root);
|
|
2663
2016
|
const resolved = path4.resolve(absoluteRoot, candidate);
|
|
2664
2017
|
if (resolved !== absoluteRoot && !resolved.startsWith(absoluteRoot + path4.sep)) {
|
|
2665
|
-
throw new WorkspaceViolation(`path escapes the workspace root: ${candidate}
|
|
2018
|
+
throw new WorkspaceViolation(`path escapes the workspace root: ${candidate}. Use a path inside the project; a relative path (like "notes/tmp.txt") is resolved from the project root.`);
|
|
2666
2019
|
}
|
|
2667
2020
|
return resolved;
|
|
2668
2021
|
}
|
|
@@ -2937,7 +2290,7 @@ function parseEditArguments(args) {
|
|
|
2937
2290
|
return [{ oldText: args.oldText, newText: args.newText, replaceAll: args.replaceAll === true }];
|
|
2938
2291
|
}
|
|
2939
2292
|
function fingerprintText(content) {
|
|
2940
|
-
return
|
|
2293
|
+
return createHash3("sha256").update(content, "utf8").digest("hex");
|
|
2941
2294
|
}
|
|
2942
2295
|
|
|
2943
2296
|
class FileReadTracker {
|
|
@@ -3286,7 +2639,7 @@ async function grepWorkspace(root, query, options = {}) {
|
|
|
3286
2639
|
return matches;
|
|
3287
2640
|
}
|
|
3288
2641
|
|
|
3289
|
-
//
|
|
2642
|
+
// ../core/src/cli/defender-playbooks.ts
|
|
3290
2643
|
var INJECTION_PLAYBOOK = `
|
|
3291
2644
|
## Injection
|
|
3292
2645
|
|
|
@@ -3988,7 +3341,7 @@ function playbookFor(id) {
|
|
|
3988
3341
|
return DEFENDER_PLAYBOOK_CATALOG.find((entry) => entry.id === wanted || entry.title.toLowerCase() === wanted);
|
|
3989
3342
|
}
|
|
3990
3343
|
|
|
3991
|
-
//
|
|
3344
|
+
// ../core/src/cli/token-saver.ts
|
|
3992
3345
|
var TOKEN_SAVER_CONTEXT_LIMIT = 16384;
|
|
3993
3346
|
var TOKEN_SAVER_TOOL_RESULT_CHARS = 3000;
|
|
3994
3347
|
var TOKEN_SAVER_TOTAL_TOOL_RESULT_CHARS = 24000;
|
|
@@ -4093,7 +3446,7 @@ function restoreFullHistory(messages, original, sent) {
|
|
|
4093
3446
|
return [messages[0], ...original, ...messages.slice(1 + sent.length)];
|
|
4094
3447
|
}
|
|
4095
3448
|
|
|
4096
|
-
//
|
|
3449
|
+
// ../core/src/cli/prompt.ts
|
|
4097
3450
|
var INSTRUCTION_FILES = ["AGENTS.override.md", "ARCHYMEDES.md", "AGENTS.md", "CLAUDE.md", ".archymedesrules"];
|
|
4098
3451
|
async function instructionBoundary(root) {
|
|
4099
3452
|
const requestedRoot = path5.resolve(root);
|
|
@@ -4137,7 +3490,7 @@ async function collectProjectContext(root, maxInstructionChars = 8000) {
|
|
|
4137
3490
|
selected.unshift({
|
|
4138
3491
|
path: item.relative,
|
|
4139
3492
|
content,
|
|
4140
|
-
sha256:
|
|
3493
|
+
sha256: createHash4("sha256").update(item.text).digest("hex"),
|
|
4141
3494
|
truncated: content.length < item.text.length
|
|
4142
3495
|
});
|
|
4143
3496
|
remaining -= content.length;
|
|
@@ -4359,8 +3712,8 @@ ${instructions}`);
|
|
|
4359
3712
|
`);
|
|
4360
3713
|
}
|
|
4361
3714
|
|
|
4362
|
-
//
|
|
4363
|
-
import { createHash as
|
|
3715
|
+
// ../core/src/cli/session.ts
|
|
3716
|
+
import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
|
|
4364
3717
|
import { promises as fs6 } from "node:fs";
|
|
4365
3718
|
import path6 from "node:path";
|
|
4366
3719
|
var SESSION_SCHEMA_VERSION = 2;
|
|
@@ -4387,7 +3740,7 @@ function canonicalize2(value) {
|
|
|
4387
3740
|
return null;
|
|
4388
3741
|
}
|
|
4389
3742
|
function integrityFor(record) {
|
|
4390
|
-
return
|
|
3743
|
+
return createHash5("sha256").update(JSON.stringify(canonicalize2(record))).digest("hex");
|
|
4391
3744
|
}
|
|
4392
3745
|
async function acquireSessionLock(lockFile) {
|
|
4393
3746
|
for (let attempt = 0;attempt < 40; attempt += 1) {
|
|
@@ -4423,7 +3776,7 @@ async function saveSession(record) {
|
|
|
4423
3776
|
const file = path6.join(directory, `${record.id}.json`);
|
|
4424
3777
|
const lockFile = `${file}.lock`;
|
|
4425
3778
|
const release = await acquireSessionLock(lockFile);
|
|
4426
|
-
const temporary = `${file}.${process.pid}.${
|
|
3779
|
+
const temporary = `${file}.${process.pid}.${randomUUID3()}.tmp`;
|
|
4427
3780
|
try {
|
|
4428
3781
|
const fileExists = await fs6.stat(file).then(() => true).catch(() => false);
|
|
4429
3782
|
const current = (await loadSnapshot(record.root, record.id))?.record;
|
|
@@ -4482,10 +3835,10 @@ function sessionJournalPath(root, id) {
|
|
|
4482
3835
|
return path6.join(sessionDirectory(root), `${id}.steps.jsonl`);
|
|
4483
3836
|
}
|
|
4484
3837
|
function journalEntryHash(entry) {
|
|
4485
|
-
return
|
|
3838
|
+
return createHash5("sha256").update(JSON.stringify(entry)).digest("hex");
|
|
4486
3839
|
}
|
|
4487
3840
|
function messageFingerprint(message) {
|
|
4488
|
-
return message === undefined ? "" :
|
|
3841
|
+
return message === undefined ? "" : createHash5("sha256").update(JSON.stringify(message)).digest("hex");
|
|
4489
3842
|
}
|
|
4490
3843
|
var durableStates = new Map;
|
|
4491
3844
|
var journalQueues = new Map;
|
|
@@ -4768,17 +4121,17 @@ ${summary.trim()}` },
|
|
|
4768
4121
|
];
|
|
4769
4122
|
}
|
|
4770
4123
|
|
|
4771
|
-
//
|
|
4124
|
+
// ../core/src/hooks/command.ts
|
|
4772
4125
|
function hookCommand(scriptPath, payload, platform) {
|
|
4773
4126
|
if (platform !== "win32")
|
|
4774
4127
|
return `env ARCHYMEDES_HOOK_EVENT_B64=${payload} ${scriptPath}`;
|
|
4775
4128
|
return `set "ARCHYMEDES_HOOK_EVENT_B64=${payload}"&& call "${scriptPath.split("/").join("\\")}"`;
|
|
4776
4129
|
}
|
|
4777
4130
|
|
|
4778
|
-
//
|
|
4131
|
+
// ../core/src/hooks/types.ts
|
|
4779
4132
|
var HOOK_PHASES = ["pre-session", "pre-turn", "pre-tool-use", "post-tool-use", "post-turn", "post-session"];
|
|
4780
4133
|
|
|
4781
|
-
//
|
|
4134
|
+
// ../core/src/hooks/registry.ts
|
|
4782
4135
|
var HOOKS_DIRECTORY = ".archymedes/hooks";
|
|
4783
4136
|
var HOOK_TIMEOUT_MS = 5000;
|
|
4784
4137
|
async function scriptsIn(workspace, phaseDirectory) {
|
|
@@ -4881,7 +4234,7 @@ class HookRegistry {
|
|
|
4881
4234
|
return warnings;
|
|
4882
4235
|
}
|
|
4883
4236
|
}
|
|
4884
|
-
//
|
|
4237
|
+
// ../core/src/mcp/config.ts
|
|
4885
4238
|
var MCP_CONFIG_PATH = ".archymedes/mcp.json";
|
|
4886
4239
|
function isPlainObject(value) {
|
|
4887
4240
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -4936,7 +4289,7 @@ async function discoverMcpServers(workspace) {
|
|
|
4936
4289
|
}
|
|
4937
4290
|
return servers;
|
|
4938
4291
|
}
|
|
4939
|
-
//
|
|
4292
|
+
// ../core/src/mcp/http-transport.ts
|
|
4940
4293
|
class HttpMcpTransport {
|
|
4941
4294
|
config;
|
|
4942
4295
|
requestTimeoutMs;
|
|
@@ -5092,7 +4445,7 @@ function isJsonRpcNotification(value) {
|
|
|
5092
4445
|
return isPlainObject2(value) && "jsonrpc" in value && !("id" in value) && typeof value.method === "string";
|
|
5093
4446
|
}
|
|
5094
4447
|
|
|
5095
|
-
//
|
|
4448
|
+
// ../core/src/mcp/stdio-transport.ts
|
|
5096
4449
|
import { spawn as spawn4 } from "node:child_process";
|
|
5097
4450
|
import { createInterface } from "node:readline";
|
|
5098
4451
|
class StdioMcpTransport {
|
|
@@ -5194,7 +4547,7 @@ function isJsonRpcNotification2(value) {
|
|
|
5194
4547
|
return typeof value === "object" && value !== null && "jsonrpc" in value && !("id" in value) && typeof value.method === "string";
|
|
5195
4548
|
}
|
|
5196
4549
|
|
|
5197
|
-
//
|
|
4550
|
+
// ../core/src/mcp/connection.ts
|
|
5198
4551
|
class McpConnection {
|
|
5199
4552
|
config;
|
|
5200
4553
|
transport;
|
|
@@ -5256,7 +4609,7 @@ class McpConnection {
|
|
|
5256
4609
|
}
|
|
5257
4610
|
var MCP_PROTOCOL_VERSION = "2024-11-05";
|
|
5258
4611
|
var REQUEST_TIMEOUT_MS = 15000;
|
|
5259
|
-
//
|
|
4612
|
+
// ../core/src/mcp/client.ts
|
|
5260
4613
|
class McpToolProvider {
|
|
5261
4614
|
connection;
|
|
5262
4615
|
kind = "mcp";
|
|
@@ -5281,7 +4634,7 @@ class McpToolProvider {
|
|
|
5281
4634
|
this.connection.close();
|
|
5282
4635
|
}
|
|
5283
4636
|
}
|
|
5284
|
-
//
|
|
4637
|
+
// ../core/src/cli/plugins.ts
|
|
5285
4638
|
var PLUGINS_DIRECTORY = ".archymedes/plugins";
|
|
5286
4639
|
function isPlainObject3(value) {
|
|
5287
4640
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -5330,7 +4683,7 @@ async function discoverPlugins(workspace) {
|
|
|
5330
4683
|
return plugins;
|
|
5331
4684
|
}
|
|
5332
4685
|
|
|
5333
|
-
//
|
|
4686
|
+
// ../core/src/cli/tool-schema.ts
|
|
5334
4687
|
class ToolArgumentError extends Error {
|
|
5335
4688
|
constructor(message) {
|
|
5336
4689
|
super(message);
|
|
@@ -5421,7 +4774,7 @@ function validateToolArguments(toolName, schema, args) {
|
|
|
5421
4774
|
return present;
|
|
5422
4775
|
}
|
|
5423
4776
|
|
|
5424
|
-
//
|
|
4777
|
+
// ../core/src/skills/manifest.ts
|
|
5425
4778
|
var SKILLS_DIRECTORY = ".archymedes/skills";
|
|
5426
4779
|
function isPlainObject5(value) {
|
|
5427
4780
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -5477,7 +4830,7 @@ function shellQuote(value, platform) {
|
|
|
5477
4830
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
5478
4831
|
return `"${value.replace(/"/g, '""').replace(/%/g, "%%")}"`;
|
|
5479
4832
|
}
|
|
5480
|
-
//
|
|
4833
|
+
// ../core/src/skills/provider.ts
|
|
5481
4834
|
class SkillToolProvider {
|
|
5482
4835
|
id;
|
|
5483
4836
|
skillsDirectory;
|
|
@@ -5507,7 +4860,7 @@ ${body}`, isError: result.exitCode !== 0 };
|
|
|
5507
4860
|
}
|
|
5508
4861
|
}
|
|
5509
4862
|
var DEFAULT_SKILL_TIMEOUT_MS = 60000;
|
|
5510
|
-
//
|
|
4863
|
+
// ../core/src/cli/external-tools.ts
|
|
5511
4864
|
var IMPLICIT_SKILL_PROVIDER_ID = "local-skills";
|
|
5512
4865
|
async function loadLocalExternalTooling(workspace) {
|
|
5513
4866
|
const providers = [new SkillToolProvider(IMPLICIT_SKILL_PROVIDER_ID, SKILLS_DIRECTORY, workspace)];
|
|
@@ -5548,7 +4901,7 @@ async function loadLocalExternalTooling(workspace) {
|
|
|
5548
4901
|
};
|
|
5549
4902
|
}
|
|
5550
4903
|
|
|
5551
|
-
//
|
|
4904
|
+
// ../core/src/cli/nested-instructions.ts
|
|
5552
4905
|
class NestedInstructionTracker {
|
|
5553
4906
|
workspace;
|
|
5554
4907
|
seenDirectories = new Set;
|
|
@@ -5597,7 +4950,7 @@ ${blocks}`;
|
|
|
5597
4950
|
}
|
|
5598
4951
|
}
|
|
5599
4952
|
|
|
5600
|
-
//
|
|
4953
|
+
// ../core/src/cli/safe-fetch.ts
|
|
5601
4954
|
import { lookup } from "node:dns/promises";
|
|
5602
4955
|
import { isIP } from "node:net";
|
|
5603
4956
|
var defaultResolveHost = async (hostname) => (await lookup(hostname, { all: true, verbatim: true })).map((entry) => entry.address);
|
|
@@ -5759,7 +5112,7 @@ async function fetchPublicText(input, options = {}) {
|
|
|
5759
5112
|
return { ok: false, error: "too many redirects" };
|
|
5760
5113
|
}
|
|
5761
5114
|
|
|
5762
|
-
//
|
|
5115
|
+
// ../core/src/cli/secret-scan.ts
|
|
5763
5116
|
var SECRET_PATTERNS = [
|
|
5764
5117
|
{ name: "AWS access key", regex: /AKIA[0-9A-Z]{16}/, severity: "critical" },
|
|
5765
5118
|
{ name: "GitHub token", regex: /gh[pousr]_[A-Za-z0-9]{36,255}/, severity: "critical" },
|
|
@@ -5790,7 +5143,7 @@ function findSecretsInLine(line) {
|
|
|
5790
5143
|
return found;
|
|
5791
5144
|
}
|
|
5792
5145
|
|
|
5793
|
-
//
|
|
5146
|
+
// ../core/src/cli/tool-providers.ts
|
|
5794
5147
|
var DEFAULT_EXTERNAL_TOOL_TIMEOUT_MS = 30000;
|
|
5795
5148
|
async function toolsFromProvider(provider, timeoutMs = DEFAULT_EXTERNAL_TOOL_TIMEOUT_MS) {
|
|
5796
5149
|
const externalTools = await provider.listTools();
|
|
@@ -5832,7 +5185,7 @@ async function collectExternalTools(providers, timeoutMs) {
|
|
|
5832
5185
|
return collected;
|
|
5833
5186
|
}
|
|
5834
5187
|
|
|
5835
|
-
//
|
|
5188
|
+
// ../core/src/cli/deploy.ts
|
|
5836
5189
|
var DEPLOY_PROVIDERS = {
|
|
5837
5190
|
vercel: {
|
|
5838
5191
|
id: "vercel",
|
|
@@ -5956,7 +5309,7 @@ function deployPlan(target, detection, options = {}) {
|
|
|
5956
5309
|
return { commands, notes };
|
|
5957
5310
|
}
|
|
5958
5311
|
|
|
5959
|
-
//
|
|
5312
|
+
// ../core/src/cli/compute.ts
|
|
5960
5313
|
var MAX_INPUT = 2000;
|
|
5961
5314
|
var MAX_DEPTH = 64;
|
|
5962
5315
|
var FACTORIAL_LIMIT = 170;
|
|
@@ -6508,11 +5861,11 @@ function compute(expression, options = {}) {
|
|
|
6508
5861
|
return { value: result, exact, rendered, radixRendered, warnings };
|
|
6509
5862
|
}
|
|
6510
5863
|
|
|
6511
|
-
//
|
|
5864
|
+
// ../core/src/cli/tools-extra/git.ts
|
|
6512
5865
|
import { execFile } from "node:child_process";
|
|
6513
5866
|
import path7 from "node:path";
|
|
6514
5867
|
|
|
6515
|
-
//
|
|
5868
|
+
// ../core/src/cli/tools-extra/shared.ts
|
|
6516
5869
|
import { promises as fs7 } from "node:fs";
|
|
6517
5870
|
function resolvedLimits(options) {
|
|
6518
5871
|
return options.limits ?? DEFAULT_WORKSPACE_LIMITS;
|
|
@@ -6567,7 +5920,7 @@ function truncateText(text, maxChars, hint) {
|
|
|
6567
5920
|
[truncated: showed ${cut.length} of ${text.length} chars. ${hint}]`, truncated: true };
|
|
6568
5921
|
}
|
|
6569
5922
|
|
|
6570
|
-
//
|
|
5923
|
+
// ../core/src/cli/tools-extra/git.ts
|
|
6571
5924
|
var GIT_BASE_ARGS = ["--no-pager", "-c", "core.fsmonitor=false", "-c", "core.quotepath=false", "-c", "color.ui=false"];
|
|
6572
5925
|
var MAX_GIT_OUTPUT = 16 * 1024 * 1024;
|
|
6573
5926
|
function runGit2(root, args, timeoutMs) {
|
|
@@ -6849,7 +6202,7 @@ function createGitTools(options) {
|
|
|
6849
6202
|
];
|
|
6850
6203
|
}
|
|
6851
6204
|
|
|
6852
|
-
//
|
|
6205
|
+
// ../core/src/cli/tools-extra/image.ts
|
|
6853
6206
|
function createImageTools(options) {
|
|
6854
6207
|
const { root } = options;
|
|
6855
6208
|
const limits = { ...resolvedLimits(options), maxReadBytes: MAX_IMAGE_BYTES };
|
|
@@ -6884,7 +6237,7 @@ function createImageTools(options) {
|
|
|
6884
6237
|
];
|
|
6885
6238
|
}
|
|
6886
6239
|
|
|
6887
|
-
//
|
|
6240
|
+
// ../core/src/cli/tools-extra/notebook.ts
|
|
6888
6241
|
import { randomBytes } from "node:crypto";
|
|
6889
6242
|
function toSourceLines(source) {
|
|
6890
6243
|
if (source === "")
|
|
@@ -7065,7 +6418,7 @@ function createNotebookTools(options) {
|
|
|
7065
6418
|
];
|
|
7066
6419
|
}
|
|
7067
6420
|
|
|
7068
|
-
//
|
|
6421
|
+
// ../core/src/cli/tools-extra/repo-map.ts
|
|
7069
6422
|
var REPO_MAP_DEFAULT_CHARS = 12000;
|
|
7070
6423
|
var REPO_MAP_MAX_CHARS = 60000;
|
|
7071
6424
|
var ENTRY_NAMES = /(?:^|\/)(?:index|main|app|lib|mod|__init__|server|cli|program)\.[^/]+$/i;
|
|
@@ -7335,7 +6688,7 @@ ${lines.join(`
|
|
|
7335
6688
|
];
|
|
7336
6689
|
}
|
|
7337
6690
|
|
|
7338
|
-
//
|
|
6691
|
+
// ../core/src/cli/tools-extra/symbols.ts
|
|
7339
6692
|
import { promises as fs8 } from "node:fs";
|
|
7340
6693
|
import path8 from "node:path";
|
|
7341
6694
|
var EXTENSIONS = {
|
|
@@ -7669,13 +7022,13 @@ class SymbolIndex {
|
|
|
7669
7022
|
}
|
|
7670
7023
|
}
|
|
7671
7024
|
|
|
7672
|
-
//
|
|
7025
|
+
// ../core/src/cli/tools-extra/index.ts
|
|
7673
7026
|
function createExtraTools(options) {
|
|
7674
7027
|
const index = options.symbolIndex ?? new SymbolIndex(options.root, resolvedLimits(options));
|
|
7675
7028
|
return [...createRepoMapTools(options, index), ...createGitTools(options), ...createNotebookTools(options), ...createImageTools(options)];
|
|
7676
7029
|
}
|
|
7677
7030
|
|
|
7678
|
-
//
|
|
7031
|
+
// ../core/src/cli/tools.ts
|
|
7679
7032
|
class TodoList {
|
|
7680
7033
|
items = [];
|
|
7681
7034
|
nextId = 1;
|
|
@@ -7728,6 +7081,18 @@ var REFUSED_COMMAND_PATTERNS = [
|
|
|
7728
7081
|
/>\s*\/dev\/sd[a-z]/,
|
|
7729
7082
|
/:\(\)\s*\{.*\|.*&\s*\}\s*;/
|
|
7730
7083
|
];
|
|
7084
|
+
var LIST_ENTRY_CAP = 400;
|
|
7085
|
+
var GLOB_SHOWN = 150;
|
|
7086
|
+
function listPrefix(raw, localRoot) {
|
|
7087
|
+
const trimmed = raw.trim();
|
|
7088
|
+
if (!trimmed || trimmed === ".")
|
|
7089
|
+
return "";
|
|
7090
|
+
if (localRoot !== null) {
|
|
7091
|
+
const relative = displayPath(localRoot, resolveInWorkspace(localRoot, trimmed));
|
|
7092
|
+
return relative === "." ? "" : relative;
|
|
7093
|
+
}
|
|
7094
|
+
return trimmed.replace(/^(\.\/)+/, "").replace(/\/+$/, "");
|
|
7095
|
+
}
|
|
7731
7096
|
function isRefusedCommand(command) {
|
|
7732
7097
|
return REFUSED_COMMAND_PATTERNS.some((pattern) => pattern.test(command)) || isRecursiveForceRemoval(command) || isFindDelete(command);
|
|
7733
7098
|
}
|
|
@@ -7739,6 +7104,7 @@ async function scanWorkspaceForSecrets(workspace, include) {
|
|
|
7739
7104
|
async function createArchymedesTools(options) {
|
|
7740
7105
|
const { workspace, todos } = options;
|
|
7741
7106
|
const commandTimeoutMs = options.commandTimeoutMs ?? 120000;
|
|
7107
|
+
const writtenFiles = new Set;
|
|
7742
7108
|
const tools = [
|
|
7743
7109
|
{
|
|
7744
7110
|
name: "read_file",
|
|
@@ -7792,24 +7158,39 @@ async function createArchymedesTools(options) {
|
|
|
7792
7158
|
requiresApproval: false,
|
|
7793
7159
|
parallelSafe: true,
|
|
7794
7160
|
async execute(args) {
|
|
7795
|
-
const prefix = typeof args.path === "string"
|
|
7161
|
+
const prefix = listPrefix(typeof args.path === "string" ? args.path : "", workspace.kind === "local" ? workspace.label : null);
|
|
7796
7162
|
const entries = await workspace.list(prefix, optionalInteger(args.depth, "depth") ?? 2);
|
|
7797
|
-
|
|
7798
|
-
|
|
7163
|
+
if (entries.length === 0) {
|
|
7164
|
+
return { content: prefix ? `${prefix} is empty, ignored, or does not exist. Paths are relative to the project root; list "." to see the top level.` : "No entries. The project root is empty (or everything in it is ignored).", data: { entries } };
|
|
7165
|
+
}
|
|
7166
|
+
const capped = entries.length >= LIST_ENTRY_CAP;
|
|
7167
|
+
return { content: capped ? `${entries.join(`
|
|
7168
|
+
`)}
|
|
7169
|
+
[Listing capped at ${LIST_ENTRY_CAP} entries; list a subdirectory or lower depth to see the rest.]` : entries.join(`
|
|
7170
|
+
`), data: { entries, truncated: capped } };
|
|
7799
7171
|
}
|
|
7800
7172
|
},
|
|
7801
7173
|
{
|
|
7802
7174
|
name: "glob_files",
|
|
7803
|
-
description: "Find files whose path matches a glob, e.g. 'src/**/*.ts' or '**/*.{js,ts}'.",
|
|
7804
|
-
inputSchema: { type: "object", properties: { pattern: { type: "string" } }, required: ["pattern"], additionalProperties: false },
|
|
7175
|
+
description: "Find files whose path matches a glob, e.g. 'src/**/*.ts' or '**/*.{js,ts}'. Optional path limits it to one directory (the pattern is then relative to it).",
|
|
7176
|
+
inputSchema: { type: "object", properties: { pattern: { type: "string" }, path: { type: "string", description: "Directory to search in. Default: project root." } }, required: ["pattern"], additionalProperties: false },
|
|
7805
7177
|
capabilityId: ARCHYMEDES_CAPABILITIES.read,
|
|
7806
7178
|
effect: "none",
|
|
7807
7179
|
requiresApproval: false,
|
|
7808
7180
|
parallelSafe: true,
|
|
7809
7181
|
async execute(args) {
|
|
7810
|
-
const
|
|
7811
|
-
|
|
7812
|
-
|
|
7182
|
+
const directory = listPrefix(typeof args.path === "string" ? args.path : "", workspace.kind === "local" ? workspace.label : null);
|
|
7183
|
+
const pattern = requiredString2(args.pattern, "pattern").replace(/^(\.\/)+/, "");
|
|
7184
|
+
const matches = await workspace.glob(directory ? `${directory}/${pattern}` : pattern);
|
|
7185
|
+
if (matches.length === 0) {
|
|
7186
|
+
return { content: directory ? `No files matched ${pattern} under ${directory}. Try "**/*" there, or list_files on it.` : "No files matched.", data: { matches } };
|
|
7187
|
+
}
|
|
7188
|
+
const shown = matches.slice(0, GLOB_SHOWN);
|
|
7189
|
+
const more = matches.length - shown.length;
|
|
7190
|
+
const note = more > 0 ? `
|
|
7191
|
+
[${more} more matched. Narrow it: pass path for one directory, or a more specific pattern.]` : "";
|
|
7192
|
+
return { content: shown.join(`
|
|
7193
|
+
`) + note, data: { matches, truncated: more > 0 } };
|
|
7813
7194
|
}
|
|
7814
7195
|
},
|
|
7815
7196
|
{
|
|
@@ -7886,6 +7267,7 @@ ${content}`,
|
|
|
7886
7267
|
async execute(args) {
|
|
7887
7268
|
const result = await workspace.writeFile(requiredString2(args.path, "path"), args.content);
|
|
7888
7269
|
fileReadTrackerFor(workspace).record(result.path, args.content);
|
|
7270
|
+
writtenFiles.add(result.path);
|
|
7889
7271
|
return { content: `Wrote ${result.path} (${result.bytesWritten} bytes).`, data: { path: result.path, bytesWritten: result.bytesWritten } };
|
|
7890
7272
|
}
|
|
7891
7273
|
},
|
|
@@ -7963,7 +7345,7 @@ ${body}
|
|
|
7963
7345
|
data: { command, exitCode: result.exitCode, stdout: result.stdout, stderr: result.stderr, missingProgram: missing }
|
|
7964
7346
|
};
|
|
7965
7347
|
}
|
|
7966
|
-
const kind = classifyVerification(command);
|
|
7348
|
+
const kind = classifyVerification(command) ?? (runsWrittenScript(command, writtenFiles) ? "smoke" : null);
|
|
7967
7349
|
const rejectedVerification = kind && result.exitCode === 0 ? rejectedVerificationReason(command, result) : null;
|
|
7968
7350
|
const verificationNote = rejectedVerification ? `
|
|
7969
7351
|
|
|
@@ -8646,7 +8028,7 @@ var TEST_COMMAND = /\b(tests?|pytest|jest|vitest|mocha|jasmine|karma|ava|rspec|m
|
|
|
8646
8028
|
var CHECK_COMMAND = /\b(typecheck|tsc|lint|eslint|pylint|ruff|flake8|mypy|pyright|check|build|compile|py_compile|vet|clippy|rubocop|audit|fmt|format)\b/i;
|
|
8647
8029
|
var BEHAVIOR_COMMAND = /\b(e2e|end-to-end|playwright|cypress|puppeteer|selenium|webdriver|testcafe|nightwatch|integration|behave|cucumber|supertest|testcontainers)\b/i;
|
|
8648
8030
|
var SMOKE_COMMAND = /\b(smoke|healthcheck|health[-_ ]?check|curl|wget|httpie|\bhttp\s+(?:get|post)\b|playwright\s+screenshot)\b/i;
|
|
8649
|
-
var PERSISTENT_COMMAND = /(?:^|(?:&&|;|\|)\s*)(?:(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:dev|start|serve)(?:\s|$)|(?:vite|next\s+dev|webpack\s+serve)(?:\s|$)|bun\s+run\s+--hot\b)|(?:^|\s)(
|
|
8031
|
+
var PERSISTENT_COMMAND = /(?:^|(?:&&|;|\|)\s*)(?:(?:npm|pnpm|yarn|bun)\s+(?:run\s+)?(?:dev|start|serve)(?:\s|$)|(?:vite|next\s+dev|webpack\s+serve)(?:\s|$)|bun\s+run\s+--hot\b)|(?:^|\s)--watch(?:\s|$)|\b(?:tsc|vitest|mocha|tailwindcss|webpack|rollup|nodemon|tsup|swc)\b[^|;&\n]*\s-w(?:\s|$)/i;
|
|
8650
8032
|
var CD_PREFIX = /^\s*cd\s+(?:[^&\n|;]|\&(?!\&))+&&\s*/;
|
|
8651
8033
|
function verificationTarget(command) {
|
|
8652
8034
|
let target = command;
|
|
@@ -8678,6 +8060,24 @@ ${result.stderr}`.trim();
|
|
|
8678
8060
|
}
|
|
8679
8061
|
return null;
|
|
8680
8062
|
}
|
|
8063
|
+
var SCRIPT_INTERPRETER = /^(?:python[\d.]*|py|node|bun|deno|tsx|ts-node|ruby|php|perl|bash|sh|zsh|lua|Rscript)$/;
|
|
8064
|
+
function runsWrittenScript(command, written) {
|
|
8065
|
+
if (written.size === 0)
|
|
8066
|
+
return false;
|
|
8067
|
+
let tokens;
|
|
8068
|
+
try {
|
|
8069
|
+
tokens = tokenizeCommand(verificationTarget(command));
|
|
8070
|
+
} catch {
|
|
8071
|
+
return false;
|
|
8072
|
+
}
|
|
8073
|
+
if (tokens.length < 2 || !SCRIPT_INTERPRETER.test(tokens[0].split("/").pop() ?? ""))
|
|
8074
|
+
return false;
|
|
8075
|
+
const file = tokens.slice(1).find((token) => !token.startsWith("-"));
|
|
8076
|
+
if (!file)
|
|
8077
|
+
return false;
|
|
8078
|
+
const clean = file.replace(/^(\.\/)+/, "");
|
|
8079
|
+
return [...written].some((path9) => clean === path9 || clean.endsWith(`/${path9}`));
|
|
8080
|
+
}
|
|
8681
8081
|
function classifyVerification(command) {
|
|
8682
8082
|
const target = verificationTarget(command);
|
|
8683
8083
|
if (BEHAVIOR_COMMAND.test(target))
|
|
@@ -8695,7 +8095,7 @@ function stripMarkup(html) {
|
|
|
8695
8095
|
`).replace(/[ \t]{2,}/g, " ").trim();
|
|
8696
8096
|
}
|
|
8697
8097
|
|
|
8698
|
-
//
|
|
8098
|
+
// ../core/src/money.ts
|
|
8699
8099
|
var CURRENCIES = (() => {
|
|
8700
8100
|
try {
|
|
8701
8101
|
return Intl.supportedValuesOf("currency");
|
|
@@ -8785,7 +8185,7 @@ function priceUsage(usage, prices) {
|
|
|
8785
8185
|
return money(micros, prices.currency);
|
|
8786
8186
|
}
|
|
8787
8187
|
|
|
8788
|
-
//
|
|
8188
|
+
// ../core/src/pricing.ts
|
|
8789
8189
|
var ISO_DATE = /^\d{4}-\d{2}-\d{2}$/;
|
|
8790
8190
|
function assertDate(value, label) {
|
|
8791
8191
|
if (!ISO_DATE.test(value) || Number.isNaN(Date.parse(value)))
|
|
@@ -8874,7 +8274,7 @@ function priceUnits(record, quantities) {
|
|
|
8874
8274
|
return money(units * 1e6, record.currency);
|
|
8875
8275
|
}
|
|
8876
8276
|
|
|
8877
|
-
//
|
|
8277
|
+
// ../core/src/providers/free-usage.ts
|
|
8878
8278
|
import { promises as fs9 } from "node:fs";
|
|
8879
8279
|
import path9 from "node:path";
|
|
8880
8280
|
var FREE_REMAINING_TOKENS_HEADER = "x-free-remaining-tokens";
|
|
@@ -9014,7 +8414,7 @@ class FreeUsageMeter {
|
|
|
9014
8414
|
}
|
|
9015
8415
|
}
|
|
9016
8416
|
|
|
9017
|
-
//
|
|
8417
|
+
// ../core/src/cli/cost.ts
|
|
9018
8418
|
function formatTokenFlow(usage) {
|
|
9019
8419
|
return `↑${compactTokenCount(usage.inputTokens)} ↓${compactTokenCount(usage.outputTokens)} tok`;
|
|
9020
8420
|
}
|
|
@@ -9042,7 +8442,7 @@ function predictAgentUsage(input) {
|
|
|
9042
8442
|
outputTokensHigh: Math.round(outputTokensExpected * 1.7)
|
|
9043
8443
|
};
|
|
9044
8444
|
}
|
|
9045
|
-
var
|
|
8445
|
+
var emptyUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0, cachedInputTokens: 0, cacheWriteTokens: 0, reasoningTokens: 0 };
|
|
9046
8446
|
var CACHE_CHURN_FLOOR_TOKENS = 20000;
|
|
9047
8447
|
var CACHE_CHURN_HINT = [
|
|
9048
8448
|
"The prompt cache is being rewritten more than it is read, which costs more than not caching at all.",
|
|
@@ -9130,7 +8530,7 @@ class CostLedger {
|
|
|
9130
8530
|
cachedInputTokens: total.cachedInputTokens + turn.usage.cachedInputTokens,
|
|
9131
8531
|
cacheWriteTokens: total.cacheWriteTokens + turn.usage.cacheWriteTokens,
|
|
9132
8532
|
reasoningTokens: total.reasoningTokens + turn.usage.reasoningTokens
|
|
9133
|
-
}), { ...
|
|
8533
|
+
}), { ...emptyUsage });
|
|
9134
8534
|
}
|
|
9135
8535
|
get history() {
|
|
9136
8536
|
return [...this.turns];
|
|
@@ -9290,10 +8690,10 @@ class CostLedger {
|
|
|
9290
8690
|
}
|
|
9291
8691
|
}
|
|
9292
8692
|
|
|
9293
|
-
//
|
|
8693
|
+
// ../core/src/cli/backends.ts
|
|
9294
8694
|
import path11 from "node:path";
|
|
9295
8695
|
|
|
9296
|
-
//
|
|
8696
|
+
// ../core/src/sandbox-search.ts
|
|
9297
8697
|
var DEFAULT_IGNORED_DIRECTORIES = [".git", "node_modules", ".next", "dist", "build", "target", "__pycache__", ".venv", "venv", ".pytest_cache", ".mypy_cache", ".ruff_cache", ".turbo", "vendor", ".archymedes"];
|
|
9298
8698
|
async function listSandboxFiles(sandbox, sandboxId, root, ignoredDirectories = DEFAULT_IGNORED_DIRECTORIES) {
|
|
9299
8699
|
const result = await sandbox.runCommand(sandboxId, {
|
|
@@ -9367,7 +8767,7 @@ function relativeTo(root, absolute) {
|
|
|
9367
8767
|
return absolute.startsWith(`${root}/`) ? absolute.slice(root.length + 1) : absolute;
|
|
9368
8768
|
}
|
|
9369
8769
|
|
|
9370
|
-
//
|
|
8770
|
+
// ../core/src/cli/applications.ts
|
|
9371
8771
|
import { spawn as spawn5 } from "node:child_process";
|
|
9372
8772
|
import { stat } from "node:fs/promises";
|
|
9373
8773
|
import http from "node:http";
|
|
@@ -9516,8 +8916,10 @@ class LocalApplicationSupervisor {
|
|
|
9516
8916
|
}
|
|
9517
8917
|
async stop(id) {
|
|
9518
8918
|
const application = this.applications.get(id);
|
|
9519
|
-
if (!application)
|
|
9520
|
-
|
|
8919
|
+
if (!application) {
|
|
8920
|
+
const known = [...this.applications.keys()];
|
|
8921
|
+
throw new Error(`Unknown application: ${id}. ${known.length > 0 ? `Running or known: ${known.join(", ")}.` : "No applications are managed right now; start one with start_application."}`);
|
|
8922
|
+
}
|
|
9521
8923
|
if (application.state !== "exited") {
|
|
9522
8924
|
terminateProcessTree2(application.process);
|
|
9523
8925
|
await Promise.race([
|
|
@@ -9553,7 +8955,7 @@ The process produced no logs.`;
|
|
|
9553
8955
|
}
|
|
9554
8956
|
}
|
|
9555
8957
|
|
|
9556
|
-
//
|
|
8958
|
+
// ../core/src/cli/backends.ts
|
|
9557
8959
|
var CONFIG_FILE_SCAN_LIMIT = 500;
|
|
9558
8960
|
function localCommandGuidance(platform) {
|
|
9559
8961
|
if (platform !== "win32")
|
|
@@ -9726,7 +9128,7 @@ class SandboxWorkspace {
|
|
|
9726
9128
|
const existing = await this.readFile(path12);
|
|
9727
9129
|
const occurrences = existing.content.split(oldText).length - 1;
|
|
9728
9130
|
if (occurrences === 0)
|
|
9729
|
-
throw new WorkspaceViolation(`oldText was not found in ${existing.path}`);
|
|
9131
|
+
throw new WorkspaceViolation(`oldText was not found in ${existing.path}.${nearestLineHint(existing.content, oldText)}`);
|
|
9730
9132
|
if (occurrences > 1 && !options.replaceAll) {
|
|
9731
9133
|
throw new WorkspaceViolation(`oldText appears ${occurrences} times in ${existing.path}; include more surrounding context or set replaceAll`);
|
|
9732
9134
|
}
|
|
@@ -9868,8 +9270,8 @@ async function downloadProject(workspace, localRoot, options = {}) {
|
|
|
9868
9270
|
return { written, failed };
|
|
9869
9271
|
}
|
|
9870
9272
|
|
|
9871
|
-
//
|
|
9872
|
-
import { createHash as
|
|
9273
|
+
// ../core/src/cli/artifacts.ts
|
|
9274
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
9873
9275
|
var ARTIFACT_DIRECTORY = ".archymedes/artifacts";
|
|
9874
9276
|
var MAX_ARTIFACT_BYTES = 480000;
|
|
9875
9277
|
function safeToolName(toolName) {
|
|
@@ -9877,7 +9279,7 @@ function safeToolName(toolName) {
|
|
|
9877
9279
|
return cleaned || "tool";
|
|
9878
9280
|
}
|
|
9879
9281
|
function artifactPathFor(toolName, content) {
|
|
9880
|
-
const digest2 =
|
|
9282
|
+
const digest2 = createHash6("sha256").update(content).digest("hex").slice(0, 12);
|
|
9881
9283
|
return `${ARTIFACT_DIRECTORY}/${safeToolName(toolName)}-${digest2}.txt`;
|
|
9882
9284
|
}
|
|
9883
9285
|
|
|
@@ -9912,12 +9314,12 @@ function countLines(content) {
|
|
|
9912
9314
|
return lines;
|
|
9913
9315
|
}
|
|
9914
9316
|
|
|
9915
|
-
//
|
|
9317
|
+
// ../core/src/cli/defender-brain.ts
|
|
9916
9318
|
import { access as access2 } from "node:fs/promises";
|
|
9917
9319
|
import path14 from "node:path";
|
|
9918
9320
|
import { fileURLToPath } from "node:url";
|
|
9919
9321
|
|
|
9920
|
-
//
|
|
9322
|
+
// ../core/src/cli/state-client.ts
|
|
9921
9323
|
import { spawn as spawn6 } from "node:child_process";
|
|
9922
9324
|
import { access } from "node:fs/promises";
|
|
9923
9325
|
import { createRequire } from "node:module";
|
|
@@ -10131,8 +9533,8 @@ async function tryConnectArchymedesState(options = {}) {
|
|
|
10131
9533
|
return binary ? ArchymedesStateClient.connect({ ...options, binary }) : null;
|
|
10132
9534
|
}
|
|
10133
9535
|
|
|
10134
|
-
//
|
|
10135
|
-
import { createHash as
|
|
9536
|
+
// ../core/src/cli/defender-feed.ts
|
|
9537
|
+
import { createHash as createHash7, createPublicKey, verify as verifySignature } from "node:crypto";
|
|
10136
9538
|
import { promises as fs10 } from "node:fs";
|
|
10137
9539
|
import path13 from "node:path";
|
|
10138
9540
|
var DEFENDER_FEED_INTERVAL_MS = 6 * 60 * 60 * 1000;
|
|
@@ -10326,7 +9728,7 @@ async function refreshDefenderFeed(options) {
|
|
|
10326
9728
|
const bytes = await boundedResponseBody(corpusResponse, manifest.corpus.bytes, "corpus");
|
|
10327
9729
|
if (bytes.byteLength !== manifest.corpus.bytes)
|
|
10328
9730
|
throw new Error("corpus byte count does not match manifest");
|
|
10329
|
-
if (
|
|
9731
|
+
if (createHash7("sha256").update(bytes).digest("hex") !== manifest.corpus.sha256)
|
|
10330
9732
|
throw new Error("corpus digest does not match manifest");
|
|
10331
9733
|
const records = bytes.toString("utf8").split(`
|
|
10332
9734
|
`).filter((line) => line.trim()).length;
|
|
@@ -10360,7 +9762,7 @@ async function refreshDefenderFeed(options) {
|
|
|
10360
9762
|
}
|
|
10361
9763
|
}
|
|
10362
9764
|
|
|
10363
|
-
//
|
|
9765
|
+
// ../core/src/cli/defender-brain.ts
|
|
10364
9766
|
async function existingDirectory(candidates) {
|
|
10365
9767
|
for (const candidate of candidates) {
|
|
10366
9768
|
try {
|
|
@@ -10446,7 +9848,7 @@ class DefenderBrain {
|
|
|
10446
9848
|
}
|
|
10447
9849
|
}
|
|
10448
9850
|
|
|
10449
|
-
//
|
|
9851
|
+
// ../core/src/cli/tool-profile.ts
|
|
10450
9852
|
var MUTATING = /\b(create|write|edit|change|modify|fix|implement|build|install|delete|remove|rename|move|run|test|commit|push|deploy|publish|send|continue|resume|update|add|refactor|replace|rewrite|append|insert|generate|format|upgrade|bump|revert|patch|migrate|scaffold|save|set up|setup)\b/i;
|
|
10451
9853
|
var REPOSITORY_READING = /\b(review|inspect|audit|analy[sz]e|diagnose|explain|find|locate|search|read|why|error|bug|code|repo(?:sitory)?|project|file|folder|function|class|test|diff)\b/i;
|
|
10452
9854
|
var DIRECT_CHAT = /^(?:hi|hello|hey|thanks|thank you|who are you|what can you do)[.!?\s]*$/i;
|
|
@@ -10473,7 +9875,7 @@ function toolsForProfile(tools, profile) {
|
|
|
10473
9875
|
return tools.filter((tool) => tool.effect === "none");
|
|
10474
9876
|
}
|
|
10475
9877
|
|
|
10476
|
-
//
|
|
9878
|
+
// ../core/src/cli/jev.ts
|
|
10477
9879
|
var JEV_API_URL = "https://api.typesafe.ai/v1/systemone";
|
|
10478
9880
|
var JEV_DEFAULT_MODEL = "jev-latest";
|
|
10479
9881
|
var JEV_TIMEOUT_MS = 30000;
|
|
@@ -10662,6 +10064,26 @@ async function requestJevVerdict(options) {
|
|
|
10662
10064
|
throw new JevError(200, "Jev returned a body that could not be read as a verdict");
|
|
10663
10065
|
}
|
|
10664
10066
|
}
|
|
10067
|
+
var DIFFICULTY_QUESTIONS = {
|
|
10068
|
+
difficulty: {
|
|
10069
|
+
type: "choice",
|
|
10070
|
+
instructions: "How much careful reasoning does this coding task need from the person or agent doing it?",
|
|
10071
|
+
criteria: {
|
|
10072
|
+
routine: "A direct, well-specified change or question with an obvious approach: add a file, rename, run a command, explain something simple",
|
|
10073
|
+
involved: "Several steps or files, but each one is clear once the previous is done",
|
|
10074
|
+
hard: "Diagnosing a failure, an unclear cause, a design or architecture decision, a subtle bug, security or concurrency reasoning, or a large refactor"
|
|
10075
|
+
}
|
|
10076
|
+
}
|
|
10077
|
+
};
|
|
10078
|
+
function difficultyFromResponse(response) {
|
|
10079
|
+
const answer = response.answers.difficulty;
|
|
10080
|
+
if (!answer || answer.type !== "choice")
|
|
10081
|
+
return;
|
|
10082
|
+
if (answer.choice !== "routine" && answer.choice !== "involved" && answer.choice !== "hard")
|
|
10083
|
+
return;
|
|
10084
|
+
const probability2 = answer.probabilities[answer.choice] ?? answer.confidence;
|
|
10085
|
+
return probability2 >= 0.55 ? { difficulty: answer.choice, probability: probability2 } : undefined;
|
|
10086
|
+
}
|
|
10665
10087
|
function turnVerdictState(input) {
|
|
10666
10088
|
const tools = input.toolNames.length > 0 ? `Tools used: ${[...new Set(input.toolNames)].join(", ")}.` : "No tools used.";
|
|
10667
10089
|
const lines = [
|
|
@@ -10696,7 +10118,7 @@ function verdictFromResponse(response) {
|
|
|
10696
10118
|
};
|
|
10697
10119
|
}
|
|
10698
10120
|
|
|
10699
|
-
//
|
|
10121
|
+
// ../core/src/cli/agent.ts
|
|
10700
10122
|
var DELEGATION_TOOLS = new Set(["delegate_task", "delegate_readonly_task"]);
|
|
10701
10123
|
var EDIT_DIAGNOSTIC_TOOLS = new Set(["edit_file", "write_file"]);
|
|
10702
10124
|
var EDIT_DIAGNOSTICS_TIMEOUT_MS = 3000;
|
|
@@ -10799,6 +10221,9 @@ class ArchymedesAgent {
|
|
|
10799
10221
|
const { maxRwf: _maxRwf, ...callerLimits } = this.options.budgets ?? {};
|
|
10800
10222
|
Object.assign(this.budgets, this.modelBudgets(), callerLimits);
|
|
10801
10223
|
}
|
|
10224
|
+
warmUp() {
|
|
10225
|
+
this.loadEnvironment();
|
|
10226
|
+
}
|
|
10802
10227
|
loadEnvironment() {
|
|
10803
10228
|
this.environment ??= probeEnvironment(this.workspace);
|
|
10804
10229
|
return this.environment.catch(() => {
|
|
@@ -10812,7 +10237,7 @@ class ArchymedesAgent {
|
|
|
10812
10237
|
this.nestedInstructions = new NestedInstructionTracker(this.workspace);
|
|
10813
10238
|
this.artifacts = new WorkspaceArtifactStore(this.workspace);
|
|
10814
10239
|
this.defenderBrain = new DefenderBrain(path15.join(options.root, ".archymedes", "security-brain"));
|
|
10815
|
-
this.checkpoints = new CheckpointStore(options.root, path15.join(options.root, ".archymedes", `checkpoint-index-${
|
|
10240
|
+
this.checkpoints = new CheckpointStore(options.root, path15.join(options.root, ".archymedes", `checkpoint-index-${randomUUID4()}`), options.git);
|
|
10816
10241
|
this.session = {
|
|
10817
10242
|
schemaVersion: 2,
|
|
10818
10243
|
revision: 0,
|
|
@@ -10961,10 +10386,12 @@ class ArchymedesAgent {
|
|
|
10961
10386
|
get todos() {
|
|
10962
10387
|
return this.todoList.list();
|
|
10963
10388
|
}
|
|
10964
|
-
diffPatch() {
|
|
10389
|
+
async diffPatch() {
|
|
10390
|
+
await this.pendingCheckpoint;
|
|
10965
10391
|
return this.checkpoints.diffPatch();
|
|
10966
10392
|
}
|
|
10967
|
-
diffStat() {
|
|
10393
|
+
async diffStat() {
|
|
10394
|
+
await this.pendingCheckpoint;
|
|
10968
10395
|
return this.checkpoints.diffStat();
|
|
10969
10396
|
}
|
|
10970
10397
|
listFiles(pattern = "**/*") {
|
|
@@ -11076,6 +10503,7 @@ class ArchymedesAgent {
|
|
|
11076
10503
|
if (this.turnAbort)
|
|
11077
10504
|
throw new Error("Cannot undo while a turn is running");
|
|
11078
10505
|
await this.acquireOwnership();
|
|
10506
|
+
await this.pendingCheckpoint;
|
|
11079
10507
|
const checkpoint = this.checkpoints.latest();
|
|
11080
10508
|
if (!checkpoint)
|
|
11081
10509
|
return;
|
|
@@ -11102,7 +10530,7 @@ class ArchymedesAgent {
|
|
|
11102
10530
|
this.delegatedInFlightRwf += reservation;
|
|
11103
10531
|
try {
|
|
11104
10532
|
const runtime = new BoundedAgentRuntime({
|
|
11105
|
-
model: this.recovery.wrap(this.options.model, () => this.session, this.options.prices, `delegate:${
|
|
10533
|
+
model: this.recovery.wrap(this.options.model, () => this.session, this.options.prices, `delegate:${randomUUID4()}`),
|
|
11106
10534
|
tools,
|
|
11107
10535
|
prices: this.options.prices,
|
|
11108
10536
|
artifacts: this.artifacts,
|
|
@@ -11116,7 +10544,7 @@ class ArchymedesAgent {
|
|
|
11116
10544
|
const result = await runtime.execute({
|
|
11117
10545
|
taskId: `${this.session.id}_delegate`,
|
|
11118
10546
|
runId: this.session.id,
|
|
11119
|
-
stepId: `delegate_${
|
|
10547
|
+
stepId: `delegate_${randomUUID4()}`,
|
|
11120
10548
|
objective: task,
|
|
11121
10549
|
history: [],
|
|
11122
10550
|
systemPrompt,
|
|
@@ -11159,7 +10587,7 @@ class ArchymedesAgent {
|
|
|
11159
10587
|
this.turnAbort = null;
|
|
11160
10588
|
throw error;
|
|
11161
10589
|
}
|
|
11162
|
-
const turnId = `turn_${
|
|
10590
|
+
const turnId = `turn_${randomUUID4()}`;
|
|
11163
10591
|
this.activeTurnId = turnId;
|
|
11164
10592
|
let turnStatus = "queued";
|
|
11165
10593
|
const transition = async (to, durable = false) => {
|
|
@@ -11218,17 +10646,28 @@ class ArchymedesAgent {
|
|
|
11218
10646
|
|
|
11219
10647
|
${requested}` : requested;
|
|
11220
10648
|
let checkpoint;
|
|
10649
|
+
let checkpointReady = Promise.resolve();
|
|
11221
10650
|
if (this.options.mode !== "plan" && this.workspace.kind === "local") {
|
|
11222
|
-
|
|
11223
|
-
|
|
11224
|
-
|
|
10651
|
+
checkpointReady = this.checkpoints.capture(titleFromObjective(objective), turnId, this.messages.length).then((taken) => {
|
|
10652
|
+
checkpoint = taken;
|
|
10653
|
+
if (taken)
|
|
10654
|
+
this.options.onEvent?.({ type: "checkpoint", checkpoint: taken });
|
|
10655
|
+
}).catch(() => {
|
|
10656
|
+
return;
|
|
10657
|
+
});
|
|
10658
|
+
this.pendingCheckpoint = checkpointReady;
|
|
11225
10659
|
}
|
|
11226
10660
|
const compaction = await this.compactIfNeeded(turnId, objective, turnAbort.signal, tokenSaver);
|
|
11227
10661
|
compactionActualRwf = compaction.actualRwf;
|
|
11228
10662
|
this.permissions.setTaskHint(objective);
|
|
10663
|
+
this.startDifficultyReading(objective, turnAbort.signal);
|
|
11229
10664
|
const runtime = new BoundedAgentRuntime({
|
|
11230
10665
|
model: this.recovery.wrap(this.options.model, () => this.session, this.options.prices, "main"),
|
|
11231
|
-
|
|
10666
|
+
...this.options.reasoning === "auto" ? { effortPolicy: (signals) => predictEffort({ ...signals, objective, ...this.jevDifficulty ? { difficultyHint: this.jevDifficulty } : {} }) } : {},
|
|
10667
|
+
tools: scoped.map((tool) => ({ ...tool, execute: async (args, context) => {
|
|
10668
|
+
await checkpointReady;
|
|
10669
|
+
return tool.execute(args, context);
|
|
10670
|
+
} })),
|
|
11232
10671
|
prices: this.options.prices,
|
|
11233
10672
|
artifacts: this.artifacts,
|
|
11234
10673
|
control: {
|
|
@@ -11267,6 +10706,7 @@ ${requested}` : requested;
|
|
|
11267
10706
|
runId: this.session.id,
|
|
11268
10707
|
stepId: `turn_${this.messages.length}`,
|
|
11269
10708
|
objective: turnObjective,
|
|
10709
|
+
...this.options.reasoning && this.options.reasoning !== "auto" ? { effort: this.options.reasoning } : {},
|
|
11270
10710
|
images: attached.images,
|
|
11271
10711
|
history: sentHistory,
|
|
11272
10712
|
systemPrompt,
|
|
@@ -11301,6 +10741,7 @@ ${hookWarnings.join(`
|
|
|
11301
10741
|
hostedRecoveryBatchId: this.recovery.settledBatchId() ?? this.session.hostedRecoveryBatchId,
|
|
11302
10742
|
updatedAt: Date.now()
|
|
11303
10743
|
};
|
|
10744
|
+
await checkpointReady;
|
|
11304
10745
|
const terminalStatus = runtimeStatusToTurnStatus(result.status);
|
|
11305
10746
|
await transition(terminalStatus, true);
|
|
11306
10747
|
await this.recordHostedUsage();
|
|
@@ -11351,6 +10792,8 @@ ${hookWarnings.join(`
|
|
|
11351
10792
|
for (const call of message.toolCalls)
|
|
11352
10793
|
toolNames.push(call.name);
|
|
11353
10794
|
}
|
|
10795
|
+
if (toolNames.length === 0)
|
|
10796
|
+
return;
|
|
11354
10797
|
try {
|
|
11355
10798
|
const response = await requestJevVerdict({
|
|
11356
10799
|
apiKey: this.jev.apiKey,
|
|
@@ -11385,6 +10828,30 @@ ${hookWarnings.join(`
|
|
|
11385
10828
|
return (verdict.outcomeProbabilities[verdict.outcome] ?? 0) >= 0.5;
|
|
11386
10829
|
}
|
|
11387
10830
|
jevCorrectionDepth = 0;
|
|
10831
|
+
pendingCheckpoint = Promise.resolve();
|
|
10832
|
+
jevDifficulty;
|
|
10833
|
+
difficultyStamp = 0;
|
|
10834
|
+
startDifficultyReading(objective, signal) {
|
|
10835
|
+
this.jevDifficulty = undefined;
|
|
10836
|
+
const stamp = ++this.difficultyStamp;
|
|
10837
|
+
if (this.options.reasoning !== "auto" || !this.jev)
|
|
10838
|
+
return;
|
|
10839
|
+
requestJevVerdict({
|
|
10840
|
+
apiKey: this.jev.apiKey,
|
|
10841
|
+
...this.jev.model ? { model: this.jev.model } : {},
|
|
10842
|
+
...this.jev.fetchImpl ? { fetchImpl: this.jev.fetchImpl } : {},
|
|
10843
|
+
state: objective,
|
|
10844
|
+
questions: DIFFICULTY_QUESTIONS,
|
|
10845
|
+
timeoutMs: 5000,
|
|
10846
|
+
signal
|
|
10847
|
+
}).then((response) => {
|
|
10848
|
+
if (stamp !== this.difficultyStamp)
|
|
10849
|
+
return;
|
|
10850
|
+
this.jevDifficulty = difficultyFromResponse(response)?.difficulty;
|
|
10851
|
+
}).catch(() => {
|
|
10852
|
+
return;
|
|
10853
|
+
});
|
|
10854
|
+
}
|
|
11388
10855
|
async correctivePrompt(objective, verdict, evidence) {
|
|
11389
10856
|
const failures = evidence.filter((entry) => entry.exitCode !== undefined && entry.exitCode !== 0).slice(-6);
|
|
11390
10857
|
const failureLine = failures.length > 0 ? `Failing commands from the last turn: ${failures.map((entry) => `\`${entry.command ?? entry.tool}\` exited ${entry.exitCode}`).join("; ")}.` : "The last turn produced no passing verification evidence.";
|
|
@@ -11484,15 +10951,15 @@ function isActiveTurnStatus(status) {
|
|
|
11484
10951
|
return status === "queued" || status === "running" || status === "waiting_approval";
|
|
11485
10952
|
}
|
|
11486
10953
|
|
|
11487
|
-
//
|
|
10954
|
+
// ../core/src/cli/edit-diagnostics.ts
|
|
11488
10955
|
import { promises as fs11 } from "node:fs";
|
|
11489
10956
|
import path16 from "node:path";
|
|
11490
10957
|
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "node:url";
|
|
11491
10958
|
|
|
11492
|
-
//
|
|
10959
|
+
// ../core/src/lsp/client.ts
|
|
11493
10960
|
import { spawn as spawn7, spawnSync } from "node:child_process";
|
|
11494
10961
|
|
|
11495
|
-
//
|
|
10962
|
+
// ../core/src/lsp/diagnostics.ts
|
|
11496
10963
|
function severityName(severity) {
|
|
11497
10964
|
switch (severity) {
|
|
11498
10965
|
case 1:
|
|
@@ -11598,7 +11065,7 @@ class DiagnosticsCollection {
|
|
|
11598
11065
|
}
|
|
11599
11066
|
}
|
|
11600
11067
|
|
|
11601
|
-
//
|
|
11068
|
+
// ../core/src/lsp/protocol.ts
|
|
11602
11069
|
var HEADER_SEPARATOR = `\r
|
|
11603
11070
|
\r
|
|
11604
11071
|
`;
|
|
@@ -11644,7 +11111,7 @@ function isJsonRpcNotification3(value) {
|
|
|
11644
11111
|
return typeof value === "object" && value !== null && "jsonrpc" in value && !("id" in value) && typeof value.method === "string";
|
|
11645
11112
|
}
|
|
11646
11113
|
|
|
11647
|
-
//
|
|
11114
|
+
// ../core/src/lsp/client.ts
|
|
11648
11115
|
class LspClientError extends Error {
|
|
11649
11116
|
constructor(message) {
|
|
11650
11117
|
super(message);
|
|
@@ -11855,7 +11322,7 @@ function toLocations(result) {
|
|
|
11855
11322
|
return candidates.filter((candidate) => typeof candidate === "object" && candidate !== null && typeof candidate.uri === "string" && typeof candidate.range === "object");
|
|
11856
11323
|
}
|
|
11857
11324
|
|
|
11858
|
-
//
|
|
11325
|
+
// ../core/src/lsp/servers.ts
|
|
11859
11326
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
11860
11327
|
var LANGUAGE_SERVERS = [
|
|
11861
11328
|
{
|
|
@@ -11996,7 +11463,7 @@ function defaultProbe(command) {
|
|
|
11996
11463
|
});
|
|
11997
11464
|
}
|
|
11998
11465
|
|
|
11999
|
-
//
|
|
11466
|
+
// ../core/src/cli/edit-diagnostics.ts
|
|
12000
11467
|
var DEFAULT_TIMEOUT_MS = 1500;
|
|
12001
11468
|
var DEFAULT_REFINE_MS = 250;
|
|
12002
11469
|
var DEFAULT_MAX_LINES = 20;
|
|
@@ -12217,7 +11684,7 @@ function createLspEditDiagnostics(root, options = {}) {
|
|
|
12217
11684
|
});
|
|
12218
11685
|
}
|
|
12219
11686
|
|
|
12220
|
-
//
|
|
11687
|
+
// ../core/src/providers/price-catalog.ts
|
|
12221
11688
|
var ANTHROPIC_VERIFIED = "2026-06-24";
|
|
12222
11689
|
var ANTHROPIC_SOURCE = "anthropic.com/pricing, recorded 2026-06-24";
|
|
12223
11690
|
var ANTHROPIC = [
|
|
@@ -12269,7 +11736,7 @@ var SERVICES = [
|
|
|
12269
11736
|
];
|
|
12270
11737
|
var PRICE_CATALOG = definePrices([...ANTHROPIC, ...OAI_COMPAT_LABS, ...SERVICES]);
|
|
12271
11738
|
|
|
12272
|
-
//
|
|
11739
|
+
// ../core/src/providers/free-catalog.ts
|
|
12273
11740
|
var FREE_ROUTER = "openrouter/free";
|
|
12274
11741
|
var FREE_BASE_URL = "https://openrouter.ai/api/v1";
|
|
12275
11742
|
var FREE_GATEWAY_URL = "";
|
|
@@ -12278,6 +11745,7 @@ var FREE_CATALOG_TTL_MS = 6 * 60 * 60 * 1000;
|
|
|
12278
11745
|
var FREE_CATALOG_MAX_RECORDS = 1e4;
|
|
12279
11746
|
var FREE_ROUTER_PREFERENCE = [
|
|
12280
11747
|
"cohere/north-mini-code:free",
|
|
11748
|
+
"nvidia/nemotron-3-super-120b-a12b:free",
|
|
12281
11749
|
"google/gemma-4-31b-it:free",
|
|
12282
11750
|
"dots-studio/dots-3-note-preview:free",
|
|
12283
11751
|
"nex-agi/nex-n2.5-pro:free",
|
|
@@ -12404,8 +11872,21 @@ function mergeFreeCatalog(live, discovery, fetchedAt, warnings = []) {
|
|
|
12404
11872
|
}
|
|
12405
11873
|
return { fetchedAt, models: [...byId.values()].sort((a, b) => a.id.localeCompare(b.id)), warnings };
|
|
12406
11874
|
}
|
|
11875
|
+
var SMALL_MODEL_BILLIONS = 4;
|
|
11876
|
+
function modelSizeBillions(model) {
|
|
11877
|
+
const id = model.toLowerCase();
|
|
11878
|
+
const billions = [...id.matchAll(/(?:^|[^a-z0-9.])(\d+(?:\.\d+)?)b(?![a-z])/g)];
|
|
11879
|
+
if (billions.length > 0)
|
|
11880
|
+
return Math.min(...billions.map((match) => Number(match[1])));
|
|
11881
|
+
const millions = id.match(/(?:^|[^a-z0-9.])(\d+(?:\.\d+)?)m(?![a-z])/);
|
|
11882
|
+
return millions ? Number(millions[1]) / 1000 : null;
|
|
11883
|
+
}
|
|
11884
|
+
function isSmallModel(model) {
|
|
11885
|
+
const size = modelSizeBillions(model);
|
|
11886
|
+
return size !== null && size <= SMALL_MODEL_BILLIONS;
|
|
11887
|
+
}
|
|
12407
11888
|
|
|
12408
|
-
//
|
|
11889
|
+
// ../core/src/providers/provider-specs.ts
|
|
12409
11890
|
var PROVIDER_IDS = [
|
|
12410
11891
|
"anthropic",
|
|
12411
11892
|
"openai",
|
|
@@ -12466,7 +11947,7 @@ var PROVIDER_INFO = {
|
|
|
12466
11947
|
}
|
|
12467
11948
|
};
|
|
12468
11949
|
|
|
12469
|
-
//
|
|
11950
|
+
// ../core/src/providers/anthropic-agent.ts
|
|
12470
11951
|
async function collectAnthropicStream(stream, onTextDelta, onOutputProgress) {
|
|
12471
11952
|
let id = "";
|
|
12472
11953
|
let model = "";
|
|
@@ -12625,7 +12106,7 @@ class AnthropicAgentTurnProvider {
|
|
|
12625
12106
|
let client;
|
|
12626
12107
|
this.call = async (body, signal) => {
|
|
12627
12108
|
if (!client) {
|
|
12628
|
-
const { default: Anthropic } = await import("./index-
|
|
12109
|
+
const { default: Anthropic } = await import("./index-qvgcwsvm.mjs").catch(() => {
|
|
12629
12110
|
throw new Error("The Anthropic provider needs the @anthropic-ai/sdk package. Install it with: npm install @anthropic-ai/sdk");
|
|
12630
12111
|
});
|
|
12631
12112
|
client = new Anthropic({ apiKey: options.apiKey, ...options.baseURL ? { baseURL: options.baseURL } : {}, maxRetries: 0 });
|
|
@@ -12645,7 +12126,7 @@ class AnthropicAgentTurnProvider {
|
|
|
12645
12126
|
...system ? { system } : {},
|
|
12646
12127
|
messages,
|
|
12647
12128
|
tools,
|
|
12648
|
-
...request.effort && this.capabilities.supportsEffort ? { output_config: { effort: request.effort } } : {},
|
|
12129
|
+
...request.effort && this.capabilities.supportsEffort ? { output_config: { effort: providerEffort(request.effort) } } : {},
|
|
12649
12130
|
metadata: { user_id: request.safetyIdentifier },
|
|
12650
12131
|
stream: true
|
|
12651
12132
|
};
|
|
@@ -12687,10 +12168,10 @@ class AnthropicAgentTurnProvider {
|
|
|
12687
12168
|
}
|
|
12688
12169
|
}
|
|
12689
12170
|
|
|
12690
|
-
//
|
|
12691
|
-
import { createHash as
|
|
12171
|
+
// ../core/src/providers/archymedes-cloud-agent.ts
|
|
12172
|
+
import { createHash as createHash8, randomUUID as randomUUID5 } from "node:crypto";
|
|
12692
12173
|
|
|
12693
|
-
//
|
|
12174
|
+
// ../core/src/providers/routing-plan.ts
|
|
12694
12175
|
function isRecord2(value) {
|
|
12695
12176
|
return typeof value === "object" && value !== null;
|
|
12696
12177
|
}
|
|
@@ -12762,7 +12243,7 @@ function planCurrency(ranked) {
|
|
|
12762
12243
|
return;
|
|
12763
12244
|
}
|
|
12764
12245
|
|
|
12765
|
-
//
|
|
12246
|
+
// ../core/src/providers/credit-balance.ts
|
|
12766
12247
|
function isRecord3(value) {
|
|
12767
12248
|
return typeof value === "object" && value !== null;
|
|
12768
12249
|
}
|
|
@@ -12797,7 +12278,7 @@ function parseCreditBalance(value) {
|
|
|
12797
12278
|
};
|
|
12798
12279
|
}
|
|
12799
12280
|
|
|
12800
|
-
//
|
|
12281
|
+
// ../core/src/providers/archymedes-cloud-agent.ts
|
|
12801
12282
|
class ArchymedesCloudError extends Error {
|
|
12802
12283
|
status;
|
|
12803
12284
|
code;
|
|
@@ -12863,7 +12344,7 @@ class ArchymedesCloudTurnProvider {
|
|
|
12863
12344
|
this.planUrl = base.endsWith("/v1") ? `${base}/routes/plan` : `${base}/v1/routes/plan`;
|
|
12864
12345
|
this.balanceUrl = base.endsWith("/v1") ? `${base}/credits/balance` : `${base}/v1/credits/balance`;
|
|
12865
12346
|
this.capabilities = capabilitiesFor(this.model);
|
|
12866
|
-
this.recoveryScope =
|
|
12347
|
+
this.recoveryScope = createHash8("sha256").update(JSON.stringify({
|
|
12867
12348
|
version: 1,
|
|
12868
12349
|
endpoint: this.completionUrl,
|
|
12869
12350
|
token: options.token,
|
|
@@ -12946,7 +12427,7 @@ class ArchymedesCloudTurnProvider {
|
|
|
12946
12427
|
async exchange(request, recoveryOnly) {
|
|
12947
12428
|
if (!request.safetyIdentifier.trim())
|
|
12948
12429
|
throw new Error("safetyIdentifier is required");
|
|
12949
|
-
const taskId = request.requestId ?? `cli_${
|
|
12430
|
+
const taskId = request.requestId ?? `cli_${randomUUID5()}`;
|
|
12950
12431
|
if (!/^[A-Za-z0-9_-]{1,160}$/.test(taskId))
|
|
12951
12432
|
throw new Error("requestId must contain 1 to 160 letters, numbers, underscores or hyphens");
|
|
12952
12433
|
request.signal?.throwIfAborted();
|
|
@@ -12973,7 +12454,7 @@ class ArchymedesCloudTurnProvider {
|
|
|
12973
12454
|
max_completion_tokens: request.maxOutputTokens,
|
|
12974
12455
|
safety_identifier: request.safetyIdentifier,
|
|
12975
12456
|
prompt_cache_key: request.safetyIdentifier,
|
|
12976
|
-
...request.effort ? { reasoning_effort: request.effort } : {},
|
|
12457
|
+
...request.effort ? { reasoning_effort: providerEffort(request.effort) } : {},
|
|
12977
12458
|
stream: false,
|
|
12978
12459
|
archymedes: {
|
|
12979
12460
|
task_id: taskId,
|
|
@@ -13014,7 +12495,9 @@ async function readBody(response) {
|
|
|
13014
12495
|
}
|
|
13015
12496
|
}
|
|
13016
12497
|
|
|
13017
|
-
//
|
|
12498
|
+
// ../core/src/providers/request-pacer.ts
|
|
12499
|
+
var MIN_LEARNABLE_CAP = 8;
|
|
12500
|
+
var LEARNED_CAP_LIFETIME_WINDOWS = 5;
|
|
13018
12501
|
var DEFAULTS = { baseGapMs: 2000, maxGapMs: 120000, releaseMs: 500 };
|
|
13019
12502
|
|
|
13020
12503
|
class RequestPacer {
|
|
@@ -13023,12 +12506,20 @@ class RequestPacer {
|
|
|
13023
12506
|
baseGapMs;
|
|
13024
12507
|
maxGapMs;
|
|
13025
12508
|
releaseMs;
|
|
12509
|
+
windowMs;
|
|
12510
|
+
cap;
|
|
12511
|
+
configuredCap;
|
|
12512
|
+
learnedAt = 0;
|
|
12513
|
+
starts = [];
|
|
13026
12514
|
now;
|
|
13027
12515
|
sleep;
|
|
13028
12516
|
constructor(options = {}) {
|
|
13029
12517
|
this.baseGapMs = options.baseGapMs ?? DEFAULTS.baseGapMs;
|
|
13030
12518
|
this.maxGapMs = options.maxGapMs ?? DEFAULTS.maxGapMs;
|
|
13031
12519
|
this.releaseMs = options.releaseMs ?? DEFAULTS.releaseMs;
|
|
12520
|
+
this.windowMs = options.windowMs ?? 60000;
|
|
12521
|
+
this.cap = options.windowCap !== undefined && options.windowCap >= 1 ? Math.floor(options.windowCap) : undefined;
|
|
12522
|
+
this.configuredCap = this.cap;
|
|
13032
12523
|
this.now = options.now ?? Date.now;
|
|
13033
12524
|
this.sleep = options.sleep ?? ((delayMs, signal) => new Promise((resolve, reject) => {
|
|
13034
12525
|
if (signal?.aborted) {
|
|
@@ -13046,33 +12537,67 @@ class RequestPacer {
|
|
|
13046
12537
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
13047
12538
|
}));
|
|
13048
12539
|
}
|
|
12540
|
+
get windowBudget() {
|
|
12541
|
+
return this.cap;
|
|
12542
|
+
}
|
|
12543
|
+
get inWindow() {
|
|
12544
|
+
this.prune(this.now());
|
|
12545
|
+
return this.starts.length;
|
|
12546
|
+
}
|
|
12547
|
+
prune(now) {
|
|
12548
|
+
let drop = 0;
|
|
12549
|
+
while (drop < this.starts.length && now - this.starts[drop] >= this.windowMs)
|
|
12550
|
+
drop += 1;
|
|
12551
|
+
if (drop > 0)
|
|
12552
|
+
this.starts.splice(0, drop);
|
|
12553
|
+
}
|
|
13049
12554
|
get paceMs() {
|
|
13050
12555
|
return this.gapMs;
|
|
13051
12556
|
}
|
|
13052
12557
|
async wait(signal) {
|
|
13053
12558
|
signal?.throwIfAborted();
|
|
13054
|
-
if (this.
|
|
13055
|
-
this.
|
|
13056
|
-
|
|
12559
|
+
if (this.learnedAt > 0 && this.now() - this.learnedAt > LEARNED_CAP_LIFETIME_WINDOWS * this.windowMs) {
|
|
12560
|
+
this.cap = this.configuredCap;
|
|
12561
|
+
this.learnedAt = 0;
|
|
12562
|
+
}
|
|
12563
|
+
if (this.cap !== undefined) {
|
|
12564
|
+
for (;; ) {
|
|
12565
|
+
const now = this.now();
|
|
12566
|
+
this.prune(now);
|
|
12567
|
+
if (this.starts.length < this.cap)
|
|
12568
|
+
break;
|
|
12569
|
+
await this.sleep(this.starts[0] + this.windowMs - now + 25, signal);
|
|
12570
|
+
signal?.throwIfAborted();
|
|
12571
|
+
}
|
|
12572
|
+
}
|
|
12573
|
+
if (this.gapMs > 0) {
|
|
12574
|
+
const remaining = this.gapMs - (this.now() - this.lastStart);
|
|
12575
|
+
if (remaining > 0)
|
|
12576
|
+
await this.sleep(remaining, signal);
|
|
12577
|
+
signal?.throwIfAborted();
|
|
13057
12578
|
}
|
|
13058
|
-
const elapsed = this.now() - this.lastStart;
|
|
13059
|
-
const remaining = this.gapMs - elapsed;
|
|
13060
|
-
if (remaining > 0)
|
|
13061
|
-
await this.sleep(remaining, signal);
|
|
13062
|
-
signal?.throwIfAborted();
|
|
13063
12579
|
this.lastStart = this.now();
|
|
12580
|
+
this.starts.push(this.lastStart);
|
|
12581
|
+
if (this.starts.length > 512)
|
|
12582
|
+
this.starts.splice(0, this.starts.length - 512);
|
|
13064
12583
|
}
|
|
13065
12584
|
reportSuccess() {
|
|
13066
12585
|
this.gapMs = Math.max(0, this.gapMs - this.releaseMs);
|
|
13067
12586
|
}
|
|
13068
12587
|
reportRateLimited(retryAfterMs) {
|
|
12588
|
+
this.prune(this.now());
|
|
12589
|
+
const admitted = this.starts.length - 1;
|
|
12590
|
+
if (admitted >= MIN_LEARNABLE_CAP && admitted < (this.cap ?? Number.POSITIVE_INFINITY)) {
|
|
12591
|
+
this.cap = admitted;
|
|
12592
|
+
this.learnedAt = this.now();
|
|
12593
|
+
}
|
|
13069
12594
|
const doubled = this.gapMs <= 0 ? this.baseGapMs : Math.min(this.maxGapMs, this.gapMs * 2);
|
|
13070
12595
|
const asked = typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs) && retryAfterMs > 0 ? retryAfterMs : 0;
|
|
13071
12596
|
this.gapMs = Math.min(this.maxGapMs, Math.max(doubled, Math.min(this.maxGapMs, asked)));
|
|
13072
12597
|
}
|
|
13073
12598
|
}
|
|
13074
12599
|
|
|
13075
|
-
//
|
|
12600
|
+
// ../core/src/providers/free-catalog-fetch.ts
|
|
13076
12601
|
var MAX_BYTES = 8 * 1024 * 1024;
|
|
13077
12602
|
async function boundedJson(fetchImpl, url, signal) {
|
|
13078
12603
|
const response = await fetchImpl(url, { signal, redirect: "error", headers: { accept: "application/json" } });
|
|
@@ -13136,7 +12661,7 @@ async function fetchFreeCatalog(options = {}) {
|
|
|
13136
12661
|
}
|
|
13137
12662
|
}
|
|
13138
12663
|
|
|
13139
|
-
//
|
|
12664
|
+
// ../core/src/providers/free-install.ts
|
|
13140
12665
|
import { promises as fs12 } from "node:fs";
|
|
13141
12666
|
import path17 from "node:path";
|
|
13142
12667
|
var FREE_INSTALL_HEADER = "x-archymedes-install";
|
|
@@ -13314,7 +12839,7 @@ class FreeInstallToken {
|
|
|
13314
12839
|
}
|
|
13315
12840
|
}
|
|
13316
12841
|
|
|
13317
|
-
//
|
|
12842
|
+
// ../core/src/providers/free-errors.ts
|
|
13318
12843
|
var OPENROUTER_PRIVACY_SETTINGS_URL = "https://openrouter.ai/settings/privacy";
|
|
13319
12844
|
var OPENROUTER_KEYS_URL = "https://openrouter.ai/keys";
|
|
13320
12845
|
var OPENROUTER_CREDITS_URL = "https://openrouter.ai/settings/credits";
|
|
@@ -13390,7 +12915,7 @@ function describeFreeFailure(input) {
|
|
|
13390
12915
|
return { message, retryable: transient, ...retryAfterMs2 ? { retryAfterMs: retryAfterMs2 } : {} };
|
|
13391
12916
|
}
|
|
13392
12917
|
|
|
13393
|
-
//
|
|
12918
|
+
// ../core/src/providers/free-health.ts
|
|
13394
12919
|
import { promises as fs13 } from "node:fs";
|
|
13395
12920
|
import path18 from "node:path";
|
|
13396
12921
|
var FREE_HEALTH_WINDOW_MS = 7 * 24 * 60 * 60 * 1000;
|
|
@@ -13443,7 +12968,7 @@ function recordFreeOutcome(records, id, outcome, now) {
|
|
|
13443
12968
|
return Object.fromEntries(newest);
|
|
13444
12969
|
}
|
|
13445
12970
|
function orderByFreeHealth(models, records, now) {
|
|
13446
|
-
return models.map((model, index) => ({ model, index, score: healthScore(records[model.id], now) })).sort((a, b) => b.score - a.score || a.index - b.index).map(({ model }) => model);
|
|
12971
|
+
return models.map((model, index) => ({ model, index, small: isSmallModel(model.id), score: healthScore(records[model.id], now) })).sort((a, b) => Number(a.small) - Number(b.small) || b.score - a.score || a.index - b.index).map(({ model }) => model);
|
|
13447
12972
|
}
|
|
13448
12973
|
function fileFreeHealthStore(file) {
|
|
13449
12974
|
return {
|
|
@@ -13499,7 +13024,7 @@ class FreeHealthTracker {
|
|
|
13499
13024
|
}
|
|
13500
13025
|
}
|
|
13501
13026
|
|
|
13502
|
-
//
|
|
13027
|
+
// ../core/src/providers/openrouter-key-info.ts
|
|
13503
13028
|
var OPENROUTER_KEY_URL = `${FREE_BASE_URL}/key`;
|
|
13504
13029
|
var OPENROUTER_KEY_INFO_TTL_MS = 60000;
|
|
13505
13030
|
var KEY_INFO_TIMEOUT_MS = 5000;
|
|
@@ -13602,7 +13127,7 @@ function nextUtcMidnight(now) {
|
|
|
13602
13127
|
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + 1)).toISOString();
|
|
13603
13128
|
}
|
|
13604
13129
|
|
|
13605
|
-
//
|
|
13130
|
+
// ../core/src/providers/tool-call-repair.ts
|
|
13606
13131
|
function isObject(value) {
|
|
13607
13132
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13608
13133
|
}
|
|
@@ -13712,7 +13237,7 @@ function repairToolCalls(calls) {
|
|
|
13712
13237
|
});
|
|
13713
13238
|
}
|
|
13714
13239
|
|
|
13715
|
-
//
|
|
13240
|
+
// ../core/src/providers/free-agent.ts
|
|
13716
13241
|
var RETRYABLE_UPSTREAM_TYPES = new Set(["upstream_timeout", "upstream_idle_timeout", "upstream_unreachable", "upstream_stream_failed"]);
|
|
13717
13242
|
function freeFailureStatus(error) {
|
|
13718
13243
|
const record2 = error;
|
|
@@ -13730,6 +13255,12 @@ function isTransportFailure(error) {
|
|
|
13730
13255
|
const name = error?.name;
|
|
13731
13256
|
return error instanceof APIConnectionError || name === "APIConnectionError" || name === "APIConnectionTimeoutError" || error instanceof TypeError || Boolean(error?.cause);
|
|
13732
13257
|
}
|
|
13258
|
+
function openRouterEffort(effort) {
|
|
13259
|
+
if (!effort)
|
|
13260
|
+
return;
|
|
13261
|
+
return effort === "xhigh" || effort === "max" ? "high" : effort;
|
|
13262
|
+
}
|
|
13263
|
+
var FREE_REQUESTS_PER_MINUTE = 20;
|
|
13733
13264
|
var MAX_ROUTER_ATTEMPTS = 4;
|
|
13734
13265
|
var CATALOG_TIMEOUT_MS = 15000;
|
|
13735
13266
|
var FREE_CANDIDATE_FIRST_BYTE_TIMEOUT_MS = 45000;
|
|
@@ -13778,7 +13309,7 @@ class FreeAgentTurnProvider {
|
|
|
13778
13309
|
this.options = options;
|
|
13779
13310
|
this.dependencies = dependencies;
|
|
13780
13311
|
this.selection = { provider: "free", model: options.model };
|
|
13781
|
-
this.pacer = dependencies.pacer ?? new RequestPacer;
|
|
13312
|
+
this.pacer = dependencies.pacer ?? new RequestPacer({ windowCap: FREE_REQUESTS_PER_MINUTE });
|
|
13782
13313
|
this.tokenSaver = options.tokenSaver ?? true;
|
|
13783
13314
|
const usage = dependencies.usage === undefined ? dependencies.call || dependencies.catalog ? undefined : new FreeUsageMeter(fileFreeUsageStore(freeUsageFile(process.env)), dependencies.now) : dependencies.usage ?? undefined;
|
|
13784
13315
|
if (usage)
|
|
@@ -13839,7 +13370,9 @@ class FreeAgentTurnProvider {
|
|
|
13839
13370
|
}
|
|
13840
13371
|
const eligible = this.catalog.models.filter((model) => model.eligible && isFreeModelId(model.id));
|
|
13841
13372
|
const selected = eligible.find((model) => model.id === this.options.model);
|
|
13842
|
-
const
|
|
13373
|
+
const routable = eligible.filter((model) => model.id !== FREE_ROUTER);
|
|
13374
|
+
const capable = routable.filter((model) => !isSmallModel(model.id));
|
|
13375
|
+
const candidates = this.options.model === FREE_ROUTER ? capable.length > 0 ? capable : routable : selected ? [selected] : [];
|
|
13843
13376
|
if (!candidates.length)
|
|
13844
13377
|
throw new FreeAccessError("No eligible free tool model is available. Run /models refresh or try again later.");
|
|
13845
13378
|
const messages = toWireMessages(request.messages);
|
|
@@ -13944,6 +13477,7 @@ class FreeAgentTurnProvider {
|
|
|
13944
13477
|
messages: withOpenRouterCacheControl(messages, model),
|
|
13945
13478
|
max_tokens: output,
|
|
13946
13479
|
...request.tools.length ? { tools: request.tools.map((tool) => ({ type: "function", function: { name: tool.name, description: tool.description, parameters: tool.inputSchema } })) } : {},
|
|
13480
|
+
...openRouterEffort(request.effort) ? { reasoning: { effort: openRouterEffort(request.effort) } } : {},
|
|
13947
13481
|
provider: { require_parameters: true, max_price: { prompt: 0, completion: 0 }, allow_fallbacks: false },
|
|
13948
13482
|
stream: true,
|
|
13949
13483
|
stream_options: { include_usage: true }
|
|
@@ -13978,7 +13512,7 @@ class FreeAgentTurnProvider {
|
|
|
13978
13512
|
}
|
|
13979
13513
|
}
|
|
13980
13514
|
|
|
13981
|
-
//
|
|
13515
|
+
// ../core/src/providers/openrouter-agent.ts
|
|
13982
13516
|
var OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
|
|
13983
13517
|
|
|
13984
13518
|
class OpenRouterAgentTurnProvider {
|
|
@@ -14027,7 +13561,7 @@ function withHint(error) {
|
|
|
14027
13561
|
return wrapped;
|
|
14028
13562
|
}
|
|
14029
13563
|
|
|
14030
|
-
//
|
|
13564
|
+
// ../core/src/providers/agent-matrix.ts
|
|
14031
13565
|
var OPENAI_COMPATIBLE_BASE_URL = {
|
|
14032
13566
|
google: "https://generativelanguage.googleapis.com/v1beta/openai/",
|
|
14033
13567
|
xai: "https://api.x.ai/v1",
|
|
@@ -14192,7 +13726,7 @@ function describeProviders(environment) {
|
|
|
14192
13726
|
}
|
|
14193
13727
|
var PRICE_ENVIRONMENT_HINT = "MODEL_INPUT_PER_MILLION, MODEL_OUTPUT_PER_MILLION (and optionally MODEL_CACHED_INPUT_PER_MILLION, MODEL_PRICE_CURRENCY, MODEL_PRICE_MODEL)";
|
|
14194
13728
|
|
|
14195
|
-
//
|
|
13729
|
+
// src/app/session-provider.ts
|
|
14196
13730
|
async function resolveSessionProvider(environment, options) {
|
|
14197
13731
|
if (options.provider || !options.resume)
|
|
14198
13732
|
return resolveProvider(environment, options);
|
|
@@ -14201,12 +13735,12 @@ async function resolveSessionProvider(environment, options) {
|
|
|
14201
13735
|
return resolveProvider(environment, selection?.provider === "free" ? { provider: "free", model: options.model ?? selection.model } : options);
|
|
14202
13736
|
}
|
|
14203
13737
|
|
|
14204
|
-
//
|
|
13738
|
+
// src/platform/settings.ts
|
|
14205
13739
|
import { promises as fs15 } from "node:fs";
|
|
14206
13740
|
import os4 from "node:os";
|
|
14207
13741
|
import path20 from "node:path";
|
|
14208
13742
|
|
|
14209
|
-
//
|
|
13743
|
+
// src/platform/i18n.ts
|
|
14210
13744
|
var CONTROL_LANGUAGES = {
|
|
14211
13745
|
en: "English",
|
|
14212
13746
|
zh: "中文 (Mandarin)",
|
|
@@ -14673,11 +14207,11 @@ function t(language, key) {
|
|
|
14673
14207
|
return MESSAGES[key][language] ?? MESSAGES[key].en;
|
|
14674
14208
|
}
|
|
14675
14209
|
|
|
14676
|
-
//
|
|
14210
|
+
// src/platform/local-currency.ts
|
|
14677
14211
|
import { promises as fs14 } from "node:fs";
|
|
14678
14212
|
import path19 from "node:path";
|
|
14679
14213
|
|
|
14680
|
-
//
|
|
14214
|
+
// src/platform/endpoints.ts
|
|
14681
14215
|
var FX_ENDPOINTS = [
|
|
14682
14216
|
"https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies",
|
|
14683
14217
|
"https://latest.currency-api.pages.dev/v1/currencies"
|
|
@@ -14721,7 +14255,7 @@ function hostOf(url) {
|
|
|
14721
14255
|
}
|
|
14722
14256
|
}
|
|
14723
14257
|
|
|
14724
|
-
//
|
|
14258
|
+
// src/platform/network.ts
|
|
14725
14259
|
var CODES = {
|
|
14726
14260
|
dns: ["ENOTFOUND", "EAI_AGAIN", "EAI_NONAME", "EAI_FAIL", "EAI_MEMORY", "EAI_SYSTEM", "DNS_E_NAME_NOT_FOUND", "DNS_E_QUERY_PENDING"],
|
|
14727
14261
|
timeout: ["ETIMEDOUT", "UND_ERR_CONNECT_TIMEOUT", "UND_ERR_HEADERS_TIMEOUT", "UND_ERR_BODY_TIMEOUT", "ERR_SOCKET_CONNECTION_TIMEOUT", "connection_timeout"],
|
|
@@ -14970,7 +14504,7 @@ function classifyNetworkError(error, options = {}) {
|
|
|
14970
14504
|
return null;
|
|
14971
14505
|
}
|
|
14972
14506
|
|
|
14973
|
-
//
|
|
14507
|
+
// src/platform/local-currency.ts
|
|
14974
14508
|
var COUNTRY_CURRENCIES = {
|
|
14975
14509
|
RW: "RWF",
|
|
14976
14510
|
EG: "EGP",
|
|
@@ -15098,7 +14632,7 @@ async function startFxRateLookup(from, to, options) {
|
|
|
15098
14632
|
return { immediate: cached?.rate ?? null, refresh };
|
|
15099
14633
|
}
|
|
15100
14634
|
|
|
15101
|
-
//
|
|
14635
|
+
// src/theme/theme.ts
|
|
15102
14636
|
var BLUEPRINT = `
|
|
15103
14637
|
/* Blueprint navy, chalk-white ink and an amber pencil — the original drafting table. */
|
|
15104
14638
|
@theme blueprint {
|
|
@@ -15400,7 +14934,7 @@ function roleCode(role, palette, depth) {
|
|
|
15400
14934
|
}
|
|
15401
14935
|
var NO_COLOR_PALETTE = buildPalette(findBuiltinTheme(DEFAULT_THEME_NAME) ?? { name: DEFAULT_THEME_NAME, description: "", tokens: DEFAULT_TOKENS }, "none");
|
|
15402
14936
|
|
|
15403
|
-
//
|
|
14937
|
+
// src/platform/settings.ts
|
|
15404
14938
|
var LANGUAGE_NAMES = {
|
|
15405
14939
|
en: "English",
|
|
15406
14940
|
zh: "中文",
|
|
@@ -15504,6 +15038,13 @@ var AUTOSAVE_CHOICES = [
|
|
|
15504
15038
|
{ value: "off", label: "Off — save with Ctrl+S (default)" },
|
|
15505
15039
|
{ value: "on", label: "On — save a second after you stop typing" }
|
|
15506
15040
|
];
|
|
15041
|
+
var REASONING_CHOICES = [
|
|
15042
|
+
{ value: "auto", label: "Auto (experimental) — lower the effort on routine steps, leave hard ones to the model" },
|
|
15043
|
+
{ value: "minimal", label: "Minimal — never think more than needed" },
|
|
15044
|
+
{ value: "low", label: "Low" },
|
|
15045
|
+
{ value: "medium", label: "Medium" },
|
|
15046
|
+
{ value: "high", label: "High — slowest" }
|
|
15047
|
+
];
|
|
15507
15048
|
var PROVIDER_CHOICES = PROVIDER_IDS.map((id) => ({ value: id, label: PROVIDER_INFO[id].label }));
|
|
15508
15049
|
var SETTING_FIELDS = [
|
|
15509
15050
|
{ key: "ARCHYMEDES_THEME", label: "Theme — colours for the whole CLI (/theme <name> also saves it)", choices: THEME_CHOICES, section: "Appearance" },
|
|
@@ -15511,6 +15052,7 @@ var SETTING_FIELDS = [
|
|
|
15511
15052
|
{ key: "ARCHYMEDES_CODE_LINE_NUMBERS", label: "Line numbers in code blocks", choices: SHOW_HIDE_CHOICES },
|
|
15512
15053
|
{ key: "ARCHYMEDES_SIMPLE", label: "Simple mode — quiet start, short help", choices: SIMPLE_CHOICES },
|
|
15513
15054
|
{ key: "ARCHYMEDES_LANGUAGE", label: "Control language", choices: LANGUAGE_CHOICES },
|
|
15055
|
+
{ key: "ARCHYMEDES_REASONING", label: "Reasoning effort — clear it to leave each model at its own default", choices: REASONING_CHOICES },
|
|
15514
15056
|
{ key: "ARCHYMEDES_RESUME", label: "Continue your last chat at startup", choices: RESUME_CHOICES, section: "Behaviour" },
|
|
15515
15057
|
{ key: "ARCHYMEDES_EDITOR_AUTOSAVE", label: "Auto-save in /edit", choices: AUTOSAVE_CHOICES },
|
|
15516
15058
|
{ key: "ARCHYMEDES_SUGGEST_MODEL", label: "Ask the model for extra suggestions (a small extra call per turn)", choices: ON_OFF_CHOICES },
|
|
@@ -15655,7 +15197,8 @@ var ENUM_SETTINGS = {
|
|
|
15655
15197
|
ARCHYMEDES_RESUME: ["ask", "always", "never"],
|
|
15656
15198
|
ARCHYMEDES_EDITOR_AUTOSAVE: ["on", "off"],
|
|
15657
15199
|
ARCHYMEDES_SUGGEST_MODEL: ["on", "off"],
|
|
15658
|
-
ARCHYMEDES_AUTO_UPDATE: ["install", "check", "off"]
|
|
15200
|
+
ARCHYMEDES_AUTO_UPDATE: ["install", "check", "off"],
|
|
15201
|
+
ARCHYMEDES_REASONING: ["auto", "minimal", "low", "medium", "high"]
|
|
15659
15202
|
};
|
|
15660
15203
|
var SETTING_CANCELLED = "\x00cancelled";
|
|
15661
15204
|
function validateSetting(key, raw) {
|
|
@@ -15892,7 +15435,7 @@ Archymedes ${controlLabel(language, "settings")}
|
|
|
15892
15435
|
}
|
|
15893
15436
|
}
|
|
15894
15437
|
|
|
15895
|
-
//
|
|
15438
|
+
// src/app/free-setup.ts
|
|
15896
15439
|
var OPENROUTER_KEYS_URL2 = "https://openrouter.ai/keys";
|
|
15897
15440
|
var FREE_PRIVACY_NOTICE = "Free models may log your prompts and code; don't send secrets. Use a paid provider for private code.";
|
|
15898
15441
|
function needsFreePrivacyNotice(environment) {
|
|
@@ -15911,70 +15454,11 @@ async function showFreePrivacyNoticeOnce(options) {
|
|
|
15911
15454
|
return next;
|
|
15912
15455
|
}
|
|
15913
15456
|
|
|
15914
|
-
//
|
|
15915
|
-
var KEY_URLS = {
|
|
15916
|
-
free: OPENROUTER_KEYS_URL2,
|
|
15917
|
-
openrouter: OPENROUTER_KEYS_URL2,
|
|
15918
|
-
anthropic: "https://console.anthropic.com/settings/keys",
|
|
15919
|
-
openai: "https://platform.openai.com/api-keys",
|
|
15920
|
-
google: "https://aistudio.google.com/apikey",
|
|
15921
|
-
xai: "https://console.x.ai",
|
|
15922
|
-
deepseek: "https://platform.deepseek.com/api_keys",
|
|
15923
|
-
mistral: "https://console.mistral.ai/api-keys",
|
|
15924
|
-
groq: "https://console.groq.com/keys"
|
|
15925
|
-
};
|
|
15926
|
-
var ORDER = ["free", ...PROVIDER_IDS.filter((id) => id !== "free")];
|
|
15927
|
-
function setupStatus(environment, requested = {}) {
|
|
15928
|
-
const resolved = resolveProvider(environment, requested);
|
|
15929
|
-
const providers = ORDER.map((id) => {
|
|
15930
|
-
const info = PROVIDER_INFO[id];
|
|
15931
|
-
const keyOnly = info.requires.length === 1 && SETTING_FIELDS.some((field) => field.key === info.requires[0]);
|
|
15932
|
-
return {
|
|
15933
|
-
id,
|
|
15934
|
-
label: info.label,
|
|
15935
|
-
...keyOnly ? { keyVariable: info.requires[0] } : {},
|
|
15936
|
-
...KEY_URLS[id] ? { keyUrl: KEY_URLS[id] } : {},
|
|
15937
|
-
configured: missingRequirements(id, environment).length === 0
|
|
15938
|
-
};
|
|
15939
|
-
});
|
|
15940
|
-
return "error" in resolved ? { configured: false, reason: resolved.error, providers } : { configured: true, providers };
|
|
15941
|
-
}
|
|
15942
|
-
async function saveSetup(params, deps) {
|
|
15943
|
-
const provider = typeof params.provider === "string" ? params.provider : "";
|
|
15944
|
-
const raw = typeof params.key === "string" ? params.key.trim() : "";
|
|
15945
|
-
if (!isProviderId(provider))
|
|
15946
|
-
return { ok: false, error: `Unknown provider "${provider}".` };
|
|
15947
|
-
const target = setupStatus(deps.environment).providers.find((candidate) => candidate.id === provider);
|
|
15948
|
-
if (!target?.keyVariable)
|
|
15949
|
-
return { ok: false, error: `${PROVIDER_INFO[provider].label} needs more than a key; run archymedes settings.` };
|
|
15950
|
-
if (!raw)
|
|
15951
|
-
return { ok: false, error: "The key is empty." };
|
|
15952
|
-
let key;
|
|
15953
|
-
try {
|
|
15954
|
-
key = validateSetting(target.keyVariable, raw);
|
|
15955
|
-
} catch (error) {
|
|
15956
|
-
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
15957
|
-
}
|
|
15958
|
-
let note;
|
|
15959
|
-
if (provider === "free" || provider === "openrouter") {
|
|
15960
|
-
const result = await (deps.checkOpenRouter ?? ((value) => checkOpenRouterKey(value)))(key);
|
|
15961
|
-
if (!result.ok && result.reason === "invalid")
|
|
15962
|
-
return { ok: false, error: describeKeyCheckFailure(result) };
|
|
15963
|
-
if (!result.ok)
|
|
15964
|
-
note = `${describeKeyCheckFailure(result)} Saved anyway; the first request will confirm it.`;
|
|
15965
|
-
}
|
|
15966
|
-
const current = await (deps.load ?? (() => loadSettings(deps.processEnvironment)))();
|
|
15967
|
-
const settings = { ...current, [target.keyVariable]: key, ARCHYMEDES_PROVIDER: provider };
|
|
15968
|
-
const file = await (deps.save ?? ((value) => saveSettings(value, deps.processEnvironment)))(settings);
|
|
15969
|
-
Object.assign(deps.environment, mergedEnvironment(settings, deps.processEnvironment));
|
|
15970
|
-
return { ok: true, file, ...note ? { note } : {} };
|
|
15971
|
-
}
|
|
15972
|
-
|
|
15973
|
-
// packages/core/src/providers/model-fetch.ts
|
|
15457
|
+
// ../core/src/providers/model-fetch.ts
|
|
15974
15458
|
import { promises as fs16 } from "node:fs";
|
|
15975
15459
|
import path21 from "node:path";
|
|
15976
15460
|
|
|
15977
|
-
//
|
|
15461
|
+
// ../core/src/providers/model-list.ts
|
|
15978
15462
|
function modelsUrl(base) {
|
|
15979
15463
|
const trimmed = base.replace(/\/+$/, "");
|
|
15980
15464
|
return trimmed.endsWith("/v1") ? `${trimmed}/models` : `${trimmed}/v1/models`;
|
|
@@ -16084,7 +15568,7 @@ function mergeModelLists(known, live) {
|
|
|
16084
15568
|
const added = live.filter((model) => !seen.has(model)).sort();
|
|
16085
15569
|
return [...known, ...added];
|
|
16086
15570
|
}
|
|
16087
|
-
//
|
|
15571
|
+
// ../core/src/providers/model-fetch.ts
|
|
16088
15572
|
async function fetchProviderModels(provider, environment, fetchImpl, timeoutMs = 4000) {
|
|
16089
15573
|
if (provider === "free") {
|
|
16090
15574
|
try {
|
|
@@ -16172,7 +15656,206 @@ function fetchableProviders(environment, providers) {
|
|
|
16172
15656
|
return providers.filter((provider) => provider !== "archymedes-cloud" && missingRequirements(provider, environment).length === 0);
|
|
16173
15657
|
}
|
|
16174
15658
|
|
|
16175
|
-
//
|
|
15659
|
+
// src/app/acp-connect.ts
|
|
15660
|
+
var DEFAULT_BASE_URLS = {
|
|
15661
|
+
anthropic: "https://api.anthropic.com",
|
|
15662
|
+
openai: "https://api.openai.com/v1",
|
|
15663
|
+
openrouter: "https://openrouter.ai/api/v1",
|
|
15664
|
+
google: "https://generativelanguage.googleapis.com/v1beta/openai",
|
|
15665
|
+
xai: "https://api.x.ai/v1",
|
|
15666
|
+
deepseek: "https://api.deepseek.com/v1",
|
|
15667
|
+
mistral: "https://api.mistral.ai/v1",
|
|
15668
|
+
groq: "https://api.groq.com/openai/v1",
|
|
15669
|
+
ollama: "http://localhost:11434/v1"
|
|
15670
|
+
};
|
|
15671
|
+
var fieldSpec = (key) => SETTING_FIELDS.find((field) => field.key === key);
|
|
15672
|
+
function providerFields(provider, environment) {
|
|
15673
|
+
const required = PROVIDER_INFO[provider].requires;
|
|
15674
|
+
const baseUrl = provider === "free" ? undefined : `${providerEnvPrefix(provider)}_BASE_URL`;
|
|
15675
|
+
const keys = [...required, ...baseUrl && !required.includes(baseUrl) && fieldSpec(baseUrl) ? [baseUrl] : []];
|
|
15676
|
+
return keys.flatMap((key) => {
|
|
15677
|
+
const spec = fieldSpec(key);
|
|
15678
|
+
if (!spec)
|
|
15679
|
+
return [];
|
|
15680
|
+
const secret = "secret" in spec && spec.secret === true;
|
|
15681
|
+
const url = "url" in spec && spec.url === true;
|
|
15682
|
+
const value = environment[key]?.trim() ?? "";
|
|
15683
|
+
const placeholder = url ? DEFAULT_BASE_URLS[provider] ?? "https://…/v1" : undefined;
|
|
15684
|
+
return [{
|
|
15685
|
+
key: spec.key,
|
|
15686
|
+
label: spec.label,
|
|
15687
|
+
kind: secret ? "secret" : url ? "url" : "text",
|
|
15688
|
+
required: required.includes(key),
|
|
15689
|
+
isSet: value !== "",
|
|
15690
|
+
value: secret && value ? maskSetting(value) : value,
|
|
15691
|
+
...placeholder ? { placeholder } : {}
|
|
15692
|
+
}];
|
|
15693
|
+
});
|
|
15694
|
+
}
|
|
15695
|
+
var refused = (error) => /\b40[13]\b/.test(error ?? "");
|
|
15696
|
+
async function connectProvider(params, deps) {
|
|
15697
|
+
const provider = typeof params.provider === "string" ? params.provider : "";
|
|
15698
|
+
if (!isProviderId(provider))
|
|
15699
|
+
return { ok: false, error: `Unknown provider "${provider}".` };
|
|
15700
|
+
const label3 = PROVIDER_INFO[provider].label;
|
|
15701
|
+
const values = params.values && typeof params.values === "object" ? params.values : {};
|
|
15702
|
+
const fields = providerFields(provider, deps.environment);
|
|
15703
|
+
const current = await (deps.load ?? (() => loadSettings(deps.processEnvironment)))();
|
|
15704
|
+
const next = { ...current };
|
|
15705
|
+
for (const field of fields) {
|
|
15706
|
+
const raw = typeof values[field.key] === "string" ? values[field.key].trim() : undefined;
|
|
15707
|
+
if (raw === undefined || raw === "") {
|
|
15708
|
+
if (field.kind === "url" && raw === "")
|
|
15709
|
+
delete next[field.key];
|
|
15710
|
+
continue;
|
|
15711
|
+
}
|
|
15712
|
+
try {
|
|
15713
|
+
next[field.key] = validateSetting(field.key, raw);
|
|
15714
|
+
} catch (error) {
|
|
15715
|
+
return { ok: false, field: field.key, error: error instanceof Error ? error.message : String(error) };
|
|
15716
|
+
}
|
|
15717
|
+
}
|
|
15718
|
+
const candidate = mergedEnvironment(next, deps.processEnvironment);
|
|
15719
|
+
const missing = missingRequirements(provider, candidate);
|
|
15720
|
+
if (missing.length > 0)
|
|
15721
|
+
return { ok: false, field: missing[0], error: `${label3} still needs ${missing.join(" and ")}.` };
|
|
15722
|
+
const keyField = fields.find((field) => field.kind === "secret")?.key;
|
|
15723
|
+
let note;
|
|
15724
|
+
if ((provider === "free" || provider === "openrouter") && candidate.OPENROUTER_API_KEY) {
|
|
15725
|
+
const check = await (deps.checkOpenRouter ?? ((value) => checkOpenRouterKey(value)))(candidate.OPENROUTER_API_KEY);
|
|
15726
|
+
if (!check.ok && check.reason === "invalid")
|
|
15727
|
+
return { ok: false, field: keyField, error: describeKeyCheckFailure(check) };
|
|
15728
|
+
if (!check.ok)
|
|
15729
|
+
note = `${describeKeyCheckFailure(check)} Saved anyway; the first request will confirm it.`;
|
|
15730
|
+
}
|
|
15731
|
+
const fetchImpl = deps.fetchImpl ?? globalThis.fetch;
|
|
15732
|
+
const listed = await fetchProviderModels(provider, candidate, fetchImpl, 8000);
|
|
15733
|
+
if (listed.models.length === 0 && refused(listed.error)) {
|
|
15734
|
+
return { ok: false, field: keyField, error: `${label3} refused the key (${listed.error}). Check it and paste it again.` };
|
|
15735
|
+
}
|
|
15736
|
+
if (listed.models.length === 0) {
|
|
15737
|
+
note = note ?? `Could not list ${label3}'s models (${listed.error ?? "none returned"}). Saved; check the base URL if this persists.`;
|
|
15738
|
+
}
|
|
15739
|
+
const file = await (deps.save ?? ((value) => saveSettings(value, deps.processEnvironment)))(next);
|
|
15740
|
+
Object.assign(deps.environment, mergedEnvironment(next, deps.processEnvironment));
|
|
15741
|
+
if (listed.models.length > 0)
|
|
15742
|
+
await rememberModels(provider, listed.models, deps.environment);
|
|
15743
|
+
return { ok: true, file, models: listed.models, ...note ? { note } : {} };
|
|
15744
|
+
}
|
|
15745
|
+
async function providerModels(params, deps) {
|
|
15746
|
+
const provider = typeof params.provider === "string" ? params.provider : "";
|
|
15747
|
+
if (!isProviderId(provider))
|
|
15748
|
+
return { models: [], error: `Unknown provider "${provider}".` };
|
|
15749
|
+
const fetchImpl = deps.fetchImpl ?? globalThis.fetch;
|
|
15750
|
+
const listed = await fetchProviderModels(provider, deps.environment, fetchImpl, 8000);
|
|
15751
|
+
if (listed.models.length > 0)
|
|
15752
|
+
await rememberModels(provider, listed.models, deps.environment);
|
|
15753
|
+
return { models: listed.models, ...listed.error ? { error: listed.error } : {} };
|
|
15754
|
+
}
|
|
15755
|
+
async function rememberModels(provider, models, environment) {
|
|
15756
|
+
try {
|
|
15757
|
+
const cache = await readModelCache(environment);
|
|
15758
|
+
await writeModelCache(environment, {
|
|
15759
|
+
fetchedAt: cache?.fetchedAt ?? Date.now(),
|
|
15760
|
+
...cache?.freeCatalog ? { freeCatalog: cache.freeCatalog } : {},
|
|
15761
|
+
models: { ...cache?.models ?? {}, [provider]: models }
|
|
15762
|
+
});
|
|
15763
|
+
} catch {}
|
|
15764
|
+
}
|
|
15765
|
+
async function rememberModel(params, deps) {
|
|
15766
|
+
const provider = typeof params.provider === "string" ? params.provider : "";
|
|
15767
|
+
const model = typeof params.model === "string" ? params.model.trim() : "";
|
|
15768
|
+
if (!isProviderId(provider) || !model)
|
|
15769
|
+
return { ok: false, error: "A provider and a model are needed." };
|
|
15770
|
+
const key = `${providerEnvPrefix(provider)}_MODEL`;
|
|
15771
|
+
if (!fieldSpec(key))
|
|
15772
|
+
return { ok: true };
|
|
15773
|
+
let value;
|
|
15774
|
+
try {
|
|
15775
|
+
value = validateSetting(key, model);
|
|
15776
|
+
} catch (error) {
|
|
15777
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
15778
|
+
}
|
|
15779
|
+
const current = await (deps.load ?? (() => loadSettings(deps.processEnvironment)))();
|
|
15780
|
+
const next = { ...current, [key]: value };
|
|
15781
|
+
await (deps.save ?? ((settings) => saveSettings(settings, deps.processEnvironment)))(next);
|
|
15782
|
+
Object.assign(deps.environment, mergedEnvironment(next, deps.processEnvironment));
|
|
15783
|
+
return { ok: true };
|
|
15784
|
+
}
|
|
15785
|
+
|
|
15786
|
+
// src/app/acp-setup.ts
|
|
15787
|
+
var KEY_URLS = {
|
|
15788
|
+
free: OPENROUTER_KEYS_URL2,
|
|
15789
|
+
openrouter: OPENROUTER_KEYS_URL2,
|
|
15790
|
+
anthropic: "https://console.anthropic.com/settings/keys",
|
|
15791
|
+
openai: "https://platform.openai.com/api-keys",
|
|
15792
|
+
google: "https://aistudio.google.com/apikey",
|
|
15793
|
+
xai: "https://console.x.ai",
|
|
15794
|
+
deepseek: "https://platform.deepseek.com/api_keys",
|
|
15795
|
+
mistral: "https://console.mistral.ai/api-keys",
|
|
15796
|
+
groq: "https://console.groq.com/keys"
|
|
15797
|
+
};
|
|
15798
|
+
var ORDER = ["free", ...PROVIDER_IDS.filter((id) => id !== "free")];
|
|
15799
|
+
function setupStatus(environment, requested = {}) {
|
|
15800
|
+
const resolved = resolveProvider(environment, requested);
|
|
15801
|
+
const providers = ORDER.map((id) => {
|
|
15802
|
+
const info = PROVIDER_INFO[id];
|
|
15803
|
+
const keyOnly = info.requires.length === 1 && SETTING_FIELDS.some((field) => field.key === info.requires[0]);
|
|
15804
|
+
return {
|
|
15805
|
+
id,
|
|
15806
|
+
label: info.label,
|
|
15807
|
+
...keyOnly ? { keyVariable: info.requires[0] } : {},
|
|
15808
|
+
...KEY_URLS[id] ? { keyUrl: KEY_URLS[id] } : {},
|
|
15809
|
+
configured: missingRequirements(id, environment).length === 0
|
|
15810
|
+
};
|
|
15811
|
+
});
|
|
15812
|
+
return "error" in resolved ? { configured: false, reason: resolved.error, providers } : { configured: true, providers };
|
|
15813
|
+
}
|
|
15814
|
+
async function saveSetup(params, deps) {
|
|
15815
|
+
const provider = typeof params.provider === "string" ? params.provider : "";
|
|
15816
|
+
const raw = typeof params.key === "string" ? params.key.trim() : "";
|
|
15817
|
+
if (!isProviderId(provider))
|
|
15818
|
+
return { ok: false, error: `Unknown provider "${provider}".` };
|
|
15819
|
+
const target = setupStatus(deps.environment).providers.find((candidate) => candidate.id === provider);
|
|
15820
|
+
if (!target?.keyVariable)
|
|
15821
|
+
return { ok: false, error: `${PROVIDER_INFO[provider].label} needs more than a key; run archymedes settings.` };
|
|
15822
|
+
if (!raw)
|
|
15823
|
+
return { ok: false, error: "The key is empty." };
|
|
15824
|
+
let key;
|
|
15825
|
+
try {
|
|
15826
|
+
key = validateSetting(target.keyVariable, raw);
|
|
15827
|
+
} catch (error) {
|
|
15828
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
15829
|
+
}
|
|
15830
|
+
let note;
|
|
15831
|
+
if (provider === "free" || provider === "openrouter") {
|
|
15832
|
+
const result = await (deps.checkOpenRouter ?? ((value) => checkOpenRouterKey(value)))(key);
|
|
15833
|
+
if (!result.ok && result.reason === "invalid")
|
|
15834
|
+
return { ok: false, error: describeKeyCheckFailure(result) };
|
|
15835
|
+
if (!result.ok)
|
|
15836
|
+
note = `${describeKeyCheckFailure(result)} Saved anyway; the first request will confirm it.`;
|
|
15837
|
+
}
|
|
15838
|
+
const current = await (deps.load ?? (() => loadSettings(deps.processEnvironment)))();
|
|
15839
|
+
const settings = { ...current, [target.keyVariable]: key, ARCHYMEDES_PROVIDER: provider };
|
|
15840
|
+
const file = await (deps.save ?? ((value) => saveSettings(value, deps.processEnvironment)))(settings);
|
|
15841
|
+
Object.assign(deps.environment, mergedEnvironment(settings, deps.processEnvironment));
|
|
15842
|
+
return { ok: true, file, ...note ? { note } : {} };
|
|
15843
|
+
}
|
|
15844
|
+
function providerOverview(environment) {
|
|
15845
|
+
const preferred = environment.ARCHYMEDES_PROVIDER?.trim().toLowerCase();
|
|
15846
|
+
return setupStatus(environment).providers.map((provider) => {
|
|
15847
|
+
const info = PROVIDER_INFO[provider.id];
|
|
15848
|
+
return {
|
|
15849
|
+
...provider,
|
|
15850
|
+
missing: missingRequirements(provider.id, environment),
|
|
15851
|
+
model: environment[`${providerEnvPrefix(provider.id)}_MODEL`]?.trim() || info.defaultModel,
|
|
15852
|
+
isDefault: preferred === provider.id,
|
|
15853
|
+
fields: providerFields(provider.id, environment)
|
|
15854
|
+
};
|
|
15855
|
+
});
|
|
15856
|
+
}
|
|
15857
|
+
|
|
15858
|
+
// src/session/models.ts
|
|
16176
15859
|
function modelsForProvider(provider, asOf) {
|
|
16177
15860
|
const seen = new Set;
|
|
16178
15861
|
for (const record2 of PRICE_CATALOG) {
|
|
@@ -16196,7 +15879,7 @@ function describePrice(prices, display, convert2) {
|
|
|
16196
15879
|
return `${formatMoney(input)}/${formatMoney(output)} per Mtok`;
|
|
16197
15880
|
}
|
|
16198
15881
|
|
|
16199
|
-
//
|
|
15882
|
+
// src/app/acp-models.ts
|
|
16200
15883
|
var PUBLIC_LISTINGS = ["free", "openrouter"];
|
|
16201
15884
|
async function modelList(environment, params, options = {}) {
|
|
16202
15885
|
const offline = /^(1|true|on|yes)$/i.test(environment.ARCHYMEDES_MODELS_OFFLINE?.trim() ?? "");
|
|
@@ -16239,7 +15922,8 @@ async function modelList(environment, params, options = {}) {
|
|
|
16239
15922
|
price: free ? "free" : prices ? describePrice(prices, prices.currency, (value) => value) : "unpriced",
|
|
16240
15923
|
free,
|
|
16241
15924
|
locked: missing.length > 0,
|
|
16242
|
-
missing
|
|
15925
|
+
missing,
|
|
15926
|
+
small: isSmallModel(model)
|
|
16243
15927
|
};
|
|
16244
15928
|
(choice.locked ? locked : ready).push(choice);
|
|
16245
15929
|
}
|
|
@@ -16247,7 +15931,7 @@ async function modelList(environment, params, options = {}) {
|
|
|
16247
15931
|
return { choices: [...ready, ...locked], unconfigured, errors, providers: PROVIDER_IDS.length };
|
|
16248
15932
|
}
|
|
16249
15933
|
|
|
16250
|
-
//
|
|
15934
|
+
// src/app/acp-commands.ts
|
|
16251
15935
|
async function runSessionCommand(command, argument, session) {
|
|
16252
15936
|
switch (command) {
|
|
16253
15937
|
case "cost":
|
|
@@ -16272,15 +15956,115 @@ async function runSessionCommand(command, argument, session) {
|
|
|
16272
15956
|
const items = session.agent.todos.map((item) => ({ text: item.text, status: item.status }));
|
|
16273
15957
|
return items.length > 0 ? { kind: "todos", items } : { kind: "text", text: "No plan yet." };
|
|
16274
15958
|
}
|
|
15959
|
+
case "memory":
|
|
15960
|
+
return memoryCommand(argument, session.agent.workspaceLabel);
|
|
15961
|
+
case "tools": {
|
|
15962
|
+
const { tools } = await session.agent.inspectTools();
|
|
15963
|
+
const lines = tools.map((tool) => `${tool.name.padEnd(24)} ${tool.requiresApproval ? "asks first " : " "}${tool.description.split(/(?<=\.)\s/)[0]}`);
|
|
15964
|
+
return { kind: "text", text: `${tools.length} tools
|
|
15965
|
+
${lines.join(`
|
|
15966
|
+
`)}` };
|
|
15967
|
+
}
|
|
16275
15968
|
default:
|
|
16276
15969
|
return { kind: "error", text: `Unknown session command "${command}".` };
|
|
16277
15970
|
}
|
|
16278
15971
|
}
|
|
15972
|
+
var MEMORY_KINDS = ["preference", "convention", "decision", "lesson", "fact"];
|
|
15973
|
+
async function memoryCommand(argument, root) {
|
|
15974
|
+
const environment = process.env;
|
|
15975
|
+
const [verb = "", ...rest] = argument.trim().split(/\s+/);
|
|
15976
|
+
try {
|
|
15977
|
+
if (verb === "" || verb === "list") {
|
|
15978
|
+
const entries2 = await loadMemories(root, environment);
|
|
15979
|
+
if (entries2.length === 0)
|
|
15980
|
+
return { kind: "text", text: "Nothing remembered yet. /memory add <text> saves a fact for this project." };
|
|
15981
|
+
return { kind: "text", text: entries2.map((entry) => `${entry.scope === "user" ? "user " : "project"} ${entry.index}. [${entry.kind}${entry.pinned ? ", pinned" : ""}] ${entry.text}`).join(`
|
|
15982
|
+
`) };
|
|
15983
|
+
}
|
|
15984
|
+
if (verb === "add") {
|
|
15985
|
+
const scope = rest[0] === "user" ? "user" : "project";
|
|
15986
|
+
if (rest[0] === "user" || rest[0] === "project")
|
|
15987
|
+
rest.shift();
|
|
15988
|
+
const kind = MEMORY_KINDS.find((candidate) => candidate === rest[0]);
|
|
15989
|
+
if (kind)
|
|
15990
|
+
rest.shift();
|
|
15991
|
+
const change = await addMemory(scope, rest.join(" "), root, environment, kind ? { kind } : {});
|
|
15992
|
+
return { kind: "text", text: change.changed ? `Remembered (${scope}).` : "Already remembered, or nothing to add." };
|
|
15993
|
+
}
|
|
15994
|
+
if (verb === "forget") {
|
|
15995
|
+
const scope = rest[0] === "user" ? "user" : "project";
|
|
15996
|
+
const index = Number(rest[rest.length - 1]);
|
|
15997
|
+
if (!Number.isInteger(index))
|
|
15998
|
+
return { kind: "error", text: "/memory forget [user] <number> — see /memory for the numbers." };
|
|
15999
|
+
const change = await forgetMemory(scope, index, root, environment);
|
|
16000
|
+
return { kind: "text", text: change.removed ? `Forgot: ${change.removed.text}` : `No ${scope} memory numbered ${index}.` };
|
|
16001
|
+
}
|
|
16002
|
+
if (verb === "clear") {
|
|
16003
|
+
const scope = rest[0] === "user" ? "user" : "project";
|
|
16004
|
+
return { kind: "text", text: (await clearMemories(scope, root, environment)).changed ? `Cleared ${scope} memory.` : `${scope} memory was already empty.` };
|
|
16005
|
+
}
|
|
16006
|
+
return { kind: "error", text: `/memory takes list, add <text>, forget <n> or clear — not "${verb}".` };
|
|
16007
|
+
} catch (error) {
|
|
16008
|
+
return { kind: "error", text: error instanceof Error ? error.message : String(error) };
|
|
16009
|
+
}
|
|
16010
|
+
}
|
|
16279
16011
|
|
|
16280
|
-
//
|
|
16012
|
+
// src/app/acp-settings.ts
|
|
16013
|
+
async function listSettings(processEnvironment) {
|
|
16014
|
+
const stored = await loadSettings(processEnvironment);
|
|
16015
|
+
const rows = SETTING_FIELDS.map((field) => {
|
|
16016
|
+
const secret = "secret" in field && field.secret === true;
|
|
16017
|
+
const choices = "choices" in field ? field.choices : undefined;
|
|
16018
|
+
const value = stored[field.key] ?? "";
|
|
16019
|
+
return {
|
|
16020
|
+
key: field.key,
|
|
16021
|
+
label: field.label,
|
|
16022
|
+
section: sectionOf(field.key) ?? "General",
|
|
16023
|
+
kind: secret ? "secret" : choices ? "choice" : "text",
|
|
16024
|
+
...choices ? { choices: choices.map((choice) => ({ value: choice.value, label: choice.label })) } : {},
|
|
16025
|
+
value: secret && value ? maskSetting(value) : value,
|
|
16026
|
+
isSet: value !== "",
|
|
16027
|
+
overriddenByEnvironment: Boolean(processEnvironment[field.key]) && processEnvironment[field.key] !== value
|
|
16028
|
+
};
|
|
16029
|
+
});
|
|
16030
|
+
return { file: settingsFile(processEnvironment), rows };
|
|
16031
|
+
}
|
|
16032
|
+
async function setSetting(params, deps) {
|
|
16033
|
+
const key = typeof params.key === "string" ? params.key : "";
|
|
16034
|
+
const raw = typeof params.value === "string" ? params.value : "";
|
|
16035
|
+
const field = SETTING_FIELDS.find((candidate) => candidate.key === key);
|
|
16036
|
+
if (!field)
|
|
16037
|
+
return { ok: false, error: `No setting named ${key || "(none)"}.` };
|
|
16038
|
+
const current = await loadSettings(deps.processEnvironment);
|
|
16039
|
+
const next = { ...current };
|
|
16040
|
+
let stored = "";
|
|
16041
|
+
if (raw.trim() === "") {
|
|
16042
|
+
delete next[field.key];
|
|
16043
|
+
} else {
|
|
16044
|
+
try {
|
|
16045
|
+
stored = validateSetting(field.key, raw);
|
|
16046
|
+
} catch (error) {
|
|
16047
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
16048
|
+
}
|
|
16049
|
+
next[field.key] = stored;
|
|
16050
|
+
}
|
|
16051
|
+
let file;
|
|
16052
|
+
try {
|
|
16053
|
+
file = await saveSettings(next, deps.processEnvironment);
|
|
16054
|
+
} catch (error) {
|
|
16055
|
+
return { ok: false, error: `Could not save: ${error instanceof Error ? error.message : String(error)}` };
|
|
16056
|
+
}
|
|
16057
|
+
if (raw.trim() === "" && deps.environment[field.key] === current[field.key])
|
|
16058
|
+
delete deps.environment[field.key];
|
|
16059
|
+
Object.assign(deps.environment, mergedEnvironment(next, deps.processEnvironment));
|
|
16060
|
+
const secret = "secret" in field && field.secret === true;
|
|
16061
|
+
return { ok: true, file, value: secret && stored ? maskSetting(stored) : stored, isSet: stored !== "" };
|
|
16062
|
+
}
|
|
16063
|
+
|
|
16064
|
+
// src/app/startup-update.ts
|
|
16281
16065
|
import { spawn as spawn8 } from "node:child_process";
|
|
16282
16066
|
|
|
16283
|
-
//
|
|
16067
|
+
// src/platform/auto-update.ts
|
|
16284
16068
|
import { promises as fs17 } from "node:fs";
|
|
16285
16069
|
import path22 from "node:path";
|
|
16286
16070
|
var AUTO_UPDATE_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
@@ -16393,7 +16177,7 @@ async function runAutoUpdate(options) {
|
|
|
16393
16177
|
return { notice: [], decision };
|
|
16394
16178
|
}
|
|
16395
16179
|
|
|
16396
|
-
//
|
|
16180
|
+
// src/platform/defender-feed-update.ts
|
|
16397
16181
|
var OFFICIAL_DEFENDER_FEED_URL = "https://circuit-archymedes.vercel.app/api/defender-brain/manifest";
|
|
16398
16182
|
var OFFICIAL_DEFENDER_FEED_KEYS = Object.freeze({
|
|
16399
16183
|
"release-2026-01": "MCowBQYDK2VwAyEA4/jb1zd6f+jIPAFja1bPNtroXV8MtAZFrKt5BSY+ngI="
|
|
@@ -16421,12 +16205,12 @@ async function updateDefenderFeed(environment) {
|
|
|
16421
16205
|
});
|
|
16422
16206
|
}
|
|
16423
16207
|
|
|
16424
|
-
//
|
|
16208
|
+
// src/platform/update.ts
|
|
16425
16209
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
16426
16210
|
import { tmpdir } from "node:os";
|
|
16427
16211
|
import { createInterface as createInterface3 } from "node:readline/promises";
|
|
16428
16212
|
|
|
16429
|
-
//
|
|
16213
|
+
// src/catalog/commands.ts
|
|
16430
16214
|
function defineCommands(table) {
|
|
16431
16215
|
return Object.entries(table).map(([name, command]) => ({ name, ...command }));
|
|
16432
16216
|
}
|
|
@@ -16499,7 +16283,7 @@ function renderCommandHelp(language = "en", shortcuts = new Map, options = {}) {
|
|
|
16499
16283
|
`);
|
|
16500
16284
|
}
|
|
16501
16285
|
|
|
16502
|
-
//
|
|
16286
|
+
// src/terminal/keybindings.ts
|
|
16503
16287
|
var FUNCTION_KEY = /^f([1-9]|1[0-2])$/;
|
|
16504
16288
|
var NAMED_KEYS = new Set(["tab", "enter", "escape", "space", "up", "down", "left", "right", "home", "end", "pageup", "pagedown", "backspace", "delete"]);
|
|
16505
16289
|
function isKeyName(value) {
|
|
@@ -16749,10 +16533,10 @@ function escapeCodeTimeoutMs(environment = process.env) {
|
|
|
16749
16533
|
const parsed = raw ? Number(raw) : NaN;
|
|
16750
16534
|
return Number.isInteger(parsed) && parsed >= 10 && parsed <= 2000 ? parsed : DEFAULT_ESCAPE_CODE_TIMEOUT_MS;
|
|
16751
16535
|
}
|
|
16752
|
-
//
|
|
16536
|
+
// package.json
|
|
16753
16537
|
var package_default = {
|
|
16754
16538
|
name: "archymedes-cli",
|
|
16755
|
-
version: "3.
|
|
16539
|
+
version: "3.4.0",
|
|
16756
16540
|
description: "Archymedes CLI — a coding agent that shows its work. Runs against your working tree or an isolated remote sandbox, with guarded approvals, git checkpoints, and exact, measured cost accounting.",
|
|
16757
16541
|
keywords: [
|
|
16758
16542
|
"cli",
|
|
@@ -16798,12 +16582,12 @@ var package_default = {
|
|
|
16798
16582
|
prepublishOnly: "bun run ../../tooling/build/build-packages.ts"
|
|
16799
16583
|
},
|
|
16800
16584
|
optionalDependencies: {
|
|
16801
|
-
"@archymedes/cli-darwin-arm64": "3.
|
|
16802
|
-
"@archymedes/cli-darwin-x64": "3.
|
|
16803
|
-
"@archymedes/cli-linux-arm64": "3.
|
|
16804
|
-
"@archymedes/cli-linux-x64": "3.
|
|
16805
|
-
"@archymedes/cli-win32-arm64": "3.
|
|
16806
|
-
"@archymedes/cli-win32-x64": "3.
|
|
16585
|
+
"@archymedes/cli-darwin-arm64": "3.4.0",
|
|
16586
|
+
"@archymedes/cli-darwin-x64": "3.4.0",
|
|
16587
|
+
"@archymedes/cli-linux-arm64": "3.4.0",
|
|
16588
|
+
"@archymedes/cli-linux-x64": "3.4.0",
|
|
16589
|
+
"@archymedes/cli-win32-arm64": "3.4.0",
|
|
16590
|
+
"@archymedes/cli-win32-x64": "3.4.0",
|
|
16807
16591
|
"@archymedes/state-darwin-arm64": "0.4.0",
|
|
16808
16592
|
"@archymedes/state-darwin-x64": "0.4.0",
|
|
16809
16593
|
"@archymedes/state-linux-arm64-gnu": "0.4.0",
|
|
@@ -16815,7 +16599,7 @@ var package_default = {
|
|
|
16815
16599
|
}
|
|
16816
16600
|
};
|
|
16817
16601
|
|
|
16818
|
-
//
|
|
16602
|
+
// src/platform/update.ts
|
|
16819
16603
|
var ARCHYMEDES_CLI_PACKAGE = "archymedes-cli";
|
|
16820
16604
|
var ARCHYMEDES_CLI_VERSION = package_default.version;
|
|
16821
16605
|
var DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
@@ -17033,7 +16817,7 @@ async function runSelfUpdate(options = {}) {
|
|
|
17033
16817
|
return { status: "updated", currentVersion, latestVersion, code: 0 };
|
|
17034
16818
|
}
|
|
17035
16819
|
|
|
17036
|
-
//
|
|
16820
|
+
// src/text/ansi.ts
|
|
17037
16821
|
var RESET = "\x1B[0m";
|
|
17038
16822
|
var BOLD = "\x1B[1m";
|
|
17039
16823
|
var DIM = "\x1B[2m";
|
|
@@ -17046,7 +16830,7 @@ function paintAll(text, codes, depth) {
|
|
|
17046
16830
|
return depth === "none" || codes.length === 0 ? text : `${codes.join("")}${text}${RESET}`;
|
|
17047
16831
|
}
|
|
17048
16832
|
|
|
17049
|
-
//
|
|
16833
|
+
// src/terminal/output.ts
|
|
17050
16834
|
var terminalStream = {
|
|
17051
16835
|
write(text) {
|
|
17052
16836
|
process.stdout.write(text);
|
|
@@ -17080,7 +16864,7 @@ class OutputRouter {
|
|
|
17080
16864
|
}
|
|
17081
16865
|
}
|
|
17082
16866
|
|
|
17083
|
-
//
|
|
16867
|
+
// src/text/glyphs.ts
|
|
17084
16868
|
var UNICODE_GLYPHS = {
|
|
17085
16869
|
starGlyphs: [".", "·", "✧", "✦", "✶"],
|
|
17086
16870
|
spinnerFrames: [" ◜ ", " ◠ ", " ◝ ", " ◞ ", " ◡ ", " ◟ "],
|
|
@@ -17187,7 +16971,7 @@ function borderGlyphsFor(style, glyphs) {
|
|
|
17187
16971
|
return ROUND_BORDER;
|
|
17188
16972
|
}
|
|
17189
16973
|
|
|
17190
|
-
//
|
|
16974
|
+
// src/text/text-width.ts
|
|
17191
16975
|
var ANSI = /\x1b\[[0-9;]*m/g;
|
|
17192
16976
|
var PRINTABLE_ASCII = /^[\x20-\x7e]*$/;
|
|
17193
16977
|
function visibleWidth(text) {
|
|
@@ -17222,7 +17006,7 @@ function clipTo(text, width, glyphs = UNICODE_GLYPHS) {
|
|
|
17222
17006
|
return `${out}${mark}`;
|
|
17223
17007
|
}
|
|
17224
17008
|
|
|
17225
|
-
//
|
|
17009
|
+
// src/render/syntax.ts
|
|
17226
17010
|
function newSyntaxState() {
|
|
17227
17011
|
return {};
|
|
17228
17012
|
}
|
|
@@ -17869,7 +17653,7 @@ function highlightSyntax(line, options) {
|
|
|
17869
17653
|
return `${out}${RESET}`;
|
|
17870
17654
|
}
|
|
17871
17655
|
|
|
17872
|
-
//
|
|
17656
|
+
// src/render/markdown.ts
|
|
17873
17657
|
var colour = (role, palette) => palette?.[role] || ANSI_PALETTE[role];
|
|
17874
17658
|
var INLINE_PATTERN = /(?<!\\)(`[^`\n]+`)|(?<!\\)(\*\*[^*\n]+\*\*)|(?<!\\)(__[^_\n]+__)|(?<!\\)(~~[^~\n]+~~)|(?<!\\)(\*[^*\n]+\*)|(?<!\\)(_[^_\n]+_)|(!?\[([^\]\n]+)\]\((https?:\/\/[^\s)\n]+)\))|(<(https?:\/\/[^>\s]+)>)/g;
|
|
17875
17659
|
var unescapeMarkdown = (text) => text.replace(/\\([\\`*_[\]{}()#+.!~>-])/g, "$1");
|
|
@@ -18090,7 +17874,7 @@ function renderMarkdown(text, options) {
|
|
|
18090
17874
|
`);
|
|
18091
17875
|
}
|
|
18092
17876
|
|
|
18093
|
-
//
|
|
17877
|
+
// src/render/tui.ts
|
|
18094
17878
|
function archymedesSpinnerFrame(index, glyphs = UNICODE_GLYPHS) {
|
|
18095
17879
|
const frames = glyphs.spinnerFrames;
|
|
18096
17880
|
const normalized = Number.isFinite(index) ? Math.max(0, Math.floor(index)) : 0;
|
|
@@ -18678,7 +18462,7 @@ function wrapPlain(text, width) {
|
|
|
18678
18462
|
return lines.length === 0 ? [""] : lines;
|
|
18679
18463
|
}
|
|
18680
18464
|
|
|
18681
|
-
//
|
|
18465
|
+
// src/render/transcript.ts
|
|
18682
18466
|
function truncateMiddle(value, maximum) {
|
|
18683
18467
|
const clean = value.replace(/\s+/g, " ").trim();
|
|
18684
18468
|
if (clean.length <= maximum)
|
|
@@ -18841,7 +18625,7 @@ function summarizeToolResult(toolName, content, isError) {
|
|
|
18841
18625
|
}
|
|
18842
18626
|
}
|
|
18843
18627
|
|
|
18844
|
-
//
|
|
18628
|
+
// src/render/sections.ts
|
|
18845
18629
|
var TONE_ROLE = {
|
|
18846
18630
|
good: "success",
|
|
18847
18631
|
bad: "error",
|
|
@@ -18968,7 +18752,7 @@ function outcomeMark(outcome, style) {
|
|
|
18968
18752
|
}
|
|
18969
18753
|
}
|
|
18970
18754
|
|
|
18971
|
-
//
|
|
18755
|
+
// src/render/code-view.ts
|
|
18972
18756
|
var MAX_DIFF_CELLS = 250000;
|
|
18973
18757
|
function diffLines(before, after) {
|
|
18974
18758
|
const left = before === "" ? [] : before.split(`
|
|
@@ -19265,7 +19049,7 @@ function renderFileChange(change, style, options = {}) {
|
|
|
19265
19049
|
};
|
|
19266
19050
|
}
|
|
19267
19051
|
|
|
19268
|
-
//
|
|
19052
|
+
// src/render/test-report.ts
|
|
19269
19053
|
function toMs(value) {
|
|
19270
19054
|
if (!value)
|
|
19271
19055
|
return;
|
|
@@ -19540,7 +19324,7 @@ function renderTestReport(report, style, options = {}) {
|
|
|
19540
19324
|
`);
|
|
19541
19325
|
}
|
|
19542
19326
|
|
|
19543
|
-
//
|
|
19327
|
+
// src/render/expandable.ts
|
|
19544
19328
|
var MAX_ENTRIES = 64;
|
|
19545
19329
|
|
|
19546
19330
|
class ExpandableStore {
|
|
@@ -19574,7 +19358,7 @@ function expandHint(id, hidden, depth, glyphs = UNICODE_GLYPHS) {
|
|
|
19574
19358
|
return paint(`${glyphs.collapsed} ${hidden} more line${hidden === 1 ? "" : "s"} hidden ${glyphs.middot} /expand ${id}`, DIM, depth);
|
|
19575
19359
|
}
|
|
19576
19360
|
|
|
19577
|
-
//
|
|
19361
|
+
// src/app/transcript.ts
|
|
19578
19362
|
var colorEnabled = false;
|
|
19579
19363
|
var wrap = (code) => (value) => colorEnabled ? `${code}${value}${RESET}` : value;
|
|
19580
19364
|
var palette = NO_COLOR_PALETTE;
|
|
@@ -19654,7 +19438,7 @@ function beginTranscriptTurn() {
|
|
|
19654
19438
|
markdown.reset();
|
|
19655
19439
|
}
|
|
19656
19440
|
|
|
19657
|
-
//
|
|
19441
|
+
// src/app/startup-update.ts
|
|
19658
19442
|
async function startupMaintenance(environment, interactive, install) {
|
|
19659
19443
|
updateDefenderFeed(environment).catch(() => {
|
|
19660
19444
|
return;
|
|
@@ -19693,7 +19477,7 @@ function installInChildProcess(entry, environment) {
|
|
|
19693
19477
|
});
|
|
19694
19478
|
}
|
|
19695
19479
|
|
|
19696
|
-
//
|
|
19480
|
+
// src/app/jev.ts
|
|
19697
19481
|
function jevOptionsFromEnvironment(environment) {
|
|
19698
19482
|
if ((environment.ARCHYMEDES_JEV ?? "").trim().toLowerCase() === "off")
|
|
19699
19483
|
return;
|
|
@@ -19704,7 +19488,7 @@ function jevOptionsFromEnvironment(environment) {
|
|
|
19704
19488
|
return { apiKey, ...model ? { model } : {}, ...environment.ARCHYMEDES_JEV_REVIEW?.trim().toLowerCase() === "off" ? { review: false } : {} };
|
|
19705
19489
|
}
|
|
19706
19490
|
|
|
19707
|
-
//
|
|
19491
|
+
// ../core/src/providers/exa.ts
|
|
19708
19492
|
var LATENCY_CEILING = {
|
|
19709
19493
|
instant: 5000,
|
|
19710
19494
|
fast: 1e4,
|
|
@@ -19910,7 +19694,7 @@ function createExaClient(environment, fetchImpl) {
|
|
|
19910
19694
|
});
|
|
19911
19695
|
}
|
|
19912
19696
|
|
|
19913
|
-
//
|
|
19697
|
+
// src/acp-server.ts
|
|
19914
19698
|
function splitFrames(buffer) {
|
|
19915
19699
|
const parts = buffer.split(`
|
|
19916
19700
|
`);
|
|
@@ -19926,8 +19710,14 @@ async function runAcpServer(options) {
|
|
|
19926
19710
|
const connection = new AcpConnection({
|
|
19927
19711
|
send,
|
|
19928
19712
|
extensions: {
|
|
19713
|
+
"_archymedes/providers": async () => ({ providers: providerOverview(options.environment) }),
|
|
19714
|
+
"_archymedes/providers/connect": async (params) => connectProvider(params, { environment: options.environment, processEnvironment: process.env }),
|
|
19715
|
+
"_archymedes/providers/models": async (params) => providerModels(params, { environment: options.environment }),
|
|
19716
|
+
"_archymedes/providers/remember-model": async (params) => rememberModel(params, { environment: options.environment, processEnvironment: process.env }),
|
|
19929
19717
|
"_archymedes/setup/status": async () => setupStatus(options.environment, { provider: options.provider, model: options.model }),
|
|
19930
19718
|
"_archymedes/setup/save": async (params) => saveSetup(params, { environment: options.environment, processEnvironment: process.env }),
|
|
19719
|
+
"_archymedes/settings/list": async () => listSettings(process.env),
|
|
19720
|
+
"_archymedes/settings/set": async (params) => setSetting(params, { environment: options.environment, processEnvironment: process.env }),
|
|
19931
19721
|
"_archymedes/models": async (params) => modelList(options.environment, params),
|
|
19932
19722
|
"_archymedes/startup": async () => ({
|
|
19933
19723
|
notices: await (startup ??= startupMaintenance(options.environment, false, installInChildProcess({ execPath: process.execPath, script: process.argv[1] ?? "" }, options.environment)))
|
|
@@ -19948,7 +19738,7 @@ async function runAcpServer(options) {
|
|
|
19948
19738
|
const workspace = started.workspace;
|
|
19949
19739
|
let agent = build(mode);
|
|
19950
19740
|
function build(currentMode) {
|
|
19951
|
-
|
|
19741
|
+
const built = new ArchymedesAgent({
|
|
19952
19742
|
root,
|
|
19953
19743
|
model: resolved.provider,
|
|
19954
19744
|
prices: priceCatalogFor(resolved.prices),
|
|
@@ -19957,9 +19747,12 @@ async function runAcpServer(options) {
|
|
|
19957
19747
|
search: createExaClient(options.environment),
|
|
19958
19748
|
onEvent,
|
|
19959
19749
|
jev: jevOptionsFromEnvironment(options.environment),
|
|
19750
|
+
...reasoningFromEnvironment(options.environment) ? { reasoning: reasoningFromEnvironment(options.environment) } : {},
|
|
19960
19751
|
afterEdit: acpEditDiagnostics(root, workspace, options.environment),
|
|
19961
19752
|
approve: async (request) => approve({ toolName: request.tool.name, summary: request.summary, toolCallId: request.call.id, ...request.pattern ? { pattern: request.pattern } : {} })
|
|
19962
19753
|
});
|
|
19754
|
+
built.warmUp();
|
|
19755
|
+
return built;
|
|
19963
19756
|
}
|
|
19964
19757
|
async function rebuild(change) {
|
|
19965
19758
|
const carried = await loadSession(root, agent.sessionId);
|
|
@@ -20072,10 +19865,10 @@ function priceCatalogFor(prices) {
|
|
|
20072
19865
|
};
|
|
20073
19866
|
}
|
|
20074
19867
|
|
|
20075
|
-
//
|
|
19868
|
+
// src/app/args.ts
|
|
20076
19869
|
import path23 from "node:path";
|
|
20077
19870
|
|
|
20078
|
-
//
|
|
19871
|
+
// src/render/charts.ts
|
|
20079
19872
|
function barChart(data, options) {
|
|
20080
19873
|
if (data.length === 0)
|
|
20081
19874
|
return [];
|
|
@@ -20100,7 +19893,7 @@ function barChart(data, options) {
|
|
|
20100
19893
|
});
|
|
20101
19894
|
}
|
|
20102
19895
|
|
|
20103
|
-
//
|
|
19896
|
+
// src/commands/chat-history.ts
|
|
20104
19897
|
function countTurns(messages) {
|
|
20105
19898
|
return messages.filter((message) => message.role === "user" && !message.internal).length;
|
|
20106
19899
|
}
|
|
@@ -20293,7 +20086,7 @@ function parseHistoryCommand(input) {
|
|
|
20293
20086
|
return { kind: "invalid", reason: `/history takes "list", a session id, "search <text>", "delete <id>", "status", or "resume" — not "${verb}".` };
|
|
20294
20087
|
}
|
|
20295
20088
|
|
|
20296
|
-
//
|
|
20089
|
+
// src/commands/pacing.ts
|
|
20297
20090
|
var PACE_PROFILES = {
|
|
20298
20091
|
off: {
|
|
20299
20092
|
level: "off",
|
|
@@ -20355,7 +20148,7 @@ function paceBadge(level, glyphs2 = UNICODE_GLYPHS) {
|
|
|
20355
20148
|
return `${glyphs2.paused} ${profileFor(level).label}`;
|
|
20356
20149
|
}
|
|
20357
20150
|
|
|
20358
|
-
//
|
|
20151
|
+
// src/app/args.ts
|
|
20359
20152
|
var SESSION_ID2 = /^\d{8}T\d{6}Z-[a-z0-9]{6}$/;
|
|
20360
20153
|
var DEFAULT_DOCKER_IMAGE = "debian:stable-slim";
|
|
20361
20154
|
function parseArgs(argv) {
|
|
@@ -20553,7 +20346,7 @@ function parseArgs(argv) {
|
|
|
20553
20346
|
return parsed;
|
|
20554
20347
|
}
|
|
20555
20348
|
|
|
20556
|
-
//
|
|
20349
|
+
// src/app/session-provider.ts
|
|
20557
20350
|
async function resolveSessionProvider2(environment, options) {
|
|
20558
20351
|
if (options.provider || !options.resume)
|
|
20559
20352
|
return resolveProvider(environment, options);
|
|
@@ -20562,7 +20355,7 @@ async function resolveSessionProvider2(environment, options) {
|
|
|
20562
20355
|
return resolveProvider(environment, selection?.provider === "free" ? { provider: "free", model: options.model ?? selection.model } : options);
|
|
20563
20356
|
}
|
|
20564
20357
|
|
|
20565
|
-
//
|
|
20358
|
+
// src/app/transcript.ts
|
|
20566
20359
|
var colorEnabled2 = false;
|
|
20567
20360
|
var liveTerminal2 = false;
|
|
20568
20361
|
var wrap2 = (code) => (value) => colorEnabled2 ? `${code}${value}${RESET}` : value;
|
|
@@ -20876,7 +20669,7 @@ ${rule(sectionStyle2(), { label: "tool activity", tone: "neutral" })}
|
|
|
20876
20669
|
}
|
|
20877
20670
|
}
|
|
20878
20671
|
|
|
20879
|
-
//
|
|
20672
|
+
// ../core/src/cli/suggestions.ts
|
|
20880
20673
|
var CATEGORY_ORDER = ["blocked", "recovery", "next", "discover", "starter"];
|
|
20881
20674
|
function defaultSignals(overrides = {}) {
|
|
20882
20675
|
return {
|
|
@@ -21273,7 +21066,7 @@ async function askModelForSuggestions(model, signals, context = {}) {
|
|
|
21273
21066
|
}
|
|
21274
21067
|
}
|
|
21275
21068
|
|
|
21276
|
-
//
|
|
21069
|
+
// src/ui/chooser.ts
|
|
21277
21070
|
var ALL_CHROME = { title: true, status: true, pagination: true, help: true };
|
|
21278
21071
|
function chromeOf(chrome) {
|
|
21279
21072
|
return { ...ALL_CHROME, ...chrome };
|
|
@@ -21501,7 +21294,7 @@ async function runChooser(keys, items, paint2, options) {
|
|
|
21501
21294
|
return;
|
|
21502
21295
|
}
|
|
21503
21296
|
|
|
21504
|
-
//
|
|
21297
|
+
// src/ui/navigation.ts
|
|
21505
21298
|
class CommandUsage {
|
|
21506
21299
|
limit;
|
|
21507
21300
|
order = [];
|
|
@@ -21524,8 +21317,8 @@ class CommandUsage {
|
|
|
21524
21317
|
}
|
|
21525
21318
|
}
|
|
21526
21319
|
|
|
21527
|
-
//
|
|
21528
|
-
import { randomUUID as
|
|
21320
|
+
// ../core/src/cli/daemon.ts
|
|
21321
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
21529
21322
|
var ARCHYMEDES_DAEMON_PROTOCOL_VERSION = 1;
|
|
21530
21323
|
var PREVIEW_HUNK_SEPARATOR = `
|
|
21531
21324
|
…
|
|
@@ -21571,7 +21364,7 @@ class ArchymedesSessionDaemon {
|
|
|
21571
21364
|
sessions = new Map;
|
|
21572
21365
|
pendingApprovals = new Map;
|
|
21573
21366
|
connect(options = {}) {
|
|
21574
|
-
const id = options.id ?? `client_${
|
|
21367
|
+
const id = options.id ?? `client_${randomUUID6()}`;
|
|
21575
21368
|
assertSafeId(id, "Client id");
|
|
21576
21369
|
if (this.clients.has(id))
|
|
21577
21370
|
throw new Error(`Daemon client already connected: ${id}`);
|
|
@@ -21590,7 +21383,7 @@ class ArchymedesSessionDaemon {
|
|
|
21590
21383
|
}
|
|
21591
21384
|
async requestApproval(sessionId, request) {
|
|
21592
21385
|
const publicRequest = {
|
|
21593
|
-
id: `approval_${
|
|
21386
|
+
id: `approval_${randomUUID6()}`,
|
|
21594
21387
|
sessionId,
|
|
21595
21388
|
summary: request.summary,
|
|
21596
21389
|
actionDigest: request.actionDigest,
|
|
@@ -21863,7 +21656,7 @@ class ArchymedesDaemonClient {
|
|
|
21863
21656
|
planRoute(objective, signal) {
|
|
21864
21657
|
return this.daemon.planRoute(this.id, this.sessionId, objective, signal);
|
|
21865
21658
|
}
|
|
21866
|
-
send(objective, commandId = `turn_${
|
|
21659
|
+
send(objective, commandId = `turn_${randomUUID6()}`) {
|
|
21867
21660
|
return this.daemon.send(this.id, this.sessionId, objective, commandId);
|
|
21868
21661
|
}
|
|
21869
21662
|
cancel() {
|
|
@@ -21922,7 +21715,7 @@ class ArchymedesDaemonClient {
|
|
|
21922
21715
|
}
|
|
21923
21716
|
}
|
|
21924
21717
|
|
|
21925
|
-
//
|
|
21718
|
+
// ../core/src/money.ts
|
|
21926
21719
|
var CURRENCIES2 = (() => {
|
|
21927
21720
|
try {
|
|
21928
21721
|
return Intl.supportedValuesOf("currency");
|
|
@@ -21965,7 +21758,7 @@ function formatMoney2(value) {
|
|
|
21965
21758
|
return value.currency === "USD" ? `${format.symbol}${rendered}` : `${format.symbol} ${rendered}`;
|
|
21966
21759
|
}
|
|
21967
21760
|
|
|
21968
|
-
//
|
|
21761
|
+
// ../core/src/cli/backends.ts
|
|
21969
21762
|
import path24 from "node:path";
|
|
21970
21763
|
var CONFIG_FILE_SCAN_LIMIT2 = 500;
|
|
21971
21764
|
function localCommandGuidance2(platform) {
|
|
@@ -22059,11 +21852,11 @@ class LocalWorkspace2 {
|
|
|
22059
21852
|
}
|
|
22060
21853
|
}
|
|
22061
21854
|
|
|
22062
|
-
//
|
|
21855
|
+
// ../core/src/cli/cost.ts
|
|
22063
21856
|
function formatTokenFlow2(usage) {
|
|
22064
21857
|
return `↑${compactTokenCount(usage.inputTokens)} ↓${compactTokenCount(usage.outputTokens)} tok`;
|
|
22065
21858
|
}
|
|
22066
|
-
var
|
|
21859
|
+
var emptyUsage2 = { inputTokens: 0, outputTokens: 0, totalTokens: 0, cachedInputTokens: 0, cacheWriteTokens: 0, reasoningTokens: 0 };
|
|
22067
21860
|
var CACHE_CHURN_FLOOR_TOKENS2 = 20000;
|
|
22068
21861
|
var CACHE_CHURN_HINT2 = [
|
|
22069
21862
|
"The prompt cache is being rewritten more than it is read, which costs more than not caching at all.",
|
|
@@ -22151,7 +21944,7 @@ class CostLedger2 {
|
|
|
22151
21944
|
cachedInputTokens: total.cachedInputTokens + turn.usage.cachedInputTokens,
|
|
22152
21945
|
cacheWriteTokens: total.cacheWriteTokens + turn.usage.cacheWriteTokens,
|
|
22153
21946
|
reasoningTokens: total.reasoningTokens + turn.usage.reasoningTokens
|
|
22154
|
-
}), { ...
|
|
21947
|
+
}), { ...emptyUsage2 });
|
|
22155
21948
|
}
|
|
22156
21949
|
get history() {
|
|
22157
21950
|
return [...this.turns];
|
|
@@ -22311,7 +22104,7 @@ class CostLedger2 {
|
|
|
22311
22104
|
}
|
|
22312
22105
|
}
|
|
22313
22106
|
|
|
22314
|
-
//
|
|
22107
|
+
// src/headless.ts
|
|
22315
22108
|
var HEADLESS_PROTOCOL_VERSION = 1;
|
|
22316
22109
|
var EXIT_CODES = {
|
|
22317
22110
|
completed: 0,
|
|
@@ -22414,7 +22207,7 @@ class HeadlessEmitter {
|
|
|
22414
22207
|
return;
|
|
22415
22208
|
}
|
|
22416
22209
|
if (safe.type === "model_turn") {
|
|
22417
|
-
this.emit("model_turn", { iteration: safe.iteration, model: safe.model, toolCalls: safe.toolCallCount, usage: safe.usage });
|
|
22210
|
+
this.emit("model_turn", { iteration: safe.iteration, model: safe.model, toolCalls: safe.toolCallCount, usage: safe.usage, ...safe.effort ? { effort: safe.effort, effortReason: safe.effortReason } : {} });
|
|
22418
22211
|
return;
|
|
22419
22212
|
}
|
|
22420
22213
|
if (safe.type === "provider_retry") {
|
|
@@ -22437,7 +22230,7 @@ class HeadlessEmitter {
|
|
|
22437
22230
|
}
|
|
22438
22231
|
}
|
|
22439
22232
|
|
|
22440
|
-
//
|
|
22233
|
+
// ../core/src/providers/price-catalog.ts
|
|
22441
22234
|
var ANTHROPIC_VERIFIED2 = "2026-06-24";
|
|
22442
22235
|
var ANTHROPIC_SOURCE2 = "anthropic.com/pricing, recorded 2026-06-24";
|
|
22443
22236
|
var ANTHROPIC2 = [
|
|
@@ -22489,7 +22282,7 @@ var SERVICES2 = [
|
|
|
22489
22282
|
];
|
|
22490
22283
|
var PRICE_CATALOG2 = definePrices([...ANTHROPIC2, ...OAI_COMPAT_LABS2, ...SERVICES2]);
|
|
22491
22284
|
|
|
22492
|
-
//
|
|
22285
|
+
// src/text/color-depth.ts
|
|
22493
22286
|
function detectColorDepth(environment, isTTY) {
|
|
22494
22287
|
if (!isTTY || environment.NO_COLOR !== undefined || environment.TERM === "dumb")
|
|
22495
22288
|
return "none";
|
|
@@ -22498,7 +22291,7 @@ function detectColorDepth(environment, isTTY) {
|
|
|
22498
22291
|
return "ansi256";
|
|
22499
22292
|
}
|
|
22500
22293
|
|
|
22501
|
-
//
|
|
22294
|
+
// src/terminal/keybindings.ts
|
|
22502
22295
|
var FUNCTION_KEY2 = /^f([1-9]|1[0-2])$/;
|
|
22503
22296
|
var NAMED_KEYS2 = new Set(["tab", "enter", "escape", "space", "up", "down", "left", "right", "home", "end", "pageup", "pagedown", "backspace", "delete"]);
|
|
22504
22297
|
function isKeyName2(value) {
|
|
@@ -22740,7 +22533,7 @@ function escapeCodeTimeoutMs2(environment = process.env) {
|
|
|
22740
22533
|
return Number.isInteger(parsed) && parsed >= 10 && parsed <= 2000 ? parsed : DEFAULT_ESCAPE_CODE_TIMEOUT_MS2;
|
|
22741
22534
|
}
|
|
22742
22535
|
|
|
22743
|
-
//
|
|
22536
|
+
// src/platform/local-currency.ts
|
|
22744
22537
|
var COUNTRY_CURRENCIES2 = {
|
|
22745
22538
|
RW: "RWF",
|
|
22746
22539
|
EG: "EGP",
|
|
@@ -22866,7 +22659,7 @@ function resolveCurrencyPreference(options) {
|
|
|
22866
22659
|
}
|
|
22867
22660
|
var FX_CACHE_MAX_AGE_MS2 = 24 * 60 * 60 * 1000;
|
|
22868
22661
|
|
|
22869
|
-
//
|
|
22662
|
+
// src/platform/settings.ts
|
|
22870
22663
|
import { promises as fs18 } from "node:fs";
|
|
22871
22664
|
import os5 from "node:os";
|
|
22872
22665
|
import path25 from "node:path";
|
|
@@ -22973,6 +22766,13 @@ var AUTOSAVE_CHOICES2 = [
|
|
|
22973
22766
|
{ value: "off", label: "Off — save with Ctrl+S (default)" },
|
|
22974
22767
|
{ value: "on", label: "On — save a second after you stop typing" }
|
|
22975
22768
|
];
|
|
22769
|
+
var REASONING_CHOICES2 = [
|
|
22770
|
+
{ value: "auto", label: "Auto (experimental) — lower the effort on routine steps, leave hard ones to the model" },
|
|
22771
|
+
{ value: "minimal", label: "Minimal — never think more than needed" },
|
|
22772
|
+
{ value: "low", label: "Low" },
|
|
22773
|
+
{ value: "medium", label: "Medium" },
|
|
22774
|
+
{ value: "high", label: "High — slowest" }
|
|
22775
|
+
];
|
|
22976
22776
|
var PROVIDER_CHOICES2 = PROVIDER_IDS.map((id) => ({ value: id, label: PROVIDER_INFO[id].label }));
|
|
22977
22777
|
var SETTING_FIELDS2 = [
|
|
22978
22778
|
{ key: "ARCHYMEDES_THEME", label: "Theme — colours for the whole CLI (/theme <name> also saves it)", choices: THEME_CHOICES2, section: "Appearance" },
|
|
@@ -22980,6 +22780,7 @@ var SETTING_FIELDS2 = [
|
|
|
22980
22780
|
{ key: "ARCHYMEDES_CODE_LINE_NUMBERS", label: "Line numbers in code blocks", choices: SHOW_HIDE_CHOICES2 },
|
|
22981
22781
|
{ key: "ARCHYMEDES_SIMPLE", label: "Simple mode — quiet start, short help", choices: SIMPLE_CHOICES2 },
|
|
22982
22782
|
{ key: "ARCHYMEDES_LANGUAGE", label: "Control language", choices: LANGUAGE_CHOICES2 },
|
|
22783
|
+
{ key: "ARCHYMEDES_REASONING", label: "Reasoning effort — clear it to leave each model at its own default", choices: REASONING_CHOICES2 },
|
|
22983
22784
|
{ key: "ARCHYMEDES_RESUME", label: "Continue your last chat at startup", choices: RESUME_CHOICES2, section: "Behaviour" },
|
|
22984
22785
|
{ key: "ARCHYMEDES_EDITOR_AUTOSAVE", label: "Auto-save in /edit", choices: AUTOSAVE_CHOICES2 },
|
|
22985
22786
|
{ key: "ARCHYMEDES_SUGGEST_MODEL", label: "Ask the model for extra suggestions (a small extra call per turn)", choices: ON_OFF_CHOICES2 },
|
|
@@ -23111,7 +22912,7 @@ function mergedEnvironment2(settings, environment = process.env) {
|
|
|
23111
22912
|
var PROVIDER_REQUIRED_NAMES2 = new Set(PROVIDER_IDS.flatMap((id) => PROVIDER_INFO[id].requires));
|
|
23112
22913
|
var PROVIDER_KEY_FIELDS2 = SETTING_FIELDS2.filter((field) => PROVIDER_REQUIRED_NAMES2.has(field.key));
|
|
23113
22914
|
|
|
23114
|
-
//
|
|
22915
|
+
// src/app/free-setup.ts
|
|
23115
22916
|
var OPENROUTER_KEYS_URL3 = "https://openrouter.ai/keys";
|
|
23116
22917
|
var FREE_SETUP_INTRO = [
|
|
23117
22918
|
"Free mode runs zero-priced models through OpenRouter and never falls back to a paid one.",
|
|
@@ -23177,7 +22978,7 @@ ${style3.bold("Free mode setup")}
|
|
|
23177
22978
|
return;
|
|
23178
22979
|
}
|
|
23179
22980
|
|
|
23180
|
-
//
|
|
22981
|
+
// src/session/tabs.ts
|
|
23181
22982
|
class WorkspaceController {
|
|
23182
22983
|
limit;
|
|
23183
22984
|
tabs = [];
|
|
@@ -23266,7 +23067,7 @@ class WorkspaceController {
|
|
|
23266
23067
|
}
|
|
23267
23068
|
}
|
|
23268
23069
|
|
|
23269
|
-
//
|
|
23070
|
+
// src/terminal/output.ts
|
|
23270
23071
|
var terminalStream2 = {
|
|
23271
23072
|
write(text) {
|
|
23272
23073
|
process.stdout.write(text);
|
|
@@ -23362,7 +23163,7 @@ class TabSink {
|
|
|
23362
23163
|
}
|
|
23363
23164
|
}
|
|
23364
23165
|
|
|
23365
|
-
//
|
|
23166
|
+
// src/terminal/job-stream.ts
|
|
23366
23167
|
var TERMINAL_STATUSES = new Set(["completed", "failed", "cancelled"]);
|
|
23367
23168
|
class WatchRegistry {
|
|
23368
23169
|
watched = new Map;
|
|
@@ -23397,7 +23198,7 @@ class WatchRegistry {
|
|
|
23397
23198
|
}
|
|
23398
23199
|
}
|
|
23399
23200
|
|
|
23400
|
-
//
|
|
23201
|
+
// src/theme/theme.ts
|
|
23401
23202
|
var BLUEPRINT2 = `
|
|
23402
23203
|
/* Blueprint navy, chalk-white ink and an amber pencil — the original drafting table. */
|
|
23403
23204
|
@theme blueprint {
|
|
@@ -23698,7 +23499,7 @@ function detectPreferredTheme(environment) {
|
|
|
23698
23499
|
return DEFAULT_THEME_NAME2;
|
|
23699
23500
|
}
|
|
23700
23501
|
|
|
23701
|
-
//
|
|
23502
|
+
// src/theme/theme-files.ts
|
|
23702
23503
|
import { promises as fs19 } from "node:fs";
|
|
23703
23504
|
import path26 from "node:path";
|
|
23704
23505
|
function themeDirectory(scope, root, environment) {
|
|
@@ -23736,7 +23537,7 @@ async function findTheme(name, root, environment) {
|
|
|
23736
23537
|
return (await discoverThemes(root, environment)).find((theme) => theme.name.toLowerCase() === wanted);
|
|
23737
23538
|
}
|
|
23738
23539
|
|
|
23739
|
-
//
|
|
23540
|
+
// src/render/syntax.ts
|
|
23740
23541
|
var DEFAULT_CODE_STYLE2 = { colors: "vscode", lineNumbers: true };
|
|
23741
23542
|
var currentCodeStyle2 = { ...DEFAULT_CODE_STYLE2 };
|
|
23742
23543
|
function codeStyleFromEnvironment(environment) {
|
|
@@ -23794,7 +23595,7 @@ var GRAMMARS2 = {
|
|
|
23794
23595
|
};
|
|
23795
23596
|
var PUNCTUATION2 = new Set([..."{}[]()<>;,.:=+-*/%!&|^~?\\"]);
|
|
23796
23597
|
|
|
23797
|
-
//
|
|
23598
|
+
// src/platform/i18n.ts
|
|
23798
23599
|
var CONTROL_LANGUAGES2 = {
|
|
23799
23600
|
en: "English",
|
|
23800
23601
|
zh: "中文 (Mandarin)",
|
|
@@ -23819,7 +23620,7 @@ function resolveControlLanguage2(value) {
|
|
|
23819
23620
|
return base in CONTROL_LANGUAGES2 ? base : "en";
|
|
23820
23621
|
}
|
|
23821
23622
|
|
|
23822
|
-
//
|
|
23623
|
+
// src/text/glyphs.ts
|
|
23823
23624
|
var UNICODE_GLYPHS2 = {
|
|
23824
23625
|
starGlyphs: [".", "·", "✧", "✦", "✶"],
|
|
23825
23626
|
spinnerFrames: [" ◜ ", " ◠ ", " ◝ ", " ◞ ", " ◡ ", " ◟ "],
|
|
@@ -23935,7 +23736,7 @@ function glyphsFor(mode) {
|
|
|
23935
23736
|
function resolveGlyphs(environment, platform = process.platform) {
|
|
23936
23737
|
return glyphsFor(detectGlyphMode(environment, platform));
|
|
23937
23738
|
}
|
|
23938
|
-
//
|
|
23739
|
+
// src/session/state-history.ts
|
|
23939
23740
|
class CliStateHistory {
|
|
23940
23741
|
root;
|
|
23941
23742
|
environment;
|
|
@@ -24046,7 +23847,7 @@ class CliStateHistory {
|
|
|
24046
23847
|
}
|
|
24047
23848
|
}
|
|
24048
23849
|
|
|
24049
|
-
//
|
|
23850
|
+
// src/ui/borrowed-keyboard.ts
|
|
24050
23851
|
function painter(output) {
|
|
24051
23852
|
let rows = 0;
|
|
24052
23853
|
const erase = () => {
|
|
@@ -24127,7 +23928,7 @@ async function openChooser(host, items, options, self) {
|
|
|
24127
23928
|
return withBorrowedKeyboard(host, self, (keys, paint2) => runChooser(keys, items, paint2, sized));
|
|
24128
23929
|
}
|
|
24129
23930
|
|
|
24130
|
-
//
|
|
23931
|
+
// src/app/prompts.ts
|
|
24131
23932
|
function renderApprovalPreview(preview2) {
|
|
24132
23933
|
if (!preview2)
|
|
24133
23934
|
return;
|
|
@@ -24265,7 +24066,7 @@ async function hiddenQuestion(readline, question, signal) {
|
|
|
24265
24066
|
}
|
|
24266
24067
|
}
|
|
24267
24068
|
|
|
24268
|
-
//
|
|
24069
|
+
// src/app/providers.ts
|
|
24269
24070
|
function readFxRates(environment) {
|
|
24270
24071
|
const genericRate = Number(environment.ARCHYMEDES_FX_RATE);
|
|
24271
24072
|
const genericFrom = environment.ARCHYMEDES_FX_FROM?.trim().toUpperCase();
|
|
@@ -24282,11 +24083,11 @@ function readFxRates(environment) {
|
|
|
24282
24083
|
}
|
|
24283
24084
|
return configured;
|
|
24284
24085
|
}
|
|
24285
|
-
//
|
|
24086
|
+
// ../core/src/cli/job-store.ts
|
|
24286
24087
|
import { promises as fs20 } from "node:fs";
|
|
24287
24088
|
import path27 from "node:path";
|
|
24288
24089
|
|
|
24289
|
-
//
|
|
24090
|
+
// ../core/src/cli/jobs.ts
|
|
24290
24091
|
var JOB_STATUSES = ["queued", "running", "paused", "completed", "failed", "cancelled"];
|
|
24291
24092
|
var DECISIONS = ["allow", "allow_always", "allow_pattern", "deny", "deny_always"];
|
|
24292
24093
|
function parseJobRecord(value, index) {
|
|
@@ -24461,7 +24262,7 @@ function recoverStale(store, now) {
|
|
|
24461
24262
|
return { store: { jobs }, recovered };
|
|
24462
24263
|
}
|
|
24463
24264
|
|
|
24464
|
-
//
|
|
24265
|
+
// ../core/src/cli/job-store.ts
|
|
24465
24266
|
function jobStoreFile(root) {
|
|
24466
24267
|
return path27.join(root, ".archymedes", "jobs.json");
|
|
24467
24268
|
}
|
|
@@ -24581,10 +24382,10 @@ async function appendJobLog(root, id, line) {
|
|
|
24581
24382
|
await fs20.appendFile(file, `${line}
|
|
24582
24383
|
`, "utf8");
|
|
24583
24384
|
}
|
|
24584
|
-
//
|
|
24385
|
+
// src/job-worker.ts
|
|
24585
24386
|
import os6 from "node:os";
|
|
24586
24387
|
|
|
24587
|
-
//
|
|
24388
|
+
// src/commands/wander.ts
|
|
24588
24389
|
async function gatherWanderEvidence(topic, search, numResults = 8) {
|
|
24589
24390
|
if (!search) {
|
|
24590
24391
|
return {
|
|
@@ -24680,7 +24481,7 @@ function renderWanderChart(results, style3, width) {
|
|
|
24680
24481
|
`);
|
|
24681
24482
|
}
|
|
24682
24483
|
|
|
24683
|
-
//
|
|
24484
|
+
// src/job-worker.ts
|
|
24684
24485
|
function workerId(hostname = os6.hostname(), pid = process.pid) {
|
|
24685
24486
|
return `${hostname}:${pid}`;
|
|
24686
24487
|
}
|
|
@@ -24858,7 +24659,7 @@ async function runJobWorkerForever(deps) {
|
|
|
24858
24659
|
}
|
|
24859
24660
|
}
|
|
24860
24661
|
|
|
24861
|
-
//
|
|
24662
|
+
// src/app/providers.ts
|
|
24862
24663
|
function renderProviders(environment, depth) {
|
|
24863
24664
|
const paint2 = (text, apply) => depth === "none" ? text : apply(text);
|
|
24864
24665
|
const statuses = describeProviders(environment);
|
|
@@ -24929,7 +24730,7 @@ function modelPriceCatalogFor(prices, exact) {
|
|
|
24929
24730
|
return { ...rates, ...prices.largeContext ? { largeContext: prices.largeContext } : {} };
|
|
24930
24731
|
}
|
|
24931
24732
|
|
|
24932
|
-
//
|
|
24733
|
+
// src/app/job-launch.ts
|
|
24933
24734
|
async function runJobWorkerProcess(root, jobId) {
|
|
24934
24735
|
const savedSettings = await loadSettings(process.env);
|
|
24935
24736
|
const environment = mergedEnvironment(savedSettings, process.env);
|
|
@@ -24966,10 +24767,10 @@ async function runJobWorkerProcess(root, jobId) {
|
|
|
24966
24767
|
}
|
|
24967
24768
|
}
|
|
24968
24769
|
|
|
24969
|
-
//
|
|
24770
|
+
// src/app/startup-commands.ts
|
|
24970
24771
|
import { createInterface as createInterface4 } from "node:readline/promises";
|
|
24971
24772
|
|
|
24972
|
-
//
|
|
24773
|
+
// src/headless.ts
|
|
24973
24774
|
var EXIT_CODES2 = {
|
|
24974
24775
|
completed: 0,
|
|
24975
24776
|
failed: 1,
|
|
@@ -24993,7 +24794,7 @@ function exitCodeForStatus2(status) {
|
|
|
24993
24794
|
return STATUS_EXIT2[status];
|
|
24994
24795
|
}
|
|
24995
24796
|
|
|
24996
|
-
//
|
|
24797
|
+
// src/platform/doctor.ts
|
|
24997
24798
|
var DEFAULT_PROBE_TIMEOUT_MS = 5000;
|
|
24998
24799
|
function modelEndpoints(environment) {
|
|
24999
24800
|
return providerEndpoints(environment).map((provider) => {
|
|
@@ -25123,7 +24924,7 @@ function doctorReport(probes, context) {
|
|
|
25123
24924
|
};
|
|
25124
24925
|
}
|
|
25125
24926
|
|
|
25126
|
-
//
|
|
24927
|
+
// src/text/color-depth.ts
|
|
25127
24928
|
function detectColorDepth2(environment, isTTY) {
|
|
25128
24929
|
if (!isTTY || environment.NO_COLOR !== undefined || environment.TERM === "dumb")
|
|
25129
24930
|
return "none";
|
|
@@ -25132,7 +24933,7 @@ function detectColorDepth2(environment, isTTY) {
|
|
|
25132
24933
|
return "ansi256";
|
|
25133
24934
|
}
|
|
25134
24935
|
|
|
25135
|
-
//
|
|
24936
|
+
// src/session/delete-session.ts
|
|
25136
24937
|
import { promises as fs21 } from "node:fs";
|
|
25137
24938
|
import path28 from "node:path";
|
|
25138
24939
|
var SAFE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
@@ -25152,7 +24953,7 @@ async function clearProjection(root, id) {
|
|
|
25152
24953
|
if (!exists)
|
|
25153
24954
|
return;
|
|
25154
24955
|
try {
|
|
25155
|
-
const { SessionProjection } = await import("./projection-
|
|
24956
|
+
const { SessionProjection } = await import("./projection-ndr3t77h.mjs");
|
|
25156
24957
|
const projection = await SessionProjection.open(root);
|
|
25157
24958
|
try {
|
|
25158
24959
|
await projection.rebuild(id);
|
|
@@ -25178,7 +24979,7 @@ async function deleteSession(root, id, options = {}) {
|
|
|
25178
24979
|
return { deleted: true };
|
|
25179
24980
|
}
|
|
25180
24981
|
|
|
25181
|
-
//
|
|
24982
|
+
// src/ui/navigation.ts
|
|
25182
24983
|
var ESSENTIAL_COMMANDS = ["/help", "/history", "/model", "/mode", "/diff", "/undo", "/settings", "/exit"];
|
|
25183
24984
|
function isEssential(command) {
|
|
25184
24985
|
return ESSENTIAL_COMMANDS.includes(command);
|
|
@@ -25245,7 +25046,7 @@ function renderAsks(suggestions, style3) {
|
|
|
25245
25046
|
`);
|
|
25246
25047
|
}
|
|
25247
25048
|
|
|
25248
|
-
//
|
|
25049
|
+
// src/app/help.ts
|
|
25249
25050
|
function helpText(language = "en", shortcuts = new Map) {
|
|
25250
25051
|
const star = glyphs.star;
|
|
25251
25052
|
const mark = (command) => isEssential(command) ? `${star} ` : " ";
|
|
@@ -25350,7 +25151,7 @@ ${renderCommandHelp(language, shortcuts, { mark })}
|
|
|
25350
25151
|
`;
|
|
25351
25152
|
}
|
|
25352
25153
|
|
|
25353
|
-
//
|
|
25154
|
+
// src/app/prompts.ts
|
|
25354
25155
|
function settingsChooser(readline) {
|
|
25355
25156
|
return (request) => openChooser({ readline, input: process.stdin, output: process.stdout }, request.items.map((item) => ({ ...item })), {
|
|
25356
25157
|
title: request.title,
|
|
@@ -25423,7 +25224,7 @@ async function hiddenQuestion2(readline, question, signal) {
|
|
|
25423
25224
|
}
|
|
25424
25225
|
}
|
|
25425
25226
|
|
|
25426
|
-
//
|
|
25227
|
+
// src/app/startup-commands.ts
|
|
25427
25228
|
function runInformationFlag(context) {
|
|
25428
25229
|
const { args, environment, language, earlyDepth } = context;
|
|
25429
25230
|
if (args.help) {
|
|
@@ -25627,7 +25428,7 @@ ${status.reason ?? "native state engine unavailable"}
|
|
|
25627
25428
|
return 0;
|
|
25628
25429
|
}
|
|
25629
25430
|
|
|
25630
|
-
//
|
|
25431
|
+
// src/app/display-currency.ts
|
|
25631
25432
|
async function settleDisplayCurrency(options) {
|
|
25632
25433
|
const { args, environment, prices, rates, state } = options;
|
|
25633
25434
|
if (prices && state.display !== prices.currency) {
|
|
@@ -25684,7 +25485,7 @@ async function settleDisplayCurrency(options) {
|
|
|
25684
25485
|
return;
|
|
25685
25486
|
}
|
|
25686
25487
|
|
|
25687
|
-
//
|
|
25488
|
+
// src/app/workspaces.ts
|
|
25688
25489
|
function createWorkspaceFactory(args, environment) {
|
|
25689
25490
|
return async (request) => {
|
|
25690
25491
|
const announce = (text) => {
|
|
@@ -25694,8 +25495,8 @@ function createWorkspaceFactory(args, environment) {
|
|
|
25694
25495
|
};
|
|
25695
25496
|
const minutes = Math.max(1, Math.min(args.sandboxMinutes, 60));
|
|
25696
25497
|
if (request.backend === "e2b") {
|
|
25697
|
-
const { findWorkspacePreset } = await import("./sandbox-templates-
|
|
25698
|
-
const { createE2BProvider } = await import("./factory-
|
|
25498
|
+
const { findWorkspacePreset } = await import("./sandbox-templates-9jcjws23.mjs");
|
|
25499
|
+
const { createE2BProvider } = await import("./factory-xpqqcyqq.mjs");
|
|
25699
25500
|
const preset = findWorkspacePreset(request.preset ?? args.preset);
|
|
25700
25501
|
const sandbox = createE2BProvider(environment, preset.templateAlias);
|
|
25701
25502
|
if (!sandbox)
|
|
@@ -25721,7 +25522,7 @@ function createWorkspaceFactory(args, environment) {
|
|
|
25721
25522
|
return { workspace: created };
|
|
25722
25523
|
}
|
|
25723
25524
|
if (request.backend === "docker") {
|
|
25724
|
-
const { createDockerProvider } = await import("./factory-
|
|
25525
|
+
const { createDockerProvider } = await import("./factory-xpqqcyqq.mjs");
|
|
25725
25526
|
const image = request.dockerImage || args.dockerImage || environment.DOCKER_CODING_IMAGE;
|
|
25726
25527
|
const sandbox = createDockerProvider({ ...environment, DOCKER_CODING_IMAGE: image });
|
|
25727
25528
|
if (!sandbox)
|
|
@@ -25750,11 +25551,11 @@ function createWorkspaceFactory(args, environment) {
|
|
|
25750
25551
|
};
|
|
25751
25552
|
}
|
|
25752
25553
|
|
|
25753
|
-
//
|
|
25554
|
+
// ../core/src/cli/balance.ts
|
|
25754
25555
|
var CRITICAL_BALANCE_USD2 = 0.5;
|
|
25755
25556
|
var LOW_BALANCE_USD2 = 2;
|
|
25756
25557
|
|
|
25757
|
-
//
|
|
25558
|
+
// src/commands/balance.ts
|
|
25758
25559
|
function formatBalance(amount, currency) {
|
|
25759
25560
|
return formatMoney(fromUnits(amount, currency));
|
|
25760
25561
|
}
|
|
@@ -25857,7 +25658,7 @@ class BalanceWatch {
|
|
|
25857
25658
|
}
|
|
25858
25659
|
}
|
|
25859
25660
|
|
|
25860
|
-
//
|
|
25661
|
+
// src/session/resumed-spend.ts
|
|
25861
25662
|
async function readSessionModelTurns(root, sessionId) {
|
|
25862
25663
|
const events = await readEventJournal(root, sessionId);
|
|
25863
25664
|
const turns = [];
|
|
@@ -25889,7 +25690,7 @@ function priceSessionModelTurns(turns, options) {
|
|
|
25889
25690
|
return { spent: total, unpriced: [...unpriced].sort() };
|
|
25890
25691
|
}
|
|
25891
25692
|
|
|
25892
|
-
//
|
|
25693
|
+
// src/app/balance-tracking.ts
|
|
25893
25694
|
function createBalanceTracking(options) {
|
|
25894
25695
|
const { environment, processEnvironment, rates, state } = options;
|
|
25895
25696
|
const usdInDisplay = (usd) => {
|
|
@@ -25978,7 +25779,7 @@ function createBalanceTracking(options) {
|
|
|
25978
25779
|
return { lowBalance, criticalBalance, balanceWatch, parseManualBalance, currentBalance, persistManualBalance, sessionSpend, balanceHeader, checkBalance, carryResumedSpend };
|
|
25979
25780
|
}
|
|
25980
25781
|
|
|
25981
|
-
//
|
|
25782
|
+
// src/app/agent-factory.ts
|
|
25982
25783
|
function createClientFactory(options) {
|
|
25983
25784
|
const { args, environment, daemon, approvalPrompt, rates, approvedBudget, state } = options;
|
|
25984
25785
|
return async (record2, runtime = {}) => {
|
|
@@ -25999,6 +25800,7 @@ function createClientFactory(options) {
|
|
|
25999
25800
|
onExpense: (expense) => state.ledger.recordExpense(expense),
|
|
26000
25801
|
onEvent,
|
|
26001
25802
|
jev: jevOptionsFromEnvironment(environment),
|
|
25803
|
+
...reasoningFromEnvironment(environment) ? { reasoning: reasoningFromEnvironment(environment) } : {},
|
|
26002
25804
|
afterEdit: editDiagnostics
|
|
26003
25805
|
}), record2);
|
|
26004
25806
|
if (editDiagnostics)
|
|
@@ -26018,14 +25820,14 @@ function closeWithClient(client, hook) {
|
|
|
26018
25820
|
client.dispose = () => dispose().finally(close);
|
|
26019
25821
|
}
|
|
26020
25822
|
|
|
26021
|
-
//
|
|
25823
|
+
// src/app/live-models.ts
|
|
26022
25824
|
async function readCachedLiveModels(environment, state) {
|
|
26023
25825
|
const cached = await readModelCache(environment);
|
|
26024
25826
|
if (isCacheFresh(cached))
|
|
26025
25827
|
state.liveModels = cached.models;
|
|
26026
25828
|
}
|
|
26027
25829
|
|
|
26028
|
-
//
|
|
25830
|
+
// src/app/session-hints.ts
|
|
26029
25831
|
function createSessionHints(options) {
|
|
26030
25832
|
const { state, watched, tabs, usage } = options;
|
|
26031
25833
|
const navContext = () => ({
|
|
@@ -26054,7 +25856,7 @@ function createSessionHints(options) {
|
|
|
26054
25856
|
return { navContext, writeHint };
|
|
26055
25857
|
}
|
|
26056
25858
|
|
|
26057
|
-
//
|
|
25859
|
+
// src/render/completion-card.ts
|
|
26058
25860
|
var CHECK_LABELS = {
|
|
26059
25861
|
tests: "tests",
|
|
26060
25862
|
typecheck: "typecheck",
|
|
@@ -26084,7 +25886,7 @@ function renderCompletionCard(input, style3) {
|
|
|
26084
25886
|
return panel(lines, style3, { title, tone: failed2 ? "bad" : verified ? "good" : "warn" });
|
|
26085
25887
|
}
|
|
26086
25888
|
|
|
26087
|
-
//
|
|
25889
|
+
// src/render/routing-receipt.ts
|
|
26088
25890
|
function formatMicros(micros, currency = "USD") {
|
|
26089
25891
|
if (micros === undefined || !Number.isFinite(micros))
|
|
26090
25892
|
return "—";
|
|
@@ -26176,10 +25978,10 @@ ${rule(cell, { label: badge })}` : out3.join(`
|
|
|
26176
25978
|
`);
|
|
26177
25979
|
}
|
|
26178
25980
|
|
|
26179
|
-
//
|
|
25981
|
+
// src/app/session-hints.ts
|
|
26180
25982
|
var failureStatus = (status) => status === "needs_approval" ? "waiting_approval" : status;
|
|
26181
25983
|
|
|
26182
|
-
//
|
|
25984
|
+
// src/app/turn-failure.ts
|
|
26183
25985
|
async function handleTurnFailure(error, request, context) {
|
|
26184
25986
|
const { args, environment, interactive, headless, recoveryState, state, navContext } = context;
|
|
26185
25987
|
if (recoveryState.last?.request === request) {
|
|
@@ -26234,7 +26036,7 @@ ${style.yellow(`Stopped at the ${formatMoney(fromUnits(args.budget, state.displa
|
|
|
26234
26036
|
return false;
|
|
26235
26037
|
}
|
|
26236
26038
|
|
|
26237
|
-
//
|
|
26039
|
+
// src/app/turn-preflight.ts
|
|
26238
26040
|
async function runTurnPreflight(request, context) {
|
|
26239
26041
|
const { args, readline, interactive, approvedBudget, rates, state } = context;
|
|
26240
26042
|
const { currentBalance, balanceWatch, sessionSpend } = context.balance;
|
|
@@ -26332,7 +26134,7 @@ async function runTurnPreflight(request, context) {
|
|
|
26332
26134
|
return true;
|
|
26333
26135
|
}
|
|
26334
26136
|
|
|
26335
|
-
//
|
|
26137
|
+
// src/app/turn-runner.ts
|
|
26336
26138
|
var addModelUsage2 = (left, right) => ({
|
|
26337
26139
|
inputTokens: left.inputTokens + right.inputTokens,
|
|
26338
26140
|
outputTokens: left.outputTokens + right.outputTokens,
|
|
@@ -26540,7 +26342,7 @@ ${result.status === "completed" ? asMarkdown(result.summary) : style.yellow(resu
|
|
|
26540
26342
|
};
|
|
26541
26343
|
}
|
|
26542
26344
|
|
|
26543
|
-
//
|
|
26345
|
+
// src/app/interrupts.ts
|
|
26544
26346
|
function createSigintHandling(options) {
|
|
26545
26347
|
const { readline, state } = options;
|
|
26546
26348
|
const handleSigint = () => {
|
|
@@ -26581,7 +26383,7 @@ function createSigintHandling(options) {
|
|
|
26581
26383
|
return { bindSigint, unbindSigint };
|
|
26582
26384
|
}
|
|
26583
26385
|
|
|
26584
|
-
//
|
|
26386
|
+
// src/app/session-start.ts
|
|
26585
26387
|
import path29 from "node:path";
|
|
26586
26388
|
async function resumeAtStartup(context) {
|
|
26587
26389
|
const { args, interactive, stateHistory, state, openClient } = context;
|
|
@@ -26654,7 +26456,7 @@ async function runOneShot(context) {
|
|
|
26654
26456
|
return args.json ? exitCodeForStatus2(state.lastTurnStatus) : ran ? 0 : 1;
|
|
26655
26457
|
}
|
|
26656
26458
|
|
|
26657
|
-
//
|
|
26459
|
+
// src/archymedes.ts
|
|
26658
26460
|
async function main() {
|
|
26659
26461
|
process.stdout.on("error", (error) => {
|
|
26660
26462
|
if (error.code === "EPIPE")
|