data fixes, partial custom indicator support

This commit is contained in:
2026-04-08 21:28:31 -04:00
parent b701554996
commit a70dcd954f
81 changed files with 5438 additions and 1852 deletions

View 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;
}