673 lines
24 KiB
TypeScript
673 lines
24 KiB
TypeScript
import { ToolDef } from '../../llm/openai-compat.js';
|
|
import { logger } from '../../logger.js';
|
|
import {
|
|
ToolContext,
|
|
ToolResult,
|
|
ToolsConfig,
|
|
ALL_TOOL_DEFS,
|
|
getToolDefs as getCoreToolDefs,
|
|
executeCoreTools,
|
|
} from './core.js';
|
|
import { saveRawData, logRawDownload, RAW_SAVE_TOOLS, RAW_LOG_ONLY_TOOLS } from './raw-save.js';
|
|
import { saveStructuredBlocks } from './structured-blocks.js';
|
|
import type { McpAggregator } from '../../mcp/aggregator.js';
|
|
import type { McpRuntimeConfig } from '../../mcp/config.js';
|
|
|
|
export type { ToolContext, ToolResult, ToolsConfig };
|
|
|
|
let _mcpAggregator: McpAggregator | null = null;
|
|
export function setMcpAggregator(agg: McpAggregator | null): void {
|
|
_mcpAggregator = agg;
|
|
}
|
|
|
|
type ExecuteCtxWithMcp = ToolContext & {
|
|
ownerId?: string | null;
|
|
jobId?: string | null;
|
|
mcpConfig?: McpRuntimeConfig;
|
|
mcpQuotaState?: { files: number; bytes: number };
|
|
};
|
|
|
|
// 外部モジュール(他チームが実装)のインターフェース型
|
|
interface ToolModule {
|
|
TOOL_DEFS: Record<string, ToolDef>;
|
|
executeTool(name: string, input: Record<string, unknown>, ctx: ToolContext): Promise<ToolResult | null>;
|
|
}
|
|
|
|
// 外部モジュールを動的にロード(存在しない場合は null)
|
|
async function tryLoadModule(specifier: string): Promise<ToolModule | null> {
|
|
try {
|
|
const mod = await import(specifier) as ToolModule;
|
|
return mod;
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
// 外部モジュールのキャッシュ
|
|
let _webModule: ToolModule | null | undefined = undefined;
|
|
let _imageModule: ToolModule | null | undefined = undefined;
|
|
let _dataModule: ToolModule | null | undefined = undefined;
|
|
let _officeModule: ToolModule | null | undefined = undefined;
|
|
let _reviewModule: ToolModule | null | undefined = undefined;
|
|
let _xModule: ToolModule | null | undefined = undefined;
|
|
let _orchestrationModule: ToolModule | null | undefined = undefined;
|
|
let _browserModule: ToolModule | null | undefined = undefined;
|
|
let _mapsModule: ToolModule | null | undefined = undefined;
|
|
let _youtubeModule: ToolModule | null | undefined = undefined;
|
|
let _piecesModule: ToolModule | null | undefined = undefined;
|
|
let _amazonModule: ToolModule | null | undefined = undefined;
|
|
let _speechModule: ToolModule | null | undefined = undefined;
|
|
let _checklistModule: ToolModule | null | undefined = undefined;
|
|
let _knowledgeModule: ToolModule | null | undefined = undefined;
|
|
let _msLearnModule: ToolModule | null | undefined = undefined;
|
|
let _slideModule: ToolModule | null | undefined = undefined;
|
|
let _userFolderModule: ToolModule | null | undefined = undefined;
|
|
|
|
async function getWebModule(): Promise<ToolModule | null> {
|
|
if (_webModule === undefined) {
|
|
_webModule = await tryLoadModule('./web.js');
|
|
if (_webModule) logger.debug('[tools/index] web module loaded');
|
|
}
|
|
return _webModule;
|
|
}
|
|
|
|
async function getImageModule(): Promise<ToolModule | null> {
|
|
if (_imageModule === undefined) {
|
|
_imageModule = await tryLoadModule('./image.js');
|
|
if (_imageModule) logger.debug('[tools/index] image module loaded');
|
|
}
|
|
return _imageModule;
|
|
}
|
|
|
|
async function getDataModule(): Promise<ToolModule | null> {
|
|
if (_dataModule === undefined) {
|
|
_dataModule = await tryLoadModule('./data.js');
|
|
if (_dataModule) logger.debug('[tools/index] data module loaded');
|
|
}
|
|
return _dataModule;
|
|
}
|
|
|
|
async function getOfficeModule(): Promise<ToolModule | null> {
|
|
if (_officeModule === undefined) {
|
|
_officeModule = await tryLoadModule('./office.js');
|
|
if (_officeModule) logger.debug('[tools/index] office module loaded');
|
|
}
|
|
return _officeModule;
|
|
}
|
|
|
|
async function getReviewModule(): Promise<ToolModule | null> {
|
|
if (_reviewModule === undefined) {
|
|
_reviewModule = await tryLoadModule('./review.js');
|
|
if (_reviewModule) logger.debug('[tools/index] review module loaded');
|
|
}
|
|
return _reviewModule;
|
|
}
|
|
|
|
async function getXModule(): Promise<ToolModule | null> {
|
|
if (_xModule === undefined) {
|
|
_xModule = await tryLoadModule('./x.js');
|
|
if (_xModule) logger.debug('[tools/index] x module loaded');
|
|
}
|
|
return _xModule;
|
|
}
|
|
|
|
async function getOrchestrationModule(): Promise<ToolModule | null> {
|
|
if (_orchestrationModule === undefined) {
|
|
_orchestrationModule = await tryLoadModule('./orchestration.js');
|
|
if (_orchestrationModule) logger.debug('[tools/index] orchestration module loaded');
|
|
}
|
|
return _orchestrationModule;
|
|
}
|
|
|
|
async function getBrowserModule(): Promise<ToolModule | null> {
|
|
if (_browserModule === undefined) {
|
|
_browserModule = await tryLoadModule('./browser.js');
|
|
if (_browserModule) logger.debug('[tools/index] browser module loaded');
|
|
}
|
|
return _browserModule;
|
|
}
|
|
|
|
async function getMapsModule(): Promise<ToolModule | null> {
|
|
if (_mapsModule === undefined) {
|
|
_mapsModule = await tryLoadModule('./maps.js');
|
|
if (_mapsModule) logger.debug('[tools/index] maps module loaded');
|
|
}
|
|
return _mapsModule;
|
|
}
|
|
|
|
async function getYoutubeModule(): Promise<ToolModule | null> {
|
|
if (_youtubeModule === undefined) {
|
|
_youtubeModule = await tryLoadModule('./youtube.js');
|
|
if (_youtubeModule) logger.debug('[tools/index] youtube module loaded');
|
|
}
|
|
return _youtubeModule;
|
|
}
|
|
|
|
async function getPiecesModule(): Promise<ToolModule | null> {
|
|
if (_piecesModule === undefined) {
|
|
_piecesModule = await tryLoadModule('./pieces.js');
|
|
if (_piecesModule) logger.debug('[tools/index] pieces module loaded');
|
|
}
|
|
return _piecesModule;
|
|
}
|
|
|
|
async function getAmazonModule(): Promise<ToolModule | null> {
|
|
if (_amazonModule === undefined) {
|
|
_amazonModule = await tryLoadModule('./amazon.js');
|
|
if (_amazonModule) logger.debug('[tools/index] amazon module loaded');
|
|
}
|
|
return _amazonModule;
|
|
}
|
|
|
|
async function getSpeechModule(): Promise<ToolModule | null> {
|
|
if (_speechModule === undefined) {
|
|
_speechModule = await tryLoadModule('./speech.js');
|
|
if (_speechModule) logger.debug('[tools/index] speech module loaded');
|
|
}
|
|
return _speechModule;
|
|
}
|
|
|
|
async function getChecklistModule(): Promise<ToolModule | null> {
|
|
if (_checklistModule === undefined) {
|
|
_checklistModule = await tryLoadModule('./checklist.js');
|
|
if (_checklistModule) logger.debug('[tools/index] checklist module loaded');
|
|
}
|
|
return _checklistModule;
|
|
}
|
|
|
|
async function getKnowledgeModule(): Promise<ToolModule | null> {
|
|
if (_knowledgeModule === undefined) {
|
|
_knowledgeModule = await tryLoadModule('./knowledge.js');
|
|
if (_knowledgeModule) logger.debug('[tools/index] knowledge module loaded');
|
|
}
|
|
return _knowledgeModule;
|
|
}
|
|
|
|
async function getSlideModule(): Promise<ToolModule | null> {
|
|
if (_slideModule === undefined) {
|
|
_slideModule = await tryLoadModule('./slide.js');
|
|
if (_slideModule) logger.debug('[tools/index] slide module loaded');
|
|
}
|
|
return _slideModule;
|
|
}
|
|
|
|
async function getMsLearnModule(): Promise<ToolModule | null> {
|
|
if (_msLearnModule === undefined) {
|
|
_msLearnModule = await tryLoadModule('./ms-learn.js');
|
|
if (_msLearnModule) logger.debug('[tools/index] ms-learn module loaded');
|
|
}
|
|
return _msLearnModule;
|
|
}
|
|
|
|
let _docsModule: ToolModule | null | undefined;
|
|
async function getDocsModule(): Promise<ToolModule | null> {
|
|
if (_docsModule === undefined) {
|
|
_docsModule = await tryLoadModule('./docs.js');
|
|
if (_docsModule) logger.debug('[tools/index] docs module loaded');
|
|
}
|
|
return _docsModule;
|
|
}
|
|
|
|
let _missionModule: ToolModule | null | undefined;
|
|
async function getMissionModule(): Promise<ToolModule | null> {
|
|
if (_missionModule === undefined) {
|
|
_missionModule = await tryLoadModule('./mission.js');
|
|
if (_missionModule) logger.debug('[tools/index] mission module loaded');
|
|
}
|
|
return _missionModule;
|
|
}
|
|
|
|
async function getUserFolderModule(): Promise<ToolModule | null> {
|
|
if (_userFolderModule === undefined) {
|
|
_userFolderModule = await tryLoadModule('./user-folder.js');
|
|
if (_userFolderModule) logger.debug('[tools/index] user-folder module loaded');
|
|
}
|
|
return _userFolderModule;
|
|
}
|
|
|
|
let _brainstormModule: ToolModule | null | undefined;
|
|
async function getBrainstormModule(): Promise<ToolModule | null> {
|
|
if (_brainstormModule === undefined) {
|
|
_brainstormModule = await tryLoadModule('./brainstorm.js');
|
|
if (_brainstormModule) logger.debug('[tools/index] brainstorm module loaded');
|
|
}
|
|
return _brainstormModule;
|
|
}
|
|
|
|
let _appDocsModule: ToolModule | null | undefined;
|
|
async function getAppDocsModule(): Promise<ToolModule | null> {
|
|
if (_appDocsModule === undefined) {
|
|
_appDocsModule = await tryLoadModule('./app-docs.js');
|
|
if (_appDocsModule) logger.debug('[tools/index] app-docs module loaded');
|
|
}
|
|
return _appDocsModule;
|
|
}
|
|
|
|
let _sshModule: ToolModule | null | undefined;
|
|
async function getSshModule(): Promise<ToolModule | null> {
|
|
if (_sshModule === undefined) {
|
|
_sshModule = await tryLoadModule('./ssh.js');
|
|
if (_sshModule) logger.debug('[tools/index] ssh module loaded');
|
|
}
|
|
return _sshModule;
|
|
}
|
|
|
|
let _sshConsoleModule: ToolModule | null | undefined;
|
|
async function getSshConsoleModule(): Promise<ToolModule | null> {
|
|
if (_sshConsoleModule === undefined) {
|
|
_sshConsoleModule = await tryLoadModule('./ssh-console.js');
|
|
if (_sshConsoleModule) logger.debug('[tools/index] ssh-console module loaded');
|
|
}
|
|
return _sshConsoleModule;
|
|
}
|
|
|
|
let _notesModule: ToolModule | null | undefined;
|
|
async function getNotesModule(): Promise<ToolModule | null> {
|
|
if (_notesModule === undefined) {
|
|
_notesModule = await tryLoadModule('./notes.js');
|
|
if (_notesModule) logger.debug('[tools/index] notes module loaded');
|
|
}
|
|
return _notesModule;
|
|
}
|
|
|
|
let _dashboardModule: ToolModule | null | undefined = undefined;
|
|
async function getDashboardModule(): Promise<ToolModule | null> {
|
|
if (_dashboardModule === undefined) {
|
|
_dashboardModule = await tryLoadModule('./dashboard.js');
|
|
if (_dashboardModule) logger.debug('[tools/index] dashboard module loaded');
|
|
}
|
|
return _dashboardModule;
|
|
}
|
|
|
|
/**
|
|
* 全モジュールのツール定義を統合して返す。
|
|
* allowedTools と editAllowed に応じてフィルタリングする。
|
|
*/
|
|
export async function getToolDefs(
|
|
allowedTools: string[],
|
|
editAllowed: boolean,
|
|
options?: { vlmEnabled?: boolean; ownerId?: string | null; mcpDisabled?: boolean },
|
|
): Promise<ToolDef[]> {
|
|
// 全ツール定義を収集
|
|
const allDefs: Record<string, ToolDef> = { ...ALL_TOOL_DEFS };
|
|
|
|
const webMod = await getWebModule();
|
|
if (webMod) Object.assign(allDefs, webMod.TOOL_DEFS);
|
|
|
|
const imageMod = await getImageModule();
|
|
if (imageMod) Object.assign(allDefs, imageMod.TOOL_DEFS);
|
|
|
|
const dataMod = await getDataModule();
|
|
if (dataMod) Object.assign(allDefs, dataMod.TOOL_DEFS);
|
|
|
|
const officeMod = await getOfficeModule();
|
|
if (officeMod) Object.assign(allDefs, officeMod.TOOL_DEFS);
|
|
|
|
const reviewMod = await getReviewModule();
|
|
if (reviewMod) Object.assign(allDefs, reviewMod.TOOL_DEFS);
|
|
|
|
const xMod = await getXModule();
|
|
if (xMod) Object.assign(allDefs, xMod.TOOL_DEFS);
|
|
|
|
const orchestrationMod = await getOrchestrationModule();
|
|
if (orchestrationMod) Object.assign(allDefs, orchestrationMod.TOOL_DEFS);
|
|
|
|
const browserMod = await getBrowserModule();
|
|
if (browserMod) Object.assign(allDefs, browserMod.TOOL_DEFS);
|
|
|
|
const mapsMod = await getMapsModule();
|
|
if (mapsMod) Object.assign(allDefs, mapsMod.TOOL_DEFS);
|
|
|
|
const youtubeMod = await getYoutubeModule();
|
|
if (youtubeMod) Object.assign(allDefs, youtubeMod.TOOL_DEFS);
|
|
|
|
const piecesMod = await getPiecesModule();
|
|
if (piecesMod) Object.assign(allDefs, piecesMod.TOOL_DEFS);
|
|
|
|
const amazonMod = await getAmazonModule();
|
|
if (amazonMod) Object.assign(allDefs, amazonMod.TOOL_DEFS);
|
|
|
|
const speechMod = await getSpeechModule();
|
|
if (speechMod) Object.assign(allDefs, speechMod.TOOL_DEFS);
|
|
|
|
const checklistMod = await getChecklistModule();
|
|
if (checklistMod) Object.assign(allDefs, checklistMod.TOOL_DEFS);
|
|
|
|
const knowledgeMod = await getKnowledgeModule();
|
|
if (knowledgeMod) Object.assign(allDefs, knowledgeMod.TOOL_DEFS);
|
|
|
|
const msLearnMod = await getMsLearnModule();
|
|
if (msLearnMod) Object.assign(allDefs, msLearnMod.TOOL_DEFS);
|
|
|
|
const slideMod = await getSlideModule();
|
|
if (slideMod) Object.assign(allDefs, slideMod.TOOL_DEFS);
|
|
|
|
const docsMod = await getDocsModule();
|
|
if (docsMod) Object.assign(allDefs, docsMod.TOOL_DEFS);
|
|
|
|
const missionMod = await getMissionModule();
|
|
if (missionMod) Object.assign(allDefs, missionMod.TOOL_DEFS);
|
|
|
|
const userFolderMod = await getUserFolderModule();
|
|
if (userFolderMod) Object.assign(allDefs, userFolderMod.TOOL_DEFS);
|
|
|
|
const brainstormMod = await getBrainstormModule();
|
|
if (brainstormMod) Object.assign(allDefs, brainstormMod.TOOL_DEFS);
|
|
|
|
const appDocsMod = await getAppDocsModule();
|
|
if (appDocsMod) Object.assign(allDefs, appDocsMod.TOOL_DEFS);
|
|
|
|
const sshMod = await getSshModule();
|
|
if (sshMod) Object.assign(allDefs, sshMod.TOOL_DEFS);
|
|
|
|
const sshConsoleMod = await getSshConsoleModule();
|
|
if (sshConsoleMod) Object.assign(allDefs, sshConsoleMod.TOOL_DEFS);
|
|
|
|
const notesMod = await getNotesModule();
|
|
if (notesMod) Object.assign(allDefs, notesMod.TOOL_DEFS);
|
|
|
|
const dashboardMod = await getDashboardModule();
|
|
if (dashboardMod) Object.assign(allDefs, dashboardMod.TOOL_DEFS);
|
|
|
|
const { TOOL_DEFS: skillToolDefs } = await import('./skills.js');
|
|
Object.assign(allDefs, skillToolDefs);
|
|
|
|
// メタツール: piece の allowed_tools に書かれていなくても常に利用可能
|
|
// - ReadToolDoc: 全ツールのドキュメント参照
|
|
// - CreateChecklist / CheckItem / GetChecklist: 進捗管理 (複数ステップタスクで使用)
|
|
// - MissionUpdate: タスクの目標 / 進捗のピン止めメモを更新 (会話が長くなって
|
|
// 最初の要件を見失わないため。常時上書き可能、未指定フィールドは保持)
|
|
// - ListUserAssets / RunUserScript: ユーザーフォルダのスクリプト探索・実行
|
|
// - Brainstorm: 着手前 or 行き詰まり時の多アプローチ比較 (issue #247)
|
|
// - ReadAppDoc / ListAppDocs / GetMyOrchestratorState: Help アシスタント用 (#help piece)
|
|
// ただし他の piece からも参照できるようにメタ扱い
|
|
const META_TOOLS = ['ReadToolDoc', 'CreateChecklist', 'CheckItem', 'GetChecklist', 'MissionUpdate', 'ListUserAssets', 'RunUserScript', 'UpdateUserMemory', 'ReadUserMemory', 'ReadUserTemplate', 'RenderUserTemplate', 'WriteUserScript', 'WriteUserTemplate', 'Brainstorm', 'ReadAppDoc', 'ListAppDocs', 'GetMyOrchestratorState', 'ReadSkill', 'ListSkills', 'InstallSkill'];
|
|
const effectiveAllowed = [...allowedTools];
|
|
for (const meta of META_TOOLS) {
|
|
if (!effectiveAllowed.includes(meta) && meta in allDefs) {
|
|
effectiveAllowed.push(meta);
|
|
}
|
|
}
|
|
|
|
const staticDefs = effectiveAllowed
|
|
.filter((name) => {
|
|
if (!editAllowed && (name === 'Write' || name === 'Edit')) return false;
|
|
if (!options?.vlmEnabled && name === 'ReadImage') return false;
|
|
return name in allDefs;
|
|
})
|
|
.map((name) => allDefs[name]!);
|
|
|
|
const mcpDefs =
|
|
_mcpAggregator && options?.ownerId && !options?.mcpDisabled
|
|
? await _mcpAggregator.getToolDefs(options.ownerId, allowedTools)
|
|
: [];
|
|
|
|
return [...staticDefs, ...mcpDefs];
|
|
}
|
|
|
|
/**
|
|
* ツールを実行する内部ルーター。
|
|
* core → web → image → data の順で各モジュールに委譲し、
|
|
* 最初に null でない結果を返したモジュールの結果を使う。
|
|
*/
|
|
async function executeToolInner(
|
|
name: string,
|
|
input: Record<string, unknown>,
|
|
ctx: ToolContext,
|
|
): Promise<ToolResult> {
|
|
if (name.startsWith('mcp__')) {
|
|
if (ctx.mcpDisabled) {
|
|
return { output: 'MCP tools are disabled for this task (options.mcpDisabled)', isError: true };
|
|
}
|
|
if (!_mcpAggregator) {
|
|
return { output: 'MCP サブシステムが初期化されていません', isError: true };
|
|
}
|
|
const ctxWithMcp = ctx as ExecuteCtxWithMcp;
|
|
if (!ctxWithMcp.mcpQuotaState) {
|
|
ctxWithMcp.mcpQuotaState = { files: 0, bytes: 0 };
|
|
}
|
|
if (!ctxWithMcp.mcpConfig) {
|
|
return { output: 'MCP 設定が ToolContext に伝播していません', isError: true };
|
|
}
|
|
const result = await _mcpAggregator.executeTool(name, input, {
|
|
workspacePath: ctx.workspacePath,
|
|
ownerId: ctxWithMcp.ownerId ?? '',
|
|
jobId: ctxWithMcp.jobId ?? '',
|
|
config: ctxWithMcp.mcpConfig,
|
|
quotaState: ctxWithMcp.mcpQuotaState,
|
|
});
|
|
if (result === null) {
|
|
return { output: `MCP ツール dispatch が ${name} に対して null を返しました`, isError: true };
|
|
}
|
|
return { output: result.output, isError: result.isError };
|
|
}
|
|
|
|
// core ツール
|
|
const coreResult = await executeCoreTools(name, input, ctx);
|
|
if (coreResult !== null) return coreResult;
|
|
|
|
// web ツール
|
|
const webMod = await getWebModule();
|
|
if (webMod) {
|
|
const webResult = await webMod.executeTool(name, input, ctx);
|
|
if (webResult !== null) return webResult;
|
|
}
|
|
|
|
// image ツール
|
|
const imageMod = await getImageModule();
|
|
if (imageMod) {
|
|
const imageResult = await imageMod.executeTool(name, input, ctx);
|
|
if (imageResult !== null) return imageResult;
|
|
}
|
|
|
|
// data ツール
|
|
const dataMod = await getDataModule();
|
|
if (dataMod) {
|
|
const dataResult = await dataMod.executeTool(name, input, ctx);
|
|
if (dataResult !== null) return dataResult;
|
|
}
|
|
|
|
// office ツール
|
|
const officeMod = await getOfficeModule();
|
|
if (officeMod) {
|
|
const officeResult = await officeMod.executeTool(name, input, ctx);
|
|
if (officeResult !== null) return officeResult;
|
|
}
|
|
|
|
// review ツール
|
|
const reviewMod = await getReviewModule();
|
|
if (reviewMod) {
|
|
const reviewResult = await reviewMod.executeTool(name, input, ctx);
|
|
if (reviewResult !== null) return reviewResult;
|
|
}
|
|
|
|
// x tools
|
|
const xMod = await getXModule();
|
|
if (xMod) {
|
|
const xResult = await xMod.executeTool(name, input, ctx);
|
|
if (xResult !== null) return xResult;
|
|
}
|
|
|
|
// orchestration ツール
|
|
const orchestrationMod = await getOrchestrationModule();
|
|
if (orchestrationMod) {
|
|
const orchestrationResult = await orchestrationMod.executeTool(name, input, ctx);
|
|
if (orchestrationResult !== null) return orchestrationResult;
|
|
}
|
|
|
|
// browser ツール
|
|
const browserMod = await getBrowserModule();
|
|
if (browserMod) {
|
|
const browserResult = await browserMod.executeTool(name, input, ctx);
|
|
if (browserResult !== null) return browserResult;
|
|
}
|
|
|
|
// maps ツール
|
|
const mapsMod = await getMapsModule();
|
|
if (mapsMod) {
|
|
const mapsResult = await mapsMod.executeTool(name, input, ctx);
|
|
if (mapsResult !== null) return mapsResult;
|
|
}
|
|
|
|
// youtube ツール
|
|
const youtubeMod = await getYoutubeModule();
|
|
if (youtubeMod) {
|
|
const youtubeResult = await youtubeMod.executeTool(name, input, ctx);
|
|
if (youtubeResult !== null) return youtubeResult;
|
|
}
|
|
|
|
// pieces ツール
|
|
const piecesMod = await getPiecesModule();
|
|
if (piecesMod) {
|
|
const piecesResult = await piecesMod.executeTool(name, input, ctx);
|
|
if (piecesResult !== null) return piecesResult;
|
|
}
|
|
|
|
// amazon ツール
|
|
const amazonMod = await getAmazonModule();
|
|
if (amazonMod) {
|
|
const amazonResult = await amazonMod.executeTool(name, input, ctx);
|
|
if (amazonResult !== null) return amazonResult;
|
|
}
|
|
|
|
// speech ツール
|
|
const speechMod = await getSpeechModule();
|
|
if (speechMod) {
|
|
const speechResult = await speechMod.executeTool(name, input, ctx);
|
|
if (speechResult !== null) return speechResult;
|
|
}
|
|
|
|
// checklist ツール
|
|
const checklistMod = await getChecklistModule();
|
|
if (checklistMod) {
|
|
const checklistResult = await checklistMod.executeTool(name, input, ctx);
|
|
if (checklistResult !== null) return checklistResult;
|
|
}
|
|
|
|
// knowledge ツール
|
|
const knowledgeMod = await getKnowledgeModule();
|
|
if (knowledgeMod) {
|
|
const knowledgeResult = await knowledgeMod.executeTool(name, input, ctx);
|
|
if (knowledgeResult !== null) return knowledgeResult;
|
|
}
|
|
|
|
// ms-learn ツール
|
|
const msLearnMod = await getMsLearnModule();
|
|
if (msLearnMod) {
|
|
const msLearnResult = await msLearnMod.executeTool(name, input, ctx);
|
|
if (msLearnResult !== null) return msLearnResult;
|
|
}
|
|
|
|
// slide ツール (SetTheme / AddSlide / BuildPptx / ResetSlides)
|
|
const slideMod = await getSlideModule();
|
|
if (slideMod) {
|
|
const slideResult = await slideMod.executeTool(name, input, ctx);
|
|
if (slideResult !== null) return slideResult;
|
|
}
|
|
|
|
// docs ツール (ReadToolDoc)
|
|
const docsMod = await getDocsModule();
|
|
if (docsMod) {
|
|
const docsResult = await docsMod.executeTool(name, input, ctx);
|
|
if (docsResult !== null) return docsResult;
|
|
}
|
|
|
|
// mission ツール (MissionUpdate)
|
|
const missionMod = await getMissionModule();
|
|
if (missionMod) {
|
|
const missionResult = await missionMod.executeTool(name, input, ctx);
|
|
if (missionResult !== null) return missionResult;
|
|
}
|
|
|
|
// user-folder ツール (ListUserAssets / RunUserScript)
|
|
const userFolderMod = await getUserFolderModule();
|
|
if (userFolderMod) {
|
|
const userFolderResult = await userFolderMod.executeTool(name, input, ctx);
|
|
if (userFolderResult !== null) return userFolderResult;
|
|
}
|
|
|
|
// brainstorm ツール (Brainstorm)
|
|
const brainstormMod = await getBrainstormModule();
|
|
if (brainstormMod) {
|
|
const brainstormResult = await brainstormMod.executeTool(name, input, ctx);
|
|
if (brainstormResult !== null) return brainstormResult;
|
|
}
|
|
|
|
// app-docs ツール (ReadAppDoc / ListAppDocs / GetMyOrchestratorState)
|
|
const appDocsMod = await getAppDocsModule();
|
|
if (appDocsMod) {
|
|
const appDocsResult = await appDocsMod.executeTool(name, input, ctx);
|
|
if (appDocsResult !== null) return appDocsResult;
|
|
}
|
|
|
|
// ssh ツール (SshExec / SshUpload / SshDownload)
|
|
const sshMod = await getSshModule();
|
|
if (sshMod) {
|
|
const sshResult = await sshMod.executeTool(name, input, ctx);
|
|
if (sshResult !== null) return sshResult;
|
|
}
|
|
|
|
// ssh-console ツール (SshConsoleEnsure / Send / Snapshot)
|
|
const sshConsoleMod = await getSshConsoleModule();
|
|
if (sshConsoleMod) {
|
|
const sshConsoleResult = await sshConsoleMod.executeTool(name, input, ctx);
|
|
if (sshConsoleResult !== null) return sshConsoleResult;
|
|
}
|
|
|
|
// notes ツール (SearchNotes / ReadNote / WriteNote)
|
|
const notesMod = await getNotesModule();
|
|
if (notesMod) {
|
|
const notesResult = await notesMod.executeTool(name, input, ctx);
|
|
if (notesResult !== null) return notesResult;
|
|
}
|
|
|
|
// dashboard ツール (UpdateDashboardWidget)
|
|
const dashboardMod = await getDashboardModule();
|
|
if (dashboardMod) {
|
|
const dashboardResult = await dashboardMod.executeTool(name, input, ctx);
|
|
if (dashboardResult !== null) return dashboardResult;
|
|
}
|
|
|
|
// skills ツール (ReadSkill)
|
|
const { executeSkillTool } = await import('./skills.js');
|
|
const skillResult = executeSkillTool(name, input, ctx);
|
|
if (skillResult !== null) return skillResult;
|
|
|
|
return { output: `Unknown tool: ${name}`, isError: true };
|
|
}
|
|
|
|
/**
|
|
* ツールを実行するルーター(生データ自動保存ラッパー付き)。
|
|
* executeToolInner に委譲した後、成功した対象ツールの結果を logs/raw/ に保存する。
|
|
*/
|
|
export async function executeTool(
|
|
name: string,
|
|
input: Record<string, unknown>,
|
|
ctx: ToolContext,
|
|
): Promise<ToolResult> {
|
|
logger.debug(`[tools/index] executing ${name}`);
|
|
|
|
const result = await executeToolInner(name, input, ctx);
|
|
|
|
// raw保存ラッパー: 成功した対象ツールの結果を logs/raw/ に保存
|
|
if (ctx.workspacePath && !result.isError) {
|
|
if (RAW_SAVE_TOOLS.has(name)) {
|
|
saveRawData(ctx.workspacePath, name, result.output);
|
|
} else if (RAW_LOG_ONLY_TOOLS.has(name)) {
|
|
const pathMatch = result.output.match(/-> (.+?) \(/);
|
|
if (pathMatch?.[1]) {
|
|
logRawDownload(ctx.workspacePath, name, pathMatch[1], result.output.length);
|
|
}
|
|
}
|
|
// 構造化データ保存: structuredBlocks があれば logs/structured/ に保存
|
|
if (result.structuredBlocks?.length) {
|
|
saveStructuredBlocks(ctx.workspacePath, result.structuredBlocks);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// 同期版 getToolDefs のラッパー(後方互換のため、コアツールのみを返す同期版)
|
|
export { getCoreToolDefs as getCoreToolDefs };
|