forge-openclaw-plugin 0.2.47 → 0.2.49
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 +6 -5
- package/dist/assets/index-2_tuemtU.css +1 -0
- package/dist/assets/index-BAmEvOXb.js +91 -0
- package/dist/assets/index-BAmEvOXb.js.map +1 -0
- package/dist/index.html +2 -2
- package/dist/openclaw/api-client.js +15 -1
- package/dist/openclaw/session-registry.js +17 -0
- package/dist/openclaw/tools.js +1 -1
- package/dist/server/server/migrations/052_agent_identity_tightening.sql +307 -0
- package/dist/server/server/migrations/053_agent_runtime_session_canonical_labels.sql +9 -0
- package/dist/server/server/src/app.js +42 -12
- package/dist/server/server/src/health-workout-adapters.js +465 -0
- package/dist/server/server/src/health.js +134 -9
- package/dist/server/server/src/openapi.js +33 -0
- package/dist/server/server/src/repositories/agent-runtime-sessions.js +122 -16
- package/dist/server/server/src/repositories/habits.js +62 -25
- package/dist/server/server/src/repositories/model-settings.js +5 -0
- package/dist/server/server/src/repositories/settings.js +101 -13
- package/dist/server/server/src/repositories/users.js +23 -0
- package/dist/server/server/src/types.js +22 -6
- package/dist/server/server/src/watch-mobile.js +33 -21
- package/dist/server/src/lib/date-keys.js +21 -0
- package/openclaw.plugin.json +1 -1
- package/package.json +5 -2
- package/server/migrations/052_agent_identity_tightening.sql +307 -0
- package/server/migrations/053_agent_runtime_session_canonical_labels.sql +9 -0
- package/skills/forge-openclaw/SKILL.md +3 -1
- package/skills/forge-openclaw/entity_conversation_playbooks.md +45 -8
- package/skills/forge-openclaw/psyche_entity_playbooks.md +14 -0
- package/dist/assets/index-BejDHw1R.js +0 -91
- package/dist/assets/index-BejDHw1R.js.map +0 -1
- package/dist/assets/index-DtEvFzXp.css +0 -1
package/dist/index.html
CHANGED
|
@@ -13,14 +13,14 @@
|
|
|
13
13
|
/>
|
|
14
14
|
<link rel="icon" type="image/png" href="/forge/assets/favicon-BCHm9dUV.ico" />
|
|
15
15
|
<link rel="alternate icon" href="/forge/assets/favicon-BCHm9dUV.ico" />
|
|
16
|
-
<script type="module" crossorigin src="/forge/assets/index-
|
|
16
|
+
<script type="module" crossorigin src="/forge/assets/index-BAmEvOXb.js"></script>
|
|
17
17
|
<link rel="modulepreload" crossorigin href="/forge/assets/vendor-D_NZFJze.js">
|
|
18
18
|
<link rel="modulepreload" crossorigin href="/forge/assets/board-CAszQU7Y.js">
|
|
19
19
|
<link rel="modulepreload" crossorigin href="/forge/assets/ui-B5MjRjKe.js">
|
|
20
20
|
<link rel="modulepreload" crossorigin href="/forge/assets/motion-CU5aNClV.js">
|
|
21
21
|
<link rel="modulepreload" crossorigin href="/forge/assets/table-CK0KcPYW.js">
|
|
22
22
|
<link rel="stylesheet" crossorigin href="/forge/assets/vendor-DT3pnAKJ.css">
|
|
23
|
-
<link rel="stylesheet" crossorigin href="/forge/assets/index-
|
|
23
|
+
<link rel="stylesheet" crossorigin href="/forge/assets/index-2_tuemtU.css">
|
|
24
24
|
</head>
|
|
25
25
|
<body class="bg-canvas text-ink antialiased">
|
|
26
26
|
<div id="root"></div>
|
|
@@ -46,6 +46,20 @@ export function canBootstrapOperatorSession(baseUrl) {
|
|
|
46
46
|
function isRecord(value) {
|
|
47
47
|
return typeof value === "object" && value !== null;
|
|
48
48
|
}
|
|
49
|
+
function extractUpstreamErrorCode(body) {
|
|
50
|
+
return isRecord(body) &&
|
|
51
|
+
isRecord(body.error) &&
|
|
52
|
+
typeof body.error.code === "string"
|
|
53
|
+
? body.error.code
|
|
54
|
+
: null;
|
|
55
|
+
}
|
|
56
|
+
function buildGuidedUpstreamMessage(result, fallback) {
|
|
57
|
+
const upstreamCode = extractUpstreamErrorCode(result.body);
|
|
58
|
+
if (result.status === 401 && upstreamCode === "auth_required") {
|
|
59
|
+
return `${fallback} In OpenClaw, do not fall back to raw Forge routes. Call forge_get_agent_onboarding, then use the shared plugin tools. For official habit outcomes, use forge_update_entities on entityType "habit" with patch.checkIn instead of a direct check-in route call.`;
|
|
60
|
+
}
|
|
61
|
+
return fallback;
|
|
62
|
+
}
|
|
49
63
|
function buildErrorBody(code, message) {
|
|
50
64
|
return {
|
|
51
65
|
ok: false,
|
|
@@ -342,7 +356,7 @@ export function expectForgeSuccess(result) {
|
|
|
342
356
|
typeof result.body.error.message === "string"
|
|
343
357
|
? result.body.error.message
|
|
344
358
|
: `Forge API returned ${result.status}`;
|
|
345
|
-
throw new ForgePluginError(result.status, "forge_plugin_upstream_error", message);
|
|
359
|
+
throw new ForgePluginError(result.status, "forge_plugin_upstream_error", buildGuidedUpstreamMessage(result, message));
|
|
346
360
|
}
|
|
347
361
|
return result.body;
|
|
348
362
|
}
|
|
@@ -1,8 +1,22 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
1
2
|
import { isAgentBootstrapEvent } from "openclaw/plugin-sdk/hook-runtime";
|
|
2
3
|
import { callConfiguredForgeApi, expectForgeSuccess, resolveConfiguredForgeActorLabel } from "./api-client.js";
|
|
3
4
|
const SESSION_IDS = new Map();
|
|
4
5
|
const SESSION_PROVIDER = "openclaw";
|
|
5
6
|
const DEFAULT_RUNTIME_AGENT_LABEL = "Forge OpenClaw";
|
|
7
|
+
function shortHash(value) {
|
|
8
|
+
return createHash("sha1").update(value).digest("hex").slice(0, 12);
|
|
9
|
+
}
|
|
10
|
+
function buildStableMachineKey(config) {
|
|
11
|
+
const source = JSON.stringify({
|
|
12
|
+
baseUrl: config.baseUrl,
|
|
13
|
+
dataRoot: config.dataRoot || ""
|
|
14
|
+
});
|
|
15
|
+
return `machine_${shortHash(source)}`;
|
|
16
|
+
}
|
|
17
|
+
function buildStableAgentIdentityKey(config) {
|
|
18
|
+
return `runtime:${SESSION_PROVIDER}:${buildStableMachineKey(config)}:default`;
|
|
19
|
+
}
|
|
6
20
|
function isRecord(value) {
|
|
7
21
|
return typeof value === "object" && value !== null;
|
|
8
22
|
}
|
|
@@ -40,6 +54,9 @@ async function registerSession(config, sessionKey, metadata) {
|
|
|
40
54
|
provider: SESSION_PROVIDER,
|
|
41
55
|
agentLabel: process.env.FORGE_AGENT_LABEL?.trim() || DEFAULT_RUNTIME_AGENT_LABEL,
|
|
42
56
|
agentType: SESSION_PROVIDER,
|
|
57
|
+
agentIdentityKey: buildStableAgentIdentityKey(config),
|
|
58
|
+
machineKey: buildStableMachineKey(config),
|
|
59
|
+
personaKey: "default",
|
|
43
60
|
actorLabel,
|
|
44
61
|
sessionKey,
|
|
45
62
|
sessionLabel: sessionKey,
|
package/dist/openclaw/tools.js
CHANGED
|
@@ -848,7 +848,7 @@ export function registerForgePluginTools(api, config) {
|
|
|
848
848
|
registerWriteTool(api, config, {
|
|
849
849
|
name: "forge_update_entities",
|
|
850
850
|
label: "Update Forge Entities",
|
|
851
|
-
description: "Update one or more Forge entities through the ordered batch workflow. Pass `operations` as an array. Each operation must include `entityType`, `id`, and `patch`. This is the preferred update path for calendar_event, work_block_template, task_timebox, preferences basic CRUD entities, and
|
|
851
|
+
description: "Update one or more Forge entities through the ordered batch workflow. Pass `operations` as an array. Each operation must include `entityType`, `id`, and `patch`. This is the preferred update path for calendar_event, work_block_template, task_timebox, preferences basic CRUD entities, questionnaire_instrument, and official habit outcome logging through `habit.patch.checkIn`.",
|
|
852
852
|
parameters: Type.Object({
|
|
853
853
|
atomic: Type.Optional(Type.Boolean()),
|
|
854
854
|
operations: Type.Array(Type.Object({
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
ALTER TABLE agent_identities ADD COLUMN identity_key TEXT;
|
|
2
|
+
ALTER TABLE agent_identities ADD COLUMN provider TEXT;
|
|
3
|
+
ALTER TABLE agent_identities ADD COLUMN machine_key TEXT;
|
|
4
|
+
ALTER TABLE agent_identities ADD COLUMN persona_key TEXT;
|
|
5
|
+
|
|
6
|
+
CREATE TABLE IF NOT EXISTS agent_identity_users (
|
|
7
|
+
agent_id TEXT NOT NULL REFERENCES agent_identities(id) ON DELETE CASCADE,
|
|
8
|
+
user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
|
9
|
+
role TEXT NOT NULL DEFAULT 'linked',
|
|
10
|
+
created_at TEXT NOT NULL,
|
|
11
|
+
updated_at TEXT NOT NULL,
|
|
12
|
+
PRIMARY KEY (agent_id, user_id)
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
CREATE INDEX IF NOT EXISTS idx_agent_identity_users_user
|
|
16
|
+
ON agent_identity_users(user_id, role);
|
|
17
|
+
|
|
18
|
+
INSERT OR IGNORE INTO users (
|
|
19
|
+
id, kind, handle, display_name, description, accent_color, created_at, updated_at
|
|
20
|
+
) VALUES
|
|
21
|
+
('user_agent_openclaw', 'bot', 'openclaw', 'OpenClaw', 'OpenClaw runtime actor linked to Forge agent identity and Kanban ownership.', '#38bdf8', datetime('now'), datetime('now')),
|
|
22
|
+
('user_agent_hermes', 'bot', 'hermes', 'Hermes', 'Hermes runtime actor linked to Forge agent identity and Kanban ownership.', '#a78bfa', datetime('now'), datetime('now')),
|
|
23
|
+
('user_agent_codex', 'bot', 'codex', 'Codex', 'Codex runtime actor linked to Forge agent identity and Kanban ownership.', '#22c55e', datetime('now'), datetime('now'));
|
|
24
|
+
|
|
25
|
+
UPDATE agent_tokens
|
|
26
|
+
SET agent_id = (
|
|
27
|
+
SELECT id FROM agent_identities
|
|
28
|
+
WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
|
|
29
|
+
ORDER BY CASE WHEN lower(label) = 'forge openclaw' THEN 0 ELSE 1 END, created_at ASC
|
|
30
|
+
LIMIT 1
|
|
31
|
+
)
|
|
32
|
+
WHERE agent_id IN (
|
|
33
|
+
SELECT id FROM agent_identities
|
|
34
|
+
WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
|
|
35
|
+
)
|
|
36
|
+
AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')) > 0;
|
|
37
|
+
|
|
38
|
+
UPDATE agent_actions
|
|
39
|
+
SET agent_id = (
|
|
40
|
+
SELECT id FROM agent_identities
|
|
41
|
+
WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
|
|
42
|
+
ORDER BY CASE WHEN lower(label) = 'forge openclaw' THEN 0 ELSE 1 END, created_at ASC
|
|
43
|
+
LIMIT 1
|
|
44
|
+
)
|
|
45
|
+
WHERE agent_id IN (
|
|
46
|
+
SELECT id FROM agent_identities
|
|
47
|
+
WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
|
|
48
|
+
)
|
|
49
|
+
AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')) > 0;
|
|
50
|
+
|
|
51
|
+
UPDATE approval_requests
|
|
52
|
+
SET requested_by_agent_id = (
|
|
53
|
+
SELECT id FROM agent_identities
|
|
54
|
+
WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
|
|
55
|
+
ORDER BY CASE WHEN lower(label) = 'forge openclaw' THEN 0 ELSE 1 END, created_at ASC
|
|
56
|
+
LIMIT 1
|
|
57
|
+
)
|
|
58
|
+
WHERE requested_by_agent_id IN (
|
|
59
|
+
SELECT id FROM agent_identities
|
|
60
|
+
WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
|
|
61
|
+
)
|
|
62
|
+
AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')) > 0;
|
|
63
|
+
|
|
64
|
+
UPDATE insights
|
|
65
|
+
SET origin_agent_id = (
|
|
66
|
+
SELECT id FROM agent_identities
|
|
67
|
+
WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
|
|
68
|
+
ORDER BY CASE WHEN lower(label) = 'forge openclaw' THEN 0 ELSE 1 END, created_at ASC
|
|
69
|
+
LIMIT 1
|
|
70
|
+
)
|
|
71
|
+
WHERE origin_agent_id IN (
|
|
72
|
+
SELECT id FROM agent_identities
|
|
73
|
+
WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
|
|
74
|
+
)
|
|
75
|
+
AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')) > 0;
|
|
76
|
+
|
|
77
|
+
UPDATE agent_runtime_sessions
|
|
78
|
+
SET agent_id = (
|
|
79
|
+
SELECT id FROM agent_identities
|
|
80
|
+
WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
|
|
81
|
+
ORDER BY CASE WHEN lower(label) = 'forge openclaw' THEN 0 ELSE 1 END, created_at ASC
|
|
82
|
+
LIMIT 1
|
|
83
|
+
)
|
|
84
|
+
WHERE agent_id IN (
|
|
85
|
+
SELECT id FROM agent_identities
|
|
86
|
+
WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
|
|
87
|
+
)
|
|
88
|
+
AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')) > 0;
|
|
89
|
+
|
|
90
|
+
DELETE FROM agent_identities
|
|
91
|
+
WHERE (lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel'))
|
|
92
|
+
AND id <> (
|
|
93
|
+
SELECT id FROM agent_identities
|
|
94
|
+
WHERE lower(agent_type) = 'openclaw' OR lower(label) IN ('forge openclaw', 'openclaw', 'aurel')
|
|
95
|
+
ORDER BY CASE WHEN lower(label) = 'forge openclaw' THEN 0 ELSE 1 END, created_at ASC
|
|
96
|
+
LIMIT 1
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
UPDATE agent_identities
|
|
100
|
+
SET label = 'Forge OpenClaw',
|
|
101
|
+
agent_type = 'openclaw',
|
|
102
|
+
provider = 'openclaw',
|
|
103
|
+
identity_key = 'runtime:openclaw:legacy:default',
|
|
104
|
+
machine_key = 'legacy',
|
|
105
|
+
persona_key = 'default',
|
|
106
|
+
description = 'OpenClaw runtime agent with stable Forge identity and linked Kanban user.',
|
|
107
|
+
updated_at = datetime('now')
|
|
108
|
+
WHERE lower(agent_type) = 'openclaw' OR lower(label) = 'forge openclaw';
|
|
109
|
+
|
|
110
|
+
UPDATE agent_tokens
|
|
111
|
+
SET agent_id = (
|
|
112
|
+
SELECT id FROM agent_identities
|
|
113
|
+
WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
|
|
114
|
+
ORDER BY CASE WHEN lower(label) = 'forge hermes' THEN 0 ELSE 1 END, created_at ASC
|
|
115
|
+
LIMIT 1
|
|
116
|
+
)
|
|
117
|
+
WHERE agent_id IN (
|
|
118
|
+
SELECT id FROM agent_identities
|
|
119
|
+
WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
|
|
120
|
+
)
|
|
121
|
+
AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%') > 0;
|
|
122
|
+
|
|
123
|
+
UPDATE agent_actions
|
|
124
|
+
SET agent_id = (
|
|
125
|
+
SELECT id FROM agent_identities
|
|
126
|
+
WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
|
|
127
|
+
ORDER BY CASE WHEN lower(label) = 'forge hermes' THEN 0 ELSE 1 END, created_at ASC
|
|
128
|
+
LIMIT 1
|
|
129
|
+
)
|
|
130
|
+
WHERE agent_id IN (
|
|
131
|
+
SELECT id FROM agent_identities
|
|
132
|
+
WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
|
|
133
|
+
)
|
|
134
|
+
AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%') > 0;
|
|
135
|
+
|
|
136
|
+
UPDATE approval_requests
|
|
137
|
+
SET requested_by_agent_id = (
|
|
138
|
+
SELECT id FROM agent_identities
|
|
139
|
+
WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
|
|
140
|
+
ORDER BY CASE WHEN lower(label) = 'forge hermes' THEN 0 ELSE 1 END, created_at ASC
|
|
141
|
+
LIMIT 1
|
|
142
|
+
)
|
|
143
|
+
WHERE requested_by_agent_id IN (
|
|
144
|
+
SELECT id FROM agent_identities
|
|
145
|
+
WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
|
|
146
|
+
)
|
|
147
|
+
AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%') > 0;
|
|
148
|
+
|
|
149
|
+
UPDATE insights
|
|
150
|
+
SET origin_agent_id = (
|
|
151
|
+
SELECT id FROM agent_identities
|
|
152
|
+
WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
|
|
153
|
+
ORDER BY CASE WHEN lower(label) = 'forge hermes' THEN 0 ELSE 1 END, created_at ASC
|
|
154
|
+
LIMIT 1
|
|
155
|
+
)
|
|
156
|
+
WHERE origin_agent_id IN (
|
|
157
|
+
SELECT id FROM agent_identities
|
|
158
|
+
WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
|
|
159
|
+
)
|
|
160
|
+
AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%') > 0;
|
|
161
|
+
|
|
162
|
+
UPDATE agent_runtime_sessions
|
|
163
|
+
SET agent_id = (
|
|
164
|
+
SELECT id FROM agent_identities
|
|
165
|
+
WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
|
|
166
|
+
ORDER BY CASE WHEN lower(label) = 'forge hermes' THEN 0 ELSE 1 END, created_at ASC
|
|
167
|
+
LIMIT 1
|
|
168
|
+
)
|
|
169
|
+
WHERE agent_id IN (
|
|
170
|
+
SELECT id FROM agent_identities
|
|
171
|
+
WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
|
|
172
|
+
)
|
|
173
|
+
AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%') > 0;
|
|
174
|
+
|
|
175
|
+
DELETE FROM agent_identities
|
|
176
|
+
WHERE (lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%')
|
|
177
|
+
AND id <> (
|
|
178
|
+
SELECT id FROM agent_identities
|
|
179
|
+
WHERE lower(agent_type) = 'hermes' OR lower(label) LIKE 'forge hermes%'
|
|
180
|
+
ORDER BY CASE WHEN lower(label) = 'forge hermes' THEN 0 ELSE 1 END, created_at ASC
|
|
181
|
+
LIMIT 1
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
UPDATE agent_identities
|
|
185
|
+
SET label = 'Forge Hermes',
|
|
186
|
+
agent_type = 'hermes',
|
|
187
|
+
provider = 'hermes',
|
|
188
|
+
identity_key = 'runtime:hermes:legacy:default',
|
|
189
|
+
machine_key = 'legacy',
|
|
190
|
+
persona_key = 'default',
|
|
191
|
+
description = 'Hermes runtime agent with stable Forge identity and linked Kanban user.',
|
|
192
|
+
updated_at = datetime('now')
|
|
193
|
+
WHERE lower(agent_type) = 'hermes' OR lower(label) = 'forge hermes';
|
|
194
|
+
|
|
195
|
+
UPDATE agent_tokens
|
|
196
|
+
SET agent_id = (
|
|
197
|
+
SELECT id FROM agent_identities
|
|
198
|
+
WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
|
|
199
|
+
ORDER BY CASE WHEN lower(label) = 'forge codex' THEN 0 ELSE 1 END, created_at ASC
|
|
200
|
+
LIMIT 1
|
|
201
|
+
)
|
|
202
|
+
WHERE agent_id IN (
|
|
203
|
+
SELECT id FROM agent_identities
|
|
204
|
+
WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
|
|
205
|
+
)
|
|
206
|
+
AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')) > 0;
|
|
207
|
+
|
|
208
|
+
UPDATE agent_actions
|
|
209
|
+
SET agent_id = (
|
|
210
|
+
SELECT id FROM agent_identities
|
|
211
|
+
WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
|
|
212
|
+
ORDER BY CASE WHEN lower(label) = 'forge codex' THEN 0 ELSE 1 END, created_at ASC
|
|
213
|
+
LIMIT 1
|
|
214
|
+
)
|
|
215
|
+
WHERE agent_id IN (
|
|
216
|
+
SELECT id FROM agent_identities
|
|
217
|
+
WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
|
|
218
|
+
)
|
|
219
|
+
AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')) > 0;
|
|
220
|
+
|
|
221
|
+
UPDATE approval_requests
|
|
222
|
+
SET requested_by_agent_id = (
|
|
223
|
+
SELECT id FROM agent_identities
|
|
224
|
+
WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
|
|
225
|
+
ORDER BY CASE WHEN lower(label) = 'forge codex' THEN 0 ELSE 1 END, created_at ASC
|
|
226
|
+
LIMIT 1
|
|
227
|
+
)
|
|
228
|
+
WHERE requested_by_agent_id IN (
|
|
229
|
+
SELECT id FROM agent_identities
|
|
230
|
+
WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
|
|
231
|
+
)
|
|
232
|
+
AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')) > 0;
|
|
233
|
+
|
|
234
|
+
UPDATE insights
|
|
235
|
+
SET origin_agent_id = (
|
|
236
|
+
SELECT id FROM agent_identities
|
|
237
|
+
WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
|
|
238
|
+
ORDER BY CASE WHEN lower(label) = 'forge codex' THEN 0 ELSE 1 END, created_at ASC
|
|
239
|
+
LIMIT 1
|
|
240
|
+
)
|
|
241
|
+
WHERE origin_agent_id IN (
|
|
242
|
+
SELECT id FROM agent_identities
|
|
243
|
+
WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
|
|
244
|
+
)
|
|
245
|
+
AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')) > 0;
|
|
246
|
+
|
|
247
|
+
UPDATE agent_runtime_sessions
|
|
248
|
+
SET agent_id = (
|
|
249
|
+
SELECT id FROM agent_identities
|
|
250
|
+
WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
|
|
251
|
+
ORDER BY CASE WHEN lower(label) = 'forge codex' THEN 0 ELSE 1 END, created_at ASC
|
|
252
|
+
LIMIT 1
|
|
253
|
+
)
|
|
254
|
+
WHERE agent_id IN (
|
|
255
|
+
SELECT id FROM agent_identities
|
|
256
|
+
WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
|
|
257
|
+
)
|
|
258
|
+
AND (SELECT COUNT(*) FROM agent_identities WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')) > 0;
|
|
259
|
+
|
|
260
|
+
DELETE FROM agent_identities
|
|
261
|
+
WHERE (lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)'))
|
|
262
|
+
AND id <> (
|
|
263
|
+
SELECT id FROM agent_identities
|
|
264
|
+
WHERE lower(agent_type) = 'codex' OR lower(label) IN ('forge codex', 'codex', 'albert (codex)')
|
|
265
|
+
ORDER BY CASE WHEN lower(label) = 'forge codex' THEN 0 ELSE 1 END, created_at ASC
|
|
266
|
+
LIMIT 1
|
|
267
|
+
);
|
|
268
|
+
|
|
269
|
+
UPDATE agent_identities
|
|
270
|
+
SET label = 'Forge Codex',
|
|
271
|
+
agent_type = 'codex',
|
|
272
|
+
provider = 'codex',
|
|
273
|
+
identity_key = 'runtime:codex:legacy:default',
|
|
274
|
+
machine_key = 'legacy',
|
|
275
|
+
persona_key = 'default',
|
|
276
|
+
description = 'Codex runtime agent with stable Forge identity and linked Kanban user.',
|
|
277
|
+
updated_at = datetime('now')
|
|
278
|
+
WHERE lower(agent_type) = 'codex' OR lower(label) = 'forge codex';
|
|
279
|
+
|
|
280
|
+
INSERT OR IGNORE INTO agent_identity_users (agent_id, user_id, role, created_at, updated_at)
|
|
281
|
+
SELECT id, 'user_agent_openclaw', 'primary', datetime('now'), datetime('now')
|
|
282
|
+
FROM agent_identities
|
|
283
|
+
WHERE provider = 'openclaw';
|
|
284
|
+
|
|
285
|
+
INSERT OR IGNORE INTO agent_identity_users (agent_id, user_id, role, created_at, updated_at)
|
|
286
|
+
SELECT id, 'user_agent_hermes', 'primary', datetime('now'), datetime('now')
|
|
287
|
+
FROM agent_identities
|
|
288
|
+
WHERE provider = 'hermes';
|
|
289
|
+
|
|
290
|
+
INSERT OR IGNORE INTO agent_identity_users (agent_id, user_id, role, created_at, updated_at)
|
|
291
|
+
SELECT id, 'user_agent_codex', 'primary', datetime('now'), datetime('now')
|
|
292
|
+
FROM agent_identities
|
|
293
|
+
WHERE provider = 'codex';
|
|
294
|
+
|
|
295
|
+
UPDATE agent_runtime_sessions
|
|
296
|
+
SET agent_label = (
|
|
297
|
+
SELECT label FROM agent_identities WHERE agent_identities.id = agent_runtime_sessions.agent_id
|
|
298
|
+
),
|
|
299
|
+
agent_type = (
|
|
300
|
+
SELECT agent_type FROM agent_identities WHERE agent_identities.id = agent_runtime_sessions.agent_id
|
|
301
|
+
),
|
|
302
|
+
updated_at = datetime('now')
|
|
303
|
+
WHERE agent_id IN (SELECT id FROM agent_identities WHERE provider IN ('openclaw', 'hermes', 'codex'));
|
|
304
|
+
|
|
305
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_agent_identities_identity_key
|
|
306
|
+
ON agent_identities(identity_key)
|
|
307
|
+
WHERE identity_key IS NOT NULL;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
UPDATE agent_runtime_sessions
|
|
2
|
+
SET agent_label = (
|
|
3
|
+
SELECT label FROM agent_identities WHERE agent_identities.id = agent_runtime_sessions.agent_id
|
|
4
|
+
),
|
|
5
|
+
agent_type = (
|
|
6
|
+
SELECT agent_type FROM agent_identities WHERE agent_identities.id = agent_runtime_sessions.agent_id
|
|
7
|
+
),
|
|
8
|
+
updated_at = datetime('now')
|
|
9
|
+
WHERE agent_id IN (SELECT id FROM agent_identities WHERE provider IN ('openclaw', 'hermes', 'codex'));
|
|
@@ -830,7 +830,8 @@ const AGENT_ONBOARDING_ENTITY_CATALOG_BASE = [
|
|
|
830
830
|
],
|
|
831
831
|
searchHints: [
|
|
832
832
|
"Search by title before creating a duplicate habit.",
|
|
833
|
-
"Use linkedTo when the habit should already be attached to a goal, project, task, or Psyche entity."
|
|
833
|
+
"Use linkedTo when the habit should already be attached to a goal, project, task, or Psyche entity.",
|
|
834
|
+
"To log an official habit outcome from the shared agent tool surface, patch the habit through forge_update_entities with checkIn: { status, dateKey?, note?, description? }."
|
|
834
835
|
],
|
|
835
836
|
examples: [
|
|
836
837
|
'{"title":"Morning training","frequency":"daily","polarity":"positive","linkedGoalIds":["goal_train_body"],"linkedValueIds":["value_steadiness"],"linkedBehaviorIds":["behavior_regulating_walk"]}'
|
|
@@ -2771,6 +2772,10 @@ const AGENT_ONBOARDING_CONVERSATION_RULES = [
|
|
|
2771
2772
|
"When useful, help the user name, define, and connect the record in that order: offer a working label, clarify what belongs inside it, then ask about links only after the record itself feels steady.",
|
|
2772
2773
|
"When the meaning is clearer than the wording, offer a tentative title or formulation yourself and invite correction instead of forcing the user to wordsmith alone.",
|
|
2773
2774
|
"For direct update or review requests, the next question should usually narrow the saved object, timeframe, or route family instead of reopening the whole meaning-making arc.",
|
|
2775
|
+
"The opening question should help the user understand what they are actually trying to save, decide, review, or change, not make them perform the schema out loud.",
|
|
2776
|
+
"If the user already named the exact correction in usable language, confirm only the missing scope, timing, or route-selecting detail that still matters, then act.",
|
|
2777
|
+
"Once a specialized-surface lane is clear, speak in route-relevant nouns such as timeline, overlay, weekday template, published output, run detail, or node result instead of generic record language.",
|
|
2778
|
+
"If the next answer would not change the route, wording, timing, or write payload in a meaningful way, stop asking and act.",
|
|
2774
2779
|
"Before saving, briefly summarize the working formulation in the user's own language when that would reduce ambiguity.",
|
|
2775
2780
|
"Once the record is clear enough to name, stop exploring broadly and ask only for the last structural detail that still matters.",
|
|
2776
2781
|
"If the record is already clear enough to save, save it instead of performing a ceremonial extra question.",
|
|
@@ -3096,6 +3101,7 @@ const AGENT_ONBOARDING_ENTITY_CONVERSATION_PLAYBOOKS = [
|
|
|
3096
3101
|
"Ask for the time window, place, or movement item that makes the question concrete.",
|
|
3097
3102
|
"Ask what they are trying to notice, preserve, or answer through that movement context.",
|
|
3098
3103
|
"Choose the dedicated day, month, all-time, timeline, places, trip-detail, or selection route once the question shape is clear.",
|
|
3104
|
+
"If the truth of one uncertain span is still unclear, read the timeline or saved-box detail before you mutate it.",
|
|
3099
3105
|
"Skip the meta lane question when the user already named the exact correction or review target and only one ambiguity remains.",
|
|
3100
3106
|
"If the request is filling a missing-data gap, use a user-defined movement box rather than a raw stay or trip patch.",
|
|
3101
3107
|
"If the request is repairing already-saved movement data, use the repair route that matches the saved object instead of treating it like a missing span.",
|
|
@@ -3113,6 +3119,7 @@ const AGENT_ONBOARDING_ENTITY_CONVERSATION_PLAYBOOKS = [
|
|
|
3113
3119
|
"Ask what part of the current energy picture feels most important or inaccurate.",
|
|
3114
3120
|
"Ask what should stay true if they are changing profile or template assumptions.",
|
|
3115
3121
|
"Ask whether the user is describing a stable weekly shape or just how today feels when the lane is still blurred.",
|
|
3122
|
+
"If the user describes a repeatable day-shape such as 'Mondays crash after lunch', treat that as a weekday-template question before you reach for profile or fatigue-signal routes.",
|
|
3116
3123
|
"If the user already named the life-force lane clearly, skip the meta lane question and ask only for the specific weekday, profile field, or signal that still matters.",
|
|
3117
3124
|
"If the request is about a durable baseline, use profile or weekday-template mutation rather than a fatigue signal; if it is about right now, prefer the fatigue-signal route.",
|
|
3118
3125
|
"If the user wants to see what changed after a write, read the overview back instead of leaving the result implicit.",
|
|
@@ -3126,11 +3133,12 @@ const AGENT_ONBOARDING_ENTITY_CONVERSATION_PLAYBOOKS = [
|
|
|
3126
3133
|
askSequence: [
|
|
3127
3134
|
"Ask whether the job is flow discovery, one flow edit, execution, run history, published output, node-level inspection, or latest-node-output lookup.",
|
|
3128
3135
|
"Ask which flow, slug, run, or node the request is about.",
|
|
3129
|
-
"Ask whether they need the flow contract,
|
|
3136
|
+
"Ask whether they need the stable flow contract, one run result, one published output, one node result, or the latest node output.",
|
|
3130
3137
|
"Ask what the user is trying to learn, repair, or publish through that flow.",
|
|
3131
3138
|
"If the user already named the flow and action clearly, skip the meta lane question and ask only for the missing run, node, or output scope.",
|
|
3132
3139
|
"If the user wants a stable public input contract or published output, prefer those dedicated reads instead of detouring through run history first.",
|
|
3133
3140
|
"If the user is still shaping a payload or edit, prefer flow detail or box catalog reads before asking for structured inputs.",
|
|
3141
|
+
"If the user is debugging one failed run, ask whether the useful artifact is the run summary, one node result, the latest node output, or the published output before you start asking for edits.",
|
|
3134
3142
|
"Prefer flow detail or published-output reads for stable contracts, and use run or node-result routes only when the user is asking about execution history or debugging.",
|
|
3135
3143
|
"Route to the dedicated workbench route family once the execution lane is clear."
|
|
3136
3144
|
]
|
|
@@ -3985,8 +3993,8 @@ function buildAgentOnboardingPayload(request) {
|
|
|
3985
3993
|
tokenRecovery: {
|
|
3986
3994
|
rawTokenStoredByForge: false,
|
|
3987
3995
|
recoveryAction: "rotate_or_issue_new_token",
|
|
3988
|
-
rotationSummary: "Forge reveals raw tokens once. If you lose one, rotate it or issue a new token
|
|
3989
|
-
settingsSummary: "Token creation, rotation, and revocation all live
|
|
3996
|
+
rotationSummary: "Forge reveals raw tokens once. If you lose one, rotate it or issue a new token through /api/v1/settings/tokens, then update the plugin config.",
|
|
3997
|
+
settingsSummary: "Token creation, rotation, and revocation all live on explicit settings routes so recovery stays operator-controlled without requiring a browser click."
|
|
3990
3998
|
},
|
|
3991
3999
|
requiredHeaders: {
|
|
3992
4000
|
authorization: "Authorization: Bearer <forge-api-token>",
|
|
@@ -4153,6 +4161,11 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4153
4161
|
specializedDomainSurfaces: {
|
|
4154
4162
|
movement: {
|
|
4155
4163
|
summary: "Dedicated movement workspace API. Use these routes for stays, trips, time-in-place questions, visited places, trip detail, selection aggregates, user-defined overlays, and repair actions on already-recorded movement data.",
|
|
4164
|
+
routeSelectionQuestions: [
|
|
4165
|
+
"Is the user asking for a day, month, all-time, timeline, place, trip detail, or selected-span answer?",
|
|
4166
|
+
"Is this a missing-gap overlay, a saved-overlay repair, or an edit to one already-recorded stay, trip, or trip point?",
|
|
4167
|
+
"If the target is already known, what one time, place, or saved-object detail is still missing before acting?"
|
|
4168
|
+
],
|
|
4156
4169
|
readRoutes: {
|
|
4157
4170
|
day: "/api/v1/movement/day",
|
|
4158
4171
|
month: "/api/v1/movement/month",
|
|
@@ -4190,6 +4203,11 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4190
4203
|
},
|
|
4191
4204
|
lifeForce: {
|
|
4192
4205
|
summary: "Dedicated life-force API. Use it to read the current energy budget, drains, recommendations, and warnings, then patch only the parts that are meant to be user-controlled.",
|
|
4206
|
+
routeSelectionQuestions: [
|
|
4207
|
+
"Is the user trying to understand the overview, change durable profile assumptions, change a weekday curve, or log a right-now fatigue signal?",
|
|
4208
|
+
"Are they describing a repeatable weekly shape or a one-off current state?",
|
|
4209
|
+
"If the lane is already clear, what one weekday, profile field, or signal detail is still missing?"
|
|
4210
|
+
],
|
|
4193
4211
|
readRoutes: {
|
|
4194
4212
|
overview: "/api/v1/life-force"
|
|
4195
4213
|
},
|
|
@@ -4202,12 +4220,18 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4202
4220
|
"Life Force is a focused domain surface, not a batch CRUD entity type.",
|
|
4203
4221
|
"Use GET /api/v1/life-force for the current overview payload with stats, drains, recommendations, and current-curve state.",
|
|
4204
4222
|
"Patch the profile only for durable personal settings, update weekday templates only for the curve itself, and post fatigue signals for real-time tired or recovered observations.",
|
|
4223
|
+
"If the user says something like 'I always dip on Tuesdays after lunch', treat that as a weekday-template change rather than a one-off fatigue signal.",
|
|
4205
4224
|
"If the user is asking what changed after a profile, template, or fatigue write, read the overview back so the effect stays visible.",
|
|
4206
4225
|
"If the user already knows they want a profile change, weekday-template edit, or right-now fatigue signal, skip the broad lane question and ask only for the missing weekday, profile field, or signal detail."
|
|
4207
4226
|
]
|
|
4208
4227
|
},
|
|
4209
4228
|
workbench: {
|
|
4210
4229
|
summary: "Dedicated graph-flow API. Use it for flow catalog reads, flow CRUD, execution, run history, published outputs, node results, and latest successful node outputs.",
|
|
4230
|
+
routeSelectionQuestions: [
|
|
4231
|
+
"Is the job flow discovery, flow editing, execution, published output, run detail, node result, latest node output, or flow chat follow-up?",
|
|
4232
|
+
"Does the user need a stable public contract or one execution artifact?",
|
|
4233
|
+
"If the flow is already known, what one run, node, or output scope detail is still missing before acting?"
|
|
4234
|
+
],
|
|
4211
4235
|
readRoutes: {
|
|
4212
4236
|
listFlows: "/api/v1/workbench/flows",
|
|
4213
4237
|
flowById: "/api/v1/workbench/flows/:id",
|
|
@@ -4233,6 +4257,7 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4233
4257
|
"Use the flow routes when the agent needs stable public input contracts, published outputs, node-level results, or reusable execution history.",
|
|
4234
4258
|
"If the user is still figuring out inputs or editable structure, read flow detail or box catalog before asking them to author a payload from memory.",
|
|
4235
4259
|
"Prefer the dedicated output and node-result routes over reverse-engineering raw traces.",
|
|
4260
|
+
"If the user only wants a published output, latest node output, or run detail, do not reopen a flow-edit intake before reading that artifact.",
|
|
4236
4261
|
"If the user already named the flow and wants one output or one run, skip the broad lane question and ask only for the missing run, node, or output scope."
|
|
4237
4262
|
]
|
|
4238
4263
|
}
|
|
@@ -4281,19 +4306,24 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4281
4306
|
installSteps: [
|
|
4282
4307
|
"Install the Forge plugin from the repo or published package.",
|
|
4283
4308
|
"Restart the OpenClaw gateway so the tool surface and UI proxy routes refresh.",
|
|
4284
|
-
"
|
|
4309
|
+
"For localhost or Tailscale, finish onboarding through operator-session bootstrap and CLI verification without opening the Forge UI.",
|
|
4310
|
+
"If remote scoped auth is needed, issue or rotate a managed token through /api/v1/settings/tokens and update the plugin config without a Settings click."
|
|
4285
4311
|
],
|
|
4286
4312
|
verifyCommands: [
|
|
4287
4313
|
`curl -s ${origin}/api/v1/health`,
|
|
4288
4314
|
"openclaw plugins install ./projects/forge/openclaw-plugin",
|
|
4289
4315
|
"openclaw plugins info forge-openclaw-plugin",
|
|
4290
|
-
"openclaw gateway restart"
|
|
4316
|
+
"openclaw gateway restart",
|
|
4317
|
+
"openclaw forge onboarding",
|
|
4318
|
+
"openclaw forge health"
|
|
4291
4319
|
],
|
|
4292
4320
|
configNotes: [
|
|
4293
4321
|
"Localhost and Tailscale targets can usually use the operator-session path without a long-lived token.",
|
|
4322
|
+
"The operator-session route is /api/v1/auth/operator-session, so trusted local OpenClaw onboarding does not need a browser confirmation step.",
|
|
4294
4323
|
"If your current OpenClaw build blocks the repo-local install because of the package scanner, keep the repo folder on plugins.load.paths and verify that plugins info still points at the local Forge source path before continuing.",
|
|
4295
4324
|
"Use a distinct actor label such as Albert (claw) so OpenClaw-originated work stays obvious in Forge provenance.",
|
|
4296
|
-
"Create each agent as a Forge bot user, then use userId or userIds in tool inputs whenever the agent should focus on one human, one bot, or a specific collaboration slice."
|
|
4325
|
+
"Create each agent as a Forge bot user, then use userId or userIds in tool inputs whenever the agent should focus on one human, one bot, or a specific collaboration slice.",
|
|
4326
|
+
"If you genuinely need a durable managed token, create it through /api/v1/settings/tokens instead of sending the operator into the Settings UI."
|
|
4297
4327
|
]
|
|
4298
4328
|
},
|
|
4299
4329
|
hermes: {
|
|
@@ -4301,7 +4331,7 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4301
4331
|
installSteps: [
|
|
4302
4332
|
"Install forge-hermes-plugin into the Python environment Hermes actually runs.",
|
|
4303
4333
|
"Let Hermes load the Forge plugin and bundled skill pack on startup.",
|
|
4304
|
-
"
|
|
4334
|
+
"If Hermes needs remote or durable scoped auth, issue a managed token through /api/v1/settings/tokens and update the Hermes config without a Settings click."
|
|
4305
4335
|
],
|
|
4306
4336
|
verifyCommands: [
|
|
4307
4337
|
"python -m pip show forge-hermes-plugin",
|
|
@@ -4435,8 +4465,8 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4435
4465
|
saveSuggestionPlacement: "end_of_message",
|
|
4436
4466
|
saveSuggestionTone: "gentle_optional",
|
|
4437
4467
|
maxQuestionsPerTurn: 1,
|
|
4438
|
-
psycheExplorationRule: "When a Psyche entity needs understanding first, begin with one exploratory question before any working formulation, replacement belief, suggested title, or save pitch. Keep the opening reflection to one or two short sentences, stay in plain prose instead of bullets or numbered lists, keep that first reply short, do not mention Forge search or save structure yet, avoid colons or list-shaped phrasing, prefer what/when/how over why until the experience is grounded, wait for the user's answer before offering a fuller formulation, ask permission before moving from charged exploration into naming or challenge when needed, do not widen into adjacent entities until the current one has a working sentence the user recognizes, and once the lived experience is coherent stop deepening and help the user name it cleanly. When the user is updating a Psyche record because of one fresh episode, anchor in that episode before renaming the durable formulation. If the user accepts the wording, move toward the save instead of reopening deeper exploration.",
|
|
4439
|
-
specializedSurfaceRule: "For Movement, Life Force, and Workbench, clarify the lane first, then name the dedicated route family in plain language and do not guess at a generic CRUD path. When the user already named a precise correction or review target, confirm only the route-selecting detail that is still missing. After a concrete specialized-surface correction, read the relevant specialized view back when the user is trying to understand the result rather than just store it. The canonical runtime routes stay under /api/v1/*, and the OpenClaw HTTP mirror exposes the same families under /forge/v1/movement, /forge/v1/life-force, and /forge/v1/workbench.",
|
|
4468
|
+
psycheExplorationRule: "When a Psyche entity needs understanding first, begin with one exploratory question before any working formulation, replacement belief, suggested title, or save pitch. Keep the opening reflection to one or two short sentences, stay in plain prose instead of bullets or numbered lists, keep that first reply short, do not mention Forge search or save structure yet, avoid colons or list-shaped phrasing, prefer what/when/how over why until the experience is grounded, wait for the user's answer before offering a fuller formulation, ask permission before moving from charged exploration into naming or challenge when needed, make the next question help the user feel more able to name the experience rather than more examined, do not widen into adjacent entities until the current one has a working sentence the user recognizes, and once the lived experience is coherent stop deepening and help the user name it cleanly. When the user is updating a Psyche record because of one fresh episode, anchor in that episode before renaming the durable formulation. If the user accepts the wording, move toward the save instead of reopening deeper exploration.",
|
|
4469
|
+
specializedSurfaceRule: "For Movement, Life Force, and Workbench, clarify the lane first, then name the dedicated route family in plain language and do not guess at a generic CRUD path. Use specializedDomainSurfaces.routeSelectionQuestions when they are present so the next follow-up stays route-selective instead of generic. Once the lane is clear, talk in route-relevant nouns such as timeline, overlay, weekday template, published output, run detail, or node result rather than generic record language. If the truth of the current state is still uncertain, read the relevant specialized view before you mutate it. When the user already named a precise correction or review target, confirm only the route-selecting detail that is still missing. After a concrete specialized-surface correction, read the relevant specialized view back when the user is trying to understand the result rather than just store it. The canonical runtime routes stay under /api/v1/*, and the OpenClaw HTTP mirror exposes the same families under /forge/v1/movement, /forge/v1/life-force, and /forge/v1/workbench.",
|
|
4440
4470
|
reviewShortcutRule: "When the user is reviewing or correcting an existing record, narrow the saved object, timeframe, or route family first. Do not reopen the whole intake unless the user is actually redefining the record.",
|
|
4441
4471
|
readModelWriteRule: "Self-observation is note-backed and should be written through observed notes with frontmatter.observedAt. Sleep and workout sessions stay on batch CRUD by default; use the reflective review helpers only when enriching one already-known record after review.",
|
|
4442
4472
|
psycheOpeningQuestionRule: "Prefer a concrete opening question tied to the entity: ask when the value mattered, what happened the last time the pattern appeared, what cue or body signal came first before the behavior, what the belief starts saying about self or outcome, what feels most at risk inside the mode, what the part is trying to get the user to do or stop doing, or where the shift began in the incident. Reflect briefly before the question, choose one follow-up lane at a time, say what is becoming clearer before the next deeper question, and if several Psyche entities are visible hold the adjacent ones lightly until the main container is clear.",
|
|
@@ -4460,9 +4490,9 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4460
4490
|
batchingRule: "forge_create_entities, forge_update_entities, forge_delete_entities, and forge_restore_entities all accept operations as arrays. Batch CRUD is the default for simple entities, so batch multiple related mutations together instead of reaching for a long list of entity-specific routes.",
|
|
4461
4491
|
searchRule: "forge_search_entities accepts searches as an array. Search before create or update when duplicate risk exists.",
|
|
4462
4492
|
createRule: "Each create operation must include entityType and full data. entityType alone is not enough. This includes calendar_event, work_block_template, task_timebox, sleep_session, workout_session, preference CRUD entities, and questionnaire_instrument alongside the usual planning and Psyche entities.",
|
|
4463
|
-
updateRule: "Each update operation must include entityType, id, and patch. For projects, lifecycle changes are status patches: active to restart, paused to suspend, completed to finish. Keep task and project scheduling rules on those same patch payloads. Calendar-event updates still run downstream provider projection sync, and manual health-session field edits belong on the batch route by default rather than on the reflective review helpers.",
|
|
4493
|
+
updateRule: "Each update operation must include entityType, id, and patch. For projects, lifecycle changes are status patches: active to restart, paused to suspend, completed to finish. Keep task and project scheduling rules on those same patch payloads. Official habit outcomes can also be logged through forge_update_entities by patching the habit with checkIn: { status, dateKey?, note?, description? } instead of route-hunting. Calendar-event updates still run downstream provider projection sync, and manual health-session field edits belong on the batch route by default rather than on the reflective review helpers.",
|
|
4464
4494
|
createExample: '{"operations":[{"entityType":"goal","data":{"title":"Create meaningfully"},"clientRef":"goal-create-1"},{"entityType":"goal","data":{"title":"Build a beautiful family"},"clientRef":"goal-create-2"}]}',
|
|
4465
|
-
updateExample: '{"operations":[{"entityType":"project","id":"project_123","patch":{"status":"paused","schedulingRules":{"blockWorkBlockKinds":["main_activity"],"allowWorkBlockKinds":["secondary_activity"]}},"clientRef":"project-suspend-1"},{"entityType":"
|
|
4495
|
+
updateExample: '{"operations":[{"entityType":"project","id":"project_123","patch":{"status":"paused","schedulingRules":{"blockWorkBlockKinds":["main_activity"],"allowWorkBlockKinds":["secondary_activity"]}},"clientRef":"project-suspend-1"},{"entityType":"habit","id":"habit_456","patch":{"checkIn":{"status":"missed","note":"Resisted the urge after dinner.","description":"85 sec reset"}},"clientRef":"habit-check-in-1"}]}'
|
|
4466
4496
|
}
|
|
4467
4497
|
};
|
|
4468
4498
|
}
|