mirror of
https://github.com/lobehub/lobehub
synced 2026-04-21 17:47:27 +00:00
🐛 fix: support memory tools run in server (#12471)
* support server memory run * refactor builtin tools list * refactor builtin tools list * add lobe-tools * fix lint
This commit is contained in:
parent
5371507b22
commit
5a30c9a14f
49 changed files with 1449 additions and 337 deletions
|
|
@ -198,7 +198,9 @@
|
|||
"@lobechat/builtin-tool-notebook": "workspace:*",
|
||||
"@lobechat/builtin-tool-page-agent": "workspace:*",
|
||||
"@lobechat/builtin-tool-skills": "workspace:*",
|
||||
"@lobechat/builtin-tool-tools": "workspace:*",
|
||||
"@lobechat/builtin-tool-web-browsing": "workspace:*",
|
||||
"@lobechat/builtin-tools": "workspace:*",
|
||||
"@lobechat/business-config": "workspace:*",
|
||||
"@lobechat/business-const": "workspace:*",
|
||||
"@lobechat/config": "workspace:*",
|
||||
|
|
|
|||
|
|
@ -6,7 +6,8 @@
|
|||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./client": "./src/client/index.ts",
|
||||
"./executor": "./src/executor/index.ts"
|
||||
"./executor": "./src/executor/index.ts",
|
||||
"./executionRuntime": "./src/ExecutionRuntime/index.ts"
|
||||
},
|
||||
"main": "./src/index.ts",
|
||||
"scripts": {
|
||||
|
|
|
|||
259
packages/builtin-tool-memory/src/ExecutionRuntime/index.ts
Normal file
259
packages/builtin-tool-memory/src/ExecutionRuntime/index.ts
Normal file
|
|
@ -0,0 +1,259 @@
|
|||
import type {
|
||||
ActivityMemoryItemSchema,
|
||||
AddIdentityActionSchema,
|
||||
ContextMemoryItemSchema,
|
||||
ExperienceMemoryItemSchema,
|
||||
PreferenceMemoryItemSchema,
|
||||
RemoveIdentityActionSchema,
|
||||
UpdateIdentityActionSchema,
|
||||
} from '@lobechat/memory-user-memory/schemas';
|
||||
import { formatMemorySearchResults } from '@lobechat/prompts';
|
||||
import type {
|
||||
AddActivityMemoryResult,
|
||||
AddContextMemoryResult,
|
||||
AddExperienceMemoryResult,
|
||||
AddIdentityMemoryResult,
|
||||
AddPreferenceMemoryResult,
|
||||
BuiltinServerRuntimeOutput,
|
||||
RemoveIdentityMemoryResult,
|
||||
SearchMemoryParams,
|
||||
SearchMemoryResult,
|
||||
UpdateIdentityMemoryResult,
|
||||
} from '@lobechat/types';
|
||||
import type { z } from 'zod';
|
||||
|
||||
export interface MemoryRuntimeService {
|
||||
addActivityMemory: (
|
||||
params: z.infer<typeof ActivityMemoryItemSchema>,
|
||||
) => Promise<AddActivityMemoryResult>;
|
||||
addContextMemory: (
|
||||
params: z.infer<typeof ContextMemoryItemSchema>,
|
||||
) => Promise<AddContextMemoryResult>;
|
||||
addExperienceMemory: (
|
||||
params: z.infer<typeof ExperienceMemoryItemSchema>,
|
||||
) => Promise<AddExperienceMemoryResult>;
|
||||
addIdentityMemory: (
|
||||
params: z.infer<typeof AddIdentityActionSchema>,
|
||||
) => Promise<AddIdentityMemoryResult>;
|
||||
addPreferenceMemory: (
|
||||
params: z.infer<typeof PreferenceMemoryItemSchema>,
|
||||
) => Promise<AddPreferenceMemoryResult>;
|
||||
removeIdentityMemory: (
|
||||
params: z.infer<typeof RemoveIdentityActionSchema>,
|
||||
) => Promise<RemoveIdentityMemoryResult>;
|
||||
searchMemory: (params: SearchMemoryParams) => Promise<SearchMemoryResult>;
|
||||
updateIdentityMemory: (
|
||||
params: z.infer<typeof UpdateIdentityActionSchema>,
|
||||
) => Promise<UpdateIdentityMemoryResult>;
|
||||
}
|
||||
|
||||
export type MemoryToolPermission = 'read-only' | 'read-write';
|
||||
|
||||
export interface MemoryExecutionRuntimeOptions {
|
||||
service: MemoryRuntimeService;
|
||||
toolPermission?: MemoryToolPermission;
|
||||
}
|
||||
|
||||
const READ_ONLY_RESULT: BuiltinServerRuntimeOutput = {
|
||||
content: 'Memory tool is in read-only mode for this chat',
|
||||
success: false,
|
||||
};
|
||||
|
||||
export class MemoryExecutionRuntime {
|
||||
private service: MemoryRuntimeService;
|
||||
private toolPermission: MemoryToolPermission;
|
||||
|
||||
constructor(options: MemoryExecutionRuntimeOptions) {
|
||||
this.service = options.service;
|
||||
this.toolPermission = options.toolPermission ?? 'read-write';
|
||||
}
|
||||
|
||||
private get isReadOnly() {
|
||||
return this.toolPermission === 'read-only';
|
||||
}
|
||||
|
||||
async searchUserMemory(params: SearchMemoryParams): Promise<BuiltinServerRuntimeOutput> {
|
||||
try {
|
||||
const result = await this.service.searchMemory(params);
|
||||
|
||||
return {
|
||||
content: formatMemorySearchResults({ query: params.query, results: result }),
|
||||
state: result,
|
||||
success: true,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
content: `searchUserMemory with error detail: ${(e as Error).message}`,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async addContextMemory(
|
||||
params: z.infer<typeof ContextMemoryItemSchema>,
|
||||
): Promise<BuiltinServerRuntimeOutput> {
|
||||
if (this.isReadOnly) return READ_ONLY_RESULT;
|
||||
try {
|
||||
const result = await this.service.addContextMemory(params);
|
||||
|
||||
if (!result.success) {
|
||||
return { content: result.message, success: false };
|
||||
}
|
||||
|
||||
return {
|
||||
content: `Context memory "${params.title}" saved with memoryId: "${result.memoryId}" and contextId: "${result.contextId}"`,
|
||||
state: { contextId: result.contextId, memoryId: result.memoryId },
|
||||
success: true,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
content: `addContextMemory with error detail: ${(e as Error).message}`,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async addActivityMemory(
|
||||
params: z.infer<typeof ActivityMemoryItemSchema>,
|
||||
): Promise<BuiltinServerRuntimeOutput> {
|
||||
if (this.isReadOnly) return READ_ONLY_RESULT;
|
||||
try {
|
||||
const result = await this.service.addActivityMemory(params);
|
||||
|
||||
if (!result.success) {
|
||||
return { content: result.message, success: false };
|
||||
}
|
||||
|
||||
return {
|
||||
content: `Activity memory "${params.title}" saved with memoryId: "${result.memoryId}" and activityId: "${result.activityId}"`,
|
||||
state: { activityId: result.activityId, memoryId: result.memoryId },
|
||||
success: true,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
content: `addActivityMemory with error detail: ${(e as Error).message}`,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async addExperienceMemory(
|
||||
params: z.infer<typeof ExperienceMemoryItemSchema>,
|
||||
): Promise<BuiltinServerRuntimeOutput> {
|
||||
if (this.isReadOnly) return READ_ONLY_RESULT;
|
||||
try {
|
||||
const result = await this.service.addExperienceMemory(params);
|
||||
|
||||
if (!result.success) {
|
||||
return { content: result.message, success: false };
|
||||
}
|
||||
|
||||
return {
|
||||
content: `Experience memory "${params.title}" saved with memoryId: "${result.memoryId}" and experienceId: "${result.experienceId}"`,
|
||||
state: { experienceId: result.experienceId, memoryId: result.memoryId },
|
||||
success: true,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
content: `addExperienceMemory with error detail: ${(e as Error).message}`,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async addIdentityMemory(
|
||||
params: z.infer<typeof AddIdentityActionSchema>,
|
||||
): Promise<BuiltinServerRuntimeOutput> {
|
||||
if (this.isReadOnly) return READ_ONLY_RESULT;
|
||||
try {
|
||||
const result = await this.service.addIdentityMemory(params);
|
||||
|
||||
if (!result.success) {
|
||||
return { content: result.message, success: false };
|
||||
}
|
||||
|
||||
return {
|
||||
content: `Identity memory "${params.title}" saved with memoryId: "${result.memoryId}" and identityId: "${result.identityId}"`,
|
||||
state: { identityId: result.identityId, memoryId: result.memoryId },
|
||||
success: true,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
content: `addIdentityMemory with error detail: ${(e as Error).message}`,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async addPreferenceMemory(
|
||||
params: z.infer<typeof PreferenceMemoryItemSchema>,
|
||||
): Promise<BuiltinServerRuntimeOutput> {
|
||||
if (this.isReadOnly) return READ_ONLY_RESULT;
|
||||
try {
|
||||
const result = await this.service.addPreferenceMemory(params);
|
||||
|
||||
if (!result.success) {
|
||||
return { content: result.message, success: false };
|
||||
}
|
||||
|
||||
return {
|
||||
content: `Preference memory "${params.title}" saved with memoryId: "${result.memoryId}" and preferenceId: "${result.preferenceId}"`,
|
||||
state: { memoryId: result.memoryId, preferenceId: result.preferenceId },
|
||||
success: true,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
content: `addPreferenceMemory with error detail: ${(e as Error).message}`,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async updateIdentityMemory(
|
||||
params: z.infer<typeof UpdateIdentityActionSchema>,
|
||||
): Promise<BuiltinServerRuntimeOutput> {
|
||||
if (this.isReadOnly) return READ_ONLY_RESULT;
|
||||
try {
|
||||
const result = await this.service.updateIdentityMemory(params);
|
||||
|
||||
if (!result.success) {
|
||||
return { content: result.message, success: false };
|
||||
}
|
||||
|
||||
return {
|
||||
content: `Identity memory updated: ${params.id}`,
|
||||
state: { identityId: params.id },
|
||||
success: true,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
content: `updateIdentityMemory with error detail: ${(e as Error).message}`,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async removeIdentityMemory(
|
||||
params: z.infer<typeof RemoveIdentityActionSchema>,
|
||||
): Promise<BuiltinServerRuntimeOutput> {
|
||||
if (this.isReadOnly) return READ_ONLY_RESULT;
|
||||
try {
|
||||
const result = await this.service.removeIdentityMemory(params);
|
||||
|
||||
if (!result.success) {
|
||||
return { content: result.message, success: false };
|
||||
}
|
||||
|
||||
return {
|
||||
content: `Identity memory removed: ${params.id}\nReason: ${params.reason}`,
|
||||
state: { identityId: params.id, reason: params.reason },
|
||||
success: true,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
content: `removeIdentityMemory with error detail: ${(e as Error).message}`,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,33 +1,35 @@
|
|||
import {
|
||||
type ActivityMemoryItemSchema,
|
||||
type AddIdentityActionSchema,
|
||||
type ContextMemoryItemSchema,
|
||||
type ExperienceMemoryItemSchema,
|
||||
type PreferenceMemoryItemSchema,
|
||||
type RemoveIdentityActionSchema,
|
||||
type UpdateIdentityActionSchema,
|
||||
import type {
|
||||
ActivityMemoryItemSchema,
|
||||
AddIdentityActionSchema,
|
||||
ContextMemoryItemSchema,
|
||||
ExperienceMemoryItemSchema,
|
||||
PreferenceMemoryItemSchema,
|
||||
RemoveIdentityActionSchema,
|
||||
UpdateIdentityActionSchema,
|
||||
} from '@lobechat/memory-user-memory/schemas';
|
||||
import { formatMemorySearchResults } from '@lobechat/prompts';
|
||||
import { type BuiltinToolContext, type BuiltinToolResult, type SearchMemoryParams } from '@lobechat/types';
|
||||
import type { BuiltinToolContext, BuiltinToolResult, SearchMemoryParams } from '@lobechat/types';
|
||||
import { BaseExecutor } from '@lobechat/types';
|
||||
import { type z } from 'zod';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import { userMemoryService } from '@/services/userMemory';
|
||||
import { getAgentStoreState } from '@/store/agent';
|
||||
import { agentChatConfigSelectors, chatConfigByIdSelectors } from '@/store/agent/selectors';
|
||||
|
||||
import { MemoryExecutionRuntime } from '../ExecutionRuntime';
|
||||
import { MemoryIdentifier } from '../manifest';
|
||||
import { MemoryApiName } from '../types';
|
||||
|
||||
/**
|
||||
* Memory Tool Executor
|
||||
*
|
||||
* Handles all memory-related operations including search, add, update, and remove.
|
||||
*/
|
||||
class MemoryExecutor extends BaseExecutor<typeof MemoryApiName> {
|
||||
readonly identifier = MemoryIdentifier;
|
||||
protected readonly apiEnum = MemoryApiName;
|
||||
|
||||
private runtime: MemoryExecutionRuntime;
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.runtime = new MemoryExecutionRuntime({ service: userMemoryService });
|
||||
}
|
||||
|
||||
private resolveToolPermission = (agentId?: string): 'read-only' | 'read-write' => {
|
||||
const state = getAgentStoreState();
|
||||
if (!state) return 'read-write';
|
||||
|
|
@ -56,323 +58,71 @@ class MemoryExecutor extends BaseExecutor<typeof MemoryApiName> {
|
|||
return chatConfig?.memory?.effort;
|
||||
};
|
||||
|
||||
// ==================== Search API ====================
|
||||
|
||||
/**
|
||||
* Search user memories based on query
|
||||
*/
|
||||
searchUserMemory = async (
|
||||
params: SearchMemoryParams,
|
||||
ctx?: BuiltinToolContext,
|
||||
): Promise<BuiltinToolResult> => {
|
||||
try {
|
||||
const result = await userMemoryService.searchMemory({
|
||||
...params,
|
||||
effort: this.resolveMemoryEffort(ctx?.agentId),
|
||||
});
|
||||
|
||||
return {
|
||||
content: formatMemorySearchResults({ query: params.query, results: result }),
|
||||
state: result,
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
return {
|
||||
content: `searchUserMemory with error detail: ${err.message}`,
|
||||
error: {
|
||||
body: error,
|
||||
message: err.message,
|
||||
type: 'PluginServerError',
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
return this.runtime.searchUserMemory({
|
||||
...params,
|
||||
effort: this.resolveMemoryEffort(ctx?.agentId),
|
||||
});
|
||||
};
|
||||
|
||||
// ==================== Add APIs ====================
|
||||
|
||||
/**
|
||||
* Add a context memory
|
||||
*/
|
||||
addContextMemory = async (
|
||||
params: z.infer<typeof ContextMemoryItemSchema>,
|
||||
ctx?: BuiltinToolContext,
|
||||
): Promise<BuiltinToolResult> => {
|
||||
try {
|
||||
this.ensureWritable(ctx?.agentId);
|
||||
const result = await userMemoryService.addContextMemory(params);
|
||||
|
||||
if (!result.success) {
|
||||
return {
|
||||
error: {
|
||||
message: result.message,
|
||||
type: 'PluginServerError',
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
content: `Context memory "${params.title}" saved with memoryId: "${result.memoryId}" and contextId: "${result.contextId}"`,
|
||||
state: { contextId: result.contextId, memoryId: result.memoryId },
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
return {
|
||||
content: `addContextMemory with error detail: ${err.message}`,
|
||||
error: {
|
||||
body: error,
|
||||
message: err.message,
|
||||
type: 'PluginServerError',
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
this.ensureWritable(ctx?.agentId);
|
||||
return this.runtime.addContextMemory(params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add an activity memory
|
||||
*/
|
||||
addActivityMemory = async (
|
||||
params: z.infer<typeof ActivityMemoryItemSchema>,
|
||||
ctx?: BuiltinToolContext,
|
||||
): Promise<BuiltinToolResult> => {
|
||||
try {
|
||||
this.ensureWritable(ctx?.agentId);
|
||||
const result = await userMemoryService.addActivityMemory(params);
|
||||
|
||||
if (!result.success) {
|
||||
return {
|
||||
error: {
|
||||
message: result.message,
|
||||
type: 'PluginServerError',
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
content: `Activity memory "${params.title}" saved with memoryId: "${result.memoryId}" and activityId: "${result.activityId}"`,
|
||||
state: { activityId: result.activityId, memoryId: result.memoryId },
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
|
||||
return {
|
||||
content: `addActivityMemory with error detail: ${err.message}`,
|
||||
error: {
|
||||
body: error,
|
||||
message: err.message,
|
||||
type: 'PluginServerError',
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
this.ensureWritable(ctx?.agentId);
|
||||
return this.runtime.addActivityMemory(params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add an experience memory
|
||||
*/
|
||||
addExperienceMemory = async (
|
||||
params: z.infer<typeof ExperienceMemoryItemSchema>,
|
||||
ctx?: BuiltinToolContext,
|
||||
): Promise<BuiltinToolResult> => {
|
||||
try {
|
||||
this.ensureWritable(ctx?.agentId);
|
||||
const result = await userMemoryService.addExperienceMemory(params);
|
||||
|
||||
if (!result.success) {
|
||||
return {
|
||||
error: {
|
||||
message: result.message,
|
||||
type: 'PluginServerError',
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
content: `Experience memory "${params.title}" saved with memoryId: "${result.memoryId}" and experienceId: "${result.experienceId}"`,
|
||||
state: { experienceId: result.experienceId, memoryId: result.memoryId },
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
|
||||
return {
|
||||
content: `addExperienceMemory with error detail: ${err.message}`,
|
||||
error: {
|
||||
body: error,
|
||||
message: err.message,
|
||||
type: 'PluginServerError',
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
this.ensureWritable(ctx?.agentId);
|
||||
return this.runtime.addExperienceMemory(params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add an identity memory
|
||||
*/
|
||||
addIdentityMemory = async (
|
||||
params: z.infer<typeof AddIdentityActionSchema>,
|
||||
ctx?: BuiltinToolContext,
|
||||
): Promise<BuiltinToolResult> => {
|
||||
try {
|
||||
this.ensureWritable(ctx?.agentId);
|
||||
const result = await userMemoryService.addIdentityMemory(params);
|
||||
|
||||
if (!result.success) {
|
||||
return {
|
||||
error: {
|
||||
message: result.message,
|
||||
type: 'PluginServerError',
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
content: `Identity memory "${params.title}" saved with memoryId: "${result.memoryId}" and identityId: "${result.identityId}"`,
|
||||
state: { identityId: result.identityId, memoryId: result.memoryId },
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
return {
|
||||
content: `addIdentityMemory with error detail: ${err.message}`,
|
||||
error: {
|
||||
body: error,
|
||||
message: err.message,
|
||||
type: 'PluginServerError',
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
this.ensureWritable(ctx?.agentId);
|
||||
return this.runtime.addIdentityMemory(params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Add a preference memory
|
||||
*/
|
||||
addPreferenceMemory = async (
|
||||
params: z.infer<typeof PreferenceMemoryItemSchema>,
|
||||
ctx?: BuiltinToolContext,
|
||||
): Promise<BuiltinToolResult> => {
|
||||
try {
|
||||
this.ensureWritable(ctx?.agentId);
|
||||
const result = await userMemoryService.addPreferenceMemory(params);
|
||||
|
||||
if (!result.success) {
|
||||
return {
|
||||
error: {
|
||||
message: result.message,
|
||||
type: 'PluginServerError',
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
content: `Preference memory "${params.title}" saved with memoryId: "${result.memoryId}" and preferenceId: "${result.preferenceId}"`,
|
||||
state: { memoryId: result.memoryId, preferenceId: result.preferenceId },
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
return {
|
||||
content: `addPreferenceMemory with error detail: ${err.message}`,
|
||||
error: {
|
||||
body: error,
|
||||
message: err.message,
|
||||
type: 'PluginServerError',
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
this.ensureWritable(ctx?.agentId);
|
||||
return this.runtime.addPreferenceMemory(params);
|
||||
};
|
||||
|
||||
// ==================== Update/Remove APIs ====================
|
||||
|
||||
/**
|
||||
* Update an identity memory
|
||||
*/
|
||||
updateIdentityMemory = async (
|
||||
params: z.infer<typeof UpdateIdentityActionSchema>,
|
||||
ctx?: BuiltinToolContext,
|
||||
): Promise<BuiltinToolResult> => {
|
||||
try {
|
||||
this.ensureWritable(ctx?.agentId);
|
||||
const result = await userMemoryService.updateIdentityMemory(params);
|
||||
|
||||
if (!result.success) {
|
||||
return {
|
||||
error: {
|
||||
message: result.message,
|
||||
type: 'PluginServerError',
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
content: `✏️ Identity memory updated: ${params.id}`,
|
||||
state: { identityId: params.id },
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
return {
|
||||
content: `updateIdentityMemory with error detail: ${err.message}`,
|
||||
error: {
|
||||
body: error,
|
||||
message: err.message,
|
||||
type: 'PluginServerError',
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
this.ensureWritable(ctx?.agentId);
|
||||
return this.runtime.updateIdentityMemory(params);
|
||||
};
|
||||
|
||||
/**
|
||||
* Remove an identity memory
|
||||
*/
|
||||
removeIdentityMemory = async (
|
||||
params: z.infer<typeof RemoveIdentityActionSchema>,
|
||||
ctx?: BuiltinToolContext,
|
||||
): Promise<BuiltinToolResult> => {
|
||||
try {
|
||||
this.ensureWritable(ctx?.agentId);
|
||||
const result = await userMemoryService.removeIdentityMemory(params);
|
||||
|
||||
if (!result.success) {
|
||||
return {
|
||||
error: { message: result.message, type: 'PluginServerError' },
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
content: `🗑️ Identity memory removed: ${params.id}\nReason: ${params.reason}`,
|
||||
state: { identityId: params.id, reason: params.reason },
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
const err = error as Error;
|
||||
return {
|
||||
content: `removeIdentityMemory with error detail: ${err.message}`,
|
||||
error: {
|
||||
body: error,
|
||||
message: err.message,
|
||||
type: 'PluginServerError',
|
||||
},
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
this.ensureWritable(ctx?.agentId);
|
||||
return this.runtime.removeIdentityMemory(params);
|
||||
};
|
||||
}
|
||||
|
||||
// Export the executor instance for registration
|
||||
export const memoryExecutor = new MemoryExecutor();
|
||||
|
|
|
|||
15
packages/builtin-tool-tools/package.json
Normal file
15
packages/builtin-tool-tools/package.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"name": "@lobechat/builtin-tool-tools",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./executor": "./src/executor/index.ts",
|
||||
"./executionRuntime": "./src/ExecutionRuntime/index.ts"
|
||||
},
|
||||
"main": "./src/index.ts",
|
||||
"devDependencies": {
|
||||
"@lobechat/prompts": "workspace:*",
|
||||
"@lobechat/types": "workspace:*"
|
||||
}
|
||||
}
|
||||
112
packages/builtin-tool-tools/src/ExecutionRuntime/index.ts
Normal file
112
packages/builtin-tool-tools/src/ExecutionRuntime/index.ts
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
import type { BuiltinServerRuntimeOutput } from '@lobechat/types';
|
||||
|
||||
import type { ActivatedToolInfo, ActivateToolsParams } from '../types';
|
||||
|
||||
export interface ToolManifestInfo {
|
||||
apiDescriptions: Array<{ description: string; name: string }>;
|
||||
identifier: string;
|
||||
name: string;
|
||||
systemRole?: string;
|
||||
}
|
||||
|
||||
export interface ToolsActivatorRuntimeService {
|
||||
getActivatedToolIds: () => string[];
|
||||
getToolManifests: (identifiers: string[]) => Promise<ToolManifestInfo[]>;
|
||||
markActivated: (identifiers: string[]) => void;
|
||||
}
|
||||
|
||||
export interface ToolsActivatorExecutionRuntimeOptions {
|
||||
service: ToolsActivatorRuntimeService;
|
||||
}
|
||||
|
||||
export class ToolsActivatorExecutionRuntime {
|
||||
private service: ToolsActivatorRuntimeService;
|
||||
|
||||
constructor(options: ToolsActivatorExecutionRuntimeOptions) {
|
||||
this.service = options.service;
|
||||
}
|
||||
|
||||
async activateTools(args: ActivateToolsParams): Promise<BuiltinServerRuntimeOutput> {
|
||||
const { identifiers } = args;
|
||||
|
||||
if (!identifiers || identifiers.length === 0) {
|
||||
return {
|
||||
content: 'No tool identifiers provided. Please specify which tools to activate.',
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const alreadyActive = this.service.getActivatedToolIds();
|
||||
const toActivate: string[] = [];
|
||||
const alreadyActiveList: string[] = [];
|
||||
|
||||
for (const id of identifiers) {
|
||||
if (alreadyActive.includes(id)) {
|
||||
alreadyActiveList.push(id);
|
||||
} else {
|
||||
toActivate.push(id);
|
||||
}
|
||||
}
|
||||
|
||||
// Fetch manifests for tools to activate
|
||||
const manifests = await this.service.getToolManifests(toActivate);
|
||||
|
||||
const foundIdentifiers = new Set(manifests.map((m) => m.identifier));
|
||||
const notFound = toActivate.filter((id) => !foundIdentifiers.has(id));
|
||||
|
||||
const activatedTools: ActivatedToolInfo[] = manifests.map((m) => ({
|
||||
apiCount: m.apiDescriptions.length,
|
||||
identifier: m.identifier,
|
||||
name: m.name,
|
||||
}));
|
||||
|
||||
// Mark newly activated tools
|
||||
if (manifests.length > 0) {
|
||||
this.service.markActivated(manifests.map((m) => m.identifier));
|
||||
}
|
||||
|
||||
// Build response content
|
||||
const parts: string[] = [];
|
||||
|
||||
if (activatedTools.length > 0) {
|
||||
parts.push('Successfully activated tools:');
|
||||
for (const manifest of manifests) {
|
||||
parts.push(`\n## ${manifest.name} (${manifest.identifier})`);
|
||||
if (manifest.systemRole) {
|
||||
parts.push(manifest.systemRole);
|
||||
}
|
||||
if (manifest.apiDescriptions.length > 0) {
|
||||
parts.push('\nAvailable APIs:');
|
||||
for (const api of manifest.apiDescriptions) {
|
||||
parts.push(`- **${api.name}**: ${api.description}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (alreadyActiveList.length > 0) {
|
||||
parts.push(`\nAlready active: ${alreadyActiveList.join(', ')}`);
|
||||
}
|
||||
|
||||
if (notFound.length > 0) {
|
||||
parts.push(`\nNot found: ${notFound.join(', ')}`);
|
||||
}
|
||||
|
||||
return {
|
||||
content: parts.join('\n'),
|
||||
state: {
|
||||
activatedTools,
|
||||
alreadyActive: alreadyActiveList,
|
||||
notFound,
|
||||
},
|
||||
success: true,
|
||||
};
|
||||
} catch (e) {
|
||||
return {
|
||||
content: `Failed to activate tools: ${(e as Error).message}`,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
47
packages/builtin-tool-tools/src/executor/index.ts
Normal file
47
packages/builtin-tool-tools/src/executor/index.ts
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
import { BaseExecutor, type BuiltinToolContext, type BuiltinToolResult } from '@lobechat/types';
|
||||
|
||||
import type { ToolsActivatorExecutionRuntime } from '../ExecutionRuntime';
|
||||
import { type ActivateToolsParams, LobeToolIdentifier, ToolsActivatorApiName } from '../types';
|
||||
|
||||
class ToolsActivatorExecutor extends BaseExecutor<typeof ToolsActivatorApiName> {
|
||||
readonly identifier = LobeToolIdentifier;
|
||||
protected readonly apiEnum = ToolsActivatorApiName;
|
||||
|
||||
private runtime: ToolsActivatorExecutionRuntime;
|
||||
|
||||
constructor(runtime: ToolsActivatorExecutionRuntime) {
|
||||
super();
|
||||
this.runtime = runtime;
|
||||
}
|
||||
|
||||
activateTools = async (
|
||||
params: ActivateToolsParams,
|
||||
ctx: BuiltinToolContext,
|
||||
): Promise<BuiltinToolResult> => {
|
||||
try {
|
||||
if (ctx.signal?.aborted) {
|
||||
return { stop: true, success: false };
|
||||
}
|
||||
|
||||
const result = await this.runtime.activateTools(params);
|
||||
|
||||
if (result.success) {
|
||||
return { content: result.content, state: result.state, success: true };
|
||||
}
|
||||
|
||||
return {
|
||||
content: result.content,
|
||||
error: { message: result.content, type: 'PluginServerError' },
|
||||
success: false,
|
||||
};
|
||||
} catch (e) {
|
||||
const err = e as Error;
|
||||
return {
|
||||
error: { body: e, message: err.message, type: 'PluginServerError' },
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export { ToolsActivatorExecutor };
|
||||
9
packages/builtin-tool-tools/src/index.ts
Normal file
9
packages/builtin-tool-tools/src/index.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
export { LobeToolsManifest } from './manifest';
|
||||
export { systemPrompt } from './systemRole';
|
||||
export {
|
||||
type ActivatedToolInfo,
|
||||
type ActivateToolsParams,
|
||||
type ActivateToolsState,
|
||||
LobeToolIdentifier,
|
||||
ToolsActivatorApiName,
|
||||
} from './types';
|
||||
36
packages/builtin-tool-tools/src/manifest.ts
Normal file
36
packages/builtin-tool-tools/src/manifest.ts
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
import type { BuiltinToolManifest } from '@lobechat/types';
|
||||
|
||||
import { systemPrompt } from './systemRole';
|
||||
import { LobeToolIdentifier, ToolsActivatorApiName } from './types';
|
||||
|
||||
export const LobeToolsManifest: BuiltinToolManifest = {
|
||||
api: [
|
||||
{
|
||||
description:
|
||||
'Activate tools from the <available_tools> list so their full API schemas become available for use. Call this before using any tool that is not yet activated. You can activate multiple tools at once.',
|
||||
name: ToolsActivatorApiName.activateTools,
|
||||
parameters: {
|
||||
properties: {
|
||||
identifiers: {
|
||||
description:
|
||||
'Array of tool identifiers to activate. Use the identifiers from the <available_tools> list.',
|
||||
items: {
|
||||
type: 'string',
|
||||
},
|
||||
type: 'array',
|
||||
},
|
||||
},
|
||||
required: ['identifiers'],
|
||||
type: 'object',
|
||||
},
|
||||
},
|
||||
],
|
||||
identifier: LobeToolIdentifier,
|
||||
meta: {
|
||||
avatar: '🔧',
|
||||
description: 'Discover and activate tools on demand',
|
||||
title: 'Tools',
|
||||
},
|
||||
systemRole: systemPrompt,
|
||||
type: 'builtin',
|
||||
};
|
||||
26
packages/builtin-tool-tools/src/systemRole.ts
Normal file
26
packages/builtin-tool-tools/src/systemRole.ts
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
export const systemPrompt = `You have access to a Tool Discovery system that allows you to dynamically activate tools on demand. Not all tools are loaded by default — you must activate them before use.
|
||||
|
||||
<how_it_works>
|
||||
1. Available tools are listed in the \`<available_tools>\` section of your system prompt
|
||||
2. Each entry shows the tool's identifier, name, and description
|
||||
3. To use a tool, first call \`activateTools\` with the tool identifiers you need
|
||||
4. After activation, the tool's full API schemas become available as native function calls in subsequent turns
|
||||
5. You can activate multiple tools at once by passing multiple identifiers
|
||||
</how_it_works>
|
||||
|
||||
<tool_selection_guidelines>
|
||||
- **activateTools**: Call this when you need to use a tool that isn't yet activated
|
||||
- Review the \`<available_tools>\` list to find relevant tools for the user's task
|
||||
- Provide an array of tool identifiers to activate
|
||||
- After activation, the tools' APIs will be available for you to call directly
|
||||
- Tools that are already active will be noted in the response
|
||||
- If an identifier is not found, it will be reported in the response
|
||||
</tool_selection_guidelines>
|
||||
|
||||
<best_practices>
|
||||
- Check the \`<available_tools>\` list before activating tools
|
||||
- Activate all tools you'll need for a task in a single call when possible
|
||||
- Only activate tools that are relevant to the user's current request
|
||||
- After activation, use the tools' APIs directly — no need to call activateTools again for the same tools
|
||||
</best_practices>
|
||||
`;
|
||||
21
packages/builtin-tool-tools/src/types.ts
Normal file
21
packages/builtin-tool-tools/src/types.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
export const LobeToolIdentifier = 'lobe-tools';
|
||||
|
||||
export const ToolsActivatorApiName = {
|
||||
activateTools: 'activateTools',
|
||||
};
|
||||
|
||||
export interface ActivateToolsParams {
|
||||
identifiers: string[];
|
||||
}
|
||||
|
||||
export interface ActivatedToolInfo {
|
||||
apiCount: number;
|
||||
identifier: string;
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface ActivateToolsState {
|
||||
activatedTools: ActivatedToolInfo[];
|
||||
alreadyActive: string[];
|
||||
notFound: string[];
|
||||
}
|
||||
44
packages/builtin-tools/package.json
Normal file
44
packages/builtin-tools/package.json
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"name": "@lobechat/builtin-tools",
|
||||
"version": "1.0.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./src/index.ts",
|
||||
"./renders": "./src/renders.ts",
|
||||
"./inspectors": "./src/inspectors.ts",
|
||||
"./interventions": "./src/interventions.ts",
|
||||
"./placeholders": "./src/placeholders.ts",
|
||||
"./portals": "./src/portals.ts",
|
||||
"./streamings": "./src/streamings.ts",
|
||||
"./identifiers": "./src/identifiers.ts",
|
||||
"./dynamicInterventionAudits": "./src/dynamicInterventionAudits.ts"
|
||||
},
|
||||
"main": "./src/index.ts",
|
||||
"dependencies": {
|
||||
"@lobechat/builtin-tool-agent-builder": "workspace:*",
|
||||
"@lobechat/builtin-tool-cloud-sandbox": "workspace:*",
|
||||
"@lobechat/builtin-tool-group-agent-builder": "workspace:*",
|
||||
"@lobechat/builtin-tool-group-management": "workspace:*",
|
||||
"@lobechat/builtin-tool-gtd": "workspace:*",
|
||||
"@lobechat/builtin-tool-knowledge-base": "workspace:*",
|
||||
"@lobechat/builtin-tool-local-system": "workspace:*",
|
||||
"@lobechat/builtin-tool-memory": "workspace:*",
|
||||
"@lobechat/builtin-tool-notebook": "workspace:*",
|
||||
"@lobechat/builtin-tool-page-agent": "workspace:*",
|
||||
"@lobechat/builtin-tool-skills": "workspace:*",
|
||||
"@lobechat/builtin-tool-tools": "workspace:*",
|
||||
"@lobechat/builtin-tool-web-browsing": "workspace:*",
|
||||
"@lobechat/const": "workspace:*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@lobechat/types": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@lobehub/ui": "^4",
|
||||
"antd-style": "*",
|
||||
"lucide-react": "*",
|
||||
"react": "*",
|
||||
"react-i18next": "*"
|
||||
}
|
||||
}
|
||||
|
|
@ -9,6 +9,7 @@ import { MemoryManifest } from '@lobechat/builtin-tool-memory';
|
|||
import { NotebookManifest } from '@lobechat/builtin-tool-notebook';
|
||||
import { PageAgentManifest } from '@lobechat/builtin-tool-page-agent';
|
||||
import { SkillsManifest } from '@lobechat/builtin-tool-skills';
|
||||
import { LobeToolsManifest } from '@lobechat/builtin-tool-tools';
|
||||
import { WebBrowsingManifest } from '@lobechat/builtin-tool-web-browsing';
|
||||
|
||||
export const builtinToolIdentifiers: string[] = [
|
||||
|
|
@ -24,4 +25,5 @@ export const builtinToolIdentifiers: string[] = [
|
|||
GTDManifest.identifier,
|
||||
MemoryManifest.identifier,
|
||||
NotebookManifest.identifier,
|
||||
LobeToolsManifest.identifier,
|
||||
];
|
||||
|
|
@ -9,6 +9,7 @@ import { MemoryManifest } from '@lobechat/builtin-tool-memory';
|
|||
import { NotebookManifest } from '@lobechat/builtin-tool-notebook';
|
||||
import { PageAgentManifest } from '@lobechat/builtin-tool-page-agent';
|
||||
import { SkillsManifest } from '@lobechat/builtin-tool-skills';
|
||||
import { LobeToolsManifest } from '@lobechat/builtin-tool-tools';
|
||||
import { WebBrowsingManifest } from '@lobechat/builtin-tool-web-browsing';
|
||||
import { isDesktop } from '@lobechat/const';
|
||||
import { type LobeBuiltinTool } from '@lobechat/types';
|
||||
|
|
@ -92,4 +93,10 @@ export const builtinTools: LobeBuiltinTool[] = [
|
|||
manifest: NotebookManifest,
|
||||
type: 'builtin',
|
||||
},
|
||||
{
|
||||
hidden: true,
|
||||
identifier: LobeToolsManifest.identifier,
|
||||
manifest: LobeToolsManifest,
|
||||
type: 'builtin',
|
||||
},
|
||||
];
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
import { builtinTools } from '@lobechat/builtin-tools';
|
||||
import {
|
||||
KLAVIS_SERVER_TYPES,
|
||||
getLobehubSkillProviderById,
|
||||
KLAVIS_SERVER_TYPES,
|
||||
type KlavisServerType,
|
||||
type LobehubSkillProviderType,
|
||||
} from '@lobechat/const';
|
||||
|
|
@ -13,23 +14,22 @@ import { Link } from 'react-router-dom';
|
|||
import urlJoin from 'url-join';
|
||||
|
||||
import { useDiscoverStore } from '@/store/discover';
|
||||
import { builtinTools } from '@/tools';
|
||||
|
||||
/**
|
||||
* Icon component for built-in tools (Klavis & LobehubSkill)
|
||||
* For string type icon, use Image component to render
|
||||
* For IconType type icon, use Icon component to render with theme fill color
|
||||
*/
|
||||
const BuiltinToolIcon = memo<
|
||||
Pick<KlavisServerType | LobehubSkillProviderType, 'icon' | 'label'>
|
||||
>(({ icon, label }) => {
|
||||
if (typeof icon === 'string') {
|
||||
return <Image alt={label} height={40} src={icon} style={{ flex: 'none' }} width={40} />;
|
||||
}
|
||||
const BuiltinToolIcon = memo<Pick<KlavisServerType | LobehubSkillProviderType, 'icon' | 'label'>>(
|
||||
({ icon, label }) => {
|
||||
if (typeof icon === 'string') {
|
||||
return <Image alt={label} height={40} src={icon} style={{ flex: 'none' }} width={40} />;
|
||||
}
|
||||
|
||||
// Use theme color fill, automatically adapts in dark mode
|
||||
return <Icon fill={cssVar.colorText} icon={icon} size={40} />;
|
||||
});
|
||||
// Use theme color fill, automatically adapts in dark mode
|
||||
return <Icon fill={cssVar.colorText} icon={icon} size={40} />;
|
||||
},
|
||||
);
|
||||
|
||||
BuiltinToolIcon.displayName = 'BuiltinToolIcon';
|
||||
|
||||
|
|
@ -195,7 +195,7 @@ const PluginItem = memo<PluginItemProps>(({ identifier }) => {
|
|||
|
||||
if (isLoading)
|
||||
return (
|
||||
<Block gap={12} horizontal key={identifier} padding={12} variant={'outlined'}>
|
||||
<Block horizontal gap={12} key={identifier} padding={12} variant={'outlined'}>
|
||||
<Skeleton paragraph={{ rows: 1 }} title={false} />
|
||||
</Block>
|
||||
);
|
||||
|
|
@ -216,9 +216,9 @@ const PluginItem = memo<PluginItemProps>(({ identifier }) => {
|
|||
|
||||
const content = (
|
||||
<Block
|
||||
horizontal
|
||||
className={cx(sourceConfig.clickable ? styles.clickable : styles.noLink)}
|
||||
gap={12}
|
||||
horizontal
|
||||
key={identifier}
|
||||
padding={12}
|
||||
variant={'outlined'}
|
||||
|
|
@ -232,7 +232,7 @@ const PluginItem = memo<PluginItemProps>(({ identifier }) => {
|
|||
}}
|
||||
>
|
||||
<div className={styles.titleRow}>
|
||||
<Text as={'h2'} className={cx(styles.title, 'plugin-title')} ellipsis>
|
||||
<Text ellipsis as={'h2'} className={cx(styles.title, 'plugin-title')}>
|
||||
{data.title}
|
||||
</Text>
|
||||
{sourceConfig.tagText && (
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { getBuiltinIntervention } from '@lobechat/builtin-tools/interventions';
|
||||
import { safeParseJSON } from '@lobechat/utils';
|
||||
import { Flexbox } from '@lobehub/ui';
|
||||
import { memo, Suspense, useCallback, useMemo, useRef, useState } from 'react';
|
||||
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { toolInterventionSelectors } from '@/store/user/selectors';
|
||||
import { getBuiltinIntervention } from '@/tools/interventions';
|
||||
|
||||
import { useConversationStore } from '../../../../../store';
|
||||
import Arguments from '../Arguments';
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
import { getBuiltinPlaceholder } from '@lobechat/builtin-tools/placeholders';
|
||||
import { getBuiltinStreaming } from '@lobechat/builtin-tools/streamings';
|
||||
import { safeParseJSON } from '@lobechat/utils';
|
||||
import { memo } from 'react';
|
||||
|
||||
import { getBuiltinPlaceholder } from '@/tools/placeholders';
|
||||
import { getBuiltinStreaming } from '@/tools/streamings';
|
||||
|
||||
import Arguments from '../Arguments';
|
||||
|
||||
interface LoadingPlaceholderProps {
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { getBuiltinRender } from '@lobechat/builtin-tools/renders';
|
||||
import { type ChatPluginPayload } from '@lobechat/types';
|
||||
import { memo } from 'react';
|
||||
|
||||
import { getBuiltinRender } from '@/tools/renders';
|
||||
|
||||
import CustomRender from './CustomRender';
|
||||
import { FallbackArgumentRender } from './FallbacktArgumentRender';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,10 +1,9 @@
|
|||
import { getBuiltinStreaming } from '@lobechat/builtin-tools/streamings';
|
||||
import { type ChatToolResult, type ToolIntervention } from '@lobechat/types';
|
||||
import { safeParsePartialJSON } from '@lobechat/utils';
|
||||
import { Flexbox } from '@lobehub/ui';
|
||||
import { memo, Suspense } from 'react';
|
||||
|
||||
import { getBuiltinStreaming } from '@/tools/streamings';
|
||||
|
||||
import AbortResponse from './AbortResponse';
|
||||
import ErrorResponse from './ErrorResponse';
|
||||
import Intervention from './Intervention';
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { builtinToolIdentifiers } from '@lobechat/builtin-tools/identifiers';
|
||||
import { Icon } from '@lobehub/ui';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
|
|
@ -8,7 +9,6 @@ import { useTranslation } from 'react-i18next';
|
|||
import { pluginHelpers, useToolStore } from '@/store/tool';
|
||||
import { toolSelectors } from '@/store/tool/selectors';
|
||||
import { shinyTextStyles } from '@/styles';
|
||||
import { builtinToolIdentifiers } from '@/tools/identifiers';
|
||||
|
||||
export const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
aborted: css`
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { getBuiltinInspector } from '@lobechat/builtin-tools/inspectors';
|
||||
import { type ToolIntervention } from '@lobechat/types';
|
||||
import { safeParseJSON, safeParsePartialJSON } from '@lobechat/utils';
|
||||
import { Flexbox } from '@lobehub/ui';
|
||||
import { memo } from 'react';
|
||||
|
||||
import { LOADING_FLAT } from '@/const/message';
|
||||
import { getBuiltinInspector } from '@/tools/inspectors';
|
||||
|
||||
import StatusIndicator from './StatusIndicator';
|
||||
import ToolTitle from './ToolTitle';
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import { getBuiltinRender } from '@lobechat/builtin-tools/renders';
|
||||
import { getBuiltinStreaming } from '@lobechat/builtin-tools/streamings';
|
||||
import { LOADING_FLAT } from '@lobechat/const';
|
||||
import { type ChatToolResult, type ToolIntervention } from '@lobechat/types';
|
||||
import { AccordionItem, Flexbox, Skeleton } from '@lobehub/ui';
|
||||
|
|
@ -9,8 +11,6 @@ import { useChatStore } from '@/store/chat';
|
|||
import { operationSelectors } from '@/store/chat/slices/operation/selectors';
|
||||
import { useToolStore } from '@/store/tool';
|
||||
import { toolSelectors } from '@/store/tool/selectors';
|
||||
import { getBuiltinRender } from '@/tools/renders';
|
||||
import { getBuiltinStreaming } from '@/tools/streamings';
|
||||
|
||||
import { ToolErrorBoundary } from '../../Tool/ErrorBoundary';
|
||||
import Actions from './Actions';
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { getBuiltinRender } from '@lobechat/builtin-tools/renders';
|
||||
import { Accordion, AccordionItem, Flexbox, Skeleton } from '@lobehub/ui';
|
||||
import { type CSSProperties } from 'react';
|
||||
import { memo, useState } from 'react';
|
||||
|
||||
import Actions from '@/features/Conversation/Messages/AssistantGroup/Tool/Actions';
|
||||
import dynamic from '@/libs/next/dynamic';
|
||||
import { getBuiltinRender } from '@/tools/renders';
|
||||
|
||||
import { dataSelectors, messageStateSelectors, useConversationStore } from '../../../store';
|
||||
import Inspectors from '../../AssistantGroup/Tool/Inspector';
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ const mockCodeInterpreterRender = vi.fn(({ content }) => (
|
|||
<div>CodeInterpreterRender: {content}</div>
|
||||
));
|
||||
|
||||
vi.mock('@/tools/renders', () => ({
|
||||
vi.mock('@lobechat/builtin-tools/renders', () => ({
|
||||
getBuiltinRender: vi.fn((identifier, apiName) => {
|
||||
if (identifier === 'lobe-web-browsing') return mockWebBrowsingRender;
|
||||
if (identifier === 'lobe-code-interpreter') return mockCodeInterpreterRender;
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
import { getBuiltinRender } from '@lobechat/builtin-tools/renders';
|
||||
import { safeParseJSON } from '@lobechat/utils';
|
||||
import { memo } from 'react';
|
||||
|
||||
import { getBuiltinRender } from '@/tools/renders';
|
||||
|
||||
import { useParseContent } from '../useParseContent';
|
||||
|
||||
export interface BuiltinTypeProps {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
import { BuiltinToolsPortals } from '@lobechat/builtin-tools/portals';
|
||||
import isEqual from 'fast-deep-equal';
|
||||
import { memo } from 'react';
|
||||
|
||||
import PluginRender from '@/features/PluginsUI/Render';
|
||||
import { useChatStore } from '@/store/chat';
|
||||
import { chatPortalSelectors, dbMessageSelectors } from '@/store/chat/selectors';
|
||||
import { BuiltinToolsPortals } from '@/tools/portals';
|
||||
import { safeParseJSON } from '@/utils/safeParseJSON';
|
||||
|
||||
const ToolRender = memo(() => {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
*/
|
||||
import { KnowledgeBaseManifest } from '@lobechat/builtin-tool-knowledge-base';
|
||||
import { WebBrowsingManifest } from '@lobechat/builtin-tool-web-browsing';
|
||||
import { defaultToolIds } from '@lobechat/builtin-tools';
|
||||
import { isDesktop } from '@lobechat/const';
|
||||
import { type PluginEnableChecker } from '@lobechat/context-engine';
|
||||
import { ToolsEngine } from '@lobechat/context-engine';
|
||||
|
|
@ -17,7 +18,6 @@ import {
|
|||
lobehubSkillStoreSelectors,
|
||||
pluginSelectors,
|
||||
} from '@/store/tool/selectors';
|
||||
import { defaultToolIds } from '@/tools';
|
||||
|
||||
import { getSearchConfig } from '../getSearchConfig';
|
||||
import { isCanUseFC } from '../isCanUseFC';
|
||||
|
|
@ -135,8 +135,8 @@ export const getEnabledTools = (
|
|||
|
||||
return (
|
||||
toolsEngine.generateTools({
|
||||
model: model, // Use provided model or fallback
|
||||
provider: provider, // Use provided provider or fallback
|
||||
model, // Use provided model or fallback
|
||||
provider, // Use provided provider or fallback
|
||||
toolIds,
|
||||
}) || []
|
||||
);
|
||||
|
|
|
|||
|
|
@ -560,6 +560,7 @@ export const createRuntimeExecutors = (
|
|||
// Execute tool using ToolExecutionService
|
||||
log(`[${operationLogId}] Executing tool ${toolName} ...`);
|
||||
const executionResult = await toolExecutionService.executeTool(chatToolPayload, {
|
||||
memoryToolPermission: agentConfig?.chatConfig?.memory?.toolPermission,
|
||||
serverDB: ctx.serverDB,
|
||||
toolManifestMap: state.toolManifestMap,
|
||||
toolResultMaxLength,
|
||||
|
|
@ -736,6 +737,7 @@ export const createRuntimeExecutors = (
|
|||
try {
|
||||
log(`[${operationLogId}] Executing tool ${toolName} ...`);
|
||||
const executionResult = await toolExecutionService.executeTool(chatToolPayload, {
|
||||
memoryToolPermission: state.metadata?.agentConfig?.chatConfig?.memory?.toolPermission,
|
||||
serverDB: ctx.serverDB,
|
||||
toolManifestMap: state.toolManifestMap,
|
||||
topicId: ctx.topicId,
|
||||
|
|
|
|||
|
|
@ -2,11 +2,10 @@
|
|||
import { KnowledgeBaseManifest } from '@lobechat/builtin-tool-knowledge-base';
|
||||
import { LocalSystemManifest } from '@lobechat/builtin-tool-local-system';
|
||||
import { WebBrowsingManifest } from '@lobechat/builtin-tool-web-browsing';
|
||||
import { builtinTools } from '@lobechat/builtin-tools';
|
||||
import { ToolsEngine } from '@lobechat/context-engine';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
|
||||
import { builtinTools } from '@/tools';
|
||||
|
||||
import { createServerAgentToolsEngine, createServerToolsEngine } from '../index';
|
||||
import { type InstalledPlugin, type ServerAgentToolsContext } from '../types';
|
||||
|
||||
|
|
|
|||
|
|
@ -12,12 +12,11 @@
|
|||
import { KnowledgeBaseManifest } from '@lobechat/builtin-tool-knowledge-base';
|
||||
import { LocalSystemManifest } from '@lobechat/builtin-tool-local-system';
|
||||
import { WebBrowsingManifest } from '@lobechat/builtin-tool-web-browsing';
|
||||
import { builtinTools, defaultToolIds } from '@lobechat/builtin-tools';
|
||||
import { type LobeToolManifest } from '@lobechat/context-engine';
|
||||
import { ToolsEngine } from '@lobechat/context-engine';
|
||||
import debug from 'debug';
|
||||
|
||||
import { builtinTools, defaultToolIds } from '@/tools';
|
||||
|
||||
import {
|
||||
type ServerAgentToolsContext,
|
||||
type ServerAgentToolsEngineConfig,
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { type AgentRuntimeContext, type AgentState } from '@lobechat/agent-runtime';
|
||||
import type { AgentRuntimeContext, AgentState } from '@lobechat/agent-runtime';
|
||||
import { AgentRuntime, GeneralChatAgent } from '@lobechat/agent-runtime';
|
||||
import { type ChatMessageError } from '@lobechat/types';
|
||||
import { AgentRuntimeErrorType, ChatErrorType } from '@lobechat/types';
|
||||
import { dynamicInterventionAudits } from '@lobechat/builtin-tools/dynamicInterventionAudits';
|
||||
import { AgentRuntimeErrorType, ChatErrorType, type ChatMessageError } from '@lobechat/types';
|
||||
import debug from 'debug';
|
||||
import urlJoin from 'url-join';
|
||||
|
||||
|
|
@ -19,7 +19,6 @@ import { QueueService } from '@/server/services/queue';
|
|||
import { LocalQueueServiceImpl } from '@/server/services/queue/impls';
|
||||
import { ToolExecutionService } from '@/server/services/toolExecution';
|
||||
import { BuiltinToolsExecutor } from '@/server/services/toolExecution/builtin';
|
||||
import { dynamicInterventionAudits } from '@/tools/dynamicInterventionAudits';
|
||||
|
||||
import {
|
||||
type AgentExecutionParams,
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ vi.mock('@/server/services/toolExecution', () => ({
|
|||
vi.mock('@/server/services/toolExecution/builtin', () => ({
|
||||
BuiltinToolsExecutor: vi.fn().mockImplementation(() => ({})),
|
||||
}));
|
||||
vi.mock('@/tools/dynamicInterventionAudits', () => ({
|
||||
vi.mock('@lobechat/builtin-tools/dynamicInterventionAudits', () => ({
|
||||
dynamicInterventionAudits: [],
|
||||
}));
|
||||
|
||||
|
|
|
|||
|
|
@ -1130,7 +1130,7 @@ export class DiscoverService {
|
|||
}
|
||||
|
||||
// Step 3: Try to find in builtin tools
|
||||
const { builtinTools } = await import('@/tools/index');
|
||||
const { builtinTools } = await import('@lobechat/builtin-tools');
|
||||
const builtinTool = builtinTools.find((tool) => tool.identifier === identifier);
|
||||
if (builtinTool) {
|
||||
log('getPluginDetail: found builtin tool for identifier=%s', identifier);
|
||||
|
|
@ -1800,7 +1800,15 @@ export class DiscoverService {
|
|||
return undefined;
|
||||
}
|
||||
|
||||
const { user, agents, agentGroups, forkedAgents, forkedAgentGroups, favoriteAgents, favoriteAgentGroups } = response;
|
||||
const {
|
||||
user,
|
||||
agents,
|
||||
agentGroups,
|
||||
forkedAgents,
|
||||
forkedAgentGroups,
|
||||
favoriteAgents,
|
||||
favoriteAgentGroups,
|
||||
} = response;
|
||||
|
||||
// Transform agents to DiscoverAssistantItem format
|
||||
const transformedAgents: DiscoverAssistantItem[] = (agents || []).map((agent: any) => ({
|
||||
|
|
|
|||
|
|
@ -8,8 +8,10 @@
|
|||
*/
|
||||
import { type ToolExecutionContext } from '../types';
|
||||
import { cloudSandboxRuntime } from './cloudSandbox';
|
||||
import { memoryRuntime } from './memory';
|
||||
import { notebookRuntime } from './notebook';
|
||||
import { skillsRuntime } from './skills';
|
||||
import { toolsActivatorRuntime } from './tools';
|
||||
import { type ServerRuntimeFactory, type ServerRuntimeRegistration } from './types';
|
||||
import { webBrowsingRuntime } from './webBrowsing';
|
||||
|
||||
|
|
@ -28,7 +30,14 @@ const registerRuntimes = (runtimes: ServerRuntimeRegistration[]) => {
|
|||
};
|
||||
|
||||
// Register all server runtimes
|
||||
registerRuntimes([webBrowsingRuntime, cloudSandboxRuntime, notebookRuntime, skillsRuntime]);
|
||||
registerRuntimes([
|
||||
webBrowsingRuntime,
|
||||
cloudSandboxRuntime,
|
||||
notebookRuntime,
|
||||
skillsRuntime,
|
||||
memoryRuntime,
|
||||
toolsActivatorRuntime,
|
||||
]);
|
||||
|
||||
// ==================== Registry API ====================
|
||||
|
||||
|
|
|
|||
698
src/server/services/toolExecution/serverRuntimes/memory.ts
Normal file
698
src/server/services/toolExecution/serverRuntimes/memory.ts
Normal file
|
|
@ -0,0 +1,698 @@
|
|||
import { MemoryIdentifier } from '@lobechat/builtin-tool-memory';
|
||||
import {
|
||||
MemoryExecutionRuntime,
|
||||
type MemoryRuntimeService,
|
||||
} from '@lobechat/builtin-tool-memory/executionRuntime';
|
||||
import { BRANDING_PROVIDER, ENABLE_BUSINESS_FEATURES } from '@lobechat/business-const';
|
||||
import {
|
||||
DEFAULT_USER_MEMORY_EMBEDDING_DIMENSIONS,
|
||||
DEFAULT_USER_MEMORY_EMBEDDING_MODEL_ITEM,
|
||||
MEMORY_SEARCH_TOP_K_LIMITS,
|
||||
} from '@lobechat/const';
|
||||
import type { LobeChatDatabase } from '@lobechat/database';
|
||||
import type {
|
||||
ActivityMemoryItemSchema,
|
||||
AddIdentityActionSchema,
|
||||
ContextMemoryItemSchema,
|
||||
ExperienceMemoryItemSchema,
|
||||
PreferenceMemoryItemSchema,
|
||||
RemoveIdentityActionSchema,
|
||||
UpdateIdentityActionSchema,
|
||||
} from '@lobechat/memory-user-memory/schemas';
|
||||
import type {
|
||||
AddActivityMemoryResult,
|
||||
AddContextMemoryResult,
|
||||
AddExperienceMemoryResult,
|
||||
AddIdentityMemoryResult,
|
||||
AddPreferenceMemoryResult,
|
||||
RemoveIdentityMemoryResult,
|
||||
SearchMemoryParams,
|
||||
SearchMemoryResult,
|
||||
UpdateIdentityMemoryResult,
|
||||
} from '@lobechat/types';
|
||||
import { LayersEnum } from '@lobechat/types';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import type { z } from 'zod';
|
||||
|
||||
import {
|
||||
type IdentityEntryBasePayload,
|
||||
type IdentityEntryPayload,
|
||||
UserMemoryModel,
|
||||
} from '@/database/models/userMemory';
|
||||
import { userSettings } from '@/database/schemas';
|
||||
import { getServerDefaultFilesConfig } from '@/server/globalConfig';
|
||||
import { initModelRuntimeFromDB } from '@/server/modules/ModelRuntime';
|
||||
|
||||
import type { ServerRuntimeRegistration } from './types';
|
||||
|
||||
type MemoryEffort = 'high' | 'low' | 'medium';
|
||||
|
||||
const normalizeMemoryEffort = (value: unknown): MemoryEffort => {
|
||||
if (value === 'low' || value === 'medium' || value === 'high') return value;
|
||||
return 'medium';
|
||||
};
|
||||
|
||||
const applySearchLimitsByEffort = (
|
||||
effort: MemoryEffort,
|
||||
requested: { activities: number; contexts: number; experiences: number; preferences: number },
|
||||
) => {
|
||||
const limit = MEMORY_SEARCH_TOP_K_LIMITS[effort];
|
||||
|
||||
return {
|
||||
activities: Math.min(requested.activities, limit.activities),
|
||||
contexts: Math.min(requested.contexts, limit.contexts),
|
||||
experiences: Math.min(requested.experiences, limit.experiences),
|
||||
preferences: Math.min(requested.preferences, limit.preferences),
|
||||
};
|
||||
};
|
||||
|
||||
const mapMemorySearchResult = (
|
||||
layeredResults: Awaited<ReturnType<UserMemoryModel['searchWithEmbedding']>>,
|
||||
): SearchMemoryResult => {
|
||||
return {
|
||||
activities: layeredResults.activities.map((activity) => ({
|
||||
accessedAt: activity.accessedAt,
|
||||
associatedLocations: activity.associatedLocations,
|
||||
associatedObjects: activity.associatedObjects,
|
||||
associatedSubjects: activity.associatedSubjects,
|
||||
capturedAt: activity.capturedAt,
|
||||
createdAt: activity.createdAt,
|
||||
endsAt: activity.endsAt,
|
||||
feedback: activity.feedback,
|
||||
id: activity.id,
|
||||
metadata: activity.metadata,
|
||||
narrative: activity.narrative,
|
||||
notes: activity.notes,
|
||||
startsAt: activity.startsAt,
|
||||
status: activity.status,
|
||||
tags: activity.tags,
|
||||
timezone: activity.timezone,
|
||||
type: activity.type,
|
||||
updatedAt: activity.updatedAt,
|
||||
userMemoryId: activity.userMemoryId,
|
||||
})),
|
||||
contexts: layeredResults.contexts.map((context) => ({
|
||||
accessedAt: context.accessedAt,
|
||||
associatedObjects: context.associatedObjects,
|
||||
associatedSubjects: context.associatedSubjects,
|
||||
createdAt: context.createdAt,
|
||||
currentStatus: context.currentStatus,
|
||||
description: context.description,
|
||||
id: context.id,
|
||||
metadata: context.metadata,
|
||||
scoreImpact: context.scoreImpact,
|
||||
scoreUrgency: context.scoreUrgency,
|
||||
tags: context.tags,
|
||||
title: context.title,
|
||||
type: context.type,
|
||||
updatedAt: context.updatedAt,
|
||||
userMemoryIds: Array.isArray(context.userMemoryIds)
|
||||
? (context.userMemoryIds as string[])
|
||||
: null,
|
||||
})),
|
||||
experiences: layeredResults.experiences.map((experience) => ({
|
||||
accessedAt: experience.accessedAt,
|
||||
action: experience.action,
|
||||
createdAt: experience.createdAt,
|
||||
id: experience.id,
|
||||
keyLearning: experience.keyLearning,
|
||||
metadata: experience.metadata,
|
||||
possibleOutcome: experience.possibleOutcome,
|
||||
reasoning: experience.reasoning,
|
||||
scoreConfidence: experience.scoreConfidence,
|
||||
situation: experience.situation,
|
||||
tags: experience.tags,
|
||||
type: experience.type,
|
||||
updatedAt: experience.updatedAt,
|
||||
userMemoryId: experience.userMemoryId,
|
||||
})),
|
||||
preferences: layeredResults.preferences.map((preference) => ({
|
||||
accessedAt: preference.accessedAt,
|
||||
conclusionDirectives: preference.conclusionDirectives,
|
||||
createdAt: preference.createdAt,
|
||||
id: preference.id,
|
||||
metadata: preference.metadata,
|
||||
scorePriority: preference.scorePriority,
|
||||
suggestions: preference.suggestions,
|
||||
tags: preference.tags,
|
||||
type: preference.type,
|
||||
updatedAt: preference.updatedAt,
|
||||
userMemoryId: preference.userMemoryId,
|
||||
})),
|
||||
} satisfies SearchMemoryResult;
|
||||
};
|
||||
|
||||
const getEmbeddingRuntime = async (serverDB: LobeChatDatabase, userId: string) => {
|
||||
const { provider, model: embeddingModel } =
|
||||
getServerDefaultFilesConfig().embeddingModel || DEFAULT_USER_MEMORY_EMBEDDING_MODEL_ITEM;
|
||||
|
||||
const agentRuntime = await initModelRuntimeFromDB(
|
||||
serverDB,
|
||||
userId,
|
||||
ENABLE_BUSINESS_FEATURES ? BRANDING_PROVIDER : provider,
|
||||
);
|
||||
|
||||
return { agentRuntime, embeddingModel };
|
||||
};
|
||||
|
||||
const createEmbedder = (agentRuntime: any, embeddingModel: string) => {
|
||||
return async (value?: string | null): Promise<number[] | undefined> => {
|
||||
if (!value || value.trim().length === 0) return undefined;
|
||||
|
||||
const embeddings = await agentRuntime.embeddings({
|
||||
dimensions: DEFAULT_USER_MEMORY_EMBEDDING_DIMENSIONS,
|
||||
input: value,
|
||||
model: embeddingModel,
|
||||
});
|
||||
|
||||
return embeddings?.[0];
|
||||
};
|
||||
};
|
||||
|
||||
class MemoryServerRuntimeService implements MemoryRuntimeService {
|
||||
private memoryModel: UserMemoryModel;
|
||||
private serverDB: LobeChatDatabase;
|
||||
private userId: string;
|
||||
private memoryEffort: MemoryEffort;
|
||||
|
||||
constructor(options: {
|
||||
memoryEffort: MemoryEffort;
|
||||
memoryModel: UserMemoryModel;
|
||||
serverDB: LobeChatDatabase;
|
||||
userId: string;
|
||||
}) {
|
||||
this.memoryModel = options.memoryModel;
|
||||
this.serverDB = options.serverDB;
|
||||
this.userId = options.userId;
|
||||
this.memoryEffort = options.memoryEffort;
|
||||
}
|
||||
|
||||
searchMemory = async (params: SearchMemoryParams): Promise<SearchMemoryResult> => {
|
||||
const { provider, model: embeddingModel } =
|
||||
getServerDefaultFilesConfig().embeddingModel || DEFAULT_USER_MEMORY_EMBEDDING_MODEL_ITEM;
|
||||
|
||||
const modelRuntime = await initModelRuntimeFromDB(this.serverDB, this.userId, provider);
|
||||
|
||||
const queryEmbeddings = await modelRuntime.embeddings({
|
||||
dimensions: DEFAULT_USER_MEMORY_EMBEDDING_DIMENSIONS,
|
||||
input: params.query,
|
||||
model: embeddingModel,
|
||||
});
|
||||
|
||||
const effectiveEffort = normalizeMemoryEffort(params.effort ?? this.memoryEffort);
|
||||
const effortDefaults = MEMORY_SEARCH_TOP_K_LIMITS[effectiveEffort];
|
||||
|
||||
const requestedLimits = {
|
||||
activities: params.topK?.activities ?? effortDefaults.activities,
|
||||
contexts: params.topK?.contexts ?? effortDefaults.contexts,
|
||||
experiences: params.topK?.experiences ?? effortDefaults.experiences,
|
||||
preferences: params.topK?.preferences ?? effortDefaults.preferences,
|
||||
};
|
||||
|
||||
const effortConstrainedLimits = applySearchLimitsByEffort(effectiveEffort, requestedLimits);
|
||||
|
||||
const layeredResults = await this.memoryModel.searchWithEmbedding({
|
||||
embedding: queryEmbeddings?.[0],
|
||||
limits: effortConstrainedLimits,
|
||||
});
|
||||
|
||||
return mapMemorySearchResult(layeredResults);
|
||||
};
|
||||
|
||||
addContextMemory = async (
|
||||
input: z.infer<typeof ContextMemoryItemSchema>,
|
||||
): Promise<AddContextMemoryResult> => {
|
||||
try {
|
||||
const { agentRuntime, embeddingModel } = await getEmbeddingRuntime(
|
||||
this.serverDB,
|
||||
this.userId,
|
||||
);
|
||||
const embed = createEmbedder(agentRuntime, embeddingModel);
|
||||
|
||||
const summaryEmbedding = await embed(input.summary);
|
||||
const detailsEmbedding = await embed(input.details);
|
||||
const contextDescriptionEmbedding = await embed(input.withContext.description);
|
||||
|
||||
const { context, memory } = await this.memoryModel.createContextMemory({
|
||||
context: {
|
||||
associatedObjects:
|
||||
UserMemoryModel.parseAssociatedObjects(input.withContext.associatedObjects) ?? null,
|
||||
associatedSubjects:
|
||||
UserMemoryModel.parseAssociatedSubjects(input.withContext.associatedSubjects) ?? null,
|
||||
currentStatus: input.withContext.currentStatus ?? null,
|
||||
description: input.withContext.description ?? null,
|
||||
descriptionVector: contextDescriptionEmbedding ?? null,
|
||||
metadata: {},
|
||||
scoreImpact: input.withContext.scoreImpact ?? null,
|
||||
scoreUrgency: input.withContext.scoreUrgency ?? null,
|
||||
tags: input.tags ?? [],
|
||||
title: input.withContext.title ?? null,
|
||||
type: input.withContext.type ?? null,
|
||||
},
|
||||
details: input.details || '',
|
||||
detailsEmbedding,
|
||||
memoryCategory: input.memoryCategory,
|
||||
memoryLayer: LayersEnum.Context,
|
||||
memoryType: input.memoryType,
|
||||
summary: input.summary,
|
||||
summaryEmbedding,
|
||||
title: input.title,
|
||||
});
|
||||
|
||||
return {
|
||||
contextId: context.id,
|
||||
memoryId: memory.id,
|
||||
message: 'Memory saved successfully',
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
message: `Failed to save memory: ${(error as Error).message}`,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
addActivityMemory = async (
|
||||
input: z.infer<typeof ActivityMemoryItemSchema>,
|
||||
): Promise<AddActivityMemoryResult> => {
|
||||
try {
|
||||
const { agentRuntime, embeddingModel } = await getEmbeddingRuntime(
|
||||
this.serverDB,
|
||||
this.userId,
|
||||
);
|
||||
const embed = createEmbedder(agentRuntime, embeddingModel);
|
||||
|
||||
const summaryEmbedding = await embed(input.summary);
|
||||
const detailsEmbedding = await embed(input.details);
|
||||
const narrativeVector = await embed(input.withActivity.narrative);
|
||||
const feedbackVector = await embed(input.withActivity.feedback);
|
||||
|
||||
const { activity, memory } = await this.memoryModel.createActivityMemory({
|
||||
activity: {
|
||||
associatedLocations:
|
||||
UserMemoryModel.parseAssociatedLocations(input.withActivity.associatedLocations) ??
|
||||
null,
|
||||
associatedObjects:
|
||||
UserMemoryModel.parseAssociatedObjects(input.withActivity.associatedObjects) ?? [],
|
||||
associatedSubjects:
|
||||
UserMemoryModel.parseAssociatedSubjects(input.withActivity.associatedSubjects) ?? [],
|
||||
endsAt: UserMemoryModel.parseDateFromString(input.withActivity.endsAt ?? undefined),
|
||||
feedback: input.withActivity.feedback ?? null,
|
||||
feedbackVector: feedbackVector ?? null,
|
||||
metadata: input.withActivity.metadata ?? null,
|
||||
narrative: input.withActivity.narrative ?? null,
|
||||
narrativeVector: narrativeVector ?? null,
|
||||
notes: input.withActivity.notes ?? null,
|
||||
startsAt: UserMemoryModel.parseDateFromString(input.withActivity.startsAt ?? undefined),
|
||||
status: input.withActivity.status ?? 'pending',
|
||||
tags: input.withActivity.tags ?? input.tags ?? [],
|
||||
timezone: input.withActivity.timezone ?? null,
|
||||
type: input.withActivity.type ?? 'other',
|
||||
},
|
||||
details: input.details || '',
|
||||
detailsEmbedding,
|
||||
memoryCategory: input.memoryCategory,
|
||||
memoryLayer: LayersEnum.Activity,
|
||||
memoryType: input.memoryType,
|
||||
summary: input.summary,
|
||||
summaryEmbedding,
|
||||
title: input.title,
|
||||
});
|
||||
|
||||
return {
|
||||
activityId: activity.id,
|
||||
memoryId: memory.id,
|
||||
message: 'Memory saved successfully',
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
message: `Failed to save memory: ${(error as Error).message}`,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
addExperienceMemory = async (
|
||||
input: z.infer<typeof ExperienceMemoryItemSchema>,
|
||||
): Promise<AddExperienceMemoryResult> => {
|
||||
try {
|
||||
const { agentRuntime, embeddingModel } = await getEmbeddingRuntime(
|
||||
this.serverDB,
|
||||
this.userId,
|
||||
);
|
||||
const embed = createEmbedder(agentRuntime, embeddingModel);
|
||||
|
||||
const summaryEmbedding = await embed(input.summary);
|
||||
const detailsEmbedding = await embed(input.details);
|
||||
const situationVector = await embed(input.withExperience.situation);
|
||||
const actionVector = await embed(input.withExperience.action);
|
||||
const keyLearningVector = await embed(input.withExperience.keyLearning);
|
||||
|
||||
const { experience, memory } = await this.memoryModel.createExperienceMemory({
|
||||
details: input.details || '',
|
||||
detailsEmbedding,
|
||||
experience: {
|
||||
action: input.withExperience.action ?? null,
|
||||
actionVector: actionVector ?? null,
|
||||
keyLearning: input.withExperience.keyLearning ?? null,
|
||||
keyLearningVector: keyLearningVector ?? null,
|
||||
metadata: {},
|
||||
possibleOutcome: input.withExperience.possibleOutcome ?? null,
|
||||
reasoning: input.withExperience.reasoning ?? null,
|
||||
scoreConfidence: input.withExperience.scoreConfidence ?? null,
|
||||
situation: input.withExperience.situation ?? null,
|
||||
situationVector: situationVector ?? null,
|
||||
tags: input.tags ?? [],
|
||||
type: input.memoryType,
|
||||
},
|
||||
memoryCategory: input.memoryCategory,
|
||||
memoryLayer: LayersEnum.Experience,
|
||||
memoryType: input.memoryType,
|
||||
summary: input.summary,
|
||||
summaryEmbedding,
|
||||
title: input.title,
|
||||
});
|
||||
|
||||
return {
|
||||
experienceId: experience.id,
|
||||
memoryId: memory.id,
|
||||
message: 'Memory saved successfully',
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
message: `Failed to save memory: ${(error as Error).message}`,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
addIdentityMemory = async (
|
||||
input: z.infer<typeof AddIdentityActionSchema>,
|
||||
): Promise<AddIdentityMemoryResult> => {
|
||||
try {
|
||||
const { agentRuntime, embeddingModel } = await getEmbeddingRuntime(
|
||||
this.serverDB,
|
||||
this.userId,
|
||||
);
|
||||
const embed = createEmbedder(agentRuntime, embeddingModel);
|
||||
|
||||
const summaryEmbedding = await embed(input.summary);
|
||||
const detailsEmbedding = await embed(input.details);
|
||||
const descriptionEmbedding = await embed(input.withIdentity.description);
|
||||
|
||||
const identityMetadata: Record<string, unknown> = {};
|
||||
if (
|
||||
input.withIdentity.scoreConfidence !== null &&
|
||||
input.withIdentity.scoreConfidence !== undefined
|
||||
) {
|
||||
identityMetadata.scoreConfidence = input.withIdentity.scoreConfidence;
|
||||
}
|
||||
if (
|
||||
input.withIdentity.sourceEvidence !== null &&
|
||||
input.withIdentity.sourceEvidence !== undefined
|
||||
) {
|
||||
identityMetadata.sourceEvidence = input.withIdentity.sourceEvidence;
|
||||
}
|
||||
|
||||
const { identityId, userMemoryId } = await this.memoryModel.addIdentityEntry({
|
||||
base: {
|
||||
details: input.details,
|
||||
detailsVector1024: detailsEmbedding ?? null,
|
||||
memoryCategory: input.memoryCategory,
|
||||
memoryLayer: LayersEnum.Identity,
|
||||
memoryType: input.memoryType,
|
||||
metadata: Object.keys(identityMetadata).length > 0 ? identityMetadata : undefined,
|
||||
summary: input.summary,
|
||||
summaryVector1024: summaryEmbedding ?? null,
|
||||
tags: input.tags,
|
||||
title: input.title,
|
||||
},
|
||||
identity: {
|
||||
description: input.withIdentity.description,
|
||||
descriptionVector: descriptionEmbedding ?? null,
|
||||
episodicDate: input.withIdentity.episodicDate,
|
||||
metadata: Object.keys(identityMetadata).length > 0 ? identityMetadata : undefined,
|
||||
relationship: input.withIdentity.relationship,
|
||||
role: input.withIdentity.role,
|
||||
tags: input.tags,
|
||||
type: input.withIdentity.type,
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
identityId,
|
||||
memoryId: userMemoryId,
|
||||
message: 'Identity memory saved successfully',
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
message: `Failed to save identity memory: ${(error as Error).message}`,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
addPreferenceMemory = async (
|
||||
input: z.infer<typeof PreferenceMemoryItemSchema>,
|
||||
): Promise<AddPreferenceMemoryResult> => {
|
||||
try {
|
||||
const { agentRuntime, embeddingModel } = await getEmbeddingRuntime(
|
||||
this.serverDB,
|
||||
this.userId,
|
||||
);
|
||||
const embed = createEmbedder(agentRuntime, embeddingModel);
|
||||
|
||||
const summaryEmbedding = await embed(input.summary);
|
||||
const detailsEmbedding = await embed(input.details);
|
||||
const conclusionVector = await embed(input.withPreference.conclusionDirectives);
|
||||
|
||||
const suggestionsText =
|
||||
input.withPreference?.suggestions?.length && input.withPreference?.suggestions?.length > 0
|
||||
? input.withPreference?.suggestions?.join('\n')
|
||||
: null;
|
||||
|
||||
const metadata = {
|
||||
appContext: input.withPreference.appContext,
|
||||
extractedScopes: input.withPreference.extractedScopes,
|
||||
originContext: input.withPreference.originContext,
|
||||
} satisfies Record<string, unknown>;
|
||||
|
||||
const { memory, preference } = await this.memoryModel.createPreferenceMemory({
|
||||
details: input.details || '',
|
||||
detailsEmbedding,
|
||||
memoryCategory: input.memoryCategory,
|
||||
memoryLayer: LayersEnum.Preference,
|
||||
memoryType: input.memoryType,
|
||||
preference: {
|
||||
conclusionDirectives: input.withPreference.conclusionDirectives || '',
|
||||
conclusionDirectivesVector: conclusionVector ?? null,
|
||||
metadata,
|
||||
scorePriority: input.withPreference.scorePriority ?? null,
|
||||
suggestions: suggestionsText,
|
||||
tags: input.tags,
|
||||
type: input.memoryType,
|
||||
},
|
||||
summary: input.summary,
|
||||
summaryEmbedding,
|
||||
title: input.title,
|
||||
});
|
||||
|
||||
return {
|
||||
memoryId: memory.id,
|
||||
message: 'Memory saved successfully',
|
||||
preferenceId: preference.id,
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
message: `Failed to save memory: ${(error as Error).message}`,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
updateIdentityMemory = async (
|
||||
input: z.infer<typeof UpdateIdentityActionSchema>,
|
||||
): Promise<UpdateIdentityMemoryResult> => {
|
||||
try {
|
||||
const { agentRuntime, embeddingModel } = await getEmbeddingRuntime(
|
||||
this.serverDB,
|
||||
this.userId,
|
||||
);
|
||||
const embed = createEmbedder(agentRuntime, embeddingModel);
|
||||
|
||||
let summaryVector1024: number[] | null | undefined;
|
||||
if (input.set.summary !== undefined) {
|
||||
const vector = await embed(input.set.summary);
|
||||
summaryVector1024 = vector ?? null;
|
||||
}
|
||||
|
||||
let detailsVector1024: number[] | null | undefined;
|
||||
if (input.set.details !== undefined) {
|
||||
const vector = await embed(input.set.details);
|
||||
detailsVector1024 = vector ?? null;
|
||||
}
|
||||
|
||||
let descriptionVector: number[] | null | undefined;
|
||||
if (input.set.withIdentity.description !== undefined) {
|
||||
const vector = await embed(input.set.withIdentity.description);
|
||||
descriptionVector = vector ?? null;
|
||||
}
|
||||
|
||||
const metadataUpdates: Record<string, unknown> = {};
|
||||
if (Object.hasOwn(input.set.withIdentity, 'scoreConfidence')) {
|
||||
metadataUpdates.scoreConfidence = input.set.withIdentity.scoreConfidence ?? null;
|
||||
}
|
||||
if (Object.hasOwn(input.set.withIdentity, 'sourceEvidence')) {
|
||||
metadataUpdates.sourceEvidence = input.set.withIdentity.sourceEvidence ?? null;
|
||||
}
|
||||
|
||||
const identityPayload: Partial<IdentityEntryPayload> = {};
|
||||
if (input.set.withIdentity.description !== undefined) {
|
||||
identityPayload.description = input.set.withIdentity.description;
|
||||
identityPayload.descriptionVector = descriptionVector;
|
||||
}
|
||||
if (input.set.withIdentity.episodicDate !== undefined) {
|
||||
identityPayload.episodicDate = input.set.withIdentity.episodicDate;
|
||||
}
|
||||
if (input.set.withIdentity.relationship !== undefined) {
|
||||
identityPayload.relationship = input.set.withIdentity.relationship;
|
||||
}
|
||||
if (input.set.withIdentity.role !== undefined) {
|
||||
identityPayload.role = input.set.withIdentity.role;
|
||||
}
|
||||
if (input.set.tags !== undefined) {
|
||||
identityPayload.tags = input.set.tags;
|
||||
}
|
||||
if (input.set.withIdentity.type !== undefined) {
|
||||
identityPayload.type = input.set.withIdentity.type;
|
||||
}
|
||||
if (Object.keys(metadataUpdates).length > 0) {
|
||||
identityPayload.metadata = metadataUpdates;
|
||||
}
|
||||
|
||||
const basePayload: Partial<IdentityEntryBasePayload> = {};
|
||||
if (input.set.details !== undefined) {
|
||||
basePayload.details = input.set.details;
|
||||
basePayload.detailsVector1024 = detailsVector1024;
|
||||
}
|
||||
if (input.set.memoryCategory !== undefined) {
|
||||
basePayload.memoryCategory = input.set.memoryCategory;
|
||||
}
|
||||
if (input.set.memoryType !== undefined) {
|
||||
basePayload.memoryType = input.set.memoryType;
|
||||
}
|
||||
if (input.set.summary !== undefined) {
|
||||
basePayload.summary = input.set.summary;
|
||||
basePayload.summaryVector1024 = summaryVector1024;
|
||||
}
|
||||
if (input.set.tags !== undefined) {
|
||||
basePayload.tags = input.set.tags;
|
||||
}
|
||||
if (input.set.title !== undefined) {
|
||||
basePayload.title = input.set.title;
|
||||
}
|
||||
if (Object.keys(metadataUpdates).length > 0) {
|
||||
basePayload.metadata = metadataUpdates;
|
||||
}
|
||||
|
||||
const updated = await this.memoryModel.updateIdentityEntry({
|
||||
base: Object.keys(basePayload).length > 0 ? basePayload : undefined,
|
||||
identity: Object.keys(identityPayload).length > 0 ? identityPayload : undefined,
|
||||
identityId: input.id,
|
||||
mergeStrategy: input.mergeStrategy,
|
||||
});
|
||||
|
||||
if (!updated) {
|
||||
return {
|
||||
message: 'Identity memory not found',
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
identityId: input.id,
|
||||
message: 'Identity memory updated successfully',
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
message: `Failed to update identity memory: ${(error as Error).message}`,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
removeIdentityMemory = async (
|
||||
input: z.infer<typeof RemoveIdentityActionSchema>,
|
||||
): Promise<RemoveIdentityMemoryResult> => {
|
||||
try {
|
||||
const removed = await this.memoryModel.removeIdentityEntry(input.id);
|
||||
|
||||
if (!removed) {
|
||||
return {
|
||||
message: 'Identity memory not found',
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
identityId: input.id,
|
||||
message: 'Identity memory removed successfully',
|
||||
reason: input.reason,
|
||||
success: true,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
message: `Failed to remove identity memory: ${(error as Error).message}`,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export const memoryRuntime: ServerRuntimeRegistration = {
|
||||
factory: async (context) => {
|
||||
if (!context.serverDB) {
|
||||
throw new Error('serverDB is required for Memory execution');
|
||||
}
|
||||
if (!context.userId) {
|
||||
throw new Error('userId is required for Memory execution');
|
||||
}
|
||||
|
||||
// Resolve memoryEffort from user settings
|
||||
let memoryEffort: MemoryEffort = 'medium';
|
||||
try {
|
||||
const userSettingsRow = await context.serverDB.query.userSettings.findFirst({
|
||||
columns: { memory: true },
|
||||
where: eq(userSettings.id, context.userId),
|
||||
});
|
||||
const memoryConfig =
|
||||
typeof userSettingsRow?.memory === 'object' && userSettingsRow?.memory !== null
|
||||
? (userSettingsRow.memory as { effort?: unknown })
|
||||
: undefined;
|
||||
memoryEffort = normalizeMemoryEffort(memoryConfig?.effort);
|
||||
} catch {
|
||||
// fallback to medium
|
||||
}
|
||||
|
||||
const memoryModel = new UserMemoryModel(context.serverDB, context.userId);
|
||||
|
||||
const service = new MemoryServerRuntimeService({
|
||||
memoryEffort,
|
||||
memoryModel,
|
||||
serverDB: context.serverDB,
|
||||
userId: context.userId,
|
||||
});
|
||||
|
||||
return new MemoryExecutionRuntime({
|
||||
service,
|
||||
toolPermission: context.memoryToolPermission,
|
||||
});
|
||||
},
|
||||
identifier: MemoryIdentifier,
|
||||
};
|
||||
37
src/server/services/toolExecution/serverRuntimes/tools.ts
Normal file
37
src/server/services/toolExecution/serverRuntimes/tools.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import { LobeToolIdentifier } from '@lobechat/builtin-tool-tools';
|
||||
import {
|
||||
type ToolManifestInfo,
|
||||
ToolsActivatorExecutionRuntime,
|
||||
type ToolsActivatorRuntimeService,
|
||||
} from '@lobechat/builtin-tool-tools/executionRuntime';
|
||||
|
||||
import { type ServerRuntimeRegistration } from './types';
|
||||
|
||||
/**
|
||||
* Tools Activator Server Runtime
|
||||
* Stub implementation — actual tool manifest resolution
|
||||
* will be implemented in follow-up work when ToolDiscoveryProvider is ready.
|
||||
*/
|
||||
export const toolsActivatorRuntime: ServerRuntimeRegistration = {
|
||||
factory: (_context) => {
|
||||
const activatedIds: string[] = [];
|
||||
|
||||
const service: ToolsActivatorRuntimeService = {
|
||||
getActivatedToolIds: () => [...activatedIds],
|
||||
getToolManifests: async (_identifiers: string[]): Promise<ToolManifestInfo[]> => {
|
||||
// Stub: will be replaced with real tool manifest lookup
|
||||
return [];
|
||||
},
|
||||
markActivated: (identifiers: string[]) => {
|
||||
for (const id of identifiers) {
|
||||
if (!activatedIds.includes(id)) {
|
||||
activatedIds.push(id);
|
||||
}
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
return new ToolsActivatorExecutionRuntime({ service });
|
||||
},
|
||||
identifier: LobeToolIdentifier,
|
||||
};
|
||||
|
|
@ -3,6 +3,8 @@ import { type LobeChatDatabase } from '@lobechat/database';
|
|||
import { type ChatToolPayload } from '@lobechat/types';
|
||||
|
||||
export interface ToolExecutionContext {
|
||||
/** Memory tool permission from agent chat config */
|
||||
memoryToolPermission?: 'read-only' | 'read-write';
|
||||
/** Server database for LobeHub Skills execution */
|
||||
serverDB?: LobeChatDatabase;
|
||||
toolManifestMap: Record<string, LobeToolManifest>;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import {
|
|||
} from '@lobechat/agent-runtime';
|
||||
import { AgentRuntime, computeStepContext, GeneralChatAgent } from '@lobechat/agent-runtime';
|
||||
import { PageAgentIdentifier } from '@lobechat/builtin-tool-page-agent';
|
||||
import { dynamicInterventionAudits } from '@lobechat/builtin-tools/dynamicInterventionAudits';
|
||||
import { isDesktop } from '@lobechat/const';
|
||||
import {
|
||||
type ChatToolPayload,
|
||||
|
|
@ -36,7 +37,6 @@ import { pageAgentRuntime } from '@/store/tool/slices/builtin/executors/lobe-pag
|
|||
import { type StoreSetter } from '@/store/types';
|
||||
import { toolInterventionSelectors } from '@/store/user/selectors';
|
||||
import { getUserStoreState } from '@/store/user/store';
|
||||
import { dynamicInterventionAudits } from '@/tools/dynamicInterventionAudits';
|
||||
import { markdownToTxt } from '@/utils/markdownToTxt';
|
||||
|
||||
import { topicSelectors } from '../../../selectors';
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
/* eslint-disable sort-keys-fix/sort-keys-fix, typescript-sort-keys/interface */
|
||||
import { builtinTools } from '@lobechat/builtin-tools';
|
||||
import { ToolArgumentsRepairer, ToolNameResolver } from '@lobechat/context-engine';
|
||||
import { type ChatToolPayload, type MessageToolCall } from '@lobechat/types';
|
||||
import { type LobeChatPluginManifest } from '@lobehub/chat-plugin-sdk';
|
||||
|
|
@ -11,7 +12,6 @@ import {
|
|||
pluginSelectors,
|
||||
} from '@/store/tool/selectors';
|
||||
import { type StoreSetter } from '@/store/types';
|
||||
import { builtinTools } from '@/tools';
|
||||
|
||||
/**
|
||||
* Internal utility methods and runtime state management
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import type { BuiltinToolContext, BuiltinToolResult, IBuiltinToolExecutor } from
|
|||
import { notebookExecutor } from './lobe-notebook';
|
||||
import { pageAgentExecutor } from './lobe-page-agent';
|
||||
import { skillsExecutor } from './lobe-skills';
|
||||
import { toolsActivatorExecutor } from './lobe-tools';
|
||||
import { webBrowsing } from './lobe-web-browsing';
|
||||
|
||||
// ==================== Import and register all executors ====================
|
||||
|
|
@ -132,5 +133,6 @@ registerExecutors([
|
|||
notebookExecutor,
|
||||
pageAgentExecutor,
|
||||
skillsExecutor,
|
||||
toolsActivatorExecutor,
|
||||
webBrowsing,
|
||||
]);
|
||||
|
|
|
|||
31
src/store/tool/slices/builtin/executors/lobe-tools.ts
Normal file
31
src/store/tool/slices/builtin/executors/lobe-tools.ts
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
/**
|
||||
* Lobe Tools Executor
|
||||
*
|
||||
* Creates and exports the ToolsActivatorExecutor instance for registration.
|
||||
* Injects a stub service as dependency — actual tool manifest resolution
|
||||
* will be implemented in follow-up work when ToolDiscoveryProvider is ready.
|
||||
*/
|
||||
import {
|
||||
type ToolManifestInfo,
|
||||
ToolsActivatorExecutionRuntime,
|
||||
type ToolsActivatorRuntimeService,
|
||||
} from '@lobechat/builtin-tool-tools/executionRuntime';
|
||||
import { ToolsActivatorExecutor } from '@lobechat/builtin-tool-tools/executor';
|
||||
|
||||
// Stub service — will be replaced with real implementation
|
||||
// when ToolDiscoveryProvider and state.tools mutations are ready
|
||||
const stubService: ToolsActivatorRuntimeService = {
|
||||
getActivatedToolIds: () => [],
|
||||
getToolManifests: async (_identifiers: string[]): Promise<ToolManifestInfo[]> => {
|
||||
return [];
|
||||
},
|
||||
markActivated: () => {},
|
||||
};
|
||||
|
||||
// Create runtime with stub service
|
||||
const runtime = new ToolsActivatorExecutionRuntime({
|
||||
service: stubService,
|
||||
});
|
||||
|
||||
// Create executor instance with the runtime
|
||||
export const toolsActivatorExecutor = new ToolsActivatorExecutor(runtime);
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
import { builtinSkills } from '@lobechat/builtin-skills';
|
||||
import { builtinTools } from '@lobechat/builtin-tools';
|
||||
import { type BuiltinSkill, type LobeBuiltinTool } from '@lobechat/types';
|
||||
|
||||
import { builtinTools } from '@/tools';
|
||||
|
||||
export interface BuiltinToolState {
|
||||
builtinSkills: BuiltinSkill[];
|
||||
builtinToolLoading: Record<string, boolean>;
|
||||
|
|
|
|||
Loading…
Reference in a new issue