archymedes-cli 3.2.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 +588 -946
- 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,11 +15497,11 @@ async function saveSetup(params, deps) {
|
|
|
15970
15497
|
return { ok: true, file, ...note ? { note } : {} };
|
|
15971
15498
|
}
|
|
15972
15499
|
|
|
15973
|
-
//
|
|
15500
|
+
// ../core/src/providers/model-fetch.ts
|
|
15974
15501
|
import { promises as fs16 } from "node:fs";
|
|
15975
15502
|
import path21 from "node:path";
|
|
15976
15503
|
|
|
15977
|
-
//
|
|
15504
|
+
// ../core/src/providers/model-list.ts
|
|
15978
15505
|
function modelsUrl(base) {
|
|
15979
15506
|
const trimmed = base.replace(/\/+$/, "");
|
|
15980
15507
|
return trimmed.endsWith("/v1") ? `${trimmed}/models` : `${trimmed}/v1/models`;
|
|
@@ -16084,7 +15611,7 @@ function mergeModelLists(known, live) {
|
|
|
16084
15611
|
const added = live.filter((model) => !seen.has(model)).sort();
|
|
16085
15612
|
return [...known, ...added];
|
|
16086
15613
|
}
|
|
16087
|
-
//
|
|
15614
|
+
// ../core/src/providers/model-fetch.ts
|
|
16088
15615
|
async function fetchProviderModels(provider, environment, fetchImpl, timeoutMs = 4000) {
|
|
16089
15616
|
if (provider === "free") {
|
|
16090
15617
|
try {
|
|
@@ -16172,7 +15699,7 @@ function fetchableProviders(environment, providers) {
|
|
|
16172
15699
|
return providers.filter((provider) => provider !== "archymedes-cloud" && missingRequirements(provider, environment).length === 0);
|
|
16173
15700
|
}
|
|
16174
15701
|
|
|
16175
|
-
//
|
|
15702
|
+
// src/session/models.ts
|
|
16176
15703
|
function modelsForProvider(provider, asOf) {
|
|
16177
15704
|
const seen = new Set;
|
|
16178
15705
|
for (const record2 of PRICE_CATALOG) {
|
|
@@ -16196,7 +15723,7 @@ function describePrice(prices, display, convert2) {
|
|
|
16196
15723
|
return `${formatMoney(input)}/${formatMoney(output)} per Mtok`;
|
|
16197
15724
|
}
|
|
16198
15725
|
|
|
16199
|
-
//
|
|
15726
|
+
// src/app/acp-models.ts
|
|
16200
15727
|
var PUBLIC_LISTINGS = ["free", "openrouter"];
|
|
16201
15728
|
async function modelList(environment, params, options = {}) {
|
|
16202
15729
|
const offline = /^(1|true|on|yes)$/i.test(environment.ARCHYMEDES_MODELS_OFFLINE?.trim() ?? "");
|
|
@@ -16239,7 +15766,8 @@ async function modelList(environment, params, options = {}) {
|
|
|
16239
15766
|
price: free ? "free" : prices ? describePrice(prices, prices.currency, (value) => value) : "unpriced",
|
|
16240
15767
|
free,
|
|
16241
15768
|
locked: missing.length > 0,
|
|
16242
|
-
missing
|
|
15769
|
+
missing,
|
|
15770
|
+
small: isSmallModel(model)
|
|
16243
15771
|
};
|
|
16244
15772
|
(choice.locked ? locked : ready).push(choice);
|
|
16245
15773
|
}
|
|
@@ -16247,7 +15775,7 @@ async function modelList(environment, params, options = {}) {
|
|
|
16247
15775
|
return { choices: [...ready, ...locked], unconfigured, errors, providers: PROVIDER_IDS.length };
|
|
16248
15776
|
}
|
|
16249
15777
|
|
|
16250
|
-
//
|
|
15778
|
+
// src/app/acp-commands.ts
|
|
16251
15779
|
async function runSessionCommand(command, argument, session) {
|
|
16252
15780
|
switch (command) {
|
|
16253
15781
|
case "cost":
|
|
@@ -16272,15 +15800,115 @@ async function runSessionCommand(command, argument, session) {
|
|
|
16272
15800
|
const items = session.agent.todos.map((item) => ({ text: item.text, status: item.status }));
|
|
16273
15801
|
return items.length > 0 ? { kind: "todos", items } : { kind: "text", text: "No plan yet." };
|
|
16274
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
|
+
}
|
|
16275
15812
|
default:
|
|
16276
15813
|
return { kind: "error", text: `Unknown session command "${command}".` };
|
|
16277
15814
|
}
|
|
16278
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
|
+
}
|
|
16279
15855
|
|
|
16280
|
-
//
|
|
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
|
+
}
|
|
15907
|
+
|
|
15908
|
+
// src/app/startup-update.ts
|
|
16281
15909
|
import { spawn as spawn8 } from "node:child_process";
|
|
16282
15910
|
|
|
16283
|
-
//
|
|
15911
|
+
// src/platform/auto-update.ts
|
|
16284
15912
|
import { promises as fs17 } from "node:fs";
|
|
16285
15913
|
import path22 from "node:path";
|
|
16286
15914
|
var AUTO_UPDATE_INTERVAL_MS = 24 * 60 * 60 * 1000;
|
|
@@ -16393,7 +16021,7 @@ async function runAutoUpdate(options) {
|
|
|
16393
16021
|
return { notice: [], decision };
|
|
16394
16022
|
}
|
|
16395
16023
|
|
|
16396
|
-
//
|
|
16024
|
+
// src/platform/defender-feed-update.ts
|
|
16397
16025
|
var OFFICIAL_DEFENDER_FEED_URL = "https://circuit-archymedes.vercel.app/api/defender-brain/manifest";
|
|
16398
16026
|
var OFFICIAL_DEFENDER_FEED_KEYS = Object.freeze({
|
|
16399
16027
|
"release-2026-01": "MCowBQYDK2VwAyEA4/jb1zd6f+jIPAFja1bPNtroXV8MtAZFrKt5BSY+ngI="
|
|
@@ -16421,12 +16049,12 @@ async function updateDefenderFeed(environment) {
|
|
|
16421
16049
|
});
|
|
16422
16050
|
}
|
|
16423
16051
|
|
|
16424
|
-
//
|
|
16052
|
+
// src/platform/update.ts
|
|
16425
16053
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
16426
16054
|
import { tmpdir } from "node:os";
|
|
16427
16055
|
import { createInterface as createInterface3 } from "node:readline/promises";
|
|
16428
16056
|
|
|
16429
|
-
//
|
|
16057
|
+
// src/catalog/commands.ts
|
|
16430
16058
|
function defineCommands(table) {
|
|
16431
16059
|
return Object.entries(table).map(([name, command]) => ({ name, ...command }));
|
|
16432
16060
|
}
|
|
@@ -16499,7 +16127,7 @@ function renderCommandHelp(language = "en", shortcuts = new Map, options = {}) {
|
|
|
16499
16127
|
`);
|
|
16500
16128
|
}
|
|
16501
16129
|
|
|
16502
|
-
//
|
|
16130
|
+
// src/terminal/keybindings.ts
|
|
16503
16131
|
var FUNCTION_KEY = /^f([1-9]|1[0-2])$/;
|
|
16504
16132
|
var NAMED_KEYS = new Set(["tab", "enter", "escape", "space", "up", "down", "left", "right", "home", "end", "pageup", "pagedown", "backspace", "delete"]);
|
|
16505
16133
|
function isKeyName(value) {
|
|
@@ -16749,10 +16377,10 @@ function escapeCodeTimeoutMs(environment = process.env) {
|
|
|
16749
16377
|
const parsed = raw ? Number(raw) : NaN;
|
|
16750
16378
|
return Number.isInteger(parsed) && parsed >= 10 && parsed <= 2000 ? parsed : DEFAULT_ESCAPE_CODE_TIMEOUT_MS;
|
|
16751
16379
|
}
|
|
16752
|
-
//
|
|
16380
|
+
// package.json
|
|
16753
16381
|
var package_default = {
|
|
16754
16382
|
name: "archymedes-cli",
|
|
16755
|
-
version: "3.
|
|
16383
|
+
version: "3.3.0",
|
|
16756
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.",
|
|
16757
16385
|
keywords: [
|
|
16758
16386
|
"cli",
|
|
@@ -16798,12 +16426,12 @@ var package_default = {
|
|
|
16798
16426
|
prepublishOnly: "bun run ../../tooling/build/build-packages.ts"
|
|
16799
16427
|
},
|
|
16800
16428
|
optionalDependencies: {
|
|
16801
|
-
"@archymedes/cli-darwin-arm64": "3.
|
|
16802
|
-
"@archymedes/cli-darwin-x64": "3.
|
|
16803
|
-
"@archymedes/cli-linux-arm64": "3.
|
|
16804
|
-
"@archymedes/cli-linux-x64": "3.
|
|
16805
|
-
"@archymedes/cli-win32-arm64": "3.
|
|
16806
|
-
"@archymedes/cli-win32-x64": "3.
|
|
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",
|
|
16807
16435
|
"@archymedes/state-darwin-arm64": "0.4.0",
|
|
16808
16436
|
"@archymedes/state-darwin-x64": "0.4.0",
|
|
16809
16437
|
"@archymedes/state-linux-arm64-gnu": "0.4.0",
|
|
@@ -16815,7 +16443,7 @@ var package_default = {
|
|
|
16815
16443
|
}
|
|
16816
16444
|
};
|
|
16817
16445
|
|
|
16818
|
-
//
|
|
16446
|
+
// src/platform/update.ts
|
|
16819
16447
|
var ARCHYMEDES_CLI_PACKAGE = "archymedes-cli";
|
|
16820
16448
|
var ARCHYMEDES_CLI_VERSION = package_default.version;
|
|
16821
16449
|
var DEFAULT_REGISTRY = "https://registry.npmjs.org";
|
|
@@ -17033,7 +16661,7 @@ async function runSelfUpdate(options = {}) {
|
|
|
17033
16661
|
return { status: "updated", currentVersion, latestVersion, code: 0 };
|
|
17034
16662
|
}
|
|
17035
16663
|
|
|
17036
|
-
//
|
|
16664
|
+
// src/text/ansi.ts
|
|
17037
16665
|
var RESET = "\x1B[0m";
|
|
17038
16666
|
var BOLD = "\x1B[1m";
|
|
17039
16667
|
var DIM = "\x1B[2m";
|
|
@@ -17046,7 +16674,7 @@ function paintAll(text, codes, depth) {
|
|
|
17046
16674
|
return depth === "none" || codes.length === 0 ? text : `${codes.join("")}${text}${RESET}`;
|
|
17047
16675
|
}
|
|
17048
16676
|
|
|
17049
|
-
//
|
|
16677
|
+
// src/terminal/output.ts
|
|
17050
16678
|
var terminalStream = {
|
|
17051
16679
|
write(text) {
|
|
17052
16680
|
process.stdout.write(text);
|
|
@@ -17080,7 +16708,7 @@ class OutputRouter {
|
|
|
17080
16708
|
}
|
|
17081
16709
|
}
|
|
17082
16710
|
|
|
17083
|
-
//
|
|
16711
|
+
// src/text/glyphs.ts
|
|
17084
16712
|
var UNICODE_GLYPHS = {
|
|
17085
16713
|
starGlyphs: [".", "·", "✧", "✦", "✶"],
|
|
17086
16714
|
spinnerFrames: [" ◜ ", " ◠ ", " ◝ ", " ◞ ", " ◡ ", " ◟ "],
|
|
@@ -17187,7 +16815,7 @@ function borderGlyphsFor(style, glyphs) {
|
|
|
17187
16815
|
return ROUND_BORDER;
|
|
17188
16816
|
}
|
|
17189
16817
|
|
|
17190
|
-
//
|
|
16818
|
+
// src/text/text-width.ts
|
|
17191
16819
|
var ANSI = /\x1b\[[0-9;]*m/g;
|
|
17192
16820
|
var PRINTABLE_ASCII = /^[\x20-\x7e]*$/;
|
|
17193
16821
|
function visibleWidth(text) {
|
|
@@ -17222,7 +16850,7 @@ function clipTo(text, width, glyphs = UNICODE_GLYPHS) {
|
|
|
17222
16850
|
return `${out}${mark}`;
|
|
17223
16851
|
}
|
|
17224
16852
|
|
|
17225
|
-
//
|
|
16853
|
+
// src/render/syntax.ts
|
|
17226
16854
|
function newSyntaxState() {
|
|
17227
16855
|
return {};
|
|
17228
16856
|
}
|
|
@@ -17869,7 +17497,7 @@ function highlightSyntax(line, options) {
|
|
|
17869
17497
|
return `${out}${RESET}`;
|
|
17870
17498
|
}
|
|
17871
17499
|
|
|
17872
|
-
//
|
|
17500
|
+
// src/render/markdown.ts
|
|
17873
17501
|
var colour = (role, palette) => palette?.[role] || ANSI_PALETTE[role];
|
|
17874
17502
|
var INLINE_PATTERN = /(?<!\\)(`[^`\n]+`)|(?<!\\)(\*\*[^*\n]+\*\*)|(?<!\\)(__[^_\n]+__)|(?<!\\)(~~[^~\n]+~~)|(?<!\\)(\*[^*\n]+\*)|(?<!\\)(_[^_\n]+_)|(!?\[([^\]\n]+)\]\((https?:\/\/[^\s)\n]+)\))|(<(https?:\/\/[^>\s]+)>)/g;
|
|
17875
17503
|
var unescapeMarkdown = (text) => text.replace(/\\([\\`*_[\]{}()#+.!~>-])/g, "$1");
|
|
@@ -18090,7 +17718,7 @@ function renderMarkdown(text, options) {
|
|
|
18090
17718
|
`);
|
|
18091
17719
|
}
|
|
18092
17720
|
|
|
18093
|
-
//
|
|
17721
|
+
// src/render/tui.ts
|
|
18094
17722
|
function archymedesSpinnerFrame(index, glyphs = UNICODE_GLYPHS) {
|
|
18095
17723
|
const frames = glyphs.spinnerFrames;
|
|
18096
17724
|
const normalized = Number.isFinite(index) ? Math.max(0, Math.floor(index)) : 0;
|
|
@@ -18678,7 +18306,7 @@ function wrapPlain(text, width) {
|
|
|
18678
18306
|
return lines.length === 0 ? [""] : lines;
|
|
18679
18307
|
}
|
|
18680
18308
|
|
|
18681
|
-
//
|
|
18309
|
+
// src/render/transcript.ts
|
|
18682
18310
|
function truncateMiddle(value, maximum) {
|
|
18683
18311
|
const clean = value.replace(/\s+/g, " ").trim();
|
|
18684
18312
|
if (clean.length <= maximum)
|
|
@@ -18841,7 +18469,7 @@ function summarizeToolResult(toolName, content, isError) {
|
|
|
18841
18469
|
}
|
|
18842
18470
|
}
|
|
18843
18471
|
|
|
18844
|
-
//
|
|
18472
|
+
// src/render/sections.ts
|
|
18845
18473
|
var TONE_ROLE = {
|
|
18846
18474
|
good: "success",
|
|
18847
18475
|
bad: "error",
|
|
@@ -18968,7 +18596,7 @@ function outcomeMark(outcome, style) {
|
|
|
18968
18596
|
}
|
|
18969
18597
|
}
|
|
18970
18598
|
|
|
18971
|
-
//
|
|
18599
|
+
// src/render/code-view.ts
|
|
18972
18600
|
var MAX_DIFF_CELLS = 250000;
|
|
18973
18601
|
function diffLines(before, after) {
|
|
18974
18602
|
const left = before === "" ? [] : before.split(`
|
|
@@ -19265,7 +18893,7 @@ function renderFileChange(change, style, options = {}) {
|
|
|
19265
18893
|
};
|
|
19266
18894
|
}
|
|
19267
18895
|
|
|
19268
|
-
//
|
|
18896
|
+
// src/render/test-report.ts
|
|
19269
18897
|
function toMs(value) {
|
|
19270
18898
|
if (!value)
|
|
19271
18899
|
return;
|
|
@@ -19540,7 +19168,7 @@ function renderTestReport(report, style, options = {}) {
|
|
|
19540
19168
|
`);
|
|
19541
19169
|
}
|
|
19542
19170
|
|
|
19543
|
-
//
|
|
19171
|
+
// src/render/expandable.ts
|
|
19544
19172
|
var MAX_ENTRIES = 64;
|
|
19545
19173
|
|
|
19546
19174
|
class ExpandableStore {
|
|
@@ -19574,7 +19202,7 @@ function expandHint(id, hidden, depth, glyphs = UNICODE_GLYPHS) {
|
|
|
19574
19202
|
return paint(`${glyphs.collapsed} ${hidden} more line${hidden === 1 ? "" : "s"} hidden ${glyphs.middot} /expand ${id}`, DIM, depth);
|
|
19575
19203
|
}
|
|
19576
19204
|
|
|
19577
|
-
//
|
|
19205
|
+
// src/app/transcript.ts
|
|
19578
19206
|
var colorEnabled = false;
|
|
19579
19207
|
var wrap = (code) => (value) => colorEnabled ? `${code}${value}${RESET}` : value;
|
|
19580
19208
|
var palette = NO_COLOR_PALETTE;
|
|
@@ -19654,7 +19282,7 @@ function beginTranscriptTurn() {
|
|
|
19654
19282
|
markdown.reset();
|
|
19655
19283
|
}
|
|
19656
19284
|
|
|
19657
|
-
//
|
|
19285
|
+
// src/app/startup-update.ts
|
|
19658
19286
|
async function startupMaintenance(environment, interactive, install) {
|
|
19659
19287
|
updateDefenderFeed(environment).catch(() => {
|
|
19660
19288
|
return;
|
|
@@ -19693,7 +19321,7 @@ function installInChildProcess(entry, environment) {
|
|
|
19693
19321
|
});
|
|
19694
19322
|
}
|
|
19695
19323
|
|
|
19696
|
-
//
|
|
19324
|
+
// src/app/jev.ts
|
|
19697
19325
|
function jevOptionsFromEnvironment(environment) {
|
|
19698
19326
|
if ((environment.ARCHYMEDES_JEV ?? "").trim().toLowerCase() === "off")
|
|
19699
19327
|
return;
|
|
@@ -19704,7 +19332,7 @@ function jevOptionsFromEnvironment(environment) {
|
|
|
19704
19332
|
return { apiKey, ...model ? { model } : {}, ...environment.ARCHYMEDES_JEV_REVIEW?.trim().toLowerCase() === "off" ? { review: false } : {} };
|
|
19705
19333
|
}
|
|
19706
19334
|
|
|
19707
|
-
//
|
|
19335
|
+
// ../core/src/providers/exa.ts
|
|
19708
19336
|
var LATENCY_CEILING = {
|
|
19709
19337
|
instant: 5000,
|
|
19710
19338
|
fast: 1e4,
|
|
@@ -19910,7 +19538,7 @@ function createExaClient(environment, fetchImpl) {
|
|
|
19910
19538
|
});
|
|
19911
19539
|
}
|
|
19912
19540
|
|
|
19913
|
-
//
|
|
19541
|
+
// src/acp-server.ts
|
|
19914
19542
|
function splitFrames(buffer) {
|
|
19915
19543
|
const parts = buffer.split(`
|
|
19916
19544
|
`);
|
|
@@ -19928,6 +19556,8 @@ async function runAcpServer(options) {
|
|
|
19928
19556
|
extensions: {
|
|
19929
19557
|
"_archymedes/setup/status": async () => setupStatus(options.environment, { provider: options.provider, model: options.model }),
|
|
19930
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 }),
|
|
19931
19561
|
"_archymedes/models": async (params) => modelList(options.environment, params),
|
|
19932
19562
|
"_archymedes/startup": async () => ({
|
|
19933
19563
|
notices: await (startup ??= startupMaintenance(options.environment, false, installInChildProcess({ execPath: process.execPath, script: process.argv[1] ?? "" }, options.environment)))
|
|
@@ -19948,7 +19578,7 @@ async function runAcpServer(options) {
|
|
|
19948
19578
|
const workspace = started.workspace;
|
|
19949
19579
|
let agent = build(mode);
|
|
19950
19580
|
function build(currentMode) {
|
|
19951
|
-
|
|
19581
|
+
const built = new ArchymedesAgent({
|
|
19952
19582
|
root,
|
|
19953
19583
|
model: resolved.provider,
|
|
19954
19584
|
prices: priceCatalogFor(resolved.prices),
|
|
@@ -19957,9 +19587,12 @@ async function runAcpServer(options) {
|
|
|
19957
19587
|
search: createExaClient(options.environment),
|
|
19958
19588
|
onEvent,
|
|
19959
19589
|
jev: jevOptionsFromEnvironment(options.environment),
|
|
19590
|
+
...reasoningFromEnvironment(options.environment) ? { reasoning: reasoningFromEnvironment(options.environment) } : {},
|
|
19960
19591
|
afterEdit: acpEditDiagnostics(root, workspace, options.environment),
|
|
19961
19592
|
approve: async (request) => approve({ toolName: request.tool.name, summary: request.summary, toolCallId: request.call.id, ...request.pattern ? { pattern: request.pattern } : {} })
|
|
19962
19593
|
});
|
|
19594
|
+
built.warmUp();
|
|
19595
|
+
return built;
|
|
19963
19596
|
}
|
|
19964
19597
|
async function rebuild(change) {
|
|
19965
19598
|
const carried = await loadSession(root, agent.sessionId);
|
|
@@ -20072,10 +19705,10 @@ function priceCatalogFor(prices) {
|
|
|
20072
19705
|
};
|
|
20073
19706
|
}
|
|
20074
19707
|
|
|
20075
|
-
//
|
|
19708
|
+
// src/app/args.ts
|
|
20076
19709
|
import path23 from "node:path";
|
|
20077
19710
|
|
|
20078
|
-
//
|
|
19711
|
+
// src/render/charts.ts
|
|
20079
19712
|
function barChart(data, options) {
|
|
20080
19713
|
if (data.length === 0)
|
|
20081
19714
|
return [];
|
|
@@ -20100,7 +19733,7 @@ function barChart(data, options) {
|
|
|
20100
19733
|
});
|
|
20101
19734
|
}
|
|
20102
19735
|
|
|
20103
|
-
//
|
|
19736
|
+
// src/commands/chat-history.ts
|
|
20104
19737
|
function countTurns(messages) {
|
|
20105
19738
|
return messages.filter((message) => message.role === "user" && !message.internal).length;
|
|
20106
19739
|
}
|
|
@@ -20293,7 +19926,7 @@ function parseHistoryCommand(input) {
|
|
|
20293
19926
|
return { kind: "invalid", reason: `/history takes "list", a session id, "search <text>", "delete <id>", "status", or "resume" — not "${verb}".` };
|
|
20294
19927
|
}
|
|
20295
19928
|
|
|
20296
|
-
//
|
|
19929
|
+
// src/commands/pacing.ts
|
|
20297
19930
|
var PACE_PROFILES = {
|
|
20298
19931
|
off: {
|
|
20299
19932
|
level: "off",
|
|
@@ -20355,7 +19988,7 @@ function paceBadge(level, glyphs2 = UNICODE_GLYPHS) {
|
|
|
20355
19988
|
return `${glyphs2.paused} ${profileFor(level).label}`;
|
|
20356
19989
|
}
|
|
20357
19990
|
|
|
20358
|
-
//
|
|
19991
|
+
// src/app/args.ts
|
|
20359
19992
|
var SESSION_ID2 = /^\d{8}T\d{6}Z-[a-z0-9]{6}$/;
|
|
20360
19993
|
var DEFAULT_DOCKER_IMAGE = "debian:stable-slim";
|
|
20361
19994
|
function parseArgs(argv) {
|
|
@@ -20553,7 +20186,7 @@ function parseArgs(argv) {
|
|
|
20553
20186
|
return parsed;
|
|
20554
20187
|
}
|
|
20555
20188
|
|
|
20556
|
-
//
|
|
20189
|
+
// src/app/session-provider.ts
|
|
20557
20190
|
async function resolveSessionProvider2(environment, options) {
|
|
20558
20191
|
if (options.provider || !options.resume)
|
|
20559
20192
|
return resolveProvider(environment, options);
|
|
@@ -20562,7 +20195,7 @@ async function resolveSessionProvider2(environment, options) {
|
|
|
20562
20195
|
return resolveProvider(environment, selection?.provider === "free" ? { provider: "free", model: options.model ?? selection.model } : options);
|
|
20563
20196
|
}
|
|
20564
20197
|
|
|
20565
|
-
//
|
|
20198
|
+
// src/app/transcript.ts
|
|
20566
20199
|
var colorEnabled2 = false;
|
|
20567
20200
|
var liveTerminal2 = false;
|
|
20568
20201
|
var wrap2 = (code) => (value) => colorEnabled2 ? `${code}${value}${RESET}` : value;
|
|
@@ -20876,7 +20509,7 @@ ${rule(sectionStyle2(), { label: "tool activity", tone: "neutral" })}
|
|
|
20876
20509
|
}
|
|
20877
20510
|
}
|
|
20878
20511
|
|
|
20879
|
-
//
|
|
20512
|
+
// ../core/src/cli/suggestions.ts
|
|
20880
20513
|
var CATEGORY_ORDER = ["blocked", "recovery", "next", "discover", "starter"];
|
|
20881
20514
|
function defaultSignals(overrides = {}) {
|
|
20882
20515
|
return {
|
|
@@ -21273,7 +20906,7 @@ async function askModelForSuggestions(model, signals, context = {}) {
|
|
|
21273
20906
|
}
|
|
21274
20907
|
}
|
|
21275
20908
|
|
|
21276
|
-
//
|
|
20909
|
+
// src/ui/chooser.ts
|
|
21277
20910
|
var ALL_CHROME = { title: true, status: true, pagination: true, help: true };
|
|
21278
20911
|
function chromeOf(chrome) {
|
|
21279
20912
|
return { ...ALL_CHROME, ...chrome };
|
|
@@ -21501,7 +21134,7 @@ async function runChooser(keys, items, paint2, options) {
|
|
|
21501
21134
|
return;
|
|
21502
21135
|
}
|
|
21503
21136
|
|
|
21504
|
-
//
|
|
21137
|
+
// src/ui/navigation.ts
|
|
21505
21138
|
class CommandUsage {
|
|
21506
21139
|
limit;
|
|
21507
21140
|
order = [];
|
|
@@ -21524,8 +21157,8 @@ class CommandUsage {
|
|
|
21524
21157
|
}
|
|
21525
21158
|
}
|
|
21526
21159
|
|
|
21527
|
-
//
|
|
21528
|
-
import { randomUUID as
|
|
21160
|
+
// ../core/src/cli/daemon.ts
|
|
21161
|
+
import { randomUUID as randomUUID6 } from "node:crypto";
|
|
21529
21162
|
var ARCHYMEDES_DAEMON_PROTOCOL_VERSION = 1;
|
|
21530
21163
|
var PREVIEW_HUNK_SEPARATOR = `
|
|
21531
21164
|
…
|
|
@@ -21571,7 +21204,7 @@ class ArchymedesSessionDaemon {
|
|
|
21571
21204
|
sessions = new Map;
|
|
21572
21205
|
pendingApprovals = new Map;
|
|
21573
21206
|
connect(options = {}) {
|
|
21574
|
-
const id = options.id ?? `client_${
|
|
21207
|
+
const id = options.id ?? `client_${randomUUID6()}`;
|
|
21575
21208
|
assertSafeId(id, "Client id");
|
|
21576
21209
|
if (this.clients.has(id))
|
|
21577
21210
|
throw new Error(`Daemon client already connected: ${id}`);
|
|
@@ -21590,7 +21223,7 @@ class ArchymedesSessionDaemon {
|
|
|
21590
21223
|
}
|
|
21591
21224
|
async requestApproval(sessionId, request) {
|
|
21592
21225
|
const publicRequest = {
|
|
21593
|
-
id: `approval_${
|
|
21226
|
+
id: `approval_${randomUUID6()}`,
|
|
21594
21227
|
sessionId,
|
|
21595
21228
|
summary: request.summary,
|
|
21596
21229
|
actionDigest: request.actionDigest,
|
|
@@ -21863,7 +21496,7 @@ class ArchymedesDaemonClient {
|
|
|
21863
21496
|
planRoute(objective, signal) {
|
|
21864
21497
|
return this.daemon.planRoute(this.id, this.sessionId, objective, signal);
|
|
21865
21498
|
}
|
|
21866
|
-
send(objective, commandId = `turn_${
|
|
21499
|
+
send(objective, commandId = `turn_${randomUUID6()}`) {
|
|
21867
21500
|
return this.daemon.send(this.id, this.sessionId, objective, commandId);
|
|
21868
21501
|
}
|
|
21869
21502
|
cancel() {
|
|
@@ -21922,7 +21555,7 @@ class ArchymedesDaemonClient {
|
|
|
21922
21555
|
}
|
|
21923
21556
|
}
|
|
21924
21557
|
|
|
21925
|
-
//
|
|
21558
|
+
// ../core/src/money.ts
|
|
21926
21559
|
var CURRENCIES2 = (() => {
|
|
21927
21560
|
try {
|
|
21928
21561
|
return Intl.supportedValuesOf("currency");
|
|
@@ -21965,7 +21598,7 @@ function formatMoney2(value) {
|
|
|
21965
21598
|
return value.currency === "USD" ? `${format.symbol}${rendered}` : `${format.symbol} ${rendered}`;
|
|
21966
21599
|
}
|
|
21967
21600
|
|
|
21968
|
-
//
|
|
21601
|
+
// ../core/src/cli/backends.ts
|
|
21969
21602
|
import path24 from "node:path";
|
|
21970
21603
|
var CONFIG_FILE_SCAN_LIMIT2 = 500;
|
|
21971
21604
|
function localCommandGuidance2(platform) {
|
|
@@ -22059,11 +21692,11 @@ class LocalWorkspace2 {
|
|
|
22059
21692
|
}
|
|
22060
21693
|
}
|
|
22061
21694
|
|
|
22062
|
-
//
|
|
21695
|
+
// ../core/src/cli/cost.ts
|
|
22063
21696
|
function formatTokenFlow2(usage) {
|
|
22064
21697
|
return `↑${compactTokenCount(usage.inputTokens)} ↓${compactTokenCount(usage.outputTokens)} tok`;
|
|
22065
21698
|
}
|
|
22066
|
-
var
|
|
21699
|
+
var emptyUsage2 = { inputTokens: 0, outputTokens: 0, totalTokens: 0, cachedInputTokens: 0, cacheWriteTokens: 0, reasoningTokens: 0 };
|
|
22067
21700
|
var CACHE_CHURN_FLOOR_TOKENS2 = 20000;
|
|
22068
21701
|
var CACHE_CHURN_HINT2 = [
|
|
22069
21702
|
"The prompt cache is being rewritten more than it is read, which costs more than not caching at all.",
|
|
@@ -22151,7 +21784,7 @@ class CostLedger2 {
|
|
|
22151
21784
|
cachedInputTokens: total.cachedInputTokens + turn.usage.cachedInputTokens,
|
|
22152
21785
|
cacheWriteTokens: total.cacheWriteTokens + turn.usage.cacheWriteTokens,
|
|
22153
21786
|
reasoningTokens: total.reasoningTokens + turn.usage.reasoningTokens
|
|
22154
|
-
}), { ...
|
|
21787
|
+
}), { ...emptyUsage2 });
|
|
22155
21788
|
}
|
|
22156
21789
|
get history() {
|
|
22157
21790
|
return [...this.turns];
|
|
@@ -22311,7 +21944,7 @@ class CostLedger2 {
|
|
|
22311
21944
|
}
|
|
22312
21945
|
}
|
|
22313
21946
|
|
|
22314
|
-
//
|
|
21947
|
+
// src/headless.ts
|
|
22315
21948
|
var HEADLESS_PROTOCOL_VERSION = 1;
|
|
22316
21949
|
var EXIT_CODES = {
|
|
22317
21950
|
completed: 0,
|
|
@@ -22414,7 +22047,7 @@ class HeadlessEmitter {
|
|
|
22414
22047
|
return;
|
|
22415
22048
|
}
|
|
22416
22049
|
if (safe.type === "model_turn") {
|
|
22417
|
-
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 } : {} });
|
|
22418
22051
|
return;
|
|
22419
22052
|
}
|
|
22420
22053
|
if (safe.type === "provider_retry") {
|
|
@@ -22437,7 +22070,7 @@ class HeadlessEmitter {
|
|
|
22437
22070
|
}
|
|
22438
22071
|
}
|
|
22439
22072
|
|
|
22440
|
-
//
|
|
22073
|
+
// ../core/src/providers/price-catalog.ts
|
|
22441
22074
|
var ANTHROPIC_VERIFIED2 = "2026-06-24";
|
|
22442
22075
|
var ANTHROPIC_SOURCE2 = "anthropic.com/pricing, recorded 2026-06-24";
|
|
22443
22076
|
var ANTHROPIC2 = [
|
|
@@ -22489,7 +22122,7 @@ var SERVICES2 = [
|
|
|
22489
22122
|
];
|
|
22490
22123
|
var PRICE_CATALOG2 = definePrices([...ANTHROPIC2, ...OAI_COMPAT_LABS2, ...SERVICES2]);
|
|
22491
22124
|
|
|
22492
|
-
//
|
|
22125
|
+
// src/text/color-depth.ts
|
|
22493
22126
|
function detectColorDepth(environment, isTTY) {
|
|
22494
22127
|
if (!isTTY || environment.NO_COLOR !== undefined || environment.TERM === "dumb")
|
|
22495
22128
|
return "none";
|
|
@@ -22498,7 +22131,7 @@ function detectColorDepth(environment, isTTY) {
|
|
|
22498
22131
|
return "ansi256";
|
|
22499
22132
|
}
|
|
22500
22133
|
|
|
22501
|
-
//
|
|
22134
|
+
// src/terminal/keybindings.ts
|
|
22502
22135
|
var FUNCTION_KEY2 = /^f([1-9]|1[0-2])$/;
|
|
22503
22136
|
var NAMED_KEYS2 = new Set(["tab", "enter", "escape", "space", "up", "down", "left", "right", "home", "end", "pageup", "pagedown", "backspace", "delete"]);
|
|
22504
22137
|
function isKeyName2(value) {
|
|
@@ -22740,7 +22373,7 @@ function escapeCodeTimeoutMs2(environment = process.env) {
|
|
|
22740
22373
|
return Number.isInteger(parsed) && parsed >= 10 && parsed <= 2000 ? parsed : DEFAULT_ESCAPE_CODE_TIMEOUT_MS2;
|
|
22741
22374
|
}
|
|
22742
22375
|
|
|
22743
|
-
//
|
|
22376
|
+
// src/platform/local-currency.ts
|
|
22744
22377
|
var COUNTRY_CURRENCIES2 = {
|
|
22745
22378
|
RW: "RWF",
|
|
22746
22379
|
EG: "EGP",
|
|
@@ -22866,7 +22499,7 @@ function resolveCurrencyPreference(options) {
|
|
|
22866
22499
|
}
|
|
22867
22500
|
var FX_CACHE_MAX_AGE_MS2 = 24 * 60 * 60 * 1000;
|
|
22868
22501
|
|
|
22869
|
-
//
|
|
22502
|
+
// src/platform/settings.ts
|
|
22870
22503
|
import { promises as fs18 } from "node:fs";
|
|
22871
22504
|
import os5 from "node:os";
|
|
22872
22505
|
import path25 from "node:path";
|
|
@@ -22973,6 +22606,13 @@ var AUTOSAVE_CHOICES2 = [
|
|
|
22973
22606
|
{ value: "off", label: "Off — save with Ctrl+S (default)" },
|
|
22974
22607
|
{ value: "on", label: "On — save a second after you stop typing" }
|
|
22975
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
|
+
];
|
|
22976
22616
|
var PROVIDER_CHOICES2 = PROVIDER_IDS.map((id) => ({ value: id, label: PROVIDER_INFO[id].label }));
|
|
22977
22617
|
var SETTING_FIELDS2 = [
|
|
22978
22618
|
{ key: "ARCHYMEDES_THEME", label: "Theme — colours for the whole CLI (/theme <name> also saves it)", choices: THEME_CHOICES2, section: "Appearance" },
|
|
@@ -22980,6 +22620,7 @@ var SETTING_FIELDS2 = [
|
|
|
22980
22620
|
{ key: "ARCHYMEDES_CODE_LINE_NUMBERS", label: "Line numbers in code blocks", choices: SHOW_HIDE_CHOICES2 },
|
|
22981
22621
|
{ key: "ARCHYMEDES_SIMPLE", label: "Simple mode — quiet start, short help", choices: SIMPLE_CHOICES2 },
|
|
22982
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 },
|
|
22983
22624
|
{ key: "ARCHYMEDES_RESUME", label: "Continue your last chat at startup", choices: RESUME_CHOICES2, section: "Behaviour" },
|
|
22984
22625
|
{ key: "ARCHYMEDES_EDITOR_AUTOSAVE", label: "Auto-save in /edit", choices: AUTOSAVE_CHOICES2 },
|
|
22985
22626
|
{ key: "ARCHYMEDES_SUGGEST_MODEL", label: "Ask the model for extra suggestions (a small extra call per turn)", choices: ON_OFF_CHOICES2 },
|
|
@@ -23111,7 +22752,7 @@ function mergedEnvironment2(settings, environment = process.env) {
|
|
|
23111
22752
|
var PROVIDER_REQUIRED_NAMES2 = new Set(PROVIDER_IDS.flatMap((id) => PROVIDER_INFO[id].requires));
|
|
23112
22753
|
var PROVIDER_KEY_FIELDS2 = SETTING_FIELDS2.filter((field) => PROVIDER_REQUIRED_NAMES2.has(field.key));
|
|
23113
22754
|
|
|
23114
|
-
//
|
|
22755
|
+
// src/app/free-setup.ts
|
|
23115
22756
|
var OPENROUTER_KEYS_URL3 = "https://openrouter.ai/keys";
|
|
23116
22757
|
var FREE_SETUP_INTRO = [
|
|
23117
22758
|
"Free mode runs zero-priced models through OpenRouter and never falls back to a paid one.",
|
|
@@ -23177,7 +22818,7 @@ ${style3.bold("Free mode setup")}
|
|
|
23177
22818
|
return;
|
|
23178
22819
|
}
|
|
23179
22820
|
|
|
23180
|
-
//
|
|
22821
|
+
// src/session/tabs.ts
|
|
23181
22822
|
class WorkspaceController {
|
|
23182
22823
|
limit;
|
|
23183
22824
|
tabs = [];
|
|
@@ -23266,7 +22907,7 @@ class WorkspaceController {
|
|
|
23266
22907
|
}
|
|
23267
22908
|
}
|
|
23268
22909
|
|
|
23269
|
-
//
|
|
22910
|
+
// src/terminal/output.ts
|
|
23270
22911
|
var terminalStream2 = {
|
|
23271
22912
|
write(text) {
|
|
23272
22913
|
process.stdout.write(text);
|
|
@@ -23362,7 +23003,7 @@ class TabSink {
|
|
|
23362
23003
|
}
|
|
23363
23004
|
}
|
|
23364
23005
|
|
|
23365
|
-
//
|
|
23006
|
+
// src/terminal/job-stream.ts
|
|
23366
23007
|
var TERMINAL_STATUSES = new Set(["completed", "failed", "cancelled"]);
|
|
23367
23008
|
class WatchRegistry {
|
|
23368
23009
|
watched = new Map;
|
|
@@ -23397,7 +23038,7 @@ class WatchRegistry {
|
|
|
23397
23038
|
}
|
|
23398
23039
|
}
|
|
23399
23040
|
|
|
23400
|
-
//
|
|
23041
|
+
// src/theme/theme.ts
|
|
23401
23042
|
var BLUEPRINT2 = `
|
|
23402
23043
|
/* Blueprint navy, chalk-white ink and an amber pencil — the original drafting table. */
|
|
23403
23044
|
@theme blueprint {
|
|
@@ -23698,7 +23339,7 @@ function detectPreferredTheme(environment) {
|
|
|
23698
23339
|
return DEFAULT_THEME_NAME2;
|
|
23699
23340
|
}
|
|
23700
23341
|
|
|
23701
|
-
//
|
|
23342
|
+
// src/theme/theme-files.ts
|
|
23702
23343
|
import { promises as fs19 } from "node:fs";
|
|
23703
23344
|
import path26 from "node:path";
|
|
23704
23345
|
function themeDirectory(scope, root, environment) {
|
|
@@ -23736,7 +23377,7 @@ async function findTheme(name, root, environment) {
|
|
|
23736
23377
|
return (await discoverThemes(root, environment)).find((theme) => theme.name.toLowerCase() === wanted);
|
|
23737
23378
|
}
|
|
23738
23379
|
|
|
23739
|
-
//
|
|
23380
|
+
// src/render/syntax.ts
|
|
23740
23381
|
var DEFAULT_CODE_STYLE2 = { colors: "vscode", lineNumbers: true };
|
|
23741
23382
|
var currentCodeStyle2 = { ...DEFAULT_CODE_STYLE2 };
|
|
23742
23383
|
function codeStyleFromEnvironment(environment) {
|
|
@@ -23794,7 +23435,7 @@ var GRAMMARS2 = {
|
|
|
23794
23435
|
};
|
|
23795
23436
|
var PUNCTUATION2 = new Set([..."{}[]()<>;,.:=+-*/%!&|^~?\\"]);
|
|
23796
23437
|
|
|
23797
|
-
//
|
|
23438
|
+
// src/platform/i18n.ts
|
|
23798
23439
|
var CONTROL_LANGUAGES2 = {
|
|
23799
23440
|
en: "English",
|
|
23800
23441
|
zh: "中文 (Mandarin)",
|
|
@@ -23819,7 +23460,7 @@ function resolveControlLanguage2(value) {
|
|
|
23819
23460
|
return base in CONTROL_LANGUAGES2 ? base : "en";
|
|
23820
23461
|
}
|
|
23821
23462
|
|
|
23822
|
-
//
|
|
23463
|
+
// src/text/glyphs.ts
|
|
23823
23464
|
var UNICODE_GLYPHS2 = {
|
|
23824
23465
|
starGlyphs: [".", "·", "✧", "✦", "✶"],
|
|
23825
23466
|
spinnerFrames: [" ◜ ", " ◠ ", " ◝ ", " ◞ ", " ◡ ", " ◟ "],
|
|
@@ -23935,7 +23576,7 @@ function glyphsFor(mode) {
|
|
|
23935
23576
|
function resolveGlyphs(environment, platform = process.platform) {
|
|
23936
23577
|
return glyphsFor(detectGlyphMode(environment, platform));
|
|
23937
23578
|
}
|
|
23938
|
-
//
|
|
23579
|
+
// src/session/state-history.ts
|
|
23939
23580
|
class CliStateHistory {
|
|
23940
23581
|
root;
|
|
23941
23582
|
environment;
|
|
@@ -24046,7 +23687,7 @@ class CliStateHistory {
|
|
|
24046
23687
|
}
|
|
24047
23688
|
}
|
|
24048
23689
|
|
|
24049
|
-
//
|
|
23690
|
+
// src/ui/borrowed-keyboard.ts
|
|
24050
23691
|
function painter(output) {
|
|
24051
23692
|
let rows = 0;
|
|
24052
23693
|
const erase = () => {
|
|
@@ -24127,7 +23768,7 @@ async function openChooser(host, items, options, self) {
|
|
|
24127
23768
|
return withBorrowedKeyboard(host, self, (keys, paint2) => runChooser(keys, items, paint2, sized));
|
|
24128
23769
|
}
|
|
24129
23770
|
|
|
24130
|
-
//
|
|
23771
|
+
// src/app/prompts.ts
|
|
24131
23772
|
function renderApprovalPreview(preview2) {
|
|
24132
23773
|
if (!preview2)
|
|
24133
23774
|
return;
|
|
@@ -24265,7 +23906,7 @@ async function hiddenQuestion(readline, question, signal) {
|
|
|
24265
23906
|
}
|
|
24266
23907
|
}
|
|
24267
23908
|
|
|
24268
|
-
//
|
|
23909
|
+
// src/app/providers.ts
|
|
24269
23910
|
function readFxRates(environment) {
|
|
24270
23911
|
const genericRate = Number(environment.ARCHYMEDES_FX_RATE);
|
|
24271
23912
|
const genericFrom = environment.ARCHYMEDES_FX_FROM?.trim().toUpperCase();
|
|
@@ -24282,11 +23923,11 @@ function readFxRates(environment) {
|
|
|
24282
23923
|
}
|
|
24283
23924
|
return configured;
|
|
24284
23925
|
}
|
|
24285
|
-
//
|
|
23926
|
+
// ../core/src/cli/job-store.ts
|
|
24286
23927
|
import { promises as fs20 } from "node:fs";
|
|
24287
23928
|
import path27 from "node:path";
|
|
24288
23929
|
|
|
24289
|
-
//
|
|
23930
|
+
// ../core/src/cli/jobs.ts
|
|
24290
23931
|
var JOB_STATUSES = ["queued", "running", "paused", "completed", "failed", "cancelled"];
|
|
24291
23932
|
var DECISIONS = ["allow", "allow_always", "allow_pattern", "deny", "deny_always"];
|
|
24292
23933
|
function parseJobRecord(value, index) {
|
|
@@ -24461,7 +24102,7 @@ function recoverStale(store, now) {
|
|
|
24461
24102
|
return { store: { jobs }, recovered };
|
|
24462
24103
|
}
|
|
24463
24104
|
|
|
24464
|
-
//
|
|
24105
|
+
// ../core/src/cli/job-store.ts
|
|
24465
24106
|
function jobStoreFile(root) {
|
|
24466
24107
|
return path27.join(root, ".archymedes", "jobs.json");
|
|
24467
24108
|
}
|
|
@@ -24581,10 +24222,10 @@ async function appendJobLog(root, id, line) {
|
|
|
24581
24222
|
await fs20.appendFile(file, `${line}
|
|
24582
24223
|
`, "utf8");
|
|
24583
24224
|
}
|
|
24584
|
-
//
|
|
24225
|
+
// src/job-worker.ts
|
|
24585
24226
|
import os6 from "node:os";
|
|
24586
24227
|
|
|
24587
|
-
//
|
|
24228
|
+
// src/commands/wander.ts
|
|
24588
24229
|
async function gatherWanderEvidence(topic, search, numResults = 8) {
|
|
24589
24230
|
if (!search) {
|
|
24590
24231
|
return {
|
|
@@ -24680,7 +24321,7 @@ function renderWanderChart(results, style3, width) {
|
|
|
24680
24321
|
`);
|
|
24681
24322
|
}
|
|
24682
24323
|
|
|
24683
|
-
//
|
|
24324
|
+
// src/job-worker.ts
|
|
24684
24325
|
function workerId(hostname = os6.hostname(), pid = process.pid) {
|
|
24685
24326
|
return `${hostname}:${pid}`;
|
|
24686
24327
|
}
|
|
@@ -24858,7 +24499,7 @@ async function runJobWorkerForever(deps) {
|
|
|
24858
24499
|
}
|
|
24859
24500
|
}
|
|
24860
24501
|
|
|
24861
|
-
//
|
|
24502
|
+
// src/app/providers.ts
|
|
24862
24503
|
function renderProviders(environment, depth) {
|
|
24863
24504
|
const paint2 = (text, apply) => depth === "none" ? text : apply(text);
|
|
24864
24505
|
const statuses = describeProviders(environment);
|
|
@@ -24929,7 +24570,7 @@ function modelPriceCatalogFor(prices, exact) {
|
|
|
24929
24570
|
return { ...rates, ...prices.largeContext ? { largeContext: prices.largeContext } : {} };
|
|
24930
24571
|
}
|
|
24931
24572
|
|
|
24932
|
-
//
|
|
24573
|
+
// src/app/job-launch.ts
|
|
24933
24574
|
async function runJobWorkerProcess(root, jobId) {
|
|
24934
24575
|
const savedSettings = await loadSettings(process.env);
|
|
24935
24576
|
const environment = mergedEnvironment(savedSettings, process.env);
|
|
@@ -24966,10 +24607,10 @@ async function runJobWorkerProcess(root, jobId) {
|
|
|
24966
24607
|
}
|
|
24967
24608
|
}
|
|
24968
24609
|
|
|
24969
|
-
//
|
|
24610
|
+
// src/app/startup-commands.ts
|
|
24970
24611
|
import { createInterface as createInterface4 } from "node:readline/promises";
|
|
24971
24612
|
|
|
24972
|
-
//
|
|
24613
|
+
// src/headless.ts
|
|
24973
24614
|
var EXIT_CODES2 = {
|
|
24974
24615
|
completed: 0,
|
|
24975
24616
|
failed: 1,
|
|
@@ -24993,7 +24634,7 @@ function exitCodeForStatus2(status) {
|
|
|
24993
24634
|
return STATUS_EXIT2[status];
|
|
24994
24635
|
}
|
|
24995
24636
|
|
|
24996
|
-
//
|
|
24637
|
+
// src/platform/doctor.ts
|
|
24997
24638
|
var DEFAULT_PROBE_TIMEOUT_MS = 5000;
|
|
24998
24639
|
function modelEndpoints(environment) {
|
|
24999
24640
|
return providerEndpoints(environment).map((provider) => {
|
|
@@ -25123,7 +24764,7 @@ function doctorReport(probes, context) {
|
|
|
25123
24764
|
};
|
|
25124
24765
|
}
|
|
25125
24766
|
|
|
25126
|
-
//
|
|
24767
|
+
// src/text/color-depth.ts
|
|
25127
24768
|
function detectColorDepth2(environment, isTTY) {
|
|
25128
24769
|
if (!isTTY || environment.NO_COLOR !== undefined || environment.TERM === "dumb")
|
|
25129
24770
|
return "none";
|
|
@@ -25132,7 +24773,7 @@ function detectColorDepth2(environment, isTTY) {
|
|
|
25132
24773
|
return "ansi256";
|
|
25133
24774
|
}
|
|
25134
24775
|
|
|
25135
|
-
//
|
|
24776
|
+
// src/session/delete-session.ts
|
|
25136
24777
|
import { promises as fs21 } from "node:fs";
|
|
25137
24778
|
import path28 from "node:path";
|
|
25138
24779
|
var SAFE_ID = /^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/;
|
|
@@ -25152,7 +24793,7 @@ async function clearProjection(root, id) {
|
|
|
25152
24793
|
if (!exists)
|
|
25153
24794
|
return;
|
|
25154
24795
|
try {
|
|
25155
|
-
const { SessionProjection } = await import("./projection-
|
|
24796
|
+
const { SessionProjection } = await import("./projection-ndr3t77h.mjs");
|
|
25156
24797
|
const projection = await SessionProjection.open(root);
|
|
25157
24798
|
try {
|
|
25158
24799
|
await projection.rebuild(id);
|
|
@@ -25178,7 +24819,7 @@ async function deleteSession(root, id, options = {}) {
|
|
|
25178
24819
|
return { deleted: true };
|
|
25179
24820
|
}
|
|
25180
24821
|
|
|
25181
|
-
//
|
|
24822
|
+
// src/ui/navigation.ts
|
|
25182
24823
|
var ESSENTIAL_COMMANDS = ["/help", "/history", "/model", "/mode", "/diff", "/undo", "/settings", "/exit"];
|
|
25183
24824
|
function isEssential(command) {
|
|
25184
24825
|
return ESSENTIAL_COMMANDS.includes(command);
|
|
@@ -25245,7 +24886,7 @@ function renderAsks(suggestions, style3) {
|
|
|
25245
24886
|
`);
|
|
25246
24887
|
}
|
|
25247
24888
|
|
|
25248
|
-
//
|
|
24889
|
+
// src/app/help.ts
|
|
25249
24890
|
function helpText(language = "en", shortcuts = new Map) {
|
|
25250
24891
|
const star = glyphs.star;
|
|
25251
24892
|
const mark = (command) => isEssential(command) ? `${star} ` : " ";
|
|
@@ -25350,7 +24991,7 @@ ${renderCommandHelp(language, shortcuts, { mark })}
|
|
|
25350
24991
|
`;
|
|
25351
24992
|
}
|
|
25352
24993
|
|
|
25353
|
-
//
|
|
24994
|
+
// src/app/prompts.ts
|
|
25354
24995
|
function settingsChooser(readline) {
|
|
25355
24996
|
return (request) => openChooser({ readline, input: process.stdin, output: process.stdout }, request.items.map((item) => ({ ...item })), {
|
|
25356
24997
|
title: request.title,
|
|
@@ -25423,7 +25064,7 @@ async function hiddenQuestion2(readline, question, signal) {
|
|
|
25423
25064
|
}
|
|
25424
25065
|
}
|
|
25425
25066
|
|
|
25426
|
-
//
|
|
25067
|
+
// src/app/startup-commands.ts
|
|
25427
25068
|
function runInformationFlag(context) {
|
|
25428
25069
|
const { args, environment, language, earlyDepth } = context;
|
|
25429
25070
|
if (args.help) {
|
|
@@ -25627,7 +25268,7 @@ ${status.reason ?? "native state engine unavailable"}
|
|
|
25627
25268
|
return 0;
|
|
25628
25269
|
}
|
|
25629
25270
|
|
|
25630
|
-
//
|
|
25271
|
+
// src/app/display-currency.ts
|
|
25631
25272
|
async function settleDisplayCurrency(options) {
|
|
25632
25273
|
const { args, environment, prices, rates, state } = options;
|
|
25633
25274
|
if (prices && state.display !== prices.currency) {
|
|
@@ -25684,7 +25325,7 @@ async function settleDisplayCurrency(options) {
|
|
|
25684
25325
|
return;
|
|
25685
25326
|
}
|
|
25686
25327
|
|
|
25687
|
-
//
|
|
25328
|
+
// src/app/workspaces.ts
|
|
25688
25329
|
function createWorkspaceFactory(args, environment) {
|
|
25689
25330
|
return async (request) => {
|
|
25690
25331
|
const announce = (text) => {
|
|
@@ -25694,8 +25335,8 @@ function createWorkspaceFactory(args, environment) {
|
|
|
25694
25335
|
};
|
|
25695
25336
|
const minutes = Math.max(1, Math.min(args.sandboxMinutes, 60));
|
|
25696
25337
|
if (request.backend === "e2b") {
|
|
25697
|
-
const { findWorkspacePreset } = await import("./sandbox-templates-
|
|
25698
|
-
const { createE2BProvider } = await import("./factory-
|
|
25338
|
+
const { findWorkspacePreset } = await import("./sandbox-templates-9jcjws23.mjs");
|
|
25339
|
+
const { createE2BProvider } = await import("./factory-r6r0ypm6.mjs");
|
|
25699
25340
|
const preset = findWorkspacePreset(request.preset ?? args.preset);
|
|
25700
25341
|
const sandbox = createE2BProvider(environment, preset.templateAlias);
|
|
25701
25342
|
if (!sandbox)
|
|
@@ -25721,7 +25362,7 @@ function createWorkspaceFactory(args, environment) {
|
|
|
25721
25362
|
return { workspace: created };
|
|
25722
25363
|
}
|
|
25723
25364
|
if (request.backend === "docker") {
|
|
25724
|
-
const { createDockerProvider } = await import("./factory-
|
|
25365
|
+
const { createDockerProvider } = await import("./factory-r6r0ypm6.mjs");
|
|
25725
25366
|
const image = request.dockerImage || args.dockerImage || environment.DOCKER_CODING_IMAGE;
|
|
25726
25367
|
const sandbox = createDockerProvider({ ...environment, DOCKER_CODING_IMAGE: image });
|
|
25727
25368
|
if (!sandbox)
|
|
@@ -25750,11 +25391,11 @@ function createWorkspaceFactory(args, environment) {
|
|
|
25750
25391
|
};
|
|
25751
25392
|
}
|
|
25752
25393
|
|
|
25753
|
-
//
|
|
25394
|
+
// ../core/src/cli/balance.ts
|
|
25754
25395
|
var CRITICAL_BALANCE_USD2 = 0.5;
|
|
25755
25396
|
var LOW_BALANCE_USD2 = 2;
|
|
25756
25397
|
|
|
25757
|
-
//
|
|
25398
|
+
// src/commands/balance.ts
|
|
25758
25399
|
function formatBalance(amount, currency) {
|
|
25759
25400
|
return formatMoney(fromUnits(amount, currency));
|
|
25760
25401
|
}
|
|
@@ -25857,7 +25498,7 @@ class BalanceWatch {
|
|
|
25857
25498
|
}
|
|
25858
25499
|
}
|
|
25859
25500
|
|
|
25860
|
-
//
|
|
25501
|
+
// src/session/resumed-spend.ts
|
|
25861
25502
|
async function readSessionModelTurns(root, sessionId) {
|
|
25862
25503
|
const events = await readEventJournal(root, sessionId);
|
|
25863
25504
|
const turns = [];
|
|
@@ -25889,7 +25530,7 @@ function priceSessionModelTurns(turns, options) {
|
|
|
25889
25530
|
return { spent: total, unpriced: [...unpriced].sort() };
|
|
25890
25531
|
}
|
|
25891
25532
|
|
|
25892
|
-
//
|
|
25533
|
+
// src/app/balance-tracking.ts
|
|
25893
25534
|
function createBalanceTracking(options) {
|
|
25894
25535
|
const { environment, processEnvironment, rates, state } = options;
|
|
25895
25536
|
const usdInDisplay = (usd) => {
|
|
@@ -25978,7 +25619,7 @@ function createBalanceTracking(options) {
|
|
|
25978
25619
|
return { lowBalance, criticalBalance, balanceWatch, parseManualBalance, currentBalance, persistManualBalance, sessionSpend, balanceHeader, checkBalance, carryResumedSpend };
|
|
25979
25620
|
}
|
|
25980
25621
|
|
|
25981
|
-
//
|
|
25622
|
+
// src/app/agent-factory.ts
|
|
25982
25623
|
function createClientFactory(options) {
|
|
25983
25624
|
const { args, environment, daemon, approvalPrompt, rates, approvedBudget, state } = options;
|
|
25984
25625
|
return async (record2, runtime = {}) => {
|
|
@@ -25999,6 +25640,7 @@ function createClientFactory(options) {
|
|
|
25999
25640
|
onExpense: (expense) => state.ledger.recordExpense(expense),
|
|
26000
25641
|
onEvent,
|
|
26001
25642
|
jev: jevOptionsFromEnvironment(environment),
|
|
25643
|
+
...reasoningFromEnvironment(environment) ? { reasoning: reasoningFromEnvironment(environment) } : {},
|
|
26002
25644
|
afterEdit: editDiagnostics
|
|
26003
25645
|
}), record2);
|
|
26004
25646
|
if (editDiagnostics)
|
|
@@ -26018,14 +25660,14 @@ function closeWithClient(client, hook) {
|
|
|
26018
25660
|
client.dispose = () => dispose().finally(close);
|
|
26019
25661
|
}
|
|
26020
25662
|
|
|
26021
|
-
//
|
|
25663
|
+
// src/app/live-models.ts
|
|
26022
25664
|
async function readCachedLiveModels(environment, state) {
|
|
26023
25665
|
const cached = await readModelCache(environment);
|
|
26024
25666
|
if (isCacheFresh(cached))
|
|
26025
25667
|
state.liveModels = cached.models;
|
|
26026
25668
|
}
|
|
26027
25669
|
|
|
26028
|
-
//
|
|
25670
|
+
// src/app/session-hints.ts
|
|
26029
25671
|
function createSessionHints(options) {
|
|
26030
25672
|
const { state, watched, tabs, usage } = options;
|
|
26031
25673
|
const navContext = () => ({
|
|
@@ -26054,7 +25696,7 @@ function createSessionHints(options) {
|
|
|
26054
25696
|
return { navContext, writeHint };
|
|
26055
25697
|
}
|
|
26056
25698
|
|
|
26057
|
-
//
|
|
25699
|
+
// src/render/completion-card.ts
|
|
26058
25700
|
var CHECK_LABELS = {
|
|
26059
25701
|
tests: "tests",
|
|
26060
25702
|
typecheck: "typecheck",
|
|
@@ -26084,7 +25726,7 @@ function renderCompletionCard(input, style3) {
|
|
|
26084
25726
|
return panel(lines, style3, { title, tone: failed2 ? "bad" : verified ? "good" : "warn" });
|
|
26085
25727
|
}
|
|
26086
25728
|
|
|
26087
|
-
//
|
|
25729
|
+
// src/render/routing-receipt.ts
|
|
26088
25730
|
function formatMicros(micros, currency = "USD") {
|
|
26089
25731
|
if (micros === undefined || !Number.isFinite(micros))
|
|
26090
25732
|
return "—";
|
|
@@ -26176,10 +25818,10 @@ ${rule(cell, { label: badge })}` : out3.join(`
|
|
|
26176
25818
|
`);
|
|
26177
25819
|
}
|
|
26178
25820
|
|
|
26179
|
-
//
|
|
25821
|
+
// src/app/session-hints.ts
|
|
26180
25822
|
var failureStatus = (status) => status === "needs_approval" ? "waiting_approval" : status;
|
|
26181
25823
|
|
|
26182
|
-
//
|
|
25824
|
+
// src/app/turn-failure.ts
|
|
26183
25825
|
async function handleTurnFailure(error, request, context) {
|
|
26184
25826
|
const { args, environment, interactive, headless, recoveryState, state, navContext } = context;
|
|
26185
25827
|
if (recoveryState.last?.request === request) {
|
|
@@ -26234,7 +25876,7 @@ ${style.yellow(`Stopped at the ${formatMoney(fromUnits(args.budget, state.displa
|
|
|
26234
25876
|
return false;
|
|
26235
25877
|
}
|
|
26236
25878
|
|
|
26237
|
-
//
|
|
25879
|
+
// src/app/turn-preflight.ts
|
|
26238
25880
|
async function runTurnPreflight(request, context) {
|
|
26239
25881
|
const { args, readline, interactive, approvedBudget, rates, state } = context;
|
|
26240
25882
|
const { currentBalance, balanceWatch, sessionSpend } = context.balance;
|
|
@@ -26332,7 +25974,7 @@ async function runTurnPreflight(request, context) {
|
|
|
26332
25974
|
return true;
|
|
26333
25975
|
}
|
|
26334
25976
|
|
|
26335
|
-
//
|
|
25977
|
+
// src/app/turn-runner.ts
|
|
26336
25978
|
var addModelUsage2 = (left, right) => ({
|
|
26337
25979
|
inputTokens: left.inputTokens + right.inputTokens,
|
|
26338
25980
|
outputTokens: left.outputTokens + right.outputTokens,
|
|
@@ -26540,7 +26182,7 @@ ${result.status === "completed" ? asMarkdown(result.summary) : style.yellow(resu
|
|
|
26540
26182
|
};
|
|
26541
26183
|
}
|
|
26542
26184
|
|
|
26543
|
-
//
|
|
26185
|
+
// src/app/interrupts.ts
|
|
26544
26186
|
function createSigintHandling(options) {
|
|
26545
26187
|
const { readline, state } = options;
|
|
26546
26188
|
const handleSigint = () => {
|
|
@@ -26581,7 +26223,7 @@ function createSigintHandling(options) {
|
|
|
26581
26223
|
return { bindSigint, unbindSigint };
|
|
26582
26224
|
}
|
|
26583
26225
|
|
|
26584
|
-
//
|
|
26226
|
+
// src/app/session-start.ts
|
|
26585
26227
|
import path29 from "node:path";
|
|
26586
26228
|
async function resumeAtStartup(context) {
|
|
26587
26229
|
const { args, interactive, stateHistory, state, openClient } = context;
|
|
@@ -26654,7 +26296,7 @@ async function runOneShot(context) {
|
|
|
26654
26296
|
return args.json ? exitCodeForStatus2(state.lastTurnStatus) : ran ? 0 : 1;
|
|
26655
26297
|
}
|
|
26656
26298
|
|
|
26657
|
-
//
|
|
26299
|
+
// src/archymedes.ts
|
|
26658
26300
|
async function main() {
|
|
26659
26301
|
process.stdout.on("error", (error) => {
|
|
26660
26302
|
if (error.code === "EPIPE")
|