mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-08-29 04:26:38 +00:00
test(python): prove installed dsh profile customization
Migrate the packaged-runtime smoke inventory from complete Cordis trees to the sdk profile plus ordered patches. Preserve the focused minimal and advanced behaviors, update the generated durable snapshots for explicit permission events and the smaller RunResult, and keep worker, MCP, ripgrep, PTY/editor, direct JSON-RPC, and real-provider coverage. Add an installed-only external bundle scenario that invokes the wheel's dsh plugin command with a local file package, verifies profile manifest reconciliation, imports @deepseek-ai/cordis as a peer, asserts the packaged proxy returns the exact host Context instance, and proves its system-prompt contribution reaches the model. Migrate the repository source e2e and runnable minimal example to the same profile grammar.
This commit is contained in:
@@ -0,0 +1,68 @@
|
||||
# Minimal Python SDK overlay for `dsh --profile sdk`: keep only persistent
|
||||
# Bash and the string-replacement editor, with no runtime-context prompt or
|
||||
# compaction. The profile still owns JSON-RPC serving and persistence.
|
||||
|
||||
- id: system-prompt
|
||||
config:
|
||||
includeHarnessIdentity: false
|
||||
includeRuntimeContext: false
|
||||
persona: !!js process.env.DSH_SYSTEM_PROMPT ?? 'You are a helpful software engineer assistant.'
|
||||
|
||||
- id: agent-instructions
|
||||
disabled: true
|
||||
- id: skill-filesystem
|
||||
disabled: true
|
||||
- id: tool-skill
|
||||
disabled: true
|
||||
- id: tool-bash
|
||||
disabled: true
|
||||
- id: tool-jobs
|
||||
disabled: true
|
||||
- id: tool-fs
|
||||
disabled: true
|
||||
- id: tool-fs-search
|
||||
disabled: true
|
||||
- id: tool-subagent-control
|
||||
disabled: true
|
||||
- id: tool-subagent-list-agents
|
||||
disabled: true
|
||||
- id: tool-subagent
|
||||
disabled: true
|
||||
- id: tool-subagent-fork
|
||||
disabled: true
|
||||
- id: tool-subagent-report
|
||||
disabled: true
|
||||
- id: tool-workflow
|
||||
disabled: true
|
||||
- id: tool-todo
|
||||
disabled: true
|
||||
- id: tool-goal
|
||||
disabled: true
|
||||
- id: tool-ralph
|
||||
disabled: true
|
||||
- id: tool-web
|
||||
disabled: true
|
||||
- id: plan-mode
|
||||
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
|
||||
@@ -10,30 +10,39 @@ from pathlib import Path
|
||||
from deepseek_harness import DeepSeekHarness
|
||||
|
||||
|
||||
CONFIG = Path(__file__).with_name("minimal.cordis.yml")
|
||||
PATCH = Path(__file__).with_name("minimal.patch.yml")
|
||||
|
||||
|
||||
def main() -> None:
|
||||
"""Parse one task and print the agent's final response."""
|
||||
parser = argparse.ArgumentParser()
|
||||
configured_home = os.environ.get("DSH_HOME", "")
|
||||
parser.add_argument("prompt", help="Task for the minimal agent")
|
||||
parser.add_argument("--workspace", type=Path, default=Path.cwd())
|
||||
parser.add_argument("--session-root", type=Path, default=Path(".dsh-sessions"))
|
||||
parser.add_argument(
|
||||
"--dsh-home",
|
||||
type=Path,
|
||||
default=Path(configured_home) if configured_home.strip() else None,
|
||||
)
|
||||
parser.add_argument("--profile", default="sdk")
|
||||
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"))
|
||||
parser.add_argument("--max-tokens", type=int)
|
||||
args = parser.parse_args()
|
||||
if args.dsh_home is None:
|
||||
parser.error("--dsh-home or a non-empty DSH_HOME is required")
|
||||
|
||||
workspace = args.workspace.resolve()
|
||||
session_root = args.session_root.resolve()
|
||||
dsh_home = args.dsh_home.resolve()
|
||||
with DeepSeekHarness(
|
||||
provider=args.provider,
|
||||
model=args.model,
|
||||
max_tokens=args.max_tokens,
|
||||
cwd=str(workspace),
|
||||
session_root=str(session_root),
|
||||
cordis=str(CONFIG.resolve()),
|
||||
dsh_home=str(dsh_home),
|
||||
profile=args.profile,
|
||||
patches=(str(PATCH.resolve()),),
|
||||
) as harness:
|
||||
result = harness.run(args.prompt, session_id=args.session_id)
|
||||
print(result.final_response)
|
||||
|
||||
@@ -8,8 +8,8 @@ import { zstdDecompress } from 'node:zlib'
|
||||
import { execa } from 'execa'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
|
||||
const binScript = fileURLToPath(new URL('../../../packages/sdk/python-runtime/src/packaged-bin.ts', import.meta.url))
|
||||
const configPath = fileURLToPath(new URL('../cordis.yml', import.meta.url))
|
||||
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 repoRoot = fileURLToPath(new URL('../../..', import.meta.url))
|
||||
const decompress = promisify(zstdDecompress)
|
||||
|
||||
@@ -45,7 +45,7 @@ function waitForLine(
|
||||
})
|
||||
}
|
||||
|
||||
describe('Python SDK runtime carrier keyless smoke', () => {
|
||||
describe('Python SDK dsh profile keyless smoke', () => {
|
||||
it.each([
|
||||
{ label: 'reports max-token turns with the default mapping config', envValue: undefined },
|
||||
{ label: 'reports max-token turns with mapping enabled through env', envValue: 'true' },
|
||||
@@ -73,16 +73,20 @@ describe('Python SDK runtime carrier keyless smoke', () => {
|
||||
// execa owns spawn, the deadline, and exit settlement around it.
|
||||
const child = execa(process.execPath, [
|
||||
'--import',
|
||||
'tsx',
|
||||
'tsx/esm',
|
||||
binScript,
|
||||
configPath,
|
||||
'--profile',
|
||||
'sdk',
|
||||
'--patch',
|
||||
patchPath,
|
||||
], {
|
||||
cwd: repoRoot,
|
||||
env: {
|
||||
DSH_HOME: join(root, '.dsh'),
|
||||
DSH_PERMISSION_MODE: 'danger-full-access',
|
||||
DSH_TELEMETRY_DISABLED: '1',
|
||||
DEEPSEEK_API_KEY: 'keyless-smoke-no-call',
|
||||
DEEPSEEK_BASE_URL: `http://127.0.0.1:${address.port}`,
|
||||
DSH_CWD: root,
|
||||
DSH_SESSION_ROOT: join(root, '.sessions'),
|
||||
...(envValue === undefined ? {} : { DSH_MAX_TOKENS_AS_SUCCESS: envValue }),
|
||||
},
|
||||
timeout: 35_000,
|
||||
@@ -149,6 +153,7 @@ describe('Python SDK runtime carrier keyless smoke', () => {
|
||||
'bash',
|
||||
'edit',
|
||||
'read',
|
||||
'read_image',
|
||||
'subagent',
|
||||
'todo_write',
|
||||
'write',
|
||||
@@ -159,7 +164,7 @@ describe('Python SDK runtime carrier keyless smoke', () => {
|
||||
expect(shutdown).toMatchObject({ jsonrpc: '2.0', id: 3, result: {} })
|
||||
const exit = await child
|
||||
expect(exit.exitCode, `signal=${String(exit.signal)}; stderr=${stderr}`).toBe(0)
|
||||
const sessionsRoot = join(root, '.sessions')
|
||||
const sessionsRoot = join(root, '.dsh', 'sessions')
|
||||
const files = await readdir(sessionsRoot, { recursive: true })
|
||||
const log = files.find(file => file.endsWith('.jsonl.zstd'))
|
||||
expect(log).toBeDefined()
|
||||
@@ -176,27 +181,36 @@ describe('Python SDK runtime carrier keyless smoke', () => {
|
||||
}, 40_000)
|
||||
|
||||
it('rejects an invalid max-token success env value', async () => {
|
||||
const { exitCode, stdout, stderr } = await execa(process.execPath, [
|
||||
'--import',
|
||||
'tsx',
|
||||
binScript,
|
||||
configPath,
|
||||
], {
|
||||
cwd: repoRoot,
|
||||
env: {
|
||||
DEEPSEEK_API_KEY: 'keyless-smoke-no-call',
|
||||
DSH_MAX_TOKENS_AS_SUCCESS: 'sometimes',
|
||||
},
|
||||
stdin: 'ignore',
|
||||
timeout: 25_000,
|
||||
killSignal: 'SIGKILL',
|
||||
reject: false,
|
||||
})
|
||||
const root = await mkdtemp(join(tmpdir(), 'dsh-python-sdk-runtime-invalid-'))
|
||||
try {
|
||||
const { exitCode, stdout, stderr } = await execa(process.execPath, [
|
||||
'--import',
|
||||
'tsx/esm',
|
||||
binScript,
|
||||
'--profile',
|
||||
'sdk',
|
||||
'--patch',
|
||||
patchPath,
|
||||
], {
|
||||
cwd: repoRoot,
|
||||
env: {
|
||||
DSH_HOME: join(root, '.dsh'),
|
||||
DEEPSEEK_API_KEY: 'keyless-smoke-no-call',
|
||||
DSH_MAX_TOKENS_AS_SUCCESS: 'sometimes',
|
||||
},
|
||||
stdin: 'ignore',
|
||||
timeout: 25_000,
|
||||
killSignal: 'SIGKILL',
|
||||
reject: false,
|
||||
})
|
||||
|
||||
expect(exitCode, stderr).toBe(1)
|
||||
expect(stdout).toBe('')
|
||||
expect(stderr).toContain('plugin tree failed to load')
|
||||
expect(stderr).toContain('failed to apply loader entry sdk-jsonrpc-server (@deepseek-ai/dsh-sdk-jsonrpc-server)')
|
||||
expect(stderr).toContain('sometimes')
|
||||
expect(exitCode, stderr).toBe(1)
|
||||
expect(stdout).toBe('')
|
||||
expect(stderr).toContain('plugin tree failed to load')
|
||||
expect(stderr).toContain('failed to apply loader entry sdk-jsonrpc-server (@deepseek-ai/dsh-sdk-jsonrpc-server)')
|
||||
expect(stderr).toContain('sometimes')
|
||||
} finally {
|
||||
await rm(root, { recursive: true, force: true })
|
||||
}
|
||||
}, 30_000)
|
||||
})
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Preserve the focused SDK test roster over the shipped sdk profile.
|
||||
|
||||
- id: agent-instructions
|
||||
disabled: true
|
||||
- id: tool-jobs
|
||||
disabled: true
|
||||
- id: tool-fs-search
|
||||
disabled: true
|
||||
- id: skill-filesystem
|
||||
disabled: true
|
||||
- id: tool-skill
|
||||
disabled: true
|
||||
- id: tool-str-replace-editor
|
||||
disabled: true
|
||||
- id: tool-subagent-control
|
||||
disabled: true
|
||||
- id: tool-subagent-list-agents
|
||||
disabled: true
|
||||
- id: tool-subagent-fork
|
||||
disabled: true
|
||||
- id: tool-subagent-report
|
||||
disabled: true
|
||||
- id: tool-workflow
|
||||
disabled: true
|
||||
- id: tool-goal
|
||||
disabled: true
|
||||
- id: plan-mode
|
||||
disabled: true
|
||||
- id: tool-ralph
|
||||
disabled: true
|
||||
- id: tool-web
|
||||
disabled: true
|
||||
|
||||
- id: tool-subagent
|
||||
config:
|
||||
provider: spawn
|
||||
toolName: subagent
|
||||
backgroundMode: one-shot
|
||||
Reference in New Issue
Block a user