replicas-engine 0.1.519 → 0.1.522
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 +272 -166
- package/package.json +1 -1
package/dist/src/index.js
CHANGED
|
@@ -195,20 +195,22 @@ function detectLanguageByPath(filePath) {
|
|
|
195
195
|
return EXT_TO_LANGUAGE[ext] ?? null;
|
|
196
196
|
}
|
|
197
197
|
|
|
198
|
-
// ../shared/src/
|
|
199
|
-
|
|
200
|
-
var
|
|
201
|
-
var
|
|
202
|
-
"
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
198
|
+
// ../shared/src/aster.ts
|
|
199
|
+
var ASTER_PROVIDER = "aster";
|
|
200
|
+
var ASTER_BASE_URL = "https://api.asterlab.ai/v1";
|
|
201
|
+
var ASTER_MODELS = [
|
|
202
|
+
"kimi-k3",
|
|
203
|
+
"glm-5.2",
|
|
204
|
+
"gpt-oss-120b-fast",
|
|
205
|
+
"gpt-oss-120b"
|
|
206
|
+
];
|
|
207
|
+
var DEFAULT_ASTER_MODEL = ASTER_MODELS[0];
|
|
208
|
+
var ASTER_MODEL_LABELS = {
|
|
209
|
+
"kimi-k3": "Kimi K3",
|
|
210
|
+
"glm-5.2": "GLM 5.2",
|
|
211
|
+
"gpt-oss-120b-fast": "GPT-OSS 120B Fast",
|
|
212
|
+
"gpt-oss-120b": "GPT-OSS 120B"
|
|
213
|
+
};
|
|
212
214
|
|
|
213
215
|
// ../shared/src/engine/types.ts
|
|
214
216
|
var DEFAULT_CHAT_TITLES = {
|
|
@@ -320,8 +322,8 @@ var AGENT_MODELS = {
|
|
|
320
322
|
CLAUDE_HAIKU_4_5_MODEL,
|
|
321
323
|
"kimi-k2.5"
|
|
322
324
|
],
|
|
323
|
-
opencode: OPENROUTER_MODELS,
|
|
324
|
-
pi: OPENROUTER_MODELS,
|
|
325
|
+
opencode: [...OPENROUTER_MODELS, ...ASTER_MODELS],
|
|
326
|
+
pi: [...OPENROUTER_MODELS, ...ASTER_MODELS],
|
|
325
327
|
relay: [CLAUDE_FABLE_5_MODEL, DEFAULT_CLAUDE_MODEL, CLAUDE_SONNET_5_MODEL]
|
|
326
328
|
};
|
|
327
329
|
var MODEL_LABELS = {
|
|
@@ -342,6 +344,7 @@ var MODEL_LABELS = {
|
|
|
342
344
|
"minimax/minimax-m3": "MiniMax M3 via OpenRouter",
|
|
343
345
|
"xiaomi/mimo-v2.5-pro": "MiMo V2.5 Pro via OpenRouter",
|
|
344
346
|
"moonshotai/kimi-k2.6": "Kimi K2.6 via OpenRouter",
|
|
347
|
+
...ASTER_MODEL_LABELS,
|
|
345
348
|
"gpt-5.4": "GPT-5.4",
|
|
346
349
|
"gpt-5.4-mini": "GPT-5.4 Mini",
|
|
347
350
|
"gpt-5.4-nano": "GPT-5.4 Nano",
|
|
@@ -609,7 +612,7 @@ var WORKSPACE_SIZES = ["small", "large"];
|
|
|
609
612
|
var INVALID_WORKSPACE_SIZE_ERROR = `Invalid size: must be one of ${WORKSPACE_SIZES.join(", ")}`;
|
|
610
613
|
|
|
611
614
|
// ../shared/src/e2b.ts
|
|
612
|
-
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-29-
|
|
615
|
+
var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-29-v4";
|
|
613
616
|
|
|
614
617
|
// ../shared/src/runtime-env.ts
|
|
615
618
|
function shellQuotePosix(value) {
|
|
@@ -2943,55 +2946,55 @@ function hasChatStarted(chat) {
|
|
|
2943
2946
|
var DESKTOP_NOVNC_PORT = 6080;
|
|
2944
2947
|
|
|
2945
2948
|
// ../shared/src/engine/v1.ts
|
|
2946
|
-
import { z
|
|
2949
|
+
import { z } from "zod";
|
|
2947
2950
|
var MERGED_MESSAGE_SEPARATOR = "\n\n<!-- replicas:merged -->\n\n";
|
|
2948
2951
|
var ENGINE_HEALTH_WAIT_HEADER = "X-Replicas-Health-Wait";
|
|
2949
2952
|
var ENGINE_HEALTH_WAIT_QUERY_PARAM = "wait_ms";
|
|
2950
2953
|
var ENGINE_HEALTH_MAX_WAIT_MS = 2e3;
|
|
2951
|
-
var createChatRequestSchema =
|
|
2952
|
-
id:
|
|
2953
|
-
createdAt:
|
|
2954
|
-
provider:
|
|
2955
|
-
title:
|
|
2956
|
-
parentChatId:
|
|
2957
|
-
clientRequestId:
|
|
2954
|
+
var createChatRequestSchema = z.object({
|
|
2955
|
+
id: z.string().uuid().optional(),
|
|
2956
|
+
createdAt: z.string().datetime().optional(),
|
|
2957
|
+
provider: z.enum(VALID_AGENT_PROVIDERS),
|
|
2958
|
+
title: z.string().min(1).optional(),
|
|
2959
|
+
parentChatId: z.string().uuid().optional(),
|
|
2960
|
+
clientRequestId: z.string().min(1).max(128).optional()
|
|
2958
2961
|
});
|
|
2959
|
-
var sendChatMessageRequestSchema =
|
|
2960
|
-
messageId:
|
|
2961
|
-
submittedAt:
|
|
2962
|
-
message:
|
|
2963
|
-
model:
|
|
2964
|
-
customInstructions:
|
|
2965
|
-
planMode:
|
|
2966
|
-
images:
|
|
2967
|
-
type:
|
|
2968
|
-
source:
|
|
2969
|
-
|
|
2970
|
-
|
|
2962
|
+
var sendChatMessageRequestSchema = z.object({
|
|
2963
|
+
messageId: z.string().optional(),
|
|
2964
|
+
submittedAt: z.string().optional(),
|
|
2965
|
+
message: z.string(),
|
|
2966
|
+
model: z.string().optional(),
|
|
2967
|
+
customInstructions: z.string().optional(),
|
|
2968
|
+
planMode: z.boolean().optional(),
|
|
2969
|
+
images: z.array(z.object({
|
|
2970
|
+
type: z.literal("image"),
|
|
2971
|
+
source: z.discriminatedUnion("type", [
|
|
2972
|
+
z.object({ type: z.literal("base64"), media_type: z.enum(IMAGE_MEDIA_TYPES), data: z.string() }),
|
|
2973
|
+
z.object({ type: z.literal("url"), url: z.string() })
|
|
2971
2974
|
])
|
|
2972
2975
|
})).optional(),
|
|
2973
|
-
thinkingLevel:
|
|
2974
|
-
goalMode:
|
|
2975
|
-
fastMode:
|
|
2976
|
-
enableInteractiveTools:
|
|
2977
|
-
type:
|
|
2978
|
-
merge:
|
|
2979
|
-
idempotencyKey:
|
|
2980
|
-
senderUserId:
|
|
2981
|
-
senderEmail:
|
|
2982
|
-
senderDisplayName:
|
|
2983
|
-
senderAvatarUrl:
|
|
2984
|
-
errorNotificationTarget:
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
type:
|
|
2989
|
-
provider:
|
|
2990
|
-
resource:
|
|
2991
|
-
repositoryId:
|
|
2992
|
-
resourceNumber:
|
|
2976
|
+
thinkingLevel: z.enum(VALID_THINKING_LEVELS).optional(),
|
|
2977
|
+
goalMode: z.boolean().optional(),
|
|
2978
|
+
fastMode: z.boolean().optional(),
|
|
2979
|
+
enableInteractiveTools: z.boolean().optional(),
|
|
2980
|
+
type: z.string().optional(),
|
|
2981
|
+
merge: z.boolean().optional(),
|
|
2982
|
+
idempotencyKey: z.string().optional(),
|
|
2983
|
+
senderUserId: z.string().optional(),
|
|
2984
|
+
senderEmail: z.string().optional(),
|
|
2985
|
+
senderDisplayName: z.string().optional(),
|
|
2986
|
+
senderAvatarUrl: z.string().optional(),
|
|
2987
|
+
errorNotificationTarget: z.discriminatedUnion("type", [
|
|
2988
|
+
z.object({ type: z.literal("slack") }),
|
|
2989
|
+
z.object({ type: z.literal("linear"), sessionId: z.string() }),
|
|
2990
|
+
z.object({
|
|
2991
|
+
type: z.literal("code_host"),
|
|
2992
|
+
provider: z.enum(["github", "gitlab"]),
|
|
2993
|
+
resource: z.enum(["issue", "pull_request"]),
|
|
2994
|
+
repositoryId: z.string(),
|
|
2995
|
+
resourceNumber: z.number()
|
|
2993
2996
|
}),
|
|
2994
|
-
|
|
2997
|
+
z.object({ type: z.literal("automation"), executionId: z.string() })
|
|
2995
2998
|
]).optional()
|
|
2996
2999
|
}).passthrough();
|
|
2997
3000
|
function isChatMessageSender(value) {
|
|
@@ -3332,32 +3335,32 @@ var DEFAULT_WORKSPACE_FILTERS = {
|
|
|
3332
3335
|
var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
|
|
3333
3336
|
|
|
3334
3337
|
// ../shared/src/routes/workspace-events.ts
|
|
3335
|
-
import { z as
|
|
3336
|
-
var workspaceChangedEventSchema =
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
type:
|
|
3340
|
-
workspaceId:
|
|
3341
|
-
chatId:
|
|
3342
|
-
ts:
|
|
3338
|
+
import { z as z2 } from "zod";
|
|
3339
|
+
var workspaceChangedEventSchema = z2.discriminatedUnion("type", [
|
|
3340
|
+
z2.object({ type: z2.literal("workspace.changed"), workspaceId: z2.string(), ts: z2.string() }),
|
|
3341
|
+
z2.object({
|
|
3342
|
+
type: z2.literal("workspace.chat.changed"),
|
|
3343
|
+
workspaceId: z2.string(),
|
|
3344
|
+
chatId: z2.string(),
|
|
3345
|
+
ts: z2.string()
|
|
3343
3346
|
}),
|
|
3344
|
-
|
|
3347
|
+
z2.object({ type: z2.literal("presence.changed"), ts: z2.string() })
|
|
3345
3348
|
]);
|
|
3346
3349
|
|
|
3347
3350
|
// ../shared/src/routes/presence.ts
|
|
3348
|
-
import { z as
|
|
3349
|
-
var presenceStatusSchema =
|
|
3350
|
-
var presenceLocationSchema =
|
|
3351
|
-
environmentId:
|
|
3352
|
-
workspaceId:
|
|
3351
|
+
import { z as z3 } from "zod";
|
|
3352
|
+
var presenceStatusSchema = z3.enum(["online", "typing"]);
|
|
3353
|
+
var presenceLocationSchema = z3.object({
|
|
3354
|
+
environmentId: z3.string().optional(),
|
|
3355
|
+
workspaceId: z3.string().optional()
|
|
3353
3356
|
});
|
|
3354
|
-
var presenceEntrySchema =
|
|
3355
|
-
userId:
|
|
3357
|
+
var presenceEntrySchema = z3.object({
|
|
3358
|
+
userId: z3.string(),
|
|
3356
3359
|
status: presenceStatusSchema,
|
|
3357
3360
|
location: presenceLocationSchema,
|
|
3358
|
-
ts:
|
|
3361
|
+
ts: z3.string()
|
|
3359
3362
|
});
|
|
3360
|
-
var updatePresenceRequestSchema =
|
|
3363
|
+
var updatePresenceRequestSchema = z3.object({
|
|
3361
3364
|
status: presenceStatusSchema,
|
|
3362
3365
|
location: presenceLocationSchema.optional()
|
|
3363
3366
|
});
|
|
@@ -10069,7 +10072,7 @@ var DEFAULT_CODEX_ARGS = ["app-server", "--listen", "stdio://"];
|
|
|
10069
10072
|
var MIN_CODEX_CLI_VERSION = "0.144.6";
|
|
10070
10073
|
var CODEX_UPGRADE_TIMEOUT_MS = 12e4;
|
|
10071
10074
|
var codexCliVersionEnsured = null;
|
|
10072
|
-
var ENGINE_PACKAGE_VERSION = "0.1.
|
|
10075
|
+
var ENGINE_PACKAGE_VERSION = "0.1.522";
|
|
10073
10076
|
var INITIALIZE_METHOD = "initialize";
|
|
10074
10077
|
var INITIALIZED_NOTIFICATION = "initialized";
|
|
10075
10078
|
var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
|
|
@@ -12671,6 +12674,24 @@ import { randomBytes as randomBytes2 } from "crypto";
|
|
|
12671
12674
|
import { fileURLToPath } from "url";
|
|
12672
12675
|
import { Agent } from "undici";
|
|
12673
12676
|
import { z as z5 } from "zod";
|
|
12677
|
+
|
|
12678
|
+
// ../shared/src/credentials/opencode-go.ts
|
|
12679
|
+
import { z as z4 } from "zod";
|
|
12680
|
+
var OPENCODE_GO_PROVIDER = "opencode-go";
|
|
12681
|
+
var DEFAULT_OPENCODE_GO_MODEL = "glm-5.2";
|
|
12682
|
+
var opencodeGoModelsDevSchema = z4.object({
|
|
12683
|
+
"opencode-go": z4.object({
|
|
12684
|
+
models: z4.record(z4.string(), z4.object({
|
|
12685
|
+
id: z4.string().optional(),
|
|
12686
|
+
name: z4.string(),
|
|
12687
|
+
description: z4.string().optional(),
|
|
12688
|
+
status: z4.enum(["alpha", "beta", "deprecated"]).optional()
|
|
12689
|
+
}))
|
|
12690
|
+
}).optional()
|
|
12691
|
+
});
|
|
12692
|
+
var OPENCODE_GO_CATALOG_CACHE_MS = 5 * 6e4;
|
|
12693
|
+
|
|
12694
|
+
// src/managers/opencode-manager.ts
|
|
12674
12695
|
import {
|
|
12675
12696
|
createOpencodeClient,
|
|
12676
12697
|
createOpencodeServer
|
|
@@ -12719,20 +12740,46 @@ async function hasOpencodeCredentials(provider) {
|
|
|
12719
12740
|
return false;
|
|
12720
12741
|
}
|
|
12721
12742
|
}
|
|
12743
|
+
async function getOpencodeProvider() {
|
|
12744
|
+
if (await hasOpencodeCredentials(OPENCODE_GO_PROVIDER)) return OPENCODE_GO_PROVIDER;
|
|
12745
|
+
if (await hasOpencodeCredentials(ASTER_PROVIDER)) return ASTER_PROVIDER;
|
|
12746
|
+
return "openrouter";
|
|
12747
|
+
}
|
|
12748
|
+
function getDefaultOpencodeModel(provider) {
|
|
12749
|
+
if (provider === OPENCODE_GO_PROVIDER) return DEFAULT_OPENCODE_GO_MODEL;
|
|
12750
|
+
if (provider === ASTER_PROVIDER) return DEFAULT_ASTER_MODEL;
|
|
12751
|
+
return DEFAULT_OPENCODE_MODEL;
|
|
12752
|
+
}
|
|
12722
12753
|
function getOpenCodeGoModel(model) {
|
|
12723
12754
|
return model.replace(/^[^/]+\//, "");
|
|
12724
12755
|
}
|
|
12725
|
-
|
|
12756
|
+
function opencodeConfig(provider, model) {
|
|
12726
12757
|
let config;
|
|
12727
|
-
if (
|
|
12758
|
+
if (provider === OPENCODE_GO_PROVIDER) {
|
|
12728
12759
|
config = {
|
|
12729
12760
|
enabled_providers: [OPENCODE_GO_PROVIDER],
|
|
12730
12761
|
model: `${OPENCODE_GO_PROVIDER}/${model}`,
|
|
12731
12762
|
permission: OPENCODE_WORKSPACE_PERMISSION,
|
|
12732
12763
|
share: "disabled"
|
|
12733
12764
|
};
|
|
12765
|
+
} else if (provider === ASTER_PROVIDER) {
|
|
12766
|
+
const models = getConfiguredOpencodeModels(model, provider);
|
|
12767
|
+
config = {
|
|
12768
|
+
enabled_providers: [ASTER_PROVIDER],
|
|
12769
|
+
model: `${ASTER_PROVIDER}/${model}`,
|
|
12770
|
+
provider: {
|
|
12771
|
+
[ASTER_PROVIDER]: {
|
|
12772
|
+
npm: "@ai-sdk/openai-compatible",
|
|
12773
|
+
name: "Aster",
|
|
12774
|
+
options: { baseURL: ASTER_BASE_URL },
|
|
12775
|
+
models: Object.fromEntries(models.map((candidate) => [candidate, {}]))
|
|
12776
|
+
}
|
|
12777
|
+
},
|
|
12778
|
+
permission: OPENCODE_WORKSPACE_PERMISSION,
|
|
12779
|
+
share: "disabled"
|
|
12780
|
+
};
|
|
12734
12781
|
} else {
|
|
12735
|
-
const models = getConfiguredOpencodeModels(model);
|
|
12782
|
+
const models = getConfiguredOpencodeModels(model, provider);
|
|
12736
12783
|
config = {
|
|
12737
12784
|
enabled_providers: ["openrouter"],
|
|
12738
12785
|
model: `openrouter/${model}`,
|
|
@@ -12745,14 +12792,10 @@ async function opencodeConfig(model) {
|
|
|
12745
12792
|
share: "disabled"
|
|
12746
12793
|
};
|
|
12747
12794
|
}
|
|
12748
|
-
const mcp = await readProvisionedOpencodeMcpConfig();
|
|
12749
|
-
if (mcp && Object.keys(mcp).length > 0) {
|
|
12750
|
-
config.mcp = mcp;
|
|
12751
|
-
}
|
|
12752
12795
|
return config;
|
|
12753
12796
|
}
|
|
12754
|
-
function getConfiguredOpencodeModels(model) {
|
|
12755
|
-
return [.../* @__PURE__ */ new Set([model, ...OPENROUTER_MODELS])];
|
|
12797
|
+
function getConfiguredOpencodeModels(model, provider) {
|
|
12798
|
+
return [.../* @__PURE__ */ new Set([model, ...provider === ASTER_PROVIDER ? ASTER_MODELS : OPENROUTER_MODELS])];
|
|
12756
12799
|
}
|
|
12757
12800
|
function opencodeCommandToSlashCommand(command) {
|
|
12758
12801
|
return createProviderSlashCommand("opencode", command.name, command.description);
|
|
@@ -12942,7 +12985,8 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
12942
12985
|
}
|
|
12943
12986
|
this.slashCommandsRequest ??= (async () => {
|
|
12944
12987
|
try {
|
|
12945
|
-
const
|
|
12988
|
+
const provider = await getOpencodeProvider();
|
|
12989
|
+
const client = await this.ensureClient(getDefaultOpencodeModel(provider), provider);
|
|
12946
12990
|
const directories = [this.workingDirectory, ...await getAgentAdditionalDirectories()];
|
|
12947
12991
|
const perDirectory = await Promise.all(directories.map(async (directory) => {
|
|
12948
12992
|
try {
|
|
@@ -12972,8 +13016,7 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
12972
13016
|
})();
|
|
12973
13017
|
return this.slashCommandsRequest;
|
|
12974
13018
|
}
|
|
12975
|
-
async ensureClient(model) {
|
|
12976
|
-
const providerId = await hasOpencodeCredentials(OPENCODE_GO_PROVIDER) ? OPENCODE_GO_PROVIDER : "openrouter";
|
|
13019
|
+
async ensureClient(model, providerId) {
|
|
12977
13020
|
if (this.client && this.providerId !== providerId) {
|
|
12978
13021
|
this.eventAbortController?.abort();
|
|
12979
13022
|
this.server?.close();
|
|
@@ -12983,11 +13026,15 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
12983
13026
|
}
|
|
12984
13027
|
this.providerId = providerId;
|
|
12985
13028
|
const configuredModel = providerId === OPENCODE_GO_PROVIDER ? getOpenCodeGoModel(model) : model;
|
|
13029
|
+
const providerModels = providerId === ASTER_PROVIDER ? ASTER_MODELS : providerId === "openrouter" ? OPENROUTER_MODELS : null;
|
|
13030
|
+
if (providerModels && !providerModels.includes(configuredModel)) {
|
|
13031
|
+
throw new Error(`Model ${configuredModel} is not available through ${providerId}.`);
|
|
13032
|
+
}
|
|
12986
13033
|
if (this.client && (providerId === OPENCODE_GO_PROVIDER || this.configuredModels.has(configuredModel))) {
|
|
12987
13034
|
return this.client;
|
|
12988
13035
|
}
|
|
12989
|
-
if (
|
|
12990
|
-
throw new Error("OpenCode Go or OpenRouter credentials are not configured for Opencode in this workspace.");
|
|
13036
|
+
if (!await hasOpencodeCredentials(providerId)) {
|
|
13037
|
+
throw new Error("OpenCode Go, Aster, or OpenRouter credentials are not configured for Opencode in this workspace.");
|
|
12991
13038
|
}
|
|
12992
13039
|
this.eventAbortController?.abort();
|
|
12993
13040
|
this.server?.close();
|
|
@@ -12997,10 +13044,13 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
12997
13044
|
}
|
|
12998
13045
|
const password = process.env.OPENCODE_SERVER_PASSWORD || randomBytes2(24).toString("base64url");
|
|
12999
13046
|
process.env.OPENCODE_SERVER_PASSWORD = password;
|
|
13047
|
+
const config = opencodeConfig(providerId, configuredModel);
|
|
13048
|
+
const mcp = await readProvisionedOpencodeMcpConfig();
|
|
13049
|
+
if (mcp && Object.keys(mcp).length > 0) config.mcp = mcp;
|
|
13000
13050
|
const server = await createOpencodeServer({
|
|
13001
13051
|
port: 0,
|
|
13002
13052
|
timeout: OPENCODE_SERVER_STARTUP_TIMEOUT_MS,
|
|
13003
|
-
config
|
|
13053
|
+
config
|
|
13004
13054
|
});
|
|
13005
13055
|
const client = createOpencodeClient({
|
|
13006
13056
|
baseUrl: server.url,
|
|
@@ -13011,7 +13061,7 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
13011
13061
|
});
|
|
13012
13062
|
this.client = client;
|
|
13013
13063
|
this.server = server;
|
|
13014
|
-
this.configuredModels = this.providerId === OPENCODE_GO_PROVIDER ? /* @__PURE__ */ new Set() : new Set(getConfiguredOpencodeModels(model));
|
|
13064
|
+
this.configuredModels = this.providerId === OPENCODE_GO_PROVIDER ? /* @__PURE__ */ new Set() : new Set(getConfiguredOpencodeModels(model, providerId));
|
|
13015
13065
|
const eventController = new AbortController();
|
|
13016
13066
|
this.eventAbortController = eventController;
|
|
13017
13067
|
this.eventSubscriptionReady = new Promise((resolve4) => {
|
|
@@ -13075,7 +13125,8 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
13075
13125
|
return OPENCODE_VARIANT_CANDIDATES_BY_THINKING_LEVEL[thinkingLevel].find((variant) => variants.has(variant));
|
|
13076
13126
|
}
|
|
13077
13127
|
async processMessageInternal(request) {
|
|
13078
|
-
const
|
|
13128
|
+
const provider = await getOpencodeProvider();
|
|
13129
|
+
const model = request.model ?? getDefaultOpencodeModel(provider);
|
|
13079
13130
|
const controller = new AbortController();
|
|
13080
13131
|
const linearSessionId = ENGINE_ENV.LINEAR_SESSION_ID;
|
|
13081
13132
|
const linearForwarder = new LinearEventForwarder(linearSessionId);
|
|
@@ -13083,7 +13134,7 @@ var OpencodeManager = class extends CodingAgentManager {
|
|
|
13083
13134
|
this.activeLinearForwarder = linearForwarder;
|
|
13084
13135
|
this.forwardedLinearPartKeys.clear();
|
|
13085
13136
|
try {
|
|
13086
|
-
const client = await this.ensureClient(model);
|
|
13137
|
+
const client = await this.ensureClient(model, provider);
|
|
13087
13138
|
const providerModel = this.providerId === OPENCODE_GO_PROVIDER ? getOpenCodeGoModel(model) : model;
|
|
13088
13139
|
const agent = request.planMode ? "plan" : "build";
|
|
13089
13140
|
const variant = await this.getThinkingVariant(client, providerModel, request.thinkingLevel);
|
|
@@ -13431,6 +13482,7 @@ var PiManager = class extends CodingAgentManager {
|
|
|
13431
13482
|
activeSessionFile = null;
|
|
13432
13483
|
historyFilePath;
|
|
13433
13484
|
historyFile;
|
|
13485
|
+
providerId = "openrouter";
|
|
13434
13486
|
constructor(options) {
|
|
13435
13487
|
super(options);
|
|
13436
13488
|
this.historyFilePath = options.historyFilePath ?? join20(PI_HISTORY_DIR, `${Date.now()}.jsonl`);
|
|
@@ -13462,8 +13514,8 @@ var PiManager = class extends CodingAgentManager {
|
|
|
13462
13514
|
}
|
|
13463
13515
|
async enqueueMessage(request) {
|
|
13464
13516
|
await this.initialized;
|
|
13465
|
-
if (!this.session && !
|
|
13466
|
-
throw new Error("OpenRouter authentication is missing for Pi. Add an
|
|
13517
|
+
if (!this.session && !this.getProviderCredentials()) {
|
|
13518
|
+
throw new Error("Aster or OpenRouter authentication is missing for Pi. Add an API key in Settings \u2192 Coding agents.");
|
|
13467
13519
|
}
|
|
13468
13520
|
return this.messageQueue.enqueue(request);
|
|
13469
13521
|
}
|
|
@@ -13476,8 +13528,9 @@ var PiManager = class extends CodingAgentManager {
|
|
|
13476
13528
|
async ensureSession(request) {
|
|
13477
13529
|
if (this.session) {
|
|
13478
13530
|
if (request.model && request.model !== this.session.model?.id) {
|
|
13479
|
-
const model2 = this.session.modelRegistry.find(
|
|
13480
|
-
if (model2)
|
|
13531
|
+
const model2 = this.session.modelRegistry.find(this.providerId, request.model);
|
|
13532
|
+
if (!model2) throw new Error(`Pi model is not available through ${this.providerId}: ${request.model}`);
|
|
13533
|
+
await this.session.setModel(model2);
|
|
13481
13534
|
}
|
|
13482
13535
|
if (request.thinkingLevel) {
|
|
13483
13536
|
this.session.setThinkingLevel(request.thinkingLevel === "ultra" || request.thinkingLevel === "ultracode" ? "xhigh" : request.thinkingLevel);
|
|
@@ -13485,34 +13538,56 @@ var PiManager = class extends CodingAgentManager {
|
|
|
13485
13538
|
return this.session;
|
|
13486
13539
|
}
|
|
13487
13540
|
const authStorage = AuthStorage.create(PI_AUTH_PATH);
|
|
13488
|
-
const
|
|
13489
|
-
if (!
|
|
13541
|
+
const credentials = this.getProviderCredentials(authStorage);
|
|
13542
|
+
if (!credentials) throw new Error("Aster or OpenRouter API key is not configured for Pi.");
|
|
13543
|
+
this.providerId = credentials.provider;
|
|
13490
13544
|
const modelRegistry = ModelRegistry.create(authStorage);
|
|
13491
13545
|
const openRouterModels = modelRegistry.getAll().filter((candidate) => candidate.provider === "openrouter");
|
|
13492
13546
|
const modelTemplate = openRouterModels[0];
|
|
13493
|
-
if (!modelTemplate) throw new Error("Pi
|
|
13494
|
-
|
|
13495
|
-
|
|
13496
|
-
|
|
13497
|
-
|
|
13498
|
-
|
|
13499
|
-
|
|
13500
|
-
|
|
13547
|
+
if (!modelTemplate) throw new Error("Pi OpenAI-compatible model template is unavailable.");
|
|
13548
|
+
if (this.providerId === ASTER_PROVIDER) {
|
|
13549
|
+
modelRegistry.registerProvider(ASTER_PROVIDER, {
|
|
13550
|
+
name: "Aster",
|
|
13551
|
+
api: "openai-completions",
|
|
13552
|
+
apiKey: credentials.apiKey,
|
|
13553
|
+
baseUrl: ASTER_BASE_URL,
|
|
13554
|
+
authHeader: true,
|
|
13555
|
+
models: ASTER_MODELS.map((id) => ({
|
|
13501
13556
|
id,
|
|
13502
|
-
name: id,
|
|
13503
|
-
api:
|
|
13504
|
-
|
|
13505
|
-
|
|
13506
|
-
input:
|
|
13507
|
-
|
|
13508
|
-
|
|
13509
|
-
maxTokens: modelTemplate.maxTokens
|
|
13557
|
+
name: ASTER_MODEL_LABELS[id] ?? id,
|
|
13558
|
+
api: "openai-completions",
|
|
13559
|
+
reasoning: true,
|
|
13560
|
+
input: ["text"],
|
|
13561
|
+
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
13562
|
+
contextWindow: id === "kimi-k3" ? 1e6 : 131072,
|
|
13563
|
+
maxTokens: 65536
|
|
13510
13564
|
}))
|
|
13511
|
-
|
|
13512
|
-
}
|
|
13513
|
-
|
|
13514
|
-
|
|
13515
|
-
|
|
13565
|
+
});
|
|
13566
|
+
} else {
|
|
13567
|
+
modelRegistry.registerProvider("openrouter", {
|
|
13568
|
+
api: modelTemplate.api,
|
|
13569
|
+
apiKey: credentials.apiKey,
|
|
13570
|
+
baseUrl: modelTemplate.baseUrl,
|
|
13571
|
+
models: [
|
|
13572
|
+
...openRouterModels,
|
|
13573
|
+
...OPENROUTER_MODELS.filter((id) => !openRouterModels.some((candidate) => candidate.id === id)).map((id) => ({
|
|
13574
|
+
id,
|
|
13575
|
+
name: id,
|
|
13576
|
+
api: modelTemplate.api,
|
|
13577
|
+
baseUrl: modelTemplate.baseUrl,
|
|
13578
|
+
reasoning: modelTemplate.reasoning,
|
|
13579
|
+
input: modelTemplate.input,
|
|
13580
|
+
cost: modelTemplate.cost,
|
|
13581
|
+
contextWindow: modelTemplate.contextWindow,
|
|
13582
|
+
maxTokens: modelTemplate.maxTokens
|
|
13583
|
+
}))
|
|
13584
|
+
]
|
|
13585
|
+
});
|
|
13586
|
+
}
|
|
13587
|
+
const defaultModel = this.providerId === ASTER_PROVIDER ? DEFAULT_ASTER_MODEL : DEFAULT_PI_MODEL;
|
|
13588
|
+
const modelId = request.model ?? defaultModel;
|
|
13589
|
+
const model = modelRegistry.find(this.providerId, modelId);
|
|
13590
|
+
if (!model) throw new Error(`Pi model is not available through ${this.providerId}: ${modelId}`);
|
|
13516
13591
|
const sessionManager = this.initialSessionId ? SessionManager.open(this.initialSessionId, PI_HISTORY_DIR, this.workingDirectory) : SessionManager.create(this.workingDirectory, PI_HISTORY_DIR);
|
|
13517
13592
|
const resourceLoader = new DefaultResourceLoader({
|
|
13518
13593
|
cwd: this.workingDirectory,
|
|
@@ -13538,9 +13613,12 @@ var PiManager = class extends CodingAgentManager {
|
|
|
13538
13613
|
this.unsubscribe = this.session.subscribe((event) => this.handleEvent(event));
|
|
13539
13614
|
return this.session;
|
|
13540
13615
|
}
|
|
13541
|
-
|
|
13542
|
-
const
|
|
13543
|
-
|
|
13616
|
+
getProviderCredentials(authStorage = AuthStorage.create(PI_AUTH_PATH)) {
|
|
13617
|
+
for (const provider of [ASTER_PROVIDER, "openrouter"]) {
|
|
13618
|
+
const credential = authStorage.get(provider);
|
|
13619
|
+
if (credential?.type === "api_key") return { provider, apiKey: credential.key };
|
|
13620
|
+
}
|
|
13621
|
+
return null;
|
|
13544
13622
|
}
|
|
13545
13623
|
handleEvent(event) {
|
|
13546
13624
|
const payload = eventPayload(event);
|
|
@@ -14407,7 +14485,10 @@ async function reconcileCanvasItems(filenames) {
|
|
|
14407
14485
|
}
|
|
14408
14486
|
|
|
14409
14487
|
// src/services/upload-chat-transcripts.ts
|
|
14410
|
-
import {
|
|
14488
|
+
import { createReadStream } from "fs";
|
|
14489
|
+
import { readdir as readdir7, readFile as readFile13, stat as stat4 } from "fs/promises";
|
|
14490
|
+
import { request as httpRequest } from "http";
|
|
14491
|
+
import { request as httpsRequest } from "https";
|
|
14411
14492
|
import { basename as basename2, join as join23 } from "path";
|
|
14412
14493
|
|
|
14413
14494
|
// src/services/chat/chat-senders.ts
|
|
@@ -14434,6 +14515,34 @@ var HISTORY_DIRS = [
|
|
|
14434
14515
|
join23(ENGINE_DIR2, "relay-histories"),
|
|
14435
14516
|
join23(ENGINE_DIR2, "codex-histories")
|
|
14436
14517
|
];
|
|
14518
|
+
async function putTranscript(uploadUrl, filePath, size) {
|
|
14519
|
+
await new Promise((resolve4, reject) => {
|
|
14520
|
+
const url = new URL(uploadUrl);
|
|
14521
|
+
const request = (url.protocol === "https:" ? httpsRequest : httpRequest)(url, {
|
|
14522
|
+
method: "PUT",
|
|
14523
|
+
headers: {
|
|
14524
|
+
"content-length": String(size),
|
|
14525
|
+
"content-type": "application/x-ndjson"
|
|
14526
|
+
}
|
|
14527
|
+
}, (response) => {
|
|
14528
|
+
response.setEncoding("utf8");
|
|
14529
|
+
let body = "";
|
|
14530
|
+
response.on("data", (chunk) => {
|
|
14531
|
+
body += chunk;
|
|
14532
|
+
});
|
|
14533
|
+
response.on("end", () => {
|
|
14534
|
+
const status = response.statusCode ?? 0;
|
|
14535
|
+
if (status >= 200 && status < 300) resolve4();
|
|
14536
|
+
else reject(new Error(`upload failed: ${status} ${body}`));
|
|
14537
|
+
});
|
|
14538
|
+
response.on("error", reject);
|
|
14539
|
+
});
|
|
14540
|
+
request.on("error", reject);
|
|
14541
|
+
const file = createReadStream(filePath, { start: 0, end: size - 1 });
|
|
14542
|
+
file.on("error", (error) => request.destroy(error));
|
|
14543
|
+
file.pipe(request);
|
|
14544
|
+
});
|
|
14545
|
+
}
|
|
14437
14546
|
async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
14438
14547
|
let flushed = 0;
|
|
14439
14548
|
let failed = 0;
|
|
@@ -14462,44 +14571,41 @@ async function flushAllChatTranscripts(chatsById = /* @__PURE__ */ new Map()) {
|
|
|
14462
14571
|
return { flushed, failed };
|
|
14463
14572
|
}
|
|
14464
14573
|
async function uploadChatTranscript(chatId, filePath, chat) {
|
|
14465
|
-
const
|
|
14466
|
-
if (
|
|
14467
|
-
|
|
14574
|
+
const { size } = await stat4(filePath);
|
|
14575
|
+
if (size === 0) return;
|
|
14576
|
+
const metadata = chat ? {
|
|
14577
|
+
provider: chat.provider,
|
|
14578
|
+
title: chat.title,
|
|
14579
|
+
createdAt: chat.createdAt,
|
|
14580
|
+
updatedAt: chat.updatedAt,
|
|
14581
|
+
parentChatId: chat.parentChatId,
|
|
14582
|
+
deletedAt: chat.deletedAt ?? null
|
|
14583
|
+
} : {};
|
|
14468
14584
|
try {
|
|
14469
|
-
senders = parseChatMessageSendersJsonl(
|
|
14585
|
+
metadata.senders = parseChatMessageSendersJsonl(
|
|
14586
|
+
await readFile13(chatMessageSendersFilePath(chatId), "utf-8")
|
|
14587
|
+
);
|
|
14470
14588
|
} catch (error) {
|
|
14471
14589
|
if (!(error && typeof error === "object" && "code" in error && error.code === "ENOENT")) throw error;
|
|
14472
14590
|
}
|
|
14473
|
-
const
|
|
14474
|
-
|
|
14475
|
-
|
|
14476
|
-
|
|
14477
|
-
|
|
14478
|
-
|
|
14479
|
-
createdAt: chat.createdAt,
|
|
14480
|
-
updatedAt: chat.updatedAt,
|
|
14481
|
-
parentChatId: chat.parentChatId,
|
|
14482
|
-
deletedAt: chat.deletedAt ?? null
|
|
14483
|
-
};
|
|
14484
|
-
form.append("provider", metadata.provider);
|
|
14485
|
-
form.append("title", metadata.title);
|
|
14486
|
-
form.append("created_at", metadata.createdAt);
|
|
14487
|
-
form.append("updated_at", metadata.updatedAt);
|
|
14488
|
-
if (metadata.parentChatId) form.append("parent_chat_id", metadata.parentChatId);
|
|
14489
|
-
form.append("deleted_at", metadata.deletedAt ?? "");
|
|
14591
|
+
const uploadRequest = { chatId, size, metadata };
|
|
14592
|
+
const prepareResponse = await monolithRequest("/v1/engine/chat-transcripts/upload-url", {
|
|
14593
|
+
body: uploadRequest
|
|
14594
|
+
});
|
|
14595
|
+
if (!prepareResponse.ok) {
|
|
14596
|
+
throw new Error(`prepare failed: ${prepareResponse.status} ${await prepareResponse.text()}`);
|
|
14490
14597
|
}
|
|
14491
|
-
|
|
14492
|
-
|
|
14598
|
+
const prepareBody = await prepareResponse.json();
|
|
14599
|
+
if (!isRecord(prepareBody) || typeof prepareBody.uploadUrl !== "string" && prepareBody.uploadUrl !== null) {
|
|
14600
|
+
throw new Error("prepare failed: invalid response");
|
|
14493
14601
|
}
|
|
14494
|
-
|
|
14495
|
-
|
|
14496
|
-
|
|
14497
|
-
|
|
14498
|
-
);
|
|
14499
|
-
|
|
14500
|
-
|
|
14501
|
-
const errorText = await response.text();
|
|
14502
|
-
throw new Error(`upload failed: ${response.status} ${errorText}`);
|
|
14602
|
+
if (prepareBody.uploadUrl === null) return;
|
|
14603
|
+
await putTranscript(prepareBody.uploadUrl, filePath, size);
|
|
14604
|
+
const finalizeResponse = await monolithRequest("/v1/engine/chat-transcripts/finalize", {
|
|
14605
|
+
body: uploadRequest
|
|
14606
|
+
});
|
|
14607
|
+
if (!finalizeResponse.ok) {
|
|
14608
|
+
throw new Error(`finalize failed: ${finalizeResponse.status} ${await finalizeResponse.text()}`);
|
|
14503
14609
|
}
|
|
14504
14610
|
}
|
|
14505
14611
|
|
|
@@ -14537,8 +14643,8 @@ async function flushRepoState() {
|
|
|
14537
14643
|
}
|
|
14538
14644
|
|
|
14539
14645
|
// src/services/upload-engine-logs.ts
|
|
14540
|
-
import { createReadStream } from "fs";
|
|
14541
|
-
import { readdir as readdir8, stat as
|
|
14646
|
+
import { createReadStream as createReadStream2 } from "fs";
|
|
14647
|
+
import { readdir as readdir8, stat as stat5 } from "fs/promises";
|
|
14542
14648
|
import { join as join24 } from "path";
|
|
14543
14649
|
var MAX_ENGINE_LOG_FLUSH_SESSIONS = 10;
|
|
14544
14650
|
var MAX_ENGINE_LOG_FLUSH_BYTES = 5 * 1024 * 1024;
|
|
@@ -14569,7 +14675,7 @@ async function flushAllEngineLogs() {
|
|
|
14569
14675
|
try {
|
|
14570
14676
|
const sessionId = filename.slice(0, -".log".length);
|
|
14571
14677
|
const filePath = join24(LOG_DIR, filename);
|
|
14572
|
-
const fileStat = await runBeforeDeadline(() =>
|
|
14678
|
+
const fileStat = await runBeforeDeadline(() => stat5(filePath), deadline);
|
|
14573
14679
|
if (!fileStat.isFile()) {
|
|
14574
14680
|
skipped++;
|
|
14575
14681
|
return null;
|
|
@@ -14601,7 +14707,7 @@ async function flushAllEngineLogs() {
|
|
|
14601
14707
|
const content = await runBeforeDeadline(async (signal) => {
|
|
14602
14708
|
if (candidate.length === 0) return Buffer.alloc(0);
|
|
14603
14709
|
const chunks = [];
|
|
14604
|
-
for await (const chunk of
|
|
14710
|
+
for await (const chunk of createReadStream2(candidate.filePath, {
|
|
14605
14711
|
start: candidate.offset,
|
|
14606
14712
|
end: candidate.offset + candidate.length - 1,
|
|
14607
14713
|
signal
|
|
@@ -15542,7 +15648,7 @@ var ChatService = class {
|
|
|
15542
15648
|
|
|
15543
15649
|
// src/services/repo-file-service.ts
|
|
15544
15650
|
import { execFile as execFile2 } from "child_process";
|
|
15545
|
-
import { readFile as readFile15, realpath, stat as
|
|
15651
|
+
import { readFile as readFile15, realpath, stat as stat6 } from "fs/promises";
|
|
15546
15652
|
import { join as join26, resolve as resolve2, extname as extname2 } from "path";
|
|
15547
15653
|
var CACHE_TTL_MS = 3e4;
|
|
15548
15654
|
var SEARCH_TIMEOUT_MS = 15e3;
|
|
@@ -15707,7 +15813,7 @@ var RepoFileService = class {
|
|
|
15707
15813
|
const repoRoot = await realpath(repo.path);
|
|
15708
15814
|
const repoPrefix = repoRoot.endsWith("/") ? repoRoot : repoRoot + "/";
|
|
15709
15815
|
if (!fullPath.startsWith(repoPrefix) && fullPath !== repoRoot) return null;
|
|
15710
|
-
const fileStat = await
|
|
15816
|
+
const fileStat = await stat6(fullPath);
|
|
15711
15817
|
if (!fileStat.isFile()) return null;
|
|
15712
15818
|
const sizeBytes = fileStat.size;
|
|
15713
15819
|
if (isBinaryExtension(filePath)) {
|
|
@@ -15810,7 +15916,7 @@ var RepoFileService = class {
|
|
|
15810
15916
|
// src/v1-routes.ts
|
|
15811
15917
|
import { Hono } from "hono";
|
|
15812
15918
|
import { z as z7 } from "zod";
|
|
15813
|
-
import { readdir as readdir10, stat as
|
|
15919
|
+
import { readdir as readdir10, stat as stat7, readFile as readFile18 } from "fs/promises";
|
|
15814
15920
|
import { join as join29, resolve as resolve3 } from "path";
|
|
15815
15921
|
|
|
15816
15922
|
// src/services/warm-hooks-service.ts
|
|
@@ -17200,7 +17306,7 @@ data: ${JSON.stringify("Terminal session not found")}
|
|
|
17200
17306
|
const sessions = await Promise.all(
|
|
17201
17307
|
logFiles.map(async (filename) => {
|
|
17202
17308
|
const filePath = join29(LOG_DIR, filename);
|
|
17203
|
-
const fileStat = await
|
|
17309
|
+
const fileStat = await stat7(filePath);
|
|
17204
17310
|
const sessionId = filename.replace(/\.log$/, "");
|
|
17205
17311
|
return {
|
|
17206
17312
|
sessionId,
|