forked from plastic-labs/openclaw-honcho
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstate.ts
More file actions
130 lines (108 loc) · 4.09 KB
/
state.ts
File metadata and controls
130 lines (108 loc) · 4.09 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/**
* Shared mutable state for the Honcho memory plugin.
* Follows the dependency-injection pattern: createPluginState() returns a
* PluginState object that gets passed to every module.
*/
import { Honcho, type Peer } from "@honcho-ai/sdk";
// @ts-ignore - resolved by openclaw runtime
import type { OpenClawPluginApi } from "openclaw/plugin-sdk";
import { honchoConfigSchema, type HonchoConfig } from "./config.js";
export const OWNER_ID = "owner";
export const LEGACY_PEER_ID = "openclaw";
export type PluginState = {
honcho: Honcho;
cfg: HonchoConfig;
ownerPeer: Peer | null;
agentPeers: Map<string, Peer>;
agentPeerMap: Record<string, string>;
/** Message count recorded at before_prompt_build time, keyed by Honcho session key.
* Used by the capture hook to determine where the current turn starts in the
* accumulated message array, so first-init skips pre-installation history. */
turnStartIndex: Map<string, number>;
initialized: boolean;
api: OpenClawPluginApi;
ensureInitialized: () => Promise<void>;
getAgentPeer: (agentId?: string) => Promise<Peer>;
resolveDefaultAgentId: () => string;
};
export function createPluginState(api: OpenClawPluginApi): PluginState {
const cfg = honchoConfigSchema.parse(api.pluginConfig);
if (!cfg.apiKey) {
api.logger.warn(
"openclaw-honcho: No API key configured. Set HONCHO_API_KEY or configure apiKey in plugin config."
);
}
const honcho = new Honcho({
apiKey: cfg.apiKey,
baseURL: cfg.baseUrl,
workspaceId: cfg.workspaceId,
});
const state: PluginState = {
honcho,
cfg,
ownerPeer: null,
agentPeers: new Map<string, Peer>(),
agentPeerMap: {},
turnStartIndex: new Map<string, number>(),
initialized: false,
api,
ensureInitialized,
getAgentPeer,
resolveDefaultAgentId,
};
function resolveDefaultAgentId(): string {
const agents = api.config?.agents?.list;
if (!Array.isArray(agents) || agents.length === 0) return "main";
const defaultAgent = agents.find((a: { default?: boolean }) => a?.default) ?? agents[0];
return (defaultAgent?.id ?? "main").toLowerCase().trim() || "main";
}
async function ensureInitialized(): Promise<void> {
if (state.initialized) return;
const wsMeta = await honcho.getMetadata();
state.agentPeerMap = (wsMeta.agentPeerMap as Record<string, string>) ?? {};
const defaultId = resolveDefaultAgentId();
if (Object.keys(state.agentPeerMap).length === 0) {
state.agentPeerMap[defaultId] = `agent-${defaultId}`;
await honcho.setMetadata({ ...wsMeta, agentPeerMap: state.agentPeerMap });
} else if (Object.values(state.agentPeerMap).includes(LEGACY_PEER_ID) && !state.agentPeerMap[defaultId]) {
state.agentPeerMap[defaultId] = LEGACY_PEER_ID;
await honcho.setMetadata({ ...wsMeta, agentPeerMap: state.agentPeerMap });
}
state.ownerPeer = await honcho.peer(OWNER_ID, { metadata: {} });
state.initialized = true;
}
async function getAgentPeer(agentId?: string): Promise<Peer> {
const id = (agentId || resolveDefaultAgentId()).toLowerCase().trim() || "main";
let peer = state.agentPeers.get(id);
if (peer) return peer;
let peerId = state.agentPeerMap[id];
if (!peerId) {
const allPeers = await honcho.peers();
for await (const p of allPeers) {
if (p.id === OWNER_ID) continue;
const meta = await p.getMetadata();
if (meta?.agentId === id) {
peerId = p.id;
api.logger.info(`[honcho] Recovered peer "${peerId}" for renamed agent "${id}"`);
break;
}
}
}
if (!peerId) {
peerId = `agent-${id}`;
}
if (state.agentPeerMap[id] !== peerId) {
state.agentPeerMap[id] = peerId;
const wsMeta = await honcho.getMetadata();
await honcho.setMetadata({ ...wsMeta, agentPeerMap: state.agentPeerMap });
}
peer = await honcho.peer(peerId);
state.agentPeers.set(id, peer);
const existingMeta = await peer.getMetadata();
if (existingMeta.agentId !== id) {
await peer.setMetadata({ ...existingMeta, agentId: id });
}
return peer;
}
return state;
}