forge-openclaw-plugin 0.2.19 → 0.2.21
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 +133 -2
- package/dist/assets/board-_C6oMy5w.js +6 -0
- package/dist/assets/{board-8L3uX7_O.js.map → board-_C6oMy5w.js.map} +1 -1
- package/dist/assets/index-B4A6TooJ.js +63 -0
- package/dist/assets/index-B4A6TooJ.js.map +1 -0
- package/dist/assets/index-D6Xs_2mo.css +1 -0
- package/dist/assets/{motion-1GAqqi8M.js → motion-D4sZgCHd.js} +2 -2
- package/dist/assets/{motion-1GAqqi8M.js.map → motion-D4sZgCHd.js.map} +1 -1
- package/dist/assets/{table-DBGlgRjk.js → table-BWzTaky1.js} +2 -2
- package/dist/assets/{table-DBGlgRjk.js.map → table-BWzTaky1.js.map} +1 -1
- package/dist/assets/{ui-iTluWjC4.js → ui-BzK4azQb.js} +7 -7
- package/dist/assets/{ui-iTluWjC4.js.map → ui-BzK4azQb.js.map} +1 -1
- package/dist/assets/vendor-DT3pnAKJ.css +1 -0
- package/dist/assets/vendor-De38P6YR.js +729 -0
- package/dist/assets/vendor-De38P6YR.js.map +1 -0
- package/dist/assets/viz-C6hfyqzu.js +34 -0
- package/dist/assets/viz-C6hfyqzu.js.map +1 -0
- package/dist/index.html +9 -9
- package/dist/openclaw/parity.d.ts +1 -1
- package/dist/openclaw/parity.js +29 -2
- package/dist/openclaw/routes.js +207 -24
- package/dist/openclaw/tools.js +324 -35
- package/dist/server/app.js +2080 -92
- package/dist/server/db.js +3 -0
- package/dist/server/health.js +1284 -0
- package/dist/server/managers/platform/background-job-manager.js +138 -2
- package/dist/server/managers/platform/llm-manager.js +126 -0
- package/dist/server/managers/platform/openai-responses-provider.js +773 -0
- package/dist/server/managers/runtime.js +6 -1
- package/dist/server/openapi.js +718 -0
- package/dist/server/preferences-seeds.js +409 -0
- package/dist/server/preferences-types.js +368 -0
- package/dist/server/psyche-types.js +42 -18
- package/dist/server/repositories/activity-events.js +53 -4
- package/dist/server/repositories/calendar.js +89 -15
- package/dist/server/repositories/collaboration.js +8 -3
- package/dist/server/repositories/diagnostic-logs.js +243 -0
- package/dist/server/repositories/entity-ownership.js +92 -0
- package/dist/server/repositories/goals.js +7 -2
- package/dist/server/repositories/habits.js +122 -16
- package/dist/server/repositories/notes.js +119 -41
- package/dist/server/repositories/preferences.js +1765 -0
- package/dist/server/repositories/projects.js +18 -7
- package/dist/server/repositories/psyche.js +84 -27
- package/dist/server/repositories/rewards.js +112 -4
- package/dist/server/repositories/strategies.js +450 -0
- package/dist/server/repositories/tags.js +11 -6
- package/dist/server/repositories/task-runs.js +10 -2
- package/dist/server/repositories/tasks.js +99 -17
- package/dist/server/repositories/users.js +417 -0
- package/dist/server/repositories/wiki-memory.js +3366 -0
- package/dist/server/services/context.js +20 -18
- package/dist/server/services/dashboard.js +29 -6
- package/dist/server/services/entity-crud.js +21 -3
- package/dist/server/services/insights.js +9 -7
- package/dist/server/services/projects.js +2 -1
- package/dist/server/services/psyche.js +10 -9
- package/dist/server/types.js +594 -30
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/server/migrations/015_multi_user_and_strategies.sql +244 -0
- package/server/migrations/016_health_companion.sql +158 -0
- package/server/migrations/016_strategy_contracts_and_user_graph.sql +22 -0
- package/server/migrations/017_preferences.sql +131 -0
- package/server/migrations/018_preference_catalogs.sql +31 -0
- package/server/migrations/019_wiki_memory.sql +255 -0
- package/server/migrations/020_wiki_page_hierarchy.sql +11 -0
- package/server/migrations/021_hide_evidence_from_wiki_index.sql +3 -0
- package/server/migrations/022_wiki_ingest_background.sql +85 -0
- package/server/migrations/023_diagnostic_logs.sql +28 -0
- package/skills/forge-openclaw/SKILL.md +126 -34
- package/skills/forge-openclaw/entity_conversation_playbooks.md +337 -0
- package/skills/forge-openclaw/psyche_entity_playbooks.md +404 -0
- package/dist/assets/board-8L3uX7_O.js +0 -6
- package/dist/assets/index-Cj1IBH_w.js +0 -36
- package/dist/assets/index-Cj1IBH_w.js.map +0 -1
- package/dist/assets/index-DQT6EbuS.css +0 -1
- package/dist/assets/vendor-BvM2F9Dp.js +0 -503
- package/dist/assets/vendor-BvM2F9Dp.js.map +0 -1
- package/dist/assets/vendor-CRS-psbw.css +0 -1
- package/dist/assets/viz-CNeunkfu.js +0 -34
- package/dist/assets/viz-CNeunkfu.js.map +0 -1
|
@@ -1,10 +1,146 @@
|
|
|
1
1
|
import { AbstractManager } from "../base.js";
|
|
2
|
+
import { recordDiagnosticLog } from "../../repositories/diagnostic-logs.js";
|
|
2
3
|
export class BackgroundJobManager extends AbstractManager {
|
|
4
|
+
maxConcurrentJobs;
|
|
3
5
|
name = "BackgroundJobManager";
|
|
6
|
+
queue = [];
|
|
7
|
+
active = new Set();
|
|
8
|
+
draining = false;
|
|
9
|
+
constructor(maxConcurrentJobs = 3) {
|
|
10
|
+
super();
|
|
11
|
+
this.maxConcurrentJobs = maxConcurrentJobs;
|
|
12
|
+
}
|
|
4
13
|
start() {
|
|
5
14
|
return;
|
|
6
15
|
}
|
|
7
|
-
|
|
8
|
-
|
|
16
|
+
enqueue(input) {
|
|
17
|
+
if (this.has(input.id)) {
|
|
18
|
+
this.recordLifecycleLog("info", "background_job_enqueue_skipped", {
|
|
19
|
+
task: input,
|
|
20
|
+
message: `Skipped duplicate background job ${input.label}.`,
|
|
21
|
+
details: {
|
|
22
|
+
queueDepth: this.queue.length,
|
|
23
|
+
activeCount: this.active.size
|
|
24
|
+
},
|
|
25
|
+
functionName: "enqueue"
|
|
26
|
+
});
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
this.queue.push(input);
|
|
30
|
+
this.recordLifecycleLog("info", "background_job_enqueued", {
|
|
31
|
+
task: input,
|
|
32
|
+
message: `Enqueued background job ${input.label}.`,
|
|
33
|
+
details: {
|
|
34
|
+
queueDepth: this.queue.length,
|
|
35
|
+
activeCount: this.active.size
|
|
36
|
+
},
|
|
37
|
+
functionName: "enqueue"
|
|
38
|
+
});
|
|
39
|
+
this.scheduleDrain();
|
|
40
|
+
}
|
|
41
|
+
isActive(jobId) {
|
|
42
|
+
return this.active.has(jobId);
|
|
43
|
+
}
|
|
44
|
+
has(jobId) {
|
|
45
|
+
return (this.active.has(jobId) || this.queue.some((task) => task.id === jobId));
|
|
46
|
+
}
|
|
47
|
+
async stop() {
|
|
48
|
+
this.draining = true;
|
|
49
|
+
while (this.active.size > 0) {
|
|
50
|
+
await new Promise((resolve) => setTimeout(resolve, 25));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
scheduleDrain() {
|
|
54
|
+
if (this.draining ||
|
|
55
|
+
this.queue.length === 0 ||
|
|
56
|
+
this.active.size >= this.maxConcurrentJobs) {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
queueMicrotask(() => {
|
|
60
|
+
void this.drainAvailable();
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
async drainAvailable() {
|
|
64
|
+
if (this.draining) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
while (!this.draining &&
|
|
68
|
+
this.queue.length > 0 &&
|
|
69
|
+
this.active.size < this.maxConcurrentJobs) {
|
|
70
|
+
const next = this.queue.shift();
|
|
71
|
+
if (!next) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
this.active.add(next.id);
|
|
75
|
+
void this.runTask(next);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async runTask(next) {
|
|
79
|
+
const startedAt = Date.now();
|
|
80
|
+
this.recordLifecycleLog("info", "background_job_started", {
|
|
81
|
+
task: next,
|
|
82
|
+
message: `Started background job ${next.label}.`,
|
|
83
|
+
details: {
|
|
84
|
+
queueDepth: this.queue.length,
|
|
85
|
+
activeCount: this.active.size,
|
|
86
|
+
maxConcurrentJobs: this.maxConcurrentJobs
|
|
87
|
+
},
|
|
88
|
+
functionName: "runTask"
|
|
89
|
+
});
|
|
90
|
+
try {
|
|
91
|
+
await next.handler();
|
|
92
|
+
this.recordLifecycleLog("info", "background_job_completed", {
|
|
93
|
+
task: next,
|
|
94
|
+
message: `Completed background job ${next.label}.`,
|
|
95
|
+
details: {
|
|
96
|
+
durationMs: Date.now() - startedAt,
|
|
97
|
+
queueDepth: this.queue.length,
|
|
98
|
+
activeCount: this.active.size,
|
|
99
|
+
maxConcurrentJobs: this.maxConcurrentJobs
|
|
100
|
+
},
|
|
101
|
+
functionName: "runTask"
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
this.recordLifecycleLog("error", "background_job_failed", {
|
|
106
|
+
task: next,
|
|
107
|
+
message: `Background job failed for ${next.label}.`,
|
|
108
|
+
details: {
|
|
109
|
+
durationMs: Date.now() - startedAt,
|
|
110
|
+
queueDepth: this.queue.length,
|
|
111
|
+
activeCount: this.active.size,
|
|
112
|
+
maxConcurrentJobs: this.maxConcurrentJobs,
|
|
113
|
+
error
|
|
114
|
+
},
|
|
115
|
+
functionName: "runTask"
|
|
116
|
+
});
|
|
117
|
+
console.error(`[${this.name}] background job failed for ${next.label}:`, error);
|
|
118
|
+
}
|
|
119
|
+
finally {
|
|
120
|
+
this.active.delete(next.id);
|
|
121
|
+
this.scheduleDrain();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
recordLifecycleLog(level, eventKey, input) {
|
|
125
|
+
try {
|
|
126
|
+
recordDiagnosticLog({
|
|
127
|
+
level,
|
|
128
|
+
source: "system",
|
|
129
|
+
scope: "background_job",
|
|
130
|
+
eventKey,
|
|
131
|
+
message: input.message,
|
|
132
|
+
functionName: input.functionName,
|
|
133
|
+
entityType: "background_job",
|
|
134
|
+
entityId: input.task.id,
|
|
135
|
+
jobId: input.task.id,
|
|
136
|
+
details: {
|
|
137
|
+
label: input.task.label,
|
|
138
|
+
...(input.details ?? {})
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
// Diagnostics should never block job execution.
|
|
144
|
+
}
|
|
9
145
|
}
|
|
10
146
|
}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { AbstractManager } from "../base.js";
|
|
2
|
+
import { readEncryptedSecret } from "../../repositories/calendar.js";
|
|
3
|
+
function emitDiagnostic(logger, input) {
|
|
4
|
+
logger?.(input);
|
|
5
|
+
}
|
|
6
|
+
export class LlmManager extends AbstractManager {
|
|
7
|
+
secretsManager;
|
|
8
|
+
name = "LlmManager";
|
|
9
|
+
providers = new Map();
|
|
10
|
+
constructor(secretsManager) {
|
|
11
|
+
super();
|
|
12
|
+
this.secretsManager = secretsManager;
|
|
13
|
+
}
|
|
14
|
+
register(provider) {
|
|
15
|
+
for (const alias of provider.providerNames) {
|
|
16
|
+
this.providers.set(alias, provider);
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
async compileWikiIngest(profile, input, options = {}, logger) {
|
|
20
|
+
const provider = this.resolveProvider(profile.provider);
|
|
21
|
+
if (!provider) {
|
|
22
|
+
emitDiagnostic(logger, {
|
|
23
|
+
level: "error",
|
|
24
|
+
message: "Wiki ingest LLM provider is not supported.",
|
|
25
|
+
details: {
|
|
26
|
+
scope: "wiki_llm",
|
|
27
|
+
eventKey: "llm_provider_missing",
|
|
28
|
+
provider: profile.provider,
|
|
29
|
+
baseUrl: profile.baseUrl,
|
|
30
|
+
model: profile.model
|
|
31
|
+
}
|
|
32
|
+
});
|
|
33
|
+
return null;
|
|
34
|
+
}
|
|
35
|
+
const apiKey = this.readApiKey(profile.secretId);
|
|
36
|
+
if (!apiKey) {
|
|
37
|
+
emitDiagnostic(logger, {
|
|
38
|
+
level: "error",
|
|
39
|
+
message: "Wiki ingest LLM profile is missing an API key.",
|
|
40
|
+
details: {
|
|
41
|
+
scope: "wiki_llm",
|
|
42
|
+
eventKey: "llm_api_key_missing",
|
|
43
|
+
provider: profile.provider,
|
|
44
|
+
baseUrl: profile.baseUrl,
|
|
45
|
+
model: profile.model,
|
|
46
|
+
secretId: profile.secretId ?? null
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
return provider.compile({
|
|
52
|
+
apiKey,
|
|
53
|
+
profile,
|
|
54
|
+
input,
|
|
55
|
+
resumeResponseId: options.resumeResponseId ?? null,
|
|
56
|
+
logger
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
async testWikiConnection(profile, explicitApiKey, logger) {
|
|
60
|
+
const provider = this.resolveProvider(profile.provider);
|
|
61
|
+
if (!provider) {
|
|
62
|
+
emitDiagnostic(logger, {
|
|
63
|
+
level: "error",
|
|
64
|
+
message: "Wiki LLM connection test requested an unsupported provider.",
|
|
65
|
+
details: {
|
|
66
|
+
scope: "wiki_llm",
|
|
67
|
+
eventKey: "llm_provider_missing",
|
|
68
|
+
provider: profile.provider,
|
|
69
|
+
baseUrl: profile.baseUrl,
|
|
70
|
+
model: profile.model
|
|
71
|
+
}
|
|
72
|
+
});
|
|
73
|
+
throw new Error("Unsupported LLM provider.");
|
|
74
|
+
}
|
|
75
|
+
const apiKey = explicitApiKey?.trim() || this.readApiKey(profile.secretId);
|
|
76
|
+
if (!apiKey) {
|
|
77
|
+
emitDiagnostic(logger, {
|
|
78
|
+
level: "error",
|
|
79
|
+
message: "Wiki LLM connection test is missing an API key.",
|
|
80
|
+
details: {
|
|
81
|
+
scope: "wiki_llm",
|
|
82
|
+
eventKey: "llm_api_key_missing",
|
|
83
|
+
provider: profile.provider,
|
|
84
|
+
baseUrl: profile.baseUrl,
|
|
85
|
+
model: profile.model,
|
|
86
|
+
secretId: profile.secretId ?? null
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
throw new Error("Save an OpenAI API key first.");
|
|
90
|
+
}
|
|
91
|
+
const result = await provider.testConnection({
|
|
92
|
+
apiKey,
|
|
93
|
+
profile,
|
|
94
|
+
logger
|
|
95
|
+
});
|
|
96
|
+
return {
|
|
97
|
+
provider: profile.provider,
|
|
98
|
+
model: profile.model,
|
|
99
|
+
baseUrl: profile.baseUrl,
|
|
100
|
+
reasoningEffort: typeof profile.metadata.reasoningEffort === "string"
|
|
101
|
+
? profile.metadata.reasoningEffort
|
|
102
|
+
: null,
|
|
103
|
+
verbosity: typeof profile.metadata.verbosity === "string"
|
|
104
|
+
? profile.metadata.verbosity
|
|
105
|
+
: null,
|
|
106
|
+
usingStoredKey: !explicitApiKey?.trim(),
|
|
107
|
+
outputPreview: result.outputPreview
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
resolveProvider(providerName) {
|
|
111
|
+
return (this.providers.get(providerName) ??
|
|
112
|
+
this.providers.get("openai-responses") ??
|
|
113
|
+
null);
|
|
114
|
+
}
|
|
115
|
+
readApiKey(secretId) {
|
|
116
|
+
if (!secretId) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
const cipherText = readEncryptedSecret(secretId);
|
|
120
|
+
if (!cipherText) {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
const payload = this.secretsManager.openJson(cipherText);
|
|
124
|
+
return payload.apiKey?.trim() || null;
|
|
125
|
+
}
|
|
126
|
+
}
|