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: 1 addition & 1 deletion apps/docs/content/docs/sessions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -522,7 +522,7 @@ template = client.beta.agents.environments.templates.create(
name="python-data",
network={"access": "restricted", "allowed_domains": ["pypi.org", "files.pythonhosted.org"]},
packages={"python": ["pandas"]},
setup_commands=["mkdir -p /workspace/outputs"],
setup_commands=[{"command": "mkdir -p /workspace/outputs"}],
)
```

Expand Down
4 changes: 2 additions & 2 deletions apps/docs/content/guide-sources.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"docs/getting-started/quickstart.md": "b989682ac2e58d59a794118fd371b37d1ea64c957d3512ff53739458a95d0f9a",
"docs/api/README.md": "ef2138c892b4de676e7b2b5622b46421204679e656dff7dcc181d261ef22009b",
"contracts/agents-api/execution-tools.md": "e0b61f6c0c236c362186c5f6d0ad69a16dd8a8d9afabe1329a1fe22e5f4a71e9",
"docs/api/public-agent-api.md": "5531748f97a84a5e183838cf6fd6ac9bc0c7ae169fb4c6da73a420dbcc77e255",
"docs/api/public-agent-api.md": "1c789993f75bb380f84f7f82fa366a95625fcdbe830c33e8fde3e2c16b4248fc",
"docs/examples.md": "0e1bdaeff51c9c36779f817be31ea9816b7d8cb2290cf8350d3c4801f436f4f9",
"contracts/agents-api/environments.md": "9c0e794738c017e9dde57a659dc184d347e33730103583534c43e86d5d4183fd",
"docs/getting-started/nodes.md": "13e1f1e867d3e361ff860960ceacc2dd5806e64f4176cd33f5e49f9a9f4d57e4",
Expand Down Expand Up @@ -41,7 +41,7 @@
"content/docs/quickstart.mdx": "d0ab9537ab68f6dd3109353e937a29c5d58ec3894b56a52873c9a1d79dfa60a6",
"content/docs/public-api.mdx": "07a8bd7309f1f5ffa2eaa7edb5823ff9dedb3d2ad728a02112febf1c92526b27",
"content/docs/agents-and-tools.mdx": "b8a85fe92e19a71b7ad7c9357ce7ad0595d50c9190edb748ca834df615b056cb",
"content/docs/sessions.mdx": "c5702840e8395545552da35162724019bb0e4ae2d131a57bd71c615a75e4fe00",
"content/docs/sessions.mdx": "33f5700b05c6ffd4ab3a21c5804055893341b7cce8e90bb190bf36d193a887de",
"content/docs/examples.mdx": "587061e65ab2e841d14980539ba94e2216d4e8135c948a852b9a8bb0359c85d7",
"content/docs/environments-and-files.mdx": "8da8ba45d3c76cc016b1f640d0f3af6e6e8922e4ae0f42ba789443fe59177b9c",
"content/docs/hosted-providers.mdx": "06f0b13b053965bbdd1bfb0a7e85d19b50987841e0512fa8331fc9a67ff71fe0",
Expand Down
11 changes: 11 additions & 0 deletions apps/parsar-daemon/internal/agent/mcode/workspace.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,17 @@ func prepareWorkspaceOptions(ctx context.Context, c WorkspaceConfig, req proto.P
}
config["permissionMode"] = "bypassPermissions"
config["sandbox"] = map[string]bool{"enabled": false}
if len(req.LocalEnvironment.Skills) > 0 {
selected := config["agents"].(map[string]any)["default"].(map[string]any)
names := make([]string, 0, len(req.LocalEnvironment.Skills))
for _, skill := range req.LocalEnvironment.Skills {
names = append(names, skill.Metadata.Name)
}
selected["skills"] = names
for _, key := range []string{"tools", "builtinTools"} {
selected[key] = append(selected[key].([]any), "skill")
}
}
raw, err = json.Marshal(config)
if err != nil {
return opts, err
Expand Down
58 changes: 58 additions & 0 deletions apps/parsar-daemon/internal/agent/mcode/workspace_skills_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package mcode

import (
"encoding/json"
"os"
"path/filepath"
"reflect"
"testing"

"github.com/MiniMax-AI-Dev/parsar/internal/agentcapabilities"
"github.com/MiniMax-AI-Dev/parsar/internal/agentskill"
)

func TestWorkspaceSkillsUseSelectedSnapshotAndNativeLoader(t *testing.T) {
c, req, _ := workspaceFixture(t)
root := t.TempDir()
path := filepath.Join(root, "plugin", "skills", "proof")
if err := os.MkdirAll(path, 0700); err != nil {
t.Fatal(err)
}
const body = "---\nname: proof\ndescription: Read a marker\n---\nSKILL_ONLY_729\n"
if err := os.WriteFile(filepath.Join(path, "SKILL.md"), []byte(body), 0600); err != nil {
t.Fatal(err)
}
req.LocalEnvironment.CapabilityRoot = root
req.LocalEnvironment.Skills = []agentcapabilities.InstalledSkill{{
InstallationRoot: root, RelativeRoot: "plugin/skills/proof", PackageRoot: "plugin",
Metadata: agentskill.Metadata{Name: "proof", Description: "Read a marker"},
}}
for range 2 {
opts, err := prepareWorkspaceOptions(t.Context(), c, req)
if err != nil {
t.Fatal(err)
}
loaded, err := os.ReadFile(filepath.Join(opts.DataDir, "skills", "proof", "SKILL.md"))
if err != nil || string(loaded) != body {
t.Fatal("native Skill path does not resolve to installed content", err)
}
raw, err := os.ReadFile(filepath.Join(opts.DataDir, "config.yaml"))
if err != nil {
t.Fatal(err)
}
var config struct {
Agents map[string]struct {
Skills, Tools, BuiltinTools []string
}
}
if err := json.Unmarshal(raw, &config); err != nil {
t.Fatal(err)
}
selected := config.Agents["default"]
if !reflect.DeepEqual(selected.Skills, []string{"proof"}) ||
!reflect.DeepEqual(selected.Tools, []string{"skill"}) ||
!reflect.DeepEqual(selected.BuiltinTools, []string{"skill"}) {
t.Fatalf("native selection lost the installed Skill: %+v", selected)
}
}
}
2 changes: 1 addition & 1 deletion docs/api/public-agent-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -519,7 +519,7 @@ template = client.beta.agents.environments.templates.create(
name="python-data",
network={"access": "restricted", "allowed_domains": ["pypi.org", "files.pythonhosted.org"]},
packages={"python": ["pandas"]},
setup_commands=["mkdir -p /workspace/outputs"],
setup_commands=[{"command": "mkdir -p /workspace/outputs"}],
)
```

Expand Down
4 changes: 3 additions & 1 deletion packages/claude-sdk-adapter/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ platforms; there is no inner sandbox, protected-root deny policy or managed shel
wrapper. Managed isolation belongs to the outer Environment, which must exclude
other tenants' and broader application credentials. An ordinary native install
provides no such boundary. Directory selection is not tenant authorization.
The adapter's existing tool callback authorizes unattended execution in native
`default` permission mode. It does not use the CLI permission-bypass flag, which
Claude rejects for root accounts.

`Config.Env` selects readiness and native process variables. Explicit tool env is
applied to tool execution, but this is not a guarantee that same-user tools cannot
Expand Down Expand Up @@ -439,4 +442,3 @@ or treat local readiness as provider authentication, public capability acceptanc
or filesystem isolation. The native installer reuses this readiness check after
copying its release components.


5 changes: 3 additions & 2 deletions packages/claude-sdk-adapter/src/workspace.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,10 +96,11 @@ export class WorkspaceProfile {
this.options = {
env, tools: [...nativeTools, ...skillTools, ...(subagents ? ["Agent", "SendMessage"] : [])],
...(skills ? { plugins: skills.paths.map(path => ({ type: "local" as const, path, skipMcpDiscovery: true })) } : {}), allowedTools: mcp?.allowed ?? [...functions], mcpServers: {}, strictMcpConfig: true,
settingSources: [], permissionMode: "bypassPermissions", persistSession: true,
// The existing callback authorizes tools without CLI permission bypass,
// which the native CLI refuses for root accounts.
settingSources: [], permissionMode: "default", persistSession: true,
settings: {},
sandbox: { enabled: false },
allowDangerouslySkipPermissions: true,
canUseTool: this.canUseTool,
hooks: { PreToolUse: [{ hooks: [this.beforeTool] }] },
};
Expand Down
4 changes: 2 additions & 2 deletions packages/claude-sdk-adapter/tests/workspace.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,11 @@ test("workspace native options bypass isolation and preserve selected tool inven
assert.deepEqual(options.settingSources, []);
assert.deepEqual(options.mcpServers, {});
assert.equal(options.strictMcpConfig, true);
assert.equal(options.permissionMode, "bypassPermissions");
assert.equal(options.permissionMode, "default");
assert.equal(options.persistSession, true);
assert.equal(options.sandbox.enabled, false);
assert.deepEqual(options.sandbox, { enabled: false });
assert.equal(options.allowDangerouslySkipPermissions, true);
assert.equal(options.allowDangerouslySkipPermissions, undefined);
assert.deepEqual(options.settings, {});
profile.verify(["Read", "Edit", "Bash"], []);
for (const tools of [[], ["Bash", "Read", "Read"], ["Bash", "Read", "Write"], ["Bash", "Read", "Edit", "Agent"]]) {
Expand Down
2 changes: 1 addition & 1 deletion packages/mcode-harness/patch-native.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ const withWorkspace = catalog.replace(selectorGate, ` const protectedWorkspace
if (!protectedWorkspace && !input.selector.allowsTool(input.tool.def.name, input.options.selectorAlias)) return false;
if (!protectedWorkspace && !isMcpServerAllowed(input.selector, input.options)) return false;`);
writeFileSync(catalogPath, withWorkspace.replace(gate, ` if (process.env.OAC_RUNTIME_MCODE_TOOL_POLICY === 'protected-mcp-v1') {
if (source === 'builtin' && !DELEGATION_TOOL_NAMES.has(toolName) && !TASK_CONTROL_TOOL_NAMES.has(toolName)) return false;
if (source === 'builtin' && toolName !== 'skill' && !DELEGATION_TOOL_NAMES.has(toolName) && !TASK_CONTROL_TOOL_NAMES.has(toolName)) return false;
if (source === 'builtin-matrix') return false;
}
${gate}`));
Expand Down
13 changes: 10 additions & 3 deletions services/agents-api/deploy/mcode/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ Use the real provider endpoint for the selected credential. Test proxies may
forward requests unchanged and capture tool names/status, but must not synthesize
model responses or log keys.

MiniMax M2 Chat Completions may return inline `<think>` content. The pinned native
Harness does not expose the provider's `reasoning_split` option; the adapter does
not guess which response text to remove. Anthropic Messages supplies distinct
thinking blocks. File read/write utilities also have no qualified public Item
mapping; only actual Bash calls become `command_execution`.

## Execution boundaries

Each API Session uses a separate native state directory and cwd. The execution
Expand All @@ -96,9 +102,10 @@ permissions. `system_packages` is unsupported; missing dependencies fail the
operation requiring them. npm/Python packages and setup retain direct execution
with the user's existing permissions.

The native model may still see `skill`, `task_query`, `task_output` and `task_stop`.
The first loads an exact registered skill name and cannot execute a script; the
configured builtin/external skill catalog is empty. Task utilities cannot create
Workspace Skills use the frozen installation's exact names and native `skill`
loader. Session-local links resolve to the installed package directories;
external discovery stays disabled. The text-only profile has no selected Skills.
Task utilities such as `task_query`, `task_output` and `task_stop` cannot create
work and enforce native Session ownership. Auxiliary native title requests are
internal bookkeeping. Do not equate these with public function or workspace tools.

Expand Down