Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions src/agents/definitions/debug.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ capabilities:
# No external event-based triggers are configured.
triggers: []

strategies:
contextPipeline: [directoryListing, contextFiles, squint, workItem]
strategies: {}

prompts:
taskPrompt: |
Expand Down
4 changes: 2 additions & 2 deletions src/agents/definitions/email-joke.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ triggers:
label: Sender Email Filter
description: Only process emails from this sender (leave empty for all)
required: false
contextPipeline: [prefetchedEmails]

strategies:
contextPipeline: [prefetchedEmails]
strategies: {}

prompts:
taskPrompt: |
Expand Down
8 changes: 4 additions & 4 deletions src/agents/definitions/implementation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,7 @@ triggers:
label: Target List
options: [todo]
defaultValue: todo
# contextPipeline can be specified per-trigger to override strategies.contextPipeline
# Currently using strategy default: [directoryListing, contextFiles, squint, workItem]
contextPipeline: [directoryListing, contextFiles, squint, workItem]
- event: pm:issue-transitioned
label: Issue Transitioned
description: Trigger when issue transitions to Todo status
Expand All @@ -49,6 +48,7 @@ triggers:
label: Target Status
options: [todo]
defaultValue: todo
contextPipeline: [directoryListing, contextFiles, squint, workItem]
- event: pm:label-added
label: Ready to Process Label
description: Trigger when Ready to Process label added to a card in the Todo list
Expand All @@ -59,9 +59,9 @@ triggers:
label: Target List
options: [todo]
defaultValue: todo
contextPipeline: [directoryListing, contextFiles, squint, workItem]

strategies:
contextPipeline: [directoryListing, contextFiles, squint, workItem]
strategies: {}

prompts:
taskPrompt: |
Expand Down
7 changes: 5 additions & 2 deletions src/agents/definitions/planning.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ triggers:
label: Target List
options: [planning]
defaultValue: planning
contextPipeline: [directoryListing, contextFiles, squint, workItem]
- event: pm:issue-transitioned
label: Issue Transitioned
description: Trigger when issue transitions to Planning status
Expand All @@ -44,6 +45,7 @@ triggers:
label: Target Status
options: [planning]
defaultValue: planning
contextPipeline: [directoryListing, contextFiles, squint, workItem]
- event: pm:label-added
label: Ready to Process Label
description: Trigger when Ready to Process label added to a card in Planning list
Expand All @@ -54,13 +56,14 @@ triggers:
label: Target List
options: [planning]
defaultValue: planning
contextPipeline: [directoryListing, contextFiles, squint, workItem]
- event: pm:comment-mention
label: Comment @mention
description: Trigger when bot is @mentioned in a card/issue comment
defaultEnabled: true
contextPipeline: [directoryListing, contextFiles, squint, workItem]

strategies:
contextPipeline: [directoryListing, contextFiles, squint, workItem]
strategies: {}

prompts:
taskPrompt: |
Expand Down
38 changes: 18 additions & 20 deletions src/agents/definitions/profiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -88,28 +88,34 @@ function getAllCapabilities(caps: AgentCapabilities): Capability[] {

/**
* Resolve the context pipeline for a given trigger event.
* Uses the trigger-specific pipeline if defined, otherwise falls back to the default.
*
* Returns the trigger-specific pipeline if defined, otherwise returns an empty array.
* This function handles several edge cases gracefully:
*
* - **No triggerEvent**: Returns `[]` when triggerEvent is undefined or empty string.
* This happens when an agent is invoked manually without a trigger.
* - **No matching trigger**: Returns `[]` when the triggerEvent doesn't match any
* trigger in the agent's triggers array. This could happen if a trigger is
* misconfigured or the agent doesn't support the given event.
* - **Trigger without contextPipeline**: Returns `[]` when the matching trigger
* exists but has no contextPipeline defined (contextPipeline is optional).
* - **Empty triggers array**: Returns `[]` for agents with no triggers (e.g., debug
* agent which is only invoked internally).
*
* @param triggers - Array of supported triggers from the agent definition
* @param defaultPipeline - Default pipeline from strategies.contextPipeline
* @param triggerEvent - Optional trigger event (e.g., 'pm:card-moved', 'scm:check-suite-success')
* @returns The context pipeline to use
* @returns The context pipeline to use (empty array for any edge case)
*/
function resolveContextPipeline(
triggers: SupportedTrigger[],
defaultPipeline: ContextStepName[],
triggerEvent?: string,
): ContextStepName[] {
if (!triggerEvent) {
return defaultPipeline;
return [];
}

const trigger = triggers.find((t) => t.event === triggerEvent);
if (trigger?.contextPipeline && trigger.contextPipeline.length > 0) {
return trigger.contextPipeline;
}

return defaultPipeline;
return trigger?.contextPipeline ?? [];
}

// ============================================================================
Expand All @@ -128,9 +134,6 @@ function buildProfileFromDefinition(def: AgentDefinition, agentType: string): Ag
// Get gadget options from strategies
const gadgetOptions = def.strategies.gadgetOptions;

// Get default context pipeline from strategies
const defaultContextPipeline = def.strategies.contextPipeline;

// Get triggers for dynamic context pipeline resolution
const triggers = def.triggers ?? [];

Expand All @@ -155,13 +158,8 @@ function buildProfileFromDefinition(def: AgentDefinition, agentType: string): Ag
...(def.backend.blockGitPush !== undefined && { blockGitPush: def.backend.blockGitPush }),
...(def.backend.requiresPR && { requiresPR: true }),
fetchContext: async (params) => {
// Resolve context pipeline: use trigger-specific pipeline if available,
// otherwise fall back to the default from strategies.contextPipeline
const contextPipeline = resolveContextPipeline(
triggers,
defaultContextPipeline,
params.input.triggerType,
);
// Resolve context pipeline from the trigger (empty array if no trigger or trigger has no pipeline)
const contextPipeline = resolveContextPipeline(triggers, params.input.triggerType);

const injections: ContextInjection[] = [];
for (const step of contextPipeline) {
Expand Down
6 changes: 2 additions & 4 deletions src/agents/definitions/respond-to-ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,9 @@ triggers:
description: Trigger when CI checks fail
defaultEnabled: true
providers: [github]
# contextPipeline can be specified per-trigger to override strategies.contextPipeline
# Currently using strategy default: [prContext, directoryListing, contextFiles, squint, workItem]
contextPipeline: [prContext, directoryListing, contextFiles, squint, workItem]

strategies:
contextPipeline: [prContext, directoryListing, contextFiles, squint, workItem]
strategies: {}

prompts:
taskPrompt: |
Expand Down
4 changes: 2 additions & 2 deletions src/agents/definitions/respond-to-planning-comment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ triggers:
label: Comment @mention
description: Trigger when bot is @mentioned in a card/issue comment
defaultEnabled: true
contextPipeline: [directoryListing, contextFiles, squint, workItem]

strategies:
contextPipeline: [directoryListing, contextFiles, squint, workItem]
strategies: {}

prompts:
taskPrompt: |
Expand Down
5 changes: 4 additions & 1 deletion src/agents/definitions/respond-to-pr-comment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ triggers:
description: Trigger when the implementer bot is @mentioned in a PR comment
defaultEnabled: true
providers: [github]
contextPipeline: [prContext, prConversation, directoryListing, contextFiles, squint]

strategies:
contextPipeline: [prContext, prConversation, directoryListing, contextFiles, squint]
gadgetOptions:
includeReviewComments: true

Expand Down Expand Up @@ -59,3 +59,6 @@ backend:
compaction: default

hint: Complete the current task efficiently before moving to the next.

trailingMessage:
includeDiagnostics: true
11 changes: 4 additions & 7 deletions src/agents/definitions/respond-to-review.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,27 +30,24 @@ triggers:
description: Trigger when a review with changes requested is submitted
defaultEnabled: true
providers: [github]
contextPipeline: [prContext, prConversation, directoryListing, contextFiles, squint]

strategies:
contextPipeline: [prContext, prConversation, directoryListing, contextFiles, squint]
gadgetOptions:
includeReviewComments: true

prompts:
taskPrompt: |
You are on the branch `<%= it.prBranch %>` for PR #<%= it.prNumber %>.

A user commented on this PR and mentioned you. Respond to their comment.
<% if (it.commentPath) { -%>
File: <%= it.commentPath %>
<% } -%>
A reviewer has submitted feedback requesting changes. Address the review comments by making the necessary code changes.

Their comment:
Review feedback:
---
<%= it.commentBody %>
---

Read the comment carefully and respond accordingly. If they ask for code changes, make the changes, commit, and push. If they ask a question, reply with a PR comment. Default to surgical, targeted changes unless they clearly ask for something broader.
Carefully read each review comment and make the requested changes. Commit and push your changes when done. Use the ReplyToReviewComment tool to respond to individual review comments as you address them. Focus on surgical, targeted fixes unless the reviewer clearly asks for broader changes.

backend:
enableStopHooks: true
Expand Down
8 changes: 4 additions & 4 deletions src/agents/definitions/review.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,21 @@ triggers:
description: Filter PRs by author type
options: [own, external, all]
defaultValue: own
# contextPipeline can be specified per-trigger to override strategies.contextPipeline
# Currently using strategy default: [prContext, contextFiles, squint]
contextPipeline: [prContext, contextFiles, squint]
- event: scm:review-requested
label: On Review Requested
description: Trigger review when a CASCADE persona is explicitly requested as reviewer
defaultEnabled: false
providers: [github]
contextPipeline: [prContext, contextFiles, squint]
- event: scm:pr-opened
label: PR Opened
description: Trigger review when a new PR is opened (without waiting for CI)
defaultEnabled: false
providers: [github]
contextPipeline: [prContext, contextFiles, squint]

strategies:
contextPipeline: [prContext, contextFiles, squint]
strategies: {}

prompts:
taskPrompt: |
Expand Down
16 changes: 8 additions & 8 deletions src/agents/definitions/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ export const TriggerParameterSchema = z
);

// ============================================================================
// Context Step Names (used by triggers and strategies)
// Context Step Names (used by trigger contextPipeline definitions)
// ============================================================================

export const CONTEXT_STEP_NAMES = [
Expand Down Expand Up @@ -112,10 +112,11 @@ export const SupportedTriggerSchema = z.object({
/** Provider filter - only applies to these providers (e.g., ['trello']) */
providers: z.array(KnownProviderSchema).optional(),
/**
* Optional custom context pipeline for this trigger.
* When specified, overrides the agent's default strategies.contextPipeline.
* Useful when different triggers require different context (e.g., PM triggers
* Context pipeline for this trigger.
* Defines what context to fetch when this trigger fires.
* Different triggers typically need different context (e.g., PM triggers
* need workItem, SCM triggers need prContext).
* When not specified, an empty pipeline is used.
*/
contextPipeline: z.array(ContextStepNameSchema).optional(),
});
Expand Down Expand Up @@ -197,13 +198,12 @@ const GadgetOptionsSchema = z
export const COMPACTION_NAMES = ['implementation', 'default'] as const;

/**
* Strategies schema - context and prompt configuration.
* Strategies schema - gadget configuration only.
* Note: gadgetBuilder removed - gadgets are now derived from capabilities.
* Note: taskPromptBuilder removed - task prompts are now stored in prompts.taskPrompt.
* Note: contextPipeline removed - context is now derived from triggers only.
*/
const StrategiesSchema = z.object({
/** Pipeline of context fetching steps */
contextPipeline: z.array(z.enum(CONTEXT_STEP_NAMES)),
/** Optional gadget configuration for special cases */
gadgetOptions: GadgetOptionsSchema,
});
Expand Down Expand Up @@ -262,7 +262,7 @@ export const AgentDefinitionSchema = z.object({
* Declares what events the agent can respond to, with configurable parameters.
*/
triggers: z.array(SupportedTriggerSchema).default([]),
/** Strategy configuration (context pipeline, prompts) */
/** Strategy configuration (gadget options) */
strategies: StrategiesSchema,
/** Backend execution configuration */
backend: BackendSchema,
Expand Down
6 changes: 4 additions & 2 deletions src/agents/definitions/splitting.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ triggers:
label: Target List
options: [splitting]
defaultValue: splitting
contextPipeline: [directoryListing, contextFiles, squint, workItem]
- event: pm:issue-transitioned
label: Issue Transitioned
description: Trigger when issue transitions to Splitting status
Expand All @@ -45,6 +46,7 @@ triggers:
label: Target Status
options: [splitting]
defaultValue: splitting
contextPipeline: [directoryListing, contextFiles, squint, workItem]
- event: pm:label-added
label: Ready to Process Label
description: Trigger when Ready to Process label added to a card in Splitting list
Expand All @@ -55,9 +57,9 @@ triggers:
label: Target List
options: [splitting]
defaultValue: splitting
contextPipeline: [directoryListing, contextFiles, squint, workItem]

strategies:
contextPipeline: [directoryListing, contextFiles, squint, workItem]
strategies: {}

prompts:
taskPrompt: |
Expand Down
2 changes: 0 additions & 2 deletions src/api/routers/agentDefinitions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import {
type AgentDefinition,
AgentDefinitionSchema,
COMPACTION_NAMES,
CONTEXT_STEP_NAMES,
DefinitionPatchSchema,
} from '../../agents/definitions/schema.js';
import { validateTemplate } from '../../agents/prompts/index.js';
Expand Down Expand Up @@ -351,7 +350,6 @@ export const agentDefinitionsRouter = router({
schema: publicProcedure.query(() => {
return {
capabilities: [...CAPABILITIES],
contextStepNames: [...CONTEXT_STEP_NAMES],
compactionNames: [...COMPACTION_NAMES],
triggerRegistry: TRIGGER_REGISTRY,
};
Expand Down
Loading