-
Notifications
You must be signed in to change notification settings - Fork 121
fix(agent-core): allow subagent cwd override for package-level AGENTS.md discovery #172
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,3 +1,4 @@ | ||
| import { resolve } from 'pathe'; | ||
| import type { TokenUsage } from '@moonshot-ai/kosong'; | ||
|
|
||
| import type { Agent } from '../agent'; | ||
|
|
@@ -32,6 +33,7 @@ type RunSubagentOptions = { | |
| readonly runInBackground: boolean; | ||
| readonly origin?: PromptOrigin | undefined; | ||
| readonly signal: AbortSignal; | ||
| readonly cwd?: string | undefined; | ||
| }; | ||
|
|
||
| type SubagentCompletion = { | ||
|
|
@@ -69,8 +71,16 @@ export class SessionSubagentHost { | |
| } | ||
|
|
||
| const profile = this.resolveProfile(parent, profileName); | ||
| const resolvedCwd = | ||
| options.cwd !== undefined | ||
| ? parent.runtime.kaos.normpath(resolve(parent.config.cwd, options.cwd)) | ||
| : undefined; | ||
| const runtime = | ||
| resolvedCwd !== undefined | ||
| ? { ...parent.runtime, kaos: parent.runtime.kaos.withCwd(resolvedCwd) } | ||
| : undefined; | ||
| const { id, agent } = await this.session.createAgent( | ||
| { type: 'sub', generate: parent.rawGenerate }, | ||
| { type: 'sub', generate: parent.rawGenerate, runtime }, | ||
|
Comment on lines
82
to
+83
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a custom-cwd subagent is saved and the session is later resumed, metadata only records the homedir/type/parent, so Useful? React with 👍 / 👎.
Comment on lines
82
to
+83
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
For a subagent spawned with a package cwd, this still creates the child without a cwd-specific Useful? React with 👍 / 👎. |
||
| undefined, | ||
| this.ownerAgentId, | ||
| ); | ||
|
|
@@ -90,7 +100,7 @@ export class SessionSubagentHost { | |
| ...options, | ||
| signal: controller.signal, | ||
| }, | ||
| () => this.configureChild(parent, agent, profile), | ||
| () => this.configureChild(parent, agent, profile, resolvedCwd), | ||
| ).finally(() => { | ||
| unlinkAbortSignal(); | ||
| this.activeChildren.delete(id); | ||
|
|
@@ -275,10 +285,11 @@ export class SessionSubagentHost { | |
| parent: Agent, | ||
| child: Agent, | ||
| profile: ResolvedAgentProfile, | ||
| cwd?: string, | ||
| ): Promise<void> { | ||
| // A subagent always inherits the parent agent's model. | ||
| child.config.update({ | ||
| cwd: parent.config.cwd, | ||
| cwd: cwd ?? parent.config.cwd, | ||
| modelAlias: parent.config.modelAlias, | ||
| thinkingLevel: parent.config.thinkingLevel, | ||
| }); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -80,6 +80,12 @@ export const AgentToolInputSchema = z.preprocess( | |
| .describe( | ||
| 'Timeout in seconds for the agent task (min 30s, max 3600s / 1hr). When omitted, a foreground task runs until completion with no timeout. The agent is stopped if it exceeds this limit.', | ||
| ), | ||
| cwd: z | ||
| .string() | ||
| .optional() | ||
| .describe( | ||
| "The working directory for the subagent. When provided, the subagent discovers AGENTS.md and resolves paths relative to this directory. When omitted, the subagent inherits the parent agent's working directory.", | ||
| ), | ||
| }), | ||
| ); | ||
|
|
||
|
|
@@ -170,15 +176,19 @@ export class AgentTool implements BuiltinTool<AgentToolInput> { | |
| const runInBackground = args.run_in_background === true; | ||
| const requestedProfileName = args.subagent_type?.length ? args.subagent_type : undefined; | ||
| const resumeAgentId = args.resume?.trim(); | ||
| if ( | ||
| resumeAgentId !== undefined && | ||
| resumeAgentId.length > 0 && | ||
| requestedProfileName !== undefined | ||
| ) { | ||
| return { | ||
| output: 'Cannot set subagent_type when resuming an existing agent. Resume by agent id only.', | ||
| isError: true, | ||
| }; | ||
| if (resumeAgentId !== undefined && resumeAgentId.length > 0) { | ||
| if (requestedProfileName !== undefined) { | ||
| return { | ||
| output: 'Cannot set subagent_type when resuming an existing agent. Resume by agent id only.', | ||
| isError: true, | ||
| }; | ||
| } | ||
| if (args.cwd !== undefined && args.cwd.length > 0) { | ||
| return { | ||
| output: 'Cannot set cwd when resuming an existing agent. Resume by agent id only.', | ||
| isError: true, | ||
| }; | ||
| } | ||
| } | ||
|
|
||
| let reservation: ReturnType<BackgroundProcessManager['reserveSlot']> | undefined; | ||
|
|
@@ -214,6 +224,7 @@ export class AgentTool implements BuiltinTool<AgentToolInput> { | |
| description: args.description, | ||
| runInBackground, | ||
| signal: backgroundController?.signal ?? foregroundDeadline?.signal ?? signal, | ||
| cwd: args.cwd, | ||
|
Comment on lines
224
to
+227
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
If a caller sets both Useful? React with 👍 / 👎. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Useful? React with 👍 / 👎. |
||
| }; | ||
|
|
||
| let handle: SubagentHandle; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When a cwd-scoped subagent later delegates without passing
cwd, this leavesruntimeundefined, soSession.createAgent()falls back to the session runtime instead of the parent subagent's cwd-scoped runtime.configureChild()still copies the parent cwd into the nested child config, which callschdiron that shared session Kaos; in that nested-subagent scenario the main agent and other agents can have their runtime cwd moved to the package directory. Use the parent runtime when no new cwd override is requested, and only wrap it withwithCwdwhen a different cwd is provided.Useful? React with 👍 / 👎.