zenox 1.3.0 → 1.4.1

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/README.md CHANGED
@@ -21,6 +21,7 @@ Zenox supercharges [OpenCode](https://opencode.ai) with specialized AI agents th
21
21
 
22
22
  - **4 Specialized Agents** — Explorer, Librarian, Oracle, UI Planner
23
23
  - **Background Tasks** — Fire multiple agents in parallel
24
+ - **Thinking Mode Variants** — Configure thinking levels (high, xhigh, max) per agent
24
25
  - **Keyword Triggers** — `ultrawork`, `deep research`, `explore codebase`
25
26
  - **Session History** — Query past sessions to learn from previous work
26
27
  - **Code Intelligence** — Search symbols via LSP
@@ -185,6 +186,34 @@ Config saves to `~/.config/opencode/zenox.json`:
185
186
  }
186
187
  ```
187
188
 
189
+ ### Thinking Mode Variants
190
+
191
+ Configure thinking/reasoning levels for models that support extended thinking (like Claude, GPT with reasoning, etc.):
192
+
193
+ ```json
194
+ {
195
+ "agents": {
196
+ "oracle": {
197
+ "model": "anthropic/claude-opus-4-5",
198
+ "variant": "high"
199
+ },
200
+ "ui-planner": {
201
+ "model": "openai/gpt-5.2-codex",
202
+ "variant": "xhigh"
203
+ }
204
+ }
205
+ }
206
+ ```
207
+
208
+ Available variants (model-dependent):
209
+ - `low` — Minimal thinking
210
+ - `medium` — Balanced thinking
211
+ - `high` — Extended thinking
212
+ - `xhigh` — Extra high thinking
213
+ - `max` — Maximum reasoning depth
214
+
215
+ Variants are applied safely — if an agent doesn't exist or the model doesn't support the variant, it gracefully falls back.
216
+
188
217
  ### Disable Agents or MCPs
189
218
 
190
219
  ```json
@@ -3,5 +3,6 @@ export type AgentFactory = (model?: string) => AgentConfig;
3
3
  export type BuiltinAgentName = "explorer" | "librarian" | "oracle" | "ui-planner";
4
4
  export type AgentOverrideConfig = Partial<AgentConfig> & {
5
5
  prompt_append?: string;
6
+ variant?: string;
6
7
  };
7
8
  export type AgentOverrides = Partial<Record<BuiltinAgentName, AgentOverrideConfig>>;
@@ -15,7 +15,7 @@ export declare class BackgroundManager {
15
15
  private mainSessionID;
16
16
  private toastManager;
17
17
  setToastManager(manager: TaskToastManager): void;
18
- setMainSession(sessionID: string): void;
18
+ setMainSession(sessionID: string | undefined): void;
19
19
  getMainSession(): string | undefined;
20
20
  private generateTaskId;
21
21
  launch(client: OpencodeClient, input: LaunchInput): Promise<BackgroundTask>;
@@ -6,14 +6,17 @@ export declare const AgentNameSchema: z.ZodEnum<["explorer", "librarian", "oracl
6
6
  export type AgentName = z.infer<typeof AgentNameSchema>;
7
7
  /**
8
8
  * Configuration for overriding an agent's settings
9
- * Only model override is supported - keeps it simple
9
+ * Supports model and variant overrides for thinking modes
10
10
  */
11
11
  export declare const AgentOverrideConfigSchema: z.ZodObject<{
12
12
  model: z.ZodOptional<z.ZodString>;
13
+ variant: z.ZodOptional<z.ZodString>;
13
14
  }, "strip", z.ZodTypeAny, {
14
15
  model?: string | undefined;
16
+ variant?: string | undefined;
15
17
  }, {
16
18
  model?: string | undefined;
19
+ variant?: string | undefined;
17
20
  }>;
18
21
  export type AgentOverrideConfig = z.infer<typeof AgentOverrideConfigSchema>;
19
22
  /**
@@ -22,57 +25,77 @@ export type AgentOverrideConfig = z.infer<typeof AgentOverrideConfigSchema>;
22
25
  export declare const AgentOverridesSchema: z.ZodObject<{
23
26
  explorer: z.ZodOptional<z.ZodObject<{
24
27
  model: z.ZodOptional<z.ZodString>;
28
+ variant: z.ZodOptional<z.ZodString>;
25
29
  }, "strip", z.ZodTypeAny, {
26
30
  model?: string | undefined;
31
+ variant?: string | undefined;
27
32
  }, {
28
33
  model?: string | undefined;
34
+ variant?: string | undefined;
29
35
  }>>;
30
36
  librarian: z.ZodOptional<z.ZodObject<{
31
37
  model: z.ZodOptional<z.ZodString>;
38
+ variant: z.ZodOptional<z.ZodString>;
32
39
  }, "strip", z.ZodTypeAny, {
33
40
  model?: string | undefined;
41
+ variant?: string | undefined;
34
42
  }, {
35
43
  model?: string | undefined;
44
+ variant?: string | undefined;
36
45
  }>>;
37
46
  oracle: z.ZodOptional<z.ZodObject<{
38
47
  model: z.ZodOptional<z.ZodString>;
48
+ variant: z.ZodOptional<z.ZodString>;
39
49
  }, "strip", z.ZodTypeAny, {
40
50
  model?: string | undefined;
51
+ variant?: string | undefined;
41
52
  }, {
42
53
  model?: string | undefined;
54
+ variant?: string | undefined;
43
55
  }>>;
44
56
  "ui-planner": z.ZodOptional<z.ZodObject<{
45
57
  model: z.ZodOptional<z.ZodString>;
58
+ variant: z.ZodOptional<z.ZodString>;
46
59
  }, "strip", z.ZodTypeAny, {
47
60
  model?: string | undefined;
61
+ variant?: string | undefined;
48
62
  }, {
49
63
  model?: string | undefined;
64
+ variant?: string | undefined;
50
65
  }>>;
51
66
  }, "strip", z.ZodTypeAny, {
52
67
  explorer?: {
53
68
  model?: string | undefined;
69
+ variant?: string | undefined;
54
70
  } | undefined;
55
71
  librarian?: {
56
72
  model?: string | undefined;
73
+ variant?: string | undefined;
57
74
  } | undefined;
58
75
  oracle?: {
59
76
  model?: string | undefined;
77
+ variant?: string | undefined;
60
78
  } | undefined;
61
79
  "ui-planner"?: {
62
80
  model?: string | undefined;
81
+ variant?: string | undefined;
63
82
  } | undefined;
64
83
  }, {
65
84
  explorer?: {
66
85
  model?: string | undefined;
86
+ variant?: string | undefined;
67
87
  } | undefined;
68
88
  librarian?: {
69
89
  model?: string | undefined;
90
+ variant?: string | undefined;
70
91
  } | undefined;
71
92
  oracle?: {
72
93
  model?: string | undefined;
94
+ variant?: string | undefined;
73
95
  } | undefined;
74
96
  "ui-planner"?: {
75
97
  model?: string | undefined;
98
+ variant?: string | undefined;
76
99
  } | undefined;
77
100
  }>;
78
101
  export type AgentOverrides = z.infer<typeof AgentOverridesSchema>;
@@ -84,57 +107,77 @@ export declare const ZenoxConfigSchema: z.ZodObject<{
84
107
  agents: z.ZodOptional<z.ZodObject<{
85
108
  explorer: z.ZodOptional<z.ZodObject<{
86
109
  model: z.ZodOptional<z.ZodString>;
110
+ variant: z.ZodOptional<z.ZodString>;
87
111
  }, "strip", z.ZodTypeAny, {
88
112
  model?: string | undefined;
113
+ variant?: string | undefined;
89
114
  }, {
90
115
  model?: string | undefined;
116
+ variant?: string | undefined;
91
117
  }>>;
92
118
  librarian: z.ZodOptional<z.ZodObject<{
93
119
  model: z.ZodOptional<z.ZodString>;
120
+ variant: z.ZodOptional<z.ZodString>;
94
121
  }, "strip", z.ZodTypeAny, {
95
122
  model?: string | undefined;
123
+ variant?: string | undefined;
96
124
  }, {
97
125
  model?: string | undefined;
126
+ variant?: string | undefined;
98
127
  }>>;
99
128
  oracle: z.ZodOptional<z.ZodObject<{
100
129
  model: z.ZodOptional<z.ZodString>;
130
+ variant: z.ZodOptional<z.ZodString>;
101
131
  }, "strip", z.ZodTypeAny, {
102
132
  model?: string | undefined;
133
+ variant?: string | undefined;
103
134
  }, {
104
135
  model?: string | undefined;
136
+ variant?: string | undefined;
105
137
  }>>;
106
138
  "ui-planner": z.ZodOptional<z.ZodObject<{
107
139
  model: z.ZodOptional<z.ZodString>;
140
+ variant: z.ZodOptional<z.ZodString>;
108
141
  }, "strip", z.ZodTypeAny, {
109
142
  model?: string | undefined;
143
+ variant?: string | undefined;
110
144
  }, {
111
145
  model?: string | undefined;
146
+ variant?: string | undefined;
112
147
  }>>;
113
148
  }, "strip", z.ZodTypeAny, {
114
149
  explorer?: {
115
150
  model?: string | undefined;
151
+ variant?: string | undefined;
116
152
  } | undefined;
117
153
  librarian?: {
118
154
  model?: string | undefined;
155
+ variant?: string | undefined;
119
156
  } | undefined;
120
157
  oracle?: {
121
158
  model?: string | undefined;
159
+ variant?: string | undefined;
122
160
  } | undefined;
123
161
  "ui-planner"?: {
124
162
  model?: string | undefined;
163
+ variant?: string | undefined;
125
164
  } | undefined;
126
165
  }, {
127
166
  explorer?: {
128
167
  model?: string | undefined;
168
+ variant?: string | undefined;
129
169
  } | undefined;
130
170
  librarian?: {
131
171
  model?: string | undefined;
172
+ variant?: string | undefined;
132
173
  } | undefined;
133
174
  oracle?: {
134
175
  model?: string | undefined;
176
+ variant?: string | undefined;
135
177
  } | undefined;
136
178
  "ui-planner"?: {
137
179
  model?: string | undefined;
180
+ variant?: string | undefined;
138
181
  } | undefined;
139
182
  }>>;
140
183
  disabled_agents: z.ZodOptional<z.ZodArray<z.ZodEnum<["explorer", "librarian", "oracle", "ui-planner"]>, "many">>;
@@ -144,15 +187,19 @@ export declare const ZenoxConfigSchema: z.ZodObject<{
144
187
  agents?: {
145
188
  explorer?: {
146
189
  model?: string | undefined;
190
+ variant?: string | undefined;
147
191
  } | undefined;
148
192
  librarian?: {
149
193
  model?: string | undefined;
194
+ variant?: string | undefined;
150
195
  } | undefined;
151
196
  oracle?: {
152
197
  model?: string | undefined;
198
+ variant?: string | undefined;
153
199
  } | undefined;
154
200
  "ui-planner"?: {
155
201
  model?: string | undefined;
202
+ variant?: string | undefined;
156
203
  } | undefined;
157
204
  } | undefined;
158
205
  disabled_agents?: ("explorer" | "librarian" | "oracle" | "ui-planner")[] | undefined;
@@ -162,15 +209,19 @@ export declare const ZenoxConfigSchema: z.ZodObject<{
162
209
  agents?: {
163
210
  explorer?: {
164
211
  model?: string | undefined;
212
+ variant?: string | undefined;
165
213
  } | undefined;
166
214
  librarian?: {
167
215
  model?: string | undefined;
216
+ variant?: string | undefined;
168
217
  } | undefined;
169
218
  oracle?: {
170
219
  model?: string | undefined;
220
+ variant?: string | undefined;
171
221
  } | undefined;
172
222
  "ui-planner"?: {
173
223
  model?: string | undefined;
224
+ variant?: string | undefined;
174
225
  } | undefined;
175
226
  } | undefined;
176
227
  disabled_agents?: ("explorer" | "librarian" | "oracle" | "ui-planner")[] | undefined;
@@ -9,8 +9,7 @@
9
9
  * - Skips child sessions (background tasks)
10
10
  * - Cooldown to prevent spam (10 seconds between reminders)
11
11
  * - Shows toast notification when enforcing
12
- *
13
- * Inspired by oh-my-opencode's todo-continuation-enforcer
12
+ * - Mode-aware: preserves Plan/Build agent context
14
13
  */
15
14
  import type { PluginInput } from "@opencode-ai/plugin";
16
15
  import type { Event } from "@opencode-ai/sdk";
package/dist/index.js CHANGED
@@ -4812,7 +4812,8 @@ var AgentNameSchema = exports_external.enum([
4812
4812
  "ui-planner"
4813
4813
  ]);
4814
4814
  var AgentOverrideConfigSchema = exports_external.object({
4815
- model: exports_external.string().optional()
4815
+ model: exports_external.string().optional(),
4816
+ variant: exports_external.string().optional()
4816
4817
  });
4817
4818
  var AgentOverridesSchema = exports_external.object({
4818
4819
  explorer: AgentOverrideConfigSchema.optional(),
@@ -4969,24 +4970,34 @@ class BackgroundManager {
4969
4970
  agent: task.agent
4970
4971
  }).catch(() => {});
4971
4972
  }
4972
- client.session.prompt({
4973
- path: { id: sessionID },
4974
- body: {
4975
- agent: input.agent,
4976
- tools: { task: false },
4977
- parts: [{ type: "text", text: input.prompt }]
4978
- }
4979
- }).catch((err) => {
4980
- const existingTask = this.tasks.get(task.id);
4981
- if (existingTask) {
4982
- existingTask.status = "failed";
4983
- existingTask.error = err.message ?? "Unknown error";
4984
- existingTask.completedAt = new Date;
4985
- if (this.toastManager) {
4986
- this.toastManager.showFailureToast(task.id, existingTask.error).catch(() => {});
4973
+ const sendPrompt = async (retryWithoutAgent = false) => {
4974
+ try {
4975
+ await client.session.prompt({
4976
+ path: { id: sessionID },
4977
+ body: {
4978
+ ...retryWithoutAgent ? {} : { agent: input.agent },
4979
+ tools: { task: false },
4980
+ parts: [{ type: "text", text: input.prompt }]
4981
+ }
4982
+ });
4983
+ } catch (err) {
4984
+ const errorMsg = err instanceof Error ? err.message : String(err);
4985
+ if (!retryWithoutAgent && (errorMsg.includes("agent.name") || errorMsg.includes("undefined is not an object"))) {
4986
+ console.warn(`[zenox] Agent "${input.agent}" not found. Retrying with default agent.`);
4987
+ return sendPrompt(true);
4988
+ }
4989
+ const existingTask = this.tasks.get(task.id);
4990
+ if (existingTask) {
4991
+ existingTask.status = "failed";
4992
+ existingTask.error = errorMsg;
4993
+ existingTask.completedAt = new Date;
4994
+ if (this.toastManager) {
4995
+ this.toastManager.showFailureToast(task.id, existingTask.error).catch(() => {});
4996
+ }
4987
4997
  }
4988
4998
  }
4989
- });
4999
+ };
5000
+ sendPrompt().catch(() => {});
4990
5001
  return task;
4991
5002
  }
4992
5003
  getTask(taskId) {
@@ -17788,6 +17799,7 @@ ${primaryKeyword.context}`;
17788
17799
  // src/hooks/todo-enforcer/index.ts
17789
17800
  var COOLDOWN_MS = 1e4;
17790
17801
  var TOAST_DURATION3 = 3000;
17802
+ var SKIP_AGENTS = ["plan"];
17791
17803
  var CONTINUATION_PROMPT = `[TODO CONTINUATION REMINDER]
17792
17804
 
17793
17805
  You have incomplete tasks in your todo list. Continue working on them.
@@ -17825,6 +17837,7 @@ function createTodoEnforcerHook(ctx) {
17825
17837
  if (now - state.lastEnforcedAt < COOLDOWN_MS) {
17826
17838
  return;
17827
17839
  }
17840
+ let agent;
17828
17841
  try {
17829
17842
  const sessionResult = await ctx.client.session.get({
17830
17843
  path: { id: sessionID }
@@ -17833,9 +17846,24 @@ function createTodoEnforcerHook(ctx) {
17833
17846
  if (session?.parentID) {
17834
17847
  return;
17835
17848
  }
17849
+ const msgs = await ctx.client.session.messages({
17850
+ path: { id: sessionID },
17851
+ query: { limit: 5 }
17852
+ });
17853
+ const messages = msgs.data ?? [];
17854
+ for (let i = messages.length - 1;i >= 0; i--) {
17855
+ const info = messages[i]?.info;
17856
+ if (info?.agent) {
17857
+ agent = info.agent;
17858
+ break;
17859
+ }
17860
+ }
17836
17861
  } catch {
17837
17862
  return;
17838
17863
  }
17864
+ if (agent && SKIP_AGENTS.includes(agent)) {
17865
+ return;
17866
+ }
17839
17867
  let todos = [];
17840
17868
  try {
17841
17869
  const todosResult = await ctx.client.session.todo({
@@ -17867,23 +17895,38 @@ Current incomplete tasks:
17867
17895
  ${todoList}
17868
17896
 
17869
17897
  ${statusLine}`;
17870
- try {
17898
+ const sendPrompt = async (omitAgent = false) => {
17871
17899
  await ctx.client.session.prompt({
17872
17900
  path: { id: sessionID },
17873
17901
  body: {
17874
17902
  noReply: false,
17903
+ ...omitAgent || !agent ? {} : { agent },
17875
17904
  parts: [{ type: "text", text: prompt }]
17876
17905
  }
17877
17906
  });
17878
- await ctx.client.tui.showToast({
17879
- body: {
17880
- title: "\uD83D\uDCCB Todo Reminder",
17881
- message: `${incomplete.length} task(s) remaining`,
17882
- variant: "info",
17883
- duration: TOAST_DURATION3
17907
+ };
17908
+ try {
17909
+ await sendPrompt();
17910
+ } catch (err) {
17911
+ const errorMsg = err instanceof Error ? err.message : String(err);
17912
+ if (errorMsg.includes("agent") || errorMsg.includes("undefined")) {
17913
+ try {
17914
+ await sendPrompt(true);
17915
+ } catch {
17916
+ return;
17884
17917
  }
17885
- }).catch(() => {});
17886
- } catch {}
17918
+ } else {
17919
+ return;
17920
+ }
17921
+ }
17922
+ await ctx.client.tui.showToast({
17923
+ body: {
17924
+ title: "\uD83D\uDCCB Todo Reminder",
17925
+ message: `${incomplete.length} task(s) remaining`,
17926
+ variant: "info",
17927
+ duration: TOAST_DURATION3
17928
+ }
17929
+ }).catch(() => {});
17887
17930
  if (sessionStates.size > 50) {
17888
17931
  cleanupOldStates();
17889
17932
  }
@@ -18203,6 +18246,45 @@ Shows which LSP servers are running and their status.`,
18203
18246
  lsp_status: lspStatus
18204
18247
  };
18205
18248
  }
18249
+ // src/shared/agent-variant.ts
18250
+ function resolveAgentVariant(config2, agentName) {
18251
+ if (!agentName)
18252
+ return;
18253
+ const agentOverrides = config2.agents;
18254
+ return agentOverrides?.[agentName]?.variant;
18255
+ }
18256
+ function applyAgentVariant(config2, agentName, message) {
18257
+ const variant = resolveAgentVariant(config2, agentName);
18258
+ if (variant !== undefined && message.variant === undefined) {
18259
+ message.variant = variant;
18260
+ }
18261
+ }
18262
+ // src/shared/first-message-variant.ts
18263
+ function createFirstMessageVariantGate() {
18264
+ const pending = new Set;
18265
+ return {
18266
+ markSessionCreated(info) {
18267
+ if (info?.id && !info.parentID) {
18268
+ pending.add(info.id);
18269
+ }
18270
+ },
18271
+ shouldOverride(sessionID) {
18272
+ if (!sessionID)
18273
+ return false;
18274
+ return pending.has(sessionID);
18275
+ },
18276
+ markApplied(sessionID) {
18277
+ if (!sessionID)
18278
+ return;
18279
+ pending.delete(sessionID);
18280
+ },
18281
+ clear(sessionID) {
18282
+ if (!sessionID)
18283
+ return;
18284
+ pending.delete(sessionID);
18285
+ }
18286
+ };
18287
+ }
18206
18288
  // src/index.ts
18207
18289
  var ZenoxPlugin = async (ctx) => {
18208
18290
  const pluginConfig = loadPluginConfig(ctx.directory);
@@ -18217,6 +18299,7 @@ var ZenoxPlugin = async (ctx) => {
18217
18299
  const todoEnforcerHook = createTodoEnforcerHook(ctx);
18218
18300
  const sessionTools = createSessionTools(ctx.client);
18219
18301
  const codeIntelligenceTools = createCodeIntelligenceTools(ctx.client);
18302
+ const firstMessageVariantGate = createFirstMessageVariantGate();
18220
18303
  const applyModelOverride = (agentName, baseAgent) => {
18221
18304
  const override = pluginConfig.agents?.[agentName];
18222
18305
  if (override?.model) {
@@ -18231,6 +18314,16 @@ var ZenoxPlugin = async (ctx) => {
18231
18314
  ...codeIntelligenceTools
18232
18315
  },
18233
18316
  "chat.message": async (input, output) => {
18317
+ const message = output.message;
18318
+ if (firstMessageVariantGate.shouldOverride(input.sessionID)) {
18319
+ const variant = resolveAgentVariant(pluginConfig, input.agent);
18320
+ if (variant !== undefined) {
18321
+ message.variant = variant;
18322
+ }
18323
+ firstMessageVariantGate.markApplied(input.sessionID);
18324
+ } else {
18325
+ applyAgentVariant(pluginConfig, input.agent, message);
18326
+ }
18234
18327
  await keywordDetectorHook["chat.message"]?.(input, output);
18235
18328
  },
18236
18329
  event: async (input) => {
@@ -18239,10 +18332,19 @@ var ZenoxPlugin = async (ctx) => {
18239
18332
  if (event.type === "session.created") {
18240
18333
  const props = event.properties;
18241
18334
  const sessionInfo = props?.info;
18335
+ firstMessageVariantGate.markSessionCreated(sessionInfo);
18242
18336
  if (sessionInfo?.id && !sessionInfo?.parentID) {
18243
18337
  backgroundManager.setMainSession(sessionInfo.id);
18244
18338
  }
18245
18339
  }
18340
+ if (event.type === "session.deleted") {
18341
+ const props = event.properties;
18342
+ const sessionID = props?.info?.id;
18343
+ firstMessageVariantGate.clear(sessionID);
18344
+ if (sessionID && sessionID === backgroundManager.getMainSession()) {
18345
+ backgroundManager.setMainSession(undefined);
18346
+ }
18347
+ }
18246
18348
  if (event.type === "session.idle") {
18247
18349
  const props = event.properties;
18248
18350
  const sessionID = props?.sessionID;
@@ -18252,14 +18354,24 @@ var ZenoxPlugin = async (ctx) => {
18252
18354
  if (notification) {
18253
18355
  const mainSessionID = backgroundManager.getMainSession();
18254
18356
  if (mainSessionID) {
18255
- await ctx.client.session.prompt({
18256
- path: { id: mainSessionID },
18257
- body: {
18258
- noReply: !notification.allComplete,
18259
- agent: notification.parentAgent,
18260
- parts: [{ type: "text", text: notification.message }]
18357
+ const sendNotification = async (omitAgent = false) => {
18358
+ try {
18359
+ await ctx.client.session.prompt({
18360
+ path: { id: mainSessionID },
18361
+ body: {
18362
+ noReply: !notification.allComplete,
18363
+ ...omitAgent ? {} : { agent: notification.parentAgent },
18364
+ parts: [{ type: "text", text: notification.message }]
18365
+ }
18366
+ });
18367
+ } catch (err) {
18368
+ const errorMsg = err instanceof Error ? err.message : String(err);
18369
+ if (!omitAgent && (errorMsg.includes("agent.name") || errorMsg.includes("undefined"))) {
18370
+ return sendNotification(true);
18371
+ }
18261
18372
  }
18262
- });
18373
+ };
18374
+ await sendNotification();
18263
18375
  }
18264
18376
  return;
18265
18377
  }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Agent Variant Handling
3
+ *
4
+ * Safely resolves and applies agent variants for thinking modes.
5
+ * Defensive implementation to prevent "undefined is not an object" errors.
6
+ */
7
+ import type { ZenoxConfig } from "../config";
8
+ /**
9
+ * Safely resolve agent variant from config
10
+ * Returns undefined if agent doesn't exist or has no variant configured
11
+ */
12
+ export declare function resolveAgentVariant(config: ZenoxConfig, agentName?: string): string | undefined;
13
+ /**
14
+ * Apply agent variant to message if configured
15
+ * Safe for undefined agents - simply does nothing
16
+ */
17
+ export declare function applyAgentVariant(config: ZenoxConfig, agentName: string | undefined, message: {
18
+ variant?: string;
19
+ }): void;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * First Message Variant Gate
3
+ *
4
+ * Tracks new sessions to apply variants only on the first message.
5
+ * Prevents variants from being applied to forked/child sessions.
6
+ */
7
+ type SessionInfo = {
8
+ id?: string;
9
+ parentID?: string;
10
+ };
11
+ /**
12
+ * Creates a gate that tracks which sessions need variant applied on first message
13
+ */
14
+ export declare function createFirstMessageVariantGate(): {
15
+ /**
16
+ * Mark a newly created session as pending variant application
17
+ * Only marks non-child sessions (no parentID)
18
+ */
19
+ markSessionCreated(info?: SessionInfo): void;
20
+ /**
21
+ * Check if this session should have variant overridden
22
+ */
23
+ shouldOverride(sessionID?: string): boolean;
24
+ /**
25
+ * Mark variant as applied for this session
26
+ */
27
+ markApplied(sessionID?: string): void;
28
+ /**
29
+ * Clear session from tracking (on session delete)
30
+ */
31
+ clear(sessionID?: string): void;
32
+ };
33
+ export type FirstMessageVariantGate = ReturnType<typeof createFirstMessageVariantGate>;
34
+ export {};
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Shared utilities for zenox plugin
3
+ */
4
+ export { resolveAgentVariant, applyAgentVariant } from "./agent-variant";
5
+ export { createFirstMessageVariantGate, type FirstMessageVariantGate, } from "./first-message-variant";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "zenox",
3
- "version": "1.3.0",
3
+ "version": "1.4.1",
4
4
  "description": "OpenCode plugin with specialized agents (explorer, librarian, oracle, ui-planner), background tasks for parallel execution, and smart orchestration",
5
5
  "author": "Ayush",
6
6
  "license": "MIT",
@@ -44,6 +44,8 @@
44
44
  "code-intelligence",
45
45
  "lsp",
46
46
  "todo-enforcer",
47
+ "thinking-modes",
48
+ "variants",
47
49
  "ai",
48
50
  "llm",
49
51
  "cli"