refactor(python): launch the minimal example through sdk-minimal

Make minimal.py select the shipped sdk-minimal profile directly and pass its selected model into the profile-owned adapter catalog. The Python SDK still starts only the bundled dsh CLI with an explicit Harness home; it no longer supplies an invocation overlay for this mode.

Drive both the source keyless process test and installed-wheel smoke through the same named profile. The keyless test pins the generated profile manifest and exact two-tool model request, while the packaged smoke keeps the persistent-shell, editor, session-log, and model-visible snapshot evidence.

Delete minimal.patch.yml and the unused complete-config/replay fixtures. Their composition now has one owner in @deepseek-ai/dsh-sdk-minimal, so the example and tests cannot drift into separate launch trees.
This commit is contained in:
Tianyi Cui
2026-08-24 17:28:28 +08:00
parent 8dc3b0380e
commit 79a8f667f7
6 changed files with 18 additions and 241 deletions
@@ -1,90 +0,0 @@
# Complete minimal-agent composition fixture for lower-level snapshot tests.
# Python users apply `minimal.patch.yml` to `dsh --profile sdk`. This fixture
# retains the same two-tool behavior without defining a supported launch path.
- id: sdk-jsonrpc-server
name: '@deepseek-ai/dsh-sdk-jsonrpc-server'
config:
maxTokensAsSuccess: false
- id: deepseek-llm-api-extensions
name: '@deepseek-ai/dsh-deepseek-llm-api-extensions'
- id: session-log-deepseek
name: '@deepseek-ai/dsh-session-log-deepseek'
- id: plugin-package-inventory-deepseek
name: '@deepseek-ai/dsh-plugin-package-inventory-deepseek'
- id: llm-deepseek
name: '@deepseek-ai/dsh-llm-deepseek'
config:
apiKeyEnv: DEEPSEEK_API_KEY
streamIdleTimeoutMs: 172800000
models:
- id: !!js process.env.DSH_MODEL ?? 'deepseek-v4-flash'
contextWindow: !!js Number(process.env.DSH_CONTEXT_WINDOW ?? 1000000)
- id: sandbox
name: '@deepseek-ai/dsh-sandbox-local'
- id: sandbox-policy
name: '@deepseek-ai/dsh-sandbox-policy'
config:
mode: danger-full-access
workspaceRoot: !!js process.env.DSH_CWD ?? process.cwd()
- id: subprocess
name: '@deepseek-ai/dsh-subprocess-local'
- id: pty
name: '@deepseek-ai/dsh-terminal'
- id: terminal-bash
name: '@deepseek-ai/dsh-terminal-bash'
config:
timeoutMs: 300000
# The editor uses the bare local filesystem; persistent Bash still consumes the
# shared danger-full-access sandbox policy above.
- id: fs-local
name: '@deepseek-ai/dsh-fs-local'
config:
cwd: !!js process.env.DSH_CWD ?? process.cwd()
- id: agent-spine
name: '@deepseek-ai/dsh-agent-spine-demo'
config:
includeHarnessIdentity: false
includeRuntimeContext: false
persona: !!js process.env.DSH_SYSTEM_PROMPT ?? 'You are a helpful software engineer assistant.'
workspaceContext: false
skills:
enabled: false
toolBash: false
toolJobs: false
- id: persistent-bash
name: '@deepseek-ai/dsh-tool-bash-persistent'
config:
timeoutMs: 300000
description: |-
Run commands in a bash shell
* When invoking this tool, the contents of the "command" parameter does NOT need to be XML-escaped.
* You don't have access to the internet via this tool.
* You do have access to a mirror of common linux and python packages via apt and pip.
* State is persistent across command calls and discussions with the user.
* To inspect a particular line range of a file, e.g. lines 10-25, try 'sed -n 10,25p /path/to/the/file'.
* Please avoid commands that may produce a very large amount of output.
* Please run long lived commands in the background, e.g. 'sleep 10 &' or start a server in the background.
- id: str-replace-editor
name: '@deepseek-ai/dsh-tool-str-replace-editor'
config:
maxOutputChars: 16000
- id: sessions
name: '@deepseek-ai/dsh-session-persistence-jsonl'
config:
root: !!js process.env.DSH_SESSION_ROOT ?? './.sessions'
compression: none
@@ -1,47 +0,0 @@
# Minimal Python SDK overlay for `dsh --profile sdk`. The SDK server applies
# the model-facing allowlist to every root session, so later base-bundle tools
# cannot appear implicitly. The profile still owns JSON-RPC and persistence.
- id: system-prompt
config:
includeHarnessIdentity: false
includeRuntimeContext: false
persona: !!js process.env.DSH_SYSTEM_PROMPT ?? 'You are a helpful software engineer assistant.'
personaComplete: true
- id: sdk-jsonrpc-server
config:
maxTokensAsSuccess: !!js "process.env.DSH_MAX_TOKENS_AS_SUCCESS === undefined ? true : JSON.parse(process.env.DSH_MAX_TOKENS_AS_SUCCESS)"
toolFilter:
allow:
- bash
- str_replace_editor
# Remove non-tool model inputs and turn rewriting, plus the one-shot Bash row
# that would conflict with the persistent Bash tool inserted below.
- id: agent-instructions
disabled: true
- id: tool-bash
disabled: true
- id: compaction-basic
disabled: true
- id: command-compact
disabled: true
- id: tool-result-pruner
disabled: true
- id: tool-str-replace-editor
config:
maxOutputChars: 16000
- insert:
- id: pty
name: '@deepseek-ai/dsh-terminal'
- id: terminal-bash
name: '@deepseek-ai/dsh-terminal-bash'
config:
timeoutMs: 300000
- id: persistent-bash
name: '@deepseek-ai/dsh-tool-bash-persistent'
config:
timeoutMs: 300000
+2 -5
View File
@@ -10,9 +10,6 @@ from pathlib import Path
from deepseek_harness import DeepSeekHarness
PATCH = Path(__file__).with_name("minimal.patch.yml")
def main() -> None:
"""Parse one task and print the agent's final response."""
parser = argparse.ArgumentParser()
@@ -24,7 +21,7 @@ def main() -> None:
type=Path,
default=Path(configured_home) if configured_home.strip() else None,
)
parser.add_argument("--profile", default="sdk")
parser.add_argument("--profile", default="sdk-minimal")
parser.add_argument("--session-id")
parser.add_argument("--provider", default="deepseek-official")
parser.add_argument("--model", default=os.environ.get("DSH_MODEL", "deepseek-v4-flash"))
@@ -42,7 +39,7 @@ def main() -> None:
cwd=str(workspace),
dsh_home=str(dsh_home),
profile=args.profile,
patches=(str(PATCH.resolve()),),
env={"DSH_MODEL": args.model},
) as harness:
result = harness.run(args.prompt, session_id=args.session_id)
print(result.final_response)
@@ -1,20 +0,0 @@
# Keyless replay keeps the complete minimal composition intact and replaces
# only its live DeepSeek adapter with the fixture-backed provider. The replay
# catalog claims the same route initialized by the SDK.
- id: base
name: '@deepseek-ai/cordis-plugin-include'
config:
path: ./minimal.cordis.yml
patches:
- id: llm-deepseek
name: '@deepseek-ai/dsh-llm-deepseek'
disabled: true
- insert:
- id: llm-replay
name: '@deepseek-ai/dsh-llm-replay'
config:
providers:
- id: deepseek-official
name: DeepSeek
models:
- id: deepseek-v4-flash
@@ -10,7 +10,6 @@ import { describe, expect, it } from 'vitest'
const binScript = fileURLToPath(new URL('../../../apps/cli/src/bin.ts', import.meta.url))
const patchPath = fileURLToPath(new URL('./keyless.patch.yml', import.meta.url))
const minimalPatchPath = fileURLToPath(new URL('../minimal.patch.yml', import.meta.url))
const repoRoot = fileURLToPath(new URL('../../..', import.meta.url))
const decompress = promisify(zstdDecompress)
@@ -181,7 +180,7 @@ describe('Python SDK dsh profile keyless smoke', () => {
}
}, 40_000)
it('keeps the minimal overlay on an explicit model-facing allowlist', async () => {
it('boots the standalone minimal profile with its exact model-facing roster', async () => {
const root = await mkdtemp(join(tmpdir(), 'dsh-python-sdk-minimal-'))
const modelRequests: Record<string, unknown>[] = []
const modelServer = createServer((request, response) => {
@@ -205,16 +204,13 @@ describe('Python SDK dsh profile keyless smoke', () => {
'tsx/esm',
binScript,
'--profile',
'sdk',
'--patch',
minimalPatchPath,
'sdk-minimal',
], {
cwd: repoRoot,
env: {
DSH_HOME: join(root, '.dsh'),
DSH_PERMISSION_MODE: 'danger-full-access',
DSH_MODEL: 'deepseek-v4-pro',
DSH_SYSTEM_PROMPT: 'Minimal allowlist prompt.',
DSH_TELEMETRY_DISABLED: '1',
DEEPSEEK_API_KEY: 'keyless-smoke-no-call',
DEEPSEEK_BASE_URL: `http://127.0.0.1:${address.port}`,
},
@@ -259,6 +255,13 @@ describe('Python SDK dsh profile keyless smoke', () => {
}
expect(request.messages?.[0]).toMatchObject({ role: 'system', content: 'Minimal allowlist prompt.' })
expect(request.tools?.map(tool => tool.function?.name).sort()).toEqual(['bash', 'str_replace_editor'])
const profile = JSON.parse(
await readFile(join(root, '.dsh', 'profiles', 'sdk-minimal', 'package.json'), 'utf8'),
) as { dsh?: { profile?: { bundles?: string[]; patchReload?: string } } }
expect(profile.dsh?.profile).toEqual({
bundles: ['@deepseek-ai/dsh-sdk-minimal'],
patchReload: 'startup',
})
child.stdin.write(`${JSON.stringify({ jsonrpc: '2.0', id: 3, method: 'shutdown' })}\n`)
await waitForLine(lines, value => value.id === 3, () => stderr)