@happycastle/oh-my-openclaw 0.9.1 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { OmocPluginApi } from '../types.js';
|
|
2
2
|
export declare function resetPersonaInjectorState(): void;
|
|
3
3
|
export declare function getPersonaInjectorState(): {
|
|
4
|
-
|
|
4
|
+
lastInjectedPersonaId: string | null;
|
|
5
5
|
};
|
|
6
6
|
export declare function registerPersonaInjector(api: OmocPluginApi): void;
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { getActivePersona } from '../utils/persona-state.js';
|
|
2
2
|
import { readPersonaPromptSync } from '../agents/persona-prompts.js';
|
|
3
|
-
|
|
4
|
-
const PERSONA_INJECTION_COOLDOWN_MS = 5_000;
|
|
5
|
-
let lastPersonaInjectionTime = 0;
|
|
3
|
+
let lastInjectedPersonaId = null;
|
|
6
4
|
export function resetPersonaInjectorState() {
|
|
7
|
-
|
|
5
|
+
lastInjectedPersonaId = null;
|
|
8
6
|
}
|
|
9
7
|
export function getPersonaInjectorState() {
|
|
10
|
-
return {
|
|
8
|
+
return { lastInjectedPersonaId };
|
|
11
9
|
}
|
|
12
10
|
export function registerPersonaInjector(api) {
|
|
13
11
|
api.registerHook('agent:bootstrap', (event) => {
|
|
@@ -18,14 +16,11 @@ export function registerPersonaInjector(api) {
|
|
|
18
16
|
if (!event.context.bootstrapFiles) {
|
|
19
17
|
event.context.bootstrapFiles = [];
|
|
20
18
|
}
|
|
21
|
-
const
|
|
22
|
-
if (
|
|
23
|
-
api.logger.info(`[omoc] Persona injection skipped (already present in bootstrapFiles)`);
|
|
19
|
+
const alreadyInFiles = event.context.bootstrapFiles.some((f) => f.path.startsWith('omoc://persona/'));
|
|
20
|
+
if (alreadyInFiles) {
|
|
24
21
|
return;
|
|
25
22
|
}
|
|
26
|
-
|
|
27
|
-
if (now - lastPersonaInjectionTime < PERSONA_INJECTION_COOLDOWN_MS) {
|
|
28
|
-
api.logger.info(`[omoc] Persona injection skipped (cooldown)`);
|
|
23
|
+
if (lastInjectedPersonaId === personaId) {
|
|
29
24
|
return;
|
|
30
25
|
}
|
|
31
26
|
try {
|
|
@@ -34,7 +29,7 @@ export function registerPersonaInjector(api) {
|
|
|
34
29
|
path: `omoc://persona/${personaId}`,
|
|
35
30
|
content,
|
|
36
31
|
});
|
|
37
|
-
|
|
32
|
+
lastInjectedPersonaId = personaId;
|
|
38
33
|
api.logger.info(`[omoc] Persona injected: ${personaId}`);
|
|
39
34
|
}
|
|
40
35
|
catch (err) {
|
|
@@ -42,6 +37,6 @@ export function registerPersonaInjector(api) {
|
|
|
42
37
|
}
|
|
43
38
|
}, {
|
|
44
39
|
name: 'oh-my-openclaw.persona-injector',
|
|
45
|
-
description: 'Injects active persona prompt
|
|
40
|
+
description: 'Injects active persona prompt once per persona change',
|
|
46
41
|
});
|
|
47
42
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { OmocPluginApi } from '../types.js';
|
|
2
|
+
export type AgentRole = 'orchestrator' | 'worker' | 'lightweight';
|
|
3
|
+
export declare function classifyAgentRole(agentId?: string): AgentRole;
|
|
2
4
|
export declare function resetEnforcerState(): void;
|
|
3
|
-
export declare function getEnforcerState(): {
|
|
4
|
-
lastInjectionTime: number;
|
|
5
|
-
consecutiveFailures: number;
|
|
6
|
-
disabledByFailures: boolean;
|
|
7
|
-
};
|
|
5
|
+
export declare function getEnforcerState(): {};
|
|
8
6
|
export declare function registerTodoEnforcer(api: OmocPluginApi): void;
|
|
@@ -1,28 +1,46 @@
|
|
|
1
1
|
import { getConfig } from '../utils/config.js';
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
const ORCHESTRATOR_IDS = new Set([
|
|
3
|
+
'omoc_prometheus',
|
|
4
|
+
'omoc_atlas',
|
|
5
|
+
]);
|
|
6
|
+
const WORKER_IDS = new Set([
|
|
7
|
+
'omoc_sisyphus',
|
|
8
|
+
'omoc_hephaestus',
|
|
9
|
+
'omoc_frontend',
|
|
10
|
+
]);
|
|
11
|
+
export function classifyAgentRole(agentId) {
|
|
12
|
+
if (!agentId)
|
|
13
|
+
return 'orchestrator';
|
|
14
|
+
if (ORCHESTRATOR_IDS.has(agentId))
|
|
15
|
+
return 'orchestrator';
|
|
16
|
+
if (WORKER_IDS.has(agentId))
|
|
17
|
+
return 'worker';
|
|
18
|
+
return 'lightweight';
|
|
19
|
+
}
|
|
20
|
+
const ORCHESTRATOR_DIRECTIVE = `[SYSTEM REMINDER - TODO CONTINUATION]
|
|
21
|
+
If you have incomplete todos, continue working on them.
|
|
6
22
|
- Mark each task complete immediately when finished
|
|
7
23
|
- If blocked, document the blocker and move to next task
|
|
24
|
+
- Do NOT restate prior messages — output only deltas and next concrete action
|
|
25
|
+
- If no actionable next step remains, declare tasks complete and stop
|
|
8
26
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
27
|
+
When you receive a subagent completion notification:
|
|
28
|
+
- Check the subagent's result against success criteria
|
|
29
|
+
- Then proceed to the next task/phase`;
|
|
30
|
+
const WORKER_DIRECTIVE = `[SYSTEM REMINDER - TASK COMPLETION]
|
|
31
|
+
Complete your assigned task, return the result, then stop.
|
|
32
|
+
- Do NOT restate prior messages — output only new findings or changes
|
|
33
|
+
- If blocked, report the blocker and stop`;
|
|
34
|
+
const DIRECTIVES = {
|
|
35
|
+
orchestrator: ORCHESTRATOR_DIRECTIVE,
|
|
36
|
+
worker: WORKER_DIRECTIVE,
|
|
37
|
+
lightweight: null,
|
|
38
|
+
};
|
|
19
39
|
export function resetEnforcerState() {
|
|
20
|
-
|
|
21
|
-
consecutiveFailures = 0;
|
|
22
|
-
disabledByFailures = false;
|
|
40
|
+
// no-op — kept for API compatibility (no global state to reset)
|
|
23
41
|
}
|
|
24
42
|
export function getEnforcerState() {
|
|
25
|
-
return {
|
|
43
|
+
return {};
|
|
26
44
|
}
|
|
27
45
|
export function registerTodoEnforcer(api) {
|
|
28
46
|
api.registerHook('agent:bootstrap', (event) => {
|
|
@@ -30,13 +48,9 @@ export function registerTodoEnforcer(api) {
|
|
|
30
48
|
if (!config.todo_enforcer_enabled) {
|
|
31
49
|
return;
|
|
32
50
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
}
|
|
37
|
-
const now = Date.now();
|
|
38
|
-
if (config.todo_enforcer_cooldown_ms > 0 && (now - lastInjectionTime) < config.todo_enforcer_cooldown_ms) {
|
|
39
|
-
api.logger.info('[omoc] Todo enforcer skipped (cooldown)');
|
|
51
|
+
const role = classifyAgentRole(event.context.agentId);
|
|
52
|
+
const directive = DIRECTIVES[role];
|
|
53
|
+
if (!directive) {
|
|
40
54
|
return;
|
|
41
55
|
}
|
|
42
56
|
if (!event.context.bootstrapFiles) {
|
|
@@ -44,27 +58,20 @@ export function registerTodoEnforcer(api) {
|
|
|
44
58
|
}
|
|
45
59
|
const alreadyInjected = event.context.bootstrapFiles.some((f) => f.path === 'omoc://todo-enforcer');
|
|
46
60
|
if (alreadyInjected) {
|
|
47
|
-
api.logger.info('[omoc] Todo enforcer skipped (already present in bootstrapFiles)');
|
|
48
61
|
return;
|
|
49
62
|
}
|
|
50
63
|
try {
|
|
51
64
|
event.context.bootstrapFiles.push({
|
|
52
65
|
path: 'omoc://todo-enforcer',
|
|
53
|
-
content:
|
|
66
|
+
content: directive,
|
|
54
67
|
});
|
|
55
|
-
|
|
56
|
-
consecutiveFailures = 0;
|
|
57
|
-
api.logger.info('[omoc] Todo enforcer directive injected');
|
|
68
|
+
api.logger.info(`[omoc] Todo enforcer injected (role: ${role})`);
|
|
58
69
|
}
|
|
59
|
-
catch {
|
|
60
|
-
|
|
61
|
-
if (config.todo_enforcer_max_failures > 0 && consecutiveFailures >= config.todo_enforcer_max_failures) {
|
|
62
|
-
disabledByFailures = true;
|
|
63
|
-
api.logger.error(`[omoc] Todo enforcer disabled after ${consecutiveFailures} consecutive failures`);
|
|
64
|
-
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
api.logger.error('[omoc] Todo enforcer injection failed:', err);
|
|
65
72
|
}
|
|
66
73
|
}, {
|
|
67
74
|
name: 'oh-my-openclaw.todo-enforcer',
|
|
68
|
-
description: 'Injects TODO
|
|
75
|
+
description: 'Injects role-aware TODO directive into agent bootstrap',
|
|
69
76
|
});
|
|
70
77
|
}
|
package/package.json
CHANGED