setup(frontend): rename frontend-react
This commit is contained in:
82
frontend-react/src/storage/debug.ts
Normal file
82
frontend-react/src/storage/debug.ts
Normal file
@@ -0,0 +1,82 @@
|
||||
import { autorun } from 'mobx';
|
||||
import { GlobalStorage } from '.';
|
||||
|
||||
export const debug = (store: GlobalStorage) => {
|
||||
autorun(() => {
|
||||
const { availiableAgents } = store;
|
||||
console.groupCollapsed('[LOG] GetAgent:', availiableAgents.length);
|
||||
for (const agent of availiableAgents) {
|
||||
// console 输出,name 粗体,profile 正常
|
||||
console.info('%c%s', 'font-weight: bold', agent.name, agent.profile);
|
||||
}
|
||||
console.groupEnd();
|
||||
});
|
||||
|
||||
autorun(() => {
|
||||
const { agentCards } = store;
|
||||
console.groupCollapsed('[LOG] AgentCards:', agentCards.length);
|
||||
for (const agentCard of agentCards) {
|
||||
console.groupCollapsed(
|
||||
`agent: ${agentCard.name}`,
|
||||
'inuse:',
|
||||
agentCard.inuse,
|
||||
'action:',
|
||||
agentCard.actions.length,
|
||||
);
|
||||
for (const action of agentCard.actions) {
|
||||
console.groupCollapsed(
|
||||
'%c%s',
|
||||
`font-weight: bold`,
|
||||
action.type,
|
||||
action.description,
|
||||
'input:',
|
||||
action.inputs.length,
|
||||
);
|
||||
for (const input of action.inputs) {
|
||||
console.info(input);
|
||||
}
|
||||
console.groupEnd();
|
||||
}
|
||||
console.groupEnd();
|
||||
}
|
||||
console.groupEnd();
|
||||
});
|
||||
|
||||
autorun(() => {
|
||||
const { refMap } = store;
|
||||
console.groupCollapsed('[LOG] RefMap');
|
||||
for (const [key, map] of Object.entries(refMap)) {
|
||||
console.groupCollapsed(key);
|
||||
for (const [k, v] of map) {
|
||||
console.info(k, v);
|
||||
}
|
||||
console.groupEnd();
|
||||
}
|
||||
console.groupEnd();
|
||||
});
|
||||
|
||||
autorun(() => {
|
||||
const { planManager } = store;
|
||||
console.groupCollapsed('[LOG] planManager');
|
||||
console.info(planManager);
|
||||
const currentLeafId = planManager.currentStepTaskLeaf;
|
||||
if (currentLeafId) {
|
||||
const currentPath = planManager.stepTaskMap.get(currentLeafId)?.path;
|
||||
const outline = {
|
||||
initialInputs: planManager.inputs,
|
||||
processes: currentPath
|
||||
?.map(nodeId => planManager.stepTaskMap.get(nodeId))
|
||||
.filter(node => node)
|
||||
.map(node => ({
|
||||
inputs: node?.inputs,
|
||||
output: node?.output,
|
||||
StepName: node?.name,
|
||||
AgentSelection: node?.agentSelection,
|
||||
})),
|
||||
};
|
||||
console.log(outline);
|
||||
}
|
||||
|
||||
console.groupEnd();
|
||||
});
|
||||
};
|
||||
1141
frontend-react/src/storage/index.ts
Normal file
1141
frontend-react/src/storage/index.ts
Normal file
File diff suppressed because it is too large
Load Diff
114
frontend-react/src/storage/plan/action.ts
Normal file
114
frontend-react/src/storage/plan/action.ts
Normal file
@@ -0,0 +1,114 @@
|
||||
import { makeAutoObservable } from 'mobx';
|
||||
import { SxProps } from '@mui/material';
|
||||
import { INodeBase } from './base';
|
||||
import { PlanManager } from './manager';
|
||||
import { IApiAgentAction } from '@/apis/generate-base-plan';
|
||||
|
||||
export enum ActionType {
|
||||
Propose = 'Propose',
|
||||
Critique = 'Critique',
|
||||
Improve = 'Improve',
|
||||
Finalize = 'Finalize',
|
||||
}
|
||||
|
||||
const AgentActionStyles = new Map<ActionType | '', SxProps>([
|
||||
[ActionType.Propose, { backgroundColor: '#B9EBF9', borderColor: '#94c2dc' }],
|
||||
[ActionType.Critique, { backgroundColor: '#EFF9B9', borderColor: '#c0dc94' }],
|
||||
[ActionType.Improve, { backgroundColor: '#E0DEFC', borderColor: '#bbb8e5' }],
|
||||
[ActionType.Finalize, { backgroundColor: '#F9C7B9', borderColor: '#dc9e94' }],
|
||||
['', { backgroundColor: '#000000', borderColor: '#000000' }],
|
||||
]);
|
||||
|
||||
export const getAgentActionStyle = (action: ActionType): SxProps => {
|
||||
return AgentActionStyles.get(action) ?? AgentActionStyles.get('')!;
|
||||
};
|
||||
|
||||
export interface IRichSentence {
|
||||
who: string;
|
||||
whoStyle: SxProps;
|
||||
content: string;
|
||||
style: SxProps;
|
||||
}
|
||||
|
||||
export class AgentActionNode implements INodeBase {
|
||||
public name: string = '';
|
||||
|
||||
public plan: PlanManager;
|
||||
|
||||
public type: ActionType = ActionType.Propose;
|
||||
|
||||
public agent: string = '';
|
||||
|
||||
public description: string = '';
|
||||
|
||||
public inputs: string[] = [];
|
||||
|
||||
public path: string[] = []; // ['A', 'B']
|
||||
|
||||
public children: string[] = []; // ['D', 'E']
|
||||
|
||||
public get id() {
|
||||
return this.path[this.path.length - 1];
|
||||
}
|
||||
|
||||
public get parent() {
|
||||
return this.path[this.path.length - 2];
|
||||
}
|
||||
|
||||
public get last() {
|
||||
return this.plan.agentActionMap.get(this.parent);
|
||||
}
|
||||
|
||||
public get renderCard(): IRichSentence {
|
||||
const style = getAgentActionStyle(this.type);
|
||||
return {
|
||||
who: this.agent,
|
||||
whoStyle: style,
|
||||
// this.description 首字母小写
|
||||
content: this.description[0].toLowerCase() + this.description.slice(1),
|
||||
style: { ...style, backgroundColor: 'transparent' },
|
||||
};
|
||||
}
|
||||
|
||||
public get apiAgentAction(): IApiAgentAction {
|
||||
return {
|
||||
id: this.name,
|
||||
type: this.type,
|
||||
agent: this.agent,
|
||||
description: this.description,
|
||||
inputs: this.inputs,
|
||||
};
|
||||
}
|
||||
|
||||
public get belongingSelection() {
|
||||
return this.plan.agentSelectionMap.get(
|
||||
this.plan.actionSelectionMap.get(this.id) ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
constructor(plan: PlanManager, json?: any) {
|
||||
this.plan = plan;
|
||||
if (json) {
|
||||
this.name = json.name ?? '';
|
||||
this.agent = json.agent ?? '';
|
||||
this.description = json.description ?? '';
|
||||
this.inputs = [...(json.inputs ?? [])];
|
||||
this.type = json.type ?? ActionType.Propose;
|
||||
this.path = [...(json.path ?? [])];
|
||||
this.children = [...(json.children ?? [])];
|
||||
}
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
public dump() {
|
||||
return {
|
||||
name: this.name,
|
||||
agent: this.agent,
|
||||
description: this.description,
|
||||
inputs: [...this.inputs],
|
||||
type: this.type,
|
||||
path: [...this.path],
|
||||
children: [...this.children],
|
||||
};
|
||||
}
|
||||
}
|
||||
13
frontend-react/src/storage/plan/base.ts
Normal file
13
frontend-react/src/storage/plan/base.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
/* A
|
||||
/ \
|
||||
B C
|
||||
/ \
|
||||
D E */
|
||||
export interface INodeBase {
|
||||
id: string; // B
|
||||
parent?: string; // A
|
||||
path: string[]; // ['A', 'B']
|
||||
children: string[]; // ['D', 'E']
|
||||
}
|
||||
|
||||
export type NodeMap<T extends INodeBase> = Map<string, T>;
|
||||
5
frontend-react/src/storage/plan/index.ts
Normal file
5
frontend-react/src/storage/plan/index.ts
Normal file
@@ -0,0 +1,5 @@
|
||||
export * from './action';
|
||||
export * from './manager';
|
||||
export * from './selection';
|
||||
export * from './stepTask';
|
||||
export * from './log';
|
||||
115
frontend-react/src/storage/plan/log.ts
Normal file
115
frontend-react/src/storage/plan/log.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import React from 'react';
|
||||
import { makeAutoObservable } from 'mobx';
|
||||
import { PlanManager } from './manager';
|
||||
import {
|
||||
IExecuteNode,
|
||||
ExecuteNodeType,
|
||||
IExecuteObject,
|
||||
} from '@/apis/execute-plan';
|
||||
|
||||
export class RehearsalLog {
|
||||
public planManager: PlanManager;
|
||||
|
||||
public outdate: boolean = false;
|
||||
|
||||
oldLog: IExecuteNode[] = [];
|
||||
|
||||
userInputs: Record<string, string> = {};
|
||||
|
||||
public get logWithoutUserInput(): IExecuteNode[] {
|
||||
if (this.oldLog.length > 0) {
|
||||
return this.oldLog;
|
||||
} else {
|
||||
const log: IExecuteNode[] = [];
|
||||
// build skeleton logs
|
||||
for (const step of this.planManager.currentPlan) {
|
||||
log.push({
|
||||
type: ExecuteNodeType.Step,
|
||||
id: step.name,
|
||||
inputs: Array.from(step.inputs),
|
||||
output: step.output,
|
||||
history: (step.agentSelection?.currentTaskProcess ?? []).map(
|
||||
action => ({
|
||||
id: action.name,
|
||||
type: action.type,
|
||||
agent: action.agent,
|
||||
description: action.description,
|
||||
inputs: action.inputs,
|
||||
result: '',
|
||||
}),
|
||||
),
|
||||
});
|
||||
// push output of the step
|
||||
log.push({
|
||||
type: ExecuteNodeType.Object,
|
||||
id: step.output,
|
||||
content: '',
|
||||
});
|
||||
}
|
||||
return log;
|
||||
}
|
||||
}
|
||||
|
||||
public get renderingLog(): (IExecuteNode & {
|
||||
ref: React.RefObject<HTMLDivElement>;
|
||||
stepId: string;
|
||||
})[] {
|
||||
const outputTaskIdMap = new Map<string, string>();
|
||||
const taskNameTaskIdMap = new Map<string, string>();
|
||||
this.planManager.currentPlan.forEach(step => {
|
||||
taskNameTaskIdMap.set(step.name, step.id);
|
||||
outputTaskIdMap.set(step.output, step.id);
|
||||
});
|
||||
return this.logWithoutUserInput.map(node => {
|
||||
let stepId = '';
|
||||
if (node.type === ExecuteNodeType.Step) {
|
||||
stepId = taskNameTaskIdMap.get(node.id) ?? '';
|
||||
} else {
|
||||
stepId = outputTaskIdMap.get(node.id) ?? '';
|
||||
}
|
||||
return {
|
||||
...node,
|
||||
ref: React.createRef(),
|
||||
stepId,
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
constructor(plan: PlanManager, json?: any) {
|
||||
this.planManager = plan;
|
||||
if (json) {
|
||||
this.oldLog = JSON.parse(JSON.stringify(json.oldLog));
|
||||
this.userInputs = JSON.parse(JSON.stringify(json.userInputs));
|
||||
}
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
public dump() {
|
||||
return {
|
||||
oldLog: JSON.parse(JSON.stringify(this.oldLog)),
|
||||
userInputs: JSON.parse(JSON.stringify(this.userInputs)),
|
||||
};
|
||||
}
|
||||
|
||||
public updateLog(newLog: IExecuteNode[]) {
|
||||
const log = [...newLog];
|
||||
const userInputs: Record<string, string> = {};
|
||||
while (log.length > 0 && log[0].type === ExecuteNodeType.Object) {
|
||||
const userInputObject = log.shift()! as IExecuteObject;
|
||||
userInputs[userInputObject.id] = userInputObject.content;
|
||||
}
|
||||
this.oldLog = log;
|
||||
this.userInputs = userInputs;
|
||||
}
|
||||
|
||||
public clearLog() {
|
||||
this.oldLog.length = 0;
|
||||
this.outdate = false;
|
||||
}
|
||||
|
||||
public setOutdate() {
|
||||
if (this.oldLog.length > 0) {
|
||||
this.outdate = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
196
frontend-react/src/storage/plan/manager.ts
Normal file
196
frontend-react/src/storage/plan/manager.ts
Normal file
@@ -0,0 +1,196 @@
|
||||
import { makeAutoObservable } from 'mobx';
|
||||
import { NodeMap } from './base';
|
||||
import { StepTaskNode } from './stepTask';
|
||||
import { AgentActionNode } from './action';
|
||||
import { AgentSelection } from './selection';
|
||||
import { IApiStepTask, IGeneratedPlan } from '@/apis/generate-base-plan';
|
||||
|
||||
export class PlanManager {
|
||||
public goal: string = '';
|
||||
|
||||
public nextStepTaskId: number = 0;
|
||||
|
||||
public nextAgentSelectionId: number = 0;
|
||||
|
||||
public nextAgentActionId: number = 0;
|
||||
|
||||
public stepTaskMap: NodeMap<StepTaskNode> = new Map();
|
||||
|
||||
public agentActionMap: NodeMap<AgentActionNode> = new Map();
|
||||
|
||||
public agentSelectionMap: Map<string, AgentSelection> = new Map();
|
||||
|
||||
public actionSelectionMap: Map<string, string> = new Map();
|
||||
|
||||
public selectionStepMap: Map<string, string> = new Map();
|
||||
|
||||
public stepTaskRoots: string[] = [];
|
||||
|
||||
public currentStepTaskLeaf?: string;
|
||||
|
||||
public previewStepTaskLeaf?: string;
|
||||
|
||||
public inputs: string[] = [];
|
||||
|
||||
public branches: Record<
|
||||
string,
|
||||
{ start?: string; requirement?: string; base?: string }
|
||||
> = {};
|
||||
|
||||
public get leaves() {
|
||||
return Object.keys(this.branches);
|
||||
}
|
||||
|
||||
public get currentPlan() {
|
||||
const path: StepTaskNode[] = [];
|
||||
let node = this.stepTaskMap.get(
|
||||
this.previewStepTaskLeaf ?? this.currentStepTaskLeaf ?? '',
|
||||
);
|
||||
while (node) {
|
||||
path.push(node);
|
||||
node = node.last;
|
||||
}
|
||||
return path.reverse();
|
||||
}
|
||||
|
||||
public get currentPath() {
|
||||
return this.currentPlan.map(node => node.id);
|
||||
}
|
||||
|
||||
public get activeStepNodeIds() {
|
||||
return new Set<string>(this.currentPath);
|
||||
}
|
||||
|
||||
public get apiPlan() {
|
||||
return {
|
||||
goal: this.goal,
|
||||
inputs: this.inputs,
|
||||
process: this.currentPlan.map(node => node.apiStepTask),
|
||||
};
|
||||
}
|
||||
|
||||
constructor() {
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
public parseApiPlan(plan: IGeneratedPlan) {
|
||||
this.goal = plan.goal;
|
||||
this.inputs = [...plan.inputs];
|
||||
const leaf = this.insertProcess(plan.process);
|
||||
this.currentStepTaskLeaf = leaf;
|
||||
}
|
||||
|
||||
public insertProcess(
|
||||
process: IApiStepTask[],
|
||||
start?: string,
|
||||
requirement?: string,
|
||||
base?: string,
|
||||
): string {
|
||||
if (start && !this.stepTaskMap.has(start)) {
|
||||
throw new Error(`StekTask node ${start} does not exist!`);
|
||||
}
|
||||
let lastChidrenList =
|
||||
this.stepTaskMap.get(start ?? '')?.children ?? this.stepTaskRoots;
|
||||
const path = [...(this.stepTaskMap.get(start ?? '')?.path ?? [])];
|
||||
for (const task of process) {
|
||||
// create agentSelection
|
||||
const agentSelection = new AgentSelection(this, {
|
||||
id: (this.nextAgentSelectionId++).toString(),
|
||||
agents: task.agents,
|
||||
});
|
||||
const leaf = agentSelection.insertActions(task.process);
|
||||
this.agentSelectionMap.set(agentSelection.id, agentSelection);
|
||||
agentSelection.currentActionLeaf = leaf;
|
||||
// create stepTask
|
||||
path.push((this.nextStepTaskId++).toString());
|
||||
const node = new StepTaskNode(this, {
|
||||
name: task.name,
|
||||
content: task.content,
|
||||
inputs: task.inputs,
|
||||
output: task.output,
|
||||
brief: task.brief,
|
||||
path,
|
||||
agentSelectionIds: [agentSelection.id],
|
||||
currentAgentSelection: agentSelection.id,
|
||||
});
|
||||
lastChidrenList.push(node.id);
|
||||
lastChidrenList = node.children;
|
||||
this.selectionStepMap.set(agentSelection.id, node.id);
|
||||
this.stepTaskMap.set(node.id, node);
|
||||
}
|
||||
const leaf = path[path.length - 1];
|
||||
this.branches[leaf] = { start, requirement, base };
|
||||
return leaf;
|
||||
}
|
||||
|
||||
public reset() {
|
||||
this.goal = '';
|
||||
this.stepTaskMap.clear();
|
||||
this.agentActionMap.clear();
|
||||
this.agentSelectionMap.clear();
|
||||
this.stepTaskRoots = [];
|
||||
this.inputs = [];
|
||||
this.currentStepTaskLeaf = undefined;
|
||||
this.previewStepTaskLeaf = undefined;
|
||||
this.nextAgentActionId = 0;
|
||||
this.nextAgentSelectionId = 0;
|
||||
this.nextStepTaskId = 0;
|
||||
}
|
||||
|
||||
public dump() {
|
||||
return {
|
||||
goal: this.goal,
|
||||
nextStepTaskId: this.nextStepTaskId,
|
||||
nextAgentSelectionId: this.nextAgentSelectionId,
|
||||
nextAgentActionId: this.nextAgentActionId,
|
||||
stepTaskMap: Array.from(this.stepTaskMap).map(([k, v]) => [k, v.dump()]),
|
||||
agentActionMap: Array.from(this.agentActionMap).map(([k, v]) => [
|
||||
k,
|
||||
v.dump(),
|
||||
]),
|
||||
agentSelectionMap: Array.from(this.agentSelectionMap).map(([k, v]) => [
|
||||
k,
|
||||
v.dump(),
|
||||
]),
|
||||
stepTaskRoots: [...this.stepTaskRoots],
|
||||
inputs: [...this.inputs],
|
||||
currentStepTaskLeaf: this.currentStepTaskLeaf,
|
||||
previewStepTaskLeaf: this.previewStepTaskLeaf,
|
||||
branch: JSON.parse(JSON.stringify(this.branches)),
|
||||
};
|
||||
}
|
||||
|
||||
public load(json: any) {
|
||||
this.reset();
|
||||
this.goal = json.goal;
|
||||
this.nextStepTaskId = json.nextStepTaskId;
|
||||
this.nextAgentSelectionId = json.nextAgentSelectionId;
|
||||
this.nextAgentActionId = json.nextAgentActionId;
|
||||
for (const [k, v] of json.agentActionMap) {
|
||||
this.agentActionMap.set(k, new AgentActionNode(this, v));
|
||||
}
|
||||
for (const [k, v] of json.agentSelectionMap) {
|
||||
const selection = new AgentSelection(this, v);
|
||||
for (const leaf of selection.leaves) {
|
||||
let node = this.agentActionMap.get(leaf);
|
||||
while (node) {
|
||||
this.actionSelectionMap.set(node.id, selection.id);
|
||||
node = node.last;
|
||||
}
|
||||
}
|
||||
this.agentSelectionMap.set(k, selection);
|
||||
}
|
||||
for (const [k, v] of json.stepTaskMap) {
|
||||
const stepTask = new StepTaskNode(this, v);
|
||||
for (const id of stepTask.agentSelectionIds) {
|
||||
this.selectionStepMap.set(id, stepTask.id);
|
||||
}
|
||||
this.stepTaskMap.set(k, stepTask);
|
||||
}
|
||||
this.stepTaskRoots = [...json.stepTaskRoots];
|
||||
this.inputs = [...json.inputs];
|
||||
this.currentStepTaskLeaf = json.currentStepTaskLeaf;
|
||||
this.previewStepTaskLeaf = json.previewStepTaskLeaf;
|
||||
this.branches = JSON.parse(JSON.stringify(json.branch));
|
||||
}
|
||||
}
|
||||
112
frontend-react/src/storage/plan/selection.ts
Normal file
112
frontend-react/src/storage/plan/selection.ts
Normal file
@@ -0,0 +1,112 @@
|
||||
import { makeAutoObservable } from 'mobx';
|
||||
import { PlanManager } from './manager';
|
||||
import { AgentActionNode } from './action';
|
||||
import { IApiAgentAction } from '@/apis/generate-base-plan';
|
||||
|
||||
export class AgentSelection {
|
||||
public id: string = '';
|
||||
|
||||
public plan: PlanManager;
|
||||
|
||||
public agents: string[] = [];
|
||||
|
||||
public actionRoot: string[] = [];
|
||||
|
||||
public currentActionLeaf?: string;
|
||||
|
||||
public previewActionLeaf?: string;
|
||||
|
||||
public branches: Record<
|
||||
string,
|
||||
{ start?: string; requirement?: string; base?: string }
|
||||
> = {};
|
||||
|
||||
public get leaves() {
|
||||
return Object.keys(this.branches);
|
||||
}
|
||||
|
||||
public get currentTaskProcess() {
|
||||
const path: AgentActionNode[] = [];
|
||||
let node = this.plan.agentActionMap.get(
|
||||
this.previewActionLeaf ?? this.currentActionLeaf ?? '',
|
||||
);
|
||||
while (node) {
|
||||
path.push(node);
|
||||
node = node.last;
|
||||
}
|
||||
return path.reverse();
|
||||
}
|
||||
|
||||
public get currentTaskProcessIds() {
|
||||
return this.currentTaskProcess.map(node => node.id);
|
||||
}
|
||||
|
||||
public get activeTaskIds() {
|
||||
return new Set<string>(this.currentTaskProcessIds);
|
||||
}
|
||||
|
||||
public get belongingStepTask() {
|
||||
return this.plan.stepTaskMap.get(
|
||||
this.plan.selectionStepMap.get(this.id) ?? '',
|
||||
);
|
||||
}
|
||||
|
||||
constructor(plan: PlanManager, json?: any) {
|
||||
this.plan = plan;
|
||||
if (json) {
|
||||
this.id = json.id ?? '';
|
||||
this.agents = [...(json.agents ?? [])];
|
||||
this.branches = JSON.parse(JSON.stringify(json.branches ?? {}));
|
||||
this.actionRoot = [...(json.actionRoot ?? [])];
|
||||
this.currentActionLeaf = json.currentActionLeaf;
|
||||
this.previewActionLeaf = json.previewActionLeaf;
|
||||
}
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
public dump() {
|
||||
return {
|
||||
id: this.id,
|
||||
agents: [...this.agents],
|
||||
branches: JSON.parse(JSON.stringify(this.branches)),
|
||||
actionRoot: [...this.actionRoot],
|
||||
currentActionLeaf: this.currentActionLeaf,
|
||||
previewActionLeaf: this.previewActionLeaf,
|
||||
};
|
||||
}
|
||||
|
||||
public insertActions(
|
||||
actions: IApiAgentAction[],
|
||||
start?: string,
|
||||
requirement?: string,
|
||||
base?: string,
|
||||
) {
|
||||
if (actions.length === 0) {
|
||||
return undefined;
|
||||
}
|
||||
if (start && !this.plan.agentActionMap.has(start)) {
|
||||
throw new Error(`AgentAction node ${start} does not exist!`);
|
||||
}
|
||||
let lastChidrenList =
|
||||
this.plan.agentActionMap.get(start ?? '')?.children ?? this.actionRoot;
|
||||
const path = [...(this.plan.agentActionMap.get(start ?? '')?.path ?? [])];
|
||||
for (const action of actions) {
|
||||
path.push((this.plan.nextAgentActionId++).toString());
|
||||
const node = new AgentActionNode(this.plan, {
|
||||
name: action.id,
|
||||
path,
|
||||
type: action.type,
|
||||
agent: action.agent,
|
||||
description: action.description,
|
||||
inputs: action.inputs,
|
||||
});
|
||||
this.plan.agentActionMap.set(node.id, node);
|
||||
this.plan.actionSelectionMap.set(node.id, this.id);
|
||||
lastChidrenList.push(node.id);
|
||||
lastChidrenList = node.children;
|
||||
}
|
||||
const leaf = path[path.length - 1];
|
||||
this.branches[leaf] = { start, requirement, base };
|
||||
return leaf;
|
||||
}
|
||||
}
|
||||
280
frontend-react/src/storage/plan/stepTask.ts
Normal file
280
frontend-react/src/storage/plan/stepTask.ts
Normal file
@@ -0,0 +1,280 @@
|
||||
import React from 'react';
|
||||
import { SxProps } from '@mui/material';
|
||||
import { makeAutoObservable } from 'mobx';
|
||||
import { INodeBase } from './base';
|
||||
import { PlanManager } from './manager';
|
||||
import {
|
||||
IRichText,
|
||||
IApiStepTask,
|
||||
IApiAgentAction,
|
||||
} from '@/apis/generate-base-plan';
|
||||
|
||||
export interface IRichSpan {
|
||||
text: string;
|
||||
style?: SxProps;
|
||||
}
|
||||
|
||||
const nameJoin = (names: string[]) => {
|
||||
// join names with comma, and 'and' for the last one
|
||||
const tmp = [...names];
|
||||
const last = tmp.pop()!;
|
||||
let t = tmp.join(', ');
|
||||
if (t.length > 0) {
|
||||
t = `${t} and ${last}`;
|
||||
} else {
|
||||
t = last;
|
||||
}
|
||||
return t;
|
||||
};
|
||||
|
||||
export class StepTaskNode implements INodeBase {
|
||||
public name: string = '';
|
||||
|
||||
public content: string = '';
|
||||
|
||||
public inputs: string[] = [];
|
||||
|
||||
public output: string = '';
|
||||
|
||||
public _brief: IRichText = {
|
||||
template: '',
|
||||
data: {},
|
||||
};
|
||||
|
||||
public path: string[] = [];
|
||||
|
||||
public children: string[] = [];
|
||||
|
||||
public plan: PlanManager;
|
||||
|
||||
public agentSelectionIds: string[] = [];
|
||||
|
||||
public currentAgentSelection?: string;
|
||||
|
||||
public previewAgentSelection?: string;
|
||||
|
||||
public agentAspectScores: Record<
|
||||
string,
|
||||
Record<string, { score: number; reason: string }>
|
||||
> = {};
|
||||
|
||||
public get brief(): IRichText {
|
||||
if (!this.agentSelection) {
|
||||
return this._brief;
|
||||
}
|
||||
const agents = [...this.agentSelection.agents];
|
||||
if (agents.length === 0) {
|
||||
return this._brief;
|
||||
}
|
||||
const data: IRichText['data'] = {};
|
||||
let indexOffset = 0;
|
||||
const inputPlaceHolders = this.inputs.map((text, index) => {
|
||||
data[(index + indexOffset).toString()] = {
|
||||
text,
|
||||
style: { background: '#ACDBA0' },
|
||||
};
|
||||
return `!<${index + indexOffset}>!`;
|
||||
});
|
||||
const inputSentence = nameJoin(inputPlaceHolders);
|
||||
indexOffset += this.inputs.length;
|
||||
const namePlaceholders = agents.map((text, index) => {
|
||||
data[(index + indexOffset).toString()] = {
|
||||
text,
|
||||
style: { background: '#E5E5E5', boxShadow: '1px 1px 4px 1px #0003' },
|
||||
};
|
||||
return `!<${index + indexOffset}>!`;
|
||||
});
|
||||
const nameSentence = nameJoin(namePlaceholders);
|
||||
indexOffset += agents.length;
|
||||
let actionSentence = this.content;
|
||||
// delete the last '.' of actionSentence
|
||||
if (actionSentence[actionSentence.length - 1] === '.') {
|
||||
actionSentence = actionSentence.slice(0, -1);
|
||||
}
|
||||
const actionIndex = indexOffset++;
|
||||
data[actionIndex.toString()] = {
|
||||
text: actionSentence,
|
||||
style: { background: '#DDD', border: '1.5px solid #ddd' },
|
||||
};
|
||||
let outputSentence = '';
|
||||
if (this.output) {
|
||||
data[indexOffset.toString()] = {
|
||||
text: this.output,
|
||||
style: { background: '#FFCA8C' },
|
||||
};
|
||||
outputSentence = `to obtain !<${indexOffset}>!`;
|
||||
}
|
||||
// Join them togeter
|
||||
let content = inputSentence;
|
||||
if (content) {
|
||||
content = `Based on ${content}, ${nameSentence} perform the task of !<${actionIndex}>!`;
|
||||
} else {
|
||||
content = `${nameSentence} perform the task of !<${actionIndex}>!`;
|
||||
}
|
||||
if (outputSentence) {
|
||||
content = `${content}, ${outputSentence}.`;
|
||||
} else {
|
||||
content = `${content}.`;
|
||||
}
|
||||
content = content.trim();
|
||||
return {
|
||||
template: content,
|
||||
data,
|
||||
};
|
||||
}
|
||||
|
||||
public get id() {
|
||||
return this.path[this.path.length - 1];
|
||||
}
|
||||
|
||||
public get last() {
|
||||
return this.plan.stepTaskMap.get(this.path[this.path.length - 2]);
|
||||
}
|
||||
|
||||
public get next() {
|
||||
return this.children
|
||||
.map(id => this.plan.stepTaskMap.get(id)!)
|
||||
.filter(node => node);
|
||||
}
|
||||
|
||||
public get agentSelection() {
|
||||
const id = this.previewAgentSelection ?? this.currentAgentSelection ?? '';
|
||||
return this.plan.agentSelectionMap.get(id);
|
||||
}
|
||||
|
||||
public get allSelections() {
|
||||
return this.agentSelectionIds
|
||||
.map(id => this.plan.agentSelectionMap.get(id)!)
|
||||
.filter(node => node);
|
||||
}
|
||||
|
||||
public get apiStepTask(): IApiStepTask {
|
||||
const actionsProcess: IApiAgentAction[] = [];
|
||||
const actions = this.agentSelection?.currentTaskProcess ?? [];
|
||||
for (const action of actions) {
|
||||
actionsProcess.push({
|
||||
id: action.name,
|
||||
type: action.type,
|
||||
agent: action.agent,
|
||||
description: action.description,
|
||||
inputs: [...action.inputs],
|
||||
});
|
||||
}
|
||||
return {
|
||||
name: this.name,
|
||||
content: this.content,
|
||||
inputs: [...this.inputs],
|
||||
output: this.output,
|
||||
agents: this.agentSelection?.agents ?? [],
|
||||
brief: JSON.parse(JSON.stringify(this.brief)) as IRichText,
|
||||
process: actionsProcess,
|
||||
};
|
||||
}
|
||||
|
||||
public get descriptionCard() {
|
||||
const briefSpan: IRichSpan[] = [];
|
||||
for (const substring of this.brief.template.split(/(!<[^>]+>!)/)) {
|
||||
if (substring[0] === '!') {
|
||||
const key = substring.slice(2, -2);
|
||||
const { text, style } = this.brief.data[key];
|
||||
briefSpan.push({ text, style });
|
||||
} else {
|
||||
briefSpan.push({ text: substring });
|
||||
}
|
||||
}
|
||||
|
||||
const actions = this.agentSelection?.currentTaskProcess ?? [];
|
||||
const detailParagraph = actions.map(action => [
|
||||
action.renderCard,
|
||||
action.id,
|
||||
]);
|
||||
|
||||
return {
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
content: this.content,
|
||||
ref: React.createRef<HTMLElement>(),
|
||||
brief: briefSpan,
|
||||
detail: detailParagraph,
|
||||
};
|
||||
}
|
||||
|
||||
public get outlineCard() {
|
||||
return {
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
inputs: this.inputs,
|
||||
output: this.output,
|
||||
agents: this.agentSelection?.agents ?? [],
|
||||
content: this.content,
|
||||
ref: React.createRef<HTMLElement>(),
|
||||
};
|
||||
}
|
||||
|
||||
public get heatmap() {
|
||||
return Object.fromEntries(
|
||||
Object.entries(this.agentAspectScores).map(([aspect, scores]) => [
|
||||
aspect,
|
||||
Object.fromEntries(
|
||||
Object.entries(scores).map(([agent, score]) => [agent, score]),
|
||||
),
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
constructor(plan: PlanManager, json?: any) {
|
||||
this.plan = plan;
|
||||
if (json) {
|
||||
this.name = json.name ?? '';
|
||||
this.content = json.content ?? '';
|
||||
this.inputs = [...(json.inputs ?? [])];
|
||||
this.output = json.output;
|
||||
this._brief = JSON.parse(
|
||||
JSON.stringify(json.brief ?? '{ template: "", data: {} }'),
|
||||
) as IRichText;
|
||||
this.path = [...(json.path ?? [])];
|
||||
this.children = [...(json.children ?? [])];
|
||||
this.agentAspectScores = JSON.parse(
|
||||
JSON.stringify(json.agentAspectScores ?? {}),
|
||||
);
|
||||
this.agentSelectionIds = [...(json.agentSelectionIds ?? [])];
|
||||
this.currentAgentSelection = json.currentAgentSelection;
|
||||
this.previewAgentSelection = json.previewAgentSelection;
|
||||
}
|
||||
makeAutoObservable(this);
|
||||
}
|
||||
|
||||
public dump() {
|
||||
return {
|
||||
name: this.name,
|
||||
content: this.content,
|
||||
inputs: [...this.inputs],
|
||||
output: this.output,
|
||||
brief: JSON.parse(JSON.stringify(this.brief)),
|
||||
path: [...this.path],
|
||||
children: [...this.children],
|
||||
agentSelectionIds: [...this.agentSelectionIds],
|
||||
agentAspectScores: JSON.parse(JSON.stringify(this.agentAspectScores)),
|
||||
currentAgentSelection: this.currentAgentSelection,
|
||||
previewAgentSelection: this.previewAgentSelection,
|
||||
};
|
||||
}
|
||||
|
||||
public appendAspectScore(
|
||||
aspect: string,
|
||||
agentScores: Record<string, { score: number; reason: string }>,
|
||||
) {
|
||||
if (this.agentAspectScores[aspect]) {
|
||||
for (const [agent, score] of Object.entries(agentScores)) {
|
||||
if (this.agentAspectScores[aspect][agent]) {
|
||||
this.agentAspectScores[aspect][agent].score = score.score;
|
||||
this.agentAspectScores[aspect][agent].reason = score.reason;
|
||||
} else {
|
||||
this.agentAspectScores[aspect][agent] = score;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.agentAspectScores[aspect] = agentScores;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user