| 790 | } |
| 791 | |
| 792 | func (f *runExecFlags) createLocalRuntimeAndSession(ctx context.Context, loadResult *teamloader.LoadResult, req runtime.CreateSessionRequest, sessStore session.Store) (runtime.Runtime, *session.Session, error) { |
| 793 | t := loadResult.Team |
| 794 | |
| 795 | // Merge user-level global permissions into the team's checker so the |
| 796 | // runtime receives a single, already-merged permission set. |
| 797 | if req.GlobalPermissions != nil && !req.GlobalPermissions.IsEmpty() { |
| 798 | t.SetPermissions(permissions.Merge(t.Permissions(), req.GlobalPermissions)) |
| 799 | } |
| 800 | |
| 801 | agt, err := t.AgentOrDefault(req.AgentName) |
| 802 | if err != nil { |
| 803 | return nil, nil, err |
| 804 | } |
| 805 | agentName := agt.Name() |
| 806 | |
| 807 | rtOpts, ctrl, err := f.snapshotRuntimeOpts() |
| 808 | if err != nil { |
| 809 | return nil, nil, err |
| 810 | } |
| 811 | runtimeOpts := append(f.runtimeOpts(loadResult, &f.runConfig, sessStore, agentName), rtOpts...) |
| 812 | localRt, err := runtime.New(ctx, t, runtimeOpts...) |
| 813 | if err != nil { |
| 814 | return nil, nil, fmt.Errorf("creating runtime: %w", err) |
| 815 | } |
| 816 | f.snapshotController = ctrl |
| 817 | |
| 818 | var sess *session.Session |
| 819 | if req.ResumeSessionID != "" { |
| 820 | // Resolve relative session references (e.g., "-1" for last session) |
| 821 | resolvedID, err := session.ResolveSessionID(ctx, sessStore, req.ResumeSessionID) |
| 822 | if err != nil { |
| 823 | return nil, nil, fmt.Errorf("resolving session %q: %w", req.ResumeSessionID, err) |
| 824 | } |
| 825 | |
| 826 | // Load existing session |
| 827 | sess, err = sessStore.GetSession(ctx, resolvedID) |
| 828 | switch { |
| 829 | case err == nil: |
| 830 | sess.ToolsApproved = req.ToolsApproved |
| 831 | sess.HideToolResults = req.HideToolResults |
| 832 | |
| 833 | // Apply any stored model overrides from the session |
| 834 | if len(sess.AgentModelOverrides) > 0 && localRt.SupportsModelSwitching() { |
| 835 | for agentName, modelRef := range sess.AgentModelOverrides { |
| 836 | if err := localRt.SetAgentModel(ctx, agentName, modelRef); err != nil { |
| 837 | slog.WarnContext(ctx, "Failed to apply stored model override", "agent", agentName, "model", modelRef, "error", err) |
| 838 | } |
| 839 | } |
| 840 | } |
| 841 | |
| 842 | slog.DebugContext(ctx, "Loaded existing session", "session_id", resolvedID, "session_ref", req.ResumeSessionID, "agent", agentName) |
| 843 | case errors.Is(err, session.ErrNotFound) && !session.IsRelativeSessionRef(req.ResumeSessionID): |
| 844 | // An explicit, caller-chosen ID that doesn't exist yet: create the |
| 845 | // session with that ID rather than failing. This lets a supervisor |
| 846 | // (e.g. a board reconnecting to a dead agent) own the ID up front and |
| 847 | // reuse it across runs — the first run creates, later runs resume. |
| 848 | // A relative ref (-1, -2, ...) never lands here: it must resolve |
| 849 | // against existing sessions. |