mirror of
https://github.com/deepseek-ai/deepseek-harness.git
synced 2026-09-11 04:00:38 +00:00
refactor(sdk): relocate JSON-RPC example and runtime without edits
Move examples/jsonrpc-agent to examples/python-sdk-agent and packages/examples/jsonrpc-demo to packages/sdk/python-runtime while preserving every file byte-for-byte. The directory placement now reflects the example's Python-distribution role and the private runtime carrier's SDK ownership. This commit deliberately keeps the old package names, commands, configuration, and snapshots inside their new directories. All 42 files are 100% renames; API/profile migration and naming changes follow separately so reviewers do not have to disentangle behavior from filesystem movement.
This commit is contained in:
@@ -0,0 +1,6 @@
|
||||
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
|
||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||
# after editing either side, bring the other along and re-record with:
|
||||
# pnpm run verify-translation-pairing --write packages/examples/jsonrpc-demo/README.md
|
||||
README.md: 28060bd5a90445529a31d4b2bc34033c88fa452c
|
||||
README.zh.md: 544486389357dbd7f1be2ba347fb81adb06527d8
|
||||
@@ -0,0 +1,33 @@
|
||||
# @deepseek-ai/dsh-sdk-jsonrpc-demo
|
||||
|
||||
English | [中文](README.zh.md)
|
||||
|
||||
Bin-only app that boots an external `cordis.yml`; its [`jsonrpc`](../../sdk/server/README.md) entry serves SDK clients over newline-delimited stdio. The config composes the spine, backends, and serving plugin. The published `dsh-jsonrpc-agent` bin resolves bare plugins from the configuration project. The Python SDK's `dsh-jsonrpc-agent-pkg` [single-executable runtime](../../../.agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md) uses `lib/packaged-bin.js` instead: packaged bare plugins resolve from its closed runtime tree, while relative plugins remain configuration-relative.
|
||||
|
||||
## Config discovery
|
||||
|
||||
The first non-empty channel wins: `$DSH_CORDIS_CONFIG`, then positional `argv[2]`. If neither names an existing file, the bin prints one-line usage to stderr and exits 1; there is no working-directory or built-in fallback. [`dsh-app-boot`](../../boot/app-boot/README.md) makes plugin load failures fatal. This protocol does not use `DSH_SNAPSHOT`.
|
||||
|
||||
A config without `dsh-sdk-jsonrpc-server` is valid and serves nothing; the bin does not designate a server plugin.
|
||||
|
||||
## Exit lifecycle
|
||||
|
||||
stdin EOF and `SIGTERM` dispose the root to quiescence and exit 0; `SIGINT` exits 130 after the same disposal. EOF may cut off an in-flight turn as documented in the [distribution Agent Note](../../../.agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.md). The `jsonrpc` plugin owns response-before-exit protocol shutdown; both paths are idempotent and safe to race.
|
||||
|
||||
## stdout is the protocol
|
||||
|
||||
stdout carries only JSON-RPC frames. The bin and boot guards diagnose on stderr, and the config must omit stdout loggers.
|
||||
|
||||
## Model Experience
|
||||
|
||||
Indirectly, through the plugins loaded from the external `cordis.yml`, which own every model-bound prompt, schema, message, and result; this bin adds none of its own.
|
||||
|
||||
#### KV Cache effect
|
||||
|
||||
No direct invalidation; the named consumer owns any request-prefix changes.
|
||||
|
||||
## Known Limitations and Deferred Work
|
||||
|
||||
- **The bin cannot prove that the config serves JSON-RPC** — a valid config with no `dsh-sdk-jsonrpc-server` entry boots successfully and serves nothing.
|
||||
- **No built-in or default config exists** — every launch must provide `DSH_CORDIS_CONFIG` or a positional path, and deployment owns the complete plugin tree and stdout discipline.
|
||||
- **stdin EOF cuts off in-flight work** — client disappearance disposes the root immediately; callers that need orderly completion use the protocol-level `shutdown` request.
|
||||
@@ -0,0 +1,33 @@
|
||||
# @deepseek-ai/dsh-sdk-jsonrpc-demo
|
||||
|
||||
[English](README.md) | 中文
|
||||
|
||||
只包含 bin 的应用,启动外部 `cordis.yml`;其 [`jsonrpc`](../../sdk/server/README.zh.md) 入口通过按换行分隔的 stdio 为 SDK 客户端提供服务。配置负责组合主干、后端和服务插件。发布的 `dsh-jsonrpc-agent` bin 从配置项目解析裸插件。Python SDK 的 `dsh-jsonrpc-agent-pkg` [单文件可执行运行时](../../../.agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.zh.md)改用 `lib/packaged-bin.js`:已打包的裸插件从封闭运行时包树解析,相对插件仍以配置目录为基准。
|
||||
|
||||
## 配置发现
|
||||
|
||||
第一个非空通道生效:先 `$DSH_CORDIS_CONFIG`,再位置参数 `argv[2]`。如果二者都没有指向现有文件,bin 会向 stderr 打印单行用法并以 1 退出;没有工作目录回退或内置回退。[`dsh-app-boot`](../../boot/app-boot/README.zh.md) 会使插件加载失败成为致命错误。此协议不使用 `DSH_SNAPSHOT`。
|
||||
|
||||
不含 `dsh-sdk-jsonrpc-server` 的配置仍然有效,只是不提供任何服务;bin 不会指定服务器插件。
|
||||
|
||||
## 退出生命周期
|
||||
|
||||
stdin EOF 和 `SIGTERM` 会 dispose(释放资源)根上下文,等待完全停稳后以 0 退出;`SIGINT` 完成同样的 dispose 后以 130 退出。EOF 可能按[分发 Agent Note](../../../.agents/notes/implemented/architecture/2026-07-10-single-file-executable-sdk-runtime-distribution.zh.md) 所述截断正在处理的轮次。`jsonrpc` 插件拥有先响应再退出的协议关闭流程;两条路径均幂等,即使发生竞态也安全。
|
||||
|
||||
## stdout 是协议
|
||||
|
||||
stdout 只承载 JSON-RPC 帧。bin 和启动守卫在 stderr 上输出诊断,配置必须省略 stdout logger。
|
||||
|
||||
## 模型体验
|
||||
|
||||
模型体验由外部 `cordis.yml` 加载的插件间接提供;这些插件负责所有面向模型的提示词、schema、消息和结果,此 bin 不添加任何内容。
|
||||
|
||||
#### KV Cache 影响
|
||||
|
||||
不会直接失效;由上述消费方负责请求前缀的任何变更。
|
||||
|
||||
## 已知限制与暂缓事项
|
||||
|
||||
- **bin 无法证明配置提供 JSON-RPC 服务**:不含 `dsh-sdk-jsonrpc-server` 条目的有效配置也能成功启动,但不会提供任何服务。
|
||||
- **不存在内置或默认配置**:每次启动都必须提供 `DSH_CORDIS_CONFIG` 或位置路径;部署方负责完整的插件树和 stdout 纪律。
|
||||
- **stdin EOF 会截断正在处理的工作**:客户端消失时立即释放根上下文;需要有序完成的调用方应使用协议级 `shutdown` 请求。
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"name": "@deepseek-ai/dsh-sdk-jsonrpc-demo",
|
||||
"description": "Bin that boots an external Cordis config for the stdio JSON-RPC SDK runtime",
|
||||
"version": "0.1.1-rc.2",
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/deepseek-ai/deepseek-harness.git",
|
||||
"directory": "packages/examples/jsonrpc-demo"
|
||||
},
|
||||
"type": "module",
|
||||
"main": "lib/index.js",
|
||||
"types": "lib/types/index.d.ts",
|
||||
"bin": {
|
||||
"dsh-jsonrpc-agent": "lib/bin.js"
|
||||
},
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./lib/types/index.d.ts",
|
||||
"default": "./lib/index.js"
|
||||
},
|
||||
"./invariant": {
|
||||
"types": "./lib/types/invariant.d.ts",
|
||||
"default": "./lib/invariant.js"
|
||||
},
|
||||
"./bin": {
|
||||
"types": "./lib/types/bin.d.ts",
|
||||
"default": "./lib/bin.js"
|
||||
},
|
||||
"./packaged-bin": {
|
||||
"types": "./lib/types/packaged-bin.d.ts",
|
||||
"default": "./lib/packaged-bin.js"
|
||||
},
|
||||
"./src/*": "./src/*",
|
||||
"./package.json": "./package.json"
|
||||
},
|
||||
"files": [
|
||||
"lib/index.js",
|
||||
"lib/invariant.js",
|
||||
"lib/bin.js",
|
||||
"lib/packaged-bin.js",
|
||||
"lib/types/**/*.d.ts"
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@deepseek-ai/dsh-app-boot": "workspace:^"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@deepseek-ai/dsh-invariants": "workspace:^",
|
||||
"@deepseek-ai/cordis": "workspace:^"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Generic JSON-RPC agent bin. External configurations own their bare plugin
|
||||
* packages; the packaged runtime uses `packaged-bin.ts` instead.
|
||||
*
|
||||
* @module @deepseek-ai/dsh-sdk-jsonrpc-demo/bin
|
||||
*/
|
||||
|
||||
import { runJsonrpcAgent } from './runner.ts'
|
||||
|
||||
await runJsonrpcAgent()
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Bin-only app package: its generic and packaged entries discover an external
|
||||
* `cordis.yml` and own process exit. This module exports no composition plugin;
|
||||
* the config chooses whether to load the
|
||||
* {@link @deepseek-ai/dsh-sdk-jsonrpc-server} serving plugin.
|
||||
*
|
||||
* @module @deepseek-ai/dsh-sdk-jsonrpc-demo
|
||||
*/
|
||||
|
||||
export {}
|
||||
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Package-owned invariant companion for `@deepseek-ai/dsh-sdk-jsonrpc-demo`.
|
||||
* @module @deepseek-ai/dsh-sdk-jsonrpc-demo/invariant
|
||||
*/
|
||||
|
||||
/* jscpd:ignore-start */
|
||||
import type { Context } from '@deepseek-ai/cordis'
|
||||
import type { InvariantInstaller } from '@deepseek-ai/dsh-invariants'
|
||||
|
||||
const PACKAGE_NAME = '@deepseek-ai/dsh-sdk-jsonrpc-demo'
|
||||
|
||||
/** Cordis companion plugin name. */
|
||||
export const name = 'sdk-jsonrpc-demo-invariant'
|
||||
/** Service required before the companion can reserve package ownership. */
|
||||
export const inject = ['invariants']
|
||||
|
||||
/**
|
||||
* No runtime invariant: this composition package owns no independent event stream or mutable data;
|
||||
* Loader and built-entry tests cover its wiring.
|
||||
*/
|
||||
const install: InvariantInstaller = () => {}
|
||||
|
||||
/**
|
||||
* Register this package's invariant companion.
|
||||
* @param ctx - Cordis context carrying the invariant service.
|
||||
* @returns the installed registration's disposer after setup succeeds.
|
||||
*/
|
||||
export const apply = (ctx: Context): Promise<() => void> =>
|
||||
Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install))
|
||||
/* jscpd:ignore-end */
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Closed-runtime JSON-RPC agent bin. Bare plugins resolve from the installed
|
||||
* runtime closure while relative plugins remain configuration-relative.
|
||||
*
|
||||
* @module @deepseek-ai/dsh-sdk-jsonrpc-demo/packaged-bin
|
||||
*/
|
||||
|
||||
import { runJsonrpcAgent } from './runner.ts'
|
||||
|
||||
/* v8 ignore next -- exercised through the built Python runtime carriers */
|
||||
await runJsonrpcAgent(import.meta.url)
|
||||
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* Shared process lifecycle for the generic and closed-runtime JSON-RPC bins.
|
||||
*
|
||||
* @module @deepseek-ai/dsh-sdk-jsonrpc-demo/runner
|
||||
*/
|
||||
|
||||
import { existsSync } from 'node:fs'
|
||||
import { boot, installFailLoud, loadEnv, resolveConfigPath } from '@deepseek-ai/dsh-app-boot'
|
||||
|
||||
/* v8 ignore start -- composition over tested app-boot/jsonrpc and executable acceptance paths */
|
||||
const NAME = 'dsh-jsonrpc-agent'
|
||||
|
||||
/**
|
||||
* Boot the explicitly selected external configuration and own process exit.
|
||||
* @param bareModuleBaseUrl - optional installed-runtime base for bare plugins;
|
||||
* omit it when the configuration project owns its plugin packages.
|
||||
* @returns after process handlers are installed; process lifetime then belongs
|
||||
* to stdin and signal events.
|
||||
*/
|
||||
export async function runJsonrpcAgent(bareModuleBaseUrl?: string): Promise<void> {
|
||||
installFailLoud(NAME)
|
||||
loadEnv(NAME)
|
||||
|
||||
// Env wins over argv; empty values are absent. External config defines the deployment.
|
||||
const fromEnv = process.env['DSH_CORDIS_CONFIG']
|
||||
const fromArgv = process.argv[2]
|
||||
const requested = fromEnv !== undefined && fromEnv !== ''
|
||||
? fromEnv
|
||||
: fromArgv !== undefined && fromArgv !== '' ? fromArgv : undefined
|
||||
const configPath = requested === undefined ? undefined : resolveConfigPath(requested, undefined)
|
||||
if (configPath === undefined || !existsSync(configPath)) {
|
||||
process.stderr.write(
|
||||
`usage: ${NAME} <path/to/cordis.yml> (or set DSH_CORDIS_CONFIG=<path>, which wins); the config is required — there is no built-in fallback\n`,
|
||||
)
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
const ctx = await boot(NAME, configPath, undefined, undefined, bareModuleBaseUrl)
|
||||
let exiting = false
|
||||
|
||||
async function disposeAndExit(code: number): Promise<void> {
|
||||
if (exiting) return
|
||||
exiting = true
|
||||
try {
|
||||
await ctx.fiber.dispose()
|
||||
} finally {
|
||||
process.exit(code)
|
||||
}
|
||||
}
|
||||
|
||||
process.stdin.on('end', () => { void disposeAndExit(0) })
|
||||
process.on('SIGTERM', () => { void disposeAndExit(0) })
|
||||
process.on('SIGINT', () => { void disposeAndExit(130) })
|
||||
}
|
||||
/* v8 ignore stop */
|
||||
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"extends": "../../../tsconfig.base.json",
|
||||
"compilerOptions": {
|
||||
"rootDir": "src",
|
||||
"outDir": "lib/types"
|
||||
},
|
||||
"include": [
|
||||
"src"
|
||||
],
|
||||
"references": [
|
||||
{
|
||||
"path": "../../../vendor/cordis"
|
||||
},
|
||||
{
|
||||
"path": "../../../vendor/loader"
|
||||
},
|
||||
{
|
||||
"path": "../../boot/app-boot"
|
||||
},
|
||||
{
|
||||
"path": "../../runtime-diagnostics/invariants"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { defineConfig } from 'tsdown'
|
||||
|
||||
/** Builds each published entry as a self-contained file admitted by the package whitelist. */
|
||||
export default defineConfig([
|
||||
{
|
||||
entry: ['lib/types/index.js'], outDir: 'lib', format: ['esm'], platform: 'node', target: 'es2024',
|
||||
fixedExtension: false, outputOptions: { codeSplitting: false }, dts: false, clean: false,
|
||||
},
|
||||
{
|
||||
entry: ['lib/types/invariant.js'], outDir: 'lib', format: ['esm'], platform: 'node', target: 'es2024',
|
||||
fixedExtension: false, outputOptions: { codeSplitting: false }, dts: false, clean: false,
|
||||
},
|
||||
{
|
||||
entry: ['lib/types/bin.js'], outDir: 'lib', format: ['esm'], platform: 'node', target: 'es2024',
|
||||
fixedExtension: false, outputOptions: { codeSplitting: false }, dts: false, clean: false,
|
||||
},
|
||||
{
|
||||
entry: ['lib/types/packaged-bin.js'], outDir: 'lib', format: ['esm'], platform: 'node', target: 'es2024',
|
||||
fixedExtension: false, outputOptions: { codeSplitting: false }, dts: false, clean: false,
|
||||
},
|
||||
])
|
||||
Reference in New Issue
Block a user