Replies: 1 comment
|
Great writeup — and the root cause is cleanly confirmed by the source. Your Gap 1 is not a bug, it's the documented (but under-publicized) contract, and it's worth making that explicit because the failure message genuinely reads like a bug. The
So the design is: a harness that lacks your plugin must still be able to read the log without breaking replay, because it cannot know what What I'd add to the docs (your suggestion #3, and it dovetails with your #1): the current err message is tersely "unknown to this harness and not marked ignorable; refusing to interpret the log — it was likely written by a newer harness". That tail assumption ("newer harness") is wrong for the out-of-tree plugin case — it's more likely a plugin event from an uninstalled plugin. A runtime hint like:
For your Gap 3 — the invisible One tool that would have caught Gap 1 immediately: a proactive completeness audit over the session log. @argszero/cordis-plugin-session-audit classifies the corruption surface before replay — its Happy to help turn Gap 1's doc sentence into a concrete PR, or review the docs-mapping table for Gap 2 if you draft it — the |
Uh oh!
There was an error while loading. Please reload this page.
中文摘要:我们开发并发布了一个第三方插件(
@wy35002/dsh-model-fallback,模型限流/配额自动回退)。开发过程踩了三个坑,其中一个是机制层缺口(第三方插件声明的持久会话事件类型永远不在KNOWN_SESSION_EVENT_TYPES里,导致带该事件的会话在任何官方 harness 上都拒绝加载),另外两个是文档盲区(client 端 inject 与ctx.remote.*命名空间的对应关系;rc 升级对仓库外插件作者的破坏性变更没有 changelog 提示)。详细经过与建议如下,希望对其他插件作者有帮助,也欢迎维护者评估是否值得改进文档或机制。Context
We built and published a third-party plugin:
@wy35002/dsh-model-fallback(+ a companion UI settings card@wy35002/dsh-model-fallback-ui) — it auto-switches the model on rate-limit/quota failures by advancing a user-configured fallback chain, and ships a settings card for labeling models free/paid.We developed it against
0.1.2-alpha.3(master at the time), then adapted and republished it for0.1.2-rc.1. It is now working end-to-end (define → publish to npm →dsh plugin add→ settings card → model calls). The documentation was a big help:docs/user/develop/basic/publish.md(bundle/profile model) anddocs/cookbook/adding-a-settings-card.md(the two halves + namespace-as-join-key) are excellent, and we followed them closely.That said, three things cost us a lot of debugging time. Sharing them in case they help other plugin authors — and in case the maintainers want to close the gaps.
Gap 1 (mechanism): durable session events written by an npm-installed plugin are always "unknown" to the stock harness
Our plugin appends a durable event type
model-fallback/switch(declared viadeclare module '@deepseek-ai/dsh-session/types'merging, folded by a session projection). Sessions written by the plugin then fail to load with:Root cause:
KNOWN_SESSION_EVENT_TYPES(packages/core/session/src/known-event-types.ts) is generated byscripts/gen-persistence-catalog.ts, which scanspackages/*/*/src/**/*.ts— in-repo sources only. A plugin installed from npm into a profile'snode_modulesis never scanned, so:Our workaround was only possible because we develop the plugin inside a repo checkout: re-run
gen-persistence-catalogwith the plugin source present underpackages/experimental/, force-rebuild (tsdowndoes not pick up the regenerated file on an incrementalbuild:lib:host— we had to re-run the host-face bundling explicitly), and restart. A plugin author who only ships npm tarballs cannot do this.Questions / suggestions:
ignorable: trueon the envelope? That keeps the log loadable on harnesses without the plugin, and our projection still folds them from the loaded log — but we could not find this documented anywhere as the contract for out-of-tree plugins. If it is the contract, a sentence in the plugin docs (docs/user/develop/) would prevent people from hitting a scary, log-poisoning failure.Gap 2 (docs): the client-side
inject→ctx.remote.*namespace mapping is undocumentedOur settings card needed
session/modelCatalog(to list each provider's models). On the browser side,ctx.remote.sessionwasundefinedeven though the Host serves the namespace fine — because ourdsh.client.injectdid not include the package that contributes that namespace.What we learned by trial and error:
ctx.remote.session(modelCatalog, prompt, …)@deepseek-ai/dsh-api-session-controllerctx.remote.llm(listProviders, …)@deepseek-ai/dsh-api-remotesdocs/cookbook/adding-a-settings-card.mdshows an exampleinjectlist, but does not explain which package contributes whichctx.remote.*namespace — and the failure mode is silent (our store swallowed the TypeError into an empty array, so the panel just showed no models). A small mapping table in that cookbook (or in the client modules README) would have saved us hours. Relatedly,session/modelCatalogis exactly the right API for "list currently routable models per provider" — worth mentioning there too, sincellm.discoverModelsonly covers providers that registered model discovery (the built-indeepseek-officialroute has none, so it errors withno model discovery is registered for "llm-deepseek").Gap 3 (docs/changelog): plugin-affecting breaking changes between 0.1.2-alpha.3 → rc.1 were invisible to out-of-tree authors
Adapting our plugin to rc.1 required discovering, by typecheck archaeology:
session.events(public getter over the log) is gone — replaced bysession.snapshotEvents()/session.surface/session.ownEvents().LlmModelInfois exported from@deepseek-ai/dsh-llm/types, not re-exported from@deepseek-ai/dsh-api-remotes/client.session/modelCatalogis the supported path;llm.discoverModels(settingsNs, request)only works for providers that registered discovery.None of these appear in any changelog/release note as plugin-affecting. Since "everything is a plugin" extends to out-of-tree authors, a short "changes affecting third-party plugins" section per release (or a
docs/user/develop/migration note per breaking release) would make rc-to-rc upgrades much cheaper.What worked well
To be balanced:
docs/user/develop/basic/(first plugin → config → publish) is a genuinely good tutorial path; the bundle/profile two-manifest model is clean anddsh plugin addjust works; and the settings-card cookbook's "namespace is the join key; a card renders when the Host serves its key" design made the two halves pair up automatically once we got the packaging right. The harness being fully source-runnable made every failure debuggable down to the generated catalog files.Happy to expand any of this into concrete docs PRs if the maintainers tell me which direction they prefer (docs-first vs. mechanism change for Gap 1).
Plugin:
@wy35002/dsh-model-fallbackon npm (host plugin + client settings card). Developed on a source checkout of0.1.2-alpha.3, now running against0.1.2-rc.1on Windows.All reactions