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 +29 -0
- package/dist/agents/types.d.ts +1 -0
- package/dist/background/manager.d.ts +1 -1
- package/dist/config/schema.d.ts +52 -1
- package/dist/hooks/todo-enforcer/index.d.ts +1 -2
- package/dist/index.js +145 -33
- package/dist/shared/agent-variant.d.ts +19 -0
- package/dist/shared/first-message-variant.d.ts +34 -0
- package/dist/shared/index.d.ts +5 -0
- package/package.json +3 -1
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
|
package/dist/agents/types.d.ts
CHANGED
|
@@ -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>;
|
package/dist/config/schema.d.ts
CHANGED
|
@@ -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
|
-
*
|
|
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
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
|
|
4981
|
-
|
|
4982
|
-
|
|
4983
|
-
|
|
4984
|
-
|
|
4985
|
-
|
|
4986
|
-
|
|
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
|
-
|
|
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
|
-
|
|
17879
|
-
|
|
17880
|
-
|
|
17881
|
-
|
|
17882
|
-
|
|
17883
|
-
|
|
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
|
-
}
|
|
17886
|
-
|
|
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
|
-
|
|
18256
|
-
|
|
18257
|
-
|
|
18258
|
-
|
|
18259
|
-
|
|
18260
|
-
|
|
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 {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "zenox",
|
|
3
|
-
"version": "1.
|
|
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"
|