dsh-github-copilot 0.4.0-alpha.21 → 0.4.0-alpha.23

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/lib/remote.js CHANGED
@@ -32,7 +32,7 @@ const DualModelCreateSchema = z.object({
32
32
  expectedRevision: revision
33
33
  }).strict();
34
34
  const DualModelCreateResultSchema = z.object({ sessionId: id }).strict();
35
- const contribution$1 = {
35
+ const contribution$2 = {
36
36
  package: "dsh-github-copilot",
37
37
  descriptors: [
38
38
  {
@@ -94,6 +94,25 @@ const contribution$1 = {
94
94
  }
95
95
  ]
96
96
  };
97
+ const contribution$1 = {
98
+ package: "dsh-github-copilot",
99
+ descriptors: [{
100
+ id: "dsh-github-copilot:githubCopilotSearchRouting.providers",
101
+ namespace: "githubCopilotSearchRouting",
102
+ service: "githubCopilotSearchRouting",
103
+ method: "providers",
104
+ invocation: { kind: "direct" },
105
+ parameters: [],
106
+ result: {
107
+ mode: "strict",
108
+ typeSymbol: "dsh-github-copilot#SearchProviderCatalog",
109
+ schema: z.object({
110
+ supported: z.boolean(),
111
+ providers: z.array(z.object({ id: z.string().min(1).max(512) }).strict()).max(512)
112
+ }).strict()
113
+ }
114
+ }]
115
+ };
97
116
  //#endregion
98
117
  //#region lib/types/remote.js
99
118
  /**
@@ -255,6 +274,7 @@ const contribution = {
255
274
  schema: GitHubCopilotMigrationStatusSchema
256
275
  }
257
276
  },
277
+ ...contribution$2.descriptors,
258
278
  ...contribution$1.descriptors
259
279
  ]
260
280
  };
package/lib/routed-web.js CHANGED
@@ -16,6 +16,7 @@ var CopilotRoutedWeb = class extends WebRuntime {
16
16
  mirroredSearchProviders = /* @__PURE__ */ new Map();
17
17
  constructor(ctx, config = {}) {
18
18
  super(ctx, config);
19
+ ctx.provide("githubCopilotSearchCatalog", { list: () => [...this.mirroredSearchProviders.keys()] });
19
20
  this.bounded = new WebRuntime(ctx.isolate("web"), { searchProvider: "copilot-session-search" });
20
21
  this.bounded.registerSearchProvider({
21
22
  id: "copilot-session-search",
@@ -23,7 +24,7 @@ var CopilotRoutedWeb = class extends WebRuntime {
23
24
  search: (request, signal) => {
24
25
  const router = ctx.get("githubCopilotSearchRouter");
25
26
  if (router === void 0) throw new WebError("Copilot session search routing is not ready", "WEB_PROVIDER_UNAVAILABLE");
26
- return router.search(request, signal, (query, querySignal) => ctx.githubCopilotOriginalWeb.search(query, querySignal), (providerId, query, querySignal) => this.searchWithProvider(providerId, query, querySignal));
27
+ return router.search(request, signal, (query, querySignal) => ctx.githubCopilotOriginalWeb.search(query, querySignal), (providerId, query, querySignal) => this.searchWithProvider(providerId, query, querySignal), (providerId) => this.captureSearchProvider(providerId));
27
28
  }
28
29
  });
29
30
  ctx.effect(() => async () => {
@@ -36,19 +37,57 @@ var CopilotRoutedWeb = class extends WebRuntime {
36
37
  return new WebError("Copilot search service was disposed", "WEB_PROVIDER_UNAVAILABLE");
37
38
  }
38
39
  searchWithProvider(providerId, request, signal) {
39
- const provider = this.mirroredSearchProviders.get(providerId);
40
+ const provider = this.captureSearchProvider(providerId);
40
41
  if (provider === void 0) return Promise.reject(new WebError(`configured web provider "${providerId}" is not registered`, "WEB_PROVIDER_CONFIGURED_MISSING"));
41
- if (!provider.available()) return Promise.reject(new WebError(`configured web provider "${providerId}" is registered but unavailable`, "WEB_PROVIDER_CONFIGURED_UNAVAILABLE"));
42
42
  return provider.search(request, signal);
43
43
  }
44
+ captureSearchProvider(providerId) {
45
+ const entry = this.mirroredSearchProviders.get(providerId);
46
+ if (entry === void 0) return void 0;
47
+ const signal = AbortSignal.any([this.lifetime.signal, entry.cancellation.signal]);
48
+ const current = () => !signal.aborted && this.mirroredSearchProviders.get(providerId) === entry;
49
+ const available = entry.provider.available.bind(entry.provider);
50
+ const search = entry.provider.search.bind(entry.provider);
51
+ return {
52
+ id: providerId,
53
+ signal,
54
+ current,
55
+ owns: (provider) => current() && entry.provider === provider,
56
+ search: async (request, callerSignal) => {
57
+ const boundSignal = AbortSignal.any([signal, ...callerSignal === void 0 ? [] : [callerSignal]]);
58
+ const assertCurrent = () => {
59
+ if (boundSignal.aborted) throw new WebError("web search aborted", "WEB_ABORTED");
60
+ if (!current()) throw new WebError("web search provider registration invalidated", "WEB_PROVIDER_UNAVAILABLE");
61
+ };
62
+ assertCurrent();
63
+ try {
64
+ const usable = available();
65
+ assertCurrent();
66
+ if (!usable) throw new WebError(`configured web provider "${providerId}" is registered but unavailable`, "WEB_PROVIDER_CONFIGURED_UNAVAILABLE");
67
+ const result = await search(request, boundSignal);
68
+ assertCurrent();
69
+ return result;
70
+ } catch (error) {
71
+ assertCurrent();
72
+ throw error;
73
+ }
74
+ }
75
+ };
76
+ }
44
77
  registerSearchProvider(provider) {
45
78
  if (this.lifetime.signal.aborted) throw this.disposedError();
46
79
  const disposeOriginal = this.ctx.githubCopilotOriginalWeb.registerSearchProvider(provider);
47
80
  const providers = this.mirroredSearchProviders;
81
+ const providerId = provider.id;
82
+ const entry = {
83
+ provider,
84
+ cancellation: new AbortController()
85
+ };
48
86
  const disposeMirror = this.ctx.effect(function* () {
49
- providers.set(provider.id, provider);
87
+ providers.set(providerId, entry);
50
88
  yield () => {
51
- if (providers.get(provider.id) === provider) providers.delete(provider.id);
89
+ entry.cancellation.abort();
90
+ if (providers.get(providerId) === entry) providers.delete(providerId);
52
91
  };
53
92
  }, "github-copilot.search-provider-mirror");
54
93
  return () => {
@@ -1,4 +1,5 @@
1
- import { Context, Service } from '@deepseek-ai/cordis';
1
+ import { Context } from '@deepseek-ai/cordis';
2
+ import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
2
3
  import { z as json } from 'zod';
3
4
  import type { DualModelView, DualModelSaveRequest, DualModelCreateRequest, DualModelCreateResult } from './dual-model-types.ts';
4
5
  export declare const DUAL_MODEL_NAMESPACE = "github-copilot-dual-model";
@@ -91,7 +92,7 @@ declare module '@deepseek-ai/cordis' {
91
92
  }
92
93
  }
93
94
  /** Always mountable; missing optional APIs produce a safe unsupported view. */
94
- export default class GitHubCopilotDualModel extends Service {
95
+ export default class GitHubCopilotDualModel extends TypertRemoteService {
95
96
  private readonly owner;
96
97
  private readonly lifetime;
97
98
  private readonly creates;
@@ -5,9 +5,20 @@ import type { WebRuntimeConfig, WebSearchRequest, WebSearchResult, WebSearchProv
5
5
  export type NativeSearch = (request: WebSearchRequest, signal?: AbortSignal) => Promise<WebSearchResult>;
6
6
  /** Exact-id dispatch over providers registered through the routed facade. */
7
7
  export type ProviderSearch = (providerId: string, request: WebSearchRequest, signal?: AbortSignal) => Promise<WebSearchResult>;
8
+ /** Captured facade registration; no provider implementation object crosses the Client boundary. */
9
+ export interface CapturedSearchProvider {
10
+ readonly id: string;
11
+ readonly signal: AbortSignal;
12
+ current(): boolean;
13
+ /** Identity proof for a router-owned provider, never an inference from its id. */
14
+ owns(provider: WebSearchProvider): boolean;
15
+ search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult>;
16
+ }
17
+ /** Resolve one registered id synchronously before the routing operation starts awaiting. */
18
+ export type CaptureSearchProvider = (providerId: string) => CapturedSearchProvider | undefined;
8
19
  /** Host-owned router; credentials and provider implementation objects stay inside the facade. */
9
20
  export interface GitHubCopilotSearchRouter {
10
- search(request: WebSearchRequest, signal: AbortSignal | undefined, delegate: NativeSearch, selectProvider?: ProviderSearch): Promise<WebSearchResult>;
21
+ search(request: WebSearchRequest, signal: AbortSignal | undefined, delegate: NativeSearch, selectProvider?: ProviderSearch, captureSearchProvider?: CaptureSearchProvider): Promise<WebSearchResult>;
11
22
  }
12
23
  declare module '@deepseek-ai/cordis' {
13
24
  interface Context {
@@ -30,6 +41,7 @@ export default class CopilotRoutedWeb extends WebRuntime {
30
41
  constructor(ctx: Context, config?: WebRuntimeConfig);
31
42
  private disposedError;
32
43
  private searchWithProvider;
44
+ private captureSearchProvider;
33
45
  registerSearchProvider(provider: WebSearchProvider): () => void;
34
46
  registerFetchProvider(provider: WebFetchProvider): () => void;
35
47
  fetch(request: WebFetchRequest, signal?: AbortSignal): Promise<WebFetchResult>;
@@ -0,0 +1,19 @@
1
+ /** Read-only search catalog bridge; no credentials, availability probes or writes. */
2
+ import { Context } from '@deepseek-ai/cordis';
3
+ import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
4
+ import type { SearchProviderCatalog } from './search-routing-remote.ts';
5
+ export interface SearchProviderDirectory {
6
+ /** Fresh IDs from facade-owned registrations, not a process-wide registry. */
7
+ list(): readonly string[];
8
+ }
9
+ declare module '@deepseek-ai/cordis' {
10
+ interface Context {
11
+ githubCopilotSearchCatalog: SearchProviderDirectory;
12
+ githubCopilotSearchRouting: SearchRoutingController;
13
+ }
14
+ }
15
+ export default class SearchRoutingController extends TypertRemoteService {
16
+ constructor(ctx: Context);
17
+ providers(): SearchProviderCatalog;
18
+ }
19
+ //# sourceMappingURL=search-routing-host.d.ts.map
@@ -0,0 +1,18 @@
1
+ /** Shared Client-safe settings shape; provider credentials and models remain provider-owned. */
2
+ export interface WebSearchRoutingConfig {
3
+ /** Auto follows the initiating Chat provider; a concrete id pins the primary, and none disables search. */
4
+ searchProvider?: string;
5
+ /** Legacy primary selection; used only when searchProvider has not been explicitly saved. */
6
+ searchMode?: 'auto' | 'fixed';
7
+ /** Final fallback provider id, or none; legacy fixed mode also uses this id as its primary. */
8
+ defaultSearchProvider?: string;
9
+ }
10
+ /** Operation-local normalized policy; reading legacy settings never migrates them on disk. */
11
+ export interface NormalizedWebSearchRouting {
12
+ readonly primaryProvider: string;
13
+ readonly defaultProvider: string;
14
+ readonly legacy: boolean;
15
+ }
16
+ /** Resolve old and new settings without guessing registered providers or dropping unknown ids. */
17
+ export declare function normalizeWebSearchRouting(config: WebSearchRoutingConfig): NormalizedWebSearchRouting;
18
+ //# sourceMappingURL=search-routing-policy.d.ts.map
@@ -0,0 +1,20 @@
1
+ /** Client-safe catalog of search registrations observed by the routed facade. */
2
+ import type { RemoteResult, TypertRemoteContribution } from '@deepseek-ai/dsh-typert-protocol';
3
+ import { z } from 'zod';
4
+ export declare const SearchProviderCatalogSchema: z.ZodObject<{
5
+ supported: z.ZodBoolean;
6
+ providers: z.ZodArray<z.ZodObject<{
7
+ id: z.ZodString;
8
+ }, z.core.$strict>>;
9
+ }, z.core.$strict>;
10
+ export type SearchProviderCatalog = z.infer<typeof SearchProviderCatalogSchema>;
11
+ declare module '@deepseek-ai/dsh-typert-protocol' {
12
+ interface TypertRemoteNamespaceMap {
13
+ githubCopilotSearchRouting: {
14
+ providers(): Promise<RemoteResult<SearchProviderCatalog>>;
15
+ };
16
+ }
17
+ }
18
+ declare const contribution: TypertRemoteContribution;
19
+ export default contribution;
20
+ //# sourceMappingURL=search-routing-remote.d.ts.map
@@ -0,0 +1,22 @@
1
+ import type { WebSearchRequest, WebSearchResult } from '@deepseek-ai/dsh-web';
2
+ /** An already selected, operation-owned search entry; availability remains its owner's responsibility. */
3
+ export interface SearchToolProvider {
4
+ readonly id: string;
5
+ search(request: WebSearchRequest, signal?: AbortSignal): Promise<WebSearchResult>;
6
+ }
7
+ /** Captured policy for one primary attempt and at most one distinct final fallback. */
8
+ export interface SearchToolRoutingDependencies {
9
+ readonly primary?: SearchToolProvider | undefined;
10
+ readonly fallback?: SearchToolProvider | undefined;
11
+ /** False, or a thrown error, revokes this operation without permitting fallback. */
12
+ readonly canContinue: () => boolean;
13
+ /** Legacy failure-spending control; does not prevent fallback when no primary was resolved. */
14
+ readonly allowFailureFallback?: boolean;
15
+ }
16
+ /**
17
+ * Execute a captured primary and optional final fallback without registry or credential access.
18
+ * The caller resolves Auto, handles disabled policy, proves registrations and supplies lifetime guards.
19
+ * Generic providers must honor the signal; this helper cannot inspect their internal auth/HTTP boundary.
20
+ */
21
+ export declare function routeSearchTools(request: WebSearchRequest, signal: AbortSignal | undefined, deps: SearchToolRoutingDependencies): Promise<WebSearchResult>;
22
+ //# sourceMappingURL=search-tool-routing.d.ts.map
@@ -3,8 +3,9 @@ import type { ReactElement } from 'react';
3
3
  interface SearchRoutingCardProps {
4
4
  readonly settings: ClientContext['remote']['settings'];
5
5
  readonly copilot: ClientContext['remote']['githubCopilot'];
6
+ readonly routing: ClientContext['remote']['githubCopilotSearchRouting'];
6
7
  }
7
- /** Models-page card for plugin-owned cross-provider search routing. */
8
+ /** Provider-level primary and final fallback; model choice stays with each provider. */
8
9
  export declare function WebSearchRoutingCard(props: SearchRoutingCardProps): ReactElement;
9
10
  export {};
10
11
  //# sourceMappingURL=web-search-routing-card.d.ts.map
@@ -1,16 +1,12 @@
1
1
  import z from '@deepseek-ai/schemastery';
2
2
  import type { SettingsNamespace } from '@deepseek-ai/dsh-settings';
3
+ import type { WebSearchRoutingConfig } from './search-routing-policy.ts';
4
+ export { normalizeWebSearchRouting } from './search-routing-policy.ts';
5
+ export type { WebSearchRoutingConfig, NormalizedWebSearchRouting } from './search-routing-policy.ts';
3
6
  /** Plugin-owned settings namespace for cross-provider web-search routing. */
4
7
  export declare const WEB_SEARCH_ROUTING_SETTINGS_NAMESPACE: SettingsNamespace;
5
8
  /** Sentinel that disables the default/fixed search backend. */
6
9
  export declare const NO_DEFAULT_SEARCH_PROVIDER = "none";
7
- /** Cross-provider policy applied by this plugin's routed web facade. */
8
- export interface WebSearchRoutingConfig {
9
- /** Auto prefers the initiating model's native search; fixed always uses the configured provider. */
10
- searchMode?: 'auto' | 'fixed';
11
- /** Registered search-provider id used by fixed mode and as auto mode's fallback. */
12
- defaultSearchProvider?: string;
13
- }
14
10
  /** User-facing routing settings; provider-specific credentials and models remain provider-owned. */
15
11
  export declare const WebSearchRoutingConfigSchema: z<WebSearchRoutingConfig>;
16
12
  //# sourceMappingURL=web-search-routing-config.d.ts.map
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "dsh-github-copilot",
3
3
  "description": "DSH companion for GitHub Copilot sign-in, account-aware model profiles, tool compatibility, and provider-hosted search.",
4
- "version": "0.4.0-alpha.21",
4
+ "version": "0.4.0-alpha.23",
5
5
  "publishConfig": {
6
6
  "access": "public",
7
7
  "registry": "https://registry.npmjs.org/",
@@ -94,8 +94,7 @@
94
94
  "@deepseek-ai/dsh-typert-protocol": "0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
95
95
  "@deepseek-ai/dsh-web": "0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
96
96
  "@deepseek-ai/dsh-web-search-deepseek": "0.1.1-rc.2 || 0.1.2-rc.1 || 0.1.3-alpha.1 || 0.1.5-alpha.1 || 0.1.5-alpha.2 || 0.1.5-rc.1 || 0.1.5-rc.2 || 0.1.6-alpha.1",
97
- "@deepseek-ai/schemastery": "^3.18.2",
98
- "react": "^18.2.0"
97
+ "@deepseek-ai/schemastery": "^3.18.2"
99
98
  },
100
99
  "peerDependenciesMeta": {
101
100
  "@deepseek-ai/dsh-web-search-deepseek": {
@@ -172,6 +171,9 @@
172
171
  "patch": "./cordis.patch.yml"
173
172
  },
174
173
  "client": {
174
+ "external": [
175
+ "react"
176
+ ],
175
177
  "inject": [
176
178
  "@deepseek-ai/dsh-api-remotes",
177
179
  "@deepseek-ai/dsh-client-ui-settings-models"