upgrade taskloop
This commit is contained in:
parent
50510ae647
commit
51ceacbc10
@ -3,11 +3,11 @@ import * as fs from 'node:fs';
|
|||||||
const targetFile = './openmcp-sdk/task-loop.js';
|
const targetFile = './openmcp-sdk/task-loop.js';
|
||||||
|
|
||||||
if (fs.existsSync(targetFile)) {
|
if (fs.existsSync(targetFile)) {
|
||||||
let content = fs.readFileSync(targetFile, 'utf8');
|
let content = fs.readFileSync(targetFile, 'utf-8');
|
||||||
|
|
||||||
// Replace element-plus with ./tools.js
|
// Replace element-plus with ./tools.js
|
||||||
content = content.replace(/'element-plus'/g, "'./tools.js'");
|
content = content.replace(/'element-plus'/g, "'./tools.mjs'");
|
||||||
content = content.replace(/"element-plus"/g, "\"./tools.js\"");
|
content = content.replace(/"element-plus"/g, "\"./tools.mjs\"");
|
||||||
|
|
||||||
// content = content.replace(/const chalk = require\("chalk"\);/g, 'const chalk = require("chalk").default;');
|
// content = content.replace(/const chalk = require\("chalk"\);/g, 'const chalk = require("chalk").default;');
|
||||||
|
|
||||||
|
@ -34,6 +34,8 @@ export interface IErrorMssage {
|
|||||||
msg: string
|
msg: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export { MessageState };
|
||||||
|
|
||||||
export interface IDoConversationResult {
|
export interface IDoConversationResult {
|
||||||
stop: boolean;
|
stop: boolean;
|
||||||
}
|
}
|
||||||
@ -83,12 +85,18 @@ export class TaskLoop {
|
|||||||
throw new Error('adapter is required');
|
throw new Error('adapter is required');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 根据 adapter 创建 nodejs 下特殊的、基于 event 的 message bridge (不占用任何端口)
|
||||||
createMessageBridge(adapter.emitter);
|
createMessageBridge(adapter.emitter);
|
||||||
|
|
||||||
|
// 用于进行连接同步
|
||||||
this.nodejsStatus.connectionFut = mcpClientAdapter.launch();
|
this.nodejsStatus.connectionFut = mcpClientAdapter.launch();
|
||||||
}
|
}
|
||||||
|
|
||||||
// web 环境下 bridge 会自动加载完成
|
// web 环境下 bridge 会自动加载完成
|
||||||
this.bridge = useMessageBridge();
|
this.bridge = useMessageBridge();
|
||||||
|
|
||||||
|
// 注册 HMR
|
||||||
|
mcpClientAdapter.addConnectRefreshListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -381,7 +389,7 @@ export class TaskLoop {
|
|||||||
if (verbose > 0) {
|
if (verbose > 0) {
|
||||||
console.log(
|
console.log(
|
||||||
chalk.gray(`[${new Date().toLocaleString()}]`),
|
chalk.gray(`[${new Date().toLocaleString()}]`),
|
||||||
chalk.blueBright('🔧 calling tool'),
|
chalk.blueBright('🔧 using tool'),
|
||||||
chalk.blueBright(toolCall.function!.name)
|
chalk.blueBright(toolCall.function!.name)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -395,13 +403,13 @@ export class TaskLoop {
|
|||||||
if (result.state === 'success') {
|
if (result.state === 'success') {
|
||||||
console.log(
|
console.log(
|
||||||
chalk.gray(`[${new Date().toLocaleString()}]`),
|
chalk.gray(`[${new Date().toLocaleString()}]`),
|
||||||
chalk.green('✓ call tools okey dockey'),
|
chalk.green('✓ use tools'),
|
||||||
chalk.green(result.state)
|
chalk.green(result.state)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log(
|
console.log(
|
||||||
chalk.gray(`[${new Date().toLocaleString()}]`),
|
chalk.gray(`[${new Date().toLocaleString()}]`),
|
||||||
chalk.red('× fail to call tools'),
|
chalk.red('× use tools'),
|
||||||
chalk.red(result.content.map(item => item.text).join(', '))
|
chalk.red(result.content.map(item => item.text).join(', '))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -413,7 +421,12 @@ export class TaskLoop {
|
|||||||
const { verbose = 0 } = this.taskOptions;
|
const { verbose = 0 } = this.taskOptions;
|
||||||
if (verbose > 0) {
|
if (verbose > 0) {
|
||||||
console.log(
|
console.log(
|
||||||
chalk.gray(`[${new Date().toLocaleString()}]`),
|
chalk.gray(`[${new Date().toLocaleString()}]`)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose > 1) {
|
||||||
|
console.log(
|
||||||
chalk.blue('task loop enters a new epoch')
|
chalk.blue('task loop enters a new epoch')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -425,9 +438,15 @@ export class TaskLoop {
|
|||||||
if (verbose > 0) {
|
if (verbose > 0) {
|
||||||
console.log(
|
console.log(
|
||||||
chalk.gray(`[${new Date().toLocaleString()}]`),
|
chalk.gray(`[${new Date().toLocaleString()}]`),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (verbose > 1) {
|
||||||
|
console.log(
|
||||||
chalk.green('task loop finish a epoch')
|
chalk.green('task loop finish a epoch')
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.onDone();
|
return this.onDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -559,7 +578,7 @@ export class TaskLoop {
|
|||||||
if (verbose > 0) {
|
if (verbose > 0) {
|
||||||
console.log(
|
console.log(
|
||||||
chalk.gray(`[${new Date().toLocaleString()}]`),
|
chalk.gray(`[${new Date().toLocaleString()}]`),
|
||||||
chalk.yellow('🤖 llm wants to call these tools'),
|
chalk.yellow('🤖 Agent wants to use these tools'),
|
||||||
chalk.yellow(this.streamingToolCalls.value.map(tool => tool.function!.name || '').join(', '))
|
chalk.yellow(this.streamingToolCalls.value.map(tool => tool.function!.name || '').join(', '))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -506,9 +506,7 @@ class McpClientAdapter {
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public platform: string
|
public platform: string
|
||||||
) {
|
) {}
|
||||||
this.addConnectRefreshListener();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description 获取连接参数签名
|
* @description 获取连接参数签名
|
||||||
@ -562,7 +560,9 @@ class McpClientAdapter {
|
|||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description register HMR
|
||||||
|
*/
|
||||||
public addConnectRefreshListener() {
|
public addConnectRefreshListener() {
|
||||||
// 创建对于 connect/refresh 的监听
|
// 创建对于 connect/refresh 的监听
|
||||||
if (!this.connectrefreshListener) {
|
if (!this.connectrefreshListener) {
|
||||||
|
@ -32,8 +32,8 @@ export default defineConfig({
|
|||||||
lib: {
|
lib: {
|
||||||
entry: resolve(__dirname, '..', 'renderer/src/components/main-panel/chat/core/task-loop.ts'),
|
entry: resolve(__dirname, '..', 'renderer/src/components/main-panel/chat/core/task-loop.ts'),
|
||||||
name: 'TaskLoop',
|
name: 'TaskLoop',
|
||||||
fileName: 'task-loop',
|
fileName: (format) => `task-loop.js`,
|
||||||
formats: ['cjs']
|
formats: ['es']
|
||||||
},
|
},
|
||||||
outDir: resolve(__dirname, '..', 'openmcp-sdk'),
|
outDir: resolve(__dirname, '..', 'openmcp-sdk'),
|
||||||
emptyOutDir: false,
|
emptyOutDir: false,
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "openmcp-sdk",
|
"name": "openmcp-sdk",
|
||||||
"version": "0.0.8",
|
"version": "0.0.8",
|
||||||
|
"type": "module",
|
||||||
"description": "openmcp-sdk",
|
"description": "openmcp-sdk",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "echo \"Error: no test specified\" && exit 1"
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
@ -195,7 +195,14 @@ export interface DefaultLLM {
|
|||||||
model: string;
|
model: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
import { MessageState, TaskLoopOptions, type ChatMessage, type ChatSetting, type TaskLoop, type TextMessage } from '../../task-loop.js';
|
import {
|
||||||
|
MessageState,
|
||||||
|
type TaskLoopOptions,
|
||||||
|
type ChatMessage,
|
||||||
|
type ChatSetting,
|
||||||
|
type TaskLoop,
|
||||||
|
type TextMessage
|
||||||
|
} from '../../task-loop.js';
|
||||||
|
|
||||||
export function UserMessage(content: string): TextMessage {
|
export function UserMessage(content: string): TextMessage {
|
||||||
return {
|
return {
|
||||||
@ -309,6 +316,7 @@ export class OmAgent {
|
|||||||
const adapter = this._adapter;
|
const adapter = this._adapter;
|
||||||
const { TaskLoop } = await import('../../task-loop.js');
|
const { TaskLoop } = await import('../../task-loop.js');
|
||||||
this._loop = new TaskLoop({ adapter, verbose, maxEpochs, maxJsonParseRetry });
|
this._loop = new TaskLoop({ adapter, verbose, maxEpochs, maxJsonParseRetry });
|
||||||
|
|
||||||
return this._loop;
|
return this._loop;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -316,9 +324,14 @@ export class OmAgent {
|
|||||||
this._defaultLLM = option;
|
this._defaultLLM = option;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async start(
|
/**
|
||||||
messages: ChatMessage[] | string,
|
* @description Asynchronous invoking agent by string or messages
|
||||||
settings?: ChatSetting & Partial<TaskLoopOptions>
|
* @param messages Chat message or string
|
||||||
|
* @param settings Chat setting and task loop options
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
public async ainvoke(
|
||||||
|
{ messages, settings }: { messages: ChatMessage[] | string; settings?: ChatSetting & Partial<TaskLoopOptions>; }
|
||||||
) {
|
) {
|
||||||
if (messages.length === 0) {
|
if (messages.length === 0) {
|
||||||
throw new Error('messages is empty');
|
throw new Error('messages is empty');
|
||||||
@ -363,6 +376,10 @@ export class OmAgent {
|
|||||||
throw new Error('default LLM is not set, please set it via omagent.setDefaultLLM() or write "defaultLLM" in mcpconfig.json');
|
throw new Error('default LLM is not set, please set it via omagent.setDefaultLLM() or write "defaultLLM" in mcpconfig.json');
|
||||||
}
|
}
|
||||||
|
|
||||||
return await loop.start(storage, userMessage);
|
await loop.start(storage, userMessage);
|
||||||
|
|
||||||
|
// get response from last message in message list
|
||||||
|
const lastMessage = storage.messages.at(-1)?.content;
|
||||||
|
return lastMessage;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,7 +38,7 @@ export class McpServerConnectMonitor {
|
|||||||
this.filePath = getFilePath(options);
|
this.filePath = getFilePath(options);
|
||||||
|
|
||||||
// 记录实例创建
|
// 记录实例创建
|
||||||
logger.info({ uuid, connectionType: options.connectionType }, 'Created new connection monitor instance');
|
// logger.info({ uuid, connectionType: options.connectionType }, 'Created new connection monitor instance');
|
||||||
|
|
||||||
switch (options.connectionType) {
|
switch (options.connectionType) {
|
||||||
case 'STDIO':
|
case 'STDIO':
|
||||||
@ -94,7 +94,7 @@ export class McpServerConnectMonitor {
|
|||||||
},
|
},
|
||||||
onStart: () => {
|
onStart: () => {
|
||||||
// 使用 info 级别记录监控开始
|
// 使用 info 级别记录监控开始
|
||||||
logger.info({ uuid: this.uuid, filePath: path.resolve(fileConfig.filePath) }, 'Started monitoring file');
|
// logger.info({ uuid: this.uuid, filePath: path.resolve(fileConfig.filePath) }, 'Started monitoring file');
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const stats = fs.statSync(fileConfig.filePath);
|
const stats = fs.statSync(fileConfig.filePath);
|
||||||
|
@ -71,7 +71,7 @@ class SingleFileMonitor {
|
|||||||
this.handleFileChange(true);
|
this.handleFileChange(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
console.log(`正在监控文件: ${this.filePath}`);
|
// console.log(`正在监控文件: ${this.filePath}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
this.onError(error as Error);
|
this.onError(error as Error);
|
||||||
}
|
}
|
||||||
@ -171,7 +171,7 @@ class SingleFileMonitor {
|
|||||||
if (this.watcher) {
|
if (this.watcher) {
|
||||||
// 明确指定close方法的类型,解决TS2554错误
|
// 明确指定close方法的类型,解决TS2554错误
|
||||||
(this.watcher.close as (callback?: () => void) => void)(() => {
|
(this.watcher.close as (callback?: () => void) => void)(() => {
|
||||||
console.log(`已停止监控文件: ${this.filePath}`);
|
// console.log(`已停止监控文件: ${this.filePath}`);
|
||||||
});
|
});
|
||||||
this.watcher = null;
|
this.watcher = null;
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,9 @@
|
|||||||
"noEmitHelpers": false,
|
"noEmitHelpers": false,
|
||||||
"experimentalDecorators": true,
|
"experimentalDecorators": true,
|
||||||
"sourceMap": true,
|
"sourceMap": true,
|
||||||
|
"types": [
|
||||||
|
"./service/task-loop.d.ts"
|
||||||
|
],
|
||||||
// 允许访问 openmcp-sdk 目录
|
// 允许访问 openmcp-sdk 目录
|
||||||
"paths": {
|
"paths": {
|
||||||
"@openmcp-sdk/*": [
|
"@openmcp-sdk/*": [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user