Pitfalls (must stay in code)
August 24, 2026 · View on GitHub
Ported from adpworker CONTRIBUTING-ADP.md and docs/ADP-接口盘点与需求.md. Each item names the fixture that pins it.
Install
dsh plugin addrecords the package.json name (@tencentcloudadp/dsh-adp), not the folder name, and injectscordis.patch.ymlas one profile bundle layer. Do not also pass--patch ./cordis.patch.yml, and do not copy those rows into the profile'scordis.patch.yml— either duplicates loader idadp-coreanddsh webfails.- If this checkout was already linked under another name (the folder alias
adp-dsh-pluginis the usual leftover), remove the old name, then add once:dsh plugin --profile web remove adp-dsh-plugin. ~/.dsh/profiles/web/package.jsonmust list@tencentcloudadp/dsh-adponce under bothdependenciesanddsh.profile.bundles. A profilecordis.patch.ymlrow that still saysname: adp-dsh-plugin(even under a leftover id such asmcp-tencent-cloud-docs) is not this bundle — delete it; it re-registersctx.adp.- Git installs fetch source and run
prepare(tsdown). pnpm ≥10 blocks that until the package is listed underallowBuildsin the profile'spnpm-workspace.yaml. Apnpm packtarball is already compiled and does not need that allowance. - After editing this checkout, run
pnpm run prepare(orpnpm test) and restartdsh web; the profile link loadslib/, notsrc/.
-
Plugins are MCP and API. Only wiring MCP drops half the marketplace. API tools live at
ToolConfig.ApiToolConfig.ExternalApiUrl. Fixture:tests/fixtures/control/plugin-detail-api.json. -
MCPTransport0 = SSE, 1 = streamable-http. POST to an SSE endpoint is 405. Never silently retry the other transport. Fixture / sim:sim-plugin-mcp-405. -
Availability is
DescribePluginonly. CatalogueAllowExternalAccessisfalseeven for working plugins. Fixture:tests/fixtures/control/plugin-summary-page0.json(false) vsplugin-detail-usable.json(URL present). Sim:sim-plugin-filter. -
API responses may be cumulative SSE.
Accept: application/jsonis ignored. LastData.Answerwins; concatenating repeats the text. Fixture:tests/fixtures/plugin/api-cumulative.sse,search-cumulative.sse. -
Plugin catalogue
PageNumberis 0-based. Sending1as the first page looks like “no results” next to a non-zeroTotalCount. Fixture: page0 + page1 JSON. Sim:sim-plugin-list. -
Account envelope is
reqId/code/data, not PascalCase. Fixture:tests/fixtures/account/lowercase.json. OneID login-url is proxied at/adp/account/login-urlfor the settings card; it does not fill the three keys. Fixture:tests/fixtures/account/login-url.json. Do notexport default AdpServicefrom the package entry:Loader.unwrapExportswould load the class and skipapply, so the proxy never registers anddsh webanswers POST with 405 empty. Sim:sim-export. -
MCP idle ~600s, no ping. Reconnect on idle. Fast fail (<3s, request likely never arrived) may retry; a call that ran for a while must not auto-retry (may already be billed).
-
Generation COS links expire ~24h. Harvest into the workspace; canonical value carries
saved_files. Sim:sim-media. -
Three keys do not substitute. SSE chat still needs AppKey. Sim:
sim-cred-missing,sim-appkey-absent. -
Skill detail examples often omit
SkillUrl/SkillMarkdownUrl. Empty URL →listonly, never useProfile.Descriptionas the body. Fixtures:skill-detail-empty.json,skill-detail-md.json. Sim:sim-skill-empty-url,sim-skill-md. -
DescribeApp.SecretInfoneedsFieldMask.Paths=["SecretInfo"]. Without it, null. May also be empty before release finishes. Fixtures:describe-app-no-mask.json,describe-app-with-mask.json. Sim:sim-appkey-mask. -
Agent/App edits do not take effect until
CreateRelease. Release is async (Status 3 success / 4 fail). Poll viactx.jobs(or inside the provision tool), never ask the model to sleep. Sim:sim-provision. -
Claw models are
ModelScene=18, not Agent thinking3. -
adp-coreis a function plugin (name/inject/apply), same asllm-adp. A class default export is eaten by the loader. Sim:sim-export. -
独立站 / 公有云 switches control + SSE, not the model gateway. Completions stay on
api.adp.cloud.tencent.comand use the site's Tool Key (ADP_API_KEY). SecretId/SecretKey is a separate credential pair. Sim:adp site proxy. -
Site settings wait for
adp, not onlysettings.ctx.inject(['settings'])can run beforeAdpServiceprovidesadp. ThenregisterSiteSettingsno-ops,settings.update('adp-core')throws, anddsh-host-webserveranswers POST/adp/sitewith an empty 400. Inject['settings', 'adp']. Sim:sim-site-settings. -
Public-cloud
DescribeSkillSummaryListrejectsFilterList.Perspective. Official body is{ SpaceId, PageNumber, PageSize }. Perspective defaults to USER and is only legal with custom ProviderType.DescribeSpaceListhas noPageNumber. Live:tests/live/cloud-e2e.test.ts. -
Model gateway path is
/chat/completions, not/v1/chat/completions. Official ADP docs only cover CAM control + AppKey SSE (wss.lke…/adp/v2/chat). The OpenAI-shaped host isapi.adp.cloud.tencent.comwith no/v1prefix (adpworkerOpenAIProviderbase_url)./v1/chat/completionsreturns 401not_authorizedfor a key that 403sAccountOverdueErroron the unprefixed path. Live:tests/live/cloud-e2e.test.ts. -
Public-cloud
SpaceIdis a real workspace, notdefault_space.cordis.patch.ymlstill defaultsspaceId: default_space. Cloud AKSK injects that value into space-scoped list/create calls, andDescribeAppSummaryList/DescribePluginSummaryListthen return4510004 空间信息不存在if it is wrong. Pick a workspace on the Settings card (stored asadp-core.spaceId). Completions do not use SpaceId; apps and plugins do. Do not send SpaceId on AppId-scoped actions (DescribeApp,DeleteApp,CreateAgent,DescribeAgentSummaryList,CreateRelease,DescribeReleaseSummary, …) — they returnUnknownParameter. Sim:sim-spaceid-scope. Live:tests/live/cloud-e2e.test.ts. -
DescribeModelListids live underModelBasic. Public-cloud and independent-siteDescribeModelListrows are{ ModelBasic: { ModelId, ModelName, … } }. Reading only top-levelModelIdyields an empty list andlistModelssilently returns builtins. Independent-siteListModelusesModelName(noModelId). Fixture: nested rows intests/unit/sim.test.tsnormalizeModelList. Live:tests/live/cloud-e2e.test.ts,tests/live/standalone-e2e.test.ts. -
Independent-site completions use the same cloud gateway. There is no
api.adp.tencent.com. A 401AuthenticationError(凭证无效或已过期)onPOST /chat/completionsmeans that API key is dead; 401not_authorizedis the/v1path bug. A valid gatewayADP_API_KEYcompletes independent-site catalog ids (Deepseek/deepseek-v4-flash,Hunyuan/hy3, …) onapi.adp.cloud.tencent.com. Live:tests/live/standalone-e2e.test.ts. -
CreateAgenttakes nestedAgent, not top-levelName. Official body is{ AppId, Kind, Agent: { Profile: { Name, Role }, Instructions, Model: { ModelId }, PluginList: [{ PluginId }], SkillList: [{ SkillId }] } }. A flatNamereturnsUnknownParameter. Claw models come fromDescribeModelListModelScene=18. Sim:sim-provision. Live:tests/live/cloud-e2e.test.ts. -
DescribeReleaseSummaryrequiresReleaseId. Official body is{ AppId, ReleaseId }.CreateReleasereturnsReleaseId; polling with onlyAppIdisMissingParameter. Status isReleaseSummary.Status(3published,4failed). Sim:sim-provision. Live:tests/live/cloud-e2e.test.ts. -
adp_callpayload must be an object. Models often stringifytype: jsonargs. A string body used to become{}and thenMissingParameter. Parse JSON strings; keep objects. Sim:sim-adp-call-json-string. -
App lists paginate with
PageNumber/PageSize, 0-based.Offset/Limitare ignored.TotalCountof hundreds with 15 rows means the first page only. Same forDescribePluginSummaryList(pitfall 5).DescribeAgentSummaryListis AppId-scoped and rejectsSpaceId. -
adp_ask_<slug>must use the same slug provision advertises.kebab("Claw Demo 应用")isclaw-demo, butslugAsciiused to return''on any CJK character andagentToolNamehashed, so provision told the model to calladp_ask_claw-demowhileregisterAskToolregisteredadp_ask_a…. The executor then returnedunknown tool "adp_ask_claw-demo". Both sides now useagentToolName/askSlug. The provision result also returnsask: { tool: "adp_ask", appKeyEnv }because DSH snapshots the tool list for the current turn. Sim:sim-ask-name,tests/unit/llm-loop.test.ts. -
Agent-loop wire format follows
llm-deepseek, not a looser OpenAI subset. ADP's gateway hosts Hunyuan, DeepSeek V4, GLM, Kimi, MiniMax. Tool-call turns must sendcontent: ""(nevernull), pass backreasoning_contentwhen thinking ran, keep user text plusrole: toolresults, and never let continuation SSE deltas withid/name""ornullwipe the first identity (communityunknown tool ""on DSH 0.1.0-rc.7). Object-shapedfunction.argumentsis JSON.stringified. Sim:tests/unit/llm-loop.test.ts,sim-llm-sse. -
adp_callneeds a per-action contract. Raw OpenAPI passthrough made the model guess:DescribeModelListwithoutModelScene,DescribeAgentDetailwithoutAppId,CreateReleasewithAgentId,GetAppSecret.AppIdinstead ofAppBizId, top-levelModifyAgent.SkillList,ChatCompletionsas a control action (InvalidAction).adp_list_actionsnow shipsrequired/hint/example;adp_callremaps/nests/drops known mistakes and refuses dead actions before the signed request. CreateRelease450027is recovered viaDescribeLatestRelease. Sim:sim-adp-call-contract,sim-release-already. -
DescribeSkillCategoryListrejectsSpaceId. Cloud AKSK auto-inject must not add it (same class as AppId-scoped actions). Sim:sim-spaceid-scope.