@weavelogic/knowledge-graph-agent 0.3.0 → 0.4.0
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/README.md +290 -3
- package/dist/_virtual/index10.js +2 -2
- package/dist/_virtual/index6.js +2 -2
- package/dist/_virtual/index7.js +2 -2
- package/dist/_virtual/index8.js +2 -2
- package/dist/_virtual/index9.js +2 -2
- package/dist/audit/config.d.ts +150 -0
- package/dist/audit/config.d.ts.map +1 -0
- package/dist/audit/config.js +111 -0
- package/dist/audit/config.js.map +1 -0
- package/dist/audit/index.d.ts +38 -0
- package/dist/audit/index.d.ts.map +1 -0
- package/dist/audit/services/audit-chain.d.ts +276 -0
- package/dist/audit/services/audit-chain.d.ts.map +1 -0
- package/dist/audit/services/audit-chain.js +502 -0
- package/dist/audit/services/audit-chain.js.map +1 -0
- package/dist/audit/services/index.d.ts +11 -0
- package/dist/audit/services/index.d.ts.map +1 -0
- package/dist/audit/services/syndication.d.ts +334 -0
- package/dist/audit/services/syndication.d.ts.map +1 -0
- package/dist/audit/services/syndication.js +589 -0
- package/dist/audit/services/syndication.js.map +1 -0
- package/dist/audit/types.d.ts +453 -0
- package/dist/audit/types.d.ts.map +1 -0
- package/dist/cli/commands/audit.d.ts +21 -0
- package/dist/cli/commands/audit.d.ts.map +1 -0
- package/dist/cli/commands/audit.js +621 -0
- package/dist/cli/commands/audit.js.map +1 -0
- package/dist/cli/commands/vector.d.ts +14 -0
- package/dist/cli/commands/vector.d.ts.map +1 -0
- package/dist/cli/commands/vector.js +429 -0
- package/dist/cli/commands/vector.js.map +1 -0
- package/dist/cli/commands/workflow.d.ts +12 -0
- package/dist/cli/commands/workflow.d.ts.map +1 -0
- package/dist/cli/commands/workflow.js +471 -0
- package/dist/cli/commands/workflow.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +26 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/database/schemas/index.d.ts +85 -0
- package/dist/database/schemas/index.d.ts.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/tools/audit/checkpoint.d.ts +58 -0
- package/dist/mcp-server/tools/audit/checkpoint.d.ts.map +1 -0
- package/dist/mcp-server/tools/audit/checkpoint.js +73 -0
- package/dist/mcp-server/tools/audit/checkpoint.js.map +1 -0
- package/dist/mcp-server/tools/audit/index.d.ts +53 -0
- package/dist/mcp-server/tools/audit/index.d.ts.map +1 -0
- package/dist/mcp-server/tools/audit/index.js +12 -0
- package/dist/mcp-server/tools/audit/index.js.map +1 -0
- package/dist/mcp-server/tools/audit/query.d.ts +58 -0
- package/dist/mcp-server/tools/audit/query.d.ts.map +1 -0
- package/dist/mcp-server/tools/audit/query.js +125 -0
- package/dist/mcp-server/tools/audit/query.js.map +1 -0
- package/dist/mcp-server/tools/audit/sync.d.ts +58 -0
- package/dist/mcp-server/tools/audit/sync.d.ts.map +1 -0
- package/dist/mcp-server/tools/audit/sync.js +126 -0
- package/dist/mcp-server/tools/audit/sync.js.map +1 -0
- package/dist/mcp-server/tools/index.d.ts +3 -0
- package/dist/mcp-server/tools/index.d.ts.map +1 -1
- package/dist/mcp-server/tools/registry.js +90 -0
- package/dist/mcp-server/tools/registry.js.map +1 -1
- package/dist/mcp-server/tools/vector/index.d.ts +12 -0
- package/dist/mcp-server/tools/vector/index.d.ts.map +1 -0
- package/dist/mcp-server/tools/vector/index.js +12 -0
- package/dist/mcp-server/tools/vector/index.js.map +1 -0
- package/dist/mcp-server/tools/vector/search.d.ts +41 -0
- package/dist/mcp-server/tools/vector/search.d.ts.map +1 -0
- package/dist/mcp-server/tools/vector/search.js +224 -0
- package/dist/mcp-server/tools/vector/search.js.map +1 -0
- package/dist/mcp-server/tools/vector/trajectory.d.ts +39 -0
- package/dist/mcp-server/tools/vector/trajectory.d.ts.map +1 -0
- package/dist/mcp-server/tools/vector/trajectory.js +170 -0
- package/dist/mcp-server/tools/vector/trajectory.js.map +1 -0
- package/dist/mcp-server/tools/vector/upsert.d.ts +44 -0
- package/dist/mcp-server/tools/vector/upsert.d.ts.map +1 -0
- package/dist/mcp-server/tools/vector/upsert.js +175 -0
- package/dist/mcp-server/tools/vector/upsert.js.map +1 -0
- package/dist/mcp-server/tools/workflow/index.d.ts +29 -0
- package/dist/mcp-server/tools/workflow/index.d.ts.map +1 -0
- package/dist/mcp-server/tools/workflow/index.js +12 -0
- package/dist/mcp-server/tools/workflow/index.js.map +1 -0
- package/dist/mcp-server/tools/workflow/list.d.ts +41 -0
- package/dist/mcp-server/tools/workflow/list.d.ts.map +1 -0
- package/dist/mcp-server/tools/workflow/list.js +195 -0
- package/dist/mcp-server/tools/workflow/list.js.map +1 -0
- package/dist/mcp-server/tools/workflow/start.d.ts +40 -0
- package/dist/mcp-server/tools/workflow/start.d.ts.map +1 -0
- package/dist/mcp-server/tools/workflow/start.js +165 -0
- package/dist/mcp-server/tools/workflow/start.js.map +1 -0
- package/dist/mcp-server/tools/workflow/status.d.ts +38 -0
- package/dist/mcp-server/tools/workflow/status.d.ts.map +1 -0
- package/dist/mcp-server/tools/workflow/status.js +97 -0
- package/dist/mcp-server/tools/workflow/status.js.map +1 -0
- package/dist/node_modules/ajv/dist/compile/index.js +1 -1
- package/dist/node_modules/ajv/dist/vocabularies/applicator/index.js +1 -1
- package/dist/node_modules/ajv/dist/vocabularies/core/index.js +1 -1
- package/dist/node_modules/ajv/dist/vocabularies/format/index.js +1 -1
- package/dist/node_modules/ajv/dist/vocabularies/validation/index.js +1 -1
- package/dist/vector/config.d.ts +300 -0
- package/dist/vector/config.d.ts.map +1 -0
- package/dist/vector/config.js +124 -0
- package/dist/vector/config.js.map +1 -0
- package/dist/vector/index.d.ts +50 -0
- package/dist/vector/index.d.ts.map +1 -0
- package/dist/vector/services/index.d.ts +13 -0
- package/dist/vector/services/index.d.ts.map +1 -0
- package/dist/vector/services/trajectory-tracker.d.ts +405 -0
- package/dist/vector/services/trajectory-tracker.d.ts.map +1 -0
- package/dist/vector/services/trajectory-tracker.js +445 -0
- package/dist/vector/services/trajectory-tracker.js.map +1 -0
- package/dist/vector/services/vector-store.d.ts +339 -0
- package/dist/vector/services/vector-store.d.ts.map +1 -0
- package/dist/vector/services/vector-store.js +748 -0
- package/dist/vector/services/vector-store.js.map +1 -0
- package/dist/vector/types.d.ts +677 -0
- package/dist/vector/types.d.ts.map +1 -0
- package/dist/workflow/adapters/goap-adapter.d.ts +196 -0
- package/dist/workflow/adapters/goap-adapter.d.ts.map +1 -0
- package/dist/workflow/adapters/goap-adapter.js +706 -0
- package/dist/workflow/adapters/goap-adapter.js.map +1 -0
- package/dist/workflow/adapters/index.d.ts +10 -0
- package/dist/workflow/adapters/index.d.ts.map +1 -0
- package/dist/workflow/config.d.ts +135 -0
- package/dist/workflow/config.d.ts.map +1 -0
- package/dist/workflow/config.js +92 -0
- package/dist/workflow/config.js.map +1 -0
- package/dist/workflow/handlers/index.d.ts +9 -0
- package/dist/workflow/handlers/index.d.ts.map +1 -0
- package/dist/workflow/handlers/webhook-handlers.d.ts +397 -0
- package/dist/workflow/handlers/webhook-handlers.d.ts.map +1 -0
- package/dist/workflow/handlers/webhook-handlers.js +454 -0
- package/dist/workflow/handlers/webhook-handlers.js.map +1 -0
- package/dist/workflow/index.d.ts +42 -0
- package/dist/workflow/index.d.ts.map +1 -0
- package/dist/workflow/services/index.d.ts +9 -0
- package/dist/workflow/services/index.d.ts.map +1 -0
- package/dist/workflow/services/workflow-service.d.ts +318 -0
- package/dist/workflow/services/workflow-service.d.ts.map +1 -0
- package/dist/workflow/services/workflow-service.js +577 -0
- package/dist/workflow/services/workflow-service.js.map +1 -0
- package/dist/workflow/types.d.ts +470 -0
- package/dist/workflow/types.d.ts.map +1 -0
- package/dist/workflow/workflows/realtime-collab.d.ts +245 -0
- package/dist/workflow/workflows/realtime-collab.d.ts.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,706 @@
|
|
|
1
|
+
import { createLogger } from "../../utils/logger.js";
|
|
2
|
+
const logger = createLogger("goap-adapter");
|
|
3
|
+
class PriorityQueue {
|
|
4
|
+
items = [];
|
|
5
|
+
/**
|
|
6
|
+
* Add an item to the queue with a priority
|
|
7
|
+
*
|
|
8
|
+
* @param item - The item to add
|
|
9
|
+
* @param priority - Priority value (lower = higher priority)
|
|
10
|
+
*/
|
|
11
|
+
enqueue(item, priority) {
|
|
12
|
+
this.items.push({ item, priority });
|
|
13
|
+
this.bubbleUp(this.items.length - 1);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Remove and return the highest priority item
|
|
17
|
+
*
|
|
18
|
+
* @returns The item with lowest priority value, or undefined if empty
|
|
19
|
+
*/
|
|
20
|
+
dequeue() {
|
|
21
|
+
if (this.items.length === 0) {
|
|
22
|
+
return void 0;
|
|
23
|
+
}
|
|
24
|
+
const result = this.items[0].item;
|
|
25
|
+
if (this.items.length === 1) {
|
|
26
|
+
this.items.pop();
|
|
27
|
+
} else {
|
|
28
|
+
this.items[0] = this.items.pop();
|
|
29
|
+
this.bubbleDown(0);
|
|
30
|
+
}
|
|
31
|
+
return result;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Check if the queue is empty
|
|
35
|
+
*/
|
|
36
|
+
isEmpty() {
|
|
37
|
+
return this.items.length === 0;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Get the current size of the queue
|
|
41
|
+
*/
|
|
42
|
+
size() {
|
|
43
|
+
return this.items.length;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Peek at the highest priority item without removing it
|
|
47
|
+
*/
|
|
48
|
+
peek() {
|
|
49
|
+
return this.items[0]?.item;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Clear all items from the queue
|
|
53
|
+
*/
|
|
54
|
+
clear() {
|
|
55
|
+
this.items = [];
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Bubble up an item to maintain heap property
|
|
59
|
+
*/
|
|
60
|
+
bubbleUp(index) {
|
|
61
|
+
while (index > 0) {
|
|
62
|
+
const parentIndex = Math.floor((index - 1) / 2);
|
|
63
|
+
if (this.items[parentIndex].priority <= this.items[index].priority) {
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
[this.items[parentIndex], this.items[index]] = [
|
|
67
|
+
this.items[index],
|
|
68
|
+
this.items[parentIndex]
|
|
69
|
+
];
|
|
70
|
+
index = parentIndex;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Bubble down an item to maintain heap property
|
|
75
|
+
*/
|
|
76
|
+
bubbleDown(index) {
|
|
77
|
+
const length = this.items.length;
|
|
78
|
+
while (true) {
|
|
79
|
+
const leftChild = 2 * index + 1;
|
|
80
|
+
const rightChild = 2 * index + 2;
|
|
81
|
+
let smallest = index;
|
|
82
|
+
if (leftChild < length && this.items[leftChild].priority < this.items[smallest].priority) {
|
|
83
|
+
smallest = leftChild;
|
|
84
|
+
}
|
|
85
|
+
if (rightChild < length && this.items[rightChild].priority < this.items[smallest].priority) {
|
|
86
|
+
smallest = rightChild;
|
|
87
|
+
}
|
|
88
|
+
if (smallest === index) {
|
|
89
|
+
break;
|
|
90
|
+
}
|
|
91
|
+
[this.items[index], this.items[smallest]] = [
|
|
92
|
+
this.items[smallest],
|
|
93
|
+
this.items[index]
|
|
94
|
+
];
|
|
95
|
+
index = smallest;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
class GOAPAdapter {
|
|
100
|
+
config;
|
|
101
|
+
actions = /* @__PURE__ */ new Map();
|
|
102
|
+
goals = /* @__PURE__ */ new Map();
|
|
103
|
+
planCache = /* @__PURE__ */ new Map();
|
|
104
|
+
customHeuristic;
|
|
105
|
+
constructor(config = {}) {
|
|
106
|
+
this.config = {
|
|
107
|
+
maxIterations: config.maxIterations ?? 1e3,
|
|
108
|
+
timeoutMs: config.timeoutMs ?? 3e4,
|
|
109
|
+
defaultCost: config.defaultCost ?? 1,
|
|
110
|
+
enableCaching: config.enableCaching ?? true,
|
|
111
|
+
maxPlanLength: config.maxPlanLength ?? 20
|
|
112
|
+
};
|
|
113
|
+
this.customHeuristic = config.heuristic;
|
|
114
|
+
this.registerDefaultActions();
|
|
115
|
+
if (config.actions) {
|
|
116
|
+
for (const action of config.actions) {
|
|
117
|
+
this.registerAction(action);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
this.registerDefaultGoals();
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Register default actions for documentation workflows
|
|
124
|
+
*/
|
|
125
|
+
registerDefaultActions() {
|
|
126
|
+
this.registerAction({
|
|
127
|
+
id: "analyze-spec",
|
|
128
|
+
name: "Analyze Specification",
|
|
129
|
+
description: "Analyze the specification document for completeness",
|
|
130
|
+
cost: 1,
|
|
131
|
+
preconditions: {
|
|
132
|
+
hasSpecification: true
|
|
133
|
+
},
|
|
134
|
+
effects: {
|
|
135
|
+
specCompleteness: 0.5
|
|
136
|
+
// Will be refined during execution
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
this.registerAction({
|
|
140
|
+
id: "generate-acceptance-criteria",
|
|
141
|
+
name: "Generate Acceptance Criteria",
|
|
142
|
+
description: "Generate acceptance criteria from specification",
|
|
143
|
+
cost: 2,
|
|
144
|
+
preconditions: {
|
|
145
|
+
hasSpecification: true,
|
|
146
|
+
specCompleteness: 0.5
|
|
147
|
+
},
|
|
148
|
+
effects: {
|
|
149
|
+
hasAcceptanceCriteria: true
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
this.registerAction({
|
|
153
|
+
id: "create-task",
|
|
154
|
+
name: "Create Task",
|
|
155
|
+
description: "Create a development task from the specification",
|
|
156
|
+
cost: 1,
|
|
157
|
+
preconditions: {
|
|
158
|
+
hasSpecification: true,
|
|
159
|
+
hasAcceptanceCriteria: true,
|
|
160
|
+
blockersFree: true
|
|
161
|
+
},
|
|
162
|
+
effects: {
|
|
163
|
+
taskDefined: true
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
this.registerAction({
|
|
167
|
+
id: "start-development",
|
|
168
|
+
name: "Start Development",
|
|
169
|
+
description: "Begin development work on the task",
|
|
170
|
+
cost: 3,
|
|
171
|
+
preconditions: {
|
|
172
|
+
taskDefined: true,
|
|
173
|
+
blockersFree: true
|
|
174
|
+
},
|
|
175
|
+
effects: {
|
|
176
|
+
developmentStarted: true
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
this.registerAction({
|
|
180
|
+
id: "fill-gaps",
|
|
181
|
+
name: "Fill Documentation Gaps",
|
|
182
|
+
description: "Generate content to fill documentation gaps",
|
|
183
|
+
cost: 2,
|
|
184
|
+
preconditions: {
|
|
185
|
+
hasSpecification: true
|
|
186
|
+
},
|
|
187
|
+
effects: {
|
|
188
|
+
specCompleteness: 0.8,
|
|
189
|
+
pendingGaps: []
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
this.registerAction({
|
|
193
|
+
id: "resolve-blockers",
|
|
194
|
+
name: "Resolve Blockers",
|
|
195
|
+
description: "Resolve blocking issues",
|
|
196
|
+
cost: 4,
|
|
197
|
+
preconditions: {
|
|
198
|
+
blockersFree: false
|
|
199
|
+
},
|
|
200
|
+
effects: {
|
|
201
|
+
blockersFree: true
|
|
202
|
+
}
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* Register default goals
|
|
207
|
+
*/
|
|
208
|
+
registerDefaultGoals() {
|
|
209
|
+
this.registerGoal({
|
|
210
|
+
id: "start-development",
|
|
211
|
+
name: "Start Development",
|
|
212
|
+
description: "Get the project ready to begin development",
|
|
213
|
+
conditions: {
|
|
214
|
+
taskDefined: true,
|
|
215
|
+
developmentStarted: true
|
|
216
|
+
},
|
|
217
|
+
priority: 10
|
|
218
|
+
});
|
|
219
|
+
this.registerGoal({
|
|
220
|
+
id: "complete-spec",
|
|
221
|
+
name: "Complete Specification",
|
|
222
|
+
description: "Ensure specification is complete with acceptance criteria",
|
|
223
|
+
conditions: {
|
|
224
|
+
hasSpecification: true,
|
|
225
|
+
specCompleteness: 0.8,
|
|
226
|
+
hasAcceptanceCriteria: true
|
|
227
|
+
},
|
|
228
|
+
priority: 8
|
|
229
|
+
});
|
|
230
|
+
this.registerGoal({
|
|
231
|
+
id: "resolve-blockers",
|
|
232
|
+
name: "Resolve All Blockers",
|
|
233
|
+
description: "Clear all blocking issues",
|
|
234
|
+
conditions: {
|
|
235
|
+
blockersFree: true
|
|
236
|
+
},
|
|
237
|
+
priority: 9
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Register an action
|
|
242
|
+
*
|
|
243
|
+
* @param action - Action definition to register
|
|
244
|
+
*/
|
|
245
|
+
registerAction(action) {
|
|
246
|
+
this.actions.set(action.id, action);
|
|
247
|
+
logger.debug("Registered action", { actionId: action.id });
|
|
248
|
+
}
|
|
249
|
+
/**
|
|
250
|
+
* Register a goal
|
|
251
|
+
*
|
|
252
|
+
* @param goal - Goal definition to register
|
|
253
|
+
*/
|
|
254
|
+
registerGoal(goal) {
|
|
255
|
+
this.goals.set(goal.id, goal);
|
|
256
|
+
logger.debug("Registered goal", { goalId: goal.id });
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* Get a registered action by ID
|
|
260
|
+
*
|
|
261
|
+
* @param actionId - Action identifier
|
|
262
|
+
* @returns Action definition or undefined
|
|
263
|
+
*/
|
|
264
|
+
getAction(actionId) {
|
|
265
|
+
return this.actions.get(actionId);
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Get a registered goal by ID
|
|
269
|
+
*
|
|
270
|
+
* @param goalId - Goal identifier
|
|
271
|
+
* @returns Goal definition or undefined
|
|
272
|
+
*/
|
|
273
|
+
getGoal(goalId) {
|
|
274
|
+
return this.goals.get(goalId);
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Get all registered actions
|
|
278
|
+
*
|
|
279
|
+
* @returns Array of action definitions
|
|
280
|
+
*/
|
|
281
|
+
getActions() {
|
|
282
|
+
return Array.from(this.actions.values());
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Get all registered goals
|
|
286
|
+
*
|
|
287
|
+
* @returns Array of goal definitions
|
|
288
|
+
*/
|
|
289
|
+
getGoals() {
|
|
290
|
+
return Array.from(this.goals.values());
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Create a plan to achieve a goal from the current state
|
|
294
|
+
*
|
|
295
|
+
* @param currentState - Current world state
|
|
296
|
+
* @param goalId - Goal to achieve
|
|
297
|
+
* @returns Plan to achieve the goal
|
|
298
|
+
*/
|
|
299
|
+
createPlan(currentState, goalId) {
|
|
300
|
+
const goal = this.goals.get(goalId);
|
|
301
|
+
if (!goal) {
|
|
302
|
+
return {
|
|
303
|
+
goalId,
|
|
304
|
+
actionIds: [],
|
|
305
|
+
totalCost: Infinity,
|
|
306
|
+
achievable: false,
|
|
307
|
+
reason: `Unknown goal: ${goalId}`,
|
|
308
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
const cacheKey = this.createCacheKey(currentState, goalId);
|
|
312
|
+
if (this.config.enableCaching && this.planCache.has(cacheKey)) {
|
|
313
|
+
const cached = this.planCache.get(cacheKey);
|
|
314
|
+
logger.debug("Using cached plan", { goalId, cacheKey });
|
|
315
|
+
return cached;
|
|
316
|
+
}
|
|
317
|
+
logger.debug("Creating plan", { goalId, currentState });
|
|
318
|
+
if (this.isGoalSatisfied(currentState, goal)) {
|
|
319
|
+
const plan2 = {
|
|
320
|
+
goalId,
|
|
321
|
+
actionIds: [],
|
|
322
|
+
totalCost: 0,
|
|
323
|
+
achievable: true,
|
|
324
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
325
|
+
};
|
|
326
|
+
this.cachePlan(cacheKey, plan2);
|
|
327
|
+
return plan2;
|
|
328
|
+
}
|
|
329
|
+
const plan = this.aStarSearch(currentState, goal);
|
|
330
|
+
this.cachePlan(cacheKey, plan);
|
|
331
|
+
return plan;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* A* search algorithm for plan finding
|
|
335
|
+
*
|
|
336
|
+
* Uses a binary heap priority queue for efficient O(log n) operations.
|
|
337
|
+
* Implements proper path reconstruction using parent node references.
|
|
338
|
+
*/
|
|
339
|
+
aStarSearch(startState, goal) {
|
|
340
|
+
const startTime = Date.now();
|
|
341
|
+
const openSet = new PriorityQueue();
|
|
342
|
+
const closedSet = /* @__PURE__ */ new Set();
|
|
343
|
+
const startHeuristic = this.heuristic(startState, goal);
|
|
344
|
+
const startNode = {
|
|
345
|
+
state: { ...startState },
|
|
346
|
+
gCost: 0,
|
|
347
|
+
hCost: startHeuristic,
|
|
348
|
+
fCost: startHeuristic,
|
|
349
|
+
parent: null,
|
|
350
|
+
action: null
|
|
351
|
+
};
|
|
352
|
+
openSet.enqueue(startNode, startNode.fCost);
|
|
353
|
+
let iterations = 0;
|
|
354
|
+
let nodesExplored = 0;
|
|
355
|
+
while (!openSet.isEmpty() && iterations < this.config.maxIterations) {
|
|
356
|
+
if (Date.now() - startTime > this.config.timeoutMs) {
|
|
357
|
+
logger.warn("Planning timeout", { goalId: goal.id, iterations, nodesExplored });
|
|
358
|
+
return {
|
|
359
|
+
goalId: goal.id,
|
|
360
|
+
actionIds: [],
|
|
361
|
+
totalCost: Infinity,
|
|
362
|
+
achievable: false,
|
|
363
|
+
reason: "Planning timeout exceeded",
|
|
364
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
365
|
+
};
|
|
366
|
+
}
|
|
367
|
+
iterations++;
|
|
368
|
+
const current = openSet.dequeue();
|
|
369
|
+
const stateKey = this.stateToKey(current.state);
|
|
370
|
+
if (closedSet.has(stateKey)) {
|
|
371
|
+
continue;
|
|
372
|
+
}
|
|
373
|
+
closedSet.add(stateKey);
|
|
374
|
+
nodesExplored++;
|
|
375
|
+
if (this.isGoalSatisfied(current.state, goal)) {
|
|
376
|
+
const plan = this.reconstructPlan(current, goal);
|
|
377
|
+
logger.debug("Plan found", {
|
|
378
|
+
goalId: goal.id,
|
|
379
|
+
iterations,
|
|
380
|
+
nodesExplored,
|
|
381
|
+
actionCount: plan.actionIds.length
|
|
382
|
+
});
|
|
383
|
+
return plan;
|
|
384
|
+
}
|
|
385
|
+
let pathLength = 0;
|
|
386
|
+
let node = current;
|
|
387
|
+
while (node) {
|
|
388
|
+
pathLength++;
|
|
389
|
+
node = node.parent;
|
|
390
|
+
}
|
|
391
|
+
if (pathLength >= this.config.maxPlanLength) {
|
|
392
|
+
continue;
|
|
393
|
+
}
|
|
394
|
+
for (const action of Array.from(this.actions.values())) {
|
|
395
|
+
if (!this.canApply(action, current.state)) {
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
const newState = this.applyAction(action, current.state);
|
|
399
|
+
const newStateKey = this.stateToKey(newState);
|
|
400
|
+
if (closedSet.has(newStateKey)) {
|
|
401
|
+
continue;
|
|
402
|
+
}
|
|
403
|
+
const gCost = current.gCost + action.cost;
|
|
404
|
+
const hCost = this.heuristic(newState, goal);
|
|
405
|
+
const fCost = gCost + hCost;
|
|
406
|
+
const newNode = {
|
|
407
|
+
state: newState,
|
|
408
|
+
gCost,
|
|
409
|
+
hCost,
|
|
410
|
+
fCost,
|
|
411
|
+
parent: current,
|
|
412
|
+
action
|
|
413
|
+
};
|
|
414
|
+
openSet.enqueue(newNode, fCost);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
logger.debug("No plan found", { goalId: goal.id, iterations, nodesExplored });
|
|
418
|
+
return {
|
|
419
|
+
goalId: goal.id,
|
|
420
|
+
actionIds: [],
|
|
421
|
+
totalCost: Infinity,
|
|
422
|
+
achievable: false,
|
|
423
|
+
reason: "No valid action sequence found",
|
|
424
|
+
createdAt: /* @__PURE__ */ new Date()
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
/**
|
|
428
|
+
* Reconstruct the plan from the goal node by following parent references
|
|
429
|
+
*
|
|
430
|
+
* @param goalNode - The node that reached the goal
|
|
431
|
+
* @param goal - The goal definition
|
|
432
|
+
* @returns Complete GOAP plan
|
|
433
|
+
*/
|
|
434
|
+
reconstructPlan(goalNode, goal) {
|
|
435
|
+
const actionIds = [];
|
|
436
|
+
let current = goalNode;
|
|
437
|
+
let totalCost = 0;
|
|
438
|
+
while (current && current.action) {
|
|
439
|
+
actionIds.unshift(current.action.id);
|
|
440
|
+
totalCost += current.action.cost;
|
|
441
|
+
current = current.parent;
|
|
442
|
+
}
|
|
443
|
+
const lengthPenalty = actionIds.length * 0.05;
|
|
444
|
+
const costPenalty = totalCost * 0.01;
|
|
445
|
+
const confidence = Math.max(0.3, 1 - lengthPenalty - costPenalty);
|
|
446
|
+
return {
|
|
447
|
+
goalId: goal.id,
|
|
448
|
+
actionIds,
|
|
449
|
+
totalCost,
|
|
450
|
+
achievable: true,
|
|
451
|
+
estimatedTimeMs: totalCost * 1e3,
|
|
452
|
+
createdAt: /* @__PURE__ */ new Date(),
|
|
453
|
+
confidence
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Heuristic function for A* (estimates cost to goal)
|
|
458
|
+
*
|
|
459
|
+
* Uses Manhattan-like distance for numeric values and
|
|
460
|
+
* fixed penalties for boolean mismatches.
|
|
461
|
+
*
|
|
462
|
+
* @param state - Current world state
|
|
463
|
+
* @param goal - Goal to reach
|
|
464
|
+
* @returns Estimated cost to reach goal
|
|
465
|
+
*/
|
|
466
|
+
heuristic(state, goal) {
|
|
467
|
+
if (this.customHeuristic) {
|
|
468
|
+
return this.customHeuristic(state, goal.conditions);
|
|
469
|
+
}
|
|
470
|
+
let distance = 0;
|
|
471
|
+
for (const [key, value] of Object.entries(goal.conditions)) {
|
|
472
|
+
const currentValue = state[key];
|
|
473
|
+
if (typeof value === "boolean") {
|
|
474
|
+
if (currentValue !== value) {
|
|
475
|
+
distance += 5;
|
|
476
|
+
}
|
|
477
|
+
} else if (typeof value === "number" && typeof currentValue === "number") {
|
|
478
|
+
if (currentValue < value) {
|
|
479
|
+
distance += (value - currentValue) * 10;
|
|
480
|
+
}
|
|
481
|
+
} else if (Array.isArray(value) && Array.isArray(currentValue)) {
|
|
482
|
+
if (value.length === 0 && currentValue.length > 0) {
|
|
483
|
+
distance += currentValue.length * 2;
|
|
484
|
+
}
|
|
485
|
+
} else if (currentValue !== value) {
|
|
486
|
+
distance += this.config.defaultCost;
|
|
487
|
+
}
|
|
488
|
+
}
|
|
489
|
+
return distance;
|
|
490
|
+
}
|
|
491
|
+
/**
|
|
492
|
+
* Check if a goal is satisfied by the current state
|
|
493
|
+
*/
|
|
494
|
+
isGoalSatisfied(state, goal) {
|
|
495
|
+
for (const [key, value] of Object.entries(goal.conditions)) {
|
|
496
|
+
const currentValue = state[key];
|
|
497
|
+
if (typeof value === "number" && typeof currentValue === "number") {
|
|
498
|
+
if (currentValue < value) {
|
|
499
|
+
return false;
|
|
500
|
+
}
|
|
501
|
+
} else if (Array.isArray(value) && Array.isArray(currentValue)) {
|
|
502
|
+
if (value.length > 0 && currentValue.length > 0) {
|
|
503
|
+
return false;
|
|
504
|
+
}
|
|
505
|
+
} else if (currentValue !== value) {
|
|
506
|
+
return false;
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
return true;
|
|
510
|
+
}
|
|
511
|
+
/**
|
|
512
|
+
* Check if an action can be applied to a state
|
|
513
|
+
*/
|
|
514
|
+
canApply(action, state) {
|
|
515
|
+
for (const [key, value] of Object.entries(action.preconditions)) {
|
|
516
|
+
const currentValue = state[key];
|
|
517
|
+
if (typeof value === "number" && typeof currentValue === "number") {
|
|
518
|
+
if (currentValue < value) {
|
|
519
|
+
return false;
|
|
520
|
+
}
|
|
521
|
+
} else if (currentValue !== value) {
|
|
522
|
+
return false;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return true;
|
|
526
|
+
}
|
|
527
|
+
/**
|
|
528
|
+
* Apply an action to a state and return the new state
|
|
529
|
+
*/
|
|
530
|
+
applyAction(action, state) {
|
|
531
|
+
const newState = { ...state };
|
|
532
|
+
for (const [key, value] of Object.entries(action.effects)) {
|
|
533
|
+
newState[key] = value;
|
|
534
|
+
}
|
|
535
|
+
return newState;
|
|
536
|
+
}
|
|
537
|
+
/**
|
|
538
|
+
* Convert state to a cache key string
|
|
539
|
+
*/
|
|
540
|
+
stateToKey(state) {
|
|
541
|
+
const sortedKeys = Object.keys(state).sort();
|
|
542
|
+
const values = sortedKeys.map((k) => `${k}:${JSON.stringify(state[k])}`);
|
|
543
|
+
return values.join("|");
|
|
544
|
+
}
|
|
545
|
+
/**
|
|
546
|
+
* Create cache key for a plan
|
|
547
|
+
*/
|
|
548
|
+
createCacheKey(state, goalId) {
|
|
549
|
+
return `${goalId}::${this.stateToKey(state)}`;
|
|
550
|
+
}
|
|
551
|
+
/**
|
|
552
|
+
* Cache a plan
|
|
553
|
+
*/
|
|
554
|
+
cachePlan(key, plan) {
|
|
555
|
+
if (this.config.enableCaching) {
|
|
556
|
+
this.planCache.set(key, plan);
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
/**
|
|
560
|
+
* Clear the plan cache
|
|
561
|
+
*/
|
|
562
|
+
clearCache() {
|
|
563
|
+
this.planCache.clear();
|
|
564
|
+
logger.debug("Plan cache cleared");
|
|
565
|
+
}
|
|
566
|
+
/**
|
|
567
|
+
* Execute a plan
|
|
568
|
+
*
|
|
569
|
+
* @param plan - Plan to execute
|
|
570
|
+
* @param initialState - Initial world state
|
|
571
|
+
* @returns Execution result
|
|
572
|
+
*/
|
|
573
|
+
async executePlan(plan, initialState) {
|
|
574
|
+
if (!plan.achievable) {
|
|
575
|
+
return {
|
|
576
|
+
success: false,
|
|
577
|
+
finalState: initialState,
|
|
578
|
+
completedSteps: [],
|
|
579
|
+
error: plan.reason || "Plan is not achievable",
|
|
580
|
+
executionTimeMs: 0
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
const startTime = Date.now();
|
|
584
|
+
let currentState = { ...initialState };
|
|
585
|
+
const completedSteps = [];
|
|
586
|
+
logger.info("Executing plan", {
|
|
587
|
+
goalId: plan.goalId,
|
|
588
|
+
actionCount: plan.actionIds.length
|
|
589
|
+
});
|
|
590
|
+
for (const actionId of plan.actionIds) {
|
|
591
|
+
const action = this.actions.get(actionId);
|
|
592
|
+
if (!action) {
|
|
593
|
+
return {
|
|
594
|
+
success: false,
|
|
595
|
+
finalState: currentState,
|
|
596
|
+
completedSteps,
|
|
597
|
+
failedStep: actionId,
|
|
598
|
+
error: `Unknown action: ${actionId}`,
|
|
599
|
+
executionTimeMs: Date.now() - startTime
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
if (!this.canApply(action, currentState)) {
|
|
603
|
+
return {
|
|
604
|
+
success: false,
|
|
605
|
+
finalState: currentState,
|
|
606
|
+
completedSteps,
|
|
607
|
+
failedStep: actionId,
|
|
608
|
+
error: `Preconditions not met for action: ${actionId}`,
|
|
609
|
+
executionTimeMs: Date.now() - startTime
|
|
610
|
+
};
|
|
611
|
+
}
|
|
612
|
+
try {
|
|
613
|
+
if (action.execute) {
|
|
614
|
+
currentState = await action.execute(currentState);
|
|
615
|
+
} else {
|
|
616
|
+
currentState = this.applyAction(action, currentState);
|
|
617
|
+
}
|
|
618
|
+
completedSteps.push(actionId);
|
|
619
|
+
logger.debug(`Action completed: ${actionId}`);
|
|
620
|
+
} catch (error) {
|
|
621
|
+
logger.error(`Action failed: ${actionId}`, error instanceof Error ? error : new Error(String(error)));
|
|
622
|
+
return {
|
|
623
|
+
success: false,
|
|
624
|
+
finalState: currentState,
|
|
625
|
+
completedSteps,
|
|
626
|
+
failedStep: actionId,
|
|
627
|
+
error: error instanceof Error ? error.message : String(error),
|
|
628
|
+
executionTimeMs: Date.now() - startTime
|
|
629
|
+
};
|
|
630
|
+
}
|
|
631
|
+
}
|
|
632
|
+
logger.info("Plan execution completed", {
|
|
633
|
+
goalId: plan.goalId,
|
|
634
|
+
completedSteps: completedSteps.length
|
|
635
|
+
});
|
|
636
|
+
return {
|
|
637
|
+
success: true,
|
|
638
|
+
finalState: currentState,
|
|
639
|
+
completedSteps,
|
|
640
|
+
executionTimeMs: Date.now() - startTime
|
|
641
|
+
};
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* Evaluate readiness for development
|
|
645
|
+
*
|
|
646
|
+
* @param state - Current world state
|
|
647
|
+
* @returns Readiness evaluation
|
|
648
|
+
*/
|
|
649
|
+
evaluateReadiness(state) {
|
|
650
|
+
const blockers = [];
|
|
651
|
+
const recommendations = [];
|
|
652
|
+
let score = 0;
|
|
653
|
+
if (!state.hasSpecification) {
|
|
654
|
+
blockers.push("No specification document found");
|
|
655
|
+
recommendations.push("Create a specification document");
|
|
656
|
+
} else {
|
|
657
|
+
score += 0.2;
|
|
658
|
+
if (state.specCompleteness < 0.5) {
|
|
659
|
+
blockers.push("Specification is incomplete");
|
|
660
|
+
recommendations.push("Complete the specification document");
|
|
661
|
+
} else if (state.specCompleteness < 0.8) {
|
|
662
|
+
recommendations.push("Consider improving specification completeness");
|
|
663
|
+
score += 0.1;
|
|
664
|
+
} else {
|
|
665
|
+
score += 0.2;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
if (!state.hasAcceptanceCriteria) {
|
|
669
|
+
blockers.push("No acceptance criteria defined");
|
|
670
|
+
recommendations.push("Define acceptance criteria");
|
|
671
|
+
} else {
|
|
672
|
+
score += 0.2;
|
|
673
|
+
}
|
|
674
|
+
if (!state.blockersFree) {
|
|
675
|
+
blockers.push("Blocking issues exist");
|
|
676
|
+
recommendations.push("Resolve blocking issues");
|
|
677
|
+
} else {
|
|
678
|
+
score += 0.2;
|
|
679
|
+
}
|
|
680
|
+
if (state.pendingGaps.length > 0) {
|
|
681
|
+
recommendations.push(`Address ${state.pendingGaps.length} documentation gaps`);
|
|
682
|
+
} else {
|
|
683
|
+
score += 0.1;
|
|
684
|
+
}
|
|
685
|
+
if (state.taskDefined) {
|
|
686
|
+
score += 0.1;
|
|
687
|
+
} else if (blockers.length === 0) {
|
|
688
|
+
recommendations.push("Create a task from the specification");
|
|
689
|
+
}
|
|
690
|
+
return {
|
|
691
|
+
score: Math.min(1, score),
|
|
692
|
+
ready: blockers.length === 0 && score >= 0.7,
|
|
693
|
+
blockers,
|
|
694
|
+
recommendations,
|
|
695
|
+
evaluatedAt: /* @__PURE__ */ new Date()
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
}
|
|
699
|
+
function createGOAPAdapter(config) {
|
|
700
|
+
return new GOAPAdapter(config);
|
|
701
|
+
}
|
|
702
|
+
export {
|
|
703
|
+
GOAPAdapter,
|
|
704
|
+
createGOAPAdapter
|
|
705
|
+
};
|
|
706
|
+
//# sourceMappingURL=goap-adapter.js.map
|