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
2 changes: 0 additions & 2 deletions apps/daemon/internal/agent/claudesdk/contracts.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ var (
_ agent.FunctionResultSubmitter = (*session)(nil)
_ agent.WorkspaceReader = (*session)(nil)
_ agent.WorkspaceDirectoryLister = (*session)(nil)
_ agent.WorkspaceWriter = (*session)(nil)
_ agent.WorkspaceReader = (*executor)(nil)
_ agent.WorkspaceDirectoryLister = (*executor)(nil)
_ agent.WorkspaceWriter = (*executor)(nil)
)
28 changes: 14 additions & 14 deletions apps/daemon/internal/agent/claudesdk/execution_controls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@ func TestExecutionControlsPreserveNativeDefaultsAndInstructions(t *testing.T) {
t.Setenv("OAC_RUNTIME_HOME", root)
config := Config{Entrypoint: filepath.Join(root, "worker"), StateDir: filepath.Join(root, "state")}
request := proto.PromptRequestPayload{RunID: "run", Input: proto.TextInput("Original input."), AgentSessionID: "native-session", AgentOptions: map[string]any{"model": "native-model", "system_prompt": "Keep these exact instructions.\nDo not replace them."}}
ordinary, _, err := prepare(config, request)
ordinary, _, err := prepareConfiguration(config, request)
if err != nil {
t.Fatal(err)
}
request.ExecutionControls = &proto.ExecutionControls{WebSearch: &proto.WebSearchControl{Mode: "disabled", ContextSize: "medium"}, TextVerbosity: "medium"}
before, _ := json.Marshal(request)
controlled, _, err := prepare(config, request)
controlled, _, err := prepareConfiguration(config, request)
if err != nil {
t.Fatal(err)
}
Expand All @@ -38,7 +38,7 @@ func TestExecutionControlsPreserveNativeDefaultsAndInstructions(t *testing.T) {
}
// Without a search control Claude Code keeps its native web tools.
request.ExecutionControls = &proto.ExecutionControls{TextVerbosity: "medium"}
absent, _, err := prepare(config, request)
absent, _, err := prepareConfiguration(config, request)
if err != nil || !reflect.DeepEqual(ordinary, absent) {
t.Fatal("absent search control changed the native configuration", err)
}
Expand All @@ -48,14 +48,14 @@ func TestLiveWebSearchReachesTheBridgeOnEveryPlacement(t *testing.T) {
live := &proto.ExecutionControls{WebSearch: &proto.WebSearchControl{Mode: "live", ContextSize: "medium"}, TextVerbosity: "medium"}
root := t.TempDir()
t.Setenv("OAC_RUNTIME_HOME", root)
none, _, err := prepare(Config{Entrypoint: filepath.Join(root, "worker"), StateDir: filepath.Join(root, "state")}, proto.PromptRequestPayload{
none, _, err := prepareConfiguration(Config{Entrypoint: filepath.Join(root, "worker"), StateDir: filepath.Join(root, "state")}, proto.PromptRequestPayload{
RunID: "run", Input: proto.TextInput("Search."), ExecutionControls: live, AgentOptions: map[string]any{"model": "native-model"}})
if err != nil || none.WebSearch != "live" {
t.Fatal("live search on environment none did not reach the bridge", err)
}
request := workspaceRequest()
request.ExecutionControls = live
workspace, _, err := prepare(workspaceFixture(t), request)
workspace, _, err := prepareConfiguration(workspaceFixture(t), request)
if err != nil || workspace.WebSearch != "live" {
t.Fatal("live search on a workspace did not reach the bridge", err)
}
Expand Down Expand Up @@ -97,7 +97,7 @@ func TestReasoningEffortReachesNativeOptions(t *testing.T) {
config := Config{Entrypoint: filepath.Join(root, "worker"), StateDir: filepath.Join(root, "state")}
for _, effort := range []string{"low", "medium", "high", "xhigh", "max"} {
request := proto.PromptRequestPayload{RunID: "run", Input: proto.TextInput("hello"), ExecutionControls: &proto.ExecutionControls{TextVerbosity: "medium", ReasoningEffort: effort}, AgentOptions: map[string]any{"model": "native-model", "harness_config": map[string]any{"thinking": map[string]any{"type": "adaptive"}}}}
start, _, err := prepare(config, request)
start, _, err := prepareConfiguration(config, request)
if err != nil {
t.Fatal(effort, err)
}
Expand Down Expand Up @@ -128,21 +128,21 @@ func TestStructuredOutputConfigurationReachesNativeUnchanged(t *testing.T) {
config := Config{Entrypoint: filepath.Join(root, "worker"), StateDir: filepath.Join(root, "state")}
schema := json.RawMessage(`{"type":"object","properties":{"n":{"const":9007199254740992}}}`)
request := proto.PromptRequestPayload{RunID: "run", Input: proto.TextInput("Original input."), DisableSubagents: true, AgentOptions: map[string]any{"model": "model", "system_prompt": "Original instructions."}, ExecutionControls: &proto.ExecutionControls{TextVerbosity: "medium", OutputFormat: &proto.OutputFormat{Type: "json_schema", Schema: schema}}}
start, _, err := prepare(config, request)
start, _, err := prepareConfiguration(config, request)
if err != nil {
t.Fatal(err)
}
if start.OutputFormat == nil || string(start.OutputFormat.Schema) != string(schema) || *start.Input[0].Content[0].Text != *request.Input[0].Content[0].Text || start.SystemPrompt != "Original instructions." {
if start.OutputFormat == nil || string(start.OutputFormat.Schema) != string(schema) || start.SystemPrompt != "Original instructions." {
t.Fatal("native configuration changed")
}
request.ExecutionControls.OutputFormat.Schema = json.RawMessage(`{"type":"object","const":9007199254740993}`)
if _, _, err := prepare(config, request); err == nil {
if _, _, err := prepareConfiguration(config, request); err == nil {
t.Fatal("lossy schema accepted")
}
request.ExecutionControls.OutputFormat.Schema = schema
request.DisableExecutionEnvironment = true
request.MCPHTTPServers = &[]proto.MCPHTTPServer{{ConnectionOrigin: "service", ServerLabel: "fixture", ServerURL: "https://example.invalid/mcp"}}
if start, _, err := prepare(config, request); err != nil || start.OutputFormat == nil {
if start, _, err := prepareConfiguration(config, request); err != nil || start.OutputFormat == nil {
t.Fatal("native structured output was narrowed by MCP", err)
}
}
Expand All @@ -155,17 +155,17 @@ func TestToolDiscoveryPreservesFrozenFunctionsBesideOtherProfiles(t *testing.T)
{Name: "lookup", Description: "Lookup", Parameters: json.RawMessage(`{"type":"object","properties":{"ticket":{"const":"original"}}}`), DeferLoading: true},
{Name: "clock", Description: "Clock", Parameters: json.RawMessage(`{"type":"object"}`)},
}}
start, _, err := prepare(config, request)
start, _, err := prepareConfiguration(config, request)
if err != nil || !start.ToolSearch || !reflect.DeepEqual(start.Functions, request.FunctionTools) {
t.Fatal("function discovery changed native definitions", err)
}
request.ExecutionControls = &proto.ExecutionControls{TextVerbosity: "medium", OutputFormat: &proto.OutputFormat{Type: "json_schema", Schema: json.RawMessage(`{"type":"object"}`)}}
if start, _, err := prepare(config, request); err != nil || !start.ToolSearch || start.OutputFormat == nil {
if start, _, err := prepareConfiguration(config, request); err != nil || !start.ToolSearch || start.OutputFormat == nil {
t.Fatal("native tool search was narrowed by structured output", err)
}
request.ExecutionControls = nil
request.ToolSearch = false
if _, _, err := prepare(config, request); err == nil {
if _, _, err := prepareConfiguration(config, request); err == nil {
t.Fatal("deferred definitions became eager")
}
}
Expand All @@ -177,7 +177,7 @@ func TestReasoningSummaryReachesTheBridgeOnlyWhenRequested(t *testing.T) {
request := proto.PromptRequestPayload{RunID: "run", Input: proto.TextInput("Input."), AgentOptions: map[string]any{"model": "native-model"}}
for _, summary := range []string{"", "auto"} {
request.ExecutionControls = &proto.ExecutionControls{TextVerbosity: "medium", ReasoningSummary: summary}
start, _, err := prepare(config, request)
start, _, err := prepareConfiguration(config, request)
if err != nil || start.ReasoningSummary != (summary != "") {
t.Fatalf("summary %q: reasoning flag %v, err %v", summary, start.ReasoningSummary, err)
}
Expand Down
6 changes: 3 additions & 3 deletions apps/daemon/internal/agent/claudesdk/local_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func TestLocalWorkspaceBindingAndRequiredHistory(t *testing.T) {
req := workspaceRequest()
req.LocalEnvironment = &proto.LocalEnvironment{ID: "environment", WorkspaceRoot: config.Workspace.Directory}
req.RequireExistingNativeSession = true
start, _, err := prepare(config, req)
start, _, err := prepareConfiguration(config, req)
if err != nil || !start.RequireHistory {
t.Fatal(start, err)
}
Expand All @@ -26,7 +26,7 @@ func TestWorkspaceProviderCredentialsReplaceAmbientSelection(t *testing.T) {
original := slices.Clone(config.Env)
req := workspaceRequest()
req.AgentOptions["model_provider"] = map[string]any{"protocol": "anthropic", "base_url": "https://provider.example/anthropic", "api_key": "selected-secret", "context_window": 64000, "max_output_tokens": 4096}
start, env, err := prepare(config, req)
start, env, err := prepareConfiguration(config, req)
if err != nil {
t.Fatal(err)
}
Expand All @@ -42,7 +42,7 @@ func TestWorkspaceProviderCredentialsReplaceAmbientSelection(t *testing.T) {
}
for _, value := range []any{nil, "secret", map[string]any{"protocol": "anthropic", "base_url": "http://provider.example", "api_key": "secret"}, map[string]any{"protocol": "anthropic", "base_url": "https://user:pass@provider.example", "api_key": "secret"}} {
req.AgentOptions["model_provider"] = value
if _, _, err := prepare(config, req); err == nil || strings.Contains(err.Error(), "secret") {
if _, _, err := prepareConfiguration(config, req); err == nil || strings.Contains(err.Error(), "secret") {
t.Fatal("unsafe provider accepted or disclosed")
}
}
Expand Down
4 changes: 2 additions & 2 deletions apps/daemon/internal/agent/claudesdk/mcp_bearer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func TestMCPBearerUsesFreshOwnedEnvironmentReferences(t *testing.T) {
req := proto.PromptRequestPayload{RunID: "run", Input: proto.TextInput("hello"), DisableExecutionEnvironment: true, MCPHTTPServers: &servers, AgentOptions: map[string]any{"model": "fixture"}}
seen := map[string]bool{}
for range 2 {
start, env, err := prepare(config, req)
start, env, err := prepareConfiguration(config, req)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -67,7 +67,7 @@ func TestMCPBearerRejectsInvalidCredentialBeforeStateCreation(t *testing.T) {
config := Config{Entrypoint: filepath.Join(root, "main.js"), StateDir: filepath.Join(root, "state")}
servers := []proto.MCPHTTPServer{{ConnectionOrigin: "service", ServerLabel: "fixture", ServerURL: "https://example.invalid/mcp", BearerToken: &token}}
req := proto.PromptRequestPayload{RunID: "run", Input: proto.TextInput("hello"), DisableExecutionEnvironment: true, MCPHTTPServers: &servers, AgentOptions: map[string]any{"model": "fixture"}}
if _, _, err := prepare(config, req); err == nil || err.Error() != "claudesdk: unsupported HTTPS MCP bearer credential" {
if _, _, err := prepareConfiguration(config, req); err == nil || err.Error() != "claudesdk: unsupported HTTPS MCP bearer credential" {
t.Fatal("invalid bearer accepted or unsafe error returned")
}
entries, err := os.ReadDir(root)
Expand Down
8 changes: 4 additions & 4 deletions apps/daemon/internal/agent/claudesdk/mcp_environment_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ func TestEnvironmentMCPUsesInstalledLauncherAndSelectedCredential(t *testing.T)
token := "selected-user-token"
t.Setenv("MCP_TOKEN", "unselected-native-token")
req.LocalEnvironment = &proto.LocalEnvironment{CapabilityRoot: "/private/runtime/capabilities", WorkspaceRoot: config.Workspace.Directory, MCP: []proto.EnvironmentMCP{
{InstallationRoot: "/private/runtime/capabilities", WorkspaceRoot: "/private/runtime/workspace", PackageRoot: "plugins/local", Server: agentplugin.MCPServer{Name: "local", Type: "stdio", Command: "untrusted-package-command", Args: []string{"package-argument"}, EnvVars: []string{"MCP_TOKEN"}}},
{InstallationRoot: "/private/runtime/capabilities", WorkspaceRoot: "/private/runtime/workspace", PackageRoot: "plugins/remote", Server: agentplugin.MCPServer{Name: "remote", Type: "http", URL: "https://example.invalid/mcp", BearerTokenEnvVar: "MCP_TOKEN"}, BearerToken: &token},
{InstallationRoot: "/private/runtime/capabilities", PackageRoot: "plugins/local", Server: agentplugin.MCPServer{Name: "local", Type: "stdio", Command: "untrusted-package-command", Args: []string{"package-argument"}, EnvVars: []string{"MCP_TOKEN"}}},
{InstallationRoot: "/private/runtime/capabilities", PackageRoot: "plugins/remote", Server: agentplugin.MCPServer{Name: "remote", Type: "http", URL: "https://example.invalid/mcp", BearerTokenEnvVar: "MCP_TOKEN"}, BearerToken: &token},
}}
start, env, err := prepare(config, req)
start, env, err := prepareConfiguration(config, req)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -63,7 +63,7 @@ func TestEnvironmentMCPRejectsUnqualifiedCombinations(t *testing.T) {
e.MCP[0].Server.URL = "http://example.invalid/mcp"
},
} {
environment := &proto.LocalEnvironment{MCP: []proto.EnvironmentMCP{{InstallationRoot: "/private/runtime/capabilities", WorkspaceRoot: "/private/runtime/workspace", PackageRoot: "plugins/remote", Server: agentplugin.MCPServer{Name: "remote", Type: "http", URL: "https://example.invalid/mcp"}}}}
environment := &proto.LocalEnvironment{MCP: []proto.EnvironmentMCP{{InstallationRoot: "/private/runtime/capabilities", PackageRoot: "plugins/remote", Server: agentplugin.MCPServer{Name: "remote", Type: "http", URL: "https://example.invalid/mcp"}}}}
mutate(environment)
if _, _, err := prepareRuntimeMCP(proto.PromptRequestPayload{LocalEnvironment: environment}); err == nil {
t.Fatal("unsupported declaration accepted")
Expand Down
2 changes: 1 addition & 1 deletion apps/daemon/internal/agent/claudesdk/mcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func TestHTTPMCPDeclaration(t *testing.T) {
case "environment":
req.DisableExecutionEnvironment = false
}
start, _, err := prepare(config, req)
start, _, err := prepareConfiguration(config, req)
valid := mode == "unrestricted" || mode == "selected" || mode == "empty" || mode == "nil-slice" || mode == "auth" || mode == "required" || mode == "query" || mode == "wildcard"
if (err == nil) != valid {
t.Fatalf("unexpected admission: %v", err)
Expand Down
12 changes: 0 additions & 12 deletions apps/daemon/internal/agent/claudesdk/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,18 +41,6 @@ type startRequest struct {
RequireHistory bool `json:"require_history,omitempty"`
}

func prepare(config Config, req proto.PromptRequestPayload) (startRequest, []string, error) {
if req.RunID == "" || req.Input.Validate() != nil {
return startRequest{}, nil, fmt.Errorf("claudesdk: run id and prompt are required")
}
start, env, err := prepareConfiguration(config, req)
if err != nil {
return startRequest{}, nil, err
}
start.Input = req.Input
return start, env, nil
}

func prepareConfiguration(config Config, req proto.PromptRequestPayload) (startRequest, []string, error) {
start := startRequest{Type: "start", Resume: req.AgentSessionID, RequireHistory: req.RequireExistingNativeSession, Functions: req.FunctionTools}
fail := func(reason string) (startRequest, []string, error) {
Expand Down
2 changes: 1 addition & 1 deletion apps/daemon/internal/agent/claudesdk/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func TestNullableSystemPrompt(t *testing.T) {
root := t.TempDir()
t.Setenv("OAC_RUNTIME_HOME", root)
config := Config{Entrypoint: filepath.Join(root, "main.js"), StateDir: filepath.Join(root, "state")}
start, _, err := prepare(config, proto.PromptRequestPayload{RunID: "run", Input: proto.TextInput("hello"), AgentOptions: tc.options})
start, _, err := prepareConfiguration(config, proto.PromptRequestPayload{RunID: "run", Input: proto.TextInput("hello"), AgentOptions: tc.options})
if (err != nil) != tc.reject || (!tc.reject && start.SystemPrompt != tc.want) {
t.Fatalf("system prompt %q, error %v", start.SystemPrompt, err)
}
Expand Down
8 changes: 4 additions & 4 deletions apps/daemon/internal/agent/claudesdk/subagents_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,18 @@ import (
func TestSubagentConfigurationUsesExplicitRequestAndFrozenLimit(t *testing.T) {
config := workspaceFixture(t)
req := workspaceRequest()
start, _, err := prepare(config, req)
start, _, err := prepareConfiguration(config, req)
if err != nil || start.Subagents != nil {
t.Fatal("ordinary execution changed", err)
}
req.DisableSubagents, req.ObserveSubagentIdentities = false, true
start, _, err = prepare(config, req)
start, _, err = prepareConfiguration(config, req)
if err != nil || start.Subagents == nil || start.Subagents.MaxConcurrent != 6 {
t.Fatal("missing default native admission limit", err)
}
limit := 2
req.MaxConcurrentSubagents = &limit
start, _, err = prepare(config, req)
start, _, err = prepareConfiguration(config, req)
limit = 4
if err != nil || start.Subagents.MaxConcurrent != 2 {
t.Fatal("subagent configuration was not frozen", err)
Expand All @@ -36,7 +36,7 @@ func TestSubagentConfigurationRejectsUnqualifiedAuthority(t *testing.T) {
req := workspaceRequest()
req.DisableSubagents, req.ObserveSubagentIdentities = false, true
change(&req)
if _, _, err := prepare(config, req); err == nil {
if _, _, err := prepareConfiguration(config, req); err == nil {
t.Fatal("unqualified subagent combination accepted")
}
}
Expand Down
15 changes: 0 additions & 15 deletions apps/daemon/internal/agent/claudesdk/unsupported.go

This file was deleted.

34 changes: 0 additions & 34 deletions apps/daemon/internal/agent/claudesdk/unsupported_test.go

This file was deleted.

4 changes: 2 additions & 2 deletions apps/daemon/internal/agent/claudesdk/usage_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ func TestUsageTransportPreservesSnapshotOnFailureAndDone(t *testing.T) {
}
var want map[string]any
_ = json.Unmarshal([]byte(original), &want)
if observed.Provider != "claude_code" || !reflect.DeepEqual(observed.Raw["claude_sdk_result"], want) || observed.Model != "" || observed.Tokens != nil || observed.CostUSD != 0 || observed.InputTokens != 0 || observed.OutputTokens != 0 {
if observed.Provider != "claude_code" || !reflect.DeepEqual(observed.Raw["claude_sdk_result"], want) || observed.Model != "" || observed.Tokens != nil {
t.Fatalf("usage normalized or lost: %+v", observed)
}
}
Expand Down Expand Up @@ -137,7 +137,7 @@ func verifyLiveUsageEvents(t *testing.T, events []proto.Envelope) {
}
}
}
if count < 1 || observed.Tokens != nil || observed.Model != "" || observed.CostUSD != 0 {
if count < 1 || observed.Tokens != nil || observed.Model != "" {
t.Fatal("live native evidence became unsupported public accounting")
}
if count > 1 {
Expand Down
Loading
Loading