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
1 change: 0 additions & 1 deletion .github/workflows/cache-warm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@ jobs:
node-version: '22.22.0'
lockfiles: |
packages/claude-sdk-adapter/pnpm-lock.yaml
packages/mcode-harness/package-lock.json
- run: pnpm --dir packages/claude-sdk-adapter fetch
- uses: ./.github/actions/mcode-companion

Expand Down
1 change: 0 additions & 1 deletion .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,6 @@ jobs:
with:
lockfiles: |
packages/claude-sdk-adapter/pnpm-lock.yaml
packages/mcode-harness/package-lock.json
- name: Test and package Harness adapters
run: make check-claude-sdk check-mcode-harness

Expand Down
1 change: 0 additions & 1 deletion .github/workflows/native.yml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ jobs:
node-version: '22.22.0'
lockfiles: |
packages/claude-sdk-adapter/pnpm-lock.yaml
packages/mcode-harness/package-lock.json
- name: Build the native daemon and test bundle boundaries
id: build
run: |
Expand Down
2 changes: 1 addition & 1 deletion apps/daemon/internal/agent/mcode/discovery_workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ func discoverWorkspace(parent context.Context, options agent.DiscoveryOptions, r
fail(err)
return nil
}
c, err := ConfigureLocal(binary, node, os.Getenv("OAC_RUNTIME_MCODE_WORKSPACE_BRIDGE"), options.RuntimeRoot, os.Getenv("OAC_RUNTIME_WORKSPACE"), binding.NetworkPolicy())
c, err := ConfigureLocal(binary, node, os.Getenv("OAC_RUNTIME_MCODE_COMPANION"), os.Getenv("OAC_RUNTIME_WORKSPACE"), binding.NetworkPolicy())
if err == nil {
err = CheckWorkspace(parent, c)
}
Expand Down
2 changes: 1 addition & 1 deletion apps/daemon/internal/agent/mcode/environment_mcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func runtimeMCP(req proto.PromptRequestPayload) ([]map[string]any, error) {
}
var servers []map[string]any
for _, binding := range bindings {
if binding.ServerLabel == "oac_workspace" || binding.ConnectionOrigin != "environment" || binding.AllowedTools != nil || binding.Required {
if binding.ConnectionOrigin != "environment" || binding.AllowedTools != nil || binding.Required {
return nil, fmt.Errorf("mcode: unsupported MCP binding")
}
if binding.Transport == "http" {
Expand Down
18 changes: 8 additions & 10 deletions apps/daemon/internal/agent/mcode/environment_mcp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,15 +50,15 @@ func TestEnvironmentMCPUsesFixedLauncherForNewAndLoadedSessions(t *testing.T) {
Env []map[string]string
} `json:"mcpServers"`
}
if json.Unmarshal(raw, &params) != nil || len(params.MCP) != 2 || params.MCP[0].Name != "oac_workspace" {
t.Fatal("environment MCP displaced workspace tools")
if json.Unmarshal(raw, &params) != nil || len(params.MCP) != 1 {
t.Fatal("native Session did not receive exactly the declared MCP server")
}
cwd, err := os.ReadFile(record + ".cwd")
workspace, pathErr := filepath.EvalSymlinks(req.LocalEnvironment.WorkspaceRoot)
if err != nil || pathErr != nil || string(cwd) != workspace || params.Cwd != req.LocalEnvironment.WorkspaceRoot {
t.Fatalf("native process and ACP Session must use the declared workspace: process=%q ACP=%q", cwd, params.Cwd)
}
server := params.MCP[1]
server := params.MCP[0]
executable, _ := os.Executable()
if server.Name != "proof.server" || server.Command != executable || server.Env == nil || len(server.Env) != 0 ||
!reflect.DeepEqual(server.Args, []string{"runtime-mcp-exec", "/private/runtime/capabilities", "plugins/fixture", "proof.server"}) {
Expand All @@ -72,7 +72,7 @@ func TestEnvironmentMCPUsesFixedLauncherForNewAndLoadedSessions(t *testing.T) {
}

func TestEnvironmentMCPRejectsUnqualifiedAuthorityBeforePreparation(t *testing.T) {
for _, name := range []string{"http-headers", "http-bearer-insecure", "http-bearer-missing", "restricted", "disabled", "duplicate", "reserved"} {
for _, name := range []string{"http-headers", "http-bearer-insecure", "http-bearer-missing", "restricted", "disabled", "duplicate"} {
t.Run(name, func(t *testing.T) {
c, req, _ := workspaceFixture(t)
c.Network, req.LocalEnvironment.NetworkAccess = "enabled", "enabled"
Expand All @@ -95,8 +95,6 @@ func TestEnvironmentMCPRejectsUnqualifiedAuthorityBeforePreparation(t *testing.T
c.Network, req.LocalEnvironment.NetworkAccess = name, name
case "duplicate":
req.LocalEnvironment.MCP = append(req.LocalEnvironment.MCP, environmentMCPFixture())
case "reserved":
req.LocalEnvironment.MCP[0].Server.Name = "oac_workspace"
}
if _, err := prepareWorkspaceOptions(testStateRoot(t), c, req); err == nil || strings.Contains(err.Error(), "confidential-http-token") {
t.Fatal("unqualified declaration accepted or credential exposed")
Expand Down Expand Up @@ -205,10 +203,10 @@ func TestEnvironmentHTTPMCPUsesEphemeralACPConfiguration(t *testing.T) {
Headers []map[string]string
} `json:"mcpServers"`
}
if json.Unmarshal(raw, &params) != nil || len(params.MCP) != 2 {
t.Fatal("HTTP MCP displaced workspace tools")
if json.Unmarshal(raw, &params) != nil || len(params.MCP) != 1 {
t.Fatal("native Session did not receive exactly the declared MCP server")
}
server := params.MCP[1]
server := params.MCP[0]
if server.Name != "remote" || server.Type != "http" || server.URL != item.Server.URL || server.Headers == nil {
t.Fatal("invalid native HTTP projection")
}
Expand All @@ -220,7 +218,7 @@ func TestEnvironmentHTTPMCPUsesEphemeralACPConfiguration(t *testing.T) {
t.Fatal("anonymous MCP inherited credentials")
}
dataDir := resource.(*executor).opts.DataDir
for _, name := range []string{"config.yaml", "mcp.json", "workspace-profile.json"} {
for _, name := range []string{"config.yaml", "mcp.json"} {
body, err := os.ReadFile(filepath.Join(dataDir, name))
if err != nil && !os.IsNotExist(err) {
t.Fatal(err)
Expand Down
15 changes: 11 additions & 4 deletions apps/daemon/internal/agent/mcode/events.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,25 @@ func (s *Session) handle(frame rpcFrame) error {
s.mu.Lock()
s.steeringReady = true
s.mu.Unlock()
var chunk struct {
Type string `json:"type"`
Text string `json:"text"`
}
if kind := event.Update.Kind; (kind == "agent_message_chunk" || kind == "agent_thought_chunk") && json.Unmarshal(event.Update.Content, &chunk) != nil {
return fmt.Errorf("mcode: invalid session update")
}
switch event.Update.Kind {
case "agent_message_chunk":
if event.Update.Content.Type != "text" {
if chunk.Type != "text" {
return fmt.Errorf("mcode: unsupported response content")
}
text := event.Update.Content.Text
text := chunk.Text
s.content.WriteString(text)
s.sequence++
s.emit(proto.TypeDelta, proto.DeltaPayload{Delta: text, Sequence: s.sequence})
case "agent_thought_chunk":
s.sequence++
s.emit(proto.TypeThinking, proto.ThinkingPayload{Text: event.Update.Content.Text, Sequence: s.sequence})
s.emit(proto.TypeThinking, proto.ThinkingPayload{Text: chunk.Text, Sequence: s.sequence})
case "tool_call", "tool_call_update":
return s.emitTool(event.Update.toolUpdate)
}
Expand Down Expand Up @@ -80,7 +87,7 @@ func (s *Session) emitTool(update toolUpdate) error {
return err
}
}
if previous.mcp == nil && workspaceToolObservation(previous, "before") == nil {
if previous.mcp == nil && s.nativeToolObservation(previous, "before") == nil {
if err := s.emitToolStage(update, "before"); err != nil {
return err
}
Expand Down
10 changes: 0 additions & 10 deletions apps/daemon/internal/agent/mcode/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,6 @@ func validateExecutionRequest(req proto.PromptRequestPayload) error {
return nil
}

func configureTextExecution(config map[string]any) {
config["agents"] = map[string]any{"default": map[string]any{
"tools": []string{}, "builtinTools": []string{}, "skills": []string{},
// Native web search calls MiniMax's cloud with a MiniMax account credential that Core does not hold.
"features": map[string]bool{"mavis": false, "delegation": false, "webSearch": false},
}}
config["askUser"] = map[string]bool{"enabled": false}
config["beta"] = map[string]bool{"browserUseTooling": false, "mcodeTools": false, "threadGoal": false}
}

// Harness children use the daemon user's ordinary environment.
func executionEnvironment() []string { return os.Environ() }

Expand Down
4 changes: 2 additions & 2 deletions apps/daemon/internal/agent/mcode/execution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ func TestExecutionOptionsInheritUserEnvironment(t *testing.T) {
r := testRequest(t)
t.Setenv("OAC_TEST_SECRET_CANARY", "secret")
t.Setenv("NODE_OPTIONS", "--import=untrusted")
opts, err := prepareOptions(testStateRoot(t), r)
opts, err := prepareOptions(testStateRoot(t), r, nil)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -50,7 +50,7 @@ func TestExecutionRejectsUnqualifiedAuthority(t *testing.T) {
} {
r := testRequest(t)
change(&r)
if _, err := prepareOptions(testStateRoot(t), r); err == nil {
if _, err := prepareOptions(testStateRoot(t), r, nil); err == nil {
t.Fatal("unsupported execution accepted")
}
}
Expand Down
2 changes: 1 addition & 1 deletion apps/daemon/internal/agent/mcode/executor.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func NewExecutorFactory(runtimeRoot string, config *WorkspaceConfig) agent.Execu
var opts launchOptions
binary := defaultBinary()
if frozen == nil {
opts, err = prepareOptions(runtimeRoot, req)
opts, err = prepareOptions(runtimeRoot, req, nil)
} else {
binary = frozen.Binary
opts, err = prepareWorkspaceOptions(runtimeRoot, *frozen, req)
Expand Down
8 changes: 4 additions & 4 deletions apps/daemon/internal/agent/mcode/executor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func workspaceFixture(t *testing.T) (WorkspaceConfig, proto.PromptRequestPayload
if err := os.WriteFile(binary, []byte(script), 0700); err != nil {
t.Fatal(err)
}
return WorkspaceConfig{Binary: binary, Node: "/usr/bin/node", Bridge: "/opt/bridge.mjs", Directory: r.LocalEnvironment.WorkspaceRoot, Network: "enabled", Scratch: t.TempDir()}, r, record
return WorkspaceConfig{Binary: binary, Node: "/usr/bin/node", Companion: "/opt/mcode-harness", Directory: r.LocalEnvironment.WorkspaceRoot, Network: "enabled"}, r, record
}

func executorFixture(t *testing.T, scenario string, workspace bool) (*executor, string) {
Expand Down Expand Up @@ -143,15 +143,15 @@ func TestExecutorCancellationRetiresOwnerAndLateCancelCannotRetarget(t *testing.
if !disabled {
// A terminal native history record still cannot prove Bash cleanup.
dir := t.TempDir()
node, bridge := filepath.Join(dir, "node"), filepath.Join(dir, "bridge.mjs")
node := filepath.Join(dir, "node")
body := "#!/bin/sh\nprintf '%s\\n' '{\"version\":1,\"complete\":true,\"rootSessionId\":\"native-1\",\"sessions\":[{\"id\":\"native-1\",\"turns\":[{\"id\":\"root-turn\",\"status\":\"aborted\"}]}]}'\n"
for name, data := range map[string]string{node: body, bridge: "", filepath.Join(dir, "subagent-snapshot.mjs"): ""} {
for name, data := range map[string]string{node: body, filepath.Join(dir, "subagent-snapshot.mjs"): ""} {
if err := os.WriteFile(name, []byte(data), 0700); err != nil {
t.Fatal(err)
}
}
t.Setenv("OAC_RUNTIME_MCODE_NODE", node)
t.Setenv("OAC_RUNTIME_MCODE_WORKSPACE_BRIDGE", bridge)
t.Setenv("OAC_RUNTIME_MCODE_COMPANION", dir)
}
out := make(chan proto.Envelope, 32)
second, err := e.StartTurn(t.Context(), "second", proto.TextInput("wait"), out)
Expand Down
4 changes: 2 additions & 2 deletions apps/daemon/internal/agent/mcode/harness_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import (
func TestNativeConfigDoesNotPretendToSupportParameters(t *testing.T) {
req := testRequest(t)
req.AgentOptions["harness_config"] = map[string]any{}
if _, err := prepareOptions(testStateRoot(t), req); err != nil {
if _, err := prepareOptions(testStateRoot(t), req, nil); err != nil {
t.Fatal(err)
}
req.AgentOptions["harness_config"] = map[string]any{"temperature": 0.5}
if _, err := prepareOptions(testStateRoot(t), req); err != harnessconfig.ErrHarnessConfig {
if _, err := prepareOptions(testStateRoot(t), req, nil); err != harnessconfig.ErrHarnessConfig {
t.Fatalf("unsupported parameter accepted: %v", err)
}
}
2 changes: 1 addition & 1 deletion apps/daemon/internal/agent/mcode/installation.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
func Installation() agent.Installation {
return agent.Installation{AgentKind: "mcode", Version: SupportedVersion, Supported: func() bool { return runtime.GOOS == "linux" || runtime.GOOS == "darwin" },
Environment: func(dir, node string) map[string]string {
return map[string]string{"OAC_RUNTIME_MCODE_BIN": filepath.Join(dir, "native", "cli.js"), "OAC_RUNTIME_MCODE_NODE": node, "OAC_RUNTIME_MCODE_WORKSPACE_BRIDGE": filepath.Join(dir, "bridge.mjs")}
return map[string]string{"OAC_RUNTIME_MCODE_BIN": filepath.Join(dir, "native", "cli.js"), "OAC_RUNTIME_MCODE_NODE": node, "OAC_RUNTIME_MCODE_COMPANION": dir}
},
Check: func(ctx context.Context, dir, node string, env []string) error {
got, err := installroot.Probe(ctx, node, []string{filepath.Join(dir, "native", "cli.js"), "--version"}, env, dir)
Expand Down
4 changes: 2 additions & 2 deletions apps/daemon/internal/agent/mcode/mcp_observations.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ type mcpToolIdentity struct{ server, tool string }
// Read its exact mapping instead of reversing lossy native name normalization.
func (s *Session) environmentMCPIdentity(name string) (*mcpToolIdentity, error) {
if s.req.LocalEnvironment == nil ||
!strings.HasPrefix(name, "mcp__") || strings.HasPrefix(name, "mcp__oac_workspace__") {
!strings.HasPrefix(name, "mcp__") {
return nil, nil
}
bindings, err := agent.ResolveMCPBindings(s.req)
Expand Down Expand Up @@ -55,7 +55,7 @@ func (s *Session) environmentMCPIdentity(name string) (*mcpToolIdentity, error)
declared++
}
}
if found != nil || declared != 1 || server.Raw == "oac_workspace" || tool.Raw == "" ||
if found != nil || declared != 1 || tool.Raw == "" ||
json.Unmarshal([]byte(server.Key), &key) != nil || len(key) != 2 || key[0] != "configured" || key[1] != server.Raw {
return nil, fmt.Errorf("mcode: ambiguous or undeclared native MCP identity")
}
Expand Down
12 changes: 0 additions & 12 deletions apps/daemon/internal/agent/mcode/mcp_observations_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,18 +164,6 @@ func TestEnvironmentMCPResultMustMatchStartAndUnsettledCallsCloseOnce(t *testing
}
}

func TestEnvironmentMCPDoesNotPublishInternalWorkspaceUtilities(t *testing.T) {
s, out := mcpObservationSession(t)
for _, name := range []string{"workspace_read", "workspace_write", "workspace_edit", "workspace_glob", "workspace_grep"} {
if err := s.emitTool(toolUpdate{ID: name, Name: "mcp__oac_workspace__" + name, Status: "completed"}); err != nil {
t.Fatal(err)
}
}
if len(out) != 0 {
t.Fatal("internal workspace utility became a public MCP call")
}
}

func TestEnvironmentMCPNativeJSONRetainsIntegerPrecision(t *testing.T) {
s, out := mcpObservationSession(t)
frames := []string{
Expand Down
8 changes: 4 additions & 4 deletions apps/daemon/internal/agent/mcode/model_provider_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ func TestOptionsModelProviderProtocols(t *testing.T) {
req := testRequest(t)
req.AgentOptions["model_provider"].(map[string]any)["protocol"] = tc.protocol
req.AgentOptions["model"] = "chosen-model"
opts, err := prepareOptions(testStateRoot(t), req)
opts, err := prepareOptions(testStateRoot(t), req, nil)
if err != nil {
t.Fatal(err)
}
Expand Down Expand Up @@ -60,7 +60,7 @@ func TestOptionsRejectInvalidProvider(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
req := testRequest(t)
req.AgentOptions["model_provider"].(map[string]any)[tc.field] = tc.value
if _, err := prepareOptions(testStateRoot(t), req); err == nil {
if _, err := prepareOptions(testStateRoot(t), req, nil); err == nil {
t.Fatal("invalid model provider accepted")
}
})
Expand All @@ -69,7 +69,7 @@ func TestOptionsRejectInvalidProvider(t *testing.T) {
req := testRequest(t)
req.AgentOptions["mcode_provider"] = req.AgentOptions["model_provider"]
delete(req.AgentOptions, "model_provider")
if _, err := prepareOptions(testStateRoot(t), req); err == nil {
if _, err := prepareOptions(testStateRoot(t), req, nil); err == nil {
t.Fatal("retired native provider option accepted")
}
})
Expand All @@ -78,7 +78,7 @@ func TestOptionsRejectInvalidProvider(t *testing.T) {
func TestOptionsAllowLoopbackProviderFixture(t *testing.T) {
req := testRequest(t)
req.AgentOptions["model_provider"].(map[string]any)["base_url"] = "http://127.0.0.1:4321/v1"
if _, err := prepareOptions(testStateRoot(t), req); err != nil {
if _, err := prepareOptions(testStateRoot(t), req, nil); err != nil {
t.Fatal(err)
}
}
64 changes: 55 additions & 9 deletions apps/daemon/internal/agent/mcode/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,17 @@ type launchOptions struct {
MCP []map[string]any
}

func prepareOptions(runtimeRoot string, req proto.PromptRequestPayload) (launchOptions, error) {
// workspaceProfile selects the native tools of a Session that has an Environment.
type workspaceProfile struct {
// ToolEnv is the Runtime's frozen tool environment as KEY=value entries.
ToolEnv []string
// WebFetch keeps the native web_fetch tool.
WebFetch bool
}

// prepareOptions writes the native configuration. A nil workspace is the none
// placement: the native process has no builtin file, process or fetch tools.
func prepareOptions(runtimeRoot string, req proto.PromptRequestPayload, workspace *workspaceProfile) (launchOptions, error) {
var result launchOptions
if _, err := harnessconfiguration.Declaration.Configuration.PrepareHarnessConfig(req.AgentOptions); err != nil {
return result, err
Expand Down Expand Up @@ -56,13 +66,14 @@ func prepareOptions(runtimeRoot string, req proto.PromptRequestPayload) (launchO
return result, err
}
config["custom_provider"] = map[string]any{"oac": provider}
configureTextExecution(config)
if !req.DisableSubagents {
config["agents"] = map[string]any{"default": map[string]any{
"tools": []string{"task", "task_append", "task_query", "task_output", "task_stop"},
"builtinTools": []string{"task", "task_append", "task_query", "task_output", "task_stop"}, "skills": []string{},
"features": map[string]bool{"mavis": false, "delegation": true, "webSearch": false},
}}
config["agents"] = map[string]any{"default": agentCapabilities(req, workspace)}
// Unattended: no ask-user. Native mcode-tools needs a MiniMax account sign-in that Core does not hold.
// Thread goals schedule continuation Turns after the Turn ends.
config["askUser"] = map[string]bool{"enabled": false}
config["beta"] = map[string]bool{"mcodeTools": false, "threadGoal": false}
if workspace != nil {
// Unattended: asks are allowed; the few that bypass cannot lift are answered cancelled and fail the tool call.
config["permissionMode"] = "bypassPermissions"
}
data, err := json.Marshal(config)
if err != nil {
Expand All @@ -71,7 +82,12 @@ func prepareOptions(runtimeRoot string, req proto.PromptRequestPayload) (launchO
if err := os.WriteFile(filepath.Join(result.DataDir, "config.yaml"), data, 0o600); err != nil {
return result, err
}
result.Env = append(executionEnvironment(), "OAC_RUNTIME_MCODE_TOOL_POLICY=protected-mcp-v1")
result.Env = executionEnvironment()
if workspace != nil {
result.Env = append(result.Env, workspace.ToolEnv...)
}
// Background bash outlives the Turn and escapes the process group; Subagent task output stays.
result.Env = append(result.Env, "OAC_RUNTIME_MCODE_BACKGROUND_BASH=off")
if err := os.WriteFile(filepath.Join(result.DataDir, "mcp.json"), []byte(`{"mcpServers":{}}`), 0o600); err != nil {
return result, err
}
Expand All @@ -86,6 +102,36 @@ func prepareOptions(runtimeRoot string, req proto.PromptRequestPayload) (launchO
return result, nil
}

// agentCapabilities is the native agents.default ceiling. A native ID list is
// all-or-nothing: one unknown ID drops the whole list and enables every tool.
func agentCapabilities(req proto.PromptRequestPayload, workspace *workspaceProfile) map[string]any {
tools := []string{}
if workspace != nil {
// website_deploy needs a MiniMax account and stays out of the list.
tools = append(tools, "read", "write", "edit", "bash", "grep", "glob", "todowrite")
if workspace.WebFetch {
tools = append(tools, "web_fetch")
}
}
capabilities := map[string]any{
"tools": tools,
// Builtin Matrix MCP tools call MiniMax's cloud with an account credential that Core does not hold.
"builtinTools": []string{},
"features": map[string]bool{
// Mavis adds cron scheduling and memory that run beyond a Turn, and needs a MiniMax account.
"mavis": false,
"delegation": !req.DisableSubagents,
// Native web search calls MiniMax's cloud with a MiniMax account credential that Core does not hold.
"webSearch": false,
},
}
if workspace == nil {
// The none placement reads no Skills; a workspace keeps the native selection with the linked Skills.
capabilities["skills"] = []string{}
}
return capabilities
}

func optionString(options map[string]any, key string) string {
value, _ := options[key].(string)
return value
Expand Down
Loading
Loading