feat: read agent_id from ctx (SDK now plumbs it)

Plexum-sdk-go now propagates the caller agent id via
`_meta.agent_id` on tools/call. AgentIDFromCtx prefers
plugin.AgentIDFromContext(ctx); falls back to the
single-active-calendar-slot heuristic for host-driven dispatch
paths (channel manager, CLI plugin-call) that lack ctx.

Drops bestEffortAgentID — the inline closure does the same thing
without the dead-Slot-iterate noise.
This commit is contained in:
h z
2026-06-03 12:54:57 +01:00
parent bc1ab7b6ea
commit 472cecd771

View File

@@ -131,15 +131,16 @@ func (p *harborForgePlugin) Init(ctx context.Context, host sdkplugin.HostAPI) er
Scheduler: p.sched, Scheduler: p.sched,
Host: host, Host: host,
AgentIDFromCtx: func(ctx context.Context) string { AgentIDFromCtx: func(ctx context.Context) string {
// Plexum stashes the calling agent id on the host-side // Host attaches the caller agent id via tools/call
// context (via WithAgent) before dispatching tool calls. // `_meta.agent_id`; SDK unpacks it into ctx.
// We can't directly import internal/agentloop from a if id := sdkplugin.AgentIDFromContext(ctx); id != "" {
// plugin, so we rely on PLEXUM_TOOL_AGENT_ID env-style return id
// (set per-call by host when we add that wiring) or fall }
// back to the only-active-agent heuristic. v1: prefer the // Fallback for host paths that don't carry an agent
// only-active wake-target (deterministic in single-agent // (channel-driven, CLI plugin-call). When a single
// HF deployments). // calendar slot is active we can deterministically
return p.bestEffortAgentID() // attribute the call to that slot's owner.
return p.sched.SingleActiveAgentID()
}, },
} }
@@ -209,28 +210,6 @@ func mapStateToCalendar(s string) calendar.AgentStatusValue {
return calendar.AgentStatusOffline return calendar.AgentStatusOffline
} }
// bestEffortAgentID is a v1 stop-gap for tools that need the calling
// agent's id but don't have it on the ctx (Plexum SDK doesn't yet
// expose this — TODO upstream). v1: if exactly one agent has an
// active calendar slot we return it; otherwise empty. The calendar
// tools (the only ones that need agent context) usually fire when
// exactly one slot is active.
func (p *harborForgePlugin) bestEffortAgentID() string {
sch := p.sched.Status()
if len(sch.Active) != 1 {
return ""
}
// We don't track AgentID on Slot directly — the scheduler keeps
// activeByAgentID. Iterate to find the one.
for _, a := range sch.Active {
// Slot is shared between agents only via the scheduler's maps;
// here we have just the Slot struct without owner.
_ = a
}
// Fallback to scheduler's helper:
return p.sched.SingleActiveAgentID()
}
func manifestFromDisk() sdkplugin.Manifest { func manifestFromDisk() sdkplugin.Manifest {
// Bundled manifest.json is the authoritative shape; the binary // Bundled manifest.json is the authoritative shape; the binary
// version reads it next to itself to avoid hand-syncing two // version reads it next to itself to avoid hand-syncing two