forge-openclaw-plugin 0.2.48 → 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/dist/assets/index-2_tuemtU.css +1 -0
- package/dist/assets/index-BAmEvOXb.js +91 -0
- package/dist/assets/{index-Bv9FWWsZ.js.map → index-BAmEvOXb.js.map} +1 -1
- package/dist/index.html +2 -2
- package/dist/openclaw/session-registry.js +17 -0
- 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 +23 -2
- package/dist/server/server/src/openapi.js +19 -0
- package/dist/server/server/src/repositories/agent-runtime-sessions.js +122 -16
- 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 +13 -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/entity_conversation_playbooks.md +19 -0
- package/skills/forge-openclaw/psyche_entity_playbooks.md +11 -0
- package/dist/assets/index-Bv9FWWsZ.js +0 -91
- 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>
|
|
@@ -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,
|
|
@@ -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'));
|
|
@@ -2772,6 +2772,10 @@ const AGENT_ONBOARDING_CONVERSATION_RULES = [
|
|
|
2772
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.",
|
|
2773
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.",
|
|
2774
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.",
|
|
2775
2779
|
"Before saving, briefly summarize the working formulation in the user's own language when that would reduce ambiguity.",
|
|
2776
2780
|
"Once the record is clear enough to name, stop exploring broadly and ask only for the last structural detail that still matters.",
|
|
2777
2781
|
"If the record is already clear enough to save, save it instead of performing a ceremonial extra question.",
|
|
@@ -4157,6 +4161,11 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4157
4161
|
specializedDomainSurfaces: {
|
|
4158
4162
|
movement: {
|
|
4159
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
|
+
],
|
|
4160
4169
|
readRoutes: {
|
|
4161
4170
|
day: "/api/v1/movement/day",
|
|
4162
4171
|
month: "/api/v1/movement/month",
|
|
@@ -4194,6 +4203,11 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4194
4203
|
},
|
|
4195
4204
|
lifeForce: {
|
|
4196
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
|
+
],
|
|
4197
4211
|
readRoutes: {
|
|
4198
4212
|
overview: "/api/v1/life-force"
|
|
4199
4213
|
},
|
|
@@ -4206,12 +4220,18 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4206
4220
|
"Life Force is a focused domain surface, not a batch CRUD entity type.",
|
|
4207
4221
|
"Use GET /api/v1/life-force for the current overview payload with stats, drains, recommendations, and current-curve state.",
|
|
4208
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.",
|
|
4209
4224
|
"If the user is asking what changed after a profile, template, or fatigue write, read the overview back so the effect stays visible.",
|
|
4210
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."
|
|
4211
4226
|
]
|
|
4212
4227
|
},
|
|
4213
4228
|
workbench: {
|
|
4214
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
|
+
],
|
|
4215
4235
|
readRoutes: {
|
|
4216
4236
|
listFlows: "/api/v1/workbench/flows",
|
|
4217
4237
|
flowById: "/api/v1/workbench/flows/:id",
|
|
@@ -4237,6 +4257,7 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4237
4257
|
"Use the flow routes when the agent needs stable public input contracts, published outputs, node-level results, or reusable execution history.",
|
|
4238
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.",
|
|
4239
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.",
|
|
4240
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."
|
|
4241
4262
|
]
|
|
4242
4263
|
}
|
|
@@ -4444,8 +4465,8 @@ function buildAgentOnboardingPayload(request) {
|
|
|
4444
4465
|
saveSuggestionPlacement: "end_of_message",
|
|
4445
4466
|
saveSuggestionTone: "gentle_optional",
|
|
4446
4467
|
maxQuestionsPerTurn: 1,
|
|
4447
|
-
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.",
|
|
4448
|
-
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. 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.",
|
|
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.",
|
|
4449
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.",
|
|
4450
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.",
|
|
4451
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.",
|
|
@@ -2137,6 +2137,11 @@ export function buildOpenApiDocument() {
|
|
|
2137
2137
|
"id",
|
|
2138
2138
|
"label",
|
|
2139
2139
|
"agentType",
|
|
2140
|
+
"identityKey",
|
|
2141
|
+
"provider",
|
|
2142
|
+
"machineKey",
|
|
2143
|
+
"personaKey",
|
|
2144
|
+
"linkedUsers",
|
|
2140
2145
|
"trustLevel",
|
|
2141
2146
|
"autonomyMode",
|
|
2142
2147
|
"approvalMode",
|
|
@@ -2150,6 +2155,20 @@ export function buildOpenApiDocument() {
|
|
|
2150
2155
|
id: { type: "string" },
|
|
2151
2156
|
label: { type: "string" },
|
|
2152
2157
|
agentType: { type: "string" },
|
|
2158
|
+
identityKey: nullable({ type: "string" }),
|
|
2159
|
+
provider: nullable({ type: "string", enum: ["openclaw", "hermes", "codex"] }),
|
|
2160
|
+
machineKey: nullable({ type: "string" }),
|
|
2161
|
+
personaKey: nullable({ type: "string" }),
|
|
2162
|
+
linkedUsers: arrayOf({
|
|
2163
|
+
type: "object",
|
|
2164
|
+
additionalProperties: false,
|
|
2165
|
+
required: ["userId", "role", "user"],
|
|
2166
|
+
properties: {
|
|
2167
|
+
userId: { type: "string" },
|
|
2168
|
+
role: { type: "string" },
|
|
2169
|
+
user: nullable({ $ref: "#/components/schemas/UserSummary" })
|
|
2170
|
+
}
|
|
2171
|
+
}),
|
|
2153
2172
|
trustLevel: {
|
|
2154
2173
|
type: "string",
|
|
2155
2174
|
enum: ["standard", "trusted", "autonomous"]
|