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
26 changes: 13 additions & 13 deletions apps/daemon/internal/agent/claudesdk/execution_controls_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,20 @@ func TestExecutionControlsPreserveNativeDefaultsAndInstructions(t *testing.T) {
root := t.TempDir()
t.Setenv("OAC_RUNTIME_HOME", root)
config := Config{Entrypoint: filepath.Join(root, "worker"), StateDir: filepath.Join(root, "state")}
request := proto.PromptRequestPayload{ModelProvider: fixtureProvider(), RunID: "run", Input: proto.TextInput("Original input."), AgentSessionID: "native-session", Model: "native-model", SystemPrompt: "Keep these exact instructions.\nDo not replace them."}
ordinary, _, err := prepare(config, request)
request := proto.PromptRequestPayload{ModelProvider: fixtureProvider(), AgentSessionID: "native-session", Model: "native-model", SystemPrompt: "Keep these exact instructions.\nDo not replace them."}
ordinary, _, err := prepareConfiguration(config, request)
if err != nil {
t.Fatal(err)
}
request.ExecutionControls = &proto.ExecutionControls{WebSearch: "disabled", TextVerbosity: "medium"}
before, _ := json.Marshal(request)
controlled, _, err := prepare(config, request)
controlled, _, err := prepareConfiguration(config, request)
if err != nil {
t.Fatal(err)
}
after, _ := json.Marshal(request)
if !reflect.DeepEqual(ordinary, controlled) || string(before) != string(after) {
t.Fatal("default controls changed native input, instructions, continuation or caller options")
t.Fatal("default controls changed instructions, continuation or caller options")
}
}

Expand Down Expand Up @@ -81,21 +81,21 @@ func TestStructuredOutputConfigurationReachesNativeUnchanged(t *testing.T) {
t.Setenv("OAC_RUNTIME_HOME", root)
config := Config{Entrypoint: filepath.Join(root, "worker"), StateDir: filepath.Join(root, "state")}
schema := json.RawMessage(`{"type":"object","properties":{"n":{"const":9007199254740992}}}`)
request := proto.PromptRequestPayload{ModelProvider: fixtureProvider(), RunID: "run", Input: proto.TextInput("Original input."), ObserveMessages: true, DisableSubagents: true, Model: "model", SystemPrompt: "Original instructions.", ExecutionControls: &proto.ExecutionControls{WebSearch: "disabled", TextVerbosity: "medium", OutputFormat: &proto.OutputFormat{Type: "json_schema", Schema: schema}}}
start, _, err := prepare(config, request)
request := proto.PromptRequestPayload{ModelProvider: fixtureProvider(), ObserveMessages: true, DisableSubagents: true, Model: "model", SystemPrompt: "Original instructions.", ExecutionControls: &proto.ExecutionControls{WebSearch: "disabled", TextVerbosity: "medium", OutputFormat: &proto.OutputFormat{Type: "json_schema", Schema: schema}}}
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.DisableSubagents = false
if _, _, err := prepare(config, request); err == nil {
if _, _, err := prepareConfiguration(config, request); err == nil {
t.Fatal("unqualified subagent combination accepted")
}
}
Expand All @@ -104,21 +104,21 @@ func TestToolDiscoveryPreservesFrozenFunctionsAndRejectsOtherProfiles(t *testing
root := t.TempDir()
t.Setenv("OAC_RUNTIME_HOME", root)
config := Config{Entrypoint: filepath.Join(root, "worker"), StateDir: filepath.Join(root, "state")}
request := proto.PromptRequestPayload{ModelProvider: fixtureProvider(), RunID: "run", Input: proto.TextInput("Original input."), DisableSubagents: true, ToolSearch: true, Model: "model", FunctionTools: []proto.FunctionTool{
request := proto.PromptRequestPayload{ModelProvider: fixtureProvider(), DisableSubagents: true, ToolSearch: true, Model: "model", FunctionTools: []proto.FunctionTool{
{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.DisableSubagents = false
if _, _, err := prepare(config, request); err == nil {
if _, _, err := prepareConfiguration(config, request); err == nil {
t.Fatal("unqualified combination admitted")
}
request.DisableSubagents = true
request.ToolSearch = false
if _, _, err := prepare(config, request); err == nil {
if _, _, err := prepareConfiguration(config, request); err == nil {
t.Fatal("deferred definitions became eager")
}
}
10 changes: 5 additions & 5 deletions apps/daemon/internal/agent/claudesdk/executor_fixture_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,17 +30,17 @@ func startSingleTurn(ctx context.Context, config Config, req proto.PromptRequest
return turn, err
}

func helperTurn(scanner *bufio.Scanner, request *startRequest) (func(bridgeEvent), func()) {
func helperTurn(scanner *bufio.Scanner) (func(bridgeEvent), func()) {
_ = json.NewEncoder(os.Stdout).Encode(bridgeEvent{Type: "executor_ready", Protocol: 3})
if !scanner.Scan() {
os.Exit(4)
}
var start struct {
Type string `json:"type"`
TurnID string `json:"turn_id"`
Input json.RawMessage `json:"input"`
Type string `json:"type"`
TurnID string `json:"turn_id"`
Input proto.MessageInput `json:"input"`
}
if json.Unmarshal(scanner.Bytes(), &start) != nil || start.Type != "turn_start" || start.TurnID == "" || json.Unmarshal(start.Input, &request.Input) != nil {
if json.Unmarshal(scanner.Bytes(), &start) != nil || start.Type != "turn_start" || start.TurnID == "" {
os.Exit(5)
}
return helperTurnOutput(scanner, start.TurnID)
Expand Down
2 changes: 1 addition & 1 deletion apps/daemon/internal/agent/claudesdk/functions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
"github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto"
)

func TestFunctionFactoryNativeReceipts(t *testing.T) {
func TestFunctionTurnNativeReceipts(t *testing.T) {
for _, mode := range []string{"functions-success", "functions-wrong-receipt", "functions-no-receipt", "functions-cancel"} {
t.Run(mode, func(t *testing.T) {
root := t.TempDir()
Expand Down
16 changes: 8 additions & 8 deletions apps/daemon/internal/agent/claudesdk/local_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,25 +19,25 @@ func TestLocalWorkspaceBindingNetworkAndRequiredHistory(t *testing.T) {
req := workspaceRequest()
req.LocalEnvironment = &proto.LocalEnvironment{ID: "environment", NetworkAccess: "enabled", WorkspaceRoot: config.Workspace.Directory}
req.RequireExistingNativeSession = true
start, _, err := prepare(config, req)
start, _, err := prepareConfiguration(config, req)
if err != nil || !start.RequireHistory || start.Workspace.NetworkAccess != "enabled" {
t.Fatal(start, err)
}
req.LocalEnvironment.NetworkAccess = "disabled"
if _, _, err := prepare(config, req); err == nil {
if _, _, err := prepareConfiguration(config, req); err == nil {
t.Fatal("accepted different Runtime network policy")
}
req.LocalEnvironment.NetworkAccess = "enabled"
config.Workspace.PublicDirectory = config.Workspace.HomeDir
if _, _, err := prepare(config, req); err == nil {
if _, _, err := prepareConfiguration(config, req); err == nil {
t.Fatal("accepted a different public workspace")
}
alias := filepath.Join(filepath.Dir(config.Workspace.Directory), "alias")
if err := os.Symlink(config.Workspace.Directory, alias); err != nil {
t.Fatal(err)
}
config.Workspace.PublicDirectory = alias
if _, _, err := prepare(config, req); err != nil {
if _, _, err := prepareConfiguration(config, req); err != nil {
t.Fatal("same workspace alias rejected", err)
}

Expand All @@ -49,12 +49,12 @@ func TestRestrictedWorkspacePolicyUsesExactBoundAuthority(t *testing.T) {
config.Workspace.AllowedDomains = []string{"Example.com", "api.example.com", "example.com"}
req := workspaceRequest()
req.LocalEnvironment = &proto.LocalEnvironment{ID: "environment", NetworkAccess: "restricted", AllowedDomains: []string{"api.example.com", "EXAMPLE.COM"}, WorkspaceRoot: config.Workspace.Directory}
if _, _, err := prepare(config, req); err == nil {
if _, _, err := prepareConfiguration(config, req); err == nil {
t.Fatal("Runtime must not promise inner network isolation")
}
for _, domains := range [][]string{{"example.com"}, {"example.org"}, nil} {
req.LocalEnvironment.AllowedDomains = domains
if _, _, err := prepare(config, req); err == nil {
if _, _, err := prepareConfiguration(config, req); err == nil {
t.Fatal("different policy entered bound Runtime", domains)
}
}
Expand All @@ -65,7 +65,7 @@ func TestWorkspaceProviderCredentialsReplaceAmbientSelection(t *testing.T) {
original := slices.Clone(config.Env)
req := workspaceRequest()
req.ModelProvider = &modelprovider.Provider{Protocol: modelprovider.Anthropic, BaseURL: "https://provider.example/anthropic", APIKey: "selected-secret"}
start, env, err := prepare(config, req)
start, env, err := prepareConfiguration(config, req)
if err != nil {
t.Fatal(err)
}
Expand All @@ -78,7 +78,7 @@ func TestWorkspaceProviderCredentialsReplaceAmbientSelection(t *testing.T) {
}
for _, baseURL := range []string{"http://provider.example", "https://user:pass@provider.example"} {
req.ModelProvider = &modelprovider.Provider{Protocol: modelprovider.Anthropic, BaseURL: baseURL, APIKey: "secret"}
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
8 changes: 4 additions & 4 deletions apps/daemon/internal/agent/claudesdk/mcp_bearer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ func TestMCPBearerUsesFreshOwnedEnvironmentReferences(t *testing.T) {
{ConnectionOrigin: "service", ServerLabel: "second", ServerURL: "https://second.example/mcp", BearerToken: &tokens[1]},
{ConnectionOrigin: "service", ServerLabel: "anonymous", ServerURL: "http://anonymous.example/mcp"},
}
req := proto.PromptRequestPayload{ModelProvider: fixtureProvider(), RunID: "run", Input: proto.TextInput("hello"), DisableExecutionEnvironment: true, MCPHTTPServers: &servers, Model: "fixture"}
req := proto.PromptRequestPayload{ModelProvider: fixtureProvider(), DisableExecutionEnvironment: true, MCPHTTPServers: &servers, 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 @@ -66,8 +66,8 @@ func TestMCPBearerRejectsInvalidCredentialBeforeStateCreation(t *testing.T) {
t.Setenv("OAC_RUNTIME_HOME", root)
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{ModelProvider: fixtureProvider(), RunID: "run", Input: proto.TextInput("hello"), DisableExecutionEnvironment: true, MCPHTTPServers: &servers, Model: "fixture"}
if _, _, err := prepare(config, req); err == nil || err.Error() != "claudesdk: unsupported HTTPS MCP bearer credential" {
req := proto.PromptRequestPayload{ModelProvider: fixtureProvider(), DisableExecutionEnvironment: true, MCPHTTPServers: &servers, Model: "fixture"}
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
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ func TestEnvironmentMCPUsesInstalledLauncherAndSelectedCredential(t *testing.T)
{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},
}}
start, env, err := prepare(config, req)
start, env, err := prepareConfiguration(config, req)
if err != nil {
t.Fatal(err)
}
Expand Down
4 changes: 2 additions & 2 deletions apps/daemon/internal/agent/claudesdk/mcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func TestHTTPMCPDeclaration(t *testing.T) {
t.Setenv("OAC_RUNTIME_HOME", root)
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"}}
req := proto.PromptRequestPayload{ModelProvider: fixtureProvider(), RunID: "run", Input: proto.TextInput("hello"), DisableExecutionEnvironment: true, MCPHTTPServers: &servers, Model: "fixture"}
req := proto.PromptRequestPayload{ModelProvider: fixtureProvider(), DisableExecutionEnvironment: true, MCPHTTPServers: &servers, Model: "fixture"}
tools := []string{"echo"}
switch mode {
case "selected":
Expand Down 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"
if (err == nil) != valid {
t.Fatalf("unexpected admission: %v", err)
Expand Down
13 changes: 0 additions & 13 deletions apps/daemon/internal/agent/claudesdk/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ type startRequest struct {
Subagents *subagentOptions `json:"subagents,omitempty"`
OutputFormat *proto.OutputFormat `json:"output_format,omitempty"`
Type string `json:"type"`
Input proto.MessageInput `json:"input,omitempty"`
Model string `json:"model"`
SystemPrompt string `json:"system_prompt"`
Cwd string `json:"cwd"`
Expand All @@ -41,18 +40,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, provider, err := prepareOptions(req, req.MCPHTTPServers != nil || (req.LocalEnvironment != nil && len(req.LocalEnvironment.MCP) != 0))
if err != nil {
Expand Down
3 changes: 1 addition & 2 deletions apps/daemon/internal/agent/claudesdk/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,7 @@ func TestModelAndProviderAreRequired(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")}
tc.req.RunID, tc.req.Input = "run", proto.TextInput("hello")
start, _, err := prepare(config, tc.req)
start, _, err := prepareConfiguration(config, tc.req)
if !errors.Is(err, tc.err) || (err == nil) != (tc.err == nil) || start.SystemPrompt != tc.want {
t.Fatalf("system prompt %q, error %v", start.SystemPrompt, err)
}
Expand Down
2 changes: 1 addition & 1 deletion apps/daemon/internal/agent/claudesdk/preparation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func TestPreparationWaitsForReceiptAndRetainsConfiguration(t *testing.T) {
if err := json.Unmarshal(raw, &frozen); err != nil {
t.Fatal(err)
}
if frozen.Model != "fixture" || frozen.Resume != "native-session" || frozen.Workspace == nil || len(frozen.Input) != 0 {
if frozen.Model != "fixture" || frozen.Resume != "native-session" || frozen.Workspace == nil {
t.Fatal("configuration-only request was not retained")
}
config.Env[0] = "HTTPS_PROXY=http://changed.example"
Expand Down
2 changes: 1 addition & 1 deletion apps/daemon/internal/agent/claudesdk/restrictions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
"github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto"
)

func TestTextFactoryAcceptsRestrictiveCapabilities(t *testing.T) {
func TestTextTurnAcceptsRestrictiveCapabilities(t *testing.T) {
for _, test := range []struct {
name string
environment, subagents bool
Expand Down
6 changes: 3 additions & 3 deletions apps/daemon/internal/agent/claudesdk/session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
"github.com/MiniMax-AI/OpenAgentCore/internal/agentdaemon/proto"
)

func TestTextFactoryCompletionAndFailures(t *testing.T) {
func TestTextTurnCompletionAndFailures(t *testing.T) {
for _, mode := range []string{"success", "wrong-resume", "missing", "malformed", "process-failed", "after-result", "bridge-error"} {
t.Run(mode, func(t *testing.T) {
root := t.TempDir()
Expand Down Expand Up @@ -73,7 +73,7 @@ func TestTextFactoryCompletionAndFailures(t *testing.T) {
}
}

func TestTextFactoryRejectsUnsupportedInput(t *testing.T) {
func TestUnsupportedRequestRejectedBeforeLaunch(t *testing.T) {
for _, kind := range []string{"execution-controls", "tool", "outside"} {
t.Run(kind, func(t *testing.T) {
root := t.TempDir()
Expand Down Expand Up @@ -129,7 +129,7 @@ func runSDKHelper() {
if json.Unmarshal(scanner.Bytes(), &request) != nil || request.Type != "executor_prepare" || request.Model != "fake-model" || request.SystemPrompt != "instructions" {
os.Exit(3)
}
encode, finish := helperTurn(scanner, &request)
encode, finish := helperTurn(scanner)
defer finish()
mode := os.Getenv("SDK_HELPER_MODE")
if strings.HasPrefix(mode, "cancellation-") {
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 @@ -38,7 +38,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
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import (

// Run only inside a separately qualified outer placement, with its pinned native
// dependencies. This fixture does not create isolation or public admission.
func TestLiveClaudeWorkspaceFactory(t *testing.T) {
func TestLiveClaudeWorkspaceTurns(t *testing.T) {
configFile := os.Getenv("OAC_TEST_CLAUDE_WORKSPACE_LIVE_CONFIG")
if configFile == "" {
t.Skip("requires explicit qualified placement and real provider configuration")
Expand Down
Loading
Loading