mumucc 0.4.17 → 0.4.18
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mumucc",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.18",
|
|
4
4
|
"description": "Open-source AI coding assistant CLI with multi-model support (Anthropic, OpenAI/GPT, DeepSeek, GLM, Ollama, etc.), MCP integration, agent swarms, and out-of-the-box developer experience.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
package/shims/globals.ts
CHANGED
|
@@ -104,6 +104,51 @@ function buildProfileDescription(): string {
|
|
|
104
104
|
return `Optional profile override for this agent. Available profiles: ${profiles.map(profile => `'${profile.id}'`).join(', ')}.`
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
+
function getRecentUserMessagesText(
|
|
108
|
+
messages: MessageType[],
|
|
109
|
+
maxMessages = 4,
|
|
110
|
+
): string {
|
|
111
|
+
return messages
|
|
112
|
+
.filter((m): m is Extract<MessageType, { type: 'user' }> => m.type === 'user')
|
|
113
|
+
.slice(-maxMessages)
|
|
114
|
+
.map(m => {
|
|
115
|
+
const content = m.message.content
|
|
116
|
+
if (typeof content === 'string') {
|
|
117
|
+
return content
|
|
118
|
+
}
|
|
119
|
+
if (Array.isArray(content)) {
|
|
120
|
+
return extractTextContent(content, '\n')
|
|
121
|
+
}
|
|
122
|
+
return ''
|
|
123
|
+
})
|
|
124
|
+
.join('\n')
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function hasExplicitNoTeamRequest(text: string): boolean {
|
|
128
|
+
if (!text) return false
|
|
129
|
+
return (
|
|
130
|
+
/(不要|别|禁止|不允许|无需|不用).{0,8}(team|团队|swarm|teammate)/i.test(
|
|
131
|
+
text,
|
|
132
|
+
) ||
|
|
133
|
+
/(no|without)\s+(team|swarm)/i.test(text)
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
function hasExplicitTeamRequest(text: string): boolean {
|
|
138
|
+
if (!text) return false
|
|
139
|
+
return /(team|团队|swarm|teammate|团队模式|多代理编队|调度团队)/i.test(text)
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function hasExplicitNoBackgroundRequest(text: string): boolean {
|
|
143
|
+
if (!text) return false
|
|
144
|
+
return (
|
|
145
|
+
/(不要|别|禁止|不允许|无需|不用).{0,8}(挂后台|后台|异步|background)/i.test(
|
|
146
|
+
text,
|
|
147
|
+
) ||
|
|
148
|
+
/(no|without)\s+background/i.test(text)
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
|
|
107
152
|
// Base input schema without multi-agent parameters
|
|
108
153
|
const baseInputSchema = lazySchema(() => z.object({
|
|
109
154
|
description: z.string().describe('A short (3-5 word) description of the task'),
|
|
@@ -282,19 +327,34 @@ export const AgentTool = buildTool({
|
|
|
282
327
|
// Get app state for permission mode and agent filtering
|
|
283
328
|
const appState = toolUseContext.getAppState();
|
|
284
329
|
const permissionMode = appState.toolPermissionContext.mode;
|
|
330
|
+
const recentUserText = getRecentUserMessagesText(toolUseContext.messages);
|
|
331
|
+
const noTeamRequested = hasExplicitNoTeamRequest(recentUserText);
|
|
332
|
+
const teamRequested = hasExplicitTeamRequest(recentUserText);
|
|
333
|
+
const noBackgroundRequested = hasExplicitNoBackgroundRequest(recentUserText);
|
|
285
334
|
// In-process teammates get a no-op setAppState; setAppStateForTasks
|
|
286
335
|
// reaches the root store so task registration/progress/kill stay visible.
|
|
287
336
|
const rootSetAppState = toolUseContext.setAppStateForTasks ?? toolUseContext.setAppState;
|
|
337
|
+
let effectiveRunInBackground = run_in_background;
|
|
338
|
+
let effectiveTeamName = team_name;
|
|
339
|
+
const teamModeAllowed = Boolean(appState.teamContext?.teamName) || (teamRequested && !noTeamRequested);
|
|
340
|
+
|
|
341
|
+
if (noBackgroundRequested) {
|
|
342
|
+
effectiveRunInBackground = false;
|
|
343
|
+
}
|
|
344
|
+
if (effectiveTeamName && !teamModeAllowed) {
|
|
345
|
+
logForDebugging(`[AgentTool] Ignoring team_name='${effectiveTeamName}' because team mode was not explicitly requested in recent user messages`);
|
|
346
|
+
effectiveTeamName = undefined;
|
|
347
|
+
}
|
|
288
348
|
|
|
289
349
|
// Check if user is trying to use agent teams without access
|
|
290
|
-
if (
|
|
350
|
+
if (effectiveTeamName && !isAgentSwarmsEnabled()) {
|
|
291
351
|
throw new Error('Agent Teams is not yet available on your plan.');
|
|
292
352
|
}
|
|
293
353
|
|
|
294
354
|
// Teammates (in-process or tmux) passing `name` would trigger spawnTeammate()
|
|
295
355
|
// below, but TeamFile.members is a flat array with one leadAgentId — nested
|
|
296
356
|
// teammates land in the roster with no provenance and confuse the lead.
|
|
297
|
-
const explicitTeamName =
|
|
357
|
+
const explicitTeamName = effectiveTeamName;
|
|
298
358
|
const teamName = explicitTeamName;
|
|
299
359
|
if (isTeammate() && teamName && name) {
|
|
300
360
|
throw new Error('Teammates cannot spawn other teammates — the team roster is flat. To spawn a subagent instead, omit the `name` parameter.');
|
|
@@ -302,7 +362,7 @@ export const AgentTool = buildTool({
|
|
|
302
362
|
// In-process teammates cannot spawn background agents (their lifecycle is
|
|
303
363
|
// tied to the leader's process). Tmux teammates are separate processes and
|
|
304
364
|
// can manage their own background agents.
|
|
305
|
-
if (isInProcessTeammate() && teamName &&
|
|
365
|
+
if (isInProcessTeammate() && teamName && effectiveRunInBackground === true) {
|
|
306
366
|
throw new Error('In-process teammates cannot spawn background agents. Use run_in_background=false for synchronous subagents.');
|
|
307
367
|
}
|
|
308
368
|
|
|
@@ -491,7 +551,7 @@ export const AgentTool = buildTool({
|
|
|
491
551
|
color: selectedAgent.color as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
|
492
552
|
is_built_in_agent: isBuiltInAgent(selectedAgent),
|
|
493
553
|
is_resume: false,
|
|
494
|
-
is_async: (
|
|
554
|
+
is_async: (effectiveRunInBackground === true || selectedAgent.background === true) && !isBackgroundTasksDisabled,
|
|
495
555
|
is_fork: isForkPath
|
|
496
556
|
});
|
|
497
557
|
|
|
@@ -594,7 +654,7 @@ export const AgentTool = buildTool({
|
|
|
594
654
|
agent_type: selectedAgent.agentType as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
|
|
595
655
|
}),
|
|
596
656
|
scope: selectedAgent.memory as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
|
597
|
-
|
|
657
|
+
source: 'subagent' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
|
|
598
658
|
});
|
|
599
659
|
}
|
|
600
660
|
|
|
@@ -613,7 +673,7 @@ export const AgentTool = buildTool({
|
|
|
613
673
|
isBuiltInAgent: isBuiltInAgent(selectedAgent),
|
|
614
674
|
startTime,
|
|
615
675
|
agentType: selectedAgent.agentType,
|
|
616
|
-
isAsync: (
|
|
676
|
+
isAsync: (effectiveRunInBackground === true || selectedAgent.background === true) && !isBackgroundTasksDisabled
|
|
617
677
|
};
|
|
618
678
|
|
|
619
679
|
// Use inline env check instead of coordinatorModule to avoid circular
|
|
@@ -622,7 +682,7 @@ export const AgentTool = buildTool({
|
|
|
622
682
|
|
|
623
683
|
// Fork subagent experiment: force ALL spawns async for a unified
|
|
624
684
|
// <task-notification> interaction model (not just fork spawns — all of them).
|
|
625
|
-
const forceAsync = isForkSubagentEnabled();
|
|
685
|
+
const forceAsync = isForkPath && isForkSubagentEnabled();
|
|
626
686
|
|
|
627
687
|
// Assistant mode: force all agents async. Synchronous subagents hold the
|
|
628
688
|
// main loop's turn open until they complete — the daemon's inputQueue
|
|
@@ -632,7 +692,7 @@ export const AgentTool = buildTool({
|
|
|
632
692
|
// <task-notification> re-entry there is handled by the else branch
|
|
633
693
|
// below (registerAsyncAgentTask + notifyOnCompletion).
|
|
634
694
|
const assistantForceAsync = feature('KAIROS') ? appState.kairosEnabled : false;
|
|
635
|
-
const shouldRunAsync = (
|
|
695
|
+
const shouldRunAsync = (effectiveRunInBackground === true || selectedAgent.background === true || isCoordinator || forceAsync || assistantForceAsync || (proactiveModule?.isProactiveActive() ?? false)) && !isBackgroundTasksDisabled;
|
|
636
696
|
// Assemble the worker's tool pool independently of the parent's.
|
|
637
697
|
// Workers always get their tools from assembleToolPool with their own
|
|
638
698
|
// permission mode, so they aren't affected by the parent's tool
|
|
@@ -265,6 +265,8 @@ Usage notes:
|
|
|
265
265
|
: ''
|
|
266
266
|
}
|
|
267
267
|
- To continue a previously spawned agent, use ${SEND_MESSAGE_TOOL_NAME} with the agent's ID or name as the \`to\` field. The agent resumes with its full context preserved. ${forkEnabled ? 'Each fresh Agent invocation with a subagent_type starts without context — provide a complete task description.' : 'Each Agent invocation starts fresh — provide a complete task description.'}
|
|
268
|
+
- Do NOT use \`name\` or \`team_name\` unless the user explicitly asked for Team/team/swarm mode, or the current session is already inside a Team. For ordinary agent delegation, omit both fields.
|
|
269
|
+
- If the user explicitly says not to use Team mode or not to run in background, you must respect that and keep the agent as a normal foreground subagent.
|
|
268
270
|
- The agent's outputs should generally be trusted
|
|
269
271
|
- Clearly tell the agent whether you expect it to write code or just to do research (search, file reads, web fetches, etc.)${forkEnabled ? '' : ", since it is not aware of the user's intent"}
|
|
270
272
|
- If the agent description mentions that it should be used proactively, then you should try your best to use it without the user having to ask for it first. Use your judgement.
|