diff --git a/src/agents/definitions/debug.yaml b/src/agents/definitions/debug.yaml index e4af00e9..f46b3e3b 100644 --- a/src/agents/definitions/debug.yaml +++ b/src/agents/definitions/debug.yaml @@ -30,8 +30,7 @@ prompts: taskPrompt: | Analyze and process the work item with ID: <%= it.cardId %>. The work item data has been pre-loaded. -backend: - needsGitHubToken: false +backend: {} hint: Analyze the current issue fully before moving to the next. diff --git a/src/agents/definitions/email-joke.yaml b/src/agents/definitions/email-joke.yaml index 9efde644..fd2cda75 100644 --- a/src/agents/definitions/email-joke.yaml +++ b/src/agents/definitions/email-joke.yaml @@ -54,8 +54,7 @@ prompts: Only emails from **<%= it.senderEmail %>** were included in the search. <% } %> -backend: - needsGitHubToken: false +backend: {} trailingMessage: {} diff --git a/src/agents/definitions/implementation.yaml b/src/agents/definitions/implementation.yaml index 0cbda959..02a42e09 100644 --- a/src/agents/definitions/implementation.yaml +++ b/src/agents/definitions/implementation.yaml @@ -55,7 +55,6 @@ prompts: Analyze and process the work item with ID: <%= it.cardId %>. The work item data has been pre-loaded. backend: - needsGitHubToken: true hooks: scm: enableStopHooks: true diff --git a/src/agents/definitions/planning.yaml b/src/agents/definitions/planning.yaml index f814a6d7..a87d88d6 100644 --- a/src/agents/definitions/planning.yaml +++ b/src/agents/definitions/planning.yaml @@ -56,8 +56,7 @@ prompts: taskPrompt: | Analyze and process the work item with ID: <%= it.cardId %>. The work item data has been pre-loaded. -backend: - needsGitHubToken: false +backend: {} hint: Complete the current planning step efficiently before moving to the next. diff --git a/src/agents/definitions/profiles.ts b/src/agents/definitions/profiles.ts index 63a78982..deddd161 100644 --- a/src/agents/definitions/profiles.ts +++ b/src/agents/definitions/profiles.ts @@ -8,6 +8,7 @@ import type { AgentInput } from '../../types/index.js'; import type { Capability, IntegrationChecker } from '../capabilities/index.js'; import { + deriveRequiredIntegrations, getGadgetNamesFromCapabilities, getSdkToolsFromCapabilities, resolveEffectiveCapabilities, @@ -115,6 +116,20 @@ function getAllCapabilities(caps: AgentCapabilities): Capability[] { return [...caps.required, ...caps.optional]; } +/** + * Derive whether an agent requires GitHub token access. + * + * Checks explicit integrations first (def.integrations.required contains 'scm'), + * then falls back to capability-derived integrations when explicit integrations + * are not declared. + */ +function requiresScmIntegration(def: AgentDefinition): boolean { + if (def.integrations?.required) { + return def.integrations.required.includes('scm'); + } + return deriveRequiredIntegrations(def.capabilities.required).includes('scm'); +} + /** * Resolve the context pipeline for a given trigger event. * @@ -186,7 +201,7 @@ function buildProfileFromDefinition(def: AgentDefinition, agentType: string): Ag }, sdkTools, enableStopHooks: scmHooks.enableStopHooks ?? false, - needsGitHubToken: def.backend.needsGitHubToken, + needsGitHubToken: requiresScmIntegration(def), ...(scmHooks.blockGitPush !== undefined && { blockGitPush: scmHooks.blockGitPush }), ...(scmHooks.requiresPR && { requiresPR: true }), ...(scmHooks.requiresReview && { requiresReview: true }), diff --git a/src/agents/definitions/respond-to-ci.yaml b/src/agents/definitions/respond-to-ci.yaml index 5efcd863..9dbccccb 100644 --- a/src/agents/definitions/respond-to-ci.yaml +++ b/src/agents/definitions/respond-to-ci.yaml @@ -41,7 +41,6 @@ prompts: CI checks have failed. Analyze the failures and fix them. backend: - needsGitHubToken: true hooks: scm: enableStopHooks: true diff --git a/src/agents/definitions/respond-to-planning-comment.yaml b/src/agents/definitions/respond-to-planning-comment.yaml index 8a1e9bd1..069c91cb 100644 --- a/src/agents/definitions/respond-to-planning-comment.yaml +++ b/src/agents/definitions/respond-to-planning-comment.yaml @@ -43,8 +43,7 @@ prompts: The work item data (title, description, checklists, attachments, comments) has been pre-loaded above. Read the user's comment carefully and classify it: if they ask a question or request clarification, reply with a thorough answer via PostComment (do not modify the plan). If they request plan changes, make surgical, targeted updates. If the comment contains both a question and a change request, do both. Default to plan updates when intent is ambiguous. -backend: - needsGitHubToken: false +backend: {} hint: Complete the current task efficiently before moving to the next. diff --git a/src/agents/definitions/respond-to-pr-comment.yaml b/src/agents/definitions/respond-to-pr-comment.yaml index ec410528..30e443c2 100644 --- a/src/agents/definitions/respond-to-pr-comment.yaml +++ b/src/agents/definitions/respond-to-pr-comment.yaml @@ -52,7 +52,6 @@ prompts: 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. backend: - needsGitHubToken: true hooks: scm: enableStopHooks: true diff --git a/src/agents/definitions/respond-to-review.yaml b/src/agents/definitions/respond-to-review.yaml index f1d31a2c..3cce197c 100644 --- a/src/agents/definitions/respond-to-review.yaml +++ b/src/agents/definitions/respond-to-review.yaml @@ -50,7 +50,6 @@ prompts: 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: - needsGitHubToken: true hooks: scm: enableStopHooks: true diff --git a/src/agents/definitions/review.yaml b/src/agents/definitions/review.yaml index 26522efc..6d9add0b 100644 --- a/src/agents/definitions/review.yaml +++ b/src/agents/definitions/review.yaml @@ -59,7 +59,6 @@ prompts: Examine the code changes carefully and submit your review using CreatePRReview. backend: - needsGitHubToken: true hooks: scm: enableStopHooks: false diff --git a/src/agents/definitions/schema.ts b/src/agents/definitions/schema.ts index 36af1614..f666123f 100644 --- a/src/agents/definitions/schema.ts +++ b/src/agents/definitions/schema.ts @@ -237,7 +237,12 @@ const BackendSchema = z.object({ * Kept for backward compatibility — new format wins when both are present. */ enableStopHooks: z.boolean().optional(), - needsGitHubToken: z.boolean(), + /** + * @deprecated No longer read from agent definitions. + * GitHub token access is now derived from `integrations.required` containing 'scm'. + * Kept optional for backward compatibility — ignored during parsing. + */ + needsGitHubToken: z.boolean().optional(), /** * @deprecated Use hooks.scm.blockGitPush instead. * Kept for backward compatibility — new format wins when both are present. diff --git a/src/agents/definitions/splitting.yaml b/src/agents/definitions/splitting.yaml index 69328e95..b084bb59 100644 --- a/src/agents/definitions/splitting.yaml +++ b/src/agents/definitions/splitting.yaml @@ -52,8 +52,7 @@ prompts: taskPrompt: | Analyze and process the work item with ID: <%= it.cardId %>. The work item data has been pre-loaded. -backend: - needsGitHubToken: false +backend: {} hint: Gather all context needed for the current step before proceeding. diff --git a/tests/unit/agents/definitions/loader.test.ts b/tests/unit/agents/definitions/loader.test.ts index 7e1cd375..b7fae20e 100644 --- a/tests/unit/agents/definitions/loader.test.ts +++ b/tests/unit/agents/definitions/loader.test.ts @@ -259,7 +259,7 @@ describe('YAML agent definitions loader', () => { expect(caps.canUpdateChecklists).toBe(true); expect(caps.isReadOnly).toBe(false); expect(def.backend.hooks?.scm?.enableStopHooks).toBe(true); - expect(def.backend.needsGitHubToken).toBe(true); + expect(def.integrations?.required).toContain('scm'); }); it('review agent is read-only', async () => { @@ -269,15 +269,15 @@ describe('YAML agent definitions loader', () => { expect(caps.canEditFiles).toBe(false); expect(caps.isReadOnly).toBe(true); expect(def.backend.hooks?.scm?.enableStopHooks).toBe(false); - expect(def.backend.needsGitHubToken).toBe(true); + expect(def.integrations?.required).toContain('scm'); }); - it('respond-to-ci agent has needsGitHubToken', async () => { + it('respond-to-ci agent requires scm integration', async () => { const def = loadAgentDefinition('respond-to-ci'); const caps = await getAgentCapabilities('respond-to-ci'); expect(caps.canEditFiles).toBe(true); - expect(def.backend.needsGitHubToken).toBe(true); + expect(def.integrations?.required).toContain('scm'); }); it('capabilities from getAgentCapabilities are derived correctly for all agents', async () => { diff --git a/tests/unit/agents/definitions/schema.test.ts b/tests/unit/agents/definitions/schema.test.ts index 3847a89b..0272e007 100644 --- a/tests/unit/agents/definitions/schema.test.ts +++ b/tests/unit/agents/definitions/schema.test.ts @@ -328,7 +328,6 @@ describe('AgentDefinitionSchema', () => { strategies: {}, backend: { enableStopHooks: false, - needsGitHubToken: false, }, hint: 'Do the thing efficiently.', prompts: { diff --git a/tests/unit/api/routers/agentDefinitions.test.ts b/tests/unit/api/routers/agentDefinitions.test.ts index aa168bc6..eddb0d4b 100644 --- a/tests/unit/api/routers/agentDefinitions.test.ts +++ b/tests/unit/api/routers/agentDefinitions.test.ts @@ -71,7 +71,6 @@ function createMockDefinition(overrides?: Partial): AgentDefini strategies: {}, backend: { enableStopHooks: true, - needsGitHubToken: true, }, hint: 'A test agent', trailingMessage: undefined, diff --git a/tests/unit/db/repositories/agentDefinitionsRepository.test.ts b/tests/unit/db/repositories/agentDefinitionsRepository.test.ts index 2788358a..e006877e 100644 --- a/tests/unit/db/repositories/agentDefinitionsRepository.test.ts +++ b/tests/unit/db/repositories/agentDefinitionsRepository.test.ts @@ -31,7 +31,6 @@ const mockDefinition: AgentDefinition = { }, backend: { enableStopHooks: false, - needsGitHubToken: true, blockGitPush: false, }, hint: 'test hint', diff --git a/web/src/components/settings/agent-definition-editor.tsx b/web/src/components/settings/agent-definition-editor.tsx index 62ea8fd1..2fcc052c 100644 --- a/web/src/components/settings/agent-definition-editor.tsx +++ b/web/src/components/settings/agent-definition-editor.tsx @@ -431,17 +431,6 @@ function BackendSection({ /> - - {/* Backend Settings */} -
-
Backend Settings
- setBackend('needsGitHubToken', v)} - label="Needs GitHub Token" - description="Agent receives GitHub token for API access. Required for PR creation and code reviews." - /> -
); } @@ -968,7 +957,7 @@ const EMPTY_DEFINITION: AgentDefinition = { }, triggers: [], strategies: {}, - backend: { needsGitHubToken: false }, + backend: {}, hint: '', trailingMessage: undefined, prompts: {