@ebowwa/daemons 0.5.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 +264 -0
- package/dist/bin/discord-cli.js +124118 -0
- package/dist/bin/manager.js +143 -0
- package/dist/bin/telegram-cli.js +124114 -0
- package/dist/index.js +125340 -0
- package/package.json +94 -0
- package/src/agent.ts +111 -0
- package/src/channels/base.ts +573 -0
- package/src/channels/discord.ts +306 -0
- package/src/channels/index.ts +169 -0
- package/src/channels/telegram.ts +315 -0
- package/src/daemon.ts +534 -0
- package/src/hooks.ts +97 -0
- package/src/index.ts +111 -0
- package/src/memory.ts +369 -0
- package/src/skills/coding/commit.ts +202 -0
- package/src/skills/coding/execute-subtask.ts +136 -0
- package/src/skills/coding/fix-issues.ts +126 -0
- package/src/skills/coding/index.ts +26 -0
- package/src/skills/coding/plan-task.ts +158 -0
- package/src/skills/coding/quality-check.ts +155 -0
- package/src/skills/index.ts +65 -0
- package/src/skills/registry.ts +380 -0
- package/src/skills/shared/index.ts +21 -0
- package/src/skills/shared/reflect.ts +156 -0
- package/src/skills/shared/review.ts +201 -0
- package/src/skills/shared/trajectory.ts +319 -0
- package/src/skills/trading/analyze-market.ts +144 -0
- package/src/skills/trading/check-risk.ts +176 -0
- package/src/skills/trading/execute-trade.ts +185 -0
- package/src/skills/trading/generate-signal.ts +160 -0
- package/src/skills/trading/index.ts +26 -0
- package/src/skills/trading/monitor-position.ts +179 -0
- package/src/skills/types.ts +235 -0
- package/src/skills/workflows.ts +340 -0
- package/src/state.ts +77 -0
- package/src/tools.ts +134 -0
- package/src/types.ts +314 -0
- package/src/workflow.ts +341 -0
- package/src/workflows/coding.ts +580 -0
- package/src/workflows/index.ts +61 -0
- package/src/workflows/trading.ts +608 -0
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GLM Daemon - Review Skill
|
|
3
|
+
*
|
|
4
|
+
* Quality review for code changes or trading performance.
|
|
5
|
+
* Used by coding and trading workflows.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { z } from "zod";
|
|
9
|
+
import type { Skill, SkillContext, SkillResult } from "../types.js";
|
|
10
|
+
import { skillRegistry } from "../registry.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Review skill parameters
|
|
14
|
+
*/
|
|
15
|
+
const ReviewParams = z.object({
|
|
16
|
+
/** Type of review: "code" | "trading" | "general" */
|
|
17
|
+
type: z.enum(["code", "trading", "general"]).optional(),
|
|
18
|
+
/** Specific criteria to review against */
|
|
19
|
+
criteria: z.array(z.string()).optional(),
|
|
20
|
+
/** Whether to approve on success */
|
|
21
|
+
approveOnPass: z.boolean().optional(),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Review result data
|
|
26
|
+
*/
|
|
27
|
+
interface ReviewData {
|
|
28
|
+
/** Whether the review passed */
|
|
29
|
+
approved: boolean;
|
|
30
|
+
/** Issues found during review */
|
|
31
|
+
issues: string[];
|
|
32
|
+
/** Suggestions for improvement */
|
|
33
|
+
suggestions: string[];
|
|
34
|
+
/** Overall assessment */
|
|
35
|
+
assessment: string;
|
|
36
|
+
/** Score (0-100) if applicable */
|
|
37
|
+
score?: number;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Default review criteria by type
|
|
42
|
+
*/
|
|
43
|
+
const DEFAULT_CRITERIA: Record<string, string[]> = {
|
|
44
|
+
code: [
|
|
45
|
+
"Correctness: Does it work as intended?",
|
|
46
|
+
"Edge cases: Are error cases handled?",
|
|
47
|
+
"Security: Any vulnerabilities?",
|
|
48
|
+
"Performance: Any bottlenecks?",
|
|
49
|
+
"Maintainability: Is it readable?",
|
|
50
|
+
],
|
|
51
|
+
trading: [
|
|
52
|
+
"Risk management: Position size within limits?",
|
|
53
|
+
"Stop loss: Properly placed?",
|
|
54
|
+
"Entry/Exit: Logical levels?",
|
|
55
|
+
"Market conditions: Suitable for current state?",
|
|
56
|
+
"P&L projection: Realistic expectations?",
|
|
57
|
+
],
|
|
58
|
+
general: [
|
|
59
|
+
"Completeness: Task fully addressed?",
|
|
60
|
+
"Quality: Meets standards?",
|
|
61
|
+
"Consistency: Follows patterns?",
|
|
62
|
+
],
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Review skill definition
|
|
67
|
+
*/
|
|
68
|
+
export const reviewSkill: Skill<z.infer<typeof ReviewParams>, ReviewData> = {
|
|
69
|
+
id: "/review",
|
|
70
|
+
name: "Review",
|
|
71
|
+
description:
|
|
72
|
+
"Quality review for changes or decisions. Can review code, trades, or general work.",
|
|
73
|
+
paramsSchema: ReviewParams,
|
|
74
|
+
tags: ["shared", "quality", "validation"],
|
|
75
|
+
parallelizable: false,
|
|
76
|
+
produces: ["approved", "issues", "assessment"],
|
|
77
|
+
|
|
78
|
+
async execute(params, context): Promise<SkillResult<ReviewData>> {
|
|
79
|
+
const reviewType = params?.type || "general";
|
|
80
|
+
const criteria = params?.criteria || DEFAULT_CRITERIA[reviewType] || DEFAULT_CRITERIA.general;
|
|
81
|
+
const approveOnPass = params?.approveOnPass ?? true;
|
|
82
|
+
|
|
83
|
+
console.log(`[/review] Type: ${reviewType}`);
|
|
84
|
+
console.log(`[/review] Criteria: ${criteria.length} items`);
|
|
85
|
+
|
|
86
|
+
// Build review prompt based on type
|
|
87
|
+
let reviewContext = "";
|
|
88
|
+
switch (reviewType) {
|
|
89
|
+
case "code":
|
|
90
|
+
reviewContext = `
|
|
91
|
+
Files changed: ${context.state.filesChanged.join(", ") || "none"}
|
|
92
|
+
Subtasks completed: ${context.state.slam.completedSubtasks.length}/${context.state.slam.subtasks.length}
|
|
93
|
+
Task: ${context.state.prompt}
|
|
94
|
+
Completion promise: ${context.state.promise}
|
|
95
|
+
`;
|
|
96
|
+
break;
|
|
97
|
+
case "trading":
|
|
98
|
+
reviewContext = `
|
|
99
|
+
Current position: ${JSON.stringify(context.custom.position || "none")}
|
|
100
|
+
P&L: ${context.custom.currentPnL || "N/A"}
|
|
101
|
+
Risk level: ${context.custom.riskLevel || "unknown"}
|
|
102
|
+
Iteration: ${context.state.iteration}
|
|
103
|
+
`;
|
|
104
|
+
break;
|
|
105
|
+
default:
|
|
106
|
+
reviewContext = `
|
|
107
|
+
Task: ${context.state.prompt}
|
|
108
|
+
Files changed: ${context.state.filesChanged.join(", ") || "none"}
|
|
109
|
+
Iterations: ${context.state.iteration}
|
|
110
|
+
`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const prompt = `Perform a thorough review.
|
|
114
|
+
|
|
115
|
+
Type: ${reviewType}
|
|
116
|
+
|
|
117
|
+
Context:
|
|
118
|
+
${reviewContext}
|
|
119
|
+
|
|
120
|
+
Review Criteria:
|
|
121
|
+
${criteria.map((c, i) => `${i + 1}. ${c}`).join("\n")}
|
|
122
|
+
|
|
123
|
+
For each criterion:
|
|
124
|
+
1. Assess whether it's met
|
|
125
|
+
2. Note any issues or concerns
|
|
126
|
+
3. Provide suggestions if applicable
|
|
127
|
+
|
|
128
|
+
Respond in JSON format:
|
|
129
|
+
{
|
|
130
|
+
"approved": true|false,
|
|
131
|
+
"issues": ["list of issues found"],
|
|
132
|
+
"suggestions": ["list of improvement suggestions"],
|
|
133
|
+
"assessment": "overall assessment text",
|
|
134
|
+
"score": 0-100
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
If all criteria are met and there are no critical issues, set approved to true.
|
|
138
|
+
If there are critical issues that must be fixed, set approved to false.`;
|
|
139
|
+
|
|
140
|
+
try {
|
|
141
|
+
const response = await context.agent.execute(prompt);
|
|
142
|
+
|
|
143
|
+
// Parse JSON from response
|
|
144
|
+
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
|
145
|
+
let data: ReviewData;
|
|
146
|
+
|
|
147
|
+
if (jsonMatch) {
|
|
148
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
149
|
+
data = {
|
|
150
|
+
approved: parsed.approved ?? false,
|
|
151
|
+
issues: parsed.issues || [],
|
|
152
|
+
suggestions: parsed.suggestions || [],
|
|
153
|
+
assessment: parsed.assessment || "",
|
|
154
|
+
score: parsed.score,
|
|
155
|
+
};
|
|
156
|
+
} else {
|
|
157
|
+
// Fallback: detect approval from response
|
|
158
|
+
const lowerResponse = response.toLowerCase();
|
|
159
|
+
const hasApproved = lowerResponse.includes("approved") && !lowerResponse.includes("not approved");
|
|
160
|
+
data = {
|
|
161
|
+
approved: approveOnPass && hasApproved,
|
|
162
|
+
issues: [],
|
|
163
|
+
suggestions: [],
|
|
164
|
+
assessment: response.substring(0, 500),
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
console.log(`[/review] Result: ${data.approved ? "APPROVED" : "NEEDS WORK"}`);
|
|
169
|
+
if (data.issues.length > 0) {
|
|
170
|
+
console.log(`[/review] Issues: ${data.issues.length}`);
|
|
171
|
+
}
|
|
172
|
+
if (data.score !== undefined) {
|
|
173
|
+
console.log(`[/review] Score: ${data.score}/100`);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
return {
|
|
177
|
+
success: true,
|
|
178
|
+
data,
|
|
179
|
+
contextUpdates: {
|
|
180
|
+
approved: data.approved,
|
|
181
|
+
reviewIssues: data.issues,
|
|
182
|
+
reviewScore: data.score,
|
|
183
|
+
},
|
|
184
|
+
};
|
|
185
|
+
} catch (error) {
|
|
186
|
+
return {
|
|
187
|
+
success: false,
|
|
188
|
+
error: error instanceof Error ? error.message : String(error),
|
|
189
|
+
contextUpdates: {
|
|
190
|
+
approved: false,
|
|
191
|
+
},
|
|
192
|
+
};
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
// Auto-register
|
|
198
|
+
skillRegistry.register(reviewSkill);
|
|
199
|
+
|
|
200
|
+
export { ReviewParams };
|
|
201
|
+
export type { ReviewData };
|
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GLM Daemon - Trajectory Skill
|
|
3
|
+
*
|
|
4
|
+
* Integration with @ebowwa/trajectory for learning from execution patterns.
|
|
5
|
+
* Provides:
|
|
6
|
+
* - Query learned patterns by domain
|
|
7
|
+
* - Record execution results for learning
|
|
8
|
+
* - Provide context about past successful patterns
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
import type { Skill, SkillContext, SkillResult } from "../types.js";
|
|
13
|
+
import { skillRegistry } from "../registry.js";
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Trajectory skill parameters
|
|
17
|
+
*/
|
|
18
|
+
const TrajectoryParams = z.discriminatedUnion("action", [
|
|
19
|
+
z.object({
|
|
20
|
+
/** Query patterns by domain */
|
|
21
|
+
action: z.literal("query"),
|
|
22
|
+
/** Domain to query (e.g., "math", "trading", "coding") */
|
|
23
|
+
domain: z.string(),
|
|
24
|
+
/** Minimum success rate filter (0-1) */
|
|
25
|
+
minSuccessRate: z.number().min(0).max(1).optional(),
|
|
26
|
+
/** Maximum patterns to return */
|
|
27
|
+
limit: z.number().min(1).max(50).optional(),
|
|
28
|
+
}),
|
|
29
|
+
z.object({
|
|
30
|
+
/** Record execution result */
|
|
31
|
+
action: z.literal("record"),
|
|
32
|
+
/** Execution data to record */
|
|
33
|
+
execution: z.object({
|
|
34
|
+
primitiveId: z.string(),
|
|
35
|
+
package: z.string(),
|
|
36
|
+
version: z.string(),
|
|
37
|
+
inputs: z.record(z.unknown()),
|
|
38
|
+
output: z.unknown(),
|
|
39
|
+
durationNs: z.number(),
|
|
40
|
+
verified: z.boolean(),
|
|
41
|
+
invariantsChecked: z.array(z.string()).optional(),
|
|
42
|
+
verificationErrors: z.array(z.string()).optional(),
|
|
43
|
+
specId: z.string().optional(),
|
|
44
|
+
sessionId: z.string().optional(),
|
|
45
|
+
}),
|
|
46
|
+
}),
|
|
47
|
+
z.object({
|
|
48
|
+
/** Get context about past patterns for a given task */
|
|
49
|
+
action: z.literal("context"),
|
|
50
|
+
/** Task description to find relevant patterns */
|
|
51
|
+
task: z.string(),
|
|
52
|
+
/** Domain hint */
|
|
53
|
+
domain: z.string().optional(),
|
|
54
|
+
}),
|
|
55
|
+
z.object({
|
|
56
|
+
/** Get memory statistics */
|
|
57
|
+
action: z.literal("stats"),
|
|
58
|
+
}),
|
|
59
|
+
]);
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Pattern info from trajectory memory
|
|
63
|
+
*/
|
|
64
|
+
interface LearnedPattern {
|
|
65
|
+
primitiveSequence: string[];
|
|
66
|
+
avgDurationMs: number;
|
|
67
|
+
successRate: number;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Trajectory skill result data
|
|
72
|
+
*/
|
|
73
|
+
interface TrajectoryData {
|
|
74
|
+
action: "query" | "record" | "context" | "stats";
|
|
75
|
+
patterns?: LearnedPattern[];
|
|
76
|
+
recorded?: {
|
|
77
|
+
executionId: string;
|
|
78
|
+
timestamp: number;
|
|
79
|
+
};
|
|
80
|
+
context?: {
|
|
81
|
+
relevantPatterns: LearnedPattern[];
|
|
82
|
+
suggestions: string[];
|
|
83
|
+
historicalSuccess: number;
|
|
84
|
+
};
|
|
85
|
+
stats?: {
|
|
86
|
+
totalExecutions: number;
|
|
87
|
+
totalCompositions: number;
|
|
88
|
+
totalTrajectories: number;
|
|
89
|
+
successfulTrajectories: number;
|
|
90
|
+
avgExecutionsPerComposition: number;
|
|
91
|
+
avgAttemptsPerTrajectory: number;
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Lazy-loaded trajectory memory reference
|
|
97
|
+
* We import dynamically to avoid bundling issues if trajectory is not installed
|
|
98
|
+
*/
|
|
99
|
+
let _trajectoryMemory: InstanceType<
|
|
100
|
+
typeof import("@ebowwa/trajectory").TrajectoryMemory
|
|
101
|
+
> | null = null;
|
|
102
|
+
let _trajectoryAvailable: boolean | null = null;
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Get or initialize trajectory memory
|
|
106
|
+
*/
|
|
107
|
+
async function getTrajectoryMemory(): Promise<
|
|
108
|
+
InstanceType<typeof import("@ebowwa/trajectory").TrajectoryMemory> | null
|
|
109
|
+
> {
|
|
110
|
+
if (_trajectoryAvailable === false) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (_trajectoryMemory) {
|
|
115
|
+
return _trajectoryMemory;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const { TrajectoryMemory } = await import("@ebowwa/trajectory");
|
|
120
|
+
|
|
121
|
+
// Use default path or custom path from env
|
|
122
|
+
const dbPath = process.env.TRAJECTORY_DB_PATH || ".trajectory/memory.lmdb";
|
|
123
|
+
_trajectoryMemory = new TrajectoryMemory({ path: dbPath });
|
|
124
|
+
_trajectoryAvailable = true;
|
|
125
|
+
return _trajectoryMemory;
|
|
126
|
+
} catch (error) {
|
|
127
|
+
console.warn(
|
|
128
|
+
"[/trajectory] @ebowwa/trajectory not available or initialization failed:",
|
|
129
|
+
error instanceof Error ? error.message : String(error)
|
|
130
|
+
);
|
|
131
|
+
_trajectoryAvailable = false;
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Trajectory skill definition
|
|
138
|
+
*/
|
|
139
|
+
export const trajectorySkill: Skill<
|
|
140
|
+
z.infer<typeof TrajectoryParams>,
|
|
141
|
+
TrajectoryData
|
|
142
|
+
> = {
|
|
143
|
+
id: "/trajectory",
|
|
144
|
+
name: "Trajectory",
|
|
145
|
+
description:
|
|
146
|
+
"Query and record execution patterns for learning. Integrates with @ebowwa/trajectory memory system.",
|
|
147
|
+
paramsSchema: TrajectoryParams,
|
|
148
|
+
tags: ["shared", "learning", "memory", "meta"],
|
|
149
|
+
parallelizable: true,
|
|
150
|
+
maxRetries: 1,
|
|
151
|
+
|
|
152
|
+
async execute(params, context): Promise<SkillResult<TrajectoryData>> {
|
|
153
|
+
const memory = await getTrajectoryMemory();
|
|
154
|
+
|
|
155
|
+
if (!memory) {
|
|
156
|
+
return {
|
|
157
|
+
success: false,
|
|
158
|
+
error:
|
|
159
|
+
"Trajectory memory not available. Ensure @ebowwa/trajectory is installed.",
|
|
160
|
+
data: { action: params.action },
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
try {
|
|
165
|
+
switch (params.action) {
|
|
166
|
+
case "query": {
|
|
167
|
+
const { domain, minSuccessRate = 0.5, limit = 10 } = params;
|
|
168
|
+
|
|
169
|
+
console.log("[/trajectory] Querying patterns for domain:", domain);
|
|
170
|
+
|
|
171
|
+
let patterns = memory.findSuccessfulPatterns(domain);
|
|
172
|
+
|
|
173
|
+
// Filter by success rate
|
|
174
|
+
patterns = patterns.filter((p) => p.successRate >= minSuccessRate);
|
|
175
|
+
|
|
176
|
+
// Sort by success rate and limit
|
|
177
|
+
patterns = patterns
|
|
178
|
+
.sort((a, b) => b.successRate - a.successRate)
|
|
179
|
+
.slice(0, limit);
|
|
180
|
+
|
|
181
|
+
console.log("[/trajectory] Found", patterns.length, "patterns for", domain);
|
|
182
|
+
|
|
183
|
+
return {
|
|
184
|
+
success: true,
|
|
185
|
+
data: {
|
|
186
|
+
action: "query",
|
|
187
|
+
patterns,
|
|
188
|
+
},
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
case "record": {
|
|
193
|
+
const { execution } = params;
|
|
194
|
+
|
|
195
|
+
console.log("[/trajectory] Recording execution:", execution.primitiveId);
|
|
196
|
+
|
|
197
|
+
const record = memory.recordExecution({
|
|
198
|
+
primitive: {
|
|
199
|
+
id: execution.primitiveId,
|
|
200
|
+
package: execution.package,
|
|
201
|
+
version: execution.version,
|
|
202
|
+
},
|
|
203
|
+
inputs: execution.inputs,
|
|
204
|
+
output: execution.output,
|
|
205
|
+
durationNs: execution.durationNs,
|
|
206
|
+
verified: execution.verified,
|
|
207
|
+
invariantsChecked: execution.invariantsChecked || [],
|
|
208
|
+
verificationErrors: execution.verificationErrors || [],
|
|
209
|
+
specId: execution.specId,
|
|
210
|
+
sessionId: execution.sessionId,
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
console.log("[/trajectory] Recorded execution", record.id);
|
|
214
|
+
|
|
215
|
+
return {
|
|
216
|
+
success: true,
|
|
217
|
+
data: {
|
|
218
|
+
action: "record",
|
|
219
|
+
recorded: {
|
|
220
|
+
executionId: record.id,
|
|
221
|
+
timestamp: record.timestamp,
|
|
222
|
+
},
|
|
223
|
+
},
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
case "context": {
|
|
228
|
+
const { task, domain } = params;
|
|
229
|
+
|
|
230
|
+
console.log("[/trajectory] Getting context for task:", task.substring(0, 50));
|
|
231
|
+
|
|
232
|
+
// Query patterns from relevant domains
|
|
233
|
+
const domains = domain
|
|
234
|
+
? [domain]
|
|
235
|
+
: ["coding", "trading", "math", "general"];
|
|
236
|
+
|
|
237
|
+
let allPatterns: LearnedPattern[] = [];
|
|
238
|
+
for (const d of domains) {
|
|
239
|
+
const patterns = memory.findSuccessfulPatterns(d);
|
|
240
|
+
allPatterns.push(...patterns);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Sort by success rate and get top patterns
|
|
244
|
+
const relevantPatterns = allPatterns
|
|
245
|
+
.sort((a, b) => b.successRate - a.successRate)
|
|
246
|
+
.slice(0, 5);
|
|
247
|
+
|
|
248
|
+
// Generate suggestions based on patterns
|
|
249
|
+
const suggestions: string[] = [];
|
|
250
|
+
if (relevantPatterns.length > 0) {
|
|
251
|
+
suggestions.push(
|
|
252
|
+
"Past successful patterns: " + relevantPatterns[0].primitiveSequence.join(" -> ")
|
|
253
|
+
);
|
|
254
|
+
if (relevantPatterns[0].successRate > 0.8) {
|
|
255
|
+
suggestions.push(
|
|
256
|
+
"This pattern has high success rate - consider following similar approach"
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const stats = memory.getStats();
|
|
262
|
+
const historicalSuccess =
|
|
263
|
+
stats.totalTrajectories > 0
|
|
264
|
+
? stats.successfulTrajectories / stats.totalTrajectories
|
|
265
|
+
: 0;
|
|
266
|
+
|
|
267
|
+
console.log("[/trajectory] Found", relevantPatterns.length, "relevant patterns");
|
|
268
|
+
|
|
269
|
+
return {
|
|
270
|
+
success: true,
|
|
271
|
+
data: {
|
|
272
|
+
action: "context",
|
|
273
|
+
context: {
|
|
274
|
+
relevantPatterns,
|
|
275
|
+
suggestions,
|
|
276
|
+
historicalSuccess,
|
|
277
|
+
},
|
|
278
|
+
},
|
|
279
|
+
};
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
case "stats": {
|
|
283
|
+
console.log("[/trajectory] Getting memory statistics");
|
|
284
|
+
|
|
285
|
+
const stats = memory.getStats();
|
|
286
|
+
|
|
287
|
+
console.log("[/trajectory] Stats:", stats.totalExecutions, "executions,", stats.successfulTrajectories + "/" + stats.totalTrajectories, "successful trajectories");
|
|
288
|
+
|
|
289
|
+
return {
|
|
290
|
+
success: true,
|
|
291
|
+
data: {
|
|
292
|
+
action: "stats",
|
|
293
|
+
stats,
|
|
294
|
+
},
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
default:
|
|
299
|
+
return {
|
|
300
|
+
success: false,
|
|
301
|
+
error: "Unknown action: " + (params as { action: string }).action,
|
|
302
|
+
data: { action: (params as { action: string }).action as TrajectoryData["action"] },
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
} catch (error) {
|
|
306
|
+
return {
|
|
307
|
+
success: false,
|
|
308
|
+
error: error instanceof Error ? error.message : String(error),
|
|
309
|
+
data: { action: params.action },
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
};
|
|
314
|
+
|
|
315
|
+
// Auto-register
|
|
316
|
+
skillRegistry.register(trajectorySkill);
|
|
317
|
+
|
|
318
|
+
export { TrajectoryParams };
|
|
319
|
+
export type { TrajectoryData, LearnedPattern };
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GLM Daemon - Analyze Market Skill
|
|
3
|
+
*
|
|
4
|
+
* Analyze market conditions and identify trading opportunities.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
import type { Skill, SkillContext, SkillResult } from "../types.js";
|
|
9
|
+
import { skillRegistry } from "../registry.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Analyze market parameters
|
|
13
|
+
*/
|
|
14
|
+
const AnalyzeMarketParams = z.object({
|
|
15
|
+
/** Market symbol or ID */
|
|
16
|
+
symbol: z.string().optional(),
|
|
17
|
+
/** Analysis timeframe */
|
|
18
|
+
timeframe: z.enum(["short", "medium", "long"]).optional(),
|
|
19
|
+
/** Include sentiment analysis */
|
|
20
|
+
includeSentiment: z.boolean().optional(),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Market analysis result data
|
|
25
|
+
*/
|
|
26
|
+
interface AnalyzeMarketData {
|
|
27
|
+
trend: "bullish" | "bearish" | "sideways";
|
|
28
|
+
confidence: number;
|
|
29
|
+
supportLevels: number[];
|
|
30
|
+
resistanceLevels: number[];
|
|
31
|
+
indicators: {
|
|
32
|
+
rsi?: number;
|
|
33
|
+
macd?: string;
|
|
34
|
+
volume?: string;
|
|
35
|
+
};
|
|
36
|
+
signals: string[];
|
|
37
|
+
riskLevel: "low" | "medium" | "high";
|
|
38
|
+
marketCondition: "volatile" | "ranging" | "trending";
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Analyze market skill
|
|
43
|
+
*/
|
|
44
|
+
export const analyzeMarketSkill: Skill<z.infer<typeof AnalyzeMarketParams>, AnalyzeMarketData> = {
|
|
45
|
+
id: "/analyze-market",
|
|
46
|
+
name: "Analyze Market",
|
|
47
|
+
description: "Analyze market conditions using technical indicators and sentiment.",
|
|
48
|
+
paramsSchema: AnalyzeMarketParams,
|
|
49
|
+
tags: ["trading", "analysis"],
|
|
50
|
+
parallelizable: true,
|
|
51
|
+
produces: ["analysis", "riskLevel", "marketCondition"],
|
|
52
|
+
|
|
53
|
+
async execute(params, context): Promise<SkillResult<AnalyzeMarketData>> {
|
|
54
|
+
const symbol = params?.symbol || context.custom.symbol || "current market";
|
|
55
|
+
const timeframe = params?.timeframe || "medium";
|
|
56
|
+
|
|
57
|
+
console.log(`[/analyze-market] Analyzing ${symbol} (${timeframe} term)`);
|
|
58
|
+
|
|
59
|
+
const prompt = `Analyze current market conditions for ${symbol}.
|
|
60
|
+
|
|
61
|
+
Consider:
|
|
62
|
+
- Price action and trends
|
|
63
|
+
- Volume analysis
|
|
64
|
+
- Technical indicators (RSI, MACD, Moving Averages)
|
|
65
|
+
- Market sentiment
|
|
66
|
+
- News and events (if known)
|
|
67
|
+
- Support and resistance levels
|
|
68
|
+
- Timeframe: ${timeframe}
|
|
69
|
+
|
|
70
|
+
Provide analysis in JSON format:
|
|
71
|
+
{
|
|
72
|
+
"trend": "bullish|bearish|sideways",
|
|
73
|
+
"confidence": 0-100,
|
|
74
|
+
"supportLevels": [price levels],
|
|
75
|
+
"resistanceLevels": [price levels],
|
|
76
|
+
"indicators": {
|
|
77
|
+
"rsi": number,
|
|
78
|
+
"macd": "bullish|bearish|neutral",
|
|
79
|
+
"volume": "high|medium|low"
|
|
80
|
+
},
|
|
81
|
+
"signals": ["list of trading signals"],
|
|
82
|
+
"riskLevel": "low|medium|high",
|
|
83
|
+
"marketCondition": "volatile|ranging|trending"
|
|
84
|
+
}`;
|
|
85
|
+
|
|
86
|
+
try {
|
|
87
|
+
const response = await context.agent.execute(prompt);
|
|
88
|
+
|
|
89
|
+
// Parse JSON from response
|
|
90
|
+
const jsonMatch = response.match(/\{[\s\S]*\}/);
|
|
91
|
+
let data: AnalyzeMarketData;
|
|
92
|
+
|
|
93
|
+
if (jsonMatch) {
|
|
94
|
+
const parsed = JSON.parse(jsonMatch[0]);
|
|
95
|
+
data = {
|
|
96
|
+
trend: parsed.trend || "sideways",
|
|
97
|
+
confidence: parsed.confidence || 50,
|
|
98
|
+
supportLevels: parsed.supportLevels || [],
|
|
99
|
+
resistanceLevels: parsed.resistanceLevels || [],
|
|
100
|
+
indicators: parsed.indicators || {},
|
|
101
|
+
signals: parsed.signals || [],
|
|
102
|
+
riskLevel: parsed.riskLevel || "medium",
|
|
103
|
+
marketCondition: parsed.marketCondition || "ranging",
|
|
104
|
+
};
|
|
105
|
+
} else {
|
|
106
|
+
// Fallback
|
|
107
|
+
data = {
|
|
108
|
+
trend: "sideways",
|
|
109
|
+
confidence: 50,
|
|
110
|
+
supportLevels: [],
|
|
111
|
+
resistanceLevels: [],
|
|
112
|
+
indicators: {},
|
|
113
|
+
signals: ["Unable to parse analysis"],
|
|
114
|
+
riskLevel: "medium",
|
|
115
|
+
marketCondition: "ranging",
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
console.log(`[/analyze-market] Trend: ${data.trend} (${data.confidence}% confidence)`);
|
|
120
|
+
console.log(`[/analyze-market] Risk: ${data.riskLevel}, Condition: ${data.marketCondition}`);
|
|
121
|
+
console.log(`[/analyze-market] Signals: ${data.signals.length}`);
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
success: true,
|
|
125
|
+
data,
|
|
126
|
+
contextUpdates: {
|
|
127
|
+
analysis: data,
|
|
128
|
+
riskLevel: data.riskLevel,
|
|
129
|
+
marketCondition: data.marketCondition,
|
|
130
|
+
},
|
|
131
|
+
};
|
|
132
|
+
} catch (error) {
|
|
133
|
+
return {
|
|
134
|
+
success: false,
|
|
135
|
+
error: error instanceof Error ? error.message : String(error),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
skillRegistry.register(analyzeMarketSkill);
|
|
142
|
+
|
|
143
|
+
export { AnalyzeMarketParams };
|
|
144
|
+
export type { AnalyzeMarketData };
|