Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions internal/common/task_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,21 @@ func AugmentArgsForTask(task *types.Task, args []string, opts TaskAugmentOptions
args = append(args, "--harness", harness)
}
}

// Pass public session-sharing if configured. This is additive to the
// collaborator-oriented --share args already set by the worker launcher
// (team:edit). The bundled Warp client applies an anyone-with-link ACL
// after the session bootstraps; the workspace-level
// AnyoneWithLinkSharingEnabled setting still gates whether the ACL
// write succeeds. FULL is rejected at the public API layer, so we only
// expect VIEWER or EDITOR here and silently skip unsupported values
// as a defensive fallback.
if task.AgentConfigSnapshot.SessionSharing != nil &&
task.AgentConfigSnapshot.SessionSharing.PublicAccess != nil {
if level := shareAccessLevelForEmission(*task.AgentConfigSnapshot.SessionSharing.PublicAccess); level != "" {
args = append(args, "--share", fmt.Sprintf("public:%s", level))
}
}
}

if task.AgentConfigSnapshot != nil && task.AgentConfigSnapshot.EnvironmentID != nil {
Expand All @@ -86,6 +101,21 @@ func AugmentArgsForTask(task *types.Task, args []string, opts TaskAugmentOptions
return args
}

// shareAccessLevelForEmission maps an internal AccessLevel to the string
// accepted by the CLI's --share flag. Returns empty string for values that
// the CLI cannot represent (e.g. FULL), in which case the caller should
// omit the emission entirely.
func shareAccessLevelForEmission(access types.AccessLevel) string {
switch access {
case types.AccessLevelViewer:
return "view"
case types.AccessLevelEditor:
return "edit"
default:
return ""
}
}

func resolveIdleOnComplete(task *types.Task, opts TaskAugmentOptions) (string, bool) {
if task != nil &&
task.AgentConfigSnapshot != nil &&
Expand Down
59 changes: 57 additions & 2 deletions internal/common/task_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import (
"github.com/warpdotdev/oz-agent-worker/internal/types"
)

func strPtr(v string) *string { return &v }
func intPtr(v int) *int { return &v }
func strPtr(v string) *string { return &v }
func intPtr(v int) *int { return &v }
func accessPtr(v types.AccessLevel) *types.AccessLevel { return &v }

func TestAugmentArgsForTask_IdleOnCompletePrecedence(t *testing.T) {
baseArgs := []string{"agent", "run"}
Expand Down Expand Up @@ -86,6 +87,60 @@ func TestAugmentArgsForTask_IdleOnCompletePrecedence(t *testing.T) {
opts: TaskAugmentOptions{},
expected: []string{"agent", "run", "--model", "claude-sonnet-4", "--idle-on-complete", "12m"},
},
{
name: "adds --share public:view when session_sharing.public_access is VIEWER",
task: &types.Task{
AgentConfigSnapshot: &types.AmbientAgentConfig{
SessionSharing: &types.SessionSharingConfig{
PublicAccess: accessPtr(types.AccessLevelViewer),
},
},
},
opts: TaskAugmentOptions{},
expected: []string{"agent", "run", "--share", "public:view", "--idle-on-complete"},
},
{
name: "adds --share public:edit when session_sharing.public_access is EDITOR",
task: &types.Task{
AgentConfigSnapshot: &types.AmbientAgentConfig{
SessionSharing: &types.SessionSharingConfig{
PublicAccess: accessPtr(types.AccessLevelEditor),
},
},
},
opts: TaskAugmentOptions{},
expected: []string{"agent", "run", "--share", "public:edit", "--idle-on-complete"},
},
{
name: "skips --share public when session_sharing is absent",
task: &types.Task{
AgentConfigSnapshot: &types.AmbientAgentConfig{},
},
opts: TaskAugmentOptions{},
expected: []string{"agent", "run", "--idle-on-complete"},
},
{
name: "skips --share public when public_access is nil",
task: &types.Task{
AgentConfigSnapshot: &types.AmbientAgentConfig{
SessionSharing: &types.SessionSharingConfig{},
},
},
opts: TaskAugmentOptions{},
expected: []string{"agent", "run", "--idle-on-complete"},
},
{
name: "silently omits --share public for unsupported access levels (defensive: FULL rejected earlier)",
task: &types.Task{
AgentConfigSnapshot: &types.AmbientAgentConfig{
SessionSharing: &types.SessionSharingConfig{
PublicAccess: accessPtr(types.AccessLevel("FULL")),
},
},
},
opts: TaskAugmentOptions{},
expected: []string{"agent", "run", "--idle-on-complete"},
},
}

for _, tt := range tests {
Expand Down
19 changes: 19 additions & 0 deletions internal/types/messages.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,24 @@ type HarnessAuthSecrets struct {
ClaudeAuthSecretName *string `json:"claude_auth_secret_name,omitempty"`
}

// AccessLevel is the serialized access-level string used inside SessionSharingConfig.
// Values mirror warp-server's model/types/enums.AccessLevel JSON representation.
type AccessLevel string

const (
AccessLevelViewer AccessLevel = "VIEWER"
AccessLevelEditor AccessLevel = "EDITOR"
)

// SessionSharingConfig mirrors warp-server's sources.SessionSharingConfig and
// carries the session-sharing choices snapshotted onto the run.
type SessionSharingConfig struct {
// PublicAccess, when set, causes the worker to emit --share public:<level>
// so the bundled Warp client applies an anyone-with-link ACL after the
// shared session bootstraps.
PublicAccess *AccessLevel `json:"public_access,omitempty"`
}

// AmbientAgentConfig represents the agent configuration.
type AmbientAgentConfig struct {
EnvironmentID *string `json:"environment_id,omitempty"`
Expand All @@ -90,6 +108,7 @@ type AmbientAgentConfig struct {
IdleTimeoutMinutes *int `json:"idle_timeout_minutes,omitempty"`
Harness *Harness `json:"harness,omitempty"`
HarnessAuthSecrets *HarnessAuthSecrets `json:"harness_auth_secrets,omitempty"`
SessionSharing *SessionSharingConfig `json:"session_sharing,omitempty"`
}

// Task represents an ambient agent job.
Expand Down
Loading