oh-my-opencode-slim 0.8.1 → 0.8.3

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/index.js CHANGED
@@ -3376,12 +3376,12 @@ var SUBAGENT_DELEGATION_RULES = {
3376
3376
  oracle: []
3377
3377
  };
3378
3378
  var DEFAULT_MODELS = {
3379
- orchestrator: "kimi-for-coding/k2p5",
3380
- oracle: "openai/gpt-5.2-codex",
3381
- librarian: "openai/gpt-5.1-codex-mini",
3382
- explorer: "openai/gpt-5.1-codex-mini",
3379
+ orchestrator: undefined,
3380
+ oracle: "openai/gpt-5.4",
3381
+ librarian: "openai/gpt-5-codex",
3382
+ explorer: "openai/gpt-5-codex",
3383
3383
  designer: "kimi-for-coding/k2p5",
3384
- fixer: "openai/gpt-5.1-codex-mini"
3384
+ fixer: "openai/gpt-5-codex"
3385
3385
  };
3386
3386
  var POLL_INTERVAL_BACKGROUND_MS = 2000;
3387
3387
  var DEFAULT_TIMEOUT_MS = 2 * 60 * 1000;
@@ -17014,7 +17014,16 @@ var FallbackChainsSchema = exports_external.object({
17014
17014
  fixer: AgentModelChainSchema.optional()
17015
17015
  }).catchall(AgentModelChainSchema);
17016
17016
  var AgentOverrideConfigSchema = exports_external.object({
17017
- model: exports_external.string().optional(),
17017
+ model: exports_external.union([
17018
+ exports_external.string(),
17019
+ exports_external.array(exports_external.union([
17020
+ exports_external.string(),
17021
+ exports_external.object({
17022
+ id: exports_external.string(),
17023
+ variant: exports_external.string().optional()
17024
+ })
17025
+ ]))
17026
+ ]).optional(),
17018
17027
  temperature: exports_external.number().min(0).max(2).optional(),
17019
17028
  variant: exports_external.string().optional().catch(undefined),
17020
17029
  skills: exports_external.array(exports_external.string()).optional(),
@@ -17138,25 +17147,27 @@ function loadPluginConfig(directory) {
17138
17147
  }
17139
17148
  return config2;
17140
17149
  }
17141
- function loadAgentPrompt(agentName) {
17150
+ function loadAgentPrompt(agentName, preset) {
17151
+ const presetDirName = preset && /^[a-zA-Z0-9_-]+$/.test(preset) ? preset : undefined;
17142
17152
  const promptsDir = path.join(getUserConfigDir(), "opencode", PROMPTS_DIR_NAME);
17153
+ const promptSearchDirs = presetDirName ? [path.join(promptsDir, presetDirName), promptsDir] : [promptsDir];
17143
17154
  const result = {};
17144
- const promptPath = path.join(promptsDir, `${agentName}.md`);
17145
- if (fs.existsSync(promptPath)) {
17146
- try {
17147
- result.prompt = fs.readFileSync(promptPath, "utf-8");
17148
- } catch (error48) {
17149
- console.warn(`[oh-my-opencode-slim] Error reading prompt file ${promptPath}:`, error48 instanceof Error ? error48.message : String(error48));
17150
- }
17151
- }
17152
- const appendPromptPath = path.join(promptsDir, `${agentName}_append.md`);
17153
- if (fs.existsSync(appendPromptPath)) {
17154
- try {
17155
- result.appendPrompt = fs.readFileSync(appendPromptPath, "utf-8");
17156
- } catch (error48) {
17157
- console.warn(`[oh-my-opencode-slim] Error reading append prompt file ${appendPromptPath}:`, error48 instanceof Error ? error48.message : String(error48));
17155
+ const readFirstPrompt = (fileName, errorPrefix) => {
17156
+ for (const dir of promptSearchDirs) {
17157
+ const promptPath = path.join(dir, fileName);
17158
+ if (!fs.existsSync(promptPath)) {
17159
+ continue;
17160
+ }
17161
+ try {
17162
+ return fs.readFileSync(promptPath, "utf-8");
17163
+ } catch (error48) {
17164
+ console.warn(`[oh-my-opencode-slim] ${errorPrefix} ${promptPath}:`, error48 instanceof Error ? error48.message : String(error48));
17165
+ }
17158
17166
  }
17159
- }
17167
+ return;
17168
+ };
17169
+ result.prompt = readFirstPrompt(`${agentName}.md`, "Error reading prompt file");
17170
+ result.appendPrompt = readFirstPrompt(`${agentName}_append.md`, "Error reading append prompt file");
17160
17171
  return result;
17161
17172
  }
17162
17173
  // src/config/utils.ts
@@ -17580,21 +17591,32 @@ function createOrchestratorAgent(model, customPrompt, customAppendPrompt) {
17580
17591
 
17581
17592
  ${customAppendPrompt}`;
17582
17593
  }
17583
- return {
17594
+ const definition = {
17584
17595
  name: "orchestrator",
17585
17596
  description: "AI coding orchestrator that delegates tasks to specialist agents for optimal quality, speed, and cost",
17586
17597
  config: {
17587
- model,
17588
17598
  temperature: 0.1,
17589
17599
  prompt
17590
17600
  }
17591
17601
  };
17602
+ if (Array.isArray(model)) {
17603
+ definition._modelArray = model.map((m) => typeof m === "string" ? { id: m } : m);
17604
+ } else if (typeof model === "string" && model) {
17605
+ definition.config.model = model;
17606
+ }
17607
+ return definition;
17592
17608
  }
17593
17609
 
17594
17610
  // src/agents/index.ts
17595
17611
  function applyOverrides(agent, override) {
17596
- if (override.model)
17597
- agent.config.model = override.model;
17612
+ if (override.model) {
17613
+ if (Array.isArray(override.model)) {
17614
+ agent._modelArray = override.model.map((m) => typeof m === "string" ? { id: m } : m);
17615
+ agent.config.model = undefined;
17616
+ } else {
17617
+ agent.config.model = override.model;
17618
+ }
17619
+ }
17598
17620
  if (override.variant)
17599
17621
  agent.config.variant = override.variant;
17600
17622
  if (override.temperature !== undefined)
@@ -17625,12 +17647,20 @@ var SUBAGENT_FACTORIES = {
17625
17647
  function createAgents(config2) {
17626
17648
  const getModelForAgent = (name) => {
17627
17649
  if (name === "fixer" && !getAgentOverride(config2, "fixer")?.model) {
17628
- return getAgentOverride(config2, "librarian")?.model ?? DEFAULT_MODELS.librarian;
17650
+ const librarianOverride = getAgentOverride(config2, "librarian")?.model;
17651
+ let librarianModel;
17652
+ if (Array.isArray(librarianOverride)) {
17653
+ const first = librarianOverride[0];
17654
+ librarianModel = typeof first === "string" ? first : first?.id;
17655
+ } else {
17656
+ librarianModel = librarianOverride;
17657
+ }
17658
+ return librarianModel ?? DEFAULT_MODELS.librarian;
17629
17659
  }
17630
17660
  return DEFAULT_MODELS[name];
17631
17661
  };
17632
17662
  const protoSubAgents = Object.entries(SUBAGENT_FACTORIES).map(([name, factory]) => {
17633
- const customPrompts = loadAgentPrompt(name);
17663
+ const customPrompts = loadAgentPrompt(name, config2?.preset);
17634
17664
  return factory(getModelForAgent(name), customPrompts.prompt, customPrompts.appendPrompt);
17635
17665
  });
17636
17666
  const allSubAgents = protoSubAgents.map((agent) => {
@@ -17641,13 +17671,13 @@ function createAgents(config2) {
17641
17671
  applyDefaultPermissions(agent, override?.skills);
17642
17672
  return agent;
17643
17673
  });
17644
- const orchestratorModel = getAgentOverride(config2, "orchestrator")?.model ?? DEFAULT_MODELS.orchestrator;
17645
- const orchestratorPrompts = loadAgentPrompt("orchestrator");
17674
+ const orchestratorOverride = getAgentOverride(config2, "orchestrator");
17675
+ const orchestratorModel = orchestratorOverride?.model ?? DEFAULT_MODELS.orchestrator;
17676
+ const orchestratorPrompts = loadAgentPrompt("orchestrator", config2?.preset);
17646
17677
  const orchestrator = createOrchestratorAgent(orchestratorModel, orchestratorPrompts.prompt, orchestratorPrompts.appendPrompt);
17647
- const oOverride = getAgentOverride(config2, "orchestrator");
17648
- applyDefaultPermissions(orchestrator, oOverride?.skills);
17649
- if (oOverride) {
17650
- applyOverrides(orchestrator, oOverride);
17678
+ applyDefaultPermissions(orchestrator, orchestratorOverride?.skills);
17679
+ if (orchestratorOverride) {
17680
+ applyOverrides(orchestrator, orchestratorOverride);
17651
17681
  }
17652
17682
  return [orchestrator, ...allSubAgents];
17653
17683
  }
@@ -17709,6 +17739,27 @@ function applyAgentVariant(variant, body) {
17709
17739
  }
17710
17740
  return { ...body, variant };
17711
17741
  }
17742
+ // src/utils/internal-initiator.ts
17743
+ var SLIM_INTERNAL_INITIATOR_MARKER = "<!-- SLIM_INTERNAL_INITIATOR -->";
17744
+ function isRecord(value) {
17745
+ return typeof value === "object" && value !== null;
17746
+ }
17747
+ function createInternalAgentTextPart(text) {
17748
+ return {
17749
+ type: "text",
17750
+ text: `${text}
17751
+ ${SLIM_INTERNAL_INITIATOR_MARKER}`
17752
+ };
17753
+ }
17754
+ function hasInternalInitiatorMarker(part) {
17755
+ if (!isRecord(part) || part.type !== "text") {
17756
+ return false;
17757
+ }
17758
+ if (typeof part.text !== "string") {
17759
+ return false;
17760
+ }
17761
+ return part.text.includes(SLIM_INTERNAL_INITIATOR_MARKER);
17762
+ }
17712
17763
  // src/utils/tmux.ts
17713
17764
  var {spawn } = globalThis.Bun;
17714
17765
  var tmuxPath = null;
@@ -18119,7 +18170,15 @@ class BackgroundTaskManager {
18119
18170
  const primary = this.config?.agents?.[agentName]?.model;
18120
18171
  const chain = [];
18121
18172
  const seen = new Set;
18122
- for (const model of [primary, ...configuredChain]) {
18173
+ let primaryIds;
18174
+ if (Array.isArray(primary)) {
18175
+ primaryIds = primary.map((m) => typeof m === "string" ? m : m.id);
18176
+ } else if (typeof primary === "string") {
18177
+ primaryIds = [primary];
18178
+ } else {
18179
+ primaryIds = [];
18180
+ }
18181
+ for (const model of [...primaryIds, ...configuredChain]) {
18123
18182
  if (!model || seen.has(model))
18124
18183
  continue;
18125
18184
  seen.add(model);
@@ -18341,7 +18400,7 @@ class BackgroundTaskManager {
18341
18400
  await this.client.session.prompt({
18342
18401
  path: { id: task.parentSessionId },
18343
18402
  body: {
18344
- parts: [{ type: "text", text: message }]
18403
+ parts: [createInternalAgentTextPart(message)]
18345
18404
  }
18346
18405
  });
18347
18406
  }
@@ -18580,8 +18639,6 @@ class TmuxSessionManager {
18580
18639
  // src/hooks/auto-update-checker/cache.ts
18581
18640
  import * as fs3 from "fs";
18582
18641
  import * as path4 from "path";
18583
- // src/cli/dynamic-model-selection.ts
18584
- var FREE_BIASED_PROVIDERS = new Set(["opencode"]);
18585
18642
  // src/hooks/auto-update-checker/constants.ts
18586
18643
  import * as os3 from "os";
18587
18644
  import * as path3 from "path";
@@ -18971,6 +19028,56 @@ function showToast(ctx, title, message, variant = "info", duration3 = 3000) {
18971
19028
  body: { title, message, variant, duration: duration3 }
18972
19029
  }).catch(() => {});
18973
19030
  }
19031
+ // src/hooks/chat-headers.ts
19032
+ var INTERNAL_MARKER_CACHE_LIMIT = 1000;
19033
+ var internalMarkerCache = new Map;
19034
+ function getProviderID(input) {
19035
+ return input.provider.info?.id || input.model.providerID;
19036
+ }
19037
+ function isCopilotProvider(providerID) {
19038
+ return providerID === "github-copilot" || providerID === "github-copilot-enterprise";
19039
+ }
19040
+ async function hasInternalMarker(client, sessionID, messageID) {
19041
+ const cacheKey = `${sessionID}:${messageID}`;
19042
+ const cached2 = internalMarkerCache.get(cacheKey);
19043
+ if (cached2 !== undefined) {
19044
+ return cached2;
19045
+ }
19046
+ try {
19047
+ const response = await client.session.message({
19048
+ path: { id: sessionID, messageID }
19049
+ });
19050
+ const hasMarker = (response.data?.parts ?? []).some(hasInternalInitiatorMarker);
19051
+ if (hasMarker) {
19052
+ if (internalMarkerCache.size >= INTERNAL_MARKER_CACHE_LIMIT) {
19053
+ internalMarkerCache.clear();
19054
+ }
19055
+ internalMarkerCache.set(cacheKey, true);
19056
+ }
19057
+ return hasMarker;
19058
+ } catch {
19059
+ return false;
19060
+ }
19061
+ }
19062
+ function createChatHeadersHook(ctx) {
19063
+ return {
19064
+ "chat.headers": async (input, output) => {
19065
+ if (!isCopilotProvider(getProviderID(input))) {
19066
+ return;
19067
+ }
19068
+ if (input.model.api.npm === "@ai-sdk/github-copilot") {
19069
+ return;
19070
+ }
19071
+ if (!input.message.id || input.message.role !== "user") {
19072
+ return;
19073
+ }
19074
+ if (!await hasInternalMarker(ctx.client, input.sessionID, input.message.id)) {
19075
+ return;
19076
+ }
19077
+ output.headers["x-initiator"] = "agent";
19078
+ }
19079
+ };
19080
+ }
18974
19081
  // src/hooks/delegate-task-retry/patterns.ts
18975
19082
  var DELEGATE_TASK_ERROR_PATTERNS = [
18976
19083
  {
@@ -19030,6 +19137,7 @@ function detectDelegateTaskError(output) {
19030
19137
  }
19031
19138
  return null;
19032
19139
  }
19140
+
19033
19141
  // src/hooks/delegate-task-retry/guidance.ts
19034
19142
  function extractAvailableList(output) {
19035
19143
  const match = output.match(/Allowed agents:\s*(.+)$/m);
@@ -19161,6 +19269,9 @@ function createPhaseReminderHook() {
19161
19269
  return;
19162
19270
  }
19163
19271
  const originalText = lastUserMessage.parts[textPartIndex].text ?? "";
19272
+ if (originalText.includes(SLIM_INTERNAL_INITIATOR_MARKER)) {
19273
+ return;
19274
+ }
19164
19275
  lastUserMessage.parts[textPartIndex].text = `${PHASE_REMINDER}
19165
19276
 
19166
19277
  ---
@@ -33415,7 +33526,14 @@ var lsp_rename = tool({
33415
33526
  // src/index.ts
33416
33527
  var OhMyOpenCodeLite = async (ctx) => {
33417
33528
  const config3 = loadPluginConfig(ctx.directory);
33529
+ const agentDefs = createAgents(config3);
33418
33530
  const agents = getAgentConfigs(config3);
33531
+ const modelArrayMap = {};
33532
+ for (const agentDef of agentDefs) {
33533
+ if (agentDef._modelArray && agentDef._modelArray.length > 0) {
33534
+ modelArrayMap[agentDef.name] = agentDef._modelArray;
33535
+ }
33536
+ }
33419
33537
  const tmuxConfig = {
33420
33538
  enabled: config3.tmux?.enabled ?? false,
33421
33539
  layout: config3.tmux?.layout ?? "main-vertical",
@@ -33439,6 +33557,7 @@ var OhMyOpenCodeLite = async (ctx) => {
33439
33557
  });
33440
33558
  const phaseReminderHook = createPhaseReminderHook();
33441
33559
  const postReadNudgeHook = createPostReadNudgeHook();
33560
+ const chatHeadersHook = createChatHeadersHook(ctx);
33442
33561
  const delegateTaskRetryHook = createDelegateTaskRetryHook(ctx);
33443
33562
  const jsonErrorRecoveryHook = createJsonErrorRecoveryHook(ctx);
33444
33563
  return {
@@ -33460,9 +33579,55 @@ var OhMyOpenCodeLite = async (ctx) => {
33460
33579
  if (!opencodeConfig.agent) {
33461
33580
  opencodeConfig.agent = { ...agents };
33462
33581
  } else {
33463
- Object.assign(opencodeConfig.agent, agents);
33582
+ for (const [name, pluginAgent] of Object.entries(agents)) {
33583
+ const existing = opencodeConfig.agent[name];
33584
+ if (existing) {
33585
+ opencodeConfig.agent[name] = {
33586
+ ...pluginAgent,
33587
+ ...existing
33588
+ };
33589
+ } else {
33590
+ opencodeConfig.agent[name] = {
33591
+ ...pluginAgent
33592
+ };
33593
+ }
33594
+ }
33464
33595
  }
33465
33596
  const configAgent = opencodeConfig.agent;
33597
+ if (Object.keys(modelArrayMap).length > 0) {
33598
+ const providerConfig = opencodeConfig.provider ?? {};
33599
+ const configuredProviders = Object.keys(providerConfig);
33600
+ for (const [agentName, modelArray] of Object.entries(modelArrayMap)) {
33601
+ let resolved = false;
33602
+ for (const modelEntry of modelArray) {
33603
+ const slashIdx = modelEntry.id.indexOf("/");
33604
+ if (slashIdx === -1)
33605
+ continue;
33606
+ const providerID = modelEntry.id.slice(0, slashIdx);
33607
+ if (configuredProviders.includes(providerID)) {
33608
+ const entry = configAgent[agentName];
33609
+ if (entry) {
33610
+ entry.model = modelEntry.id;
33611
+ if (modelEntry.variant) {
33612
+ entry.variant = modelEntry.variant;
33613
+ }
33614
+ }
33615
+ log("[plugin] resolved model fallback", {
33616
+ agent: agentName,
33617
+ model: modelEntry.id,
33618
+ variant: modelEntry.variant
33619
+ });
33620
+ resolved = true;
33621
+ break;
33622
+ }
33623
+ }
33624
+ if (!resolved) {
33625
+ log("[plugin] no provider match for model array", {
33626
+ agent: agentName
33627
+ });
33628
+ }
33629
+ }
33630
+ }
33466
33631
  const configMcp = opencodeConfig.mcp;
33467
33632
  if (!configMcp) {
33468
33633
  opencodeConfig.mcp = { ...mcps };
@@ -33499,6 +33664,7 @@ var OhMyOpenCodeLite = async (ctx) => {
33499
33664
  await backgroundManager.handleSessionDeleted(input.event);
33500
33665
  await tmuxSessionManager.onSessionDeleted(input.event);
33501
33666
  },
33667
+ "chat.headers": chatHeadersHook["chat.headers"],
33502
33668
  "experimental.chat.messages.transform": phaseReminderHook["experimental.chat.messages.transform"],
33503
33669
  "tool.execute.after": async (input, output) => {
33504
33670
  await delegateTaskRetryHook["tool.execute.after"](input, output);
@@ -1,5 +1,6 @@
1
1
  export * from './agent-variant';
2
2
  export * from './env';
3
+ export * from './internal-initiator';
3
4
  export { log } from './logger';
4
5
  export * from './polling';
5
6
  export * from './tmux';
@@ -0,0 +1,6 @@
1
+ export declare const SLIM_INTERNAL_INITIATOR_MARKER = "<!-- SLIM_INTERNAL_INITIATOR -->";
2
+ export declare function createInternalAgentTextPart(text: string): {
3
+ type: 'text';
4
+ text: string;
5
+ };
6
+ export declare function hasInternalInitiatorMarker(part: unknown): boolean;