mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-13 19:20:04 +00:00
✨ feat: align self-iteration builtin tool with shared runtime and inspector patterns (#14827)
This commit is contained in:
@@ -237,6 +237,14 @@
|
||||
"builtins.lobe-page-agent.apiName.updateNode": "Update node",
|
||||
"builtins.lobe-page-agent.apiName.wrapNodes": "Wrap nodes",
|
||||
"builtins.lobe-page-agent.title": "Page",
|
||||
"builtins.lobe-self-feedback-intent.apiName.declareSelfFeedbackIntent": "Record improvement idea",
|
||||
"builtins.lobe-self-feedback-intent.inspector.gap.proposal": "Suggest improvement",
|
||||
"builtins.lobe-self-feedback-intent.inspector.memory.write": "Record preference",
|
||||
"builtins.lobe-self-feedback-intent.inspector.rejected": "Not recorded",
|
||||
"builtins.lobe-self-feedback-intent.inspector.skill.consolidate": "Organize methods",
|
||||
"builtins.lobe-self-feedback-intent.inspector.skill.create": "New method found",
|
||||
"builtins.lobe-self-feedback-intent.inspector.skill.refine": "Improve method",
|
||||
"builtins.lobe-self-feedback-intent.title": "Improvement Ideas",
|
||||
"builtins.lobe-skill-store.apiName.importFromMarket": "Import from Market",
|
||||
"builtins.lobe-skill-store.apiName.importSkill": "Import Skill",
|
||||
"builtins.lobe-skill-store.apiName.searchSkill": "Search Skills",
|
||||
|
||||
@@ -237,6 +237,14 @@
|
||||
"builtins.lobe-page-agent.apiName.updateNode": "更新节点",
|
||||
"builtins.lobe-page-agent.apiName.wrapNodes": "包装节点",
|
||||
"builtins.lobe-page-agent.title": "文档",
|
||||
"builtins.lobe-self-feedback-intent.apiName.declareSelfFeedbackIntent": "记录改进想法",
|
||||
"builtins.lobe-self-feedback-intent.inspector.gap.proposal": "提出改进建议",
|
||||
"builtins.lobe-self-feedback-intent.inspector.memory.write": "记下偏好",
|
||||
"builtins.lobe-self-feedback-intent.inspector.rejected": "未记录",
|
||||
"builtins.lobe-self-feedback-intent.inspector.skill.consolidate": "整理方法",
|
||||
"builtins.lobe-self-feedback-intent.inspector.skill.create": "发现新方法",
|
||||
"builtins.lobe-self-feedback-intent.inspector.skill.refine": "改进方法",
|
||||
"builtins.lobe-self-feedback-intent.title": "改进想法",
|
||||
"builtins.lobe-skill-store.apiName.importFromMarket": "从市场导入",
|
||||
"builtins.lobe-skill-store.apiName.importSkill": "导入技能",
|
||||
"builtins.lobe-skill-store.apiName.searchSkill": "搜索技能",
|
||||
|
||||
@@ -4,11 +4,20 @@
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"exports": {
|
||||
".": "./src/index.ts"
|
||||
".": "./src/index.ts",
|
||||
"./client": "./src/client/index.ts",
|
||||
"./executionRuntime": "./src/ExecutionRuntime/index.ts"
|
||||
},
|
||||
"main": "./src/index.ts",
|
||||
"devDependencies": {
|
||||
"@lobechat/context-engine": "workspace:*",
|
||||
"@lobechat/types": "workspace:*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@lobehub/ui": "^5",
|
||||
"antd-style": "*",
|
||||
"lucide-react": "*",
|
||||
"react": "*",
|
||||
"react-i18next": "*"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
import type { BuiltinServerRuntimeOutput } from '@lobechat/types';
|
||||
|
||||
import type {
|
||||
DeclareSelfFeedbackIntentContext,
|
||||
DeclareSelfFeedbackIntentInput,
|
||||
DeclareSelfFeedbackIntentPayload,
|
||||
DeclareSelfFeedbackIntentResult,
|
||||
DeclareSelfFeedbackIntentState,
|
||||
} from '../types';
|
||||
|
||||
export interface SelfFeedbackIntentRuntimeService {
|
||||
declareIntent: (
|
||||
input: DeclareSelfFeedbackIntentInput,
|
||||
) => Promise<DeclareSelfFeedbackIntentResult>;
|
||||
}
|
||||
|
||||
export interface SelfFeedbackIntentExecutionRuntimeOptions {
|
||||
service: SelfFeedbackIntentRuntimeService;
|
||||
}
|
||||
|
||||
const REQUIRED_CONTEXT_KEYS = ['agentId', 'userId', 'topicId'];
|
||||
|
||||
const createJsonOutput = (
|
||||
state: DeclareSelfFeedbackIntentState,
|
||||
success: boolean,
|
||||
): BuiltinServerRuntimeOutput => ({
|
||||
content: JSON.stringify(state),
|
||||
state,
|
||||
success,
|
||||
});
|
||||
|
||||
export class SelfFeedbackIntentExecutionRuntime {
|
||||
private service: SelfFeedbackIntentRuntimeService;
|
||||
|
||||
constructor(options: SelfFeedbackIntentExecutionRuntimeOptions) {
|
||||
this.service = options.service;
|
||||
}
|
||||
|
||||
declareSelfFeedbackIntent = async (
|
||||
input: DeclareSelfFeedbackIntentPayload,
|
||||
context: DeclareSelfFeedbackIntentContext = {},
|
||||
): Promise<BuiltinServerRuntimeOutput> => {
|
||||
const { agentId, operationId, toolCallId, topicId, userId } = context;
|
||||
|
||||
if (!agentId || !userId || !topicId) {
|
||||
return createJsonOutput(
|
||||
{
|
||||
accepted: false,
|
||||
reason: 'missing_context',
|
||||
required: REQUIRED_CONTEXT_KEYS,
|
||||
},
|
||||
false,
|
||||
);
|
||||
}
|
||||
|
||||
try {
|
||||
const result = await this.service.declareIntent({
|
||||
agentId,
|
||||
input,
|
||||
topicId,
|
||||
userId,
|
||||
...(operationId ? { operationId } : {}),
|
||||
...(toolCallId ? { toolCallId } : {}),
|
||||
});
|
||||
|
||||
return createJsonOutput(
|
||||
{
|
||||
accepted: result.accepted,
|
||||
reason: result.reason ?? null,
|
||||
sourceId: result.sourceId ?? null,
|
||||
strength: result.strength,
|
||||
},
|
||||
true,
|
||||
);
|
||||
} catch (e) {
|
||||
const message = e instanceof Error ? e.message : 'Unknown self-feedback intent error';
|
||||
|
||||
return {
|
||||
content: `declareSelfFeedbackIntent with error detail: ${message}`,
|
||||
error: { message },
|
||||
state: {
|
||||
accepted: false,
|
||||
reason: 'runtime_error',
|
||||
} satisfies DeclareSelfFeedbackIntentState,
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
+116
@@ -0,0 +1,116 @@
|
||||
'use client';
|
||||
|
||||
import type { BuiltinInspectorProps } from '@lobechat/types';
|
||||
import { Icon } from '@lobehub/ui';
|
||||
import { createStaticStyles, cx } from 'antd-style';
|
||||
import { CheckCircle2, CircleAlert } from 'lucide-react';
|
||||
import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
|
||||
import { highlightTextStyles, inspectorTextStyles, shinyTextStyles } from '@/styles';
|
||||
|
||||
import type {
|
||||
DeclareSelfFeedbackIntentParams,
|
||||
DeclareSelfFeedbackIntentState,
|
||||
} from '../../../types';
|
||||
|
||||
const getIntentLabelKey = (data?: Partial<DeclareSelfFeedbackIntentParams>) => {
|
||||
if (data?.kind === 'memory' && data.action === 'write') {
|
||||
return 'builtins.lobe-self-feedback-intent.inspector.memory.write';
|
||||
}
|
||||
|
||||
if (data?.kind === 'skill' && data.action === 'create') {
|
||||
return 'builtins.lobe-self-feedback-intent.inspector.skill.create';
|
||||
}
|
||||
|
||||
if (data?.kind === 'skill' && data.action === 'refine') {
|
||||
return 'builtins.lobe-self-feedback-intent.inspector.skill.refine';
|
||||
}
|
||||
|
||||
if (data?.kind === 'skill' && data.action === 'consolidate') {
|
||||
return 'builtins.lobe-self-feedback-intent.inspector.skill.consolidate';
|
||||
}
|
||||
|
||||
if (data?.kind === 'gap' && data.action === 'proposal') {
|
||||
return 'builtins.lobe-self-feedback-intent.inspector.gap.proposal';
|
||||
}
|
||||
|
||||
return 'builtins.lobe-self-feedback-intent.apiName.declareSelfFeedbackIntent';
|
||||
};
|
||||
|
||||
const styles = createStaticStyles(({ css, cssVar }) => ({
|
||||
iconAccepted: css`
|
||||
flex-shrink: 0;
|
||||
color: ${cssVar.colorSuccess};
|
||||
`,
|
||||
iconRejected: css`
|
||||
flex-shrink: 0;
|
||||
color: ${cssVar.colorWarning};
|
||||
`,
|
||||
meta: css`
|
||||
flex-shrink: 0;
|
||||
font-size: 12px;
|
||||
color: ${cssVar.colorTextTertiary};
|
||||
`,
|
||||
summary: css`
|
||||
overflow: hidden;
|
||||
|
||||
min-width: 0;
|
||||
max-width: 320px;
|
||||
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
`,
|
||||
}));
|
||||
|
||||
export const DeclareSelfFeedbackIntentInspector = memo<
|
||||
BuiltinInspectorProps<DeclareSelfFeedbackIntentParams, DeclareSelfFeedbackIntentState>
|
||||
>(({ args, partialArgs, isArgumentsStreaming, isLoading, pluginState }) => {
|
||||
const { t } = useTranslation('plugin');
|
||||
|
||||
const data = args ?? partialArgs;
|
||||
const summary = data?.summary;
|
||||
const hasContext = Boolean(summary || data?.kind || data?.action);
|
||||
const title = t(getIntentLabelKey(data));
|
||||
|
||||
if (isArgumentsStreaming && !hasContext) {
|
||||
return (
|
||||
<div className={cx(inspectorTextStyles.root, shinyTextStyles.shinyText)}>
|
||||
<span>{title}</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const isSettled = !isArgumentsStreaming && !isLoading && !!pluginState;
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{ flexWrap: 'wrap', gap: 4 }}
|
||||
className={cx(
|
||||
inspectorTextStyles.root,
|
||||
(isArgumentsStreaming || isLoading) && shinyTextStyles.shinyText,
|
||||
)}
|
||||
>
|
||||
<span>{title}</span>
|
||||
{summary && (
|
||||
<span className={cx(highlightTextStyles.primary, styles.summary)}>{summary}</span>
|
||||
)}
|
||||
{isSettled &&
|
||||
pluginState &&
|
||||
(pluginState.accepted ? (
|
||||
<Icon className={styles.iconAccepted} icon={CheckCircle2} size={14} />
|
||||
) : (
|
||||
<>
|
||||
<Icon className={styles.iconRejected} icon={CircleAlert} size={14} />
|
||||
<span className={styles.meta}>
|
||||
{t('builtins.lobe-self-feedback-intent.inspector.rejected')}
|
||||
</span>
|
||||
</>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
});
|
||||
|
||||
DeclareSelfFeedbackIntentInspector.displayName = 'DeclareSelfFeedbackIntentInspector';
|
||||
|
||||
export default DeclareSelfFeedbackIntentInspector;
|
||||
@@ -0,0 +1,11 @@
|
||||
import type { BuiltinInspector } from '@lobechat/types';
|
||||
|
||||
import { SelfFeedbackIntentApiName } from '../../types';
|
||||
import { DeclareSelfFeedbackIntentInspector } from './DeclareSelfFeedbackIntent';
|
||||
|
||||
export const SelfFeedbackIntentInspectors: Record<string, BuiltinInspector> = {
|
||||
[SelfFeedbackIntentApiName.declareSelfFeedbackIntent]:
|
||||
DeclareSelfFeedbackIntentInspector as BuiltinInspector,
|
||||
};
|
||||
|
||||
export { DeclareSelfFeedbackIntentInspector } from './DeclareSelfFeedbackIntent';
|
||||
@@ -0,0 +1,4 @@
|
||||
export { DeclareSelfFeedbackIntentInspector, SelfFeedbackIntentInspectors } from './Inspector';
|
||||
|
||||
export { selfFeedbackIntentManifest } from '../manifest';
|
||||
export * from '../types';
|
||||
@@ -1,11 +1,12 @@
|
||||
import type { LobeToolManifest, OperationToolSet, ToolSource } from '@lobechat/context-engine';
|
||||
import { describe, expect, it } from 'vitest';
|
||||
import { describe, expect, it, vi } from 'vitest';
|
||||
|
||||
import {
|
||||
injectSelfFeedbackIntentTool,
|
||||
SELF_FEEDBACK_INTENT_API_NAME,
|
||||
SELF_FEEDBACK_INTENT_IDENTIFIER,
|
||||
SELF_FEEDBACK_INTENT_TOOL_NAME,
|
||||
SelfFeedbackIntentExecutionRuntime,
|
||||
selfFeedbackIntentManifest,
|
||||
shouldExposeSelfFeedbackIntentTool,
|
||||
} from './index';
|
||||
@@ -103,6 +104,7 @@ describe('selfFeedbackIntentTool', () => {
|
||||
'skillId',
|
||||
]);
|
||||
expect(api.description).toContain('does not mutate memory or skills');
|
||||
expect(properties.evidenceRefs.items.properties.summary).toBeDefined();
|
||||
expect(api.parameters.required).toEqual([
|
||||
'action',
|
||||
'kind',
|
||||
@@ -110,6 +112,93 @@ describe('selfFeedbackIntentTool', () => {
|
||||
'summary',
|
||||
'reason',
|
||||
]);
|
||||
expect(selfFeedbackIntentManifest.systemRole).toContain('<aggressive_usage_policy>');
|
||||
});
|
||||
});
|
||||
|
||||
describe('SelfFeedbackIntentExecutionRuntime', () => {
|
||||
/**
|
||||
* @example
|
||||
* The package runtime delegates declaration emission to an injected service and persists state.
|
||||
*/
|
||||
it('delegates declarations to the injected service', async () => {
|
||||
const service = {
|
||||
declareIntent: vi.fn().mockResolvedValue({
|
||||
accepted: true,
|
||||
sourceId: 'self-feedback-intent:user-1:agent-1:topic:topic-1:tool-call-1',
|
||||
strength: 'strong' as const,
|
||||
}),
|
||||
};
|
||||
const runtime = new SelfFeedbackIntentExecutionRuntime({ service });
|
||||
|
||||
const result = await runtime.declareSelfFeedbackIntent(
|
||||
{
|
||||
action: 'refine',
|
||||
confidence: 0.91,
|
||||
evidenceRefs: [{ id: 'msg-1', type: 'message' }],
|
||||
kind: 'skill',
|
||||
reason: 'The release workflow correction should become reusable.',
|
||||
summary: 'Refine the release workflow skill.',
|
||||
},
|
||||
{
|
||||
agentId: 'agent-1',
|
||||
toolCallId: 'tool-call-1',
|
||||
topicId: 'topic-1',
|
||||
userId: 'user-1',
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.success).toBe(true);
|
||||
expect(result.state).toEqual({
|
||||
accepted: true,
|
||||
reason: null,
|
||||
sourceId: 'self-feedback-intent:user-1:agent-1:topic:topic-1:tool-call-1',
|
||||
strength: 'strong',
|
||||
});
|
||||
expect(service.declareIntent).toHaveBeenCalledWith({
|
||||
agentId: 'agent-1',
|
||||
input: {
|
||||
action: 'refine',
|
||||
confidence: 0.91,
|
||||
evidenceRefs: [{ id: 'msg-1', type: 'message' }],
|
||||
kind: 'skill',
|
||||
reason: 'The release workflow correction should become reusable.',
|
||||
summary: 'Refine the release workflow skill.',
|
||||
},
|
||||
toolCallId: 'tool-call-1',
|
||||
topicId: 'topic-1',
|
||||
userId: 'user-1',
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* @example
|
||||
* Missing runtime identity context returns a tool failure before crossing service boundaries.
|
||||
*/
|
||||
it('returns missing context failure without calling the service', async () => {
|
||||
const service = {
|
||||
declareIntent: vi.fn(),
|
||||
};
|
||||
const runtime = new SelfFeedbackIntentExecutionRuntime({ service });
|
||||
|
||||
const result = await runtime.declareSelfFeedbackIntent(
|
||||
{
|
||||
action: 'proposal',
|
||||
confidence: 0.6,
|
||||
kind: 'gap',
|
||||
reason: 'The inspector is missing.',
|
||||
summary: 'Add a self-feedback inspector.',
|
||||
},
|
||||
{ agentId: 'agent-1', userId: 'user-1' },
|
||||
);
|
||||
|
||||
expect(result.success).toBe(false);
|
||||
expect(JSON.parse(result.content)).toEqual({
|
||||
accepted: false,
|
||||
reason: 'missing_context',
|
||||
required: ['agentId', 'userId', 'topicId'],
|
||||
});
|
||||
expect(service.declareIntent).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -1,12 +1,32 @@
|
||||
export * from './ExecutionRuntime';
|
||||
export {
|
||||
injectSelfFeedbackIntentTool,
|
||||
type SelfFeedbackIntentToolSetParts,
|
||||
shouldExposeSelfFeedbackIntentTool,
|
||||
} from './inject';
|
||||
export { selfFeedbackIntentManifest } from './manifest';
|
||||
export { systemPrompt } from './systemRole';
|
||||
export {
|
||||
type DeclareSelfFeedbackIntentContext,
|
||||
type DeclareSelfFeedbackIntentInput,
|
||||
type DeclareSelfFeedbackIntentParams,
|
||||
type DeclareSelfFeedbackIntentPayload,
|
||||
type DeclareSelfFeedbackIntentRejectionReason,
|
||||
type DeclareSelfFeedbackIntentResult,
|
||||
type DeclareSelfFeedbackIntentState,
|
||||
type DeclareSelfFeedbackIntentStateReason,
|
||||
SELF_FEEDBACK_INTENT_API_NAME,
|
||||
SELF_FEEDBACK_INTENT_ACTIONS,
|
||||
SELF_FEEDBACK_INTENT_EVIDENCE_REF_TYPES,
|
||||
SELF_FEEDBACK_INTENT_IDENTIFIER,
|
||||
SELF_FEEDBACK_INTENT_KINDS,
|
||||
SELF_FEEDBACK_INTENT_TOOL_NAME,
|
||||
type ShouldExposeSelfFeedbackIntentToolOptions,
|
||||
SelfFeedbackIntentApiName,
|
||||
type SelfFeedbackIntentApiNameType,
|
||||
type SelfFeedbackIntentAction,
|
||||
type SelfFeedbackIntentEvidenceRef,
|
||||
type SelfFeedbackIntentEvidenceRefType,
|
||||
type SelfFeedbackIntentKind,
|
||||
type SelfFeedbackIntentStrength,
|
||||
} from './types';
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
import type { BuiltinToolManifest } from '@lobechat/types';
|
||||
|
||||
import { SELF_FEEDBACK_INTENT_API_NAME, SELF_FEEDBACK_INTENT_IDENTIFIER } from './types';
|
||||
import { systemPrompt } from './systemRole';
|
||||
import {
|
||||
SELF_FEEDBACK_INTENT_ACTIONS,
|
||||
SELF_FEEDBACK_INTENT_EVIDENCE_REF_TYPES,
|
||||
SELF_FEEDBACK_INTENT_IDENTIFIER,
|
||||
SELF_FEEDBACK_INTENT_KINDS,
|
||||
SelfFeedbackIntentApiName,
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
* Self-iteration intent builtin tool manifest.
|
||||
@@ -19,44 +26,54 @@ export const selfFeedbackIntentManifest = {
|
||||
api: [
|
||||
{
|
||||
description:
|
||||
'Declare advisory self-feedback intent for future review. This only records intent and does not mutate memory or skills.',
|
||||
name: SELF_FEEDBACK_INTENT_API_NAME,
|
||||
'Declare advisory self-feedback intent for future review whenever the running agent finds a concrete, reusable improvement opportunity. Use this proactively for memory, skill, or system gap feedback; it only records intent and does not mutate memory or skills.',
|
||||
name: SelfFeedbackIntentApiName.declareSelfFeedbackIntent,
|
||||
parameters: {
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
action: {
|
||||
description: 'Self-iteration action the agent believes may be useful.',
|
||||
enum: ['write', 'create', 'refine', 'consolidate', 'proposal'],
|
||||
description:
|
||||
'Self-iteration action the agent believes may be useful. Use write for memory, create/refine/consolidate for skills, and proposal for system or workflow gaps.',
|
||||
enum: [...SELF_FEEDBACK_INTENT_ACTIONS],
|
||||
type: 'string',
|
||||
},
|
||||
kind: {
|
||||
description: 'Self-iteration target category for the declaration.',
|
||||
enum: ['memory', 'skill', 'gap'],
|
||||
description:
|
||||
'Self-iteration target category: memory for durable user signals, skill for reusable procedures or capabilities, gap for product/runtime/tooling/policy feedback.',
|
||||
enum: [...SELF_FEEDBACK_INTENT_KINDS],
|
||||
type: 'string',
|
||||
},
|
||||
confidence: {
|
||||
description: 'Agent confidence from 0 to 1.',
|
||||
description:
|
||||
'Agent confidence from 0 to 1 that this declaration is worth downstream review. Prefer >=0.75 for well-grounded evidence and 0.45-0.74 for plausible but review-needed feedback.',
|
||||
maximum: 1,
|
||||
minimum: 0,
|
||||
type: 'number',
|
||||
},
|
||||
summary: {
|
||||
description: 'Short summary of the self-feedback intent.',
|
||||
description:
|
||||
'Short, actionable summary of the self-feedback intent. Name the target and desired improvement.',
|
||||
type: 'string',
|
||||
},
|
||||
reason: {
|
||||
description: 'Rationale for why this self-feedback intent may be useful.',
|
||||
description:
|
||||
'Rationale explaining the triggering evidence, why it matters, and the expected future benefit.',
|
||||
type: 'string',
|
||||
},
|
||||
evidenceRefs: {
|
||||
description: 'Optional references that justify the declaration.',
|
||||
description:
|
||||
'Optional stable references that justify the declaration. Prefer concrete message, tool_call, operation, topic, receipt, task, agent_document, or memory refs.',
|
||||
items: {
|
||||
additionalProperties: false,
|
||||
properties: {
|
||||
id: { description: 'Stable evidence identifier.', type: 'string' },
|
||||
summary: {
|
||||
description: 'Optional short note explaining why this evidence matters.',
|
||||
type: 'string',
|
||||
},
|
||||
type: {
|
||||
description: 'Evidence object type.',
|
||||
enum: ['message', 'tool_call', 'receipt', 'document', 'custom'],
|
||||
enum: [...SELF_FEEDBACK_INTENT_EVIDENCE_REF_TYPES],
|
||||
type: 'string',
|
||||
},
|
||||
},
|
||||
@@ -79,13 +96,13 @@ export const selfFeedbackIntentManifest = {
|
||||
},
|
||||
},
|
||||
],
|
||||
executors: ['server'],
|
||||
identifier: SELF_FEEDBACK_INTENT_IDENTIFIER,
|
||||
meta: {
|
||||
description:
|
||||
'Let a running agent declare advisory self-feedback intent without mutating memory or skills directly.',
|
||||
'Let a running agent proactively declare advisory self-feedback intent without mutating memory or skills directly.',
|
||||
title: 'Self Feedback Intent',
|
||||
},
|
||||
systemRole:
|
||||
'Declare advisory self-feedback intent only when future self-review may improve memory or skills. This tool records intent and must not claim that it directly mutates resources.',
|
||||
systemRole: systemPrompt,
|
||||
type: 'builtin',
|
||||
} as const satisfies BuiltinToolManifest;
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
export const systemPrompt = `You have access to the Self Feedback Intent tool. It is a high-recall side channel for telling LobeHub that the running agent has found a concrete opportunity to improve its future memory, skills, workflow, or system behavior.
|
||||
|
||||
<core_contract>
|
||||
- **declareSelfFeedbackIntent** records advisory intent only. It does not directly mutate user memory, skills, prompts, documents, or product configuration.
|
||||
- Downstream self-iteration reviewers own validation, dedupe, approval, and any eventual write/refine/create/consolidate action.
|
||||
- Use this tool to make the system aware of what the agent thinks should be reviewed later, even when the current user task should continue normally.
|
||||
</core_contract>
|
||||
|
||||
<aggressive_usage_policy>
|
||||
- Be proactive. Declare self-feedback intent whenever a specific, reusable improvement is visible and can be grounded in the current run.
|
||||
- Prefer declaring a concise intent over silently losing a useful learning signal. The downstream pipeline can reject weak, duplicate, or unsafe declarations.
|
||||
- Emit at most the strongest 1-3 declarations per operation or topic. Do not spam vague reflections, stylistic preferences, or duplicate signals.
|
||||
- Use confidence >= 0.75 when you have concrete evidence refs and a clear future benefit. Use 0.45-0.74 for plausible but review-needed improvements. Avoid calls below 0.45 unless the gap is operationally important.
|
||||
</aggressive_usage_policy>
|
||||
|
||||
<when_to_call>
|
||||
Call **declareSelfFeedbackIntent** when any of these happen:
|
||||
- The user corrects the agent, asks "remember next time", points out a repeated miss, or gives feedback that should improve future behavior.
|
||||
- The agent discovers a reusable workflow, checklist, prompt pattern, tool-use strategy, or coding/review heuristic that should become or refine a skill.
|
||||
- The agent sees an outdated, incomplete, duplicated, or missing memory signal that should be reviewed before future conversations.
|
||||
- A tool, runtime, inspector, prompt, policy, or routing behavior caused friction and a concrete system gap should be reviewed.
|
||||
- A task succeeds only after a non-obvious fix, workaround, or diagnosis that future agents should reuse.
|
||||
</when_to_call>
|
||||
|
||||
<action_kind_mapping>
|
||||
- **kind=memory + action=write**: durable user preference, identity/context/experience signal, or stale/missing memory worth review.
|
||||
- **kind=skill + action=create**: a reusable procedure or capability does not exist yet.
|
||||
- **kind=skill + action=refine**: an existing skill should be sharpened, corrected, made more aggressive, or expanded with examples.
|
||||
- **kind=skill + action=consolidate**: multiple overlapping skills or procedures should be merged.
|
||||
- **kind=gap + action=proposal**: product/runtime/tooling/policy gaps, missing UI, weak inspector, poor evidence capture, or unsupported automation ideas.
|
||||
</action_kind_mapping>
|
||||
|
||||
<argument_rules>
|
||||
- **summary**: one short, actionable sentence. Name the target and desired improvement.
|
||||
- **reason**: include the triggering evidence, why it matters, and the expected future benefit.
|
||||
- **confidence**: calibrated probability that this declaration is worth downstream review, not certainty that a mutation should happen.
|
||||
- **evidenceRefs**: include stable ids when available. Prefer message, tool_call, operation, topic, receipt, task, agent_document, or memory refs over generic prose.
|
||||
- **memoryId** and **skillId**: include only when you know the exact existing target. Do not invent ids.
|
||||
</argument_rules>
|
||||
|
||||
<boundaries>
|
||||
- Do not use this tool as a user-facing answer, apology, or progress update.
|
||||
- Do not declare secrets, credentials, private keys, or sensitive personal data as self-feedback.
|
||||
- Do not claim that the declaration saved memory or updated a skill. Say only that the intent was declared when you mention it internally.
|
||||
- If a direct user request conflicts with self-iteration, satisfy the user request first and only declare concise feedback if it will not distract from the task.
|
||||
</boundaries>`;
|
||||
@@ -7,6 +7,151 @@ export const SELF_FEEDBACK_INTENT_API_NAME = 'declareSelfFeedbackIntent';
|
||||
/** LLM-visible tool name generated from identifier and API name. */
|
||||
export const SELF_FEEDBACK_INTENT_TOOL_NAME = `${SELF_FEEDBACK_INTENT_IDENTIFIER}____${SELF_FEEDBACK_INTENT_API_NAME}`;
|
||||
|
||||
/** Stable API name map used by manifests, runtimes, and inspectors. */
|
||||
export const SelfFeedbackIntentApiName = {
|
||||
declareSelfFeedbackIntent: SELF_FEEDBACK_INTENT_API_NAME,
|
||||
} as const;
|
||||
|
||||
export type SelfFeedbackIntentApiNameType =
|
||||
(typeof SelfFeedbackIntentApiName)[keyof typeof SelfFeedbackIntentApiName];
|
||||
|
||||
export const SELF_FEEDBACK_INTENT_ACTIONS = [
|
||||
'write',
|
||||
'create',
|
||||
'refine',
|
||||
'consolidate',
|
||||
'proposal',
|
||||
] as const;
|
||||
|
||||
export const SELF_FEEDBACK_INTENT_KINDS = ['memory', 'skill', 'gap'] as const;
|
||||
|
||||
export const SELF_FEEDBACK_INTENT_EVIDENCE_REF_TYPES = [
|
||||
'topic',
|
||||
'message',
|
||||
'operation',
|
||||
'source',
|
||||
'receipt',
|
||||
'tool_call',
|
||||
'task',
|
||||
'agent_document',
|
||||
'memory',
|
||||
] as const;
|
||||
|
||||
/** Actions that an agent may declare as self-feedback intent. */
|
||||
export type SelfFeedbackIntentAction = (typeof SELF_FEEDBACK_INTENT_ACTIONS)[number];
|
||||
|
||||
/** Self-feedback target categories accepted from agent-declared intent. */
|
||||
export type SelfFeedbackIntentKind = (typeof SELF_FEEDBACK_INTENT_KINDS)[number];
|
||||
|
||||
/** Evidence reference type accepted by downstream self-iteration handlers. */
|
||||
export type SelfFeedbackIntentEvidenceRefType =
|
||||
(typeof SELF_FEEDBACK_INTENT_EVIDENCE_REF_TYPES)[number];
|
||||
|
||||
/** Evidence strength assigned to one accepted or rejected declaration. */
|
||||
export type SelfFeedbackIntentStrength = 'strong' | 'weak';
|
||||
|
||||
/** Optional reference that grounds one self-feedback declaration. */
|
||||
export interface SelfFeedbackIntentEvidenceRef {
|
||||
/** Stable evidence identifier in its source domain. */
|
||||
id: string;
|
||||
/** Optional short note explaining why this evidence matters. */
|
||||
summary?: string;
|
||||
/** Evidence object type. */
|
||||
type: SelfFeedbackIntentEvidenceRefType;
|
||||
}
|
||||
|
||||
/** Input payload declared by the running agent through the self-feedback intent tool. */
|
||||
export interface DeclareSelfFeedbackIntentPayload {
|
||||
/** Self-feedback action the agent believes may be useful. */
|
||||
action: SelfFeedbackIntentAction;
|
||||
/** Agent confidence from 0 to 1. */
|
||||
confidence: number;
|
||||
/** Evidence references that justify the declaration. */
|
||||
evidenceRefs?: SelfFeedbackIntentEvidenceRef[];
|
||||
/** Target category for the declaration. */
|
||||
kind: SelfFeedbackIntentKind;
|
||||
/** Existing memory id when the declaration targets a known memory. */
|
||||
memoryId?: string;
|
||||
/** Human-readable rationale from the agent. */
|
||||
reason: string;
|
||||
/** Existing skill id when the declaration targets a known skill. */
|
||||
skillId?: string;
|
||||
/** Short declaration summary for downstream review. */
|
||||
summary: string;
|
||||
}
|
||||
|
||||
export type DeclareSelfFeedbackIntentParams = DeclareSelfFeedbackIntentPayload;
|
||||
|
||||
/** Runtime context required to emit one self-feedback declaration. */
|
||||
export interface DeclareSelfFeedbackIntentContext {
|
||||
/** Stable agent id associated with the running agent. */
|
||||
agentId?: string;
|
||||
/** Runtime operation id when the declaration belongs to a narrower operation scope. */
|
||||
operationId?: string;
|
||||
/** Caller-provided tool-call id. */
|
||||
toolCallId?: string;
|
||||
/** Current topic id for stable source ids and topic fallback scope. */
|
||||
topicId?: string;
|
||||
/** Stable user id associated with the running agent. */
|
||||
userId?: string;
|
||||
}
|
||||
|
||||
/** Input used by a runtime service to declare one self-feedback source event. */
|
||||
export interface DeclareSelfFeedbackIntentInput {
|
||||
/** Stable agent id associated with the running agent. */
|
||||
agentId: string;
|
||||
/** Agent-declared self-feedback intent payload. */
|
||||
input: DeclareSelfFeedbackIntentPayload;
|
||||
/** Runtime operation id when the declaration belongs to a narrower operation scope. */
|
||||
operationId?: string;
|
||||
/** Caller-provided tool-call id. */
|
||||
toolCallId?: string;
|
||||
/** Current topic id for stable source ids and topic fallback scope. */
|
||||
topicId: string;
|
||||
/** Stable user id associated with the running agent. */
|
||||
userId: string;
|
||||
}
|
||||
|
||||
export type DeclareSelfFeedbackIntentRejectionReason =
|
||||
| 'enqueue_gate_rejected'
|
||||
| 'intent_gate_rejected'
|
||||
| 'invalid_action'
|
||||
| 'invalid_confidence'
|
||||
| 'invalid_kind'
|
||||
| 'rate_limited';
|
||||
|
||||
/** Result returned after one declaration attempt. */
|
||||
export interface DeclareSelfFeedbackIntentResult {
|
||||
/** Whether the declaration was accepted and emitted to the enqueue boundary. */
|
||||
accepted: boolean;
|
||||
/** Optional rejection reason when no source was enqueued. */
|
||||
reason?: DeclareSelfFeedbackIntentRejectionReason;
|
||||
/** Stable source id built for accepted declarations when available. */
|
||||
sourceId?: string;
|
||||
/** Evidence strength assigned from confidence and evidence presence. */
|
||||
strength: SelfFeedbackIntentStrength;
|
||||
}
|
||||
|
||||
export type DeclareSelfFeedbackIntentStateReason =
|
||||
| DeclareSelfFeedbackIntentRejectionReason
|
||||
| 'missing_context'
|
||||
| 'runtime_error'
|
||||
| null;
|
||||
|
||||
/** State persisted for inspector display after one self-feedback declaration. */
|
||||
export interface DeclareSelfFeedbackIntentState {
|
||||
/** Whether the declaration crossed the Agent Signal enqueue boundary. */
|
||||
accepted: boolean;
|
||||
/** Missing context keys when the runtime cannot emit the declaration. */
|
||||
required?: string[];
|
||||
/** Rejection or runtime reason. */
|
||||
reason: DeclareSelfFeedbackIntentStateReason;
|
||||
/** Stable source id for accepted declarations. */
|
||||
sourceId?: null | string;
|
||||
/** Evidence strength assigned by the declaration service. */
|
||||
strength?: SelfFeedbackIntentStrength;
|
||||
}
|
||||
|
||||
/** Gate input used to decide whether the declaration tool may be exposed. */
|
||||
export interface ShouldExposeSelfFeedbackIntentToolOptions {
|
||||
/** Agent-level self-iteration chat config gate. */
|
||||
|
||||
@@ -42,6 +42,10 @@ import {
|
||||
import { MemoryInspectors, MemoryManifest } from '@lobechat/builtin-tool-memory/client';
|
||||
import { MessageInspectors, MessageManifest } from '@lobechat/builtin-tool-message/client';
|
||||
import { PageAgentInspectors, PageAgentManifest } from '@lobechat/builtin-tool-page-agent/client';
|
||||
import {
|
||||
SelfFeedbackIntentInspectors,
|
||||
selfFeedbackIntentManifest,
|
||||
} from '@lobechat/builtin-tool-self-iteration/client';
|
||||
import {
|
||||
SkillStoreInspectors,
|
||||
SkillStoreManifest,
|
||||
@@ -57,7 +61,7 @@ import {
|
||||
WebOnboardingManifest,
|
||||
} from '@lobechat/builtin-tool-web-onboarding/client';
|
||||
import { createRunCommandInspector } from '@lobechat/shared-tool-ui/inspectors';
|
||||
import { type BuiltinInspector } from '@lobechat/types';
|
||||
import type { BuiltinInspector } from '@lobechat/types';
|
||||
|
||||
import { CodexInspectors } from './codex';
|
||||
import { GithubIdentifier, GithubInspectors } from './github';
|
||||
@@ -93,6 +97,10 @@ const BuiltinToolInspectors: Record<string, Record<string, BuiltinInspector>> =
|
||||
[MessageManifest.identifier]: MessageInspectors as Record<string, BuiltinInspector>,
|
||||
[PageAgentManifest.identifier]: PageAgentInspectors as Record<string, BuiltinInspector>,
|
||||
[LobeActivatorManifest.identifier]: LobeActivatorInspectors as Record<string, BuiltinInspector>,
|
||||
[selfFeedbackIntentManifest.identifier]: SelfFeedbackIntentInspectors as Record<
|
||||
string,
|
||||
BuiltinInspector
|
||||
>,
|
||||
[SkillStoreManifest.identifier]: SkillStoreInspectors as Record<string, BuiltinInspector>,
|
||||
[SkillsManifest.identifier]: SkillsInspectors as Record<string, BuiltinInspector>,
|
||||
[TaskManifest.identifier]: TaskInspectors as Record<string, BuiltinInspector>,
|
||||
|
||||
@@ -1,8 +1,32 @@
|
||||
import { type ChildProcess, spawn } from 'node:child_process';
|
||||
import dotenv from 'dotenv';
|
||||
import dotenvExpand from 'dotenv-expand';
|
||||
import net from 'node:net';
|
||||
|
||||
dotenv.config();
|
||||
const env = process.env.NODE_ENV || 'development';
|
||||
|
||||
const shellEnv = Object.entries(process.env).reduce<Record<string, string>>(
|
||||
(acc, [key, value]) => {
|
||||
if (typeof value === 'string') acc[key] = value;
|
||||
return acc;
|
||||
},
|
||||
{},
|
||||
);
|
||||
const dotenvEnv: Record<string, string> = {};
|
||||
const dotenvResult = dotenv.config({
|
||||
override: true,
|
||||
path: ['.env', `.env.${env}`, `.env.${env}.local`],
|
||||
processEnv: dotenvEnv,
|
||||
});
|
||||
|
||||
if (dotenvResult.parsed) {
|
||||
const expanded = dotenvExpand.expand({
|
||||
parsed: dotenvResult.parsed,
|
||||
processEnv: { ...dotenvEnv, ...shellEnv },
|
||||
});
|
||||
|
||||
Object.assign(process.env, expanded.parsed, shellEnv);
|
||||
}
|
||||
|
||||
const NEXT_HOST = 'localhost';
|
||||
|
||||
|
||||
@@ -290,6 +290,14 @@ export default {
|
||||
'builtins.lobe-task.runTasks.failedCount': '{{count}} failed',
|
||||
'builtins.lobe-task.runTasks.more': '+{{count}} more',
|
||||
'builtins.lobe-task.title': 'Task Tools',
|
||||
'builtins.lobe-self-feedback-intent.apiName.declareSelfFeedbackIntent': 'Record improvement idea',
|
||||
'builtins.lobe-self-feedback-intent.inspector.gap.proposal': 'Suggest improvement',
|
||||
'builtins.lobe-self-feedback-intent.inspector.memory.write': 'Record preference',
|
||||
'builtins.lobe-self-feedback-intent.inspector.rejected': 'Not recorded',
|
||||
'builtins.lobe-self-feedback-intent.inspector.skill.consolidate': 'Organize methods',
|
||||
'builtins.lobe-self-feedback-intent.inspector.skill.create': 'New method found',
|
||||
'builtins.lobe-self-feedback-intent.inspector.skill.refine': 'Improve method',
|
||||
'builtins.lobe-self-feedback-intent.title': 'Improvement Ideas',
|
||||
'builtins.lobe-user-memory.apiName.addContextMemory': 'Add context memory',
|
||||
'builtins.lobe-user-memory.apiName.addExperienceMemory': 'Add experience memory',
|
||||
'builtins.lobe-user-memory.apiName.addIdentityMemory': 'Add identity memory',
|
||||
|
||||
@@ -1,79 +1,36 @@
|
||||
import { AGENT_SIGNAL_SOURCE_TYPES } from '@lobechat/agent-signal/source';
|
||||
import type {
|
||||
DeclareSelfFeedbackIntentInput,
|
||||
DeclareSelfFeedbackIntentPayload,
|
||||
DeclareSelfFeedbackIntentResult,
|
||||
SelfFeedbackIntentAction,
|
||||
SelfFeedbackIntentKind,
|
||||
SelfFeedbackIntentStrength,
|
||||
} from '@lobechat/builtin-tool-self-iteration';
|
||||
import {
|
||||
SELF_FEEDBACK_INTENT_ACTIONS,
|
||||
SELF_FEEDBACK_INTENT_KINDS,
|
||||
} from '@lobechat/builtin-tool-self-iteration';
|
||||
|
||||
import type { AgentSignalSourceEventInput } from '@/server/services/agentSignal/emitter';
|
||||
|
||||
import type { EvidenceRef } from './selfIteration/types';
|
||||
import { buildSelfFeedbackIntentSourceId } from './selfIteration/types';
|
||||
|
||||
export type {
|
||||
DeclareSelfFeedbackIntentInput,
|
||||
DeclareSelfFeedbackIntentPayload,
|
||||
DeclareSelfFeedbackIntentResult,
|
||||
SelfFeedbackIntentAction,
|
||||
SelfFeedbackIntentKind,
|
||||
SelfFeedbackIntentStrength,
|
||||
} from '@lobechat/builtin-tool-self-iteration';
|
||||
|
||||
type MaybePromise<TValue> = TValue | Promise<TValue>;
|
||||
|
||||
/** Actions that an agent may declare as self-feedback intent. */
|
||||
export type SelfFeedbackIntentAction = 'write' | 'create' | 'refine' | 'consolidate' | 'proposal';
|
||||
|
||||
/** Self-feedback target categories accepted from agent-declared intent. */
|
||||
export type SelfFeedbackIntentKind = 'memory' | 'skill' | 'gap';
|
||||
|
||||
/** Evidence strength assigned to one accepted or rejected declaration. */
|
||||
export type SelfFeedbackIntentStrength = 'strong' | 'weak';
|
||||
|
||||
/** Source event input emitted by the self-feedback intent declaration service. */
|
||||
export type SelfFeedbackIntentSourceEventInput =
|
||||
AgentSignalSourceEventInput<'agent.self_feedback_intent.declared'>;
|
||||
|
||||
/** Input payload declared by the running agent through the self-feedback intent tool. */
|
||||
export interface DeclareSelfFeedbackIntentPayload {
|
||||
/** Self-feedback action the agent believes may be useful. */
|
||||
action: SelfFeedbackIntentAction;
|
||||
/** Agent confidence from 0 to 1. */
|
||||
confidence: number;
|
||||
/** Evidence references that justify the declaration. */
|
||||
evidenceRefs?: EvidenceRef[];
|
||||
/** Target category for the declaration. */
|
||||
kind: SelfFeedbackIntentKind;
|
||||
/** Existing memory id when the declaration targets a known memory. */
|
||||
memoryId?: string;
|
||||
/** Human-readable rationale from the agent. */
|
||||
reason: string;
|
||||
/** Existing skill id when the declaration targets a known skill. */
|
||||
skillId?: string;
|
||||
/** Short declaration summary for downstream review. */
|
||||
summary: string;
|
||||
}
|
||||
|
||||
/** Input used to declare one agent-facing self-feedback intent source event. */
|
||||
export interface DeclareSelfFeedbackIntentInput {
|
||||
/** Stable agent id associated with the running agent. */
|
||||
agentId: string;
|
||||
/** Agent-declared self-feedback intent payload. */
|
||||
input: DeclareSelfFeedbackIntentPayload;
|
||||
/** Runtime operation id when the declaration belongs to a narrower operation scope. */
|
||||
operationId?: string;
|
||||
/** Caller-provided tool-call id. When omitted, the injected id generator is used. */
|
||||
toolCallId?: string;
|
||||
/** Current topic id for stable source ids and topic fallback scope. */
|
||||
topicId: string;
|
||||
/** Stable user id associated with the running agent. */
|
||||
userId: string;
|
||||
}
|
||||
|
||||
/** Result returned after one declaration attempt. */
|
||||
export interface DeclareSelfFeedbackIntentResult {
|
||||
/** Whether the declaration was accepted and emitted to the enqueue boundary. */
|
||||
accepted: boolean;
|
||||
/** Optional rejection reason when no source was enqueued. */
|
||||
reason?:
|
||||
| 'enqueue_gate_rejected'
|
||||
| 'intent_gate_rejected'
|
||||
| 'invalid_action'
|
||||
| 'invalid_confidence'
|
||||
| 'invalid_kind'
|
||||
| 'rate_limited';
|
||||
/** Stable source id built for accepted declarations when available. */
|
||||
sourceId?: string;
|
||||
/** Evidence strength assigned from confidence and evidence presence. */
|
||||
strength: SelfFeedbackIntentStrength;
|
||||
}
|
||||
|
||||
/** Dependencies used by the pure self-feedback intent declaration service. */
|
||||
export interface SelfFeedbackIntentServiceDependencies {
|
||||
/**
|
||||
@@ -119,14 +76,8 @@ export interface SelfFeedbackIntentService {
|
||||
const DECLARATION_LIMIT_PER_SCOPE = 3;
|
||||
const STRONG_CONFIDENCE_THRESHOLD = 0.75;
|
||||
|
||||
const validActions = new Set<SelfFeedbackIntentAction>([
|
||||
'write',
|
||||
'create',
|
||||
'refine',
|
||||
'consolidate',
|
||||
'proposal',
|
||||
]);
|
||||
const validKinds = new Set<SelfFeedbackIntentKind>(['memory', 'skill', 'gap']);
|
||||
const validActions = new Set<SelfFeedbackIntentAction>(SELF_FEEDBACK_INTENT_ACTIONS);
|
||||
const validKinds = new Set<SelfFeedbackIntentKind>(SELF_FEEDBACK_INTENT_KINDS);
|
||||
|
||||
const getStrength = (input: DeclareSelfFeedbackIntentPayload): SelfFeedbackIntentStrength => {
|
||||
if (!input.evidenceRefs?.length || input.confidence < STRONG_CONFIDENCE_THRESHOLD) {
|
||||
|
||||
@@ -1,28 +1,12 @@
|
||||
import { SELF_FEEDBACK_INTENT_IDENTIFIER } from '@lobechat/builtin-tool-self-iteration';
|
||||
import { SelfFeedbackIntentExecutionRuntime } from '@lobechat/builtin-tool-self-iteration/executionRuntime';
|
||||
import { nanoid } from '@lobechat/utils';
|
||||
|
||||
import { enqueueAgentSignalSourceEvent } from '@/server/services/agentSignal';
|
||||
import type { DeclareSelfFeedbackIntentPayload } from '@/server/services/agentSignal/services/selfFeedbackIntent';
|
||||
import { createSelfFeedbackIntentService } from '@/server/services/agentSignal/services/selfFeedbackIntent';
|
||||
|
||||
import type { ToolExecutionContext, ToolExecutionResult } from '../types';
|
||||
import type { ServerRuntimeRegistration } from './types';
|
||||
|
||||
type SelfFeedbackIntentToolResultContent = {
|
||||
accepted: boolean;
|
||||
reason: null | string;
|
||||
sourceId: null | string;
|
||||
strength: 'strong' | 'weak';
|
||||
};
|
||||
|
||||
const createJsonResult = (
|
||||
content: SelfFeedbackIntentToolResultContent,
|
||||
success: boolean,
|
||||
): ToolExecutionResult => ({
|
||||
content: JSON.stringify(content),
|
||||
success,
|
||||
});
|
||||
|
||||
const sharedSelfFeedbackIntentService = createSelfFeedbackIntentService({
|
||||
enqueueSource: (sourceEvent) =>
|
||||
enqueueAgentSignalSourceEvent(sourceEvent, {
|
||||
@@ -32,72 +16,26 @@ const sharedSelfFeedbackIntentService = createSelfFeedbackIntentService({
|
||||
nextToolCallId: () => nanoid(),
|
||||
});
|
||||
|
||||
/**
|
||||
* Server runtime for advisory self-feedback intent declarations.
|
||||
*
|
||||
* Use when:
|
||||
* - A running agent calls declareSelfFeedbackIntent
|
||||
* - The server should enqueue Agent Signal source events without mutating resources directly
|
||||
*
|
||||
* Expects:
|
||||
* - Tool execution context includes `agentId`, `userId`, and `topicId`
|
||||
* - `operationId` and `toolCallId` are used when present for stable source identity
|
||||
*
|
||||
* Returns:
|
||||
* - JSON tool content with accepted status, source id, strength, and rejection reason
|
||||
*/
|
||||
class SelfFeedbackIntentRuntime {
|
||||
declareSelfFeedbackIntent = async (
|
||||
input: DeclareSelfFeedbackIntentPayload,
|
||||
context: ToolExecutionContext,
|
||||
): Promise<ToolExecutionResult> => {
|
||||
const { agentId, operationId, toolCallId, topicId, userId } = context;
|
||||
|
||||
if (!agentId || !userId || !topicId) {
|
||||
return {
|
||||
content: JSON.stringify({
|
||||
accepted: false,
|
||||
reason: 'missing_context',
|
||||
required: ['agentId', 'userId', 'topicId'],
|
||||
}),
|
||||
success: false,
|
||||
};
|
||||
}
|
||||
|
||||
const result = await sharedSelfFeedbackIntentService.declareIntent({
|
||||
agentId,
|
||||
input,
|
||||
operationId,
|
||||
toolCallId,
|
||||
topicId,
|
||||
userId,
|
||||
});
|
||||
|
||||
return createJsonResult(
|
||||
{
|
||||
accepted: result.accepted,
|
||||
reason: result.reason ?? null,
|
||||
sourceId: result.sourceId ?? null,
|
||||
strength: result.strength,
|
||||
},
|
||||
true,
|
||||
);
|
||||
};
|
||||
}
|
||||
const runtime = new SelfFeedbackIntentExecutionRuntime({
|
||||
service: sharedSelfFeedbackIntentService,
|
||||
});
|
||||
|
||||
/**
|
||||
* Registers the self-feedback intent builtin server runtime.
|
||||
*
|
||||
* Use when:
|
||||
* - A running agent calls declareSelfFeedbackIntent
|
||||
* - The server should enqueue Agent Signal source events without mutating resources directly
|
||||
* - BuiltinToolsExecutor needs to resolve the injected declaration tool
|
||||
*
|
||||
* Expects:
|
||||
* - Per-call method validation handles required runtime context
|
||||
* - The package ExecutionRuntime validates per-call `agentId`, `userId`, and `topicId`
|
||||
* - The shared service preserves fast-loop declaration rate limits
|
||||
*
|
||||
* Returns:
|
||||
* - A lightweight runtime instance for the current execution
|
||||
* - A shared runtime instance backed by the server Agent Signal enqueue boundary
|
||||
*/
|
||||
export const selfFeedbackIntentRuntime: ServerRuntimeRegistration = {
|
||||
factory: () => new SelfFeedbackIntentRuntime(),
|
||||
factory: () => runtime,
|
||||
identifier: SELF_FEEDBACK_INTENT_IDENTIFIER,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user