neoagent 2.3.1-beta.63 → 2.3.1-beta.65
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/docs/capabilities.md +1 -1
- package/docs/configuration.md +2 -2
- package/flutter_app/lib/main.dart +1 -0
- package/flutter_app/lib/main_account_settings.dart +50 -22
- package/flutter_app/lib/main_admin.dart +24 -10
- package/flutter_app/lib/main_app_shell.dart +10 -9
- package/flutter_app/lib/main_chat.dart +631 -318
- package/flutter_app/lib/main_controller.dart +29 -8
- package/flutter_app/lib/main_devices.dart +4 -6
- package/flutter_app/lib/main_integrations.dart +15 -7
- package/flutter_app/lib/main_models.dart +207 -8
- package/flutter_app/lib/main_navigation.dart +36 -18
- package/flutter_app/lib/main_operations.dart +162 -91
- package/flutter_app/lib/main_settings.dart +273 -78
- package/flutter_app/lib/main_shared.dart +8 -6
- package/flutter_app/lib/main_unified.dart +388 -0
- package/package.json +1 -1
- package/server/db/database.js +52 -0
- package/server/public/.last_build_id +1 -1
- package/server/public/assets/AssetManifest.json +1 -1
- package/server/public/assets/fonts/MaterialIcons-Regular.otf +0 -0
- package/server/public/flutter_bootstrap.js +1 -1
- package/server/public/main.dart.js +79074 -78010
- package/server/routes/agents.js +2 -1
- package/server/routes/browser.js +1 -14
- package/server/routes/memory.js +75 -3
- package/server/routes/settings.js +1 -5
- package/server/routes/widgets.js +4 -4
- package/server/services/ai/capabilityHealth.js +1 -10
- package/server/services/ai/deliverables/artifact_helpers.js +190 -0
- package/server/services/ai/deliverables/contracts.js +113 -0
- package/server/services/ai/deliverables/deliverables.test.js +76 -0
- package/server/services/ai/deliverables/index.js +20 -0
- package/server/services/ai/deliverables/selector.js +94 -0
- package/server/services/ai/deliverables/validator.js +63 -0
- package/server/services/ai/deliverables/workflows.js +195 -0
- package/server/services/ai/engine.js +259 -1
- package/server/services/ai/runEvents.js +100 -0
- package/server/services/ai/systemPrompt.js +6 -0
- package/server/services/ai/tools.js +1 -5
- package/server/services/manager.js +5 -56
- package/server/services/memory/manager.js +242 -26
- package/server/services/runtime/manager.js +2 -6
- package/server/services/runtime/settings.js +6 -12
- package/server/services/websocket.js +3 -1
- package/server/services/widgets/focus_widget.js +134 -0
- package/server/services/widgets/service.js +130 -2
- package/server/utils/deployment.js +4 -3
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
clampText,
|
|
5
|
+
normalizeDeliverableSelection,
|
|
6
|
+
} = require('./contracts');
|
|
7
|
+
const { listDeliverableWorkflows } = require('./workflows');
|
|
8
|
+
|
|
9
|
+
function buildDeliverableSelectorPrompt({ tools = [] }) {
|
|
10
|
+
const workflows = listDeliverableWorkflows().map((workflow) => ({
|
|
11
|
+
type: workflow.type,
|
|
12
|
+
displayName: workflow.displayName,
|
|
13
|
+
expectedOutputs: workflow.expectedOutputs,
|
|
14
|
+
}));
|
|
15
|
+
const toolNames = tools
|
|
16
|
+
.map((tool) => String(tool?.name || '').trim())
|
|
17
|
+
.filter(Boolean)
|
|
18
|
+
.slice(0, 40);
|
|
19
|
+
|
|
20
|
+
return [
|
|
21
|
+
'Return JSON only.',
|
|
22
|
+
'Classify whether this request should use a deliverable workflow.',
|
|
23
|
+
'Choose exactly one type from: slides, document, research_report, data_analysis, image, video.',
|
|
24
|
+
'Use status="selected" only when a concrete artifact-producing workflow clearly owns the primary outcome.',
|
|
25
|
+
'Use status="standard" when the request is conversational, operational, ambiguous, or not primarily about producing one of these deliverables.',
|
|
26
|
+
'Be conservative. If confidence is low, choose status="standard".',
|
|
27
|
+
'Schema:',
|
|
28
|
+
JSON.stringify({
|
|
29
|
+
status: 'selected',
|
|
30
|
+
type: 'document',
|
|
31
|
+
confidence: 0.82,
|
|
32
|
+
goal: 'Create a polished launch memo.',
|
|
33
|
+
requested_outputs: ['launch memo pdf'],
|
|
34
|
+
supporting_capabilities: ['web_search'],
|
|
35
|
+
}, null, 2),
|
|
36
|
+
`Available workflows:\n${JSON.stringify(workflows, null, 2)}`,
|
|
37
|
+
toolNames.length ? `Available tools/capabilities: ${toolNames.join(', ')}` : '',
|
|
38
|
+
].filter(Boolean).join('\n\n');
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
async function selectDeliverableWorkflow({
|
|
42
|
+
engine,
|
|
43
|
+
provider,
|
|
44
|
+
providerName,
|
|
45
|
+
model,
|
|
46
|
+
messages,
|
|
47
|
+
tools = [],
|
|
48
|
+
options = {},
|
|
49
|
+
}) {
|
|
50
|
+
const response = await engine.requestStructuredJson({
|
|
51
|
+
provider,
|
|
52
|
+
providerName,
|
|
53
|
+
model,
|
|
54
|
+
messages,
|
|
55
|
+
prompt: buildDeliverableSelectorPrompt({ tools }),
|
|
56
|
+
maxTokens: 600,
|
|
57
|
+
normalize: normalizeDeliverableSelection,
|
|
58
|
+
fallback: { status: 'standard', confidence: 0 },
|
|
59
|
+
reasoningEffort: engine.getReasoningEffort(providerName, options),
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
const selection = normalizeDeliverableSelection(response.value);
|
|
63
|
+
if (
|
|
64
|
+
selection.status !== 'selected'
|
|
65
|
+
|| !selection.type
|
|
66
|
+
|| Number(selection.confidence || 0) < 0.7
|
|
67
|
+
) {
|
|
68
|
+
return {
|
|
69
|
+
selection: {
|
|
70
|
+
status: 'standard',
|
|
71
|
+
type: null,
|
|
72
|
+
confidence: Number(selection.confidence || 0),
|
|
73
|
+
goal: '',
|
|
74
|
+
requestedOutputs: [],
|
|
75
|
+
supportingCapabilities: [],
|
|
76
|
+
},
|
|
77
|
+
usage: response.usage,
|
|
78
|
+
raw: response.raw,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
selection: {
|
|
84
|
+
...selection,
|
|
85
|
+
goal: clampText(selection.goal, 240),
|
|
86
|
+
},
|
|
87
|
+
usage: response.usage,
|
|
88
|
+
raw: response.raw,
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
module.exports = {
|
|
93
|
+
selectDeliverableWorkflow,
|
|
94
|
+
};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
normalizeDeliverableResult,
|
|
5
|
+
normalizeDeliverableValidationResult,
|
|
6
|
+
} = require('./contracts');
|
|
7
|
+
|
|
8
|
+
class DeliverableValidationError extends Error {
|
|
9
|
+
constructor(message, details = {}) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.name = 'DeliverableValidationError';
|
|
12
|
+
this.deliverableValidation = details.validation || null;
|
|
13
|
+
this.deliverableResult = details.result || null;
|
|
14
|
+
this.disableAutonomousRetry = true;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
async function validateDeliverableExecution({
|
|
19
|
+
workflow,
|
|
20
|
+
request,
|
|
21
|
+
plan,
|
|
22
|
+
finalReply,
|
|
23
|
+
artifacts,
|
|
24
|
+
toolExecutions,
|
|
25
|
+
runId,
|
|
26
|
+
}) {
|
|
27
|
+
const validation = normalizeDeliverableValidationResult(
|
|
28
|
+
await workflow.validate({
|
|
29
|
+
request,
|
|
30
|
+
plan,
|
|
31
|
+
finalReply,
|
|
32
|
+
artifacts,
|
|
33
|
+
toolExecutions,
|
|
34
|
+
runId,
|
|
35
|
+
}),
|
|
36
|
+
);
|
|
37
|
+
const result = normalizeDeliverableResult({
|
|
38
|
+
type: workflow.type,
|
|
39
|
+
status: validation.status === 'passed' ? 'completed' : 'failed',
|
|
40
|
+
summary: workflow.summarize({
|
|
41
|
+
request,
|
|
42
|
+
plan,
|
|
43
|
+
finalReply,
|
|
44
|
+
artifacts: validation.artifacts,
|
|
45
|
+
validation,
|
|
46
|
+
toolExecutions,
|
|
47
|
+
runId,
|
|
48
|
+
}),
|
|
49
|
+
artifacts: validation.artifacts,
|
|
50
|
+
validation,
|
|
51
|
+
metadata: {
|
|
52
|
+
requestedOutputs: request?.requestedOutputs || [],
|
|
53
|
+
supportingCapabilities: request?.supportingCapabilities || [],
|
|
54
|
+
preferredTools: plan?.preferredTools || [],
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
return { validation, result };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
module.exports = {
|
|
61
|
+
DeliverableValidationError,
|
|
62
|
+
validateDeliverableExecution,
|
|
63
|
+
};
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { clampText, normalizeArtifactContract } = require('./contracts');
|
|
4
|
+
|
|
5
|
+
function cloneWorkflow(workflow) {
|
|
6
|
+
if (!workflow) return null;
|
|
7
|
+
return {
|
|
8
|
+
...workflow,
|
|
9
|
+
preferredTools: Array.isArray(workflow.preferredTools) ? [...workflow.preferredTools] : [],
|
|
10
|
+
expectedOutputs: Array.isArray(workflow.expectedOutputs) ? [...workflow.expectedOutputs] : [],
|
|
11
|
+
expectedArtifactKinds: Array.isArray(workflow.expectedArtifactKinds) ? [...workflow.expectedArtifactKinds] : [],
|
|
12
|
+
expectedExtensions: Array.isArray(workflow.expectedExtensions) ? [...workflow.expectedExtensions] : [],
|
|
13
|
+
summaryHints: Array.isArray(workflow.summaryHints) ? [...workflow.summaryHints] : [],
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function createWorkflow(config) {
|
|
18
|
+
const workflow = {
|
|
19
|
+
type: config.type,
|
|
20
|
+
displayName: config.displayName,
|
|
21
|
+
preferredTools: Array.isArray(config.preferredTools) ? [...config.preferredTools] : [],
|
|
22
|
+
expectedOutputs: Array.isArray(config.expectedOutputs) ? [...config.expectedOutputs] : [],
|
|
23
|
+
expectedArtifactKinds: Array.isArray(config.expectedArtifactKinds) ? [...config.expectedArtifactKinds] : [],
|
|
24
|
+
expectedExtensions: Array.isArray(config.expectedExtensions) ? [...config.expectedExtensions] : [],
|
|
25
|
+
summaryHints: Array.isArray(config.summaryHints) ? [...config.summaryHints] : [],
|
|
26
|
+
canHandle(request) {
|
|
27
|
+
return request?.type === config.type;
|
|
28
|
+
},
|
|
29
|
+
normalizeRequest(input = {}) {
|
|
30
|
+
return {
|
|
31
|
+
type: config.type,
|
|
32
|
+
goal: clampText(input.goal || input.userMessage, 240),
|
|
33
|
+
requestedOutputs: Array.isArray(input.requestedOutputs) ? input.requestedOutputs.map((item) => clampText(item, 120)).filter(Boolean) : [],
|
|
34
|
+
supportingCapabilities: Array.isArray(input.supportingCapabilities) ? input.supportingCapabilities.map((item) => clampText(item, 64)).filter(Boolean) : [],
|
|
35
|
+
};
|
|
36
|
+
},
|
|
37
|
+
buildExecutionPlan(request) {
|
|
38
|
+
return {
|
|
39
|
+
type: config.type,
|
|
40
|
+
displayName: config.displayName,
|
|
41
|
+
goal: request.goal,
|
|
42
|
+
requestedOutputs: request.requestedOutputs,
|
|
43
|
+
supportingCapabilities: request.supportingCapabilities,
|
|
44
|
+
preferredTools: [...this.preferredTools],
|
|
45
|
+
expectedOutputs: [...this.expectedOutputs],
|
|
46
|
+
validationRules: [
|
|
47
|
+
`Produce deliverable artifacts of type "${config.type}" before finishing.`,
|
|
48
|
+
'Mention output files or artifact links explicitly in the final response when available.',
|
|
49
|
+
'Do not report success until the expected deliverable exists and can be summarized concretely.',
|
|
50
|
+
],
|
|
51
|
+
};
|
|
52
|
+
},
|
|
53
|
+
async run(plan) {
|
|
54
|
+
return plan;
|
|
55
|
+
},
|
|
56
|
+
validate({ artifacts = [], finalReply = '', toolExecutions = [] }) {
|
|
57
|
+
const artifactList = Array.isArray(artifacts)
|
|
58
|
+
? artifacts.map(normalizeArtifactContract).filter((artifact) => artifact.path || artifact.uri)
|
|
59
|
+
: [];
|
|
60
|
+
const matchedArtifacts = artifactList.filter((artifact) => {
|
|
61
|
+
if (this.expectedArtifactKinds.includes(artifact.kind)) return true;
|
|
62
|
+
const candidate = (artifact.path || artifact.uri || '').toLowerCase();
|
|
63
|
+
return this.expectedExtensions.some((extension) => candidate.endsWith(extension));
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const errors = [];
|
|
67
|
+
const warnings = [];
|
|
68
|
+
if (matchedArtifacts.length === 0) {
|
|
69
|
+
errors.push(`No ${this.displayName.toLowerCase()} artifact was detected.`);
|
|
70
|
+
}
|
|
71
|
+
const trimmedReply = String(finalReply || '').trim();
|
|
72
|
+
if (!trimmedReply) {
|
|
73
|
+
errors.push('Final response is empty.');
|
|
74
|
+
}
|
|
75
|
+
if (!errors.length && trimmedReply.length < 24) {
|
|
76
|
+
warnings.push('Final response is extremely short for a deliverable run.');
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
status: errors.length > 0 ? 'failed' : 'passed',
|
|
81
|
+
summary: errors.length > 0
|
|
82
|
+
? `${this.displayName} validation failed: ${errors[0]}`
|
|
83
|
+
: `${this.displayName} deliverable validated.`,
|
|
84
|
+
errors,
|
|
85
|
+
warnings,
|
|
86
|
+
artifacts: matchedArtifacts,
|
|
87
|
+
metrics: {
|
|
88
|
+
artifactCount: matchedArtifacts.length,
|
|
89
|
+
toolExecutionCount: Array.isArray(toolExecutions) ? toolExecutions.length : 0,
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
},
|
|
93
|
+
summarize({ artifacts = [], validation, finalReply = '' }) {
|
|
94
|
+
const artifactSummary = artifacts.length > 0
|
|
95
|
+
? artifacts.map((artifact) => artifact.label || artifact.path || artifact.uri).filter(Boolean).slice(0, 4).join(', ')
|
|
96
|
+
: 'no artifacts captured';
|
|
97
|
+
return clampText(
|
|
98
|
+
validation?.status === 'passed'
|
|
99
|
+
? `${this.displayName} delivered: ${artifactSummary}.`
|
|
100
|
+
: `${this.displayName} validation failed: ${validation?.errors?.[0] || 'unknown validation error'}.`,
|
|
101
|
+
320,
|
|
102
|
+
);
|
|
103
|
+
},
|
|
104
|
+
};
|
|
105
|
+
workflow.baseValidate = workflow.validate;
|
|
106
|
+
return workflow;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
const WORKFLOWS = [
|
|
110
|
+
createWorkflow({
|
|
111
|
+
type: 'slides',
|
|
112
|
+
displayName: 'Slides',
|
|
113
|
+
preferredTools: ['write_file', 'edit_file', 'execute_command', 'browser_screenshot', 'generate_image'],
|
|
114
|
+
expectedOutputs: ['presentation deck', 'exported slide file', 'visual proof'],
|
|
115
|
+
expectedArtifactKinds: ['slides', 'document', 'image'],
|
|
116
|
+
expectedExtensions: ['.ppt', '.pptx', '.pdf', '.html', '.png', '.jpg', '.jpeg'],
|
|
117
|
+
}),
|
|
118
|
+
createWorkflow({
|
|
119
|
+
type: 'document',
|
|
120
|
+
displayName: 'Document',
|
|
121
|
+
preferredTools: ['write_file', 'edit_file', 'execute_command', 'browser_screenshot'],
|
|
122
|
+
expectedOutputs: ['document file', 'rendered export'],
|
|
123
|
+
expectedArtifactKinds: ['document'],
|
|
124
|
+
expectedExtensions: ['.pdf', '.doc', '.docx', '.md', '.txt', '.html', '.htm'],
|
|
125
|
+
}),
|
|
126
|
+
createWorkflow({
|
|
127
|
+
type: 'research_report',
|
|
128
|
+
displayName: 'Research report',
|
|
129
|
+
preferredTools: ['web_search', 'http_request', 'write_file', 'edit_file'],
|
|
130
|
+
expectedOutputs: ['research report', 'citations or source-backed artifact'],
|
|
131
|
+
expectedArtifactKinds: ['document'],
|
|
132
|
+
expectedExtensions: ['.pdf', '.doc', '.docx', '.md', '.txt', '.html', '.htm'],
|
|
133
|
+
validate(payload) {
|
|
134
|
+
const base = this.baseValidate(payload);
|
|
135
|
+
const reply = String(payload.finalReply || '');
|
|
136
|
+
const hasCitation = /(https?:\/\/|source:|sources:|references?:|\[\d+\])/i.test(reply);
|
|
137
|
+
if (!hasCitation && base.artifacts.length === 0) {
|
|
138
|
+
base.errors.push('No citation or report artifact was detected.');
|
|
139
|
+
base.status = 'failed';
|
|
140
|
+
base.summary = 'Research report validation failed: no citation or report artifact was detected.';
|
|
141
|
+
}
|
|
142
|
+
return base;
|
|
143
|
+
},
|
|
144
|
+
}),
|
|
145
|
+
createWorkflow({
|
|
146
|
+
type: 'data_analysis',
|
|
147
|
+
displayName: 'Data analysis',
|
|
148
|
+
preferredTools: ['execute_command', 'write_file', 'edit_file', 'browser_screenshot'],
|
|
149
|
+
expectedOutputs: ['analysis artifact', 'chart or data export'],
|
|
150
|
+
expectedArtifactKinds: ['data', 'image', 'document'],
|
|
151
|
+
expectedExtensions: ['.csv', '.tsv', '.xlsx', '.xls', '.json', '.png', '.jpg', '.jpeg', '.svg', '.pdf', '.html'],
|
|
152
|
+
}),
|
|
153
|
+
createWorkflow({
|
|
154
|
+
type: 'image',
|
|
155
|
+
displayName: 'Image',
|
|
156
|
+
preferredTools: ['generate_image', 'write_file', 'edit_file'],
|
|
157
|
+
expectedOutputs: ['generated or edited image'],
|
|
158
|
+
expectedArtifactKinds: ['image'],
|
|
159
|
+
expectedExtensions: ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg'],
|
|
160
|
+
}),
|
|
161
|
+
createWorkflow({
|
|
162
|
+
type: 'video',
|
|
163
|
+
displayName: 'Video',
|
|
164
|
+
preferredTools: ['execute_command', 'write_file', 'edit_file'],
|
|
165
|
+
expectedOutputs: ['rendered video asset'],
|
|
166
|
+
expectedArtifactKinds: ['video'],
|
|
167
|
+
expectedExtensions: ['.mp4', '.mov', '.m4v', '.webm'],
|
|
168
|
+
}),
|
|
169
|
+
];
|
|
170
|
+
|
|
171
|
+
function listDeliverableWorkflows() {
|
|
172
|
+
return WORKFLOWS.map(cloneWorkflow);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function getDeliverableWorkflow(type) {
|
|
176
|
+
return cloneWorkflow(WORKFLOWS.find((workflow) => workflow.type === type) || null);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
function buildDeliverableWorkflowGuidance(plan) {
|
|
180
|
+
if (!plan) return '';
|
|
181
|
+
return [
|
|
182
|
+
`[Deliverable workflow: ${plan.displayName}]`,
|
|
183
|
+
plan.goal ? `Deliverable goal: ${plan.goal}` : '',
|
|
184
|
+
plan.requestedOutputs?.length ? `Requested outputs: ${plan.requestedOutputs.join(', ')}` : '',
|
|
185
|
+
plan.preferredTools?.length ? `Preferred tools/capabilities: ${plan.preferredTools.join(', ')}` : '',
|
|
186
|
+
plan.expectedOutputs?.length ? `Expected artifacts: ${plan.expectedOutputs.join(', ')}` : '',
|
|
187
|
+
'Before finishing, ensure the final deliverable exists, validate it, and summarize the produced artifacts clearly.',
|
|
188
|
+
].filter(Boolean).join('\n');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
module.exports = {
|
|
192
|
+
buildDeliverableWorkflowGuidance,
|
|
193
|
+
getDeliverableWorkflow,
|
|
194
|
+
listDeliverableWorkflows,
|
|
195
|
+
};
|