agent-planner-mcp 1.5.10 → 1.5.12
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/package.json +1 -1
- package/src/tools/bdi/desires.js +17 -8
- package/src/tools/bdi/intentions.js +26 -6
package/package.json
CHANGED
package/src/tools/bdi/desires.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* directly — no UI round-trip and no forced approval gate.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
const { asOf, formatResponse, errorResponse, safeArray } = require('./_shared');
|
|
10
|
+
const { asOf, formatResponse, errorResponse, safeArray, apiErrorMessage } = require('./_shared');
|
|
11
11
|
|
|
12
12
|
const listGoalsDefinition = {
|
|
13
13
|
name: 'list_goals',
|
|
@@ -110,11 +110,20 @@ async function updateGoalHandler(args, apiClient) {
|
|
|
110
110
|
const applied = [];
|
|
111
111
|
const failures = [];
|
|
112
112
|
|
|
113
|
-
// Direct field updates
|
|
113
|
+
// Direct field updates. title/description/priority/status share their name
|
|
114
|
+
// with the backend, but success_criteria must be camelCased to successCriteria
|
|
115
|
+
// — the goal update schema is .strict(), so the snake_case key was rejected
|
|
116
|
+
// with a 400 (the one multi-word field, hence "description writes but
|
|
117
|
+
// success_criteria fails"). Match the create shape: wrap a bare array as
|
|
118
|
+
// { criteria: [...] }.
|
|
114
119
|
const directFields = {};
|
|
115
|
-
for (const k of ['title', 'description', 'priority', 'status'
|
|
120
|
+
for (const k of ['title', 'description', 'priority', 'status']) {
|
|
116
121
|
if (changes[k] !== undefined) directFields[k] = changes[k];
|
|
117
122
|
}
|
|
123
|
+
if (changes.success_criteria !== undefined) {
|
|
124
|
+
const sc = changes.success_criteria;
|
|
125
|
+
directFields.successCriteria = Array.isArray(sc) ? { criteria: sc } : sc;
|
|
126
|
+
}
|
|
118
127
|
// Map the public `committed` boolean onto the backend's commitment write
|
|
119
128
|
// (the API still accepts the legacy goalType field and translates it to
|
|
120
129
|
// promoted_at). committed:true ⇒ promoted, false ⇒ aspirational.
|
|
@@ -127,21 +136,21 @@ async function updateGoalHandler(args, apiClient) {
|
|
|
127
136
|
await apiClient.goals.update(goal_id, directFields);
|
|
128
137
|
applied.push('direct_fields');
|
|
129
138
|
} catch (err) {
|
|
130
|
-
failures.push({ step: 'direct_fields', error: err
|
|
139
|
+
failures.push({ step: 'direct_fields', error: apiErrorMessage(err) });
|
|
131
140
|
}
|
|
132
141
|
}
|
|
133
142
|
|
|
134
143
|
for (const planId of safeArray(changes.add_linked_plans)) {
|
|
135
144
|
try { await apiClient.goals.linkPlan(goal_id, planId); applied.push(`link_plan:${planId}`); }
|
|
136
|
-
catch (err) { failures.push({ step: `link_plan:${planId}`, error: err
|
|
145
|
+
catch (err) { failures.push({ step: `link_plan:${planId}`, error: apiErrorMessage(err) }); }
|
|
137
146
|
}
|
|
138
147
|
for (const planId of safeArray(changes.remove_linked_plans)) {
|
|
139
148
|
try { await apiClient.goals.unlinkPlan(goal_id, planId); applied.push(`unlink_plan:${planId}`); }
|
|
140
|
-
catch (err) { failures.push({ step: `unlink_plan:${planId}`, error: err
|
|
149
|
+
catch (err) { failures.push({ step: `unlink_plan:${planId}`, error: apiErrorMessage(err) }); }
|
|
141
150
|
}
|
|
142
151
|
for (const nodeId of safeArray(changes.add_achievers)) {
|
|
143
152
|
try { await apiClient.goals.addAchiever(goal_id, nodeId); applied.push(`add_achiever:${nodeId}`); }
|
|
144
|
-
catch (err) { failures.push({ step: `add_achiever:${nodeId}`, error: err
|
|
153
|
+
catch (err) { failures.push({ step: `add_achiever:${nodeId}`, error: apiErrorMessage(err) }); }
|
|
145
154
|
}
|
|
146
155
|
for (const nodeId of safeArray(changes.remove_achievers)) {
|
|
147
156
|
try {
|
|
@@ -152,7 +161,7 @@ async function updateGoalHandler(args, apiClient) {
|
|
|
152
161
|
applied.push(`remove_achiever:${nodeId}`);
|
|
153
162
|
}
|
|
154
163
|
} catch (err) {
|
|
155
|
-
failures.push({ step: `remove_achiever:${nodeId}`, error: err
|
|
164
|
+
failures.push({ step: `remove_achiever:${nodeId}`, error: apiErrorMessage(err) });
|
|
156
165
|
}
|
|
157
166
|
}
|
|
158
167
|
|
|
@@ -229,15 +229,21 @@ async function resolveDecisionHandler(args, apiClient) {
|
|
|
229
229
|
if (action === 'approve' && decision?.metadata?.proposed_subtasks?.length) {
|
|
230
230
|
for (const proposal of decision.metadata.proposed_subtasks) {
|
|
231
231
|
try {
|
|
232
|
+
// createNode's schema is .strict() and has no acceptance_criteria field —
|
|
233
|
+
// sending it 400s the whole subtask. Fold it into the description so the
|
|
234
|
+
// criteria survive instead of being silently dropped on approval.
|
|
235
|
+
const description = [
|
|
236
|
+
proposal.description,
|
|
237
|
+
proposal.acceptance_criteria ? `Acceptance criteria: ${proposal.acceptance_criteria}` : null,
|
|
238
|
+
].filter(Boolean).join('\n\n') || undefined;
|
|
232
239
|
const node = await apiClient.nodes.createNode(plan_id, {
|
|
233
240
|
parent_id: proposal.parent_id,
|
|
234
241
|
node_type: proposal.node_type || 'task',
|
|
235
242
|
title: proposal.title,
|
|
236
|
-
description
|
|
243
|
+
description,
|
|
237
244
|
status: 'not_started',
|
|
238
245
|
task_mode: proposal.task_mode || 'free',
|
|
239
246
|
agent_instructions: proposal.agent_instructions,
|
|
240
|
-
acceptance_criteria: proposal.acceptance_criteria,
|
|
241
247
|
});
|
|
242
248
|
created.push({ id: node.id || node.node?.id, title: proposal.title, parent_id: proposal.parent_id });
|
|
243
249
|
} catch (err) {
|
|
@@ -274,6 +280,12 @@ const STATUS_TO_LOG_TYPE = {
|
|
|
274
280
|
plan_ready: 'progress',
|
|
275
281
|
};
|
|
276
282
|
|
|
283
|
+
// The backend log endpoint accepts comment/progress/reasoning/decision/challenge.
|
|
284
|
+
// Two friendly aliases the tool historically advertised are NOT valid there and
|
|
285
|
+
// 400'd the log step — map them to the closest valid type.
|
|
286
|
+
const LOG_TYPE_ALIASES = { blocker: 'challenge', completion: 'progress' };
|
|
287
|
+
const normalizeLogType = (lt) => (lt ? (LOG_TYPE_ALIASES[lt] || lt) : lt);
|
|
288
|
+
|
|
277
289
|
const updateTaskDefinition = {
|
|
278
290
|
name: 'update_task',
|
|
279
291
|
description:
|
|
@@ -295,8 +307,9 @@ const updateTaskDefinition = {
|
|
|
295
307
|
log_message: { type: 'string', description: 'Optional progress note' },
|
|
296
308
|
log_type: {
|
|
297
309
|
type: 'string',
|
|
298
|
-
enum: ['progress', '
|
|
299
|
-
description: "Defaults from status: blocked→challenge, others→progress."
|
|
310
|
+
enum: ['progress', 'reasoning', 'decision', 'challenge', 'comment'],
|
|
311
|
+
description: "Defaults from status: blocked→challenge, others→progress. "
|
|
312
|
+
+ "Legacy 'blocker'/'completion' are accepted and mapped to challenge/progress.",
|
|
300
313
|
},
|
|
301
314
|
release_claim: {
|
|
302
315
|
type: 'boolean',
|
|
@@ -344,7 +357,7 @@ async function updateTaskHandler(args, apiClient) {
|
|
|
344
357
|
const data = await apiClient.v1.updateTask(task_id, {
|
|
345
358
|
status,
|
|
346
359
|
log_message,
|
|
347
|
-
log_type: args.log_type,
|
|
360
|
+
log_type: normalizeLogType(args.log_type),
|
|
348
361
|
release_claim,
|
|
349
362
|
add_learning,
|
|
350
363
|
});
|
|
@@ -390,7 +403,7 @@ async function updateTaskHandler(args, apiClient) {
|
|
|
390
403
|
|
|
391
404
|
// 2. Log entry
|
|
392
405
|
if (log_message) {
|
|
393
|
-
const logType = args.log_type || STATUS_TO_LOG_TYPE[status] || 'progress';
|
|
406
|
+
const logType = normalizeLogType(args.log_type) || STATUS_TO_LOG_TYPE[status] || 'progress';
|
|
394
407
|
try {
|
|
395
408
|
const log = await apiClient.logs.addLogEntry(planId, task_id, {
|
|
396
409
|
content: log_message,
|
|
@@ -718,6 +731,13 @@ async function addLearningHandler(args, apiClient) {
|
|
|
718
731
|
plan_id: scope.plan_id,
|
|
719
732
|
node_id: scope.node_id,
|
|
720
733
|
entity_type: entry_type,
|
|
734
|
+
// The episodes endpoint only persists {content,name,plan_id,node_id,metadata};
|
|
735
|
+
// the top-level entry_type/source_description were silently dropped. Carry
|
|
736
|
+
// the categorization in metadata so it survives on the stored episode.
|
|
737
|
+
metadata: {
|
|
738
|
+
entry_type,
|
|
739
|
+
source_description: source_description || 'BDI add_learning',
|
|
740
|
+
},
|
|
721
741
|
});
|
|
722
742
|
return formatResponse({
|
|
723
743
|
as_of: asOf(),
|