diff --git a/src/cli/commands/add/tool-action.ts b/src/cli/commands/add/tool-action.ts index 314038da4..cced82d81 100644 --- a/src/cli/commands/add/tool-action.ts +++ b/src/cli/commands/add/tool-action.ts @@ -1,5 +1,5 @@ import { ConfigIO } from '../../../lib'; -import type { HarnessSpec } from '../../../schema'; +import type { HarnessGatewayOutboundAuth, HarnessSpec } from '../../../schema'; import type { HarnessToolType } from '../../../schema/schemas/primitives/harness'; export interface AddToolOptions { @@ -11,9 +11,17 @@ export interface AddToolOptions { codeInterpreterArn?: string; gatewayArn?: string; gateway?: string; + outboundAuth?: string; + providerArn?: string; + scopes?: string; + grantType?: string; json?: boolean; } +const VALID_OUTBOUND_AUTH_TYPES = ['awsIam', 'none', 'oauth'] as const; +const VALID_GRANT_TYPES = ['CLIENT_CREDENTIALS', 'USER_FEDERATION'] as const; +const ARN_PATTERN = /^arn:[^:]+:/; + export interface AddToolResult { success: boolean; error?: string; @@ -49,6 +57,61 @@ export async function handleAddTool(options: AddToolOptions): Promise s.trim()) + .filter(Boolean); + if (scopes.length === 0) { + return { success: false, error: '--scopes must contain at least one scope' }; + } + if ( + options.grantType !== undefined && + !VALID_GRANT_TYPES.includes(options.grantType as (typeof VALID_GRANT_TYPES)[number]) + ) { + return { + success: false, + error: `Invalid --grant-type '${options.grantType}'. Valid: ${VALID_GRANT_TYPES.join(', ')}`, + }; + } + outboundAuth = { + oauth: { + providerArn: options.providerArn, + scopes, + ...(options.grantType && { grantType: options.grantType as (typeof VALID_GRANT_TYPES)[number] }), + }, + }; + } + } + const configIO = new ConfigIO(); // Resolve --gateway (project name) to ARN from deployed-state @@ -98,7 +161,12 @@ export async function handleAddTool(options: AddToolOptions): Promise', 'Custom code interpreter ARN (optional for agentcore_code_interpreter)') .option('--gateway-arn ', 'Gateway ARN (for agentcore_gateway)') .option('--gateway ', 'Project gateway name — resolves ARN from deployed state (for agentcore_gateway)') + .option( + '--outbound-auth ', + 'Gateway outbound auth: awsIam, none, or oauth (default: awsIam if omitted) [agentcore_gateway]' + ) + .option('--provider-arn ', 'OAuth credential provider ARN (required when --outbound-auth oauth)') + .option( + '--scopes ', + 'Comma-separated OAuth scopes (required when --outbound-auth oauth), e.g. "openid,profile" or "https://api.example.com/read"' + ) + .option( + '--grant-type ', + 'OAuth grant type: CLIENT_CREDENTIALS or USER_FEDERATION (for --outbound-auth oauth)' + ) .option('--json', 'Output as JSON') .action(async cliOptions => { if (!findConfigRoot()) { @@ -35,6 +48,10 @@ export function registerAddTool(addCmd: Command): void { codeInterpreterArn: cliOptions.codeInterpreterArn, gatewayArn: cliOptions.gatewayArn, gateway: cliOptions.gateway, + outboundAuth: cliOptions.outboundAuth, + providerArn: cliOptions.providerArn, + scopes: cliOptions.scopes, + grantType: cliOptions.grantType, json: cliOptions.json, }); diff --git a/src/cli/operations/deploy/imperative/deployers/__tests__/harness-mapper.test.ts b/src/cli/operations/deploy/imperative/deployers/__tests__/harness-mapper.test.ts index cd9625013..8d5e033d9 100644 --- a/src/cli/operations/deploy/imperative/deployers/__tests__/harness-mapper.test.ts +++ b/src/cli/operations/deploy/imperative/deployers/__tests__/harness-mapper.test.ts @@ -199,6 +199,146 @@ describe('mapHarnessSpecToCreateOptions', () => { expect(result.tools).toBeUndefined(); }); + + it('passes gateway tool with outboundAuth awsIam through the mapper', async () => { + const spec = minimalSpec({ + tools: [ + { + type: 'agentcore_gateway', + name: 'my_gw', + config: { + agentCoreGateway: { + gatewayArn: 'arn:aws:bedrock-agentcore:us-west-2:123:gateway/abc', + outboundAuth: { awsIam: {} }, + }, + }, + }, + ], + }); + + const result = await mapHarnessSpecToCreateOptions({ ...BASE_OPTIONS, harnessSpec: spec }); + + expect(result.tools).toEqual([ + { + type: 'agentcore_gateway', + name: 'my_gw', + config: { + agentCoreGateway: { + gatewayArn: 'arn:aws:bedrock-agentcore:us-west-2:123:gateway/abc', + outboundAuth: { awsIam: {} }, + }, + }, + }, + ]); + }); + + it('passes gateway tool with outboundAuth none through the mapper', async () => { + const spec = minimalSpec({ + tools: [ + { + type: 'agentcore_gateway', + name: 'my_gw', + config: { + agentCoreGateway: { + gatewayArn: 'arn:aws:bedrock-agentcore:us-west-2:123:gateway/abc', + outboundAuth: { none: {} }, + }, + }, + }, + ], + }); + + const result = await mapHarnessSpecToCreateOptions({ ...BASE_OPTIONS, harnessSpec: spec }); + + expect(result.tools).toEqual([ + { + type: 'agentcore_gateway', + name: 'my_gw', + config: { + agentCoreGateway: { + gatewayArn: 'arn:aws:bedrock-agentcore:us-west-2:123:gateway/abc', + outboundAuth: { none: {} }, + }, + }, + }, + ]); + }); + + it('passes gateway tool with outboundAuth oauth through the mapper', async () => { + const spec = minimalSpec({ + tools: [ + { + type: 'agentcore_gateway', + name: 'my_gw', + config: { + agentCoreGateway: { + gatewayArn: 'arn:aws:bedrock-agentcore:us-west-2:123:gateway/abc', + outboundAuth: { + oauth: { + providerArn: + 'arn:aws:bedrock-agentcore:us-west-2:123:token-vault/default/oauth2credentialprovider/my-provider', + scopes: ['read', 'write'], + grantType: 'CLIENT_CREDENTIALS', + }, + }, + }, + }, + }, + ], + }); + + const result = await mapHarnessSpecToCreateOptions({ ...BASE_OPTIONS, harnessSpec: spec }); + + expect(result.tools).toEqual([ + { + type: 'agentcore_gateway', + name: 'my_gw', + config: { + agentCoreGateway: { + gatewayArn: 'arn:aws:bedrock-agentcore:us-west-2:123:gateway/abc', + outboundAuth: { + oauth: { + providerArn: + 'arn:aws:bedrock-agentcore:us-west-2:123:token-vault/default/oauth2credentialprovider/my-provider', + scopes: ['read', 'write'], + grantType: 'CLIENT_CREDENTIALS', + }, + }, + }, + }, + }, + ]); + }); + + it('passes gateway tool without outboundAuth through the mapper', async () => { + const spec = minimalSpec({ + tools: [ + { + type: 'agentcore_gateway', + name: 'my_gw', + config: { + agentCoreGateway: { + gatewayArn: 'arn:aws:bedrock-agentcore:us-west-2:123:gateway/abc', + }, + }, + }, + ], + }); + + const result = await mapHarnessSpecToCreateOptions({ ...BASE_OPTIONS, harnessSpec: spec }); + + expect(result.tools).toEqual([ + { + type: 'agentcore_gateway', + name: 'my_gw', + config: { + agentCoreGateway: { + gatewayArn: 'arn:aws:bedrock-agentcore:us-west-2:123:gateway/abc', + }, + }, + }, + ]); + }); }); // ── Skills mapping ───────────────────────────────────────────────────── diff --git a/src/cli/primitives/HarnessPrimitive.ts b/src/cli/primitives/HarnessPrimitive.ts index 590fb9035..1b93eb7c5 100644 --- a/src/cli/primitives/HarnessPrimitive.ts +++ b/src/cli/primitives/HarnessPrimitive.ts @@ -1,5 +1,6 @@ import { APP_DIR, ConfigIO, findConfigRoot } from '../../lib'; import type { + HarnessGatewayOutboundAuth, HarnessModelProvider, HarnessSpec, MemoryStrategy, @@ -45,6 +46,9 @@ export interface AddHarnessOptions { mcpName?: string; mcpUrl?: string; gatewayArn?: string; + gatewayOutboundAuth?: 'awsIam' | 'none' | 'oauth'; + gatewayProviderArn?: string; + gatewayScopes?: string[]; authorizerType?: RuntimeAuthorizerType; jwtConfig?: JwtConfigOptions; configBaseDir?: string; @@ -104,10 +108,33 @@ export class HarnessPrimitive extends BasePrimitive 0 + ) { + outboundAuth = { + oauth: { + providerArn: options.gatewayProviderArn, + scopes: options.gatewayScopes, + }, + }; + } tools.push({ type: 'agentcore_gateway', name: 'gateway', - config: { agentCoreGateway: { gatewayArn: options.gatewayArn } }, + config: { + agentCoreGateway: { + gatewayArn: options.gatewayArn, + ...(outboundAuth && { outboundAuth }), + }, + }, }); } } diff --git a/src/cli/tui/screens/harness/AddHarnessFlow.tsx b/src/cli/tui/screens/harness/AddHarnessFlow.tsx index 180d73042..eca698713 100644 --- a/src/cli/tui/screens/harness/AddHarnessFlow.tsx +++ b/src/cli/tui/screens/harness/AddHarnessFlow.tsx @@ -68,6 +68,14 @@ export function AddHarnessFlow({ isInteractive = true, onExit, onBack, onDev, on mcpName: config.mcpName, mcpUrl: config.mcpUrl, gatewayArn: config.gatewayArn, + gatewayOutboundAuth: config.gatewayOutboundAuth, + gatewayProviderArn: config.gatewayProviderArn, + gatewayScopes: config.gatewayScopes + ? config.gatewayScopes + .split(',') + .map(s => s.trim()) + .filter(Boolean) + : undefined, authorizerType: config.authorizerType, jwtConfig: config.jwtConfig ? { diff --git a/src/cli/tui/screens/harness/AddHarnessScreen.tsx b/src/cli/tui/screens/harness/AddHarnessScreen.tsx index 63511efef..13c3fc125 100644 --- a/src/cli/tui/screens/harness/AddHarnessScreen.tsx +++ b/src/cli/tui/screens/harness/AddHarnessScreen.tsx @@ -22,6 +22,7 @@ import { ADVANCED_SETTING_OPTIONS, AUTHORIZER_TYPE_OPTIONS, CONTAINER_MODE_OPTIONS, + GATEWAY_OUTBOUND_AUTH_OPTIONS, HARNESS_STEP_LABELS, MEMORY_OPTIONS, MODEL_PROVIDER_OPTIONS, @@ -86,6 +87,11 @@ export function AddHarnessScreen({ existingHarnessNames, onComplete, onExit }: A [] ); + const gatewayOutboundAuthItems: SelectableItem[] = useMemo( + () => GATEWAY_OUTBOUND_AUTH_OPTIONS.map(opt => ({ id: opt.id, title: opt.title, description: opt.description })), + [] + ); + const isNameStep = wizard.step === 'name'; const isModelProviderStep = wizard.step === 'model-provider'; const isApiKeyArnStep = wizard.step === 'api-key-arn'; @@ -97,6 +103,9 @@ export function AddHarnessScreen({ existingHarnessNames, onComplete, onExit }: A const isMcpNameStep = wizard.step === 'mcp-name'; const isMcpUrlStep = wizard.step === 'mcp-url'; const isGatewayArnStep = wizard.step === 'gateway-arn'; + const isGatewayOutboundAuthStep = wizard.step === 'gateway-outbound-auth'; + const isGatewayProviderArnStep = wizard.step === 'gateway-provider-arn'; + const isGatewayScopesStep = wizard.step === 'gateway-scopes'; const isMemoryStep = wizard.step === 'memory'; const isAuthorizerTypeStep = wizard.step === 'authorizerType'; const isJwtConfigStep = wizard.step === 'jwtConfig'; @@ -158,6 +167,13 @@ export function AddHarnessScreen({ existingHarnessNames, onComplete, onExit }: A isActive: isAuthorizerTypeStep, }); + const gatewayOutboundAuthNav = useListNavigation({ + items: gatewayOutboundAuthItems, + onSelect: item => wizard.setGatewayOutboundAuth(item.id as 'awsIam' | 'none' | 'oauth'), + onExit: () => wizard.goBack(), + isActive: isGatewayOutboundAuthStep, + }); + const networkModeNav = useListNavigation({ items: networkModeItems, onSelect: item => wizard.setNetworkMode(NetworkModeSchema.parse(item.id)), @@ -194,7 +210,8 @@ export function AddHarnessScreen({ existingHarnessNames, onComplete, onExit }: A isContainerStep || isNetworkModeStep || isTruncationStrategyStep || - isAuthorizerTypeStep + isAuthorizerTypeStep || + isGatewayOutboundAuthStep ? HELP_TEXT.NAVIGATE_SELECT : isConfirmStep ? HELP_TEXT.CONFIRM_CANCEL @@ -256,6 +273,22 @@ export function AddHarnessScreen({ existingHarnessNames, onComplete, onExit }: A if (wizard.config.gatewayArn) { fields.push({ label: 'Gateway ARN', value: wizard.config.gatewayArn }); } + if (wizard.config.gatewayOutboundAuth) { + fields.push({ + label: 'Gateway Auth', + value: + GATEWAY_OUTBOUND_AUTH_OPTIONS.find(o => o.id === wizard.config.gatewayOutboundAuth)?.title ?? + wizard.config.gatewayOutboundAuth, + }); + } + if (wizard.config.gatewayOutboundAuth === 'oauth') { + if (wizard.config.gatewayProviderArn) { + fields.push({ label: 'Provider ARN', value: wizard.config.gatewayProviderArn }); + } + if (wizard.config.gatewayScopes) { + fields.push({ label: 'OAuth Scopes', value: wizard.config.gatewayScopes }); + } + } } if (wizard.config.containerUri) { @@ -437,6 +470,39 @@ export function AddHarnessScreen({ existingHarnessNames, onComplete, onExit }: A /> )} + {isGatewayOutboundAuthStep && ( + + )} + + {isGatewayProviderArnStep && ( + wizard.goBack()} + customValidation={value => (isValidArn(value) ? true : ARN_VALIDATION_MESSAGE)} + /> + )} + + {isGatewayScopesStep && ( + wizard.goBack()} + customValidation={value => (value.trim().length > 0 ? true : 'At least one scope is required')} + /> + )} + {isMemoryStep && ( = { @@ -69,6 +75,9 @@ export const HARNESS_STEP_LABELS: Record = { 'mcp-name': 'MCP name', 'mcp-url': 'MCP URL', 'gateway-arn': 'Gateway ARN', + 'gateway-outbound-auth': 'Gateway auth', + 'gateway-provider-arn': 'Provider ARN', + 'gateway-scopes': 'OAuth scopes', memory: 'Memory', authorizerType: 'Auth type', jwtConfig: 'JWT config', @@ -157,3 +166,9 @@ export const AUTHORIZER_TYPE_OPTIONS = [ { id: 'AWS_IAM' as const, title: 'AWS IAM', description: 'Use AWS IAM authentication (default)' }, { id: 'CUSTOM_JWT' as const, title: 'Custom JWT', description: 'Use a custom JWT authorizer (OIDC)' }, ] as const; + +export const GATEWAY_OUTBOUND_AUTH_OPTIONS = [ + { id: 'awsIam', title: 'AWS IAM (default)', description: 'SigV4 signing with the harness execution role' }, + { id: 'none', title: 'None', description: 'No authentication headers' }, + { id: 'oauth', title: 'OAuth', description: 'Bearer token via AgentCore Identity credential provider' }, +]; diff --git a/src/cli/tui/screens/harness/useAddHarnessWizard.ts b/src/cli/tui/screens/harness/useAddHarnessWizard.ts index 8f6b57143..13325fe35 100644 --- a/src/cli/tui/screens/harness/useAddHarnessWizard.ts +++ b/src/cli/tui/screens/harness/useAddHarnessWizard.ts @@ -78,6 +78,10 @@ export function useAddHarnessWizard() { } if (config.selectedTools?.includes('agentcore_gateway')) { steps.push('gateway-arn'); + steps.push('gateway-outbound-auth'); + if (config.gatewayOutboundAuth === 'oauth') { + steps.push('gateway-provider-arn', 'gateway-scopes'); + } } } @@ -120,6 +124,7 @@ export function useAddHarnessWizard() { config.authorizerType, config.networkMode, config.selectedTools, + config.gatewayOutboundAuth, advancedSettings, ]); @@ -238,9 +243,32 @@ export function useAddHarnessWizard() { [advancedSettings, config.selectedTools] ); - const setGatewayArn = useCallback( - (gatewayArn: string) => { - setConfig(c => ({ ...c, gatewayArn })); + const setGatewayArn = useCallback((gatewayArn: string) => { + setConfig(c => ({ ...c, gatewayArn })); + setStep('gateway-outbound-auth'); + }, []); + + const setGatewayOutboundAuth = useCallback( + (authType: 'awsIam' | 'none' | 'oauth') => { + setConfig(c => ({ ...c, gatewayOutboundAuth: authType })); + if (authType === 'oauth') { + setStep('gateway-provider-arn'); + } else { + const next = getNextAdvancedStep(advancedSettings, 'tools'); + setStep(next ?? 'confirm'); + } + }, + [advancedSettings] + ); + + const setGatewayProviderArn = useCallback((gatewayProviderArn: string) => { + setConfig(c => ({ ...c, gatewayProviderArn })); + setStep('gateway-scopes'); + }, []); + + const setGatewayScopes = useCallback( + (gatewayScopes: string) => { + setConfig(c => ({ ...c, gatewayScopes })); const next = getNextAdvancedStep(advancedSettings, 'tools'); setStep(next ?? 'confirm'); }, @@ -405,6 +433,9 @@ export function useAddHarnessWizard() { setMcpName, setMcpUrl, setGatewayArn, + setGatewayOutboundAuth, + setGatewayProviderArn, + setGatewayScopes, setMemoryEnabled, setAuthorizerType, setJwtConfig, diff --git a/src/schema/schemas/agentcore-project.ts b/src/schema/schemas/agentcore-project.ts index 7812c8db3..6f343c3df 100644 --- a/src/schema/schemas/agentcore-project.ts +++ b/src/schema/schemas/agentcore-project.ts @@ -44,8 +44,10 @@ export type { RatingScale, } from './primitives/evaluator'; export { BedrockModelIdSchema, isValidBedrockModelId, EvaluatorNameSchema } from './primitives/evaluator'; -export type { HarnessSpec, HarnessModelProvider } from './primitives/harness'; +export type { HarnessGatewayOutboundAuth, HarnessSpec, HarnessModelProvider } from './primitives/harness'; export { + GatewayOAuthGrantTypeSchema, + HarnessGatewayOutboundAuthSchema, HarnessNameSchema, HarnessSpecSchema, HarnessToolTypeSchema, diff --git a/src/schema/schemas/primitives/__tests__/harness.test.ts b/src/schema/schemas/primitives/__tests__/harness.test.ts index d32b5db7d..8ec96a1c8 100644 --- a/src/schema/schemas/primitives/__tests__/harness.test.ts +++ b/src/schema/schemas/primitives/__tests__/harness.test.ts @@ -112,20 +112,99 @@ describe('HarnessToolSchema', () => { expect(result.success).toBe(true); }); - it('accepts gateway tool with credentialProviderName', () => { + it('accepts gateway tool with outboundAuth awsIam', () => { + const result = HarnessToolSchema.safeParse({ + type: 'agentcore_gateway', + name: 'my-gw', + config: { + agentCoreGateway: { + gatewayArn: 'arn:aws:bedrock-agentcore:us-west-2:123:gateway/abc', + outboundAuth: { awsIam: {} }, + }, + }, + }); + expect(result.success).toBe(true); + }); + + it('accepts gateway tool with outboundAuth none', () => { + const result = HarnessToolSchema.safeParse({ + type: 'agentcore_gateway', + name: 'my-gw', + config: { + agentCoreGateway: { + gatewayArn: 'arn:aws:bedrock-agentcore:us-west-2:123:gateway/abc', + outboundAuth: { none: {} }, + }, + }, + }); + expect(result.success).toBe(true); + }); + + it('accepts gateway tool with outboundAuth oauth', () => { + const result = HarnessToolSchema.safeParse({ + type: 'agentcore_gateway', + name: 'my-gw', + config: { + agentCoreGateway: { + gatewayArn: 'arn:aws:bedrock-agentcore:us-west-2:123:gateway/abc', + outboundAuth: { + oauth: { + providerArn: + 'arn:aws:bedrock-agentcore:us-west-2:123:token-vault/default/oauth2credentialprovider/my-provider', + scopes: ['read', 'write'], + grantType: 'CLIENT_CREDENTIALS', + }, + }, + }, + }, + }); + expect(result.success).toBe(true); + }); + + it('accepts gateway tool without outboundAuth (defaults to SigV4)', () => { const result = HarnessToolSchema.safeParse({ type: 'agentcore_gateway', name: 'my-gw', config: { agentCoreGateway: { gatewayArn: 'arn:aws:bedrock-agentcore:us-west-2:123:gateway/abc', - credentialProviderName: 'my-oauth', }, }, }); expect(result.success).toBe(true); }); + it('rejects gateway tool with invalid outboundAuth variant', () => { + const result = HarnessToolSchema.safeParse({ + type: 'agentcore_gateway', + name: 'my-gw', + config: { + agentCoreGateway: { + gatewayArn: 'arn:aws:bedrock-agentcore:us-west-2:123:gateway/abc', + outboundAuth: { unknownAuth: {} }, + }, + }, + }); + expect(result.success).toBe(false); + }); + + it('rejects gateway tool with credentialProviderName and shows migration message', () => { + const result = HarnessToolSchema.safeParse({ + type: 'agentcore_gateway', + name: 'my-gw', + config: { + agentCoreGateway: { + gatewayArn: 'arn:aws:bedrock-agentcore:us-west-2:123:gateway/abc', + credentialProviderName: 'my-oauth', + }, + }, + }); + expect(result.success).toBe(false); + if (!result.success) { + expect(result.error.issues.some(i => i.message.includes('no longer supported'))).toBe(true); + } + }); + it('accepts inline function tool', () => { const result = HarnessToolSchema.safeParse({ type: 'inline_function', diff --git a/src/schema/schemas/primitives/harness.ts b/src/schema/schemas/primitives/harness.ts index 0ffe1ab6f..823d75d82 100644 --- a/src/schema/schemas/primitives/harness.ts +++ b/src/schema/schemas/primitives/harness.ts @@ -89,11 +89,40 @@ export const AgentCoreCodeInterpreterConfigSchema = z.object({ }), }); -export const AgentCoreGatewayConfigSchema = z.object({ - agentCoreGateway: z.object({ - gatewayArn: z.string().min(1), - credentialProviderName: z.string().optional(), +export const GatewayOAuthGrantTypeSchema = z.enum(['CLIENT_CREDENTIALS', 'USER_FEDERATION']); + +export const HarnessGatewayOutboundAuthSchema = z.union([ + z.object({ awsIam: z.object({}) }), + z.object({ none: z.object({}) }), + z.object({ + oauth: z.object({ + providerArn: z.string().min(1), + scopes: z.array(z.string().min(1)), + grantType: GatewayOAuthGrantTypeSchema.optional(), + customParameters: z.record(z.string(), z.string()).optional(), + }), }), +]); + +export type HarnessGatewayOutboundAuth = z.infer; + +export const AgentCoreGatewayConfigSchema = z.object({ + agentCoreGateway: z + .object({ + gatewayArn: z.string().min(1), + outboundAuth: HarnessGatewayOutboundAuthSchema.optional(), + }) + .passthrough() + .superRefine((data, ctx) => { + if ('credentialProviderName' in data) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: + 'credentialProviderName is no longer supported. Use outboundAuth instead. Example: outboundAuth: { awsIam: {} } or outboundAuth: { oauth: { providerArn: "...", scopes: [...] } }', + path: ['credentialProviderName'], + }); + } + }), }); export const InlineFunctionConfigSchema = z.object({ diff --git a/src/schema/schemas/primitives/index.ts b/src/schema/schemas/primitives/index.ts index 0df1f3c3e..cdc229352 100644 --- a/src/schema/schemas/primitives/index.ts +++ b/src/schema/schemas/primitives/index.ts @@ -46,6 +46,7 @@ export { } from './policy'; export type { + HarnessGatewayOutboundAuth, HarnessMemoryRef, HarnessModel, HarnessModelProvider, @@ -56,6 +57,8 @@ export type { } from './harness'; export { AllowedToolSchema, + GatewayOAuthGrantTypeSchema, + HarnessGatewayOutboundAuthSchema, HarnessMemoryRefSchema, HarnessModelProviderSchema, HarnessModelSchema,