news 2026/10/21 2:14:25

[DeepSeek Harness插件内核-11]这算Cordis一个大BUG吗?

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
[DeepSeek Harness插件内核-11]这算Cordis一个大BUG吗?

在DeepSeek Harness插件内核-10:Fiber是如何管理插件生命周期的 介绍Fiber的时候,我曾经提到过Cordis一个关于Context隔离的问题,我们今天就来着重聊聊,看看它是否是Deep Harness的Bug。如果它算一个BUG的话,我觉得这是一个大BuG。

1. 问题重现

我们先利用一个简单的例子来重写这个问题。 如下面的代码所示,我们创建了一个作为根的Context,并采用指定的名称foobar注册了一个函数形式的服务,函数输出字符串foo。然后我们调用Context的isolate方法针对服务名称foobar创建了一个与根Context隔离的子Context,并在子Context上面使用相同的名称注册了另一个函数,后者输出bar。我们验证隔离性,我们直接利用从两个Context的foobar属性提取并执行注册的函数。

import{Context}from'@deepseek-ai/cordis'declaremodule'@deepseek-ai/cordis'{interfaceContext{foobar:()=>void;}}constcontext=newContext();context.provide("foobar",()=>console.log("foo"));constsubContext=context.isolate("foobar");subContext.provide("foobar",()=>console.log("bar"));context.foobar();subContext.foobar();console.log();context.plugin(ctx=>ctx.foobar());subContext.inject(["foobar"],ctx=>ctx.foobar());

然后我们在根Context调用plugin方法注册了一个插件,对应的插件函数会直接提取并执行当前Context的foobar属性,并作为函数予以执行。针对子Context,我们则调用inject将foobar服务作为注入到注册的插件中,该插件与注册在根Context的插件具有相同的实现。从如下的输出可以看出:直接调用Context提取的服务函数会输出我们希望的结果,但是通过插件执行的输出则不行。

foo bar bar bar

输出为bar的函数注册在子Context上,而且是通过调用isolate针对服务注册名称foobar创建的,但是却没有起到隔离的作用,把注册在根Context上的同名服务给覆盖了。

2. 进一步验证Context上注册的服务是否正确?

我们可以进一步按照DeepSeek Harness插件内核-06:Context全面解析介绍的关于isolate方法执行逻辑看看作为服务标识的Symbol是否正确写入两个Context的symbols.isolate字典中。为此我们利用如下的方式分别从两个Context的symbols.isolate字典中将服务名称foobar对应的Symbol提取出来,然后以此作为Key从RefelectService中提取对应的服务实例并执行。从输出来看毫无问题。

import{Context,symbols}from'@deepseek-ai/cordis'declaremodule'@deepseek-ai/cordis'{interfaceContext{foobar:()=>void;}}constcontext=newContext();context.provide("foobar",()=>console.log("foo"));constsubContext=context.isolate("foobar");subContext.provide("foobar",()=>console.log("bar"));context.foobar();subContext.foobar();console.log();letkey=context[symbols.isolate]["foobar"]assymbol;(context.reflect.store[key]?.valueas()=>void)();key=subContext[symbols.isolate]["foobar"]assymbol;(context.reflect.store[key]?.valueas()=>void)();

输出:

foo bar foo bar

3. 查看Fiber的服务存储

到目前为止我们可以确认当注册在根Context中的插件在执行的时候,提取foobar服务实例并没有按照我们希望的方式:从根Context的symbols.isolate字典中根据指定的服务注册名称查询出作为服务实例唯一标识的Symbol,再从ReflectService的store这个服务全局注册表中提取对应的封装了服务实例的Impl对象。那么插件执行过程中提取的服务实例来源于何处呢?通过DeepSeek Harness插件内核-08:利用RefectService以反射方式扩展Context的介绍,ReflectService的provide方法还会将服务冗余存储与当前Fiber对象的store字典中,如下的演示程序证实了这一点:

import{Context,symbols}from'@deepseek-ai/cordis'declaremodule'@deepseek-ai/cordis'{interfaceContext{foobar:()=>void;}}constcontext=newContext();context.provide("foobar",()=>console.log("foo"));constsubContext=context.isolate("foobar");subContext.provide("foobar",()=>console.log("bar"));context.foobar();subContext.foobar();(context.fiber.store!["foobar"]?.valueas()=>void)();

输出:

foo bar bar

而且这也能充分介绍前面的现象:当我们调用isolate方法创建一个子Context的时候,只会为创建的Context指定一个symbols.isolate字典,但是Fiber依然是继承自父Context。所以当我们调用provide方法在子Context上注册同名服务的时候,虽然可以保证新的服务映射会保存在子Context上,由于两个Context共享同一个Fiber,之前存储在store字典中的服务自然被覆盖了。

4. 是什么导致从Fiber中提取服务

到目前为止,一切都是我的猜测,如何确定注册的插件执行的时候会从Fiber中提取服务呢?由于插件仅仅是调用ctx.foobar()方法提取并执行服务函数,而且我们知道这个插件的ctx只是一个代理而已,针对foobar方法的读取会被代理处理器拦截,既然ctx的foobar属性返回了错误的对象,我们就通过代理处理器的定义来看看它究竟注入了怎样的拦截操作。通过DeepSeek Harness插件内核-07:Context全面解析的介绍,我们知道这个代理处理器定义在ReflectService的静态属性handler上。

exportclassReflectService{statichandler:ProxyHandler<Context>={get:(target,prop,ctx:Context)=>{...try{...returnctx.events.waterfall('internal/get',ctx,prop,error,()=>{constkey=target[symbols.isolate][prop]letfiber=(ctx[symbols.shadow]asContext??ctx).fiberwhile(true){constimpl=fiber.store?.[prop]if(impl)returngetTraceable(ctx,impl.value)if(propinfiber.inject){error.message=`cannot get required service "${prop}" in inactive context`throwerror}if(!fiber.runtime)throwerrorif(fiber.parent[symbols.isolate][prop]!==key)throwerror fiber=fiber.parent.fiber}})}catch(e:any){throwe===error?enhanceError(e):e}},}}

ReflectService的静态属性handler返回一个ProxyHandler<Context>对象,上面提供了该对象get方法的部分代码,我们上面的假设在这里得到了印证(const impl = fiber.store?.[prop];if (impl) return getTraceable(ctx, impl.value))。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/21 2:13:21

老款 Mac 免费装最新 macOS:OpenCore Legacy Patcher 完整安装指南

老款 Mac 免费装最新 macOS:OpenCore Legacy Patcher 完整安装指南 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 苹果的官方更新列表里已经没有你的老机型了…

作者头像 李华
网站建设 2026/10/21 2:10:57

小模型量化值不值?Qwen2.5-0.5B-Instruct W8A8量化版实测与对比

大模型基础模型Qwen 【免费下载链接】Qwen2.5-0.5B-Instruct 项目地址&#xff1a; https://ai.gitcode.com/hf_mirrors/vllm-ascend/Qwen2.5-0.5B-Instruct 点击查看 免费下载 本文围绕 Qwen2.5-0.5B-Instruct 这款 0.49B 参数量的指令微调对话模型&#xff0c;对比其 BF16 原…

作者头像 李华
网站建设 2026/10/21 2:09:45

基于改进粒子群优化的永磁同步电机多参数辨识全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 2:08:58

海量终端AI化破局:从工程化流水线到数据闭环的落地路径

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/21 2:07:32

ZCC485高速超低功耗RS485芯片实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华