data fixes, partial custom indicator support
This commit is contained in:
92
gateway/src/harness/subagents/web-explore/index.ts
Normal file
92
gateway/src/harness/subagents/web-explore/index.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import { BaseSubagent, type SubagentConfig, type SubagentContext } from '../base-subagent.js';
|
||||
import type { BaseChatModel } from '@langchain/core/language_models/chat_models';
|
||||
import { SystemMessage } from '@langchain/core/messages';
|
||||
import { createReactAgent } from '@langchain/langgraph/prebuilt';
|
||||
import type { FastifyBaseLogger } from 'fastify';
|
||||
|
||||
/**
|
||||
* Web Explore Subagent
|
||||
*
|
||||
* Accepts a research instruction, searches the web (DuckDuckGo) or arXiv
|
||||
* for academic queries, fetches relevant page/PDF content, and returns a
|
||||
* markdown summary with cited sources.
|
||||
*
|
||||
* No MCP client needed — operates entirely through platform tools.
|
||||
*/
|
||||
export class WebExploreSubagent extends BaseSubagent {
|
||||
constructor(
|
||||
config: SubagentConfig,
|
||||
model: BaseChatModel,
|
||||
logger: FastifyBaseLogger,
|
||||
tools?: any[]
|
||||
) {
|
||||
super(config, model, logger, undefined, tools);
|
||||
}
|
||||
|
||||
async execute(context: SubagentContext, instruction: string): Promise<string> {
|
||||
this.logger.info(
|
||||
{
|
||||
subagent: this.getName(),
|
||||
userId: context.userContext.userId,
|
||||
instruction: instruction.substring(0, 200),
|
||||
toolCount: this.tools.length,
|
||||
toolNames: this.tools.map(t => t.name),
|
||||
},
|
||||
'Web explore subagent starting'
|
||||
);
|
||||
|
||||
const initialMessages = this.buildMessages(context, instruction);
|
||||
const systemMessage = initialMessages[0];
|
||||
const humanMessage = initialMessages[initialMessages.length - 1];
|
||||
|
||||
const agent = createReactAgent({
|
||||
llm: this.model,
|
||||
tools: this.tools,
|
||||
prompt: systemMessage as SystemMessage,
|
||||
});
|
||||
|
||||
const result = await agent.invoke(
|
||||
{ messages: [humanMessage] },
|
||||
{ recursionLimit: 15 }
|
||||
);
|
||||
|
||||
const allMessages: any[] = result.messages ?? [];
|
||||
|
||||
this.logger.info({ messageCount: allMessages.length }, 'Web explore subagent graph completed');
|
||||
|
||||
const lastAI = [...allMessages].reverse().find(
|
||||
(m: any) => m.constructor?.name === 'AIMessage' || m._getType?.() === 'ai'
|
||||
);
|
||||
|
||||
const finalText = lastAI
|
||||
? (typeof lastAI.content === 'string' ? lastAI.content : JSON.stringify(lastAI.content))
|
||||
: 'No results found.';
|
||||
|
||||
this.logger.info({ textLength: finalText.length }, 'Web explore subagent finished');
|
||||
|
||||
return finalText;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory function to create and initialize WebExploreSubagent
|
||||
*/
|
||||
export async function createWebExploreSubagent(
|
||||
model: BaseChatModel,
|
||||
logger: FastifyBaseLogger,
|
||||
basePath: string,
|
||||
tools?: any[]
|
||||
): Promise<WebExploreSubagent> {
|
||||
const { readFile } = await import('fs/promises');
|
||||
const { join } = await import('path');
|
||||
const yaml = await import('js-yaml');
|
||||
|
||||
const configPath = join(basePath, 'config.yaml');
|
||||
const configContent = await readFile(configPath, 'utf-8');
|
||||
const config = yaml.load(configContent) as SubagentConfig;
|
||||
|
||||
const subagent = new WebExploreSubagent(config, model, logger, tools);
|
||||
await subagent.initialize(basePath);
|
||||
|
||||
return subagent;
|
||||
}
|
||||
Reference in New Issue
Block a user