replicas-engine 0.1.875 → 0.1.877

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.
@@ -277,6 +277,8 @@ var FALLBACK_AGENT_MODEL = {
277
277
  relay: DEFAULT_CLAUDE_MODEL
278
278
  };
279
279
  function getDefaultAgentModel(provider, overrides) {
280
+ const catalogDefault = overrides?.defaultModels?.[provider];
281
+ if (catalogDefault !== void 0) return catalogDefault ?? "";
280
282
  const fallback = FALLBACK_AGENT_MODEL[provider];
281
283
  const options = getAgentModelOptions(provider, overrides);
282
284
  return options.includes(fallback) ? fallback : options[0];
@@ -544,124 +546,6 @@ function paginateEngineLogContent(input) {
544
546
  // ../shared/src/analytics/types.ts
545
547
  import { z as z2 } from "zod";
546
548
 
547
- // ../shared/src/credentials/types.ts
548
- var CREDENTIAL_SCOPE = {
549
- USER: "user",
550
- ORG: "org"
551
- };
552
- var CREDENTIAL_SCOPES = Object.values(CREDENTIAL_SCOPE);
553
- var CREDENTIAL_SCOPE_PRIORITY = [CREDENTIAL_SCOPE.USER, CREDENTIAL_SCOPE.ORG];
554
-
555
- // ../shared/src/credentials/agents.ts
556
- var CREDENTIAL_METHOD = {
557
- OAUTH: "oauth",
558
- API_KEY: "api_key",
559
- OPENAI_COMPATIBLE: "openai-compatible",
560
- FOUNDRY: "foundry",
561
- BEDROCK: "bedrock",
562
- OPENCODE_GO: "opencode-go",
563
- ASTER: "aster",
564
- OPENROUTER: "openrouter",
565
- AI_GATEWAY: "ai-gateway",
566
- MUSE_OAUTH: "muse-oauth"
567
- };
568
- var CREDENTIAL_TYPE = {
569
- CLAUDE_OAUTH: "claude",
570
- ANTHROPIC_API_KEY: "claude_anthropic_api_key",
571
- CLAUDE_FOUNDRY: "claude_foundry",
572
- CLAUDE_BEDROCK: "claude_bedrock",
573
- CODEX_OAUTH: "codex",
574
- OPENAI_API_KEY: "openai_api_key",
575
- OPENAI_COMPATIBLE: "openai_compatible",
576
- CODEX_FOUNDRY: "codex_foundry",
577
- CURSOR_API_KEY: "cursor_api_key",
578
- OPENCODE_GO_API_KEY: "opencode_go_api_key",
579
- ASTER_API_KEY: "aster_api_key",
580
- OPENROUTER_API_KEY: "openrouter_api_key",
581
- AI_GATEWAY_API_KEY: "ai_gateway_api_key",
582
- GEMINI_API_KEY: "gemini_api_key",
583
- MUSE_OAUTH: "muse_oauth",
584
- MUSE_API_KEY: "muse_api_key"
585
- };
586
- var INFERENCE_PROVIDER_LABELS = {
587
- [CREDENTIAL_METHOD.OPENCODE_GO]: "OpenCode Go",
588
- [CREDENTIAL_METHOD.ASTER]: "Aster",
589
- [CREDENTIAL_METHOD.OPENROUTER]: "OpenRouter"
590
- };
591
- var AGENT_CREDENTIAL_METHODS_IN_ORDER = {
592
- [AGENT.CLAUDE]: [
593
- { method: CREDENTIAL_METHOD.OAUTH, credentialType: CREDENTIAL_TYPE.CLAUDE_OAUTH },
594
- { method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.ANTHROPIC_API_KEY },
595
- { method: CREDENTIAL_METHOD.FOUNDRY, credentialType: CREDENTIAL_TYPE.CLAUDE_FOUNDRY },
596
- { method: CREDENTIAL_METHOD.BEDROCK, credentialType: CREDENTIAL_TYPE.CLAUDE_BEDROCK }
597
- ],
598
- [AGENT.CODEX]: [
599
- { method: CREDENTIAL_METHOD.OAUTH, credentialType: CREDENTIAL_TYPE.CODEX_OAUTH },
600
- { method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.OPENAI_API_KEY },
601
- { method: CREDENTIAL_METHOD.OPENAI_COMPATIBLE, credentialType: CREDENTIAL_TYPE.OPENAI_COMPATIBLE },
602
- { method: CREDENTIAL_METHOD.FOUNDRY, credentialType: CREDENTIAL_TYPE.CODEX_FOUNDRY }
603
- ],
604
- [AGENT.CURSOR]: [
605
- { method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.CURSOR_API_KEY }
606
- ],
607
- [AGENT.DEEPSEEK]: [
608
- { method: CREDENTIAL_METHOD.OPENROUTER, credentialType: CREDENTIAL_TYPE.OPENROUTER_API_KEY }
609
- ],
610
- [AGENT.FX]: [
611
- { method: CREDENTIAL_METHOD.AI_GATEWAY, credentialType: CREDENTIAL_TYPE.AI_GATEWAY_API_KEY }
612
- ],
613
- [AGENT.GEMINI]: [
614
- { method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.GEMINI_API_KEY }
615
- ],
616
- [AGENT.KIMI]: [
617
- { method: CREDENTIAL_METHOD.AI_GATEWAY, credentialType: CREDENTIAL_TYPE.AI_GATEWAY_API_KEY }
618
- ],
619
- [AGENT.MUSE]: [
620
- { method: CREDENTIAL_METHOD.MUSE_OAUTH, credentialType: CREDENTIAL_TYPE.MUSE_OAUTH },
621
- { method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.MUSE_API_KEY }
622
- ],
623
- [AGENT.OPENCODE]: [
624
- { method: CREDENTIAL_METHOD.OPENCODE_GO, credentialType: CREDENTIAL_TYPE.OPENCODE_GO_API_KEY },
625
- { method: CREDENTIAL_METHOD.ASTER, credentialType: CREDENTIAL_TYPE.ASTER_API_KEY },
626
- { method: CREDENTIAL_METHOD.OPENROUTER, credentialType: CREDENTIAL_TYPE.OPENROUTER_API_KEY }
627
- ],
628
- [AGENT.PI]: [
629
- { method: CREDENTIAL_METHOD.OPENCODE_GO, credentialType: CREDENTIAL_TYPE.OPENCODE_GO_API_KEY },
630
- { method: CREDENTIAL_METHOD.ASTER, credentialType: CREDENTIAL_TYPE.ASTER_API_KEY },
631
- { method: CREDENTIAL_METHOD.OPENROUTER, credentialType: CREDENTIAL_TYPE.OPENROUTER_API_KEY }
632
- ]
633
- };
634
- function agentCredentialMethods(agent) {
635
- return AGENT_CREDENTIAL_METHODS_IN_ORDER[agent].map((entry) => entry.method);
636
- }
637
- function getCredentialMethodLabel(agent, method) {
638
- switch (method) {
639
- case CREDENTIAL_METHOD.OAUTH:
640
- if (agent === AGENT.CODEX) return "ChatGPT account";
641
- return "Claude account";
642
- case CREDENTIAL_METHOD.API_KEY:
643
- if (agent === AGENT.CODEX) return "OpenAI API key";
644
- if (agent === AGENT.CURSOR) return "Cursor API key";
645
- if (agent === AGENT.GEMINI) return "Gemini API key";
646
- if (agent === AGENT.MUSE) return "Muse API key";
647
- return "Anthropic API key";
648
- case CREDENTIAL_METHOD.OPENAI_COMPATIBLE:
649
- return "OpenAI-compatible endpoint";
650
- case CREDENTIAL_METHOD.FOUNDRY:
651
- return "Microsoft Foundry";
652
- case CREDENTIAL_METHOD.BEDROCK:
653
- return "AWS Bedrock";
654
- case CREDENTIAL_METHOD.OPENCODE_GO:
655
- case CREDENTIAL_METHOD.ASTER:
656
- case CREDENTIAL_METHOD.OPENROUTER:
657
- return INFERENCE_PROVIDER_LABELS[method];
658
- case CREDENTIAL_METHOD.AI_GATEWAY:
659
- return "Vercel AI Gateway";
660
- case CREDENTIAL_METHOD.MUSE_OAUTH:
661
- return "Muse account";
662
- }
663
- }
664
-
665
549
  // ../shared/src/result.ts
666
550
  function createSuccessResult(data) {
667
551
  return { ok: true, data };
@@ -798,6 +682,209 @@ function resolveOpenAICompatibleModelsUrl(values) {
798
682
  return values.modelsUrl || `${values.baseUrl}/models`;
799
683
  }
800
684
 
685
+ // ../shared/src/credentials/ollama.ts
686
+ var OLLAMA_AGENTS = ["claude", "codex", "deepseek", "kimi", "opencode", "pi"];
687
+ function ollamaAuthEnvKeys(agent) {
688
+ return ["API_KEY", "BASE_URL"].map((key) => `REPLICAS_${agent.toUpperCase()}_OLLAMA_${key}`);
689
+ }
690
+ function ollamaAuthEnv(agent, credential) {
691
+ const [key, url] = ollamaAuthEnvKeys(agent);
692
+ return { [key]: credential.apiKey, [url]: credential.baseUrl };
693
+ }
694
+ function readOllamaAuthEnv(agent, env) {
695
+ const [key, url] = ollamaAuthEnvKeys(agent);
696
+ const apiKey = env[key];
697
+ const baseUrl = env[url];
698
+ return apiKey && baseUrl ? { apiKey, baseUrl } : null;
699
+ }
700
+
701
+ // ../shared/src/credentials/ollama-models.ts
702
+ var DEFAULT_OLLAMA_MODEL = "gpt-oss:20b";
703
+ var catalogs = /* @__PURE__ */ new Map();
704
+ function getDefaultOllamaModel(models) {
705
+ return models.find((model) => model.id === DEFAULT_OLLAMA_MODEL && model.capabilities?.includes("tools") && (model.contextWindow ?? 0) >= 64e3)?.id ?? null;
706
+ }
707
+ function parseOllamaModelDetails(model, payload) {
708
+ if (!isRecord(payload)) return model;
709
+ const capabilities = Array.isArray(payload.capabilities) ? payload.capabilities.filter((value) => typeof value === "string") : void 0;
710
+ const info = isRecord(payload.model_info) ? payload.model_info : {};
711
+ const context = Object.entries(info).find(([key]) => key.endsWith(".context_length"))?.[1];
712
+ const configured = typeof payload.parameters === "string" ? /(?:^|\n)\s*num_ctx\s+(\d+)/.exec(payload.parameters)?.[1] : void 0;
713
+ const contextWindow = configured ? Number(configured) : context;
714
+ return {
715
+ ...model,
716
+ ...capabilities ? { capabilities } : {},
717
+ ...typeof contextWindow === "number" && Number.isSafeInteger(contextWindow) && contextWindow > 0 ? { contextWindow } : {}
718
+ };
719
+ }
720
+ function listOllamaModels(credential) {
721
+ const key = JSON.stringify([credential.baseUrl, credential.apiKey]);
722
+ const cached = catalogs.get(key);
723
+ if (cached && cached.expiresAt > Date.now()) return cached.models;
724
+ const models = loadOllamaModels(credential).catch((error) => {
725
+ if (catalogs.get(key)?.models === models) catalogs.delete(key);
726
+ throw error;
727
+ });
728
+ catalogs.set(key, { expiresAt: Date.now() + 6e4, models });
729
+ return models;
730
+ }
731
+ async function loadOllamaModels(credential) {
732
+ const models = await listOpenAICompatibleModels({ apiKey: credential.apiKey, baseUrl: `${credential.baseUrl}/v1` });
733
+ const url = `${credential.baseUrl}/api/show`;
734
+ validateExternalApiHost(url, "Ollama model details");
735
+ const detailed = [];
736
+ const signal = AbortSignal.timeout(1e4);
737
+ for (let offset = 0; offset < models.length; offset += 10) {
738
+ if (signal.aborted) {
739
+ detailed.push(...models.slice(offset));
740
+ break;
741
+ }
742
+ detailed.push(...await Promise.all(models.slice(offset, offset + 10).map(async (model) => {
743
+ try {
744
+ const response = await fetch(url, {
745
+ method: "POST",
746
+ redirect: "error",
747
+ signal,
748
+ headers: { Authorization: `Bearer ${credential.apiKey}`, "Content-Type": "application/json" },
749
+ body: JSON.stringify({ model: model.id })
750
+ });
751
+ return response.ok ? parseOllamaModelDetails(model, await response.json()) : model;
752
+ } catch {
753
+ return model;
754
+ }
755
+ })));
756
+ }
757
+ return detailed.sort((left, right) => left.id.localeCompare(right.id));
758
+ }
759
+
760
+ // ../shared/src/credentials/types.ts
761
+ var CREDENTIAL_SCOPE = {
762
+ USER: "user",
763
+ ORG: "org"
764
+ };
765
+ var CREDENTIAL_SCOPES = Object.values(CREDENTIAL_SCOPE);
766
+ var CREDENTIAL_SCOPE_PRIORITY = [CREDENTIAL_SCOPE.USER, CREDENTIAL_SCOPE.ORG];
767
+
768
+ // ../shared/src/credentials/agents.ts
769
+ var CREDENTIAL_METHOD = {
770
+ OAUTH: "oauth",
771
+ API_KEY: "api_key",
772
+ OPENAI_COMPATIBLE: "openai-compatible",
773
+ OLLAMA: "ollama",
774
+ FOUNDRY: "foundry",
775
+ BEDROCK: "bedrock",
776
+ OPENCODE_GO: "opencode-go",
777
+ ASTER: "aster",
778
+ OPENROUTER: "openrouter",
779
+ AI_GATEWAY: "ai-gateway",
780
+ MUSE_OAUTH: "muse-oauth"
781
+ };
782
+ var CREDENTIAL_TYPE = {
783
+ CLAUDE_OAUTH: "claude",
784
+ ANTHROPIC_API_KEY: "claude_anthropic_api_key",
785
+ CLAUDE_FOUNDRY: "claude_foundry",
786
+ CLAUDE_BEDROCK: "claude_bedrock",
787
+ CODEX_OAUTH: "codex",
788
+ OPENAI_API_KEY: "openai_api_key",
789
+ OPENAI_COMPATIBLE: "openai_compatible",
790
+ OLLAMA: "ollama",
791
+ CODEX_FOUNDRY: "codex_foundry",
792
+ CURSOR_API_KEY: "cursor_api_key",
793
+ OPENCODE_GO_API_KEY: "opencode_go_api_key",
794
+ ASTER_API_KEY: "aster_api_key",
795
+ OPENROUTER_API_KEY: "openrouter_api_key",
796
+ AI_GATEWAY_API_KEY: "ai_gateway_api_key",
797
+ GEMINI_API_KEY: "gemini_api_key",
798
+ MUSE_OAUTH: "muse_oauth",
799
+ MUSE_API_KEY: "muse_api_key"
800
+ };
801
+ var INFERENCE_PROVIDER_LABELS = {
802
+ [CREDENTIAL_METHOD.OLLAMA]: "Ollama",
803
+ [CREDENTIAL_METHOD.OPENCODE_GO]: "OpenCode Go",
804
+ [CREDENTIAL_METHOD.ASTER]: "Aster",
805
+ [CREDENTIAL_METHOD.OPENROUTER]: "OpenRouter"
806
+ };
807
+ var AGENT_CREDENTIAL_METHODS_IN_ORDER = {
808
+ [AGENT.CLAUDE]: [
809
+ { method: CREDENTIAL_METHOD.OAUTH, credentialType: CREDENTIAL_TYPE.CLAUDE_OAUTH },
810
+ { method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.ANTHROPIC_API_KEY },
811
+ { method: CREDENTIAL_METHOD.FOUNDRY, credentialType: CREDENTIAL_TYPE.CLAUDE_FOUNDRY },
812
+ { method: CREDENTIAL_METHOD.BEDROCK, credentialType: CREDENTIAL_TYPE.CLAUDE_BEDROCK },
813
+ { method: CREDENTIAL_METHOD.OLLAMA, credentialType: CREDENTIAL_TYPE.OLLAMA }
814
+ ],
815
+ [AGENT.CODEX]: [
816
+ { method: CREDENTIAL_METHOD.OAUTH, credentialType: CREDENTIAL_TYPE.CODEX_OAUTH },
817
+ { method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.OPENAI_API_KEY },
818
+ { method: CREDENTIAL_METHOD.OPENAI_COMPATIBLE, credentialType: CREDENTIAL_TYPE.OPENAI_COMPATIBLE },
819
+ { method: CREDENTIAL_METHOD.FOUNDRY, credentialType: CREDENTIAL_TYPE.CODEX_FOUNDRY },
820
+ { method: CREDENTIAL_METHOD.OLLAMA, credentialType: CREDENTIAL_TYPE.OLLAMA }
821
+ ],
822
+ [AGENT.CURSOR]: [
823
+ { method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.CURSOR_API_KEY }
824
+ ],
825
+ [AGENT.DEEPSEEK]: [
826
+ { method: CREDENTIAL_METHOD.OPENROUTER, credentialType: CREDENTIAL_TYPE.OPENROUTER_API_KEY },
827
+ { method: CREDENTIAL_METHOD.OLLAMA, credentialType: CREDENTIAL_TYPE.OLLAMA }
828
+ ],
829
+ [AGENT.FX]: [
830
+ { method: CREDENTIAL_METHOD.AI_GATEWAY, credentialType: CREDENTIAL_TYPE.AI_GATEWAY_API_KEY }
831
+ ],
832
+ [AGENT.GEMINI]: [
833
+ { method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.GEMINI_API_KEY }
834
+ ],
835
+ [AGENT.KIMI]: [
836
+ { method: CREDENTIAL_METHOD.AI_GATEWAY, credentialType: CREDENTIAL_TYPE.AI_GATEWAY_API_KEY },
837
+ { method: CREDENTIAL_METHOD.OLLAMA, credentialType: CREDENTIAL_TYPE.OLLAMA }
838
+ ],
839
+ [AGENT.MUSE]: [
840
+ { method: CREDENTIAL_METHOD.MUSE_OAUTH, credentialType: CREDENTIAL_TYPE.MUSE_OAUTH },
841
+ { method: CREDENTIAL_METHOD.API_KEY, credentialType: CREDENTIAL_TYPE.MUSE_API_KEY }
842
+ ],
843
+ [AGENT.OPENCODE]: [
844
+ { method: CREDENTIAL_METHOD.OPENCODE_GO, credentialType: CREDENTIAL_TYPE.OPENCODE_GO_API_KEY },
845
+ { method: CREDENTIAL_METHOD.ASTER, credentialType: CREDENTIAL_TYPE.ASTER_API_KEY },
846
+ { method: CREDENTIAL_METHOD.OPENROUTER, credentialType: CREDENTIAL_TYPE.OPENROUTER_API_KEY },
847
+ { method: CREDENTIAL_METHOD.OLLAMA, credentialType: CREDENTIAL_TYPE.OLLAMA }
848
+ ],
849
+ [AGENT.PI]: [
850
+ { method: CREDENTIAL_METHOD.OPENCODE_GO, credentialType: CREDENTIAL_TYPE.OPENCODE_GO_API_KEY },
851
+ { method: CREDENTIAL_METHOD.ASTER, credentialType: CREDENTIAL_TYPE.ASTER_API_KEY },
852
+ { method: CREDENTIAL_METHOD.OPENROUTER, credentialType: CREDENTIAL_TYPE.OPENROUTER_API_KEY },
853
+ { method: CREDENTIAL_METHOD.OLLAMA, credentialType: CREDENTIAL_TYPE.OLLAMA }
854
+ ]
855
+ };
856
+ function agentCredentialMethods(agent) {
857
+ return AGENT_CREDENTIAL_METHODS_IN_ORDER[agent].map((entry) => entry.method);
858
+ }
859
+ function getCredentialMethodLabel(agent, method) {
860
+ switch (method) {
861
+ case CREDENTIAL_METHOD.OAUTH:
862
+ if (agent === AGENT.CODEX) return "ChatGPT account";
863
+ return "Claude account";
864
+ case CREDENTIAL_METHOD.API_KEY:
865
+ if (agent === AGENT.CODEX) return "OpenAI API key";
866
+ if (agent === AGENT.CURSOR) return "Cursor API key";
867
+ if (agent === AGENT.GEMINI) return "Gemini API key";
868
+ if (agent === AGENT.MUSE) return "Muse API key";
869
+ return "Anthropic API key";
870
+ case CREDENTIAL_METHOD.OPENAI_COMPATIBLE:
871
+ return "OpenAI-compatible endpoint";
872
+ case CREDENTIAL_METHOD.FOUNDRY:
873
+ return "Microsoft Foundry";
874
+ case CREDENTIAL_METHOD.BEDROCK:
875
+ return "AWS Bedrock";
876
+ case CREDENTIAL_METHOD.OLLAMA:
877
+ case CREDENTIAL_METHOD.OPENCODE_GO:
878
+ case CREDENTIAL_METHOD.ASTER:
879
+ case CREDENTIAL_METHOD.OPENROUTER:
880
+ return INFERENCE_PROVIDER_LABELS[method];
881
+ case CREDENTIAL_METHOD.AI_GATEWAY:
882
+ return "Vercel AI Gateway";
883
+ case CREDENTIAL_METHOD.MUSE_OAUTH:
884
+ return "Muse account";
885
+ }
886
+ }
887
+
801
888
  // ../shared/src/pricing.ts
802
889
  var WORKSPACE_SOURCES = ["api", "dashboard", "slack", "linear", "github", "gitlab", "automation", "mothership"];
803
890
  var CLIENT_MESSAGE_SOURCES = ["web", "desktop", "mobile", "tui"];
@@ -3911,6 +3998,15 @@ function removeReplicasInstructions(text) {
3911
3998
  return removeTag(text, REPLICAS_INSTRUCTIONS_TAG);
3912
3999
  }
3913
4000
 
4001
+ // ../shared/src/user-message-matching.ts
4002
+ function parseTimestampMs(timestamp) {
4003
+ const value = typeof timestamp === "number" ? timestamp : Date.parse(timestamp);
4004
+ return Number.isFinite(value) ? value : 0;
4005
+ }
4006
+ function areUserMessagesWithinMatchWindow(a, b) {
4007
+ return a.content === b.content && Math.abs(parseTimestampMs(a.timestamp) - parseTimestampMs(b.timestamp)) <= USER_MESSAGE_MATCH_GRACE_PERIOD_MS;
4008
+ }
4009
+
3914
4010
  // ../shared/src/display-message/parsers/codex-asp-parser.ts
3915
4011
  function collectCodexTurns(events) {
3916
4012
  const turns = /* @__PURE__ */ new Map();
@@ -4178,6 +4274,25 @@ function parsePatch(input) {
4178
4274
  }
4179
4275
  return operations;
4180
4276
  }
4277
+ function takeRecordedPrompt(prompts, echo, turnIndex) {
4278
+ const timestampMs = parseTimestampMs(echo.timestamp);
4279
+ let closestIndex = -1;
4280
+ let closestDistance = Infinity;
4281
+ for (let i = prompts.length - 1; i >= 0; i--) {
4282
+ const candidate = prompts[i];
4283
+ const distance = Math.abs(candidate.timestampMs - timestampMs);
4284
+ if (distance > closestDistance) continue;
4285
+ if (candidate.index >= turnIndex && !areUserMessagesWithinMatchWindow(
4286
+ { content: candidate.message.content, timestamp: candidate.timestampMs },
4287
+ { content: echo.content, timestamp: timestampMs }
4288
+ )) continue;
4289
+ const images = candidate.message.images;
4290
+ if (images && echo.images && (images.length !== echo.images.length || images.some((image, index) => image.mediaType !== echo.images?.[index].mediaType || image.data !== echo.images?.[index].data))) continue;
4291
+ closestIndex = i;
4292
+ closestDistance = distance;
4293
+ }
4294
+ return closestIndex === -1 ? void 0 : prompts.splice(closestIndex, 1)[0].message;
4295
+ }
4181
4296
  function parseCodexEvents(events) {
4182
4297
  const messages = [];
4183
4298
  const turns = collectCodexTurns(events);
@@ -4361,26 +4476,35 @@ function parseCodexEvents(events) {
4361
4476
  }
4362
4477
  }
4363
4478
  });
4479
+ const recordedPrompts = /* @__PURE__ */ new Map();
4480
+ messages.forEach((message, index) => {
4481
+ if (message.type !== "user") return;
4482
+ const prompts = recordedPrompts.get(message.content) ?? [];
4483
+ prompts.push({ message, index, timestampMs: parseTimestampMs(message.timestamp) });
4484
+ recordedPrompts.set(message.content, prompts);
4485
+ });
4364
4486
  const claimedPrompts = /* @__PURE__ */ new Set();
4365
4487
  for (const { index, turnId } of turnInsertions.reverse()) {
4366
4488
  const turn = turns.get(turnId);
4367
4489
  if (!turn) continue;
4368
4490
  const kept = [];
4369
4491
  for (const message of messagesForCodexTurn(turn)) {
4370
- const recordedIndex = message.type === "user" ? messages.findLastIndex((candidate, candidateIndex) => candidateIndex < index && candidate.type === "user" && candidate.content === message.content && !claimedPrompts.has(candidateIndex)) : -1;
4371
- if (recordedIndex === -1) {
4492
+ if (message.type !== "user") {
4372
4493
  kept.push(message);
4373
4494
  continue;
4374
4495
  }
4375
- claimedPrompts.add(recordedIndex);
4376
- const recorded = messages[recordedIndex];
4377
- if (recorded.type === "user" && message.type === "user" && !recorded.images && message.images) {
4378
- messages[recordedIndex] = { ...recorded, images: message.images };
4496
+ const prompts = recordedPrompts.get(message.content);
4497
+ const recorded = prompts && takeRecordedPrompt(prompts, message, index);
4498
+ if (!recorded) {
4499
+ kept.push(message);
4500
+ continue;
4379
4501
  }
4502
+ claimedPrompts.add(recorded);
4503
+ kept.push({ ...recorded, images: recorded.images ?? message.images });
4380
4504
  }
4381
4505
  messages.splice(index, 0, ...kept);
4382
4506
  }
4383
- return messages;
4507
+ return messages.filter((message) => !claimedPrompts.has(message));
4384
4508
  }
4385
4509
 
4386
4510
  // ../shared/src/display-message/parsers/cursor-parser.ts
@@ -5397,15 +5521,6 @@ function parseMcpToolName(name) {
5397
5521
  return { server, tool };
5398
5522
  }
5399
5523
 
5400
- // ../shared/src/user-message-matching.ts
5401
- function parseTimestampMs(timestamp) {
5402
- const value = Date.parse(timestamp);
5403
- return Number.isFinite(value) ? value : 0;
5404
- }
5405
- function areUserMessagesWithinMatchWindow(a, b) {
5406
- return a.content === b.content && Math.abs(parseTimestampMs(a.timestamp) - parseTimestampMs(b.timestamp)) <= USER_MESSAGE_MATCH_GRACE_PERIOD_MS;
5407
- }
5408
-
5409
5524
  // ../shared/src/display-message/parsers/claude-parser.ts
5410
5525
  var ABORTED_TERMINAL_REASONS = /* @__PURE__ */ new Set(["aborted_streaming", "aborted_tools"]);
5411
5526
  function createSubagentMessage(messageIndex, timestamp, fields) {
@@ -6948,6 +7063,8 @@ function hasChatStarted(chat) {
6948
7063
 
6949
7064
  // ../shared/src/routes/codex.ts
6950
7065
  var CODEX_AUTH_ENV_KEYS = [
7066
+ "REPLICAS_CODEX_OLLAMA_API_KEY",
7067
+ "REPLICAS_CODEX_OLLAMA_BASE_URL",
6951
7068
  "OPENAI_API_KEY",
6952
7069
  "CODEX_OPENAI_BASE_URL",
6953
7070
  "CODEX_OPENAI_MODELS_URL",
@@ -6968,6 +7085,12 @@ function codexOpenAICompatibleAuthEnv(response) {
6968
7085
  }
6969
7086
  function codexAuthEnvFromResponse(response) {
6970
7087
  switch (response.type) {
7088
+ case "ollama":
7089
+ return {
7090
+ ...codexOpenAICompatibleAuthEnv({ apiKey: response.apiKey, baseUrl: `${response.baseUrl}/v1` }),
7091
+ ...ollamaAuthEnv("codex", response),
7092
+ REPLICAS_CODEX_AUTH_METHOD: "ollama"
7093
+ };
6971
7094
  case "oauth":
6972
7095
  return { REPLICAS_CODEX_AUTH_METHOD: "oauth" };
6973
7096
  case "api_key":
@@ -7003,6 +7126,7 @@ var CODEX_AUTH_ENV_KEYS_BY_METHOD = {
7003
7126
  "CODEX_OPENAI_AUTHORIZATION_HEADER",
7004
7127
  "REPLICAS_CODEX_AUTH_METHOD"
7005
7128
  ],
7129
+ ollama: ["OPENAI_API_KEY", "CODEX_OPENAI_BASE_URL", "REPLICAS_CODEX_AUTH_METHOD", "REPLICAS_CODEX_OLLAMA_API_KEY", "REPLICAS_CODEX_OLLAMA_BASE_URL"],
7006
7130
  bedrock: [],
7007
7131
  foundry: ["AZURE_OPENAI_API_KEY", "CODEX_FOUNDRY_BASE_URL", "CODEX_FOUNDRY_MODEL", "REPLICAS_CODEX_AUTH_METHOD"]
7008
7132
  };
@@ -7010,6 +7134,8 @@ var CODEX_AUTH_ENV_KEYS_BY_METHOD = {
7010
7134
  // ../shared/src/routes/claude.ts
7011
7135
  var CLAUDE_AUTH_ENV_KEYS = [
7012
7136
  "ANTHROPIC_API_KEY",
7137
+ "ANTHROPIC_AUTH_TOKEN",
7138
+ "ANTHROPIC_BASE_URL",
7013
7139
  "CLAUDE_CODE_USE_BEDROCK",
7014
7140
  "AWS_ACCESS_KEY_ID",
7015
7141
  "AWS_SECRET_ACCESS_KEY",
@@ -7025,6 +7151,13 @@ var CLAUDE_AUTH_ENV_KEYS = [
7025
7151
  ];
7026
7152
  function claudeAuthEnvFromResponse(response) {
7027
7153
  switch (response.type) {
7154
+ case "ollama":
7155
+ return {
7156
+ ANTHROPIC_API_KEY: "",
7157
+ ANTHROPIC_AUTH_TOKEN: response.apiKey,
7158
+ ANTHROPIC_BASE_URL: response.baseUrl,
7159
+ REPLICAS_CLAUDE_AUTH_METHOD: "ollama"
7160
+ };
7028
7161
  case "oauth":
7029
7162
  return { REPLICAS_CLAUDE_AUTH_METHOD: "oauth" };
7030
7163
  case "api_key":
@@ -7055,6 +7188,7 @@ var CLAUDE_AUTH_ENV_KEYS_BY_METHOD = {
7055
7188
  oauth: ["REPLICAS_CLAUDE_AUTH_METHOD"],
7056
7189
  api_key: ["ANTHROPIC_API_KEY", "REPLICAS_CLAUDE_AUTH_METHOD"],
7057
7190
  "openai-compatible": [],
7191
+ ollama: ["ANTHROPIC_API_KEY", "ANTHROPIC_AUTH_TOKEN", "ANTHROPIC_BASE_URL", "REPLICAS_CLAUDE_AUTH_METHOD"],
7058
7192
  bedrock: [
7059
7193
  "CLAUDE_CODE_USE_BEDROCK",
7060
7194
  "AWS_ACCESS_KEY_ID",
@@ -7926,10 +8060,15 @@ export {
7926
8060
  codexReasoningEffortForThinkingLevel,
7927
8061
  getProviderDisplayName,
7928
8062
  detectAgentQuotaLimit,
7929
- CREDENTIAL_METHOD,
7930
- AGENT_CREDENTIAL_METHODS_IN_ORDER,
7931
8063
  listOpenAICompatibleModels,
7932
8064
  resolveOpenAICompatibleModelsUrl,
8065
+ OLLAMA_AGENTS,
8066
+ readOllamaAuthEnv,
8067
+ DEFAULT_OLLAMA_MODEL,
8068
+ getDefaultOllamaModel,
8069
+ listOllamaModels,
8070
+ CREDENTIAL_METHOD,
8071
+ AGENT_CREDENTIAL_METHODS_IN_ORDER,
7933
8072
  agentCredentialSnapshotSchema,
7934
8073
  isAgentChatTurnActivityRecord,
7935
8074
  isAgentChatSkillActivityRecord,
@@ -8041,13 +8180,13 @@ export {
8041
8180
  MEMORY_ROOT,
8042
8181
  MEMORY_INDEX_FILENAME,
8043
8182
  MEMORY_MARKER_GUIDANCE,
8183
+ areUserMessagesWithinMatchWindow,
8044
8184
  extractErrorText,
8045
8185
  isTransientErrorText,
8046
8186
  extractToolResultText,
8047
8187
  normalizeContentBlocks,
8048
8188
  TaskAccumulator,
8049
8189
  parseMcpToolName,
8050
- areUserMessagesWithinMatchWindow,
8051
8190
  coerceClaudeResultPayload,
8052
8191
  stripAgentDiagnosticErrors,
8053
8192
  isClaudeResultError,
@@ -4,7 +4,7 @@ const require = __createRequire(import.meta.url);
4
4
  import {
5
5
  HOOK_EXEC_MAX_BUFFER_BYTES,
6
6
  isVersionBelow
7
- } from "./chunk-OJTGCTIK.js";
7
+ } from "./chunk-NTUXPZOE.js";
8
8
 
9
9
  // src/utils/codex-agent-env.ts
10
10
  function buildCodexAgentEnv(source = process.env) {
@@ -241,7 +241,11 @@ var DEFAULT_CODEX_ARGS = [
241
241
  var MIN_CODEX_CLI_VERSION = "0.153.3";
242
242
  var CODEX_UPGRADE_TIMEOUT_MS = 12e4;
243
243
  var codexCliVersionEnsured = null;
244
- var ENGINE_PACKAGE_VERSION = "0.1.875";
244
+ function getCodexModelProvider(method) {
245
+ if (method === "foundry") return "azure";
246
+ return method === "ollama" || method === "openai-compatible" ? "replicas_openai_compatible" : "openai";
247
+ }
248
+ var ENGINE_PACKAGE_VERSION = "0.1.877";
245
249
  var INITIALIZE_METHOD = "initialize";
246
250
  var INITIALIZED_NOTIFICATION = "initialized";
247
251
  var ACCOUNT_LOGIN_START_METHOD = "account/login/start";
@@ -266,7 +270,7 @@ var AppServerProcess = class {
266
270
  "-c",
267
271
  `model=${JSON.stringify(options.env.CODEX_FOUNDRY_MODEL)}`,
268
272
  "-c",
269
- 'model_provider="azure"',
273
+ `model_provider=${JSON.stringify(getCodexModelProvider(options.env.REPLICAS_CODEX_AUTH_METHOD))}`,
270
274
  "-c",
271
275
  'model_providers.azure.name="Azure OpenAI"',
272
276
  "-c",
@@ -276,11 +280,15 @@ var AppServerProcess = class {
276
280
  "-c",
277
281
  'model_providers.azure.wire_api="responses"'
278
282
  ];
279
- } else if (!options.args && options.env.REPLICAS_CODEX_AUTH_METHOD === "openai-compatible") {
283
+ } else if (!options.args && (options.env.REPLICAS_CODEX_AUTH_METHOD === "openai-compatible" || options.env.REPLICAS_CODEX_AUTH_METHOD === "ollama")) {
280
284
  baseArgs = [
281
285
  ...DEFAULT_CODEX_ARGS,
286
+ ...options.env.REPLICAS_CODEX_AUTH_METHOD === "ollama" ? [
287
+ "-c",
288
+ 'web_search="disabled"'
289
+ ] : [],
282
290
  "-c",
283
- 'model_provider="replicas_openai_compatible"',
291
+ `model_provider=${JSON.stringify(getCodexModelProvider(options.env.REPLICAS_CODEX_AUTH_METHOD))}`,
284
292
  "-c",
285
293
  'model_providers.replicas_openai_compatible.name="OpenAI Compatible"',
286
294
  "-c",
@@ -480,5 +488,6 @@ export {
480
488
  execAsync,
481
489
  execFileAsync,
482
490
  SUBPROCESS_MAX_BUFFER,
491
+ getCodexModelProvider,
483
492
  AppServerProcess
484
493
  };
@@ -3,12 +3,12 @@ import { createRequire as __createRequire } from 'node:module';
3
3
  const require = __createRequire(import.meta.url);
4
4
  import {
5
5
  evaluateCommandProtection
6
- } from "./chunk-M4NXJJHV.js";
7
- import "./chunk-CZLOYOGI.js";
6
+ } from "./chunk-DOC4BA3P.js";
7
+ import "./chunk-MOJN6DR4.js";
8
8
  import {
9
9
  isRecord
10
10
  } from "./chunk-UZSNFLDQ.js";
11
- import "./chunk-OJTGCTIK.js";
11
+ import "./chunk-NTUXPZOE.js";
12
12
  import "./chunk-VEQXQN22.js";
13
13
 
14
14
  // src/command-protection-hook.ts
@@ -3,13 +3,13 @@ import { createRequire as __createRequire } from 'node:module';
3
3
  const require = __createRequire(import.meta.url);
4
4
  import {
5
5
  evaluateCommandProtection
6
- } from "./chunk-M4NXJJHV.js";
6
+ } from "./chunk-DOC4BA3P.js";
7
7
  import {
8
8
  notifyPostToolUse
9
- } from "./chunk-2QTX7QUN.js";
10
- import "./chunk-CZLOYOGI.js";
9
+ } from "./chunk-37NX5RE5.js";
10
+ import "./chunk-MOJN6DR4.js";
11
11
  import "./chunk-UZSNFLDQ.js";
12
- import "./chunk-OJTGCTIK.js";
12
+ import "./chunk-NTUXPZOE.js";
13
13
  import "./chunk-VEQXQN22.js";
14
14
 
15
15
  // src/deepseek-command-protection-plugin.ts
@@ -8,12 +8,12 @@ import {
8
8
  import {
9
9
  AppServerProcess,
10
10
  buildCodexAgentEnv
11
- } from "./chunk-YZJKOKGE.js";
11
+ } from "./chunk-VJQGQEZV.js";
12
12
  import {
13
13
  AGENT,
14
14
  getMemoryOutputSafetyViolation,
15
15
  headlessAgentRequestSchema
16
- } from "./chunk-OJTGCTIK.js";
16
+ } from "./chunk-NTUXPZOE.js";
17
17
  import "./chunk-VEQXQN22.js";
18
18
 
19
19
  // src/headless-agent.ts