Skip to content

Commit 149b19d

Browse files
committed
feat(github): add GitHub Context Agent
Implements GitHubAgent following coordinator pattern: **Agent Implementation:** - Follows Explorer/Planner agent patterns - Implements Agent interface (initialize, handleMessage, healthCheck, shutdown) - Handles 4 actions: index, search, context, related - Integrates GitHubIndexer for document management - Proper error handling and logging **Message Handling:** - Request/response pattern via coordinator - Supports all GitHubContextRequest actions - Returns GitHubContextResult or GitHubContextError - Compatible with coordinator message routing **Exports:** - GitHubAgent class - GitHubAgentConfig interface - All utilities and types available **Fixed:** - Consistent TypeScript imports (no .js extensions) - Proper Message interface compliance (priority field) - Type-safe payload handling Ready for coordinator integration ✅
1 parent cd0b60d commit 149b19d

File tree

3 files changed

+176
-3
lines changed

3 files changed

+176
-3
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
/**
2+
* GitHub Context Agent
3+
* Provides rich context from GitHub issues, PRs, and discussions
4+
*/
5+
6+
import type { RepositoryIndexer } from '@lytics/dev-agent-core';
7+
import type { Agent, AgentContext, Message } from '../types';
8+
import { GitHubIndexer } from './indexer';
9+
import type {
10+
GitHubContextError,
11+
GitHubContextRequest,
12+
GitHubContextResult,
13+
GitHubIndexOptions,
14+
} from './types';
15+
16+
export interface GitHubAgentConfig {
17+
repositoryPath: string;
18+
codeIndexer: RepositoryIndexer;
19+
storagePath?: string;
20+
}
21+
22+
export class GitHubAgent implements Agent {
23+
name = 'github';
24+
capabilities = ['github-index', 'github-search', 'github-context', 'github-related'];
25+
26+
private context?: AgentContext;
27+
private indexer?: GitHubIndexer;
28+
private config: GitHubAgentConfig;
29+
30+
constructor(config: GitHubAgentConfig) {
31+
this.config = config;
32+
}
33+
34+
async initialize(context: AgentContext): Promise<void> {
35+
this.context = context;
36+
this.name = context.agentName;
37+
38+
this.indexer = new GitHubIndexer(this.config.codeIndexer);
39+
40+
context.logger.info('GitHub agent initialized', {
41+
capabilities: this.capabilities,
42+
repository: this.config.repositoryPath,
43+
});
44+
}
45+
46+
async handleMessage(message: Message): Promise<Message | null> {
47+
if (!this.context || !this.indexer) {
48+
throw new Error('GitHub agent not initialized');
49+
}
50+
51+
const { logger } = this.context;
52+
53+
if (message.type !== 'request') {
54+
logger.debug('Ignoring non-request message', { type: message.type });
55+
return null;
56+
}
57+
58+
try {
59+
const request = message.payload as unknown as GitHubContextRequest;
60+
logger.debug('Processing GitHub request', { action: request.action });
61+
62+
let result: GitHubContextResult | GitHubContextError;
63+
64+
switch (request.action) {
65+
case 'index':
66+
result = await this.handleIndex(request.indexOptions);
67+
break;
68+
case 'search':
69+
result = await this.handleSearch(request.query || '', request.searchOptions);
70+
break;
71+
case 'context':
72+
result = await this.handleGetContext(request.issueNumber!);
73+
break;
74+
case 'related':
75+
result = await this.handleFindRelated(request.issueNumber!);
76+
break;
77+
default:
78+
result = {
79+
action: 'index',
80+
error: `Unknown action: ${(request as GitHubContextRequest).action}`,
81+
};
82+
}
83+
84+
return {
85+
id: `${message.id}-response`,
86+
type: 'response',
87+
sender: this.name,
88+
recipient: message.sender,
89+
correlationId: message.id,
90+
payload: result as unknown as Record<string, unknown>,
91+
priority: message.priority,
92+
timestamp: Date.now(),
93+
};
94+
} catch (error) {
95+
const errorMsg = error instanceof Error ? error.message : String(error);
96+
logger.error(errorMsg);
97+
98+
const errorResult = {
99+
action: 'index' as const,
100+
error: errorMsg,
101+
};
102+
103+
return {
104+
id: `${message.id}-error`,
105+
type: 'response',
106+
sender: this.name,
107+
recipient: message.sender,
108+
correlationId: message.id,
109+
payload: errorResult as Record<string, unknown>,
110+
priority: message.priority,
111+
timestamp: Date.now(),
112+
};
113+
}
114+
}
115+
116+
private async handleIndex(options?: GitHubIndexOptions): Promise<GitHubContextResult> {
117+
const stats = await this.indexer!.index(options);
118+
return {
119+
action: 'index',
120+
stats,
121+
};
122+
}
123+
124+
private async handleSearch(
125+
query: string,
126+
options?: { limit?: number }
127+
): Promise<GitHubContextResult> {
128+
const results = await this.indexer!.search(query, options);
129+
return {
130+
action: 'search',
131+
results,
132+
};
133+
}
134+
135+
private async handleGetContext(issueNumber: number): Promise<GitHubContextResult> {
136+
const context = await this.indexer!.getContext(issueNumber);
137+
return {
138+
action: 'context',
139+
context: context || undefined,
140+
};
141+
}
142+
143+
private async handleFindRelated(issueNumber: number): Promise<GitHubContextResult> {
144+
const related = await this.indexer!.findRelated(issueNumber);
145+
return {
146+
action: 'related',
147+
related,
148+
};
149+
}
150+
151+
async healthCheck(): Promise<boolean> {
152+
return this.indexer !== undefined;
153+
}
154+
155+
async shutdown(): Promise<void> {
156+
if (this.context) {
157+
this.context.logger.info('GitHub agent shutting down');
158+
}
159+
this.indexer = undefined;
160+
}
161+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
/**
2+
* GitHub Context Subagent
3+
* Index and search GitHub issues, PRs, and discussions
4+
*/
5+
6+
export type { GitHubAgentConfig } from './agent';
7+
export { GitHubAgent } from './agent';
8+
export { GitHubIndexer } from './indexer';
9+
export * from './types';
10+
export * from './utils';

packages/subagents/src/index.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,12 @@ export type {
3131
SimilarCodeRequest,
3232
SimilarCodeResult,
3333
} from './explorer/types';
34-
// GitHub Context
35-
export { GitHubIndexer } from './github/indexer.js';
34+
export type { GitHubAgentConfig } from './github/agent';
35+
// GitHub Context Agent
36+
export { GitHubAgent } from './github/agent';
37+
export { GitHubIndexer } from './github/indexer';
3638
export type * from './github/types';
37-
export * from './github/utils/index.js';
39+
export * from './github/utils';
3840
// Logger module
3941
export { CoordinatorLogger } from './logger';
4042
// Agent modules

0 commit comments

Comments
 (0)