@wowok/agent-mcp 2.5.3 → 2.5.5
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 +33 -26
- package/dist/customer/index.d.ts +2 -2
- package/dist/customer/index.js +1 -1
- package/dist/customer/info-puzzle.d.ts +39 -2
- package/dist/customer/info-puzzle.js +370 -29
- package/dist/customer/risk-assessment.js +51 -14
- package/dist/customer/types.d.ts +85 -0
- package/dist/knowledge/machine-ledger.js +32 -29
- package/dist/knowledge/machine-risk.js +23 -0
- package/dist/knowledge/machine-templates.js +118 -86
- package/dist/knowledge/reward-confirm.d.ts +3 -0
- package/dist/knowledge/reward-confirm.js +30 -0
- package/dist/knowledge/reward-puzzle.d.ts +1 -0
- package/dist/knowledge/reward-puzzle.js +12 -0
- package/dist/knowledge/reward-risk.d.ts +4 -1
- package/dist/knowledge/reward-risk.js +85 -3
- package/dist/knowledge/reward-templates.d.ts +1 -1
- package/dist/knowledge/reward-templates.js +77 -5
- package/dist/knowledge/tools-reference.js +5 -4
- package/dist/knowledge/trust-metrics.d.ts +4 -0
- package/dist/knowledge/trust-metrics.js +67 -7
- package/dist/project/evaluation.d.ts +53 -0
- package/dist/project/evaluation.js +853 -0
- package/dist/project/graph-builder.d.ts +43 -0
- package/dist/project/graph-builder.js +572 -0
- package/dist/project/handlers.d.ts +152 -0
- package/dist/project/handlers.js +458 -0
- package/dist/project/index.d.ts +1 -0
- package/dist/project/index.js +24 -1
- package/dist/project/query.d.ts +1 -0
- package/dist/project/query.js +2 -0
- package/dist/project/semantic-assembler.d.ts +93 -0
- package/dist/project/semantic-assembler.js +345 -0
- package/dist/schema/call/arbitration.d.ts +54 -54
- package/dist/schema/call/base.js +1 -1
- package/dist/schema/call/demand.d.ts +48 -48
- package/dist/schema/operations.d.ts +76 -76
- package/dist/schema/project/index.d.ts +1558 -3885
- package/dist/schema/project/index.js +357 -961
- package/dist/schema/trust/index.d.ts +24 -24
- package/dist/schemas/bridge_operation.schema.json +1 -1
- package/dist/schemas/guard2file.schema.json +1 -1
- package/dist/schemas/index.json +2 -2
- package/dist/schemas/machineNode2file.schema.json +1 -1
- package/dist/schemas/onchain_operations.schema.json +5 -5
- package/dist/schemas/onchain_operations_allocation.schema.json +1 -1
- package/dist/schemas/onchain_operations_arbitration.schema.json +1 -1
- package/dist/schemas/onchain_operations_contact.schema.json +1 -1
- package/dist/schemas/onchain_operations_demand.schema.json +1 -1
- package/dist/schemas/onchain_operations_gen_passport.schema.json +2 -2
- package/dist/schemas/onchain_operations_gen_proof.schema.json +2 -2
- package/dist/schemas/onchain_operations_guard.schema.json +1 -1
- package/dist/schemas/onchain_operations_machine.schema.json +1 -1
- package/dist/schemas/onchain_operations_order.schema.json +1 -1
- package/dist/schemas/onchain_operations_payment.schema.json +1 -1
- package/dist/schemas/onchain_operations_permission.schema.json +1 -1
- package/dist/schemas/onchain_operations_personal.schema.json +1 -1
- package/dist/schemas/onchain_operations_progress.schema.json +1 -1
- package/dist/schemas/onchain_operations_proof.schema.json +1 -1
- package/dist/schemas/onchain_operations_repository.schema.json +1 -1
- package/dist/schemas/onchain_operations_reward.schema.json +1 -1
- package/dist/schemas/onchain_operations_service.schema.json +1 -1
- package/dist/schemas/onchain_operations_treasury.schema.json +1 -1
- package/dist/schemas/project_operation.output.json +975 -2471
- package/dist/schemas/project_operation.schema.json +207 -534
- package/dist/tools/handlers/onchain.js +97 -19
- package/dist/tools/handlers/project.js +34 -1046
- package/dist/tools/index.js +84 -55
- package/package.json +2 -2
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { type Project, type ProjectObject, type GraphEdge } from "@wowok/wowok";
|
|
2
|
+
import type { ReputationData } from "./graph-builder.js";
|
|
3
|
+
export interface SemanticObjectContext {
|
|
4
|
+
address: string;
|
|
5
|
+
name: string | null;
|
|
6
|
+
objectType: string | null;
|
|
7
|
+
role: string | null;
|
|
8
|
+
description: string;
|
|
9
|
+
keyFields: Record<string, unknown>;
|
|
10
|
+
cacheFreshness: "fresh" | "stale" | "unknown";
|
|
11
|
+
}
|
|
12
|
+
export interface SemanticGraphContext {
|
|
13
|
+
nodeCount: number;
|
|
14
|
+
edgeCount: number;
|
|
15
|
+
edgesByType: Record<string, number>;
|
|
16
|
+
edgesBySource: Record<string, number>;
|
|
17
|
+
directDependencies: Array<{
|
|
18
|
+
target: string;
|
|
19
|
+
targetType: string | null;
|
|
20
|
+
fieldName: string | null;
|
|
21
|
+
relationshipType: string;
|
|
22
|
+
}>;
|
|
23
|
+
potentialGaps: Array<{
|
|
24
|
+
target: string;
|
|
25
|
+
targetType: string | null;
|
|
26
|
+
fieldName: string;
|
|
27
|
+
reason: string;
|
|
28
|
+
}>;
|
|
29
|
+
}
|
|
30
|
+
export interface SemanticReputationContext {
|
|
31
|
+
address: string;
|
|
32
|
+
likes: number;
|
|
33
|
+
dislikes: number;
|
|
34
|
+
affiliations: number;
|
|
35
|
+
sentimentScore: number;
|
|
36
|
+
notableVoters: Array<{
|
|
37
|
+
who: string;
|
|
38
|
+
like: boolean;
|
|
39
|
+
dislike: boolean;
|
|
40
|
+
affiliation: boolean;
|
|
41
|
+
}>;
|
|
42
|
+
}
|
|
43
|
+
export interface SemanticProjectContext {
|
|
44
|
+
project: {
|
|
45
|
+
prefix: string;
|
|
46
|
+
name: string;
|
|
47
|
+
description: string | null;
|
|
48
|
+
industry: string | null;
|
|
49
|
+
perspective: string;
|
|
50
|
+
status: string;
|
|
51
|
+
network: string;
|
|
52
|
+
serviceAddress: string | null;
|
|
53
|
+
currentVersion: string | null;
|
|
54
|
+
};
|
|
55
|
+
objects: SemanticObjectContext[];
|
|
56
|
+
graph: SemanticGraphContext;
|
|
57
|
+
reputation: SemanticReputationContext[];
|
|
58
|
+
freshnessSummary: {
|
|
59
|
+
freshCount: number;
|
|
60
|
+
staleCount: number;
|
|
61
|
+
unknownCount: number;
|
|
62
|
+
oldestFetch: number | null;
|
|
63
|
+
newestFetch: number | null;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
export interface EvaluationPrompt {
|
|
67
|
+
evaluationType: "risk" | "trust" | "worth_buying" | "completeness" | "value";
|
|
68
|
+
context: SemanticProjectContext;
|
|
69
|
+
prompt: string;
|
|
70
|
+
scoringCriteria: ScoringCriterion[];
|
|
71
|
+
}
|
|
72
|
+
export interface ScoringCriterion {
|
|
73
|
+
name: string;
|
|
74
|
+
description: string;
|
|
75
|
+
weight: number;
|
|
76
|
+
minScore: number;
|
|
77
|
+
maxScore: number;
|
|
78
|
+
}
|
|
79
|
+
export declare class SemanticAssembler {
|
|
80
|
+
private localProject;
|
|
81
|
+
constructor();
|
|
82
|
+
assemble(project: Project, objects: ProjectObject[], edges: GraphEdge[], reputation?: Map<string, ReputationData>): Promise<SemanticProjectContext>;
|
|
83
|
+
private assembleObjects;
|
|
84
|
+
private describeObject;
|
|
85
|
+
private extractKeyFields;
|
|
86
|
+
private assembleGraph;
|
|
87
|
+
private assembleReputation;
|
|
88
|
+
private classifyFreshness;
|
|
89
|
+
private computeFreshnessSummary;
|
|
90
|
+
buildEvaluationPrompt(evaluationType: EvaluationPrompt["evaluationType"], context: SemanticProjectContext): EvaluationPrompt;
|
|
91
|
+
private getScoringCriteria;
|
|
92
|
+
private formatPrompt;
|
|
93
|
+
}
|
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
import { LocalProject, } from "@wowok/wowok";
|
|
2
|
+
const FRESH_THRESHOLD_MS = 1 * 60 * 60 * 1000;
|
|
3
|
+
const STALE_THRESHOLD_MS = 24 * 60 * 60 * 1000;
|
|
4
|
+
export class SemanticAssembler {
|
|
5
|
+
localProject;
|
|
6
|
+
constructor() {
|
|
7
|
+
this.localProject = LocalProject.Instance();
|
|
8
|
+
}
|
|
9
|
+
async assemble(project, objects, edges, reputation) {
|
|
10
|
+
const objectContexts = await this.assembleObjects(objects);
|
|
11
|
+
const graphContext = this.assembleGraph(edges);
|
|
12
|
+
const reputationContexts = this.assembleReputation(objects, reputation);
|
|
13
|
+
const freshnessSummary = this.computeFreshnessSummary(objectContexts);
|
|
14
|
+
return {
|
|
15
|
+
project: {
|
|
16
|
+
prefix: project.prefix,
|
|
17
|
+
name: project.name,
|
|
18
|
+
description: project.description,
|
|
19
|
+
industry: project.industry,
|
|
20
|
+
perspective: project.perspective,
|
|
21
|
+
status: project.status,
|
|
22
|
+
network: project.network,
|
|
23
|
+
serviceAddress: project.serviceAddress,
|
|
24
|
+
currentVersion: project.currentVersion,
|
|
25
|
+
},
|
|
26
|
+
objects: objectContexts,
|
|
27
|
+
graph: graphContext,
|
|
28
|
+
reputation: reputationContexts,
|
|
29
|
+
freshnessSummary,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
async assembleObjects(objects) {
|
|
33
|
+
const result = [];
|
|
34
|
+
for (const obj of objects) {
|
|
35
|
+
const cached = await this.localProject.getCachedObject(obj.objectAddress);
|
|
36
|
+
const description = cached
|
|
37
|
+
? this.describeObject(obj, cached)
|
|
38
|
+
: `Object ${obj.objectAddress} (no cached on-chain data)`;
|
|
39
|
+
const keyFields = cached
|
|
40
|
+
? this.extractKeyFields(obj.objectType, cached)
|
|
41
|
+
: {};
|
|
42
|
+
const cacheFreshness = cached
|
|
43
|
+
? this.classifyFreshness(cached.fetchedAt)
|
|
44
|
+
: "unknown";
|
|
45
|
+
result.push({
|
|
46
|
+
address: obj.objectAddress,
|
|
47
|
+
name: obj.objectName,
|
|
48
|
+
objectType: obj.objectType,
|
|
49
|
+
role: obj.role,
|
|
50
|
+
description,
|
|
51
|
+
keyFields,
|
|
52
|
+
cacheFreshness,
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
return result;
|
|
56
|
+
}
|
|
57
|
+
describeObject(obj, cached) {
|
|
58
|
+
const type = obj.objectType ?? "unknown";
|
|
59
|
+
const name = obj.objectName ?? abbreviateAddress(obj.objectAddress);
|
|
60
|
+
let desc = `${type} "${name}" at ${abbreviateAddress(obj.objectAddress)}`;
|
|
61
|
+
try {
|
|
62
|
+
const data = JSON.parse(cached.data);
|
|
63
|
+
switch (type) {
|
|
64
|
+
case "Service": {
|
|
65
|
+
const published = data.bPublished;
|
|
66
|
+
const paused = data.bPaused;
|
|
67
|
+
const sales = data.sales;
|
|
68
|
+
desc += published
|
|
69
|
+
? paused
|
|
70
|
+
? " (published but PAUSED)"
|
|
71
|
+
: " (published, active)"
|
|
72
|
+
: " (not yet published)";
|
|
73
|
+
if (sales && Array.isArray(sales) && sales.length > 0) {
|
|
74
|
+
desc += ` with ${sales.length} sale option(s)`;
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
case "Machine": {
|
|
79
|
+
const nodeCount = data.node_count ?? data.nodeCount;
|
|
80
|
+
const published = data.bPublished;
|
|
81
|
+
desc += published
|
|
82
|
+
? ` (published, ${nodeCount} nodes)`
|
|
83
|
+
: ` (draft, ${nodeCount} nodes)`;
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
case "Treasury": {
|
|
87
|
+
desc += " (compensation fund)";
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
case "Guard": {
|
|
91
|
+
desc += " (validation rules)";
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
default:
|
|
95
|
+
break;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
}
|
|
100
|
+
return desc;
|
|
101
|
+
}
|
|
102
|
+
extractKeyFields(objectType, cached) {
|
|
103
|
+
const fields = {};
|
|
104
|
+
try {
|
|
105
|
+
const data = JSON.parse(cached.data);
|
|
106
|
+
switch (objectType) {
|
|
107
|
+
case "Service":
|
|
108
|
+
fields.bPublished = data.bPublished;
|
|
109
|
+
fields.bPaused = data.bPaused;
|
|
110
|
+
fields.sales = data.sales;
|
|
111
|
+
fields.machine = data.machine;
|
|
112
|
+
fields.buy_guard = data.buy_guard;
|
|
113
|
+
fields.permission = data.permission;
|
|
114
|
+
fields.compensation_fund = data.compensation_fund;
|
|
115
|
+
fields.order_allocators = data.order_allocators;
|
|
116
|
+
fields.arbitrations = data.arbitrations;
|
|
117
|
+
fields.rewards = data.rewards;
|
|
118
|
+
fields.repositories = data.repositories;
|
|
119
|
+
break;
|
|
120
|
+
case "Machine":
|
|
121
|
+
fields.bPublished = data.bPublished;
|
|
122
|
+
fields.bPaused = data.bPaused;
|
|
123
|
+
fields.node_count = data.node_count ?? data.nodeCount;
|
|
124
|
+
fields.permission = data.permission;
|
|
125
|
+
break;
|
|
126
|
+
case "Treasury":
|
|
127
|
+
fields.permission = data.permission;
|
|
128
|
+
fields.guard = data.guard;
|
|
129
|
+
break;
|
|
130
|
+
case "Allocation":
|
|
131
|
+
case "Arbitration":
|
|
132
|
+
case "Reward":
|
|
133
|
+
case "Repository":
|
|
134
|
+
case "Demand":
|
|
135
|
+
fields.permission = data.permission;
|
|
136
|
+
fields.guard = data.guard;
|
|
137
|
+
break;
|
|
138
|
+
default:
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
}
|
|
144
|
+
return fields;
|
|
145
|
+
}
|
|
146
|
+
assembleGraph(edges) {
|
|
147
|
+
const edgesByType = {};
|
|
148
|
+
const edgesBySource = {};
|
|
149
|
+
const directDependencies = [];
|
|
150
|
+
const potentialGaps = [];
|
|
151
|
+
for (const edge of edges) {
|
|
152
|
+
edgesByType[edge.relationshipType] = (edgesByType[edge.relationshipType] ?? 0) + 1;
|
|
153
|
+
edgesBySource[edge.edgeSource] = (edgesBySource[edge.edgeSource] ?? 0) + 1;
|
|
154
|
+
if (edge.edgeSource === "internal" && edge.depth === 0) {
|
|
155
|
+
directDependencies.push({
|
|
156
|
+
target: edge.targetObject,
|
|
157
|
+
targetType: null,
|
|
158
|
+
fieldName: edge.fieldName,
|
|
159
|
+
relationshipType: edge.relationshipType,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
if (edge.edgeSource === "potential") {
|
|
163
|
+
const reason = edge.metadata?.reason;
|
|
164
|
+
potentialGaps.push({
|
|
165
|
+
target: edge.targetObject,
|
|
166
|
+
targetType: edge.metadata?.expected_target_type,
|
|
167
|
+
fieldName: edge.fieldName ?? "unknown",
|
|
168
|
+
reason: typeof reason === "string" ? reason : "expected_relationship_missing",
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return {
|
|
173
|
+
nodeCount: new Set([...edges.map((e) => e.sourceObject), ...edges.map((e) => e.targetObject)]).size,
|
|
174
|
+
edgeCount: edges.length,
|
|
175
|
+
edgesByType,
|
|
176
|
+
edgesBySource,
|
|
177
|
+
directDependencies,
|
|
178
|
+
potentialGaps,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
assembleReputation(objects, reputation) {
|
|
182
|
+
if (!reputation || reputation.size === 0)
|
|
183
|
+
return [];
|
|
184
|
+
const result = [];
|
|
185
|
+
for (const obj of objects) {
|
|
186
|
+
const rep = reputation.get(obj.objectAddress);
|
|
187
|
+
if (!rep)
|
|
188
|
+
continue;
|
|
189
|
+
const total = rep.likes + rep.dislikes;
|
|
190
|
+
const sentimentScore = total > 0 ? rep.likes / total : 0.5;
|
|
191
|
+
result.push({
|
|
192
|
+
address: obj.objectAddress,
|
|
193
|
+
likes: rep.likes,
|
|
194
|
+
dislikes: rep.dislikes,
|
|
195
|
+
affiliations: rep.affiliations,
|
|
196
|
+
sentimentScore,
|
|
197
|
+
notableVoters: rep.voters.slice(0, 5).map((v) => ({
|
|
198
|
+
who: abbreviateAddress(v.who),
|
|
199
|
+
like: v.like,
|
|
200
|
+
dislike: v.dislike,
|
|
201
|
+
affiliation: v.affiliation,
|
|
202
|
+
})),
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
return result;
|
|
206
|
+
}
|
|
207
|
+
classifyFreshness(fetchedAt) {
|
|
208
|
+
const age = Date.now() - fetchedAt;
|
|
209
|
+
if (age < FRESH_THRESHOLD_MS)
|
|
210
|
+
return "fresh";
|
|
211
|
+
if (age < STALE_THRESHOLD_MS)
|
|
212
|
+
return "stale";
|
|
213
|
+
return "stale";
|
|
214
|
+
}
|
|
215
|
+
computeFreshnessSummary(objects) {
|
|
216
|
+
let freshCount = 0;
|
|
217
|
+
let staleCount = 0;
|
|
218
|
+
let unknownCount = 0;
|
|
219
|
+
let oldestFetch = null;
|
|
220
|
+
let newestFetch = null;
|
|
221
|
+
for (const obj of objects) {
|
|
222
|
+
switch (obj.cacheFreshness) {
|
|
223
|
+
case "fresh":
|
|
224
|
+
freshCount++;
|
|
225
|
+
break;
|
|
226
|
+
case "stale":
|
|
227
|
+
staleCount++;
|
|
228
|
+
break;
|
|
229
|
+
case "unknown":
|
|
230
|
+
unknownCount++;
|
|
231
|
+
break;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
return { freshCount, staleCount, unknownCount, oldestFetch, newestFetch };
|
|
235
|
+
}
|
|
236
|
+
buildEvaluationPrompt(evaluationType, context) {
|
|
237
|
+
const criteria = this.getScoringCriteria(evaluationType);
|
|
238
|
+
const prompt = this.formatPrompt(evaluationType, context, criteria);
|
|
239
|
+
return {
|
|
240
|
+
evaluationType,
|
|
241
|
+
context,
|
|
242
|
+
prompt,
|
|
243
|
+
scoringCriteria: criteria,
|
|
244
|
+
};
|
|
245
|
+
}
|
|
246
|
+
getScoringCriteria(evaluationType) {
|
|
247
|
+
switch (evaluationType) {
|
|
248
|
+
case "risk":
|
|
249
|
+
return [
|
|
250
|
+
{ name: "structural_risk", description: "Risk from missing bindings, broken workflows, incomplete setup", weight: 0.3, minScore: 0, maxScore: 100 },
|
|
251
|
+
{ name: "fund_safety", description: "Risk from Treasury/Allocation misconfiguration, missing compensation fund", weight: 0.25, minScore: 0, maxScore: 100 },
|
|
252
|
+
{ name: "operational_risk", description: "Risk from Machine/Guard complexity, pause state, missing arbitration", weight: 0.25, minScore: 0, maxScore: 100 },
|
|
253
|
+
{ name: "governance_risk", description: "Risk from Permission setup, missing UM, overly permissive rules", weight: 0.2, minScore: 0, maxScore: 100 },
|
|
254
|
+
];
|
|
255
|
+
case "trust":
|
|
256
|
+
return [
|
|
257
|
+
{ name: "reputation", description: "Registrar like/dislike ratio and affiliation count", weight: 0.3, minScore: 0, maxScore: 100 },
|
|
258
|
+
{ name: "arbitration_coverage", description: "Presence and quality of arbitration arrangements", weight: 0.25, minScore: 0, maxScore: 100 },
|
|
259
|
+
{ name: "guard_quality", description: "Guard rule complexity and coverage of business scenarios", weight: 0.25, minScore: 0, maxScore: 100 },
|
|
260
|
+
{ name: "transparency", description: "Object descriptions, repository data, contact information availability", weight: 0.2, minScore: 0, maxScore: 100 },
|
|
261
|
+
];
|
|
262
|
+
case "worth_buying":
|
|
263
|
+
return [
|
|
264
|
+
{ name: "price_reasonableness", description: "Service pricing vs. comparable services and market norms", weight: 0.3, minScore: 0, maxScore: 100 },
|
|
265
|
+
{ name: "refund_protection", description: "Compensation fund balance, lock duration, refund workflow availability", weight: 0.25, minScore: 0, maxScore: 100 },
|
|
266
|
+
{ name: "risk_adjusted_value", description: "Value proposition adjusted for project risk score", weight: 0.25, minScore: 0, maxScore: 100 },
|
|
267
|
+
{ name: "trust_adjusted_value", description: "Value proposition adjusted for merchant trust score", weight: 0.2, minScore: 0, maxScore: 100 },
|
|
268
|
+
];
|
|
269
|
+
case "completeness":
|
|
270
|
+
return [
|
|
271
|
+
{ name: "object_coverage", description: "Expected objects present vs. missing (based on EXPECTED_RELATIONSHIPS)", weight: 0.3, minScore: 0, maxScore: 100 },
|
|
272
|
+
{ name: "binding_completeness", description: "Required bindings established (Service→Machine, Guard, Permission, etc.)", weight: 0.3, minScore: 0, maxScore: 100 },
|
|
273
|
+
{ name: "workflow_rationality", description: "Machine node topology is sound, no dangling nodes or cycles", weight: 0.2, minScore: 0, maxScore: 100 },
|
|
274
|
+
{ name: "deployment_readiness", description: "Service publishable, all prerequisites met", weight: 0.2, minScore: 0, maxScore: 100 },
|
|
275
|
+
];
|
|
276
|
+
case "value":
|
|
277
|
+
return [
|
|
278
|
+
{ name: "market_positioning", description: "Service differentiation and competitive positioning", weight: 0.3, minScore: 0, maxScore: 100 },
|
|
279
|
+
{ name: "revenue_potential", description: "Pricing strategy and revenue model viability", weight: 0.3, minScore: 0, maxScore: 100 },
|
|
280
|
+
{ name: "scalability", description: "Ability to handle growth (Machine capacity, Allocation flexibility)", weight: 0.2, minScore: 0, maxScore: 100 },
|
|
281
|
+
{ name: "ecosystem_fit", description: "Integration with WoWok ecosystem (rewards, demands, repositories)", weight: 0.2, minScore: 0, maxScore: 100 },
|
|
282
|
+
];
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
formatPrompt(evaluationType, context, criteria) {
|
|
286
|
+
const lines = [];
|
|
287
|
+
lines.push(`# Project Evaluation: ${evaluationType.toUpperCase()}`);
|
|
288
|
+
lines.push("");
|
|
289
|
+
lines.push(`## Project: ${context.project.name} (${context.project.prefix})`);
|
|
290
|
+
lines.push(`- Perspective: ${context.project.perspective}`);
|
|
291
|
+
lines.push(`- Status: ${context.project.status}`);
|
|
292
|
+
lines.push(`- Network: ${context.project.network}`);
|
|
293
|
+
lines.push(`- Industry: ${context.project.industry ?? "unspecified"}`);
|
|
294
|
+
lines.push(`- Service: ${context.project.serviceAddress ?? "not set"}`);
|
|
295
|
+
lines.push("");
|
|
296
|
+
lines.push("## Objects");
|
|
297
|
+
for (const obj of context.objects) {
|
|
298
|
+
lines.push(`- ${obj.description}`);
|
|
299
|
+
}
|
|
300
|
+
lines.push("");
|
|
301
|
+
lines.push("## Relationship Graph");
|
|
302
|
+
lines.push(`- Total nodes: ${context.graph.nodeCount}`);
|
|
303
|
+
lines.push(`- Total edges: ${context.graph.edgeCount}`);
|
|
304
|
+
lines.push(`- Edge sources: ${JSON.stringify(context.graph.edgesBySource)}`);
|
|
305
|
+
lines.push(`- Edge types: ${JSON.stringify(context.graph.edgesByType)}`);
|
|
306
|
+
lines.push(`- Direct dependencies: ${context.graph.directDependencies.length}`);
|
|
307
|
+
if (context.graph.potentialGaps.length > 0) {
|
|
308
|
+
lines.push(`- **Missing relationships (potential gaps): ${context.graph.potentialGaps.length}**`);
|
|
309
|
+
for (const gap of context.graph.potentialGaps.slice(0, 10)) {
|
|
310
|
+
lines.push(` - ${gap.fieldName} → ${gap.targetType ?? "unknown"} (${gap.reason})`);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
lines.push("");
|
|
314
|
+
if (context.reputation.length > 0) {
|
|
315
|
+
lines.push("## Reputation Data (from Registrar)");
|
|
316
|
+
for (const rep of context.reputation) {
|
|
317
|
+
lines.push(`- ${abbreviateAddress(rep.address)}: ${rep.likes} likes, ${rep.dislikes} dislikes, ${rep.affiliations} affiliations (sentiment: ${(rep.sentimentScore * 100).toFixed(0)}%)`);
|
|
318
|
+
}
|
|
319
|
+
lines.push("");
|
|
320
|
+
}
|
|
321
|
+
lines.push("## Cache Freshness");
|
|
322
|
+
lines.push(`- Fresh: ${context.freshnessSummary.freshCount}`);
|
|
323
|
+
lines.push(`- Stale: ${context.freshnessSummary.staleCount}`);
|
|
324
|
+
lines.push(`- Unknown: ${context.freshnessSummary.unknownCount}`);
|
|
325
|
+
lines.push("");
|
|
326
|
+
lines.push("## Scoring Criteria");
|
|
327
|
+
lines.push("Please score each criterion (0-100, higher = better) and provide a brief justification:");
|
|
328
|
+
for (const c of criteria) {
|
|
329
|
+
lines.push(`- **${c.name}** (weight: ${c.weight}): ${c.description}`);
|
|
330
|
+
}
|
|
331
|
+
lines.push("");
|
|
332
|
+
lines.push("## Instructions");
|
|
333
|
+
lines.push(`1. Analyze the project from the "${evaluationType}" perspective.`);
|
|
334
|
+
lines.push("2. Score each criterion above (0-100).");
|
|
335
|
+
lines.push("3. Compute a weighted overall score.");
|
|
336
|
+
lines.push("4. Provide a 1-2 sentence summary of your assessment.");
|
|
337
|
+
lines.push("5. Return the result as JSON: { score: number, summary: string, details: { criterion_scores: {...}, justification: string } }");
|
|
338
|
+
return lines.join("\n");
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
function abbreviateAddress(address) {
|
|
342
|
+
if (!address || address.length < 12)
|
|
343
|
+
return address;
|
|
344
|
+
return `${address.slice(0, 6)}...${address.slice(-4)}`;
|
|
345
|
+
}
|