replicas-engine 0.1.206 → 0.1.208
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/index.js +208 -32
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -396,7 +396,7 @@ function parseReplicasConfigString(content, filename) {
|
|
|
396
396
|
}
|
|
397
397
|
|
|
398
398
|
// ../shared/src/engine/environment.ts
|
|
399
|
-
var DAYTONA_SNAPSHOT_ID = "23-05-2026-royal-york-
|
|
399
|
+
var DAYTONA_SNAPSHOT_ID = "23-05-2026-royal-york-v6";
|
|
400
400
|
|
|
401
401
|
// ../shared/src/engine/types.ts
|
|
402
402
|
var DEFAULT_CHAT_TITLES = {
|
|
@@ -436,6 +436,46 @@ var IMAGE_MEDIA_TYPES = ["image/png", "image/jpeg", "image/gif", "image/webp"];
|
|
|
436
436
|
// ../shared/src/engine/v1.ts
|
|
437
437
|
var MERGED_MESSAGE_SEPARATOR = "\n\n<!-- replicas:merged -->\n\n";
|
|
438
438
|
|
|
439
|
+
// ../shared/src/routes/codex.ts
|
|
440
|
+
var CODEX_AUTH_ENV_KEYS = [
|
|
441
|
+
"OPENAI_API_KEY",
|
|
442
|
+
"REPLICAS_CODEX_AUTH_METHOD"
|
|
443
|
+
];
|
|
444
|
+
function codexAuthEnvFromResponse(response) {
|
|
445
|
+
switch (response.type) {
|
|
446
|
+
case "oauth":
|
|
447
|
+
return { REPLICAS_CODEX_AUTH_METHOD: "oauth" };
|
|
448
|
+
case "api_key":
|
|
449
|
+
return { OPENAI_API_KEY: response.apiKey, REPLICAS_CODEX_AUTH_METHOD: "api_key" };
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
// ../shared/src/routes/claude.ts
|
|
454
|
+
var CLAUDE_AUTH_ENV_KEYS = [
|
|
455
|
+
"ANTHROPIC_API_KEY",
|
|
456
|
+
"CLAUDE_CODE_USE_BEDROCK",
|
|
457
|
+
"AWS_ACCESS_KEY_ID",
|
|
458
|
+
"AWS_SECRET_ACCESS_KEY",
|
|
459
|
+
"AWS_REGION",
|
|
460
|
+
"REPLICAS_CLAUDE_AUTH_METHOD"
|
|
461
|
+
];
|
|
462
|
+
function claudeAuthEnvFromResponse(response) {
|
|
463
|
+
switch (response.type) {
|
|
464
|
+
case "oauth":
|
|
465
|
+
return { REPLICAS_CLAUDE_AUTH_METHOD: "oauth" };
|
|
466
|
+
case "api_key":
|
|
467
|
+
return { ANTHROPIC_API_KEY: response.apiKey, REPLICAS_CLAUDE_AUTH_METHOD: "api_key" };
|
|
468
|
+
case "bedrock":
|
|
469
|
+
return {
|
|
470
|
+
CLAUDE_CODE_USE_BEDROCK: "1",
|
|
471
|
+
AWS_ACCESS_KEY_ID: response.awsAccessKeyId,
|
|
472
|
+
AWS_SECRET_ACCESS_KEY: response.awsSecretAccessKey,
|
|
473
|
+
AWS_REGION: response.awsRegion,
|
|
474
|
+
REPLICAS_CLAUDE_AUTH_METHOD: "bedrock"
|
|
475
|
+
};
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
439
479
|
// ../shared/src/routes/workspaces.ts
|
|
440
480
|
var WORKSPACE_FILE_UPLOAD_MAX_SIZE_BYTES = 20 * 1024 * 1024;
|
|
441
481
|
var WORKSPACE_FILE_CONTENT_MAX_SIZE_BYTES = 1 * 1024 * 1024;
|
|
@@ -707,12 +747,16 @@ var ClaudeTokenManager = class extends BaseRefreshManager {
|
|
|
707
747
|
super("ClaudeTokenManager");
|
|
708
748
|
}
|
|
709
749
|
getSkipReason() {
|
|
710
|
-
|
|
711
|
-
|
|
750
|
+
const method = ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD;
|
|
751
|
+
if (method === "api_key" || method === "bedrock") {
|
|
752
|
+
return `auth method is ${method}`;
|
|
712
753
|
}
|
|
713
754
|
return null;
|
|
714
755
|
}
|
|
715
756
|
async doRefresh(config) {
|
|
757
|
+
await this.refreshWithRequest(config);
|
|
758
|
+
}
|
|
759
|
+
async refreshWithRequest(config, request) {
|
|
716
760
|
console.log("[ClaudeTokenManager] Refreshing Claude credentials...");
|
|
717
761
|
const response = await fetch(`${config.monolithUrl}/v1/engine/claude/refresh-credentials`, {
|
|
718
762
|
method: "POST",
|
|
@@ -720,39 +764,81 @@ var ClaudeTokenManager = class extends BaseRefreshManager {
|
|
|
720
764
|
Authorization: `Bearer ${config.engineSecret}`,
|
|
721
765
|
"X-Workspace-Id": config.workspaceId,
|
|
722
766
|
"Content-Type": "application/json"
|
|
723
|
-
}
|
|
767
|
+
},
|
|
768
|
+
...request ? { body: JSON.stringify(request) } : {}
|
|
724
769
|
});
|
|
725
770
|
if (!response.ok) {
|
|
726
771
|
const errorText = await response.text();
|
|
727
772
|
throw new Error(`Credentials refresh failed: ${response.status} ${errorText}`);
|
|
728
773
|
}
|
|
729
774
|
const data = await response.json();
|
|
730
|
-
await this.
|
|
731
|
-
console.log(`[ClaudeTokenManager] Credentials refreshed
|
|
775
|
+
await this.applyCredentialsResponse(data);
|
|
776
|
+
console.log(`[ClaudeTokenManager] Credentials refreshed (method=${data.type})`);
|
|
732
777
|
}
|
|
733
|
-
|
|
734
|
-
* Re-fetches credentials from the monolith after an auth failure is detected.
|
|
735
|
-
* With the 1-hour refresh threshold, the monolith will have already
|
|
736
|
-
* proactively refreshed the token, so this just pulls the latest.
|
|
737
|
-
*
|
|
738
|
-
* Returns true if credentials were successfully updated, false otherwise.
|
|
739
|
-
*/
|
|
740
|
-
async fetchFreshCredentials() {
|
|
741
|
-
if (this.getSkipReason()) {
|
|
742
|
-
return false;
|
|
743
|
-
}
|
|
778
|
+
async fetchFreshCredentials(failureReason) {
|
|
744
779
|
const config = this.getRuntimeConfig();
|
|
745
780
|
if (!config) return false;
|
|
746
781
|
try {
|
|
747
782
|
console.log("[ClaudeTokenManager] Fetching fresh credentials from monolith after auth failure...");
|
|
748
|
-
|
|
783
|
+
const failedMethod = ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD;
|
|
784
|
+
await this.refreshWithRequest(config, failedMethod && failedMethod !== "none" ? {
|
|
785
|
+
failedMethod,
|
|
786
|
+
failureReason
|
|
787
|
+
} : void 0);
|
|
788
|
+
if (ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD === "oauth") {
|
|
789
|
+
this.start().catch((error) => {
|
|
790
|
+
console.error("[ClaudeTokenManager] Failed to restart OAuth refresh service after fallback:", error);
|
|
791
|
+
});
|
|
792
|
+
}
|
|
749
793
|
return true;
|
|
750
794
|
} catch (error) {
|
|
751
795
|
console.error("[ClaudeTokenManager] Failed to fetch fresh credentials:", error);
|
|
752
796
|
return false;
|
|
753
797
|
}
|
|
754
798
|
}
|
|
755
|
-
async
|
|
799
|
+
async applyCredentialsResponse(response) {
|
|
800
|
+
if (response.type === "oauth") {
|
|
801
|
+
await this.writeOauthCredentialsFile({
|
|
802
|
+
accessToken: response.accessToken,
|
|
803
|
+
refreshToken: response.refreshToken,
|
|
804
|
+
expiresAt: response.expiresAt,
|
|
805
|
+
scopes: response.scopes,
|
|
806
|
+
subscriptionType: response.subscriptionType
|
|
807
|
+
});
|
|
808
|
+
} else {
|
|
809
|
+
await this.removeOauthCredentialsFile();
|
|
810
|
+
}
|
|
811
|
+
const envVars = claudeAuthEnvFromResponse(response);
|
|
812
|
+
for (const key of CLAUDE_AUTH_ENV_KEYS) {
|
|
813
|
+
switch (key) {
|
|
814
|
+
case "REPLICAS_CLAUDE_AUTH_METHOD":
|
|
815
|
+
ENGINE_ENV.REPLICAS_CLAUDE_AUTH_METHOD = envVars.REPLICAS_CLAUDE_AUTH_METHOD;
|
|
816
|
+
break;
|
|
817
|
+
case "ANTHROPIC_API_KEY":
|
|
818
|
+
ENGINE_ENV.ANTHROPIC_API_KEY = envVars.ANTHROPIC_API_KEY;
|
|
819
|
+
break;
|
|
820
|
+
case "CLAUDE_CODE_USE_BEDROCK":
|
|
821
|
+
ENGINE_ENV.CLAUDE_CODE_USE_BEDROCK = envVars.CLAUDE_CODE_USE_BEDROCK;
|
|
822
|
+
break;
|
|
823
|
+
case "AWS_ACCESS_KEY_ID":
|
|
824
|
+
ENGINE_ENV.AWS_ACCESS_KEY_ID = envVars.AWS_ACCESS_KEY_ID;
|
|
825
|
+
break;
|
|
826
|
+
case "AWS_SECRET_ACCESS_KEY":
|
|
827
|
+
ENGINE_ENV.AWS_SECRET_ACCESS_KEY = envVars.AWS_SECRET_ACCESS_KEY;
|
|
828
|
+
break;
|
|
829
|
+
case "AWS_REGION":
|
|
830
|
+
ENGINE_ENV.AWS_REGION = envVars.AWS_REGION;
|
|
831
|
+
break;
|
|
832
|
+
}
|
|
833
|
+
const value = envVars[key];
|
|
834
|
+
if (value !== void 0) {
|
|
835
|
+
process.env[key] = value;
|
|
836
|
+
} else {
|
|
837
|
+
delete process.env[key];
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
async writeOauthCredentialsFile(credentials) {
|
|
756
842
|
const workspaceHome = ENGINE_ENV.HOME_DIR;
|
|
757
843
|
const claudeDir = path2.join(workspaceHome, ".claude");
|
|
758
844
|
const credentialsPath = path2.join(claudeDir, ".credentials.json");
|
|
@@ -773,6 +859,13 @@ var ClaudeTokenManager = class extends BaseRefreshManager {
|
|
|
773
859
|
console.error("[ClaudeTokenManager] Failed to update credentials file:", error);
|
|
774
860
|
}
|
|
775
861
|
}
|
|
862
|
+
async removeOauthCredentialsFile() {
|
|
863
|
+
const credentialsPath = path2.join(ENGINE_ENV.HOME_DIR, ".claude", ".credentials.json");
|
|
864
|
+
try {
|
|
865
|
+
await fs2.unlink(credentialsPath);
|
|
866
|
+
} catch {
|
|
867
|
+
}
|
|
868
|
+
}
|
|
776
869
|
};
|
|
777
870
|
var claudeTokenManager = new ClaudeTokenManager();
|
|
778
871
|
|
|
@@ -784,12 +877,18 @@ var CodexTokenManager = class extends BaseRefreshManager {
|
|
|
784
877
|
super("CodexTokenManager");
|
|
785
878
|
}
|
|
786
879
|
getSkipReason() {
|
|
787
|
-
if (ENGINE_ENV.
|
|
880
|
+
if (ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "api_key") {
|
|
881
|
+
return "auth method is api_key";
|
|
882
|
+
}
|
|
883
|
+
if (!ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD && ENGINE_ENV.OPENAI_API_KEY) {
|
|
788
884
|
return "OPENAI_API_KEY is set";
|
|
789
885
|
}
|
|
790
886
|
return null;
|
|
791
887
|
}
|
|
792
888
|
async doRefresh(config) {
|
|
889
|
+
await this.refreshWithRequest(config);
|
|
890
|
+
}
|
|
891
|
+
async refreshWithRequest(config, request) {
|
|
793
892
|
console.log("[CodexTokenManager] Refreshing Codex credentials...");
|
|
794
893
|
const response = await fetch(`${config.monolithUrl}/v1/engine/codex/refresh-credentials`, {
|
|
795
894
|
method: "POST",
|
|
@@ -797,17 +896,63 @@ var CodexTokenManager = class extends BaseRefreshManager {
|
|
|
797
896
|
Authorization: `Bearer ${config.engineSecret}`,
|
|
798
897
|
"X-Workspace-Id": config.workspaceId,
|
|
799
898
|
"Content-Type": "application/json"
|
|
800
|
-
}
|
|
899
|
+
},
|
|
900
|
+
...request ? { body: JSON.stringify(request) } : {}
|
|
801
901
|
});
|
|
802
902
|
if (!response.ok) {
|
|
803
903
|
const errorText = await response.text();
|
|
804
904
|
throw new Error(`Credentials refresh failed: ${response.status} ${errorText}`);
|
|
805
905
|
}
|
|
806
906
|
const data = await response.json();
|
|
807
|
-
await this.
|
|
808
|
-
console.log(`[CodexTokenManager] Credentials refreshed
|
|
907
|
+
await this.applyCredentialsResponse(data);
|
|
908
|
+
console.log(`[CodexTokenManager] Credentials refreshed (method=${data.type})`);
|
|
809
909
|
}
|
|
810
|
-
async
|
|
910
|
+
async fetchFreshCredentials(failureReason) {
|
|
911
|
+
const config = this.getRuntimeConfig();
|
|
912
|
+
if (!config) return false;
|
|
913
|
+
try {
|
|
914
|
+
console.log("[CodexTokenManager] Fetching fresh credentials from monolith after auth failure...");
|
|
915
|
+
const failedMethod = ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD;
|
|
916
|
+
await this.refreshWithRequest(config, failedMethod === "oauth" || failedMethod === "api_key" ? {
|
|
917
|
+
failedMethod,
|
|
918
|
+
failureReason
|
|
919
|
+
} : void 0);
|
|
920
|
+
if (ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD === "oauth") {
|
|
921
|
+
this.start().catch((error) => {
|
|
922
|
+
console.error("[CodexTokenManager] Failed to restart OAuth refresh service after fallback:", error);
|
|
923
|
+
});
|
|
924
|
+
}
|
|
925
|
+
return true;
|
|
926
|
+
} catch (error) {
|
|
927
|
+
console.error("[CodexTokenManager] Failed to fetch fresh credentials:", error);
|
|
928
|
+
return false;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
async applyCredentialsResponse(response) {
|
|
932
|
+
if (response.type === "oauth") {
|
|
933
|
+
await this.writeOauthCredentialsFile(response);
|
|
934
|
+
} else {
|
|
935
|
+
await this.removeOauthCredentialsFile();
|
|
936
|
+
}
|
|
937
|
+
const envVars = codexAuthEnvFromResponse(response);
|
|
938
|
+
for (const key of CODEX_AUTH_ENV_KEYS) {
|
|
939
|
+
switch (key) {
|
|
940
|
+
case "REPLICAS_CODEX_AUTH_METHOD":
|
|
941
|
+
ENGINE_ENV.REPLICAS_CODEX_AUTH_METHOD = envVars.REPLICAS_CODEX_AUTH_METHOD;
|
|
942
|
+
break;
|
|
943
|
+
case "OPENAI_API_KEY":
|
|
944
|
+
ENGINE_ENV.OPENAI_API_KEY = envVars.OPENAI_API_KEY;
|
|
945
|
+
break;
|
|
946
|
+
}
|
|
947
|
+
const value = envVars[key];
|
|
948
|
+
if (value !== void 0) {
|
|
949
|
+
process.env[key] = value;
|
|
950
|
+
} else {
|
|
951
|
+
delete process.env[key];
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
async writeOauthCredentialsFile(credentials) {
|
|
811
956
|
const workspaceHome = ENGINE_ENV.HOME_DIR;
|
|
812
957
|
const codexDir = path3.join(workspaceHome, ".codex");
|
|
813
958
|
const authPath = path3.join(codexDir, "auth.json");
|
|
@@ -829,6 +974,13 @@ var CodexTokenManager = class extends BaseRefreshManager {
|
|
|
829
974
|
console.error("[CodexTokenManager] Failed to update credentials file:", error);
|
|
830
975
|
}
|
|
831
976
|
}
|
|
977
|
+
async removeOauthCredentialsFile() {
|
|
978
|
+
const authPath = path3.join(ENGINE_ENV.HOME_DIR, ".codex", "auth.json");
|
|
979
|
+
try {
|
|
980
|
+
await fs3.unlink(authPath);
|
|
981
|
+
} catch {
|
|
982
|
+
}
|
|
983
|
+
}
|
|
832
984
|
};
|
|
833
985
|
var codexTokenManager = new CodexTokenManager();
|
|
834
986
|
|
|
@@ -3244,7 +3396,7 @@ var ClaudeManager = class _ClaudeManager extends CodingAgentManager {
|
|
|
3244
3396
|
} catch (error) {
|
|
3245
3397
|
if (_ClaudeManager.isAuthError(error)) {
|
|
3246
3398
|
console.warn("[ClaudeManager] Auth failure detected, refreshing credentials and retrying...", error);
|
|
3247
|
-
const refreshed = await claudeTokenManager.fetchFreshCredentials();
|
|
3399
|
+
const refreshed = await claudeTokenManager.fetchFreshCredentials(error instanceof Error ? error.message : String(error));
|
|
3248
3400
|
if (refreshed) {
|
|
3249
3401
|
await this.executeQuery(request);
|
|
3250
3402
|
return;
|
|
@@ -3555,7 +3707,7 @@ function extractRateLimitsSnapshot(parsed) {
|
|
|
3555
3707
|
}
|
|
3556
3708
|
return { state, balance, rateLimitResetType, planType };
|
|
3557
3709
|
}
|
|
3558
|
-
var CodexManager = class extends CodingAgentManager {
|
|
3710
|
+
var CodexManager = class _CodexManager extends CodingAgentManager {
|
|
3559
3711
|
codex;
|
|
3560
3712
|
currentThreadId = null;
|
|
3561
3713
|
currentThread = null;
|
|
@@ -3571,13 +3723,20 @@ var CodexManager = class extends CodingAgentManager {
|
|
|
3571
3723
|
quotaBlocked = false;
|
|
3572
3724
|
constructor(options) {
|
|
3573
3725
|
super(options);
|
|
3726
|
+
this.codex = this.createCodexClient();
|
|
3727
|
+
this.tempImageDir = join13(homedir11(), ".replicas", "codex", "temp-images");
|
|
3728
|
+
this.initializeManager(this.processMessageInternal.bind(this));
|
|
3729
|
+
}
|
|
3730
|
+
createCodexClient() {
|
|
3574
3731
|
const codexApiKey = resolveCodexApiKey();
|
|
3575
|
-
|
|
3732
|
+
return new Codex({
|
|
3576
3733
|
env: buildCodexAgentEnv(),
|
|
3577
3734
|
...codexApiKey ? { apiKey: codexApiKey } : {}
|
|
3578
3735
|
});
|
|
3579
|
-
|
|
3580
|
-
|
|
3736
|
+
}
|
|
3737
|
+
resetCodexClient() {
|
|
3738
|
+
this.codex = this.createCodexClient();
|
|
3739
|
+
this.currentThread = null;
|
|
3581
3740
|
}
|
|
3582
3741
|
async initialize() {
|
|
3583
3742
|
if (this.initialSessionId) {
|
|
@@ -3706,10 +3865,22 @@ var CodexManager = class extends CodingAgentManager {
|
|
|
3706
3865
|
}
|
|
3707
3866
|
return tempPaths;
|
|
3708
3867
|
}
|
|
3709
|
-
/**
|
|
3710
|
-
* Internal method that actually processes the message
|
|
3711
|
-
*/
|
|
3712
3868
|
async processMessageInternal(request) {
|
|
3869
|
+
try {
|
|
3870
|
+
await this.executeCodexTurn(request);
|
|
3871
|
+
} catch (error) {
|
|
3872
|
+
if (_CodexManager.isAuthError(error)) {
|
|
3873
|
+
const refreshed = await codexTokenManager.fetchFreshCredentials(error instanceof Error ? error.message : String(error));
|
|
3874
|
+
if (refreshed) {
|
|
3875
|
+
this.resetCodexClient();
|
|
3876
|
+
await this.executeCodexTurn(request);
|
|
3877
|
+
return;
|
|
3878
|
+
}
|
|
3879
|
+
}
|
|
3880
|
+
throw error;
|
|
3881
|
+
}
|
|
3882
|
+
}
|
|
3883
|
+
async executeCodexTurn(request) {
|
|
3713
3884
|
if (this.quotaBlocked && this.latestQuotaSnapshot) {
|
|
3714
3885
|
await this.flushQuotaSnapshotFromCurrentSession();
|
|
3715
3886
|
if (this.quotaBlocked && this.latestQuotaSnapshot) {
|
|
@@ -3839,6 +4010,11 @@ var CodexManager = class extends CodingAgentManager {
|
|
|
3839
4010
|
this.activeAbortController = null;
|
|
3840
4011
|
}
|
|
3841
4012
|
}
|
|
4013
|
+
static isAuthError(error) {
|
|
4014
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
4015
|
+
const lower = msg.toLowerCase();
|
|
4016
|
+
return lower.includes("unauthorized") || lower.includes("authentication") || lower.includes("invalid api key") || lower.includes("incorrect api key") || lower.includes("api key") && lower.includes("invalid") || lower.includes("login") || lower.includes("401");
|
|
4017
|
+
}
|
|
3842
4018
|
async getHistory() {
|
|
3843
4019
|
if (!this.currentThreadId) {
|
|
3844
4020
|
return {
|