feat(kb): per-agent hf-token via secret-mgr (openclaw mirror)
Phase 4c openclaw side. dynamic-kb-* tools now resolve a per-agent
hf-token via the existing secret-mgr binary (same path ClawSkills
`tc-ctrl get-token` workflow uses), instead of relying solely on the
plugin-level apiKey config.
plugin/index.ts kbDeps.tokenFor: spawns secret-mgr with
AGENT_ID env set, parses stdout, 5s timeout. Returns null on any
failure so the caller cleanly falls back to the plugin-level
KBClient (which uses Config.APIKey via Bearer).
plugin/index.ts kbDeps.makeClient: builds a fresh KBClient bound
to the resolved per-agent token. Plugin-level Client stays as
the fallback when no agent token is set.
Cross-runtime parity: Plexum side uses HostAPI.GetAgentSecret RPC,
openclaw side shells out to secret-mgr. Same KBDeps interface; same
behaviour.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -940,9 +940,10 @@ function register(api: PluginAPI): void {
|
|||||||
|
|
||||||
// ---- dynamic-kb-* family (DESIGN-DYNAMIC-BLOCK.md §3.3 / §4.4)
|
// ---- dynamic-kb-* family (DESIGN-DYNAMIC-BLOCK.md §3.3 / §4.4)
|
||||||
// Cross-runtime mirror of HarborForge.PlexumPlugin/internal/tools/kb.go +
|
// Cross-runtime mirror of HarborForge.PlexumPlugin/internal/tools/kb.go +
|
||||||
// /internal/kbblock + /internal/kbclient. v1 auth = plugin-level apiKey
|
// /internal/kbblock + /internal/kbclient. v1 auth: per-agent hf-token
|
||||||
// via Bearer (per-agent hf-token resolution is a TODO matching the
|
// resolved via secret-mgr (matches the rest of the Hangman-Lab
|
||||||
// Plexum side).
|
// openclaw plugins). Falls back to plugin-level apiKey when no
|
||||||
|
// per-agent token is configured.
|
||||||
const kbCfg = resolveConfig();
|
const kbCfg = resolveConfig();
|
||||||
const kbBackendUrl =
|
const kbBackendUrl =
|
||||||
typeof kbCfg?.backendUrl === 'string' && kbCfg.backendUrl
|
typeof kbCfg?.backendUrl === 'string' && kbCfg.backendUrl
|
||||||
@@ -951,8 +952,24 @@ function register(api: PluginAPI): void {
|
|||||||
const kbApiKey = typeof kbCfg?.apiKey === 'string' ? (kbCfg.apiKey as string) : '';
|
const kbApiKey = typeof kbCfg?.apiKey === 'string' ? (kbCfg.apiKey as string) : '';
|
||||||
const kbDeps: KBDeps = {
|
const kbDeps: KBDeps = {
|
||||||
client: kbApiKey ? new KBClient(kbBackendUrl, kbApiKey) : null,
|
client: kbApiKey ? new KBClient(kbBackendUrl, kbApiKey) : null,
|
||||||
tokenFor: null,
|
tokenFor: async (agentId: string): Promise<string | null> => {
|
||||||
makeClient: null,
|
// Per-agent hf-token via secret-mgr (decision #20 mirror).
|
||||||
|
// Spawn the existing secret-mgr binary with AGENT_ID set; same
|
||||||
|
// path ClawSkills `tc-ctrl get-token` workflow shells to.
|
||||||
|
try {
|
||||||
|
const { spawnSync } = await import('node:child_process');
|
||||||
|
const res = spawnSync('secret-mgr', ['get-secret', '--key', 'hf-token'], {
|
||||||
|
env: { ...process.env, AGENT_ID: agentId },
|
||||||
|
encoding: 'utf8',
|
||||||
|
timeout: 5000,
|
||||||
|
});
|
||||||
|
if (res.status === 0 && res.stdout.trim()) return res.stdout.trim();
|
||||||
|
return null;
|
||||||
|
} catch {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
makeClient: (token: string) => new KBClient(kbBackendUrl, token),
|
||||||
turnFor: () => 0,
|
turnFor: () => 0,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user