archymedes-cli 3.1.0 → 3.3.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-1g1y6q74.mjs → archymedes-h13ap0za.mjs} +1 -1
- package/dist/{archymedes-95xvcvww.mjs → archymedes-j0vrbr99.mjs} +941 -151
- package/dist/archymedes-main.mjs +657 -1036
- package/dist/{factory-8xk6y60m.mjs → factory-r6r0ypm6.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-j0vrbr99.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|jest|vitest|mocha|sass|tailwindcss|esbuild|webpack|rollup|nodemon|parcel|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,
|
|
@@ -11102,7 +10527,7 @@ class ArchymedesAgent {
|
|
|
11102
10527
|
this.delegatedInFlightRwf += reservation;
|
|
11103
10528
|
try {
|
|
11104
10529
|
const runtime = new BoundedAgentRuntime({
|
|
11105
|
-
model: this.recovery.wrap(this.options.model, () => this.session, this.options.prices, `delegate:${
|
|
10530
|
+
model: this.recovery.wrap(this.options.model, () => this.session, this.options.prices, `delegate:${randomUUID4()}`),
|
|
11106
10531
|
tools,
|
|
11107
10532
|
prices: this.options.prices,
|
|
11108
10533
|
artifacts: this.artifacts,
|
|
@@ -11116,7 +10541,7 @@ class ArchymedesAgent {
|
|
|
11116
10541
|
const result = await runtime.execute({
|
|
11117
10542
|
taskId: `${this.session.id}_delegate`,
|
|
11118
10543
|
runId: this.session.id,
|
|
11119
|
-
stepId: `delegate_${
|
|
10544
|
+
stepId: `delegate_${randomUUID4()}`,
|
|
11120
10545
|
objective: task,
|
|
11121
10546
|
history: [],
|
|
11122
10547
|
systemPrompt,
|
|
@@ -11159,7 +10584,7 @@ class ArchymedesAgent {
|
|
|
11159
10584
|
this.turnAbort = null;
|
|
11160
10585
|
throw error;
|
|
11161
10586
|
}
|
|
11162
|
-
const turnId = `turn_${
|
|
10587
|
+
const turnId = `turn_${randomUUID4()}`;
|
|
11163
10588
|
this.activeTurnId = turnId;
|
|
11164
10589
|
let turnStatus = "queued";
|
|
11165
10590
|
const transition = async (to, durable = false) => {
|
|
@@ -11218,17 +10643,27 @@ class ArchymedesAgent {
|
|
|
11218
10643
|
|
|
11219
10644
|
${requested}` : requested;
|
|
11220
10645
|
let checkpoint;
|
|
10646
|
+
let checkpointReady = Promise.resolve();
|
|
11221
10647
|
if (this.options.mode !== "plan" && this.workspace.kind === "local") {
|
|
11222
|
-
|
|
11223
|
-
|
|
11224
|
-
|
|
10648
|
+
checkpointReady = this.checkpoints.capture(titleFromObjective(objective), turnId, this.messages.length).then((taken) => {
|
|
10649
|
+
checkpoint = taken;
|
|
10650
|
+
if (taken)
|
|
10651
|
+
this.options.onEvent?.({ type: "checkpoint", checkpoint: taken });
|
|
10652
|
+
}).catch(() => {
|
|
10653
|
+
return;
|
|
10654
|
+
});
|
|
11225
10655
|
}
|
|
11226
10656
|
const compaction = await this.compactIfNeeded(turnId, objective, turnAbort.signal, tokenSaver);
|
|
11227
10657
|
compactionActualRwf = compaction.actualRwf;
|
|
11228
10658
|
this.permissions.setTaskHint(objective);
|
|
10659
|
+
this.startDifficultyReading(objective, turnAbort.signal);
|
|
11229
10660
|
const runtime = new BoundedAgentRuntime({
|
|
11230
10661
|
model: this.recovery.wrap(this.options.model, () => this.session, this.options.prices, "main"),
|
|
11231
|
-
|
|
10662
|
+
...this.options.reasoning === "auto" ? { effortPolicy: (signals) => predictEffort({ ...signals, objective, ...this.jevDifficulty ? { difficultyHint: this.jevDifficulty } : {} }) } : {},
|
|
10663
|
+
tools: scoped.map((tool) => tool.effect === "none" ? tool : { ...tool, execute: async (args, context) => {
|
|
10664
|
+
await checkpointReady;
|
|
10665
|
+
return tool.execute(args, context);
|
|
10666
|
+
} }),
|
|
11232
10667
|
prices: this.options.prices,
|
|
11233
10668
|
artifacts: this.artifacts,
|
|
11234
10669
|
control: {
|
|
@@ -11267,6 +10702,7 @@ ${requested}` : requested;
|
|
|
11267
10702
|
runId: this.session.id,
|
|
11268
10703
|
stepId: `turn_${this.messages.length}`,
|
|
11269
10704
|
objective: turnObjective,
|
|
10705
|
+
...this.options.reasoning && this.options.reasoning !== "auto" ? { effort: this.options.reasoning } : {},
|
|
11270
10706
|
images: attached.images,
|
|
11271
10707
|
history: sentHistory,
|
|
11272
10708
|
systemPrompt,
|
|
@@ -11301,6 +10737,7 @@ ${hookWarnings.join(`
|
|
|
11301
10737
|
hostedRecoveryBatchId: this.recovery.settledBatchId() ?? this.session.hostedRecoveryBatchId,
|
|
11302
10738
|
updatedAt: Date.now()
|
|
11303
10739
|
};
|
|
10740
|
+
await checkpointReady;
|
|
11304
10741
|
const terminalStatus = runtimeStatusToTurnStatus(result.status);
|
|
11305
10742
|
await transition(terminalStatus, true);
|
|
11306
10743
|
await this.recordHostedUsage();
|
|
@@ -11351,6 +10788,8 @@ ${hookWarnings.join(`
|
|
|
11351
10788
|
for (const call of message.toolCalls)
|
|
11352
10789
|
toolNames.push(call.name);
|
|
11353
10790
|
}
|
|
10791
|
+
if (toolNames.length === 0)
|
|
10792
|
+
return;
|
|
11354
10793
|
try {
|
|
11355
10794
|
const response = await requestJevVerdict({
|
|
11356
10795
|
apiKey: this.jev.apiKey,
|
|
@@ -11385,6 +10824,29 @@ ${hookWarnings.join(`
|
|
|
11385
10824
|
return (verdict.outcomeProbabilities[verdict.outcome] ?? 0) >= 0.5;
|
|
11386
10825
|
}
|
|
11387
10826
|
jevCorrectionDepth = 0;
|
|
10827
|
+
jevDifficulty;
|
|
10828
|
+
difficultyStamp = 0;
|
|
10829
|
+
startDifficultyReading(objective, signal) {
|
|
10830
|
+
this.jevDifficulty = undefined;
|
|
10831
|
+
const stamp = ++this.difficultyStamp;
|
|
10832
|
+
if (this.options.reasoning !== "auto" || !this.jev)
|
|
10833
|
+
return;
|
|
10834
|
+
requestJevVerdict({
|
|
10835
|
+
apiKey: this.jev.apiKey,
|
|
10836
|
+
...this.jev.model ? { model: this.jev.model } : {},
|
|
10837
|
+
...this.jev.fetchImpl ? { fetchImpl: this.jev.fetchImpl } : {},
|
|
10838
|
+
state: objective,
|
|
10839
|
+
questions: DIFFICULTY_QUESTIONS,
|
|
10840
|
+
timeoutMs: 5000,
|
|
10841
|
+
signal
|
|
10842
|
+
}).then((response) => {
|
|
10843
|
+
if (stamp !== this.difficultyStamp)
|
|
10844
|
+
return;
|
|
10845
|
+
this.jevDifficulty = difficultyFromResponse(response)?.difficulty;
|
|
10846
|
+
}).catch(() => {
|
|
10847
|
+
return;
|
|
10848
|
+
});
|
|
10849
|
+
}
|
|
11388
10850
|
async correctivePrompt(objective, verdict, evidence) {
|
|
11389
10851
|
const failures = evidence.filter((entry) => entry.exitCode !== undefined && entry.exitCode !== 0).slice(-6);
|
|
11390
10852
|
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 +10946,15 @@ function isActiveTurnStatus(status) {
|
|
|
11484
10946
|
return status === "queued" || status === "running" || status === "waiting_approval";
|
|
11485
10947
|
}
|
|
11486
10948
|
|
|
11487
|
-
//
|
|
10949
|
+
// ../core/src/cli/edit-diagnostics.ts
|
|
11488
10950
|
import { promises as fs11 } from "node:fs";
|
|
11489
10951
|
import path16 from "node:path";
|
|
11490
10952
|
import { fileURLToPath as fileURLToPath2, pathToFileURL } from "node:url";
|
|
11491
10953
|
|
|
11492
|
-
//
|
|
10954
|
+
// ../core/src/lsp/client.ts
|
|
11493
10955
|
import { spawn as spawn7, spawnSync } from "node:child_process";
|
|
11494
10956
|
|
|
11495
|
-
//
|
|
10957
|
+
// ../core/src/lsp/diagnostics.ts
|
|
11496
10958
|
function severityName(severity) {
|
|
11497
10959
|
switch (severity) {
|
|
11498
10960
|
case 1:
|
|
@@ -11598,7 +11060,7 @@ class DiagnosticsCollection {
|
|
|
11598
11060
|
}
|
|
11599
11061
|
}
|
|
11600
11062
|
|
|
11601
|
-
//
|
|
11063
|
+
// ../core/src/lsp/protocol.ts
|
|
11602
11064
|
var HEADER_SEPARATOR = `\r
|
|
11603
11065
|
\r
|
|
11604
11066
|
`;
|
|
@@ -11644,7 +11106,7 @@ function isJsonRpcNotification3(value) {
|
|
|
11644
11106
|
return typeof value === "object" && value !== null && "jsonrpc" in value && !("id" in value) && typeof value.method === "string";
|
|
11645
11107
|
}
|
|
11646
11108
|
|
|
11647
|
-
//
|
|
11109
|
+
// ../core/src/lsp/client.ts
|
|
11648
11110
|
class LspClientError extends Error {
|
|
11649
11111
|
constructor(message) {
|
|
11650
11112
|
super(message);
|
|
@@ -11855,7 +11317,7 @@ function toLocations(result) {
|
|
|
11855
11317
|
return candidates.filter((candidate) => typeof candidate === "object" && candidate !== null && typeof candidate.uri === "string" && typeof candidate.range === "object");
|
|
11856
11318
|
}
|
|
11857
11319
|
|
|
11858
|
-
//
|
|
11320
|
+
// ../core/src/lsp/servers.ts
|
|
11859
11321
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
11860
11322
|
var LANGUAGE_SERVERS = [
|
|
11861
11323
|
{
|
|
@@ -11996,7 +11458,7 @@ function defaultProbe(command) {
|
|
|
11996
11458
|
});
|
|
11997
11459
|
}
|
|
11998
11460
|
|
|
11999
|
-
//
|
|
11461
|
+
// ../core/src/cli/edit-diagnostics.ts
|
|
12000
11462
|
var DEFAULT_TIMEOUT_MS = 1500;
|
|
12001
11463
|
var DEFAULT_REFINE_MS = 250;
|
|
12002
11464
|
var DEFAULT_MAX_LINES = 20;
|
|
@@ -12217,7 +11679,7 @@ function createLspEditDiagnostics(root, options = {}) {
|
|
|
12217
11679
|
});
|
|
12218
11680
|
}
|
|
12219
11681
|
|
|
12220
|
-
//
|
|
11682
|
+
// ../core/src/providers/price-catalog.ts
|
|
12221
11683
|
var ANTHROPIC_VERIFIED = "2026-06-24";
|
|
12222
11684
|
var ANTHROPIC_SOURCE = "anthropic.com/pricing, recorded 2026-06-24";
|
|
12223
11685
|
var ANTHROPIC = [
|
|
@@ -12269,7 +11731,7 @@ var SERVICES = [
|
|
|
12269
11731
|
];
|
|
12270
11732
|
var PRICE_CATALOG = definePrices([...ANTHROPIC, ...OAI_COMPAT_LABS, ...SERVICES]);
|
|
12271
11733
|
|
|
12272
|
-
//
|
|
11734
|
+
// ../core/src/providers/free-catalog.ts
|
|
12273
11735
|
var FREE_ROUTER = "openrouter/free";
|
|
12274
11736
|
var FREE_BASE_URL = "https://openrouter.ai/api/v1";
|
|
12275
11737
|
var FREE_GATEWAY_URL = "";
|
|
@@ -12278,6 +11740,7 @@ var FREE_CATALOG_TTL_MS = 6 * 60 * 60 * 1000;
|
|
|
12278
11740
|
var FREE_CATALOG_MAX_RECORDS = 1e4;
|
|
12279
11741
|
var FREE_ROUTER_PREFERENCE = [
|
|
12280
11742
|
"cohere/north-mini-code:free",
|
|
11743
|
+
"nvidia/nemotron-3-super-120b-a12b:free",
|
|
12281
11744
|
"google/gemma-4-31b-it:free",
|
|
12282
11745
|
"dots-studio/dots-3-note-preview:free",
|
|
12283
11746
|
"nex-agi/nex-n2.5-pro:free",
|
|
@@ -12404,8 +11867,21 @@ function mergeFreeCatalog(live, discovery, fetchedAt, warnings = []) {
|
|
|
12404
11867
|
}
|
|
12405
11868
|
return { fetchedAt, models: [...byId.values()].sort((a, b) => a.id.localeCompare(b.id)), warnings };
|
|
12406
11869
|
}
|
|
11870
|
+
var SMALL_MODEL_BILLIONS = 4;
|
|
11871
|
+
function modelSizeBillions(model) {
|
|
11872
|
+
const id = model.toLowerCase();
|
|
11873
|
+
const billions = [...id.matchAll(/(?:^|[^a-z0-9.])(\d+(?:\.\d+)?)b(?![a-z])/g)];
|
|
11874
|
+
if (billions.length > 0)
|
|
11875
|
+
return Math.min(...billions.map((match) => Number(match[1])));
|
|
11876
|
+
const millions = id.match(/(?:^|[^a-z0-9.])(\d+(?:\.\d+)?)m(?![a-z])/);
|
|
11877
|
+
return millions ? Number(millions[1]) / 1000 : null;
|
|
11878
|
+
}
|
|
11879
|
+
function isSmallModel(model) {
|
|
11880
|
+
const size = modelSizeBillions(model);
|
|
11881
|
+
return size !== null && size <= SMALL_MODEL_BILLIONS;
|
|
11882
|
+
}
|
|
12407
11883
|
|
|
12408
|
-
//
|
|
11884
|
+
// ../core/src/providers/provider-specs.ts
|
|
12409
11885
|
var PROVIDER_IDS = [
|
|
12410
11886
|
"anthropic",
|
|
12411
11887
|
"openai",
|
|
@@ -12466,7 +11942,7 @@ var PROVIDER_INFO = {
|
|
|
12466
11942
|
}
|
|
12467
11943
|
};
|
|
12468
11944
|
|
|
12469
|
-
//
|
|
11945
|
+
// ../core/src/providers/anthropic-agent.ts
|
|
12470
11946
|
async function collectAnthropicStream(stream, onTextDelta, onOutputProgress) {
|
|
12471
11947
|
let id = "";
|
|
12472
11948
|
let model = "";
|
|
@@ -12625,7 +12101,7 @@ class AnthropicAgentTurnProvider {
|
|
|
12625
12101
|
let client;
|
|
12626
12102
|
this.call = async (body, signal) => {
|
|
12627
12103
|
if (!client) {
|
|
12628
|
-
const { default: Anthropic } = await import("./index-
|
|
12104
|
+
const { default: Anthropic } = await import("./index-qvgcwsvm.mjs").catch(() => {
|
|
12629
12105
|
throw new Error("The Anthropic provider needs the @anthropic-ai/sdk package. Install it with: npm install @anthropic-ai/sdk");
|
|
12630
12106
|
});
|
|
12631
12107
|
client = new Anthropic({ apiKey: options.apiKey, ...options.baseURL ? { baseURL: options.baseURL } : {}, maxRetries: 0 });
|
|
@@ -12645,7 +12121,7 @@ class AnthropicAgentTurnProvider {
|
|
|
12645
12121
|
...system ? { system } : {},
|
|
12646
12122
|
messages,
|
|
12647
12123
|
tools,
|
|
12648
|
-
...request.effort && this.capabilities.supportsEffort ? { output_config: { effort: request.effort } } : {},
|
|
12124
|
+
...request.effort && this.capabilities.supportsEffort ? { output_config: { effort: providerEffort(request.effort) } } : {},
|
|
12649
12125
|
metadata: { user_id: request.safetyIdentifier },
|
|
12650
12126
|
stream: true
|
|
12651
12127
|
};
|
|
@@ -12687,10 +12163,10 @@ class AnthropicAgentTurnProvider {
|
|
|
12687
12163
|
}
|
|
12688
12164
|
}
|
|
12689
12165
|
|
|
12690
|
-
//
|
|
12691
|
-
import { createHash as
|
|
12166
|
+
// ../core/src/providers/archymedes-cloud-agent.ts
|
|
12167
|
+
import { createHash as createHash8, randomUUID as randomUUID5 } from "node:crypto";
|
|
12692
12168
|
|
|
12693
|
-
//
|
|
12169
|
+
// ../core/src/providers/routing-plan.ts
|
|
12694
12170
|
function isRecord2(value) {
|
|
12695
12171
|
return typeof value === "object" && value !== null;
|
|
12696
12172
|
}
|
|
@@ -12762,7 +12238,7 @@ function planCurrency(ranked) {
|
|
|
12762
12238
|
return;
|
|
12763
12239
|
}
|
|
12764
12240
|
|
|
12765
|
-
//
|
|
12241
|
+
// ../core/src/providers/credit-balance.ts
|
|
12766
12242
|
function isRecord3(value) {
|
|
12767
12243
|
return typeof value === "object" && value !== null;
|
|
12768
12244
|
}
|
|
@@ -12797,7 +12273,7 @@ function parseCreditBalance(value) {
|
|
|
12797
12273
|
};
|
|
12798
12274
|
}
|
|
12799
12275
|
|
|
12800
|
-
//
|
|
12276
|
+
// ../core/src/providers/archymedes-cloud-agent.ts
|
|
12801
12277
|
class ArchymedesCloudError extends Error {
|
|
12802
12278
|
status;
|
|
12803
12279
|
code;
|
|
@@ -12863,7 +12339,7 @@ class ArchymedesCloudTurnProvider {
|
|
|
12863
12339
|
this.planUrl = base.endsWith("/v1") ? `${base}/routes/plan` : `${base}/v1/routes/plan`;
|
|
12864
12340
|
this.balanceUrl = base.endsWith("/v1") ? `${base}/credits/balance` : `${base}/v1/credits/balance`;
|
|
12865
12341
|
this.capabilities = capabilitiesFor(this.model);
|
|
12866
|
-
this.recoveryScope =
|
|
12342
|
+
this.recoveryScope = createHash8("sha256").update(JSON.stringify({
|
|
12867
12343
|
version: 1,
|
|
12868
12344
|
endpoint: this.completionUrl,
|
|
12869
12345
|
token: options.token,
|
|
@@ -12946,7 +12422,7 @@ class ArchymedesCloudTurnProvider {
|
|
|
12946
12422
|
async exchange(request, recoveryOnly) {
|
|
12947
12423
|
if (!request.safetyIdentifier.trim())
|
|
12948
12424
|
throw new Error("safetyIdentifier is required");
|
|
12949
|
-
const taskId = request.requestId ?? `cli_${
|
|
12425
|
+
const taskId = request.requestId ?? `cli_${randomUUID5()}`;
|
|
12950
12426
|
if (!/^[A-Za-z0-9_-]{1,160}$/.test(taskId))
|
|
12951
12427
|
throw new Error("requestId must contain 1 to 160 letters, numbers, underscores or hyphens");
|
|
12952
12428
|
request.signal?.throwIfAborted();
|
|
@@ -12973,7 +12449,7 @@ class ArchymedesCloudTurnProvider {
|
|
|
12973
12449
|
max_completion_tokens: request.maxOutputTokens,
|
|
12974
12450
|
safety_identifier: request.safetyIdentifier,
|
|
12975
12451
|
prompt_cache_key: request.safetyIdentifier,
|
|
12976
|
-
...request.effort ? { reasoning_effort: request.effort } : {},
|
|
12452
|
+
...request.effort ? { reasoning_effort: providerEffort(request.effort) } : {},
|
|
12977
12453
|
stream: false,
|
|
12978
12454
|
archymedes: {
|
|
12979
12455
|
task_id: taskId,
|
|
@@ -13014,7 +12490,7 @@ async function readBody(response) {
|
|
|
13014
12490
|
}
|
|
13015
12491
|
}
|
|
13016
12492
|
|
|
13017
|
-
//
|
|
12493
|
+
// ../core/src/providers/request-pacer.ts
|
|
13018
12494
|
var DEFAULTS = { baseGapMs: 2000, maxGapMs: 120000, releaseMs: 500 };
|
|
13019
12495
|
|
|
13020
12496
|
class RequestPacer {
|
|
@@ -13023,12 +12499,17 @@ class RequestPacer {
|
|
|
13023
12499
|
baseGapMs;
|
|
13024
12500
|
maxGapMs;
|
|
13025
12501
|
releaseMs;
|
|
12502
|
+
windowMs;
|
|
12503
|
+
cap;
|
|
12504
|
+
starts = [];
|
|
13026
12505
|
now;
|
|
13027
12506
|
sleep;
|
|
13028
12507
|
constructor(options = {}) {
|
|
13029
12508
|
this.baseGapMs = options.baseGapMs ?? DEFAULTS.baseGapMs;
|
|
13030
12509
|
this.maxGapMs = options.maxGapMs ?? DEFAULTS.maxGapMs;
|
|
13031
12510
|
this.releaseMs = options.releaseMs ?? DEFAULTS.releaseMs;
|
|
12511
|
+
this.windowMs = options.windowMs ?? 60000;
|
|
12512
|
+
this.cap = options.windowCap !== undefined && options.windowCap >= 1 ? Math.floor(options.windowCap) : undefined;
|
|
13032
12513
|
this.now = options.now ?? Date.now;
|
|
13033
12514
|
this.sleep = options.sleep ?? ((delayMs, signal) => new Promise((resolve, reject) => {
|
|
13034
12515
|
if (signal?.aborted) {
|
|
@@ -13046,33 +12527,61 @@ class RequestPacer {
|
|
|
13046
12527
|
signal?.addEventListener("abort", onAbort, { once: true });
|
|
13047
12528
|
}));
|
|
13048
12529
|
}
|
|
12530
|
+
get windowBudget() {
|
|
12531
|
+
return this.cap;
|
|
12532
|
+
}
|
|
12533
|
+
get inWindow() {
|
|
12534
|
+
this.prune(this.now());
|
|
12535
|
+
return this.starts.length;
|
|
12536
|
+
}
|
|
12537
|
+
prune(now) {
|
|
12538
|
+
let drop = 0;
|
|
12539
|
+
while (drop < this.starts.length && now - this.starts[drop] >= this.windowMs)
|
|
12540
|
+
drop += 1;
|
|
12541
|
+
if (drop > 0)
|
|
12542
|
+
this.starts.splice(0, drop);
|
|
12543
|
+
}
|
|
13049
12544
|
get paceMs() {
|
|
13050
12545
|
return this.gapMs;
|
|
13051
12546
|
}
|
|
13052
12547
|
async wait(signal) {
|
|
13053
12548
|
signal?.throwIfAborted();
|
|
13054
|
-
if (this.
|
|
13055
|
-
|
|
13056
|
-
|
|
12549
|
+
if (this.cap !== undefined) {
|
|
12550
|
+
for (;; ) {
|
|
12551
|
+
const now = this.now();
|
|
12552
|
+
this.prune(now);
|
|
12553
|
+
if (this.starts.length < this.cap)
|
|
12554
|
+
break;
|
|
12555
|
+
await this.sleep(this.starts[0] + this.windowMs - now + 25, signal);
|
|
12556
|
+
signal?.throwIfAborted();
|
|
12557
|
+
}
|
|
12558
|
+
}
|
|
12559
|
+
if (this.gapMs > 0) {
|
|
12560
|
+
const remaining = this.gapMs - (this.now() - this.lastStart);
|
|
12561
|
+
if (remaining > 0)
|
|
12562
|
+
await this.sleep(remaining, signal);
|
|
12563
|
+
signal?.throwIfAborted();
|
|
13057
12564
|
}
|
|
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
12565
|
this.lastStart = this.now();
|
|
12566
|
+
this.starts.push(this.lastStart);
|
|
12567
|
+
if (this.starts.length > 512)
|
|
12568
|
+
this.starts.splice(0, this.starts.length - 512);
|
|
13064
12569
|
}
|
|
13065
12570
|
reportSuccess() {
|
|
13066
12571
|
this.gapMs = Math.max(0, this.gapMs - this.releaseMs);
|
|
13067
12572
|
}
|
|
13068
12573
|
reportRateLimited(retryAfterMs) {
|
|
12574
|
+
this.prune(this.now());
|
|
12575
|
+
const admitted = this.starts.length - 1;
|
|
12576
|
+
if (admitted >= 2)
|
|
12577
|
+
this.cap = Math.min(this.cap ?? Number.POSITIVE_INFINITY, admitted);
|
|
13069
12578
|
const doubled = this.gapMs <= 0 ? this.baseGapMs : Math.min(this.maxGapMs, this.gapMs * 2);
|
|
13070
12579
|
const asked = typeof retryAfterMs === "number" && Number.isFinite(retryAfterMs) && retryAfterMs > 0 ? retryAfterMs : 0;
|
|
13071
12580
|
this.gapMs = Math.min(this.maxGapMs, Math.max(doubled, Math.min(this.maxGapMs, asked)));
|
|
13072
12581
|
}
|
|
13073
12582
|
}
|
|
13074
12583
|
|
|
13075
|
-
//
|
|
12584
|
+
// ../core/src/providers/free-catalog-fetch.ts
|
|
13076
12585
|
var MAX_BYTES = 8 * 1024 * 1024;
|
|
13077
12586
|
async function boundedJson(fetchImpl, url, signal) {
|
|
13078
12587
|
const response = await fetchImpl(url, { signal, redirect: "error", headers: { accept: "application/json" } });
|
|
@@ -13136,7 +12645,7 @@ async function fetchFreeCatalog(options = {}) {
|
|
|
13136
12645
|
}
|
|
13137
12646
|
}
|
|
13138
12647
|
|
|
13139
|
-
//
|
|
12648
|
+
// ../core/src/providers/free-install.ts
|
|
13140
12649
|
import { promises as fs12 } from "node:fs";
|
|
13141
12650
|
import path17 from "node:path";
|
|
13142
12651
|
var FREE_INSTALL_HEADER = "x-archymedes-install";
|
|
@@ -13314,7 +12823,7 @@ class FreeInstallToken {
|
|
|
13314
12823
|
}
|
|
13315
12824
|
}
|
|
13316
12825
|
|
|
13317
|
-
//
|
|
12826
|
+
// ../core/src/providers/free-errors.ts
|
|
13318
12827
|
var OPENROUTER_PRIVACY_SETTINGS_URL = "https://openrouter.ai/settings/privacy";
|
|
13319
12828
|
var OPENROUTER_KEYS_URL = "https://openrouter.ai/keys";
|
|
13320
12829
|
var OPENROUTER_CREDITS_URL = "https://openrouter.ai/settings/credits";
|
|
@@ -13390,7 +12899,7 @@ function describeFreeFailure(input) {
|
|
|
13390
12899
|
return { message, retryable: transient, ...retryAfterMs2 ? { retryAfterMs: retryAfterMs2 } : {} };
|
|
13391
12900
|
}
|
|
13392
12901
|
|
|
13393
|
-
//
|
|
12902
|
+
// ../core/src/providers/free-health.ts
|
|
13394
12903
|
import { promises as fs13 } from "node:fs";
|
|
13395
12904
|
import path18 from "node:path";
|
|
13396
12905
|
var FREE_HEALTH_WINDOW_MS = 7 * 24 * 60 * 60 * 1000;
|
|
@@ -13443,7 +12952,7 @@ function recordFreeOutcome(records, id, outcome, now) {
|
|
|
13443
12952
|
return Object.fromEntries(newest);
|
|
13444
12953
|
}
|
|
13445
12954
|
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);
|
|
12955
|
+
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
12956
|
}
|
|
13448
12957
|
function fileFreeHealthStore(file) {
|
|
13449
12958
|
return {
|
|
@@ -13499,7 +13008,7 @@ class FreeHealthTracker {
|
|
|
13499
13008
|
}
|
|
13500
13009
|
}
|
|
13501
13010
|
|
|
13502
|
-
//
|
|
13011
|
+
// ../core/src/providers/openrouter-key-info.ts
|
|
13503
13012
|
var OPENROUTER_KEY_URL = `${FREE_BASE_URL}/key`;
|
|
13504
13013
|
var OPENROUTER_KEY_INFO_TTL_MS = 60000;
|
|
13505
13014
|
var KEY_INFO_TIMEOUT_MS = 5000;
|
|
@@ -13602,7 +13111,7 @@ function nextUtcMidnight(now) {
|
|
|
13602
13111
|
return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate() + 1)).toISOString();
|
|
13603
13112
|
}
|
|
13604
13113
|
|
|
13605
|
-
//
|
|
13114
|
+
// ../core/src/providers/tool-call-repair.ts
|
|
13606
13115
|
function isObject(value) {
|
|
13607
13116
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
13608
13117
|
}
|
|
@@ -13712,7 +13221,7 @@ function repairToolCalls(calls) {
|
|
|
13712
13221
|
});
|
|
13713
13222
|
}
|
|
13714
13223
|
|
|
13715
|
-
//
|
|
13224
|
+
// ../core/src/providers/free-agent.ts
|
|
13716
13225
|
var RETRYABLE_UPSTREAM_TYPES = new Set(["upstream_timeout", "upstream_idle_timeout", "upstream_unreachable", "upstream_stream_failed"]);
|
|
13717
13226
|
function freeFailureStatus(error) {
|
|
13718
13227
|
const record2 = error;
|
|
@@ -13730,6 +13239,12 @@ function isTransportFailure(error) {
|
|
|
13730
13239
|
const name = error?.name;
|
|
13731
13240
|
return error instanceof APIConnectionError || name === "APIConnectionError" || name === "APIConnectionTimeoutError" || error instanceof TypeError || Boolean(error?.cause);
|
|
13732
13241
|
}
|
|
13242
|
+
function openRouterEffort(effort) {
|
|
13243
|
+
if (!effort)
|
|
13244
|
+
return;
|
|
13245
|
+
return effort === "xhigh" || effort === "max" ? "high" : effort;
|
|
13246
|
+
}
|
|
13247
|
+
var FREE_REQUESTS_PER_MINUTE = 20;
|
|
13733
13248
|
var MAX_ROUTER_ATTEMPTS = 4;
|
|
13734
13249
|
var CATALOG_TIMEOUT_MS = 15000;
|
|
13735
13250
|
var FREE_CANDIDATE_FIRST_BYTE_TIMEOUT_MS = 45000;
|
|
@@ -13778,7 +13293,7 @@ class FreeAgentTurnProvider {
|
|
|
13778
13293
|
this.options = options;
|
|
13779
13294
|
this.dependencies = dependencies;
|
|
13780
13295
|
this.selection = { provider: "free", model: options.model };
|
|
13781
|
-
this.pacer = dependencies.pacer ?? new RequestPacer;
|
|
13296
|
+
this.pacer = dependencies.pacer ?? new RequestPacer({ windowCap: FREE_REQUESTS_PER_MINUTE });
|
|
13782
13297
|
this.tokenSaver = options.tokenSaver ?? true;
|
|
13783
13298
|
const usage = dependencies.usage === undefined ? dependencies.call || dependencies.catalog ? undefined : new FreeUsageMeter(fileFreeUsageStore(freeUsageFile(process.env)), dependencies.now) : dependencies.usage ?? undefined;
|
|
13784
13299
|
if (usage)
|
|
@@ -13839,7 +13354,9 @@ class FreeAgentTurnProvider {
|
|
|
13839
13354
|
}
|
|
13840
13355
|
const eligible = this.catalog.models.filter((model) => model.eligible && isFreeModelId(model.id));
|
|
13841
13356
|
const selected = eligible.find((model) => model.id === this.options.model);
|
|
13842
|
-
const
|
|
13357
|
+
const routable = eligible.filter((model) => model.id !== FREE_ROUTER);
|
|
13358
|
+
const capable = routable.filter((model) => !isSmallModel(model.id));
|
|
13359
|
+
const candidates = this.options.model === FREE_ROUTER ? capable.length > 0 ? capable : routable : selected ? [selected] : [];
|
|
13843
13360
|
if (!candidates.length)
|
|
13844
13361
|
throw new FreeAccessError("No eligible free tool model is available. Run /models refresh or try again later.");
|
|
13845
13362
|
const messages = toWireMessages(request.messages);
|
|
@@ -13944,6 +13461,7 @@ class FreeAgentTurnProvider {
|
|
|
13944
13461
|
messages: withOpenRouterCacheControl(messages, model),
|
|
13945
13462
|
max_tokens: output,
|
|
13946
13463
|
...request.tools.length ? { tools: request.tools.map((tool) => ({ type: "function", function: { name: tool.name, description: tool.description, parameters: tool.inputSchema } })) } : {},
|
|
13464
|
+
...openRouterEffort(request.effort) ? { reasoning: { effort: openRouterEffort(request.effort) } } : {},
|
|
13947
13465
|
provider: { require_parameters: true, max_price: { prompt: 0, completion: 0 }, allow_fallbacks: false },
|
|
13948
13466
|
stream: true,
|
|
13949
13467
|
stream_options: { include_usage: true }
|
|
@@ -13978,7 +13496,7 @@ class FreeAgentTurnProvider {
|
|
|
13978
13496
|
}
|
|
13979
13497
|
}
|
|
13980
13498
|
|
|
13981
|
-
//
|
|
13499
|
+
// ../core/src/providers/openrouter-agent.ts
|
|
13982
13500
|
var OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
|
|
13983
13501
|
|
|
13984
13502
|
class OpenRouterAgentTurnProvider {
|
|
@@ -14027,7 +13545,7 @@ function withHint(error) {
|
|
|
14027
13545
|
return wrapped;
|
|
14028
13546
|
}
|
|
14029
13547
|
|
|
14030
|
-
//
|
|
13548
|
+
// ../core/src/providers/agent-matrix.ts
|
|
14031
13549
|
var OPENAI_COMPATIBLE_BASE_URL = {
|
|
14032
13550
|
google: "https://generativelanguage.googleapis.com/v1beta/openai/",
|
|
14033
13551
|
xai: "https://api.x.ai/v1",
|
|
@@ -14192,7 +13710,7 @@ function describeProviders(environment) {
|
|
|
14192
13710
|
}
|
|
14193
13711
|
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
13712
|
|
|
14195
|
-
//
|
|
13713
|
+
// src/app/session-provider.ts
|
|
14196
13714
|
async function resolveSessionProvider(environment, options) {
|
|
14197
13715
|
if (options.provider || !options.resume)
|
|
14198
13716
|
return resolveProvider(environment, options);
|
|
@@ -14201,12 +13719,12 @@ async function resolveSessionProvider(environment, options) {
|
|
|
14201
13719
|
return resolveProvider(environment, selection?.provider === "free" ? { provider: "free", model: options.model ?? selection.model } : options);
|
|
14202
13720
|
}
|
|
14203
13721
|
|
|
14204
|
-
//
|
|
13722
|
+
// src/platform/settings.ts
|
|
14205
13723
|
import { promises as fs15 } from "node:fs";
|
|
14206
13724
|
import os4 from "node:os";
|
|
14207
13725
|
import path20 from "node:path";
|
|
14208
13726
|
|
|
14209
|
-
//
|
|
13727
|
+
// src/platform/i18n.ts
|
|
14210
13728
|
var CONTROL_LANGUAGES = {
|
|
14211
13729
|
en: "English",
|
|
14212
13730
|
zh: "中文 (Mandarin)",
|
|
@@ -14673,11 +14191,11 @@ function t(language, key) {
|
|
|
14673
14191
|
return MESSAGES[key][language] ?? MESSAGES[key].en;
|
|
14674
14192
|
}
|
|
14675
14193
|
|
|
14676
|
-
//
|
|
14194
|
+
// src/platform/local-currency.ts
|
|
14677
14195
|
import { promises as fs14 } from "node:fs";
|
|
14678
14196
|
import path19 from "node:path";
|
|
14679
14197
|
|
|
14680
|
-
//
|
|
14198
|
+
// src/platform/endpoints.ts
|
|
14681
14199
|
var FX_ENDPOINTS = [
|
|
14682
14200
|
"https://cdn.jsdelivr.net/npm/@fawazahmed0/currency-api@latest/v1/currencies",
|
|
14683
14201
|
"https://latest.currency-api.pages.dev/v1/currencies"
|
|
@@ -14721,7 +14239,7 @@ function hostOf(url) {
|
|
|
14721
14239
|
}
|
|
14722
14240
|
}
|
|
14723
14241
|
|
|
14724
|
-
//
|
|
14242
|
+
// src/platform/network.ts
|
|
14725
14243
|
var CODES = {
|
|
14726
14244
|
dns: ["ENOTFOUND", "EAI_AGAIN", "EAI_NONAME", "EAI_FAIL", "EAI_MEMORY", "EAI_SYSTEM", "DNS_E_NAME_NOT_FOUND", "DNS_E_QUERY_PENDING"],
|
|
14727
14245
|
timeout: ["ETIMEDOUT", "UND_ERR_CONNECT_TIMEOUT", "UND_ERR_HEADERS_TIMEOUT", "UND_ERR_BODY_TIMEOUT", "ERR_SOCKET_CONNECTION_TIMEOUT", "connection_timeout"],
|
|
@@ -14970,7 +14488,7 @@ function classifyNetworkError(error, options = {}) {
|
|
|
14970
14488
|
return null;
|
|
14971
14489
|
}
|
|
14972
14490
|
|
|
14973
|
-
//
|
|
14491
|
+
// src/platform/local-currency.ts
|
|
14974
14492
|
var COUNTRY_CURRENCIES = {
|
|
14975
14493
|
RW: "RWF",
|
|
14976
14494
|
EG: "EGP",
|
|
@@ -15098,7 +14616,7 @@ async function startFxRateLookup(from, to, options) {
|
|
|
15098
14616
|
return { immediate: cached?.rate ?? null, refresh };
|
|
15099
14617
|
}
|
|
15100
14618
|
|
|
15101
|
-
//
|
|
14619
|
+
// src/theme/theme.ts
|
|
15102
14620
|
var BLUEPRINT = `
|
|
15103
14621
|
/* Blueprint navy, chalk-white ink and an amber pencil — the original drafting table. */
|
|
15104
14622
|
@theme blueprint {
|
|
@@ -15400,7 +14918,7 @@ function roleCode(role, palette, depth) {
|
|
|
15400
14918
|
}
|
|
15401
14919
|
var NO_COLOR_PALETTE = buildPalette(findBuiltinTheme(DEFAULT_THEME_NAME) ?? { name: DEFAULT_THEME_NAME, description: "", tokens: DEFAULT_TOKENS }, "none");
|
|
15402
14920
|
|
|
15403
|
-
//
|
|
14921
|
+
// src/platform/settings.ts
|
|
15404
14922
|
var LANGUAGE_NAMES = {
|
|
15405
14923
|
en: "English",
|
|
15406
14924
|
zh: "中文",
|
|
@@ -15504,6 +15022,13 @@ var AUTOSAVE_CHOICES = [
|
|
|
15504
15022
|
{ value: "off", label: "Off — save with Ctrl+S (default)" },
|
|
15505
15023
|
{ value: "on", label: "On — save a second after you stop typing" }
|
|
15506
15024
|
];
|
|
15025
|
+
var REASONING_CHOICES = [
|
|
15026
|
+
{ value: "auto", label: "Auto (experimental) — lower the effort on routine steps, leave hard ones to the model" },
|
|
15027
|
+
{ value: "minimal", label: "Minimal — never think more than needed" },
|
|
15028
|
+
{ value: "low", label: "Low" },
|
|
15029
|
+
{ value: "medium", label: "Medium" },
|
|
15030
|
+
{ value: "high", label: "High — slowest" }
|
|
15031
|
+
];
|
|
15507
15032
|
var PROVIDER_CHOICES = PROVIDER_IDS.map((id) => ({ value: id, label: PROVIDER_INFO[id].label }));
|
|
15508
15033
|
var SETTING_FIELDS = [
|
|
15509
15034
|
{ key: "ARCHYMEDES_THEME", label: "Theme — colours for the whole CLI (/theme <name> also saves it)", choices: THEME_CHOICES, section: "Appearance" },
|
|
@@ -15511,6 +15036,7 @@ var SETTING_FIELDS = [
|
|
|
15511
15036
|
{ key: "ARCHYMEDES_CODE_LINE_NUMBERS", label: "Line numbers in code blocks", choices: SHOW_HIDE_CHOICES },
|
|
15512
15037
|
{ key: "ARCHYMEDES_SIMPLE", label: "Simple mode — quiet start, short help", choices: SIMPLE_CHOICES },
|
|
15513
15038
|
{ key: "ARCHYMEDES_LANGUAGE", label: "Control language", choices: LANGUAGE_CHOICES },
|
|
15039
|
+
{ key: "ARCHYMEDES_REASONING", label: "Reasoning effort — clear it to leave each model at its own default", choices: REASONING_CHOICES },
|
|
15514
15040
|
{ key: "ARCHYMEDES_RESUME", label: "Continue your last chat at startup", choices: RESUME_CHOICES, section: "Behaviour" },
|
|
15515
15041
|
{ key: "ARCHYMEDES_EDITOR_AUTOSAVE", label: "Auto-save in /edit", choices: AUTOSAVE_CHOICES },
|
|
15516
15042
|
{ key: "ARCHYMEDES_SUGGEST_MODEL", label: "Ask the model for extra suggestions (a small extra call per turn)", choices: ON_OFF_CHOICES },
|
|
@@ -15655,7 +15181,8 @@ var ENUM_SETTINGS = {
|
|
|
15655
15181
|
ARCHYMEDES_RESUME: ["ask", "always", "never"],
|
|
15656
15182
|
ARCHYMEDES_EDITOR_AUTOSAVE: ["on", "off"],
|
|
15657
15183
|
ARCHYMEDES_SUGGEST_MODEL: ["on", "off"],
|
|
15658
|
-
ARCHYMEDES_AUTO_UPDATE: ["install", "check", "off"]
|
|
15184
|
+
ARCHYMEDES_AUTO_UPDATE: ["install", "check", "off"],
|
|
15185
|
+
ARCHYMEDES_REASONING: ["auto", "minimal", "low", "medium", "high"]
|
|
15659
15186
|
};
|
|
15660
15187
|
var SETTING_CANCELLED = "\x00cancelled";
|
|
15661
15188
|
function validateSetting(key, raw) {
|
|
@@ -15892,7 +15419,7 @@ Archymedes ${controlLabel(language, "settings")}
|
|
|
15892
15419
|
}
|
|
15893
15420
|
}
|
|
15894
15421
|
|
|
15895
|
-
//
|
|
15422
|
+
// src/app/free-setup.ts
|
|
15896
15423
|
var OPENROUTER_KEYS_URL2 = "https://openrouter.ai/keys";
|
|
15897
15424
|
var FREE_PRIVACY_NOTICE = "Free models may log your prompts and code; don't send secrets. Use a paid provider for private code.";
|
|
15898
15425
|
function needsFreePrivacyNotice(environment) {
|
|
@@ -15911,7 +15438,7 @@ async function showFreePrivacyNoticeOnce(options) {
|
|
|
15911
15438
|
return next;
|
|
15912
15439
|
}
|
|
15913
15440
|
|
|
15914
|
-
//
|
|
15441
|
+
// src/app/acp-setup.ts
|
|
15915
15442
|
var KEY_URLS = {
|
|
15916
15443
|
free: OPENROUTER_KEYS_URL2,
|
|
15917
15444
|
openrouter: OPENROUTER_KEYS_URL2,
|
|
@@ -15970,61 +15497,11 @@ async function saveSetup(params, deps) {
|
|
|
15970
15497
|
return { ok: true, file, ...note ? { note } : {} };
|
|
15971
15498
|
}
|
|
15972
15499
|
|
|
15973
|
-
//
|
|
15974
|
-
function modelsForProvider(provider, asOf) {
|
|
15975
|
-
const seen = new Set;
|
|
15976
|
-
for (const record2 of PRICE_CATALOG) {
|
|
15977
|
-
if (record2.provider !== provider || record2.modality !== "text" || record2.billingUnit !== "tokens")
|
|
15978
|
-
continue;
|
|
15979
|
-
seen.add(record2.model);
|
|
15980
|
-
}
|
|
15981
|
-
const fallback = PROVIDERS[provider].defaultModel;
|
|
15982
|
-
seen.add(fallback);
|
|
15983
|
-
const models = [...seen].filter((model) => model !== fallback).sort();
|
|
15984
|
-
return [fallback, ...models];
|
|
15985
|
-
}
|
|
15986
|
-
function buildModelCatalog(environment, asOf, live) {
|
|
15987
|
-
const choices = [];
|
|
15988
|
-
const unconfigured = [];
|
|
15989
|
-
for (const provider of PROVIDER_IDS) {
|
|
15990
|
-
const spec = PROVIDERS[provider];
|
|
15991
|
-
const missing = missingRequirements(provider, environment);
|
|
15992
|
-
if (missing.length > 0) {
|
|
15993
|
-
unconfigured.push({ provider, label: spec.label, missing });
|
|
15994
|
-
continue;
|
|
15995
|
-
}
|
|
15996
|
-
const known = modelsForProvider(provider, asOf);
|
|
15997
|
-
const knownSet = new Set(known);
|
|
15998
|
-
const extra = (live?.[provider] ?? []).filter((model) => !knownSet.has(model) && (provider !== "free" || isFreeModelId(model))).slice().sort();
|
|
15999
|
-
for (const model of [...known, ...extra]) {
|
|
16000
|
-
choices.push({
|
|
16001
|
-
provider,
|
|
16002
|
-
providerLabel: spec.label,
|
|
16003
|
-
model,
|
|
16004
|
-
isProviderDefault: model === (environment[`${providerEnvPrefix(provider)}_MODEL`]?.trim() || spec.defaultModel),
|
|
16005
|
-
prices: catalogPrices(provider, model, asOf),
|
|
16006
|
-
...knownSet.has(model) ? {} : { live: true }
|
|
16007
|
-
});
|
|
16008
|
-
}
|
|
16009
|
-
}
|
|
16010
|
-
return { choices, unconfigured };
|
|
16011
|
-
}
|
|
16012
|
-
function describePrice(prices, display, convert2) {
|
|
16013
|
-
if (!prices)
|
|
16014
|
-
return "unpriced";
|
|
16015
|
-
const input = convert2({ currency: prices.currency, micros: prices.inputPerMillion });
|
|
16016
|
-
const output = convert2({ currency: prices.currency, micros: prices.outputPerMillion });
|
|
16017
|
-
if (!input || !output) {
|
|
16018
|
-
return `${formatMoney(money(prices.inputPerMillion, prices.currency))}/${formatMoney(money(prices.outputPerMillion, prices.currency))} per Mtok`;
|
|
16019
|
-
}
|
|
16020
|
-
return `${formatMoney(input)}/${formatMoney(output)} per Mtok`;
|
|
16021
|
-
}
|
|
16022
|
-
|
|
16023
|
-
// packages/core/src/providers/model-fetch.ts
|
|
15500
|
+
// ../core/src/providers/model-fetch.ts
|
|
16024
15501
|
import { promises as fs16 } from "node:fs";
|
|
16025
15502
|
import path21 from "node:path";
|
|
16026
15503
|
|
|
16027
|
-
//
|
|
15504
|
+
// ../core/src/providers/model-list.ts
|
|
16028
15505
|
function modelsUrl(base) {
|
|
16029
15506
|
const trimmed = base.replace(/\/+$/, "");
|
|
16030
15507
|
return trimmed.endsWith("/v1") ? `${trimmed}/models` : `${trimmed}/v1/models`;
|
|
@@ -16036,10 +15513,8 @@ function modelsEndpoint(provider, environment) {
|
|
|
16036
15513
|
return { url: `${FREE_BASE_URL}/models`, headers: {} };
|
|
16037
15514
|
case "openrouter": {
|
|
16038
15515
|
const key = trimmed(environment.OPENROUTER_API_KEY);
|
|
16039
|
-
if (!key)
|
|
16040
|
-
return;
|
|
16041
15516
|
const base = trimmed(environment.OPENROUTER_BASE_URL) ?? "https://openrouter.ai/api/v1";
|
|
16042
|
-
return { url: modelsUrl(base), headers: { authorization: `Bearer ${key}` } };
|
|
15517
|
+
return { url: modelsUrl(base), headers: key ? { authorization: `Bearer ${key}` } : {} };
|
|
16043
15518
|
}
|
|
16044
15519
|
case "archymedes-cloud":
|
|
16045
15520
|
return;
|
|
@@ -16136,7 +15611,7 @@ function mergeModelLists(known, live) {
|
|
|
16136
15611
|
const added = live.filter((model) => !seen.has(model)).sort();
|
|
16137
15612
|
return [...known, ...added];
|
|
16138
15613
|
}
|
|
16139
|
-
//
|
|
15614
|
+
// ../core/src/providers/model-fetch.ts
|
|
16140
15615
|
async function fetchProviderModels(provider, environment, fetchImpl, timeoutMs = 4000) {
|
|
16141
15616
|
if (provider === "free") {
|
|
16142
15617
|
try {
|
|
@@ -16224,51 +15699,83 @@ function fetchableProviders(environment, providers) {
|
|
|
16224
15699
|
return providers.filter((provider) => provider !== "archymedes-cloud" && missingRequirements(provider, environment).length === 0);
|
|
16225
15700
|
}
|
|
16226
15701
|
|
|
16227
|
-
//
|
|
16228
|
-
function
|
|
16229
|
-
|
|
16230
|
-
|
|
16231
|
-
if (
|
|
16232
|
-
|
|
16233
|
-
|
|
16234
|
-
|
|
16235
|
-
|
|
16236
|
-
|
|
16237
|
-
|
|
16238
|
-
|
|
16239
|
-
};
|
|
15702
|
+
// src/session/models.ts
|
|
15703
|
+
function modelsForProvider(provider, asOf) {
|
|
15704
|
+
const seen = new Set;
|
|
15705
|
+
for (const record2 of PRICE_CATALOG) {
|
|
15706
|
+
if (record2.provider !== provider || record2.modality !== "text" || record2.billingUnit !== "tokens")
|
|
15707
|
+
continue;
|
|
15708
|
+
seen.add(record2.model);
|
|
15709
|
+
}
|
|
15710
|
+
const fallback = PROVIDERS[provider].defaultModel;
|
|
15711
|
+
seen.add(fallback);
|
|
15712
|
+
const models = [...seen].filter((model) => model !== fallback).sort();
|
|
15713
|
+
return [fallback, ...models];
|
|
16240
15714
|
}
|
|
16241
|
-
|
|
16242
|
-
|
|
16243
|
-
|
|
16244
|
-
|
|
15715
|
+
function describePrice(prices, display, convert2) {
|
|
15716
|
+
if (!prices)
|
|
15717
|
+
return "unpriced";
|
|
15718
|
+
const input = convert2({ currency: prices.currency, micros: prices.inputPerMillion });
|
|
15719
|
+
const output = convert2({ currency: prices.currency, micros: prices.outputPerMillion });
|
|
15720
|
+
if (!input || !output) {
|
|
15721
|
+
return `${formatMoney(money(prices.inputPerMillion, prices.currency))}/${formatMoney(money(prices.outputPerMillion, prices.currency))} per Mtok`;
|
|
15722
|
+
}
|
|
15723
|
+
return `${formatMoney(input)}/${formatMoney(output)} per Mtok`;
|
|
16245
15724
|
}
|
|
16246
15725
|
|
|
16247
|
-
//
|
|
16248
|
-
|
|
16249
|
-
|
|
15726
|
+
// src/app/acp-models.ts
|
|
15727
|
+
var PUBLIC_LISTINGS = ["free", "openrouter"];
|
|
15728
|
+
async function modelList(environment, params, options = {}) {
|
|
15729
|
+
const offline = /^(1|true|on|yes)$/i.test(environment.ARCHYMEDES_MODELS_OFFLINE?.trim() ?? "");
|
|
15730
|
+
const cached = await readModelCache(environment);
|
|
15731
|
+
let live = isCacheFresh(cached, options.now) ? cached.models : undefined;
|
|
16250
15732
|
let errors = [];
|
|
16251
|
-
if (params.refresh === true)
|
|
16252
|
-
|
|
16253
|
-
|
|
16254
|
-
|
|
16255
|
-
|
|
16256
|
-
|
|
16257
|
-
|
|
16258
|
-
|
|
16259
|
-
|
|
16260
|
-
|
|
16261
|
-
|
|
16262
|
-
|
|
16263
|
-
|
|
16264
|
-
|
|
16265
|
-
|
|
16266
|
-
|
|
16267
|
-
|
|
16268
|
-
|
|
15733
|
+
if (params.refresh === true || !live && !offline) {
|
|
15734
|
+
const asked = new Set(fetchableProviders(environment, PROVIDER_IDS));
|
|
15735
|
+
if (!offline)
|
|
15736
|
+
for (const provider of PUBLIC_LISTINGS)
|
|
15737
|
+
asked.add(provider);
|
|
15738
|
+
const loaded = await loadLiveModels([...asked], environment, { refresh: true, ...options });
|
|
15739
|
+
if (Object.keys(loaded.models).length > 0)
|
|
15740
|
+
live = { ...live ?? cached?.models ?? {}, ...loaded.models };
|
|
15741
|
+
errors = loaded.errors.filter((error) => error.provider !== "ollama" || Boolean(environment.OLLAMA_BASE_URL?.trim())).map((error) => `${error.provider}: ${error.error}`);
|
|
15742
|
+
}
|
|
15743
|
+
live ??= cached?.models;
|
|
15744
|
+
const ready = [];
|
|
15745
|
+
const locked = [];
|
|
15746
|
+
const unconfigured = [];
|
|
15747
|
+
const freeIds = new Set(live?.free ?? []);
|
|
15748
|
+
for (const provider of PROVIDER_IDS) {
|
|
15749
|
+
const spec = PROVIDERS[provider];
|
|
15750
|
+
const missing = missingRequirements(provider, environment);
|
|
15751
|
+
if (missing.length > 0)
|
|
15752
|
+
unconfigured.push({ provider, label: spec.label, missing });
|
|
15753
|
+
const known = modelsForProvider(provider);
|
|
15754
|
+
const knownSet = new Set(known);
|
|
15755
|
+
const extra = (live?.[provider] ?? []).filter((model) => !knownSet.has(model) && (provider !== "free" || isFreeModelId(model)) && !(provider === "openrouter" && freeIds.has(model))).sort();
|
|
15756
|
+
const preferred = environment[`${providerEnvPrefix(provider)}_MODEL`]?.trim() || spec.defaultModel;
|
|
15757
|
+
for (const model of [...known, ...extra]) {
|
|
15758
|
+
const prices = catalogPrices(provider, model);
|
|
15759
|
+
const free = provider === "free" || model.endsWith(":free") || Boolean(prices && prices.inputPerMillion === 0 && prices.outputPerMillion === 0);
|
|
15760
|
+
const choice = {
|
|
15761
|
+
provider,
|
|
15762
|
+
providerLabel: spec.label,
|
|
15763
|
+
model,
|
|
15764
|
+
isDefault: model === preferred,
|
|
15765
|
+
live: !knownSet.has(model),
|
|
15766
|
+
price: free ? "free" : prices ? describePrice(prices, prices.currency, (value) => value) : "unpriced",
|
|
15767
|
+
free,
|
|
15768
|
+
locked: missing.length > 0,
|
|
15769
|
+
missing,
|
|
15770
|
+
small: isSmallModel(model)
|
|
15771
|
+
};
|
|
15772
|
+
(choice.locked ? locked : ready).push(choice);
|
|
15773
|
+
}
|
|
15774
|
+
}
|
|
15775
|
+
return { choices: [...ready, ...locked], unconfigured, errors, providers: PROVIDER_IDS.length };
|
|
16269
15776
|
}
|
|
16270
15777
|
|
|
16271
|
-
//
|
|
15778
|
+
// src/app/acp-commands.ts
|
|
16272
15779
|
async function runSessionCommand(command, argument, session) {
|
|
16273
15780
|
switch (command) {
|
|
16274
15781
|
case "cost":
|
|
@@ -16293,15 +15800,115 @@ async function runSessionCommand(command, argument, session) {
|
|
|
16293
15800
|
const items = session.agent.todos.map((item) => ({ text: item.text, status: item.status }));
|
|
16294
15801
|
return items.length > 0 ? { kind: "todos", items } : { kind: "text", text: "No plan yet." };
|
|
16295
15802
|
}
|
|
15803
|
+
case "memory":
|
|
15804
|
+
return memoryCommand(argument, session.agent.workspaceLabel);
|
|
15805
|
+
case "tools": {
|
|
15806
|
+
const { tools } = await session.agent.inspectTools();
|
|
15807
|
+
const lines = tools.map((tool) => `${tool.name.padEnd(24)} ${tool.requiresApproval ? "asks first " : " "}${tool.description.split(/(?<=\.)\s/)[0]}`);
|
|
15808
|
+
return { kind: "text", text: `${tools.length} tools
|
|
15809
|
+
${lines.join(`
|
|
15810
|
+
`)}` };
|
|
15811
|
+
}
|
|
16296
15812
|
default:
|
|
16297
15813
|
return { kind: "error", text: `Unknown session command "${command}".` };
|
|
16298
15814
|
}
|
|
16299
15815
|
}
|
|
15816
|
+
var MEMORY_KINDS = ["preference", "convention", "decision", "lesson", "fact"];
|
|
15817
|
+
async function memoryCommand(argument, root) {
|
|
15818
|
+
const environment = process.env;
|
|
15819
|
+
const [verb = "", ...rest] = argument.trim().split(/\s+/);
|
|
15820
|
+
try {
|
|
15821
|
+
if (verb === "" || verb === "list") {
|
|
15822
|
+
const entries2 = await loadMemories(root, environment);
|
|
15823
|
+
if (entries2.length === 0)
|
|
15824
|
+
return { kind: "text", text: "Nothing remembered yet. /memory add <text> saves a fact for this project." };
|
|
15825
|
+
return { kind: "text", text: entries2.map((entry) => `${entry.scope === "user" ? "user " : "project"} ${entry.index}. [${entry.kind}${entry.pinned ? ", pinned" : ""}] ${entry.text}`).join(`
|
|
15826
|
+
`) };
|
|
15827
|
+
}
|
|
15828
|
+
if (verb === "add") {
|
|
15829
|
+
const scope = rest[0] === "user" ? "user" : "project";
|
|
15830
|
+
if (rest[0] === "user" || rest[0] === "project")
|
|
15831
|
+
rest.shift();
|
|
15832
|
+
const kind = MEMORY_KINDS.find((candidate) => candidate === rest[0]);
|
|
15833
|
+
if (kind)
|
|
15834
|
+
rest.shift();
|
|
15835
|
+
const change = await addMemory(scope, rest.join(" "), root, environment, kind ? { kind } : {});
|
|
15836
|
+
return { kind: "text", text: change.changed ? `Remembered (${scope}).` : "Already remembered, or nothing to add." };
|
|
15837
|
+
}
|
|
15838
|
+
if (verb === "forget") {
|
|
15839
|
+
const scope = rest[0] === "user" ? "user" : "project";
|
|
15840
|
+
const index = Number(rest[rest.length - 1]);
|
|
15841
|
+
if (!Number.isInteger(index))
|
|
15842
|
+
return { kind: "error", text: "/memory forget [user] <number> — see /memory for the numbers." };
|
|
15843
|
+
const change = await forgetMemory(scope, index, root, environment);
|
|
15844
|
+
return { kind: "text", text: change.removed ? `Forgot: ${change.removed.text}` : `No ${scope} memory numbered ${index}.` };
|
|
15845
|
+
}
|
|
15846
|
+
if (verb === "clear") {
|
|
15847
|
+
const scope = rest[0] === "user" ? "user" : "project";
|
|
15848
|
+
return { kind: "text", text: (await clearMemories(scope, root, environment)).changed ? `Cleared ${scope} memory.` : `${scope} memory was already empty.` };
|
|
15849
|
+
}
|
|
15850
|
+
return { kind: "error", text: `/memory takes list, add <text>, forget <n> or clear — not "${verb}".` };
|
|
15851
|
+
} catch (error) {
|
|
15852
|
+
return { kind: "error", text: error instanceof Error ? error.message : String(error) };
|
|
15853
|
+
}
|
|
15854
|
+
}
|
|
15855
|
+
|
|
15856
|
+
// src/app/acp-settings.ts
|
|
15857
|
+
async function listSettings(processEnvironment) {
|
|
15858
|
+
const stored = await loadSettings(processEnvironment);
|
|
15859
|
+
const rows = SETTING_FIELDS.map((field) => {
|
|
15860
|
+
const secret = "secret" in field && field.secret === true;
|
|
15861
|
+
const choices = "choices" in field ? field.choices : undefined;
|
|
15862
|
+
const value = stored[field.key] ?? "";
|
|
15863
|
+
return {
|
|
15864
|
+
key: field.key,
|
|
15865
|
+
label: field.label,
|
|
15866
|
+
section: sectionOf(field.key) ?? "General",
|
|
15867
|
+
kind: secret ? "secret" : choices ? "choice" : "text",
|
|
15868
|
+
...choices ? { choices: choices.map((choice) => ({ value: choice.value, label: choice.label })) } : {},
|
|
15869
|
+
value: secret && value ? maskSetting(value) : value,
|
|
15870
|
+
isSet: value !== "",
|
|
15871
|
+
overriddenByEnvironment: Boolean(processEnvironment[field.key]) && processEnvironment[field.key] !== value
|
|
15872
|
+
};
|
|
15873
|
+
});
|
|
15874
|
+
return { file: settingsFile(processEnvironment), rows };
|
|
15875
|
+
}
|
|
15876
|
+
async function setSetting(params, deps) {
|
|
15877
|
+
const key = typeof params.key === "string" ? params.key : "";
|
|
15878
|
+
const raw = typeof params.value === "string" ? params.value : "";
|
|
15879
|
+
const field = SETTING_FIELDS.find((candidate) => candidate.key === key);
|
|
15880
|
+
if (!field)
|
|
15881
|
+
return { ok: false, error: `No setting named ${key || "(none)"}.` };
|
|
15882
|
+
const current = await loadSettings(deps.processEnvironment);
|
|
15883
|
+
const next = { ...current };
|
|
15884
|
+
let stored = "";
|
|
15885
|
+
if (raw.trim() === "") {
|
|
15886
|
+
delete next[field.key];
|
|
15887
|
+
} else {
|
|
15888
|
+
try {
|
|
15889
|
+
stored = validateSetting(field.key, raw);
|
|
15890
|
+
} catch (error) {
|
|
15891
|
+
return { ok: false, error: error instanceof Error ? error.message : String(error) };
|
|
15892
|
+
}
|
|
15893
|
+
next[field.key] = stored;
|
|
15894
|
+
}
|
|
15895
|
+
let file;
|
|
15896
|
+
try {
|
|
15897
|
+
file = await saveSettings(next, deps.processEnvironment);
|
|
15898
|
+
} catch (error) {
|
|
15899
|
+
return { ok: false, error: `Could not save: ${error instanceof Error ? error.message : String(error)}` };
|
|
15900
|
+
}
|
|
15901
|
+
if (raw.trim() === "" && deps.environment[field.key] === current[field.key])
|
|
15902
|
+
delete deps.environment[field.key];
|
|
15903
|
+
Object.assign(deps.environment, mergedEnvironment(next, deps.processEnvironment));
|
|
15904
|
+
const secret = "secret" in field && field.secret === true;
|
|
15905
|
+
return { ok: true, file, value: secret && stored ? maskSetting(stored) : stored, isSet: stored !== "" };
|
|
15906
|
+
}
|
|
16300
15907
|
|
|
16301
|
-
//
|
|
15908
|
+
// src/app/startup-update.ts
|
|
16302
15909
|
import { spawn as spawn8 } from "node:child_process";
|
|
16303
15910
|
|
|
16304
|
-
//
|
|
15911
|
+
// src/platform/auto-update.ts
|
|
16305
15912
|
import { promises as fs17 } from "node:fs";
|
|
16306
15913
|
import path22 from "node:path";
|
|
16307
15914
|
var AUTO_UPDATE_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
@@ -16414,7 +16021,7 @@ async function runAutoUpdate(options) {
|
|
|
16414
16021
|
return { notice: [], decision };
|
|
16415
16022
|
}
|
|
16416
16023
|
|
|
16417
|
-
//
|
|
16024
|
+
// src/platform/defender-feed-update.ts
|
|
16418
16025
|
var OFFICIAL_DEFENDER_FEED_URL = "https://circuit-archymedes.vercel.app/api/defender-brain/manifest";
|
|
16419
16026
|
var OFFICIAL_DEFENDER_FEED_KEYS = Object.freeze({
|
|
16420
16027
|
"release-2026-01": "MCowBQYDK2VwAyEA4/jb1zd6f+jIPAFja1bPNtroXV8MtAZFrKt5BSY+ngI="
|
|
@@ -16442,12 +16049,12 @@ async function updateDefenderFeed(environment) {
|
|
|
16442
16049
|
});
|
|
16443
16050
|
}
|
|
16444
16051
|
|
|
16445
|
-
//
|
|
16052
|
+
// src/platform/update.ts
|
|
16446
16053
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
16447
16054
|
import { tmpdir } from "node:os";
|
|
16448
16055
|
import { createInterface as createInterface3 } from "node:readline/promises";
|
|
16449
16056
|
|
|
16450
|
-
//
|
|
16057
|
+
// src/catalog/commands.ts
|
|
16451
16058
|
function defineCommands(table) {
|
|
16452
16059
|
return Object.entries(table).map(([name, command]) => ({ name, ...command }));
|
|
16453
16060
|
}
|
|
@@ -16520,7 +16127,7 @@ function renderCommandHelp(language = "en", shortcuts = new Map, options = {}) {
|
|
|
16520
16127
|
`);
|
|
16521
16128
|
}
|
|
16522
16129
|
|
|
16523
|
-
//
|
|
16130
|
+
// src/terminal/keybindings.ts
|
|
16524
16131
|
var FUNCTION_KEY = /^f([1-9]|1[0-2])$/;
|
|
16525
16132
|
var NAMED_KEYS = new Set(["tab", "enter", "escape", "space", "up", "down", "left", "right", "home", "end", "pageup", "pagedown", "backspace", "delete"]);
|
|
16526
16133
|
function isKeyName(value) {
|
|
@@ -16770,10 +16377,10 @@ function escapeCodeTimeoutMs(environment = process.env) {
|
|
|
16770
16377
|
const parsed = raw ? Number(raw) : NaN;
|
|
16771
16378
|
return Number.isInteger(parsed) && parsed >= 10 && parsed <= 2000 ? parsed : DEFAULT_ESCAPE_CODE_TIMEOUT_MS;
|
|
16772
16379
|
}
|
|
16773
|
-
//
|
|
16380
|
+
// package.json
|
|
16774
16381
|
var package_default = {
|
|
16775
16382
|
name: "archymedes-cli",
|
|
16776
|
-
version: "3.
|
|
16383
|
+
version: "3.3.0",
|
|
16777
16384
|
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.",
|
|
16778
16385
|
keywords: [
|
|
16779
16386
|
"cli",
|
|
@@ -16819,12 +16426,12 @@ var package_default = {
|
|
|
16819
16426
|
prepublishOnly: "bun run ../../tooling/build/build-packages.ts"
|
|
16820
16427
|
},
|
|
16821
16428
|
optionalDependencies: {
|
|
16822
|
-
"@archymedes/cli-darwin-arm64": "3.
|
|
16823
|
-
"@archymedes/cli-darwin-x64": "3.
|
|
16824
|
-
"@archymedes/cli-linux-arm64": "3.
|
|
16825
|
-
"@archymedes/cli-linux-x64": "3.
|
|
16826
|
-
"@archymedes/cli-win32-arm64": "3.
|
|
16827
|
-
"@archymedes/cli-win32-x64": "3.
|
|
16429
|
+
"@archymedes/cli-darwin-arm64": "3.3.0",
|
|
16430
|
+
"@archymedes/cli-darwin-x64": "3.3.0",
|
|
16431
|
+
"@archymedes/cli-linux-arm64": "3.3.0",
|
|
16432
|
+
"@archymedes/cli-linux-x64": "3.3.0",
|
|
16433
|
+
"@archymedes/cli-win32-arm64": "3.3.0",
|
|
16434
|
+
"@archymedes/cli-win32-x64": "3.3.0",
|
|
16828
16435
|
"@archymedes/state-darwin-arm64": "0.4.0",
|
|
16829
16436
|
"@archymedes/state-darwin-x64": "0.4.0",
|
|
16830
16437
|
"@archymedes/state-linux-arm64-gnu": "0.4.0",
|
|
@@ -16836,7 +16443,7 @@ var package_default = {
|
|
|
16836
16443
|
}
|
|
16837
16444
|
};
|
|
16838
16445
|
|
|
16839
|
-
//
|
|
16446
|
+
// src/platform/update.ts
|
|
16840
16447
|
var ARCHYMEDES_CLI_PACKAGE = "archymedes-cli";
|
|
16841
16448
|
var ARCHYMEDES_CLI_VERSION = package_default.version;
|
|
16842
16449
|
var DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
@@ -17054,7 +16661,7 @@ async function runSelfUpdate(options = {}) {
|
|
|
17054
16661
|
return { status: "updated", currentVersion, latestVersion, code: 0 };
|
|
17055
16662
|
}
|
|
17056
16663
|
|
|
17057
|
-
//
|
|
16664
|
+
// src/text/ansi.ts
|
|
17058
16665
|
var RESET = "\x1B[0m";
|
|
17059
16666
|
var BOLD = "\x1B[1m";
|
|
17060
16667
|
var DIM = "\x1B[2m";
|
|
@@ -17067,7 +16674,7 @@ function paintAll(text, codes, depth) {
|
|
|
17067
16674
|
return depth === "none" || codes.length === 0 ? text : `${codes.join("")}${text}${RESET}`;
|
|
17068
16675
|
}
|
|
17069
16676
|
|
|
17070
|
-
//
|
|
16677
|
+
// src/terminal/output.ts
|
|
17071
16678
|
var terminalStream = {
|
|
17072
16679
|
write(text) {
|
|
17073
16680
|
process.stdout.write(text);
|
|
@@ -17101,7 +16708,7 @@ class OutputRouter {
|
|
|
17101
16708
|
}
|
|
17102
16709
|
}
|
|
17103
16710
|
|
|
17104
|
-
//
|
|
16711
|
+
// src/text/glyphs.ts
|
|
17105
16712
|
var UNICODE_GLYPHS = {
|
|
17106
16713
|
starGlyphs: [".", "·", "✧", "✦", "✶"],
|
|
17107
16714
|
spinnerFrames: [" ◜ ", " ◠ ", " ◝ ", " ◞ ", " ◡ ", " ◟ "],
|
|
@@ -17208,7 +16815,7 @@ function borderGlyphsFor(style, glyphs) {
|
|
|
17208
16815
|
return ROUND_BORDER;
|
|
17209
16816
|
}
|
|
17210
16817
|
|
|
17211
|
-
//
|
|
16818
|
+
// src/text/text-width.ts
|
|
17212
16819
|
var ANSI = /\x1b\[[0-9;]*m/g;
|
|
17213
16820
|
var PRINTABLE_ASCII = /^[\x20-\x7e]*$/;
|
|
17214
16821
|
function visibleWidth(text) {
|
|
@@ -17243,7 +16850,7 @@ function clipTo(text, width, glyphs = UNICODE_GLYPHS) {
|
|
|
17243
16850
|
return `${out}${mark}`;
|
|
17244
16851
|
}
|
|
17245
16852
|
|
|
17246
|
-
//
|
|
16853
|
+
// src/render/syntax.ts
|
|
17247
16854
|
function newSyntaxState() {
|
|
17248
16855
|
return {};
|
|
17249
16856
|
}
|
|
@@ -17890,7 +17497,7 @@ function highlightSyntax(line, options) {
|
|
|
17890
17497
|
return `${out}${RESET}`;
|
|
17891
17498
|
}
|
|
17892
17499
|
|
|
17893
|
-
//
|
|
17500
|
+
// src/render/markdown.ts
|
|
17894
17501
|
var colour = (role, palette) => palette?.[role] || ANSI_PALETTE[role];
|
|
17895
17502
|
var INLINE_PATTERN = /(?<!\\)(`[^`\n]+`)|(?<!\\)(\*\*[^*\n]+\*\*)|(?<!\\)(__[^_\n]+__)|(?<!\\)(~~[^~\n]+~~)|(?<!\\)(\*[^*\n]+\*)|(?<!\\)(_[^_\n]+_)|(!?\[([^\]\n]+)\]\((https?:\/\/[^\s)\n]+)\))|(<(https?:\/\/[^>\s]+)>)/g;
|
|
17896
17503
|
var unescapeMarkdown = (text) => text.replace(/\\([\\`*_[\]{}()#+.!~>-])/g, "$1");
|
|
@@ -18111,7 +17718,7 @@ function renderMarkdown(text, options) {
|
|
|
18111
17718
|
`);
|
|
18112
17719
|
}
|
|
18113
17720
|
|
|
18114
|
-
//
|
|
17721
|
+
// src/render/tui.ts
|
|
18115
17722
|
function archymedesSpinnerFrame(index, glyphs = UNICODE_GLYPHS) {
|
|
18116
17723
|
const frames = glyphs.spinnerFrames;
|
|
18117
17724
|
const normalized = Number.isFinite(index) ? Math.max(0, Math.floor(index)) : 0;
|
|
@@ -18699,7 +18306,7 @@ function wrapPlain(text, width) {
|
|
|
18699
18306
|
return lines.length === 0 ? [""] : lines;
|
|
18700
18307
|
}
|
|
18701
18308
|
|
|
18702
|
-
//
|
|
18309
|
+
// src/render/transcript.ts
|
|
18703
18310
|
function truncateMiddle(value, maximum) {
|
|
18704
18311
|
const clean = value.replace(/\s+/g, " ").trim();
|
|
18705
18312
|
if (clean.length <= maximum)
|
|
@@ -18862,7 +18469,7 @@ function summarizeToolResult(toolName, content, isError) {
|
|
|
18862
18469
|
}
|
|
18863
18470
|
}
|
|
18864
18471
|
|
|
18865
|
-
//
|
|
18472
|
+
// src/render/sections.ts
|
|
18866
18473
|
var TONE_ROLE = {
|
|
18867
18474
|
good: "success",
|
|
18868
18475
|
bad: "error",
|
|
@@ -18989,7 +18596,7 @@ function outcomeMark(outcome, style) {
|
|
|
18989
18596
|
}
|
|
18990
18597
|
}
|
|
18991
18598
|
|
|
18992
|
-
//
|
|
18599
|
+
// src/render/code-view.ts
|
|
18993
18600
|
var MAX_DIFF_CELLS = 250000;
|
|
18994
18601
|
function diffLines(before, after) {
|
|
18995
18602
|
const left = before === "" ? [] : before.split(`
|
|
@@ -19286,7 +18893,7 @@ function renderFileChange(change, style, options = {}) {
|
|
|
19286
18893
|
};
|
|
19287
18894
|
}
|
|
19288
18895
|
|
|
19289
|
-
//
|
|
18896
|
+
// src/render/test-report.ts
|
|
19290
18897
|
function toMs(value) {
|
|
19291
18898
|
if (!value)
|
|
19292
18899
|
return;
|
|
@@ -19561,7 +19168,7 @@ function renderTestReport(report, style, options = {}) {
|
|
|
19561
19168
|
`);
|
|
19562
19169
|
}
|
|
19563
19170
|
|
|
19564
|
-
//
|
|
19171
|
+
// src/render/expandable.ts
|
|
19565
19172
|
var MAX_ENTRIES = 64;
|
|
19566
19173
|
|
|
19567
19174
|
class ExpandableStore {
|
|
@@ -19595,7 +19202,7 @@ function expandHint(id, hidden, depth, glyphs = UNICODE_GLYPHS) {
|
|
|
19595
19202
|
return paint(`${glyphs.collapsed} ${hidden} more line${hidden === 1 ? "" : "s"} hidden ${glyphs.middot} /expand ${id}`, DIM, depth);
|
|
19596
19203
|
}
|
|
19597
19204
|
|
|
19598
|
-
//
|
|
19205
|
+
// src/app/transcript.ts
|
|
19599
19206
|
var colorEnabled = false;
|
|
19600
19207
|
var wrap = (code) => (value) => colorEnabled ? `${code}${value}${RESET}` : value;
|
|
19601
19208
|
var palette = NO_COLOR_PALETTE;
|
|
@@ -19675,7 +19282,7 @@ function beginTranscriptTurn() {
|
|
|
19675
19282
|
markdown.reset();
|
|
19676
19283
|
}
|
|
19677
19284
|
|
|
19678
|
-
//
|
|
19285
|
+
// src/app/startup-update.ts
|
|
19679
19286
|
async function startupMaintenance(environment, interactive, install) {
|
|
19680
19287
|
updateDefenderFeed(environment).catch(() => {
|
|
19681
19288
|
return;
|
|
@@ -19714,7 +19321,7 @@ function installInChildProcess(entry, environment) {
|
|
|
19714
19321
|
});
|
|
19715
19322
|
}
|
|
19716
19323
|
|
|
19717
|
-
//
|
|
19324
|
+
// src/app/jev.ts
|
|
19718
19325
|
function jevOptionsFromEnvironment(environment) {
|
|
19719
19326
|
if ((environment.ARCHYMEDES_JEV ?? "").trim().toLowerCase() === "off")
|
|
19720
19327
|
return;
|
|
@@ -19725,7 +19332,7 @@ function jevOptionsFromEnvironment(environment) {
|
|
|
19725
19332
|
return { apiKey, ...model ? { model } : {}, ...environment.ARCHYMEDES_JEV_REVIEW?.trim().toLowerCase() === "off" ? { review: false } : {} };
|
|
19726
19333
|
}
|
|
19727
19334
|
|
|
19728
|
-
//
|
|
19335
|
+
// ../core/src/providers/exa.ts
|
|
19729
19336
|
var LATENCY_CEILING = {
|
|
19730
19337
|
instant: 5000,
|
|
19731
19338
|
fast: 1e4,
|
|
@@ -19931,7 +19538,7 @@ function createExaClient(environment, fetchImpl) {
|
|
|
19931
19538
|
});
|
|
19932
19539
|
}
|
|
19933
19540
|
|
|
19934
|
-
//
|
|
19541
|
+
// src/acp-server.ts
|
|
19935
19542
|
function splitFrames(buffer) {
|
|
19936
19543
|
const parts = buffer.split(`
|
|
19937
19544
|
`);
|
|
@@ -19949,6 +19556,8 @@ async function runAcpServer(options) {
|
|
|
19949
19556
|
extensions: {
|
|
19950
19557
|
"_archymedes/setup/status": async () => setupStatus(options.environment, { provider: options.provider, model: options.model }),
|
|
19951
19558
|
"_archymedes/setup/save": async (params) => saveSetup(params, { environment: options.environment, processEnvironment: process.env }),
|
|
19559
|
+
"_archymedes/settings/list": async () => listSettings(process.env),
|
|
19560
|
+
"_archymedes/settings/set": async (params) => setSetting(params, { environment: options.environment, processEnvironment: process.env }),
|
|
19952
19561
|
"_archymedes/models": async (params) => modelList(options.environment, params),
|
|
19953
19562
|
"_archymedes/startup": async () => ({
|
|
19954
19563
|
notices: await (startup ??= startupMaintenance(options.environment, false, installInChildProcess({ execPath: process.execPath, script: process.argv[1] ?? "" }, options.environment)))
|
|
@@ -19969,7 +19578,7 @@ async function runAcpServer(options) {
|
|
|
19969
19578
|
const workspace = started.workspace;
|
|
19970
19579
|
let agent = build(mode);
|
|
19971
19580
|
function build(currentMode) {
|
|
19972
|
-
|
|
19581
|
+
const built = new ArchymedesAgent({
|
|
19973
19582
|
root,
|
|
19974
19583
|
model: resolved.provider,
|
|
19975
19584
|
prices: priceCatalogFor(resolved.prices),
|
|
@@ -19978,9 +19587,12 @@ async function runAcpServer(options) {
|
|
|
19978
19587
|
search: createExaClient(options.environment),
|
|
19979
19588
|
onEvent,
|
|
19980
19589
|
jev: jevOptionsFromEnvironment(options.environment),
|
|
19590
|
+
...reasoningFromEnvironment(options.environment) ? { reasoning: reasoningFromEnvironment(options.environment) } : {},
|
|
19981
19591
|
afterEdit: acpEditDiagnostics(root, workspace, options.environment),
|
|
19982
19592
|
approve: async (request) => approve({ toolName: request.tool.name, summary: request.summary, toolCallId: request.call.id, ...request.pattern ? { pattern: request.pattern } : {} })
|
|
19983
19593
|
});
|
|
19594
|
+
built.warmUp();
|
|
19595
|
+
return built;
|
|
19984
19596
|
}
|
|
19985
19597
|
async function rebuild(change) {
|
|
19986
19598
|
const carried = await loadSession(root, agent.sessionId);
|
|
@@ -20093,10 +19705,10 @@ function priceCatalogFor(prices) {
|
|
|
20093
19705
|
};
|
|
20094
19706
|
}
|
|
20095
19707
|
|
|
20096
|
-
//
|
|
19708
|
+
// src/app/args.ts
|
|
20097
19709
|
import path23 from "node:path";
|
|
20098
19710
|
|
|
20099
|
-
//
|
|
19711
|
+
// src/render/charts.ts
|
|
20100
19712
|
function barChart(data, options) {
|
|
20101
19713
|
if (data.length === 0)
|
|
20102
19714
|
return [];
|
|
@@ -20121,7 +19733,7 @@ function barChart(data, options) {
|
|
|
20121
19733
|
});
|
|
20122
19734
|
}
|
|
20123
19735
|
|
|
20124
|
-
//
|
|
19736
|
+
// src/commands/chat-history.ts
|
|
20125
19737
|
function countTurns(messages) {
|
|
20126
19738
|
return messages.filter((message) => message.role === "user" && !message.internal).length;
|
|
20127
19739
|
}
|
|
@@ -20314,7 +19926,7 @@ function parseHistoryCommand(input) {
|
|
|
20314
19926
|
return { kind: "invalid", reason: `/history takes "list", a session id, "search <text>", "delete <id>", "status", or "resume" — not "${verb}".` };
|
|
20315
19927
|
}
|
|
20316
19928
|
|
|
20317
|
-
//
|
|
19929
|
+
// src/commands/pacing.ts
|
|
20318
19930
|
var PACE_PROFILES = {
|
|
20319
19931
|
off: {
|
|
20320
19932
|
level: "off",
|
|
@@ -20376,7 +19988,7 @@ function paceBadge(level, glyphs2 = UNICODE_GLYPHS) {
|
|
|
20376
19988
|
return `${glyphs2.paused} ${profileFor(level).label}`;
|
|
20377
19989
|
}
|
|
20378
19990
|
|
|
20379
|
-
//
|
|
19991
|
+
// src/app/args.ts
|
|
20380
19992
|
var SESSION_ID2 = /^\d{8}T\d{6}Z-[a-z0-9]{6}$/;
|
|
20381
19993
|
var DEFAULT_DOCKER_IMAGE = "debian:stable-slim";
|
|
20382
19994
|
function parseArgs(argv) {
|
|
@@ -20574,7 +20186,7 @@ function parseArgs(argv) {
|
|
|
20574
20186
|
return parsed;
|
|
20575
20187
|
}
|
|
20576
20188
|
|
|
20577
|
-
//
|
|
20189
|
+
// src/app/session-provider.ts
|
|
20578
20190
|
async function resolveSessionProvider2(environment, options) {
|
|
20579
20191
|
if (options.provider || !options.resume)
|
|
20580
20192
|
return resolveProvider(environment, options);
|
|
@@ -20583,7 +20195,7 @@ async function resolveSessionProvider2(environment, options) {
|
|
|
20583
20195
|
return resolveProvider(environment, selection?.provider === "free" ? { provider: "free", model: options.model ?? selection.model } : options);
|
|
20584
20196
|
}
|
|
20585
20197
|
|
|
20586
|
-
//
|
|
20198
|
+
// src/app/transcript.ts
|
|
20587
20199
|
var colorEnabled2 = false;
|
|
20588
20200
|
var liveTerminal2 = false;
|
|
20589
20201
|
var wrap2 = (code) => (value) => colorEnabled2 ? `${code}${value}${RESET}` : value;
|
|
@@ -20897,7 +20509,7 @@ ${rule(sectionStyle2(), { label: "tool activity", tone: "neutral" })}
|
|
|
20897
20509
|
}
|
|
20898
20510
|
}
|
|
20899
20511
|
|
|
20900
|
-
//
|
|
20512
|
+
// ../core/src/cli/suggestions.ts
|
|
20901
20513
|
var CATEGORY_ORDER = ["blocked", "recovery", "next", "discover", "starter"];
|
|
20902
20514
|
function defaultSignals(overrides = {}) {
|
|
20903
20515
|
return {
|
|
@@ -21294,7 +20906,7 @@ async function askModelForSuggestions(model, signals, context = {}) {
|
|
|
21294
20906
|
}
|
|
21295
20907
|
}
|
|
21296
20908
|
|
|
21297
|
-
//
|
|
20909
|
+
// src/ui/chooser.ts
|
|
21298
20910
|
var ALL_CHROME = { title: true, status: true, pagination: true, help: true };
|
|
21299
20911
|
function chromeOf(chrome) {
|
|
21300
20912
|
return { ...ALL_CHROME, ...chrome };
|
|
@@ -21522,7 +21134,7 @@ async function runChooser(keys, items, paint2, options) {
|
|
|
21522
21134
|
return;
|
|
21523
21135
|
}
|
|
21524
21136
|
|
|
21525
|
-
//
|
|
21137
|
+
// src/ui/navigation.ts
|
|
21526
21138
|
class CommandUsage {
|
|
21527
21139
|
limit;
|
|
21528
21140
|
order = [];
|
|
@@ -21545,8 +21157,8 @@ class CommandUsage {
|
|
|
21545
21157
|
}
|
|
21546
21158
|
}
|
|
21547
21159
|
|
|
21548
|
-
//
|
|
21549
|
-
import { randomUUID as
|
|
21160
|
+
// ../core/src/cli/daemon.ts
|
|
21161
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
21550
21162
|
var ARCHYMEDES_DAEMON_PROTOCOL_VERSION = 1;
|
|
21551
21163
|
var PREVIEW_HUNK_SEPARATOR = `
|
|
21552
21164
|
…
|
|
@@ -21592,7 +21204,7 @@ class ArchymedesSessionDaemon {
|
|
|
21592
21204
|
sessions = new Map;
|
|
21593
21205
|
pendingApprovals = new Map;
|
|
21594
21206
|
connect(options = {}) {
|
|
21595
|
-
const id = options.id ?? `client_${
|
|
21207
|
+
const id = options.id ?? `client_${randomUUID6()}`;
|
|
21596
21208
|
assertSafeId(id, "Client id");
|
|
21597
21209
|
if (this.clients.has(id))
|
|
21598
21210
|
throw new Error(`Daemon client already connected: ${id}`);
|
|
@@ -21611,7 +21223,7 @@ class ArchymedesSessionDaemon {
|
|
|
21611
21223
|
}
|
|
21612
21224
|
async requestApproval(sessionId, request) {
|
|
21613
21225
|
const publicRequest = {
|
|
21614
|
-
id: `approval_${
|
|
21226
|
+
id: `approval_${randomUUID6()}`,
|
|
21615
21227
|
sessionId,
|
|
21616
21228
|
summary: request.summary,
|
|
21617
21229
|
actionDigest: request.actionDigest,
|
|
@@ -21884,7 +21496,7 @@ class ArchymedesDaemonClient {
|
|
|
21884
21496
|
planRoute(objective, signal) {
|
|
21885
21497
|
return this.daemon.planRoute(this.id, this.sessionId, objective, signal);
|
|
21886
21498
|
}
|
|
21887
|
-
send(objective, commandId = `turn_${
|
|
21499
|
+
send(objective, commandId = `turn_${randomUUID6()}`) {
|
|
21888
21500
|
return this.daemon.send(this.id, this.sessionId, objective, commandId);
|
|
21889
21501
|
}
|
|
21890
21502
|
cancel() {
|
|
@@ -21943,7 +21555,7 @@ class ArchymedesDaemonClient {
|
|
|
21943
21555
|
}
|
|
21944
21556
|
}
|
|
21945
21557
|
|
|
21946
|
-
//
|
|
21558
|
+
// ../core/src/money.ts
|
|
21947
21559
|
var CURRENCIES2 = (() => {
|
|
21948
21560
|
try {
|
|
21949
21561
|
return Intl.supportedValuesOf("currency");
|
|
@@ -21986,7 +21598,7 @@ function formatMoney2(value) {
|
|
|
21986
21598
|
return value.currency === "USD" ? `${format.symbol}${rendered}` : `${format.symbol} ${rendered}`;
|
|
21987
21599
|
}
|
|
21988
21600
|
|
|
21989
|
-
//
|
|
21601
|
+
// ../core/src/cli/backends.ts
|
|
21990
21602
|
import path24 from "node:path";
|
|
21991
21603
|
var CONFIG_FILE_SCAN_LIMIT2 = 500;
|
|
21992
21604
|
function localCommandGuidance2(platform) {
|
|
@@ -22080,11 +21692,11 @@ class LocalWorkspace2 {
|
|
|
22080
21692
|
}
|
|
22081
21693
|
}
|
|
22082
21694
|
|
|
22083
|
-
//
|
|
21695
|
+
// ../core/src/cli/cost.ts
|
|
22084
21696
|
function formatTokenFlow2(usage) {
|
|
22085
21697
|
return `↑${compactTokenCount(usage.inputTokens)} ↓${compactTokenCount(usage.outputTokens)} tok`;
|
|
22086
21698
|
}
|
|
22087
|
-
var
|
|
21699
|
+
var emptyUsage2 = { inputTokens: 0, outputTokens: 0, totalTokens: 0, cachedInputTokens: 0, cacheWriteTokens: 0, reasoningTokens: 0 };
|
|
22088
21700
|
var CACHE_CHURN_FLOOR_TOKENS2 = 20000;
|
|
22089
21701
|
var CACHE_CHURN_HINT2 = [
|
|
22090
21702
|
"The prompt cache is being rewritten more than it is read, which costs more than not caching at all.",
|
|
@@ -22172,7 +21784,7 @@ class CostLedger2 {
|
|
|
22172
21784
|
cachedInputTokens: total.cachedInputTokens + turn.usage.cachedInputTokens,
|
|
22173
21785
|
cacheWriteTokens: total.cacheWriteTokens + turn.usage.cacheWriteTokens,
|
|
22174
21786
|
reasoningTokens: total.reasoningTokens + turn.usage.reasoningTokens
|
|
22175
|
-
}), { ...
|
|
21787
|
+
}), { ...emptyUsage2 });
|
|
22176
21788
|
}
|
|
22177
21789
|
get history() {
|
|
22178
21790
|
return [...this.turns];
|
|
@@ -22332,7 +21944,7 @@ class CostLedger2 {
|
|
|
22332
21944
|
}
|
|
22333
21945
|
}
|
|
22334
21946
|
|
|
22335
|
-
//
|
|
21947
|
+
// src/headless.ts
|
|
22336
21948
|
var HEADLESS_PROTOCOL_VERSION = 1;
|
|
22337
21949
|
var EXIT_CODES = {
|
|
22338
21950
|
completed: 0,
|
|
@@ -22435,7 +22047,7 @@ class HeadlessEmitter {
|
|
|
22435
22047
|
return;
|
|
22436
22048
|
}
|
|
22437
22049
|
if (safe.type === "model_turn") {
|
|
22438
|
-
this.emit("model_turn", { iteration: safe.iteration, model: safe.model, toolCalls: safe.toolCallCount, usage: safe.usage });
|
|
22050
|
+
this.emit("model_turn", { iteration: safe.iteration, model: safe.model, toolCalls: safe.toolCallCount, usage: safe.usage, ...safe.effort ? { effort: safe.effort, effortReason: safe.effortReason } : {} });
|
|
22439
22051
|
return;
|
|
22440
22052
|
}
|
|
22441
22053
|
if (safe.type === "provider_retry") {
|
|
@@ -22458,7 +22070,7 @@ class HeadlessEmitter {
|
|
|
22458
22070
|
}
|
|
22459
22071
|
}
|
|
22460
22072
|
|
|
22461
|
-
//
|
|
22073
|
+
// ../core/src/providers/price-catalog.ts
|
|
22462
22074
|
var ANTHROPIC_VERIFIED2 = "2026-06-24";
|
|
22463
22075
|
var ANTHROPIC_SOURCE2 = "anthropic.com/pricing, recorded 2026-06-24";
|
|
22464
22076
|
var ANTHROPIC2 = [
|
|
@@ -22510,7 +22122,7 @@ var SERVICES2 = [
|
|
|
22510
22122
|
];
|
|
22511
22123
|
var PRICE_CATALOG2 = definePrices([...ANTHROPIC2, ...OAI_COMPAT_LABS2, ...SERVICES2]);
|
|
22512
22124
|
|
|
22513
|
-
//
|
|
22125
|
+
// src/text/color-depth.ts
|
|
22514
22126
|
function detectColorDepth(environment, isTTY) {
|
|
22515
22127
|
if (!isTTY || environment.NO_COLOR !== undefined || environment.TERM === "dumb")
|
|
22516
22128
|
return "none";
|
|
@@ -22519,7 +22131,7 @@ function detectColorDepth(environment, isTTY) {
|
|
|
22519
22131
|
return "ansi256";
|
|
22520
22132
|
}
|
|
22521
22133
|
|
|
22522
|
-
//
|
|
22134
|
+
// src/terminal/keybindings.ts
|
|
22523
22135
|
var FUNCTION_KEY2 = /^f([1-9]|1[0-2])$/;
|
|
22524
22136
|
var NAMED_KEYS2 = new Set(["tab", "enter", "escape", "space", "up", "down", "left", "right", "home", "end", "pageup", "pagedown", "backspace", "delete"]);
|
|
22525
22137
|
function isKeyName2(value) {
|
|
@@ -22761,7 +22373,7 @@ function escapeCodeTimeoutMs2(environment = process.env) {
|
|
|
22761
22373
|
return Number.isInteger(parsed) && parsed >= 10 && parsed <= 2000 ? parsed : DEFAULT_ESCAPE_CODE_TIMEOUT_MS2;
|
|
22762
22374
|
}
|
|
22763
22375
|
|
|
22764
|
-
//
|
|
22376
|
+
// src/platform/local-currency.ts
|
|
22765
22377
|
var COUNTRY_CURRENCIES2 = {
|
|
22766
22378
|
RW: "RWF",
|
|
22767
22379
|
EG: "EGP",
|
|
@@ -22887,7 +22499,7 @@ function resolveCurrencyPreference(options) {
|
|
|
22887
22499
|
}
|
|
22888
22500
|
var FX_CACHE_MAX_AGE_MS2 = 24 * 60 * 60 * 1000;
|
|
22889
22501
|
|
|
22890
|
-
//
|
|
22502
|
+
// src/platform/settings.ts
|
|
22891
22503
|
import { promises as fs18 } from "node:fs";
|
|
22892
22504
|
import os5 from "node:os";
|
|
22893
22505
|
import path25 from "node:path";
|
|
@@ -22994,6 +22606,13 @@ var AUTOSAVE_CHOICES2 = [
|
|
|
22994
22606
|
{ value: "off", label: "Off — save with Ctrl+S (default)" },
|
|
22995
22607
|
{ value: "on", label: "On — save a second after you stop typing" }
|
|
22996
22608
|
];
|
|
22609
|
+
var REASONING_CHOICES2 = [
|
|
22610
|
+
{ value: "auto", label: "Auto (experimental) — lower the effort on routine steps, leave hard ones to the model" },
|
|
22611
|
+
{ value: "minimal", label: "Minimal — never think more than needed" },
|
|
22612
|
+
{ value: "low", label: "Low" },
|
|
22613
|
+
{ value: "medium", label: "Medium" },
|
|
22614
|
+
{ value: "high", label: "High — slowest" }
|
|
22615
|
+
];
|
|
22997
22616
|
var PROVIDER_CHOICES2 = PROVIDER_IDS.map((id) => ({ value: id, label: PROVIDER_INFO[id].label }));
|
|
22998
22617
|
var SETTING_FIELDS2 = [
|
|
22999
22618
|
{ key: "ARCHYMEDES_THEME", label: "Theme — colours for the whole CLI (/theme <name> also saves it)", choices: THEME_CHOICES2, section: "Appearance" },
|
|
@@ -23001,6 +22620,7 @@ var SETTING_FIELDS2 = [
|
|
|
23001
22620
|
{ key: "ARCHYMEDES_CODE_LINE_NUMBERS", label: "Line numbers in code blocks", choices: SHOW_HIDE_CHOICES2 },
|
|
23002
22621
|
{ key: "ARCHYMEDES_SIMPLE", label: "Simple mode — quiet start, short help", choices: SIMPLE_CHOICES2 },
|
|
23003
22622
|
{ key: "ARCHYMEDES_LANGUAGE", label: "Control language", choices: LANGUAGE_CHOICES2 },
|
|
22623
|
+
{ key: "ARCHYMEDES_REASONING", label: "Reasoning effort — clear it to leave each model at its own default", choices: REASONING_CHOICES2 },
|
|
23004
22624
|
{ key: "ARCHYMEDES_RESUME", label: "Continue your last chat at startup", choices: RESUME_CHOICES2, section: "Behaviour" },
|
|
23005
22625
|
{ key: "ARCHYMEDES_EDITOR_AUTOSAVE", label: "Auto-save in /edit", choices: AUTOSAVE_CHOICES2 },
|
|
23006
22626
|
{ key: "ARCHYMEDES_SUGGEST_MODEL", label: "Ask the model for extra suggestions (a small extra call per turn)", choices: ON_OFF_CHOICES2 },
|
|
@@ -23132,7 +22752,7 @@ function mergedEnvironment2(settings, environment = process.env) {
|
|
|
23132
22752
|
var PROVIDER_REQUIRED_NAMES2 = new Set(PROVIDER_IDS.flatMap((id) => PROVIDER_INFO[id].requires));
|
|
23133
22753
|
var PROVIDER_KEY_FIELDS2 = SETTING_FIELDS2.filter((field) => PROVIDER_REQUIRED_NAMES2.has(field.key));
|
|
23134
22754
|
|
|
23135
|
-
//
|
|
22755
|
+
// src/app/free-setup.ts
|
|
23136
22756
|
var OPENROUTER_KEYS_URL3 = "https://openrouter.ai/keys";
|
|
23137
22757
|
var FREE_SETUP_INTRO = [
|
|
23138
22758
|
"Free mode runs zero-priced models through OpenRouter and never falls back to a paid one.",
|
|
@@ -23198,7 +22818,7 @@ ${style3.bold("Free mode setup")}
|
|
|
23198
22818
|
return;
|
|
23199
22819
|
}
|
|
23200
22820
|
|
|
23201
|
-
//
|
|
22821
|
+
// src/session/tabs.ts
|
|
23202
22822
|
class WorkspaceController {
|
|
23203
22823
|
limit;
|
|
23204
22824
|
tabs = [];
|
|
@@ -23287,7 +22907,7 @@ class WorkspaceController {
|
|
|
23287
22907
|
}
|
|
23288
22908
|
}
|
|
23289
22909
|
|
|
23290
|
-
//
|
|
22910
|
+
// src/terminal/output.ts
|
|
23291
22911
|
var terminalStream2 = {
|
|
23292
22912
|
write(text) {
|
|
23293
22913
|
process.stdout.write(text);
|
|
@@ -23383,7 +23003,7 @@ class TabSink {
|
|
|
23383
23003
|
}
|
|
23384
23004
|
}
|
|
23385
23005
|
|
|
23386
|
-
//
|
|
23006
|
+
// src/terminal/job-stream.ts
|
|
23387
23007
|
var TERMINAL_STATUSES = new Set(["completed", "failed", "cancelled"]);
|
|
23388
23008
|
class WatchRegistry {
|
|
23389
23009
|
watched = new Map;
|
|
@@ -23418,7 +23038,7 @@ class WatchRegistry {
|
|
|
23418
23038
|
}
|
|
23419
23039
|
}
|
|
23420
23040
|
|
|
23421
|
-
//
|
|
23041
|
+
// src/theme/theme.ts
|
|
23422
23042
|
var BLUEPRINT2 = `
|
|
23423
23043
|
/* Blueprint navy, chalk-white ink and an amber pencil — the original drafting table. */
|
|
23424
23044
|
@theme blueprint {
|
|
@@ -23719,7 +23339,7 @@ function detectPreferredTheme(environment) {
|
|
|
23719
23339
|
return DEFAULT_THEME_NAME2;
|
|
23720
23340
|
}
|
|
23721
23341
|
|
|
23722
|
-
//
|
|
23342
|
+
// src/theme/theme-files.ts
|
|
23723
23343
|
import { promises as fs19 } from "node:fs";
|
|
23724
23344
|
import path26 from "node:path";
|
|
23725
23345
|
function themeDirectory(scope, root, environment) {
|
|
@@ -23757,7 +23377,7 @@ async function findTheme(name, root, environment) {
|
|
|
23757
23377
|
return (await discoverThemes(root, environment)).find((theme) => theme.name.toLowerCase() === wanted);
|
|
23758
23378
|
}
|
|
23759
23379
|
|
|
23760
|
-
//
|
|
23380
|
+
// src/render/syntax.ts
|
|
23761
23381
|
var DEFAULT_CODE_STYLE2 = { colors: "vscode", lineNumbers: true };
|
|
23762
23382
|
var currentCodeStyle2 = { ...DEFAULT_CODE_STYLE2 };
|
|
23763
23383
|
function codeStyleFromEnvironment(environment) {
|
|
@@ -23815,7 +23435,7 @@ var GRAMMARS2 = {
|
|
|
23815
23435
|
};
|
|
23816
23436
|
var PUNCTUATION2 = new Set([..."{}[]()<>;,.:=+-*/%!&|^~?\\"]);
|
|
23817
23437
|
|
|
23818
|
-
//
|
|
23438
|
+
// src/platform/i18n.ts
|
|
23819
23439
|
var CONTROL_LANGUAGES2 = {
|
|
23820
23440
|
en: "English",
|
|
23821
23441
|
zh: "中文 (Mandarin)",
|
|
@@ -23840,7 +23460,7 @@ function resolveControlLanguage2(value) {
|
|
|
23840
23460
|
return base in CONTROL_LANGUAGES2 ? base : "en";
|
|
23841
23461
|
}
|
|
23842
23462
|
|
|
23843
|
-
//
|
|
23463
|
+
// src/text/glyphs.ts
|
|
23844
23464
|
var UNICODE_GLYPHS2 = {
|
|
23845
23465
|
starGlyphs: [".", "·", "✧", "✦", "✶"],
|
|
23846
23466
|
spinnerFrames: [" ◜ ", " ◠ ", " ◝ ", " ◞ ", " ◡ ", " ◟ "],
|
|
@@ -23956,7 +23576,7 @@ function glyphsFor(mode) {
|
|
|
23956
23576
|
function resolveGlyphs(environment, platform = process.platform) {
|
|
23957
23577
|
return glyphsFor(detectGlyphMode(environment, platform));
|
|
23958
23578
|
}
|
|
23959
|
-
//
|
|
23579
|
+
// src/session/state-history.ts
|
|
23960
23580
|
class CliStateHistory {
|
|
23961
23581
|
root;
|
|
23962
23582
|
environment;
|
|
@@ -24067,7 +23687,7 @@ class CliStateHistory {
|
|
|
24067
23687
|
}
|
|
24068
23688
|
}
|
|
24069
23689
|
|
|
24070
|
-
//
|
|
23690
|
+
// src/ui/borrowed-keyboard.ts
|
|
24071
23691
|
function painter(output) {
|
|
24072
23692
|
let rows = 0;
|
|
24073
23693
|
const erase = () => {
|
|
@@ -24148,7 +23768,7 @@ async function openChooser(host, items, options, self) {
|
|
|
24148
23768
|
return withBorrowedKeyboard(host, self, (keys, paint2) => runChooser(keys, items, paint2, sized));
|
|
24149
23769
|
}
|
|
24150
23770
|
|
|
24151
|
-
//
|
|
23771
|
+
// src/app/prompts.ts
|
|
24152
23772
|
function renderApprovalPreview(preview2) {
|
|
24153
23773
|
if (!preview2)
|
|
24154
23774
|
return;
|
|
@@ -24286,7 +23906,7 @@ async function hiddenQuestion(readline, question, signal) {
|
|
|
24286
23906
|
}
|
|
24287
23907
|
}
|
|
24288
23908
|
|
|
24289
|
-
//
|
|
23909
|
+
// src/app/providers.ts
|
|
24290
23910
|
function readFxRates(environment) {
|
|
24291
23911
|
const genericRate = Number(environment.ARCHYMEDES_FX_RATE);
|
|
24292
23912
|
const genericFrom = environment.ARCHYMEDES_FX_FROM?.trim().toUpperCase();
|
|
@@ -24303,11 +23923,11 @@ function readFxRates(environment) {
|
|
|
24303
23923
|
}
|
|
24304
23924
|
return configured;
|
|
24305
23925
|
}
|
|
24306
|
-
//
|
|
23926
|
+
// ../core/src/cli/job-store.ts
|
|
24307
23927
|
import { promises as fs20 } from "node:fs";
|
|
24308
23928
|
import path27 from "node:path";
|
|
24309
23929
|
|
|
24310
|
-
//
|
|
23930
|
+
// ../core/src/cli/jobs.ts
|
|
24311
23931
|
var JOB_STATUSES = ["queued", "running", "paused", "completed", "failed", "cancelled"];
|
|
24312
23932
|
var DECISIONS = ["allow", "allow_always", "allow_pattern", "deny", "deny_always"];
|
|
24313
23933
|
function parseJobRecord(value, index) {
|
|
@@ -24482,7 +24102,7 @@ function recoverStale(store, now) {
|
|
|
24482
24102
|
return { store: { jobs }, recovered };
|
|
24483
24103
|
}
|
|
24484
24104
|
|
|
24485
|
-
//
|
|
24105
|
+
// ../core/src/cli/job-store.ts
|
|
24486
24106
|
function jobStoreFile(root) {
|
|
24487
24107
|
return path27.join(root, ".archymedes", "jobs.json");
|
|
24488
24108
|
}
|
|
@@ -24602,10 +24222,10 @@ async function appendJobLog(root, id, line) {
|
|
|
24602
24222
|
await fs20.appendFile(file, `${line}
|
|
24603
24223
|
`, "utf8");
|
|
24604
24224
|
}
|
|
24605
|
-
//
|
|
24225
|
+
// src/job-worker.ts
|
|
24606
24226
|
import os6 from "node:os";
|
|
24607
24227
|
|
|
24608
|
-
//
|
|
24228
|
+
// src/commands/wander.ts
|
|
24609
24229
|
async function gatherWanderEvidence(topic, search, numResults = 8) {
|
|
24610
24230
|
if (!search) {
|
|
24611
24231
|
return {
|
|
@@ -24701,7 +24321,7 @@ function renderWanderChart(results, style3, width) {
|
|
|
24701
24321
|
`);
|
|
24702
24322
|
}
|
|
24703
24323
|
|
|
24704
|
-
//
|
|
24324
|
+
// src/job-worker.ts
|
|
24705
24325
|
function workerId(hostname = os6.hostname(), pid = process.pid) {
|
|
24706
24326
|
return `${hostname}:${pid}`;
|
|
24707
24327
|
}
|
|
@@ -24879,7 +24499,7 @@ async function runJobWorkerForever(deps) {
|
|
|
24879
24499
|
}
|
|
24880
24500
|
}
|
|
24881
24501
|
|
|
24882
|
-
//
|
|
24502
|
+
// src/app/providers.ts
|
|
24883
24503
|
function renderProviders(environment, depth) {
|
|
24884
24504
|
const paint2 = (text, apply) => depth === "none" ? text : apply(text);
|
|
24885
24505
|
const statuses = describeProviders(environment);
|
|
@@ -24950,7 +24570,7 @@ function modelPriceCatalogFor(prices, exact) {
|
|
|
24950
24570
|
return { ...rates, ...prices.largeContext ? { largeContext: prices.largeContext } : {} };
|
|
24951
24571
|
}
|
|
24952
24572
|
|
|
24953
|
-
//
|
|
24573
|
+
// src/app/job-launch.ts
|
|
24954
24574
|
async function runJobWorkerProcess(root, jobId) {
|
|
24955
24575
|
const savedSettings = await loadSettings(process.env);
|
|
24956
24576
|
const environment = mergedEnvironment(savedSettings, process.env);
|
|
@@ -24987,10 +24607,10 @@ async function runJobWorkerProcess(root, jobId) {
|
|
|
24987
24607
|
}
|
|
24988
24608
|
}
|
|
24989
24609
|
|
|
24990
|
-
//
|
|
24610
|
+
// src/app/startup-commands.ts
|
|
24991
24611
|
import { createInterface as createInterface4 } from "node:readline/promises";
|
|
24992
24612
|
|
|
24993
|
-
//
|
|
24613
|
+
// src/headless.ts
|
|
24994
24614
|
var EXIT_CODES2 = {
|
|
24995
24615
|
completed: 0,
|
|
24996
24616
|
failed: 1,
|
|
@@ -25014,7 +24634,7 @@ function exitCodeForStatus2(status) {
|
|
|
25014
24634
|
return STATUS_EXIT2[status];
|
|
25015
24635
|
}
|
|
25016
24636
|
|
|
25017
|
-
//
|
|
24637
|
+
// src/platform/doctor.ts
|
|
25018
24638
|
var DEFAULT_PROBE_TIMEOUT_MS = 5000;
|
|
25019
24639
|
function modelEndpoints(environment) {
|
|
25020
24640
|
return providerEndpoints(environment).map((provider) => {
|
|
@@ -25144,7 +24764,7 @@ function doctorReport(probes, context) {
|
|
|
25144
24764
|
};
|
|
25145
24765
|
}
|
|
25146
24766
|
|
|
25147
|
-
//
|
|
24767
|
+
// src/text/color-depth.ts
|
|
25148
24768
|
function detectColorDepth2(environment, isTTY) {
|
|
25149
24769
|
if (!isTTY || environment.NO_COLOR !== undefined || environment.TERM === "dumb")
|
|
25150
24770
|
return "none";
|
|
@@ -25153,7 +24773,7 @@ function detectColorDepth2(environment, isTTY) {
|
|
|
25153
24773
|
return "ansi256";
|
|
25154
24774
|
}
|
|
25155
24775
|
|
|
25156
|
-
//
|
|
24776
|
+
// src/session/delete-session.ts
|
|
25157
24777
|
import { promises as fs21 } from "node:fs";
|
|
25158
24778
|
import path28 from "node:path";
|
|
25159
24779
|
var SAFE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
@@ -25173,7 +24793,7 @@ async function clearProjection(root, id) {
|
|
|
25173
24793
|
if (!exists)
|
|
25174
24794
|
return;
|
|
25175
24795
|
try {
|
|
25176
|
-
const { SessionProjection } = await import("./projection-
|
|
24796
|
+
const { SessionProjection } = await import("./projection-ndr3t77h.mjs");
|
|
25177
24797
|
const projection = await SessionProjection.open(root);
|
|
25178
24798
|
try {
|
|
25179
24799
|
await projection.rebuild(id);
|
|
@@ -25199,7 +24819,7 @@ async function deleteSession(root, id, options = {}) {
|
|
|
25199
24819
|
return { deleted: true };
|
|
25200
24820
|
}
|
|
25201
24821
|
|
|
25202
|
-
//
|
|
24822
|
+
// src/ui/navigation.ts
|
|
25203
24823
|
var ESSENTIAL_COMMANDS = ["/help", "/history", "/model", "/mode", "/diff", "/undo", "/settings", "/exit"];
|
|
25204
24824
|
function isEssential(command) {
|
|
25205
24825
|
return ESSENTIAL_COMMANDS.includes(command);
|
|
@@ -25266,7 +24886,7 @@ function renderAsks(suggestions, style3) {
|
|
|
25266
24886
|
`);
|
|
25267
24887
|
}
|
|
25268
24888
|
|
|
25269
|
-
//
|
|
24889
|
+
// src/app/help.ts
|
|
25270
24890
|
function helpText(language = "en", shortcuts = new Map) {
|
|
25271
24891
|
const star = glyphs.star;
|
|
25272
24892
|
const mark = (command) => isEssential(command) ? `${star} ` : " ";
|
|
@@ -25371,7 +24991,7 @@ ${renderCommandHelp(language, shortcuts, { mark })}
|
|
|
25371
24991
|
`;
|
|
25372
24992
|
}
|
|
25373
24993
|
|
|
25374
|
-
//
|
|
24994
|
+
// src/app/prompts.ts
|
|
25375
24995
|
function settingsChooser(readline) {
|
|
25376
24996
|
return (request) => openChooser({ readline, input: process.stdin, output: process.stdout }, request.items.map((item) => ({ ...item })), {
|
|
25377
24997
|
title: request.title,
|
|
@@ -25444,7 +25064,7 @@ async function hiddenQuestion2(readline, question, signal) {
|
|
|
25444
25064
|
}
|
|
25445
25065
|
}
|
|
25446
25066
|
|
|
25447
|
-
//
|
|
25067
|
+
// src/app/startup-commands.ts
|
|
25448
25068
|
function runInformationFlag(context) {
|
|
25449
25069
|
const { args, environment, language, earlyDepth } = context;
|
|
25450
25070
|
if (args.help) {
|
|
@@ -25648,7 +25268,7 @@ ${status.reason ?? "native state engine unavailable"}
|
|
|
25648
25268
|
return 0;
|
|
25649
25269
|
}
|
|
25650
25270
|
|
|
25651
|
-
//
|
|
25271
|
+
// src/app/display-currency.ts
|
|
25652
25272
|
async function settleDisplayCurrency(options) {
|
|
25653
25273
|
const { args, environment, prices, rates, state } = options;
|
|
25654
25274
|
if (prices && state.display !== prices.currency) {
|
|
@@ -25705,7 +25325,7 @@ async function settleDisplayCurrency(options) {
|
|
|
25705
25325
|
return;
|
|
25706
25326
|
}
|
|
25707
25327
|
|
|
25708
|
-
//
|
|
25328
|
+
// src/app/workspaces.ts
|
|
25709
25329
|
function createWorkspaceFactory(args, environment) {
|
|
25710
25330
|
return async (request) => {
|
|
25711
25331
|
const announce = (text) => {
|
|
@@ -25715,8 +25335,8 @@ function createWorkspaceFactory(args, environment) {
|
|
|
25715
25335
|
};
|
|
25716
25336
|
const minutes = Math.max(1, Math.min(args.sandboxMinutes, 60));
|
|
25717
25337
|
if (request.backend === "e2b") {
|
|
25718
|
-
const { findWorkspacePreset } = await import("./sandbox-templates-
|
|
25719
|
-
const { createE2BProvider } = await import("./factory-
|
|
25338
|
+
const { findWorkspacePreset } = await import("./sandbox-templates-9jcjws23.mjs");
|
|
25339
|
+
const { createE2BProvider } = await import("./factory-r6r0ypm6.mjs");
|
|
25720
25340
|
const preset = findWorkspacePreset(request.preset ?? args.preset);
|
|
25721
25341
|
const sandbox = createE2BProvider(environment, preset.templateAlias);
|
|
25722
25342
|
if (!sandbox)
|
|
@@ -25742,7 +25362,7 @@ function createWorkspaceFactory(args, environment) {
|
|
|
25742
25362
|
return { workspace: created };
|
|
25743
25363
|
}
|
|
25744
25364
|
if (request.backend === "docker") {
|
|
25745
|
-
const { createDockerProvider } = await import("./factory-
|
|
25365
|
+
const { createDockerProvider } = await import("./factory-r6r0ypm6.mjs");
|
|
25746
25366
|
const image = request.dockerImage || args.dockerImage || environment.DOCKER_CODING_IMAGE;
|
|
25747
25367
|
const sandbox = createDockerProvider({ ...environment, DOCKER_CODING_IMAGE: image });
|
|
25748
25368
|
if (!sandbox)
|
|
@@ -25771,11 +25391,11 @@ function createWorkspaceFactory(args, environment) {
|
|
|
25771
25391
|
};
|
|
25772
25392
|
}
|
|
25773
25393
|
|
|
25774
|
-
//
|
|
25394
|
+
// ../core/src/cli/balance.ts
|
|
25775
25395
|
var CRITICAL_BALANCE_USD2 = 0.5;
|
|
25776
25396
|
var LOW_BALANCE_USD2 = 2;
|
|
25777
25397
|
|
|
25778
|
-
//
|
|
25398
|
+
// src/commands/balance.ts
|
|
25779
25399
|
function formatBalance(amount, currency) {
|
|
25780
25400
|
return formatMoney(fromUnits(amount, currency));
|
|
25781
25401
|
}
|
|
@@ -25878,7 +25498,7 @@ class BalanceWatch {
|
|
|
25878
25498
|
}
|
|
25879
25499
|
}
|
|
25880
25500
|
|
|
25881
|
-
//
|
|
25501
|
+
// src/session/resumed-spend.ts
|
|
25882
25502
|
async function readSessionModelTurns(root, sessionId) {
|
|
25883
25503
|
const events = await readEventJournal(root, sessionId);
|
|
25884
25504
|
const turns = [];
|
|
@@ -25910,7 +25530,7 @@ function priceSessionModelTurns(turns, options) {
|
|
|
25910
25530
|
return { spent: total, unpriced: [...unpriced].sort() };
|
|
25911
25531
|
}
|
|
25912
25532
|
|
|
25913
|
-
//
|
|
25533
|
+
// src/app/balance-tracking.ts
|
|
25914
25534
|
function createBalanceTracking(options) {
|
|
25915
25535
|
const { environment, processEnvironment, rates, state } = options;
|
|
25916
25536
|
const usdInDisplay = (usd) => {
|
|
@@ -25999,7 +25619,7 @@ function createBalanceTracking(options) {
|
|
|
25999
25619
|
return { lowBalance, criticalBalance, balanceWatch, parseManualBalance, currentBalance, persistManualBalance, sessionSpend, balanceHeader, checkBalance, carryResumedSpend };
|
|
26000
25620
|
}
|
|
26001
25621
|
|
|
26002
|
-
//
|
|
25622
|
+
// src/app/agent-factory.ts
|
|
26003
25623
|
function createClientFactory(options) {
|
|
26004
25624
|
const { args, environment, daemon, approvalPrompt, rates, approvedBudget, state } = options;
|
|
26005
25625
|
return async (record2, runtime = {}) => {
|
|
@@ -26020,6 +25640,7 @@ function createClientFactory(options) {
|
|
|
26020
25640
|
onExpense: (expense) => state.ledger.recordExpense(expense),
|
|
26021
25641
|
onEvent,
|
|
26022
25642
|
jev: jevOptionsFromEnvironment(environment),
|
|
25643
|
+
...reasoningFromEnvironment(environment) ? { reasoning: reasoningFromEnvironment(environment) } : {},
|
|
26023
25644
|
afterEdit: editDiagnostics
|
|
26024
25645
|
}), record2);
|
|
26025
25646
|
if (editDiagnostics)
|
|
@@ -26039,14 +25660,14 @@ function closeWithClient(client, hook) {
|
|
|
26039
25660
|
client.dispose = () => dispose().finally(close);
|
|
26040
25661
|
}
|
|
26041
25662
|
|
|
26042
|
-
//
|
|
26043
|
-
async function
|
|
25663
|
+
// src/app/live-models.ts
|
|
25664
|
+
async function readCachedLiveModels(environment, state) {
|
|
26044
25665
|
const cached = await readModelCache(environment);
|
|
26045
25666
|
if (isCacheFresh(cached))
|
|
26046
25667
|
state.liveModels = cached.models;
|
|
26047
25668
|
}
|
|
26048
25669
|
|
|
26049
|
-
//
|
|
25670
|
+
// src/app/session-hints.ts
|
|
26050
25671
|
function createSessionHints(options) {
|
|
26051
25672
|
const { state, watched, tabs, usage } = options;
|
|
26052
25673
|
const navContext = () => ({
|
|
@@ -26075,7 +25696,7 @@ function createSessionHints(options) {
|
|
|
26075
25696
|
return { navContext, writeHint };
|
|
26076
25697
|
}
|
|
26077
25698
|
|
|
26078
|
-
//
|
|
25699
|
+
// src/render/completion-card.ts
|
|
26079
25700
|
var CHECK_LABELS = {
|
|
26080
25701
|
tests: "tests",
|
|
26081
25702
|
typecheck: "typecheck",
|
|
@@ -26105,7 +25726,7 @@ function renderCompletionCard(input, style3) {
|
|
|
26105
25726
|
return panel(lines, style3, { title, tone: failed2 ? "bad" : verified ? "good" : "warn" });
|
|
26106
25727
|
}
|
|
26107
25728
|
|
|
26108
|
-
//
|
|
25729
|
+
// src/render/routing-receipt.ts
|
|
26109
25730
|
function formatMicros(micros, currency = "USD") {
|
|
26110
25731
|
if (micros === undefined || !Number.isFinite(micros))
|
|
26111
25732
|
return "—";
|
|
@@ -26197,10 +25818,10 @@ ${rule(cell, { label: badge })}` : out3.join(`
|
|
|
26197
25818
|
`);
|
|
26198
25819
|
}
|
|
26199
25820
|
|
|
26200
|
-
//
|
|
25821
|
+
// src/app/session-hints.ts
|
|
26201
25822
|
var failureStatus = (status) => status === "needs_approval" ? "waiting_approval" : status;
|
|
26202
25823
|
|
|
26203
|
-
//
|
|
25824
|
+
// src/app/turn-failure.ts
|
|
26204
25825
|
async function handleTurnFailure(error, request, context) {
|
|
26205
25826
|
const { args, environment, interactive, headless, recoveryState, state, navContext } = context;
|
|
26206
25827
|
if (recoveryState.last?.request === request) {
|
|
@@ -26255,7 +25876,7 @@ ${style.yellow(`Stopped at the ${formatMoney(fromUnits(args.budget, state.displa
|
|
|
26255
25876
|
return false;
|
|
26256
25877
|
}
|
|
26257
25878
|
|
|
26258
|
-
//
|
|
25879
|
+
// src/app/turn-preflight.ts
|
|
26259
25880
|
async function runTurnPreflight(request, context) {
|
|
26260
25881
|
const { args, readline, interactive, approvedBudget, rates, state } = context;
|
|
26261
25882
|
const { currentBalance, balanceWatch, sessionSpend } = context.balance;
|
|
@@ -26353,7 +25974,7 @@ async function runTurnPreflight(request, context) {
|
|
|
26353
25974
|
return true;
|
|
26354
25975
|
}
|
|
26355
25976
|
|
|
26356
|
-
//
|
|
25977
|
+
// src/app/turn-runner.ts
|
|
26357
25978
|
var addModelUsage2 = (left, right) => ({
|
|
26358
25979
|
inputTokens: left.inputTokens + right.inputTokens,
|
|
26359
25980
|
outputTokens: left.outputTokens + right.outputTokens,
|
|
@@ -26561,7 +26182,7 @@ ${result.status === "completed" ? asMarkdown(result.summary) : style.yellow(resu
|
|
|
26561
26182
|
};
|
|
26562
26183
|
}
|
|
26563
26184
|
|
|
26564
|
-
//
|
|
26185
|
+
// src/app/interrupts.ts
|
|
26565
26186
|
function createSigintHandling(options) {
|
|
26566
26187
|
const { readline, state } = options;
|
|
26567
26188
|
const handleSigint = () => {
|
|
@@ -26602,7 +26223,7 @@ function createSigintHandling(options) {
|
|
|
26602
26223
|
return { bindSigint, unbindSigint };
|
|
26603
26224
|
}
|
|
26604
26225
|
|
|
26605
|
-
//
|
|
26226
|
+
// src/app/session-start.ts
|
|
26606
26227
|
import path29 from "node:path";
|
|
26607
26228
|
async function resumeAtStartup(context) {
|
|
26608
26229
|
const { args, interactive, stateHistory, state, openClient } = context;
|
|
@@ -26675,7 +26296,7 @@ async function runOneShot(context) {
|
|
|
26675
26296
|
return args.json ? exitCodeForStatus2(state.lastTurnStatus) : ran ? 0 : 1;
|
|
26676
26297
|
}
|
|
26677
26298
|
|
|
26678
|
-
//
|
|
26299
|
+
// src/archymedes.ts
|
|
26679
26300
|
async function main() {
|
|
26680
26301
|
process.stdout.on("error", (error) => {
|
|
26681
26302
|
if (error.code === "EPIPE")
|
|
@@ -27113,7 +26734,7 @@ async function main() {
|
|
|
27113
26734
|
out2.route(firstSink);
|
|
27114
26735
|
let explainedTabs = false;
|
|
27115
26736
|
let liveModels = {};
|
|
27116
|
-
await
|
|
26737
|
+
await readCachedLiveModels(environment, state);
|
|
27117
26738
|
if (args.estimateOnly) {
|
|
27118
26739
|
out2.write(`${ledger.formatPrediction(await agent.estimate(args.prompt))}
|
|
27119
26740
|
`);
|