@ai-workbench/remote-agent 0.8.23 → 0.8.24

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # AI Workbench 远程助手 · @ai-workbench/remote-agent@0.8.23 · 插件 → 添加插件
1
+ # AI Workbench 远程助手 · @ai-workbench/remote-agent@0.8.24 · 插件 → 添加插件
2
2
 
3
3
  通过官方 DSH 插件入口使用 Claude(远程主机)与 Codex(远程主机)。登录和工作区来源由“远程主机连接”组件提供;员工在原生工作区和模型菜单中选择文件夹与型号。
4
4
 
@@ -43,3 +43,5 @@ Codex 员工端只使用随包提供的原生组件,通道等待本次组件
43
43
  工程验证、独立审查、固定包摘要及实际设备验收分别记录在 `docs/evidence/2026-10-24-X-executor-readiness/` 和项目 X 回执中。插件不修改 DSH 核心,不添加启动器或自定义 profile。
44
44
 
45
45
  远程助手参数页只显示官方 ConfigForms 当前值,不提供保存、放弃或恢复继承值;修改请使用 DSH 官方 Config“打开配置文件”入口。
46
+
47
+ 模型目录在官方启动读取时获取,并在连接变为 connected 时经官方注册刷新;官方菜单打开或重试读取缓存是 DSH 官方限制,本插件不改官方菜单或核心。真正不支持的推理档位由 DSH 预检,其英文提示保留为观察项。
package/dist/acp.js CHANGED
@@ -484,7 +484,7 @@ export class AcpSession {
484
484
  signal?.addEventListener('abort', abort, { once: true });
485
485
  try {
486
486
  const hello = await this.stage('acp-initialize', () => this.connection.agent.request(acp.methods.agent.initialize, {
487
- protocolVersion: acp.PROTOCOL_VERSION, clientInfo: { name: '@ai-workbench/remote-agent', version: '0.8.23' },
487
+ protocolVersion: acp.PROTOCOL_VERSION, clientInfo: { name: '@ai-workbench/remote-agent', version: '0.8.24' },
488
488
  clientCapabilities: { fs: { readTextFile: false, writeTextFile: false }, terminal: false, session: { notices: {} }, ...(this.employeeMeta ? { _meta: { awEmployeeExecution: { version: 1, closeReason: 1 } } } : {}) },
489
489
  }, { cancellationSignal: signal }));
490
490
  if (hello.protocolVersion !== acp.PROTOCOL_VERSION)
@@ -152,7 +152,7 @@ export async function openEmployeeMcp(options) {
152
152
  return tools.call(request.params.name, request.params.arguments ?? {}, signal, event => { if (sink)
153
153
  observeUsing(event, sink); });
154
154
  });
155
- mcp.onerror = () => { observeConnection?.({ layer: 'relay', initiator: 'mcp.server-error', reason: 'EMPLOYEE_MCP_PROTOCOL_OR_TRANSPORT_ERROR', action: 'failure' }); observe({ kind: 'session', severity: 'warning', code: 'CLAUDE_EMPLOYEE_MCP_UNKNOWN', summary: '本机工具连接出现协议或传输错误;恢复后可在原会话继续。' }); };
155
+ mcp.onerror = () => { observeConnection?.({ layer: 'relay', initiator: 'mcp.server-error', reason: 'EMPLOYEE_MCP_PROTOCOL_OR_TRANSPORT_ERROR', action: 'failure' }); observe({ kind: 'session', severity: 'warning', code: 'CLAUDE_EMPLOYEE_MCP_UNKNOWN', summary: '本机工具连接中断,在途结果未知,没有重放;恢复后可在原会话继续。' }); };
156
156
  mcp.onclose = () => { observeConnection?.({ layer: 'relay', initiator: 'mcp.client-closed', reason: 'MCP_CLIENT_CLOSED', action: 'close' }); clients.delete(mcp); transports.delete(transport); };
157
157
  void mcp.connect(transport).catch(error => { observeConnection?.({ layer: 'relay', initiator: 'mcp.connect-failure', reason: closeCode(error, 'MCP_CONNECT_FAILED'), action: 'close' }); socket.destroy(); });
158
158
  });
package/dist/index.d.ts CHANGED
@@ -74,8 +74,8 @@ export declare class CodexRemoteAdapter extends LlmAdapter {
74
74
  listModels(provider: string): Promise<(LlmResolvedModelInfo & {
75
75
  catalog: HostModel;
76
76
  })[]>;
77
- resolveModel(provider: string, id: string, _signal?: AbortSignal): Promise<LlmResolvedModelInfo>;
78
- prepareCall(provider: string, id: string, _signal?: AbortSignal): Promise<{
77
+ resolveModel(provider: string, id: string, signal?: AbortSignal): Promise<LlmResolvedModelInfo>;
78
+ prepareCall(provider: string, id: string, signal?: AbortSignal): Promise<{
79
79
  model: LlmResolvedModelInfo;
80
80
  stream: (options: GenerateOptions) => AsyncGenerator<StreamChunk, any, any>;
81
81
  }>;
package/dist/index.js CHANGED
@@ -27,7 +27,7 @@ import { createClaudeLocalProvider } from "./claude-local.js";
27
27
  import { readLocalUserTurn } from "./local-user-turn.js";
28
28
  import { readEmployeeWorkspace } from "./employee-workspace.js";
29
29
  import { createPreflightDiagnostics } from "./preflight-diagnostic.js";
30
- import { installModelInputRetention } from "./model-input-retention.js";
30
+ import { installModelInputRetention, markModelPreparationFailure } from "./model-input-retention.js";
31
31
  import { dshPermissionSource, permissionMode } from "./permissions.js";
32
32
  export { readDshPermissions } from "./permissions.js";
33
33
  export const name = 'ai-workbench-remote-agent';
@@ -121,8 +121,33 @@ export class CodexRemoteAdapter extends LlmAdapter {
121
121
  finally {
122
122
  catalog.release();
123
123
  } }
124
- async resolveModel(provider, id, _signal) { return this.modelPresentation.resolve(provider, id) ?? { provider, id, name: id }; }
125
- async prepareCall(provider, id, _signal) { return { model: await this.resolveModel(provider, id), stream: (options) => this.stream(options) }; }
124
+ async resolveModel(provider, id, signal) {
125
+ const displayed = this.modelPresentation.resolve(provider, id);
126
+ if (displayed)
127
+ return displayed;
128
+ const active = signal ? AbortSignal.any([signal, this.lifetime.signal]) : this.lifetime.signal;
129
+ const catalog = await this.catalog(active);
130
+ try {
131
+ active.throwIfAborted();
132
+ this.modelPresentation.remember(catalog);
133
+ const resolved = this.modelPresentation.resolve(provider, id);
134
+ if (!resolved)
135
+ throw new LlmError('所选模型当前不可用,请打开模型菜单重新选择。', 'MODEL_CATALOG_UNAVAILABLE');
136
+ return resolved;
137
+ }
138
+ finally {
139
+ catalog.release();
140
+ }
141
+ }
142
+ async prepareCall(provider, id, signal) {
143
+ try {
144
+ return { model: await this.resolveModel(provider, id, signal), stream: (options) => this.stream(options) };
145
+ }
146
+ catch (error) {
147
+ markModelPreparationFailure(provider, error, signal);
148
+ throw error;
149
+ }
150
+ }
126
151
  providerRetryPolicy() { return { mode: 'normal', maxRetries: 0, retryableCodes: [], initialDelayMs: 0, maxDelayMs: 0, jitterRatio: 0 }; }
127
152
  cleanupRuntime(runtime, cause = { layer: 'adapter', initiator: 'adapter.cleanup-runtime', reason: 'RUNTIME_CLEANUP', action: 'dispose' }) {
128
153
  runtime.closeDiagnostics?.record(cause);
@@ -665,12 +690,18 @@ export function apply(ctx, live) {
665
690
  }
666
691
  return managerForProfile().recordLoginFailure({ sessionId, code, diagnostic, context: { turn, step } });
667
692
  }, modelDirectory, preflightDiagnostics, dshPermissionSource(ctx));
668
- for (const agent of AGENTS)
669
- void adapter.listModels(agent.id).catch(() => ctx.logger('remote-agent').warn('模型列表暂不可用,打开菜单时可重新读取'));
670
693
  const ids = AGENTS.map(agent => agent.id);
671
694
  const entries = () => AGENTS.map(agent => ({ provider: agent.id, displayName: agent.name[language], settingsNs: actualSettingsNamespace ?? settingsNamespace, settingsPath: [] }));
672
695
  const directory = ctx.llm.registerConfigurableProviders(entries());
673
696
  const registration = ctx.llm.registerAdapter(ids, adapter);
697
+ let connection;
698
+ ctx.on('ai-workbench/connection-state', state => {
699
+ const previous = connection;
700
+ connection = state;
701
+ // Official replacement invalidates the browser's shared catalog and loads it.
702
+ if (state.phase === 'connected' && (previous?.phase !== 'connected' || previous.instanceId !== state.instanceId || previous.epoch !== state.epoch))
703
+ registration.replace(ids);
704
+ });
674
705
  installModelInputRetention(ctx, { isOurProvider: provider => ids.includes(provider), diagnosticForAttempt: position => preflightDiagnostics.forPreparation(position.sessionId, position), preflightDiagnostic: (provider, message) => diagnostic('preflight', provider, message), diagnostic: (provider, message) => diagnostic('input', provider, message) });
675
706
  const cleanup = async (id) => { try {
676
707
  await adapter.detachSession(id);
@@ -1,6 +1,5 @@
1
1
  /** Functional wording from connect-api appendix D1-D3 (L0.5.1 candidate). */
2
2
  export declare const REMOTE_CODEX_NAME = "Codex\uFF08\u8FDC\u7A0B\u4E3B\u673A\uFF09";
3
3
  export declare const CONNECTION_REQUIRED = "\u8FDC\u7A0B\u4E3B\u673A\u8FDE\u63A5\u7EC4\u4EF6\u6CA1\u6709\u88C5\u597D\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u3002";
4
- export declare const TEST_HOST_NOTICE = "\u8FDC\u7A0B\u4E3B\u673A\u6B63\u5728\u4F7F\u7528\u6D4B\u8BD5\u914D\u7F6E\uFF0C\u9047\u5230\u95EE\u9898\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u3002";
5
4
  /** Employee failures use business language; diagnostic codes remain separately available. */
6
5
  export declare function employeeFailure(code: string, brand?: 'codex' | 'claude'): string;
@@ -1,7 +1,6 @@
1
1
  /** Functional wording from connect-api appendix D1-D3 (L0.5.1 candidate). */
2
2
  export const REMOTE_CODEX_NAME = 'Codex(远程主机)';
3
3
  export const CONNECTION_REQUIRED = '远程主机连接组件没有装好,请联系管理员。';
4
- export const TEST_HOST_NOTICE = '远程主机正在使用测试配置,遇到问题请联系管理员。';
5
4
  /** Employee failures use business language; diagnostic codes remain separately available. */
6
5
  export function employeeFailure(code, brand = 'codex') {
7
6
  const messages = {
@@ -89,18 +89,6 @@ export type RuntimeProvider = ((request: RuntimeRequest) => Promise<Runtime>) &
89
89
  preflight?: (request: RuntimeRequest) => Promise<void>;
90
90
  };
91
91
  export interface ConnectTarget {
92
- hostContext?: {
93
- enforcement: 'production' | 'test';
94
- checkExitCode: 0 | 1;
95
- failedChecks: {
96
- id: string;
97
- status: string;
98
- }[];
99
- unverifiedChecks: {
100
- id: string;
101
- status: string;
102
- }[];
103
- };
104
92
  host: string;
105
93
  username: string;
106
94
  port: number;
@@ -165,8 +153,6 @@ declare module '@deepseek-ai/cordis' {
165
153
  export declare function awaitL<T>(operation: () => Promise<T>, signal?: AbortSignal): Promise<T>;
166
154
  export declare function unwrap<T>(result: Result<T>): T;
167
155
  export declare function validateTarget(t: ConnectTarget): void;
168
- /** Only the declared public check identifiers/statuses, never provider evidence. */
169
- export declare function hostContextNotice(t: ConnectTarget): string | undefined;
170
156
  export declare function identity(t: ConnectTarget): string;
171
157
  /** Reject draft.3 and legacy runtime rather than inventing workspace bindings. */
172
158
  export declare function requireNativeWorkspace(api: ConnectApi): asserts api is ConnectApi & NativeWorkspaceApi;
package/dist/provider.js CHANGED
@@ -2,7 +2,7 @@ import { hostWorkspaceGuard } from "./host-workspace.js";
2
2
  import { connectNeedError } from "./connect-need.js";
3
3
  import { loginDiagnostic, loginReason } from "./login-diagnostic.js";
4
4
  import { NeedError } from "./remote.js";
5
- import { CONNECTION_REQUIRED, TEST_HOST_NOTICE } from "./presentation.js";
5
+ import { CONNECTION_REQUIRED } from "./presentation.js";
6
6
  import { CODEX_AGENT } from "./agents.js";
7
7
  export function requireLoginCoordinator(api) {
8
8
  if (!['getConnectionState', 'getLoginPromptState', 'requestLoginPrompt', 'refreshLoginPrompts'].every(key => typeof api[key] === 'function'))
@@ -118,19 +118,6 @@ export function validateTarget(t) {
118
118
  || ![t.projectRoot, t.session.command, t.session.root, t.session.settingsPath].every(p => typeof p === 'string' && p.startsWith('/'))) {
119
119
  throw new NeedError('CONNECT_API_MISMATCH', '我需要 connect-api 0.3.0 的可信主机、项目和 session 能力;旧目标不能继续使用', 'L 提供的完整 0.3.0 目标');
120
120
  }
121
- hostContextNotice(t);
122
- }
123
- /** Only the declared public check identifiers/statuses, never provider evidence. */
124
- export function hostContextNotice(t) {
125
- const h = t.hostContext;
126
- if (h === undefined)
127
- return;
128
- const checks = (items) => Array.isArray(items) && items.every(item => item && typeof item.id === 'string' && typeof item.status === 'string');
129
- if (!h || (h.enforcement !== 'test' && h.enforcement !== 'production') || (h.checkExitCode !== 0 && h.checkExitCode !== 1) || !checks(h.failedChecks) || !checks(h.unverifiedChecks))
130
- throw new NeedError('CONNECT_API_MISMATCH', '主机检查背景无效,不能假定已通过生产检查', 'L 提供的有效 hostContext');
131
- if (h.enforcement !== 'test')
132
- return;
133
- return TEST_HOST_NOTICE;
134
121
  }
135
122
  export function identity(t) { return `${t.username}@${t.host}:${t.port}`; }
136
123
  /** Reject draft.3 and legacy runtime rather than inventing workspace bindings. */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-workbench/remote-agent",
3
- "version": "0.8.23",
3
+ "version": "0.8.24",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",