mirror of
https://github.com/sipeed/picoclaw.git
synced 2026-06-12 18:08:54 +00:00
refactor(context): carry route and scope through runtime
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package session
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/sipeed/picoclaw/pkg/routing"
|
||||
@@ -10,6 +11,7 @@ import (
|
||||
// The current implementation intentionally preserves the legacy session-key
|
||||
// layout while moving key construction out of the router.
|
||||
type Allocation struct {
|
||||
Scope SessionScope
|
||||
SessionKey string
|
||||
MainSessionKey string
|
||||
}
|
||||
@@ -27,6 +29,7 @@ type AllocationInput struct {
|
||||
// AllocateRouteSession maps a route decision onto the current legacy
|
||||
// agent-scoped session-key format.
|
||||
func AllocateRouteSession(input AllocationInput) Allocation {
|
||||
scope := buildSessionScope(input)
|
||||
sessionKey := strings.ToLower(routing.BuildAgentPeerSessionKey(routing.SessionKeyParams{
|
||||
AgentID: input.AgentID,
|
||||
Channel: input.Channel,
|
||||
@@ -37,7 +40,58 @@ func AllocateRouteSession(input AllocationInput) Allocation {
|
||||
}))
|
||||
mainSessionKey := strings.ToLower(routing.BuildAgentMainSessionKey(input.AgentID))
|
||||
return Allocation{
|
||||
Scope: scope,
|
||||
SessionKey: sessionKey,
|
||||
MainSessionKey: mainSessionKey,
|
||||
}
|
||||
}
|
||||
|
||||
func buildSessionScope(input AllocationInput) SessionScope {
|
||||
scope := SessionScope{
|
||||
Version: ScopeVersionV1,
|
||||
AgentID: routing.NormalizeAgentID(input.AgentID),
|
||||
Channel: strings.ToLower(strings.TrimSpace(input.Channel)),
|
||||
Account: routing.NormalizeAccountID(input.AccountID),
|
||||
}
|
||||
|
||||
peer := input.Peer
|
||||
if peer == nil {
|
||||
peer = &routing.RoutePeer{Kind: "direct"}
|
||||
}
|
||||
|
||||
peerKind := strings.ToLower(strings.TrimSpace(peer.Kind))
|
||||
if peerKind == "" {
|
||||
peerKind = "direct"
|
||||
}
|
||||
|
||||
switch peerKind {
|
||||
case "direct":
|
||||
if input.SessionPolicy.DMScope == routing.DMScopeMain {
|
||||
return scope
|
||||
}
|
||||
peerID := routing.CanonicalSessionPeerID(
|
||||
input.Channel,
|
||||
peer.ID,
|
||||
input.SessionPolicy.DMScope,
|
||||
input.SessionPolicy.IdentityLinks,
|
||||
)
|
||||
if peerID == "" {
|
||||
return scope
|
||||
}
|
||||
scope.Dimensions = []string{"sender"}
|
||||
scope.Values = map[string]string{
|
||||
"sender": peerID,
|
||||
}
|
||||
default:
|
||||
peerID := strings.ToLower(strings.TrimSpace(peer.ID))
|
||||
if peerID == "" {
|
||||
peerID = "unknown"
|
||||
}
|
||||
scope.Dimensions = []string{"chat"}
|
||||
scope.Values = map[string]string{
|
||||
"chat": fmt.Sprintf("%s:%s", peerKind, peerID),
|
||||
}
|
||||
}
|
||||
|
||||
return scope
|
||||
}
|
||||
|
||||
@@ -26,6 +26,15 @@ func TestAllocateRouteSession_PerPeerDM(t *testing.T) {
|
||||
if allocation.MainSessionKey != "agent:main:main" {
|
||||
t.Fatalf("MainSessionKey = %q, want %q", allocation.MainSessionKey, "agent:main:main")
|
||||
}
|
||||
if allocation.Scope.Version != ScopeVersionV1 {
|
||||
t.Fatalf("Scope.Version = %d, want %d", allocation.Scope.Version, ScopeVersionV1)
|
||||
}
|
||||
if len(allocation.Scope.Dimensions) != 1 || allocation.Scope.Dimensions[0] != "sender" {
|
||||
t.Fatalf("Scope.Dimensions = %v, want [sender]", allocation.Scope.Dimensions)
|
||||
}
|
||||
if allocation.Scope.Values["sender"] != "user123" {
|
||||
t.Fatalf("Scope.Values[sender] = %q, want user123", allocation.Scope.Values["sender"])
|
||||
}
|
||||
}
|
||||
|
||||
func TestAllocateRouteSession_GroupPeer(t *testing.T) {
|
||||
@@ -48,4 +57,10 @@ func TestAllocateRouteSession_GroupPeer(t *testing.T) {
|
||||
if allocation.MainSessionKey != "agent:main:main" {
|
||||
t.Fatalf("MainSessionKey = %q, want %q", allocation.MainSessionKey, "agent:main:main")
|
||||
}
|
||||
if len(allocation.Scope.Dimensions) != 1 || allocation.Scope.Dimensions[0] != "chat" {
|
||||
t.Fatalf("Scope.Dimensions = %v, want [chat]", allocation.Scope.Dimensions)
|
||||
}
|
||||
if allocation.Scope.Values["chat"] != "channel:c001" {
|
||||
t.Fatalf("Scope.Values[chat] = %q, want channel:c001", allocation.Scope.Values["chat"])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
package session
|
||||
|
||||
// ScopeVersionV1 is the first structured session-scope schema version.
|
||||
const ScopeVersionV1 = 1
|
||||
|
||||
// SessionScope describes the semantic session partition selected for a turn.
|
||||
type SessionScope struct {
|
||||
Version int `json:"version"`
|
||||
AgentID string `json:"agent_id"`
|
||||
Channel string `json:"channel"`
|
||||
Account string `json:"account"`
|
||||
Dimensions []string `json:"dimensions"`
|
||||
Values map[string]string `json:"values"`
|
||||
}
|
||||
|
||||
// CloneScope returns a deep copy of scope.
|
||||
func CloneScope(scope *SessionScope) *SessionScope {
|
||||
if scope == nil {
|
||||
return nil
|
||||
}
|
||||
cloned := *scope
|
||||
if len(scope.Dimensions) > 0 {
|
||||
cloned.Dimensions = append([]string(nil), scope.Dimensions...)
|
||||
}
|
||||
if len(scope.Values) > 0 {
|
||||
cloned.Values = make(map[string]string, len(scope.Values))
|
||||
for key, value := range scope.Values {
|
||||
cloned.Values[key] = value
|
||||
}
|
||||
}
|
||||
return &cloned
|
||||
}
|
||||
Reference in New Issue
Block a user