replicas-engine 0.1.520 → 0.1.523

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.
Files changed (2) hide show
  1. package/dist/src/index.js +203 -125
  2. 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/credentials/opencode-go.ts
199
- import { z } from "zod";
200
- var OPENCODE_GO_PROVIDER = "opencode-go";
201
- var opencodeGoModelsDevSchema = z.object({
202
- "opencode-go": z.object({
203
- models: z.record(z.string(), z.object({
204
- id: z.string().optional(),
205
- name: z.string(),
206
- description: z.string().optional(),
207
- status: z.enum(["alpha", "beta", "deprecated"]).optional()
208
- }))
209
- }).optional()
210
- });
211
- var OPENCODE_GO_CATALOG_CACHE_MS = 5 * 6e4;
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-v2";
615
+ var E2B_TEMPLATE_NAME = "replicas-sandbox-2026-07-29-v5";
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 as z2 } from "zod";
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 = z2.object({
2952
- id: z2.string().uuid().optional(),
2953
- createdAt: z2.string().datetime().optional(),
2954
- provider: z2.enum(VALID_AGENT_PROVIDERS),
2955
- title: z2.string().min(1).optional(),
2956
- parentChatId: z2.string().uuid().optional(),
2957
- clientRequestId: z2.string().min(1).max(128).optional()
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 = z2.object({
2960
- messageId: z2.string().optional(),
2961
- submittedAt: z2.string().optional(),
2962
- message: z2.string(),
2963
- model: z2.string().optional(),
2964
- customInstructions: z2.string().optional(),
2965
- planMode: z2.boolean().optional(),
2966
- images: z2.array(z2.object({
2967
- type: z2.literal("image"),
2968
- source: z2.discriminatedUnion("type", [
2969
- z2.object({ type: z2.literal("base64"), media_type: z2.enum(IMAGE_MEDIA_TYPES), data: z2.string() }),
2970
- z2.object({ type: z2.literal("url"), url: z2.string() })
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: z2.enum(VALID_THINKING_LEVELS).optional(),
2974
- goalMode: z2.boolean().optional(),
2975
- fastMode: z2.boolean().optional(),
2976
- enableInteractiveTools: z2.boolean().optional(),
2977
- type: z2.string().optional(),
2978
- merge: z2.boolean().optional(),
2979
- idempotencyKey: z2.string().optional(),
2980
- senderUserId: z2.string().optional(),
2981
- senderEmail: z2.string().optional(),
2982
- senderDisplayName: z2.string().optional(),
2983
- senderAvatarUrl: z2.string().optional(),
2984
- errorNotificationTarget: z2.discriminatedUnion("type", [
2985
- z2.object({ type: z2.literal("slack") }),
2986
- z2.object({ type: z2.literal("linear"), sessionId: z2.string() }),
2987
- z2.object({
2988
- type: z2.literal("code_host"),
2989
- provider: z2.enum(["github", "gitlab"]),
2990
- resource: z2.enum(["issue", "pull_request"]),
2991
- repositoryId: z2.string(),
2992
- resourceNumber: z2.number()
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
- z2.object({ type: z2.literal("automation"), executionId: z2.string() })
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 z3 } from "zod";
3336
- var workspaceChangedEventSchema = z3.discriminatedUnion("type", [
3337
- z3.object({ type: z3.literal("workspace.changed"), workspaceId: z3.string(), ts: z3.string() }),
3338
- z3.object({
3339
- type: z3.literal("workspace.chat.changed"),
3340
- workspaceId: z3.string(),
3341
- chatId: z3.string(),
3342
- ts: z3.string()
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
- z3.object({ type: z3.literal("presence.changed"), ts: z3.string() })
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 z4 } from "zod";
3349
- var presenceStatusSchema = z4.enum(["online", "typing"]);
3350
- var presenceLocationSchema = z4.object({
3351
- environmentId: z4.string().optional(),
3352
- workspaceId: z4.string().optional()
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 = z4.object({
3355
- userId: z4.string(),
3357
+ var presenceEntrySchema = z3.object({
3358
+ userId: z3.string(),
3356
3359
  status: presenceStatusSchema,
3357
3360
  location: presenceLocationSchema,
3358
- ts: z4.string()
3361
+ ts: z3.string()
3359
3362
  });
3360
- var updatePresenceRequestSchema = z4.object({
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.520";
10075
+ var ENGINE_PACKAGE_VERSION = "0.1.523";
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
- async function opencodeConfig(model) {
12756
+ function opencodeConfig(provider, model) {
12726
12757
  let config;
12727
- if (await hasOpencodeCredentials(OPENCODE_GO_PROVIDER)) {
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 client = await this.ensureClient(DEFAULT_OPENCODE_MODEL);
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 (this.providerId !== OPENCODE_GO_PROVIDER && !await hasOpencodeCredentials("openrouter")) {
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: await opencodeConfig(configuredModel)
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 model = request.model ?? DEFAULT_OPENCODE_MODEL;
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 && !await this.getOpenRouterApiKey()) {
13466
- throw new Error("OpenRouter authentication is missing for Pi. Add an OpenRouter API key in Settings \u2192 Coding agents.");
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("openrouter", request.model);
13480
- if (model2) await this.session.setModel(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 apiKey = await this.getOpenRouterApiKey(authStorage);
13489
- if (!apiKey) throw new Error("OpenRouter API key is not configured for Pi.");
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 OpenRouter model catalog is empty.");
13494
- modelRegistry.registerProvider("openrouter", {
13495
- api: modelTemplate.api,
13496
- apiKey,
13497
- baseUrl: modelTemplate.baseUrl,
13498
- models: [
13499
- ...openRouterModels,
13500
- ...OPENROUTER_MODELS.filter((id) => !openRouterModels.some((candidate) => candidate.id === id)).map((id) => ({
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: modelTemplate.api,
13504
- baseUrl: modelTemplate.baseUrl,
13505
- reasoning: modelTemplate.reasoning,
13506
- input: modelTemplate.input,
13507
- cost: modelTemplate.cost,
13508
- contextWindow: modelTemplate.contextWindow,
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
- const modelId = request.model ?? DEFAULT_PI_MODEL;
13514
- const model = modelRegistry.find("openrouter", modelId) ?? modelRegistry.find("openrouter", DEFAULT_PI_MODEL);
13515
- if (!model) throw new Error(`Pi model is not available through OpenRouter: ${modelId}`);
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
- async getOpenRouterApiKey(authStorage = AuthStorage.create(PI_AUTH_PATH)) {
13542
- const credential = authStorage.get("openrouter");
13543
- return credential?.type === "api_key" ? credential.key : void 0;
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);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "replicas-engine",
3
- "version": "0.1.520",
3
+ "version": "0.1.523",
4
4
  "description": "Lightweight API server for Replicas workspaces",
5
5
  "type": "module",
6
6
  "main": "dist/src/index.js",