@khorsheed/dsh-local-agent 0.2.0-rc.1 → 0.2.0
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/CHANGELOG.md +31 -0
- package/README.en.md +23 -164
- package/README.i18n.yaml +2 -2
- package/README.md +23 -164
- package/lib/client.js +23707 -4768
- package/lib/index.js +827 -62
- package/lib/member-bridge.js +195 -25
- package/lib/tool-factory.js +52 -19
- package/lib/typert.host.js +1440 -353
- package/lib/typert.remote-client.d.ts +43 -3
- package/lib/typert.remote-client.js +973 -335
- package/lib/types/client/FamilyCard.d.ts +37 -0
- package/lib/types/client/FamilyCard.js +55 -0
- package/lib/types/client/HarnessModelPicker.d.ts +21 -1
- package/lib/types/client/HarnessModelPicker.js +31 -3
- package/lib/types/client/MemberLiveNode.js +38 -4
- package/lib/types/client/ModelListSection.d.ts +49 -0
- package/lib/types/client/ModelListSection.js +132 -0
- package/lib/types/client/ProviderAuthBlock.d.ts +10 -2
- package/lib/types/client/ProviderAuthBlock.js +13 -6
- package/lib/types/client/auth-status.d.ts +6 -0
- package/lib/types/client/auth-status.js +8 -0
- package/lib/types/client/harness-cards.d.ts +72 -0
- package/lib/types/client/harness-cards.js +57 -0
- package/lib/types/client/icons.d.ts +2 -1
- package/lib/types/client/icons.js +1 -0
- package/lib/types/client/index.d.ts +32 -7
- package/lib/types/client/index.js +66 -9
- package/lib/types/client/locales.d.ts +25 -1
- package/lib/types/client/locales.js +50 -2
- package/lib/types/client/model-directory-scope.d.ts +14 -0
- package/lib/types/client/model-directory-scope.js +20 -0
- package/lib/types/gateway.d.ts +49 -1
- package/lib/types/gateway.js +89 -0
- package/lib/types/index.d.ts +91 -38
- package/lib/types/index.js +190 -58
- package/lib/types/live-stream.d.ts +11 -0
- package/lib/types/live-stream.js +26 -0
- package/lib/types/member-bridge.d.ts +11 -1
- package/lib/types/member-bridge.js +81 -13
- package/lib/types/member-channel.d.ts +44 -1
- package/lib/types/member-channel.js +65 -2
- package/lib/types/member-controls.d.ts +8 -0
- package/lib/types/member-controls.js +15 -2
- package/lib/types/mode-skills.d.ts +18 -0
- package/lib/types/mode-skills.js +56 -0
- package/lib/types/model-list.d.ts +55 -0
- package/lib/types/model-list.js +101 -0
- package/lib/types/preset-tool-host.d.ts +70 -0
- package/lib/types/preset-tool-host.js +210 -0
- package/lib/types/tool-factory.d.ts +9 -3
- package/lib/types/tool-factory.js +55 -18
- package/lib/types/types.d.ts +62 -5
- package/package.json +27 -23
- package/lib/invariant.js +0 -85
- package/lib/types/invariant.d.ts +0 -16
- package/lib/types/invariant.js +0 -105
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The harness-card registry behind the「本机 Agent 委派」family card: each
|
|
3
|
+
* delegation companion's client registers one section (its settings card
|
|
4
|
+
* body) through the localAgentUi service's `registerHarnessCard`, and the
|
|
5
|
+
* core's single `plugins.item` entry renders every registered section sorted
|
|
6
|
+
* by order. Sections come from THIS registry, never the gateway roster — a
|
|
7
|
+
* registered harness absent host-side still renders, its body degrading
|
|
8
|
+
* exactly like the retired standalone card did.
|
|
9
|
+
*
|
|
10
|
+
* The registry lives on the cordis service (not a module export) because every
|
|
11
|
+
* plugin's client bundle inlines its own copy of the core's sources: module
|
|
12
|
+
* identity is per bundle, the service is the one shared instance.
|
|
13
|
+
* @module @khorsheed/dsh-local-agent/client — harness card registry
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* In-memory registry with the useSyncExternalStore face the family card
|
|
17
|
+
* subscribes through: a version counter as the snapshot (mutations bump it)
|
|
18
|
+
* and a cached sorted list readers re-read after a bump.
|
|
19
|
+
*/
|
|
20
|
+
export class HarnessCardRegistry {
|
|
21
|
+
entries = new Map();
|
|
22
|
+
listeners = new Set();
|
|
23
|
+
version = 0;
|
|
24
|
+
sorted = [];
|
|
25
|
+
/**
|
|
26
|
+
* Register one harness's section; re-registering the same name replaces the
|
|
27
|
+
* entry. The returned disposer removes only the entry it registered (a stale
|
|
28
|
+
* disposer never evicts a newer registration of the same name).
|
|
29
|
+
* @param entry - the section registration.
|
|
30
|
+
* @returns the unregister.
|
|
31
|
+
*/
|
|
32
|
+
register = (entry) => {
|
|
33
|
+
this.entries.set(entry.name, entry);
|
|
34
|
+
this.bump();
|
|
35
|
+
return () => {
|
|
36
|
+
if (this.entries.get(entry.name) !== entry)
|
|
37
|
+
return;
|
|
38
|
+
this.entries.delete(entry.name);
|
|
39
|
+
this.bump();
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
/** The registered sections in display order (order, then name). */
|
|
43
|
+
cards = () => this.sorted;
|
|
44
|
+
/** The mutation counter — the useSyncExternalStore snapshot. */
|
|
45
|
+
snapshotVersion = () => this.version;
|
|
46
|
+
/** Subscribe a listener fired after every mutation; returns the unsubscribe. */
|
|
47
|
+
subscribe = (listener) => {
|
|
48
|
+
this.listeners.add(listener);
|
|
49
|
+
return () => { this.listeners.delete(listener); };
|
|
50
|
+
};
|
|
51
|
+
bump() {
|
|
52
|
+
this.version += 1;
|
|
53
|
+
this.sorted = [...this.entries.values()].sort((a, b) => a.order - b.order || (a.name < b.name ? -1 : a.name > b.name ? 1 : 0));
|
|
54
|
+
for (const listener of [...this.listeners])
|
|
55
|
+
listener();
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Generated by scripts/sync-icon-artwork.mts from @deepseek-ai/dsh-client-ui-primitives
|
|
3
|
-
* (v0.1
|
|
3
|
+
* (v0.2.1-rc.1, harness 1600d8a1e1) — do not edit by hand. The 0.1.5 and rc.1 host lines
|
|
4
4
|
* share no icon export name, so the rc.1 artwork is inlined here: pure SVG,
|
|
5
5
|
* no host runtime identity, identical on every line. Re-run the generator
|
|
6
6
|
* after adding an icon import or bumping the harness checkout.
|
|
@@ -18,5 +18,6 @@ export declare const IconCheckOutlineMedium: ({ size, className }: IconProps) =>
|
|
|
18
18
|
export declare const IconChevronDownOutlineMedium: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
19
19
|
export declare const IconChevronUpOutlineMedium: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
20
20
|
export declare const IconQueueOutlineMedium: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
21
|
+
export declare const IconThinkOutlineRegular: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
21
22
|
export declare const IconTrashOutlineMedium: ({ size, className }: IconProps) => import("react").JSX.Element;
|
|
22
23
|
//# sourceMappingURL=icons.d.ts.map
|
|
@@ -3,4 +3,5 @@ export const IconCheckOutlineMedium = ({ size = 16, className }) => (_jsx("svg",
|
|
|
3
3
|
export const IconChevronDownOutlineMedium = ({ size = 14, className }) => (_jsx("svg", { width: size, height: size, className: className, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", strokeWidth: 1.3, children: _jsx("path", { d: "M4 6L7.29289 9.29289C7.68342 9.68342 8.31658 9.68342 8.70711 9.29289L12 6", stroke: "currentColor" }) }));
|
|
4
4
|
export const IconChevronUpOutlineMedium = ({ size = 14, className }) => (_jsx("svg", { width: size, height: size, className: className, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", strokeWidth: 1.3, children: _jsx("path", { d: "M12 10L8.70711 6.70711C8.31658 6.31658 7.68342 6.31658 7.29289 6.70711L4 10", stroke: "currentColor" }) }));
|
|
5
5
|
export const IconQueueOutlineMedium = ({ size = 14, className }) => (_jsxs("svg", { width: size, height: size, className: className, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", strokeWidth: 1.3, children: [_jsx("path", { d: "M5 6.75H11", stroke: "currentColor" }), _jsx("path", { d: "M5 9H8", stroke: "currentColor" }), _jsx("path", { d: "M2.37067 11.2497C1.5872 9.89252 1.32042 8.29798 1.61945 6.7597C1.91847 5.22141 2.76317 3.84293 3.99801 2.87809C5.23285 1.91325 6.7747 1.427 8.33964 1.50888C9.90458 1.59076 11.3873 2.23526 12.5147 3.32369C13.6422 4.41232 14.3384 5.8717 14.4751 7.43304C14.6118 8.99438 14.1797 10.5525 13.2585 11.8205C12.3372 13.0885 10.9889 13.9809 9.4617 14.3334C8.18666 14.6277 6.8587 14.529 5.64964 14.0601C5.17095 13.8745 4.76937 13.4929 4.26509 13.3963C3.67389 13.2832 2.95232 13.5595 2.0377 14.3334", stroke: "currentColor" })] }));
|
|
6
|
+
export const IconThinkOutlineRegular = ({ size = 16, className }) => (_jsxs("svg", { width: size, height: size, className: className, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", strokeWidth: 1, children: [_jsx("path", { d: "M10.2854 5.71481C12.9673 8.39663 14.1182 11.5938 12.8562 12.8559C11.5942 14.1179 8.39706 12.9669 5.71518 10.2851C3.03333 7.60323 1.88236 4.40608 3.14441 3.14403C4.40644 1.882 7.6036 3.03297 10.2854 5.71481Z", stroke: "currentColor" }), _jsx("path", { d: "M10.2854 10.2851C7.6036 12.9669 4.40644 14.1179 3.14441 12.8559C1.88236 11.5938 3.03333 8.39663 5.71518 5.71481C8.39706 3.03297 11.5942 1.882 12.8562 3.14403C14.1182 4.40608 12.9673 7.60323 10.2854 10.2851Z", stroke: "currentColor" }), _jsx("path", { d: "M8.86291 8.0002C8.86291 8.47549 8.47762 8.86087 8.00224 8.86087C7.52694 8.86087 7.1416 8.47549 7.1416 8.0002C7.1416 7.52485 7.52694 7.13953 8.00224 7.13953C8.47762 7.13953 8.86291 7.52485 8.86291 8.0002Z", fill: "currentColor" })] }));
|
|
6
7
|
export const IconTrashOutlineMedium = ({ size = 16, className }) => (_jsxs("svg", { width: size, height: size, className: className, viewBox: "0 0 16 16", fill: "none", xmlns: "http://www.w3.org/2000/svg", "aria-hidden": "true", strokeWidth: 1.3, children: [_jsx("path", { d: "M1.28149 3.88831H14.7187", stroke: "currentColor" }), _jsx("path", { d: "M5.41602 3.88833V2.47962C5.41602 2.29282 5.52492 2.11366 5.71876 1.98157C5.9126 1.84948 6.17551 1.77527 6.44964 1.77527H9.55053C9.82466 1.77527 10.0876 1.84948 10.2814 1.98157C10.4753 2.11366 10.5842 2.29282 10.5842 2.47962V3.88833", stroke: "currentColor" }), _jsx("path", { d: "M2.57349 3.88831L3.19366 13.2943C3.21937 13.5502 3.33952 13.7872 3.53065 13.9593C3.72178 14.1313 3.97016 14.2259 4.22729 14.2246H11.7728C12.0299 14.2259 12.2783 14.1313 12.4694 13.9593C12.6605 13.7872 12.7807 13.5502 12.8064 13.2943L13.4266 3.88831", stroke: "currentColor" }), _jsx("path", { d: "M6.44946 6.98926V11.1238", stroke: "currentColor" }), _jsx("path", { d: "M9.55054 6.98926V11.1238", stroke: "currentColor" })] }));
|
|
@@ -1,12 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Local-agent records plugin, browser half: the member composer for delegated
|
|
3
|
-
* CLI sessions,
|
|
4
|
-
* packages compose (ProviderAuthBlock, the auth-status bus, AuthStatusDot)
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* (
|
|
9
|
-
*
|
|
3
|
+
* CLI sessions, the shared settings-card building blocks the provider
|
|
4
|
+
* packages compose (ProviderAuthBlock, the auth-status bus, AuthStatusDot),
|
|
5
|
+
* and the「本机 Agent 委派」family card — ONE `plugins.item` entry on the
|
|
6
|
+
* Plugins page that renders each harness's settings section, registered by
|
|
7
|
+
* the provider packages through the localAgentUi service's
|
|
8
|
+
* `registerHarnessCard` (a provider on a core predating the family card
|
|
9
|
+
* keeps its own standalone card; this core alone shows the card with an
|
|
10
|
+
* empty state). The card registers with the core client bundle itself —
|
|
11
|
+
* no served-namespace gate: the whileServed convention only lists
|
|
12
|
+
* namespaces whose Config has a volatile field, and this core's Config
|
|
13
|
+
* has none, so its namespace never serves (the companions' sections keep
|
|
14
|
+
* their own namespace gates).
|
|
15
|
+
* Roster and status ride the read-only local-agent Remote
|
|
10
16
|
* channel (no session events); only the user-initiated login/logout/preset
|
|
11
17
|
* commands go through the commands Remote, whose visible command node is the
|
|
12
18
|
* expected feedback. Delegation records live with the shared subagent
|
|
@@ -16,16 +22,23 @@
|
|
|
16
22
|
*/
|
|
17
23
|
import { type ReactNode } from 'react';
|
|
18
24
|
import { type HarnessModelPickerProps } from './HarnessModelPicker.tsx';
|
|
25
|
+
import { type HarnessCardRegistration } from './harness-cards.ts';
|
|
19
26
|
import type { Context } from '@deepseek-ai/cordis';
|
|
20
27
|
import type { TypertRemoteNamespaceMap } from '@deepseek-ai/dsh-typert-protocol';
|
|
21
28
|
import { type LocalAgentKey } from './locales.ts';
|
|
22
29
|
export type { LocalAgentHarnessView } from './LocalAgentRecordsAction.tsx';
|
|
23
30
|
export { ProviderAuthBlock } from './ProviderAuthBlock.tsx';
|
|
24
31
|
export type { ProviderAuthBlockProps, ProviderAuthInjected } from './ProviderAuthBlock.tsx';
|
|
32
|
+
export { ModelListSection } from './ModelListSection.tsx';
|
|
33
|
+
export type { ModelListSectionListFace, ModelListSectionProps } from './ModelListSection.tsx';
|
|
25
34
|
export { AuthStatusDot } from './AuthStatusDot.tsx';
|
|
26
35
|
export type { AuthStatusDotProps } from './AuthStatusDot.tsx';
|
|
27
36
|
export { publishAuthStatus, useHarnessAuthStatus, resetAuthStatuses, readAuthStatus } from './auth-status.ts';
|
|
28
37
|
export type { HarnessAuthStatusKind } from './auth-status.ts';
|
|
38
|
+
export { HarnessCardRegistry } from './harness-cards.ts';
|
|
39
|
+
export type { HarnessCardRegistration, HarnessCardRenderProps } from './harness-cards.ts';
|
|
40
|
+
export { LocalAgentFamilyCard } from './FamilyCard.tsx';
|
|
41
|
+
export type { FamilyCardInjected, LocalAgentFamilyCardProps } from './FamilyCard.tsx';
|
|
29
42
|
export type { MemberComposerInjected, MemberComposerMatch, MemberComposerProps } from './MemberComposer.tsx';
|
|
30
43
|
export { selectCliMember } from './MemberComposer.tsx';
|
|
31
44
|
/** The mounted local-agent gateway namespace, read back from the global store. */
|
|
@@ -37,6 +50,18 @@ export interface LocalAgentUi {
|
|
|
37
50
|
renderMemberInbox(childSessionId: string): ReactNode;
|
|
38
51
|
renderHarnessModelPicker(name: string, props: HarnessModelPickerInput): ReactNode;
|
|
39
52
|
renderMemberConfiguration(childSessionId: string): ReactNode;
|
|
53
|
+
/**
|
|
54
|
+
* Register one harness's section in the family card; returns the
|
|
55
|
+
* unregister. Optional on the TYPE because a companion may run against a
|
|
56
|
+
* core that predates the family card: companions probe
|
|
57
|
+
* `typeof ui.registerHarnessCard === 'function'` and keep their standalone
|
|
58
|
+
* plugins.item card when it is absent. This core always provides it.
|
|
59
|
+
*/
|
|
60
|
+
registerHarnessCard?(entry: HarnessCardRegistration): () => void;
|
|
61
|
+
/** The registered harness sections in display order (the family card's reading). */
|
|
62
|
+
harnessCards?(): readonly HarnessCardRegistration[];
|
|
63
|
+
/** The registry's useSyncExternalStore subscribe. */
|
|
64
|
+
subscribeHarnessCards?(listener: () => void): () => void;
|
|
40
65
|
}
|
|
41
66
|
declare module '@deepseek-ai/cordis' {
|
|
42
67
|
interface Context {
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { MemberFeeds } from './member-feed.js';
|
|
2
2
|
/**
|
|
3
3
|
* Local-agent records plugin, browser half: the member composer for delegated
|
|
4
|
-
* CLI sessions,
|
|
5
|
-
* packages compose (ProviderAuthBlock, the auth-status bus, AuthStatusDot)
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
* (
|
|
10
|
-
*
|
|
4
|
+
* CLI sessions, the shared settings-card building blocks the provider
|
|
5
|
+
* packages compose (ProviderAuthBlock, the auth-status bus, AuthStatusDot),
|
|
6
|
+
* and the「本机 Agent 委派」family card — ONE `plugins.item` entry on the
|
|
7
|
+
* Plugins page that renders each harness's settings section, registered by
|
|
8
|
+
* the provider packages through the localAgentUi service's
|
|
9
|
+
* `registerHarnessCard` (a provider on a core predating the family card
|
|
10
|
+
* keeps its own standalone card; this core alone shows the card with an
|
|
11
|
+
* empty state). The card registers with the core client bundle itself —
|
|
12
|
+
* no served-namespace gate: the whileServed convention only lists
|
|
13
|
+
* namespaces whose Config has a volatile field, and this core's Config
|
|
14
|
+
* has none, so its namespace never serves (the companions' sections keep
|
|
15
|
+
* their own namespace gates).
|
|
16
|
+
* Roster and status ride the read-only local-agent Remote
|
|
11
17
|
* channel (no session events); only the user-initiated login/logout/preset
|
|
12
18
|
* commands go through the commands Remote, whose visible command node is the
|
|
13
19
|
* expected feedback. Delegation records live with the shared subagent
|
|
@@ -17,6 +23,9 @@ import { MemberFeeds } from './member-feed.js';
|
|
|
17
23
|
*/
|
|
18
24
|
import { createElement } from 'react';
|
|
19
25
|
import { HarnessModelPicker } from './HarnessModelPicker.js';
|
|
26
|
+
import { scopeDirectoryToList } from './model-directory-scope.js';
|
|
27
|
+
import { LocalAgentFamilyCard } from './FamilyCard.js';
|
|
28
|
+
import { HarnessCardRegistry } from './harness-cards.js';
|
|
20
29
|
import { MemberConfiguration } from './MemberConfiguration.js';
|
|
21
30
|
import { MemberConfigurationStores } from './member-configuration.js';
|
|
22
31
|
import localAgentRemote from '@khorsheed/dsh-local-agent/remote';
|
|
@@ -26,8 +35,11 @@ import { memberLiveDefinition } from './live-node.js';
|
|
|
26
35
|
import { MemberLiveNode, MemberLiveOutputView } from './MemberLiveNode.js';
|
|
27
36
|
import { MemberLiveOutputs } from './live-output.js';
|
|
28
37
|
export { ProviderAuthBlock } from './ProviderAuthBlock.js';
|
|
38
|
+
export { ModelListSection } from './ModelListSection.js';
|
|
29
39
|
export { AuthStatusDot } from './AuthStatusDot.js';
|
|
30
40
|
export { publishAuthStatus, useHarnessAuthStatus, resetAuthStatuses, readAuthStatus } from './auth-status.js';
|
|
41
|
+
export { HarnessCardRegistry } from './harness-cards.js';
|
|
42
|
+
export { LocalAgentFamilyCard } from './FamilyCard.js';
|
|
31
43
|
export { selectCliMember } from './MemberComposer.js';
|
|
32
44
|
import { MemberInboxView } from './MemberInboxView.js';
|
|
33
45
|
export { ModelConfigurationFields } from './ModelConfigurationFields.js';
|
|
@@ -76,8 +88,21 @@ export async function apply(ctx) {
|
|
|
76
88
|
let face = directoryFaces.get(name);
|
|
77
89
|
if (face === undefined)
|
|
78
90
|
directoryFaces.set(name, face = {
|
|
79
|
-
read: async (refresh) =>
|
|
80
|
-
|
|
91
|
+
read: async (refresh) => {
|
|
92
|
+
const directory = unwrap(await gateway.modelDirectory(name, undefined, refresh));
|
|
93
|
+
return directory === null ? null : scopeDirectoryToList(directory, unwrap(await gateway.modelList(name)));
|
|
94
|
+
},
|
|
95
|
+
follow: async function* (signal) {
|
|
96
|
+
// The invite picker faces the curated list, not the raw served
|
|
97
|
+
// catalog; re-read the list on each directory revision.
|
|
98
|
+
let list = unwrap(await gateway.modelList(name));
|
|
99
|
+
for await (const directory of gateway.followModelDirectory(name, undefined, signal)) {
|
|
100
|
+
if (signal.aborted)
|
|
101
|
+
return;
|
|
102
|
+
list = unwrap(await gateway.modelList(name));
|
|
103
|
+
yield scopeDirectoryToList(directory, list);
|
|
104
|
+
}
|
|
105
|
+
},
|
|
81
106
|
});
|
|
82
107
|
return face;
|
|
83
108
|
};
|
|
@@ -92,11 +117,20 @@ export async function apply(ctx) {
|
|
|
92
117
|
return face;
|
|
93
118
|
};
|
|
94
119
|
const outputs = new MemberLiveOutputs((id, signal) => feeds.follow(id, 'output', signal));
|
|
120
|
+
// The family card's section registry: companions register through the
|
|
121
|
+
// service below, the plugins.item entry reads it reactively. Service-held,
|
|
122
|
+
// never module-held — each client bundle inlines its own copy of these
|
|
123
|
+
// sources, so only the cordis service is the shared instance.
|
|
124
|
+
const harnessCards = new HarnessCardRegistry();
|
|
125
|
+
const t = ctx.locale.bind(NS);
|
|
95
126
|
const configurationUi = {
|
|
96
127
|
renderMemberOutput: (id, startedAt) => createElement(MemberLiveOutputView, { key: `${id}:${startedAt}`, sessionId: id, startedAt, outputs, t: ctx.locale.bind(NS) }),
|
|
97
128
|
renderMemberInbox: id => createElement(MemberInboxView, { key: id, face: inboxFace(id), t: ctx.locale.bind(NS) }),
|
|
98
129
|
renderHarnessModelPicker: (name, props) => createElement(HarnessModelPicker, { ...props, key: name, face: directoryFace(name), t: ctx.locale.bind(NS) }),
|
|
99
130
|
renderMemberConfiguration: id => createElement(MemberConfiguration, { key: id, store: configurations.get(id), diagnostics: outputs.diagnostics, t: ctx.locale.bind(NS) }),
|
|
131
|
+
registerHarnessCard: entry => harnessCards.register(entry),
|
|
132
|
+
harnessCards: () => harnessCards.cards(),
|
|
133
|
+
subscribeHarnessCards: listener => harnessCards.subscribe(listener),
|
|
100
134
|
};
|
|
101
135
|
ctx.provide('localAgentUi', configurationUi);
|
|
102
136
|
ctx.inject(['uiConversation'], lctx => { lctx.uiConversation.events.register(memberLiveDefinition); });
|
|
@@ -128,6 +162,29 @@ export async function apply(ctx) {
|
|
|
128
162
|
setMemberModel: (childSessionId, model) => gateway.setMemberModel(childSessionId, model).then(result => (result.ok ? result.value : undefined)),
|
|
129
163
|
}),
|
|
130
164
|
}, MemberComposer));
|
|
165
|
+
// The family card: ONE Plugins-page entry rendering every registered
|
|
166
|
+
// harness section. Registered UNCONDITIONALLY, not gated on the core row's
|
|
167
|
+
// served namespace like the companions' retired standalone cards: the
|
|
168
|
+
// whileServed list only carries namespaces whose Config schema has a
|
|
169
|
+
// volatile field, and this core's Config has none — gating on it meant the
|
|
170
|
+
// card never mounted (and the new-core companions had already given up
|
|
171
|
+
// their standalone seats, so no local-agent card rendered at all). The
|
|
172
|
+
// client bundle loads only with the core row in the composition, so the
|
|
173
|
+
// bundle's presence is the gate; a core whose server half failed simply
|
|
174
|
+
// renders the sections' degraded states.
|
|
175
|
+
ctx.slots.inject('plugins.item', () => ctx.slots.register({
|
|
176
|
+
name: 'plugins.item',
|
|
177
|
+
id: 'local-agent',
|
|
178
|
+
// Ahead of the harnesses' retired standalone cards (orders 110-140).
|
|
179
|
+
order: 100,
|
|
180
|
+
label: () => t('family.title'),
|
|
181
|
+
locale: NS,
|
|
182
|
+
inject: () => ({
|
|
183
|
+
harnessCards,
|
|
184
|
+
harnessStatus: name => gateway?.status(name, undefined).then(result => (result.ok ? result.value : undefined))
|
|
185
|
+
?? Promise.resolve(undefined),
|
|
186
|
+
}),
|
|
187
|
+
}, LocalAgentFamilyCard));
|
|
131
188
|
return async () => {
|
|
132
189
|
for (const dispose of disposers.reverse())
|
|
133
190
|
await dispose();
|
|
@@ -24,6 +24,7 @@ export declare const zh: {
|
|
|
24
24
|
readonly "configuration.details": "模型目录详情";
|
|
25
25
|
readonly "configuration.model": "模型";
|
|
26
26
|
readonly "configuration.effort": "推理强度";
|
|
27
|
+
readonly "configuration.effortDefault": "默认";
|
|
27
28
|
readonly "configuration.inherit": "继承成员创建配置";
|
|
28
29
|
readonly "configuration.default": "跟随 harness 默认值";
|
|
29
30
|
readonly "configuration.search": "搜索模型名称或 ID";
|
|
@@ -55,7 +56,6 @@ export declare const zh: {
|
|
|
55
56
|
readonly "configuration.cancelled": "已接收撤销请求,正在恢复配置。";
|
|
56
57
|
readonly "configuration.failed": "配置操作失败,请检查原因后重试。";
|
|
57
58
|
readonly 'stream.thinking': '思考中';
|
|
58
|
-
readonly 'stream.writing': '正在生成';
|
|
59
59
|
readonly 'stream.recovering': '部分记录,等待实时连接';
|
|
60
60
|
readonly 'stream.copy': '复制';
|
|
61
61
|
readonly 'stream.copied': '已复制';
|
|
@@ -87,6 +87,30 @@ export declare const zh: {
|
|
|
87
87
|
readonly 'settings.unsupported': '待支持';
|
|
88
88
|
readonly 'settings.rosterFailed': '无法读取本地 Agent 列表,请重试';
|
|
89
89
|
readonly 'settings.retry': '重试';
|
|
90
|
+
readonly 'family.title': '本机 Agent 委派';
|
|
91
|
+
readonly 'family.description': '本机安装的编码 agent CLI 的委派通道:端点凭据、默认模型与常驻模式';
|
|
92
|
+
readonly 'family.cliMissing': '未检测到 CLI';
|
|
93
|
+
readonly 'family.empty': '还没有已注册的委派通道';
|
|
94
|
+
readonly 'family.expand': '展开';
|
|
95
|
+
readonly 'family.collapse': '收起';
|
|
96
|
+
readonly 'models.title': '可用模型';
|
|
97
|
+
readonly 'models.info.aria': '可用模型说明';
|
|
98
|
+
readonly 'models.info': '列表从上到下是优先级:每轮委派默认使用第一个模型。点「添加模型」从端点当前供应的目录里勾选加入,所以列表里只会有端点真实供应的模型;拖动行调整顺序;留空则跟随原有默认(设置值或 CLI 内置默认)。列表保存在作用域目录(models.json),保存对下一轮委派生效。';
|
|
99
|
+
readonly 'models.empty': '列表为空 —— 跟随原有默认(设置值或 CLI 内置默认)';
|
|
100
|
+
readonly 'models.add': '+ 添加模型';
|
|
101
|
+
readonly 'models.delete': '移除';
|
|
102
|
+
readonly 'models.defaultChip': '默认';
|
|
103
|
+
readonly 'models.orderHint': '拖动行调整顺序,第一个为默认';
|
|
104
|
+
readonly 'models.applied': '已保存,下一轮委派生效;进行中的轮次不受影响';
|
|
105
|
+
readonly 'models.error': '保存失败,请重试';
|
|
106
|
+
readonly 'models.dialog.title': '选择要添加的模型';
|
|
107
|
+
readonly 'models.dialog.hint': '以下是端点当前供应的模型,勾选要添加的模型。';
|
|
108
|
+
readonly 'models.dialog.search': '搜索模型';
|
|
109
|
+
readonly 'models.dialog.selectAll': '全选';
|
|
110
|
+
readonly 'models.dialog.cancel': '取消';
|
|
111
|
+
readonly 'models.dialog.confirm': '添加所选';
|
|
112
|
+
readonly 'models.dialog.loading': '正在加载端点目录…';
|
|
113
|
+
readonly 'models.dialog.empty': '端点目录为空 —— 先保存凭据';
|
|
90
114
|
readonly 'member.checking': '正在确认成员身份…';
|
|
91
115
|
readonly 'member.readonly.title': '一次性子代理记录';
|
|
92
116
|
readonly 'member.readonly.body': '一次性任务不支持后续消息,可在这里查看完整执行记录。';
|
|
@@ -24,6 +24,7 @@ export const zh = {
|
|
|
24
24
|
"configuration.details": "模型目录详情",
|
|
25
25
|
"configuration.model": "模型",
|
|
26
26
|
"configuration.effort": "推理强度",
|
|
27
|
+
"configuration.effortDefault": "默认",
|
|
27
28
|
"configuration.inherit": "继承成员创建配置",
|
|
28
29
|
"configuration.default": "跟随 harness 默认值",
|
|
29
30
|
"configuration.search": "搜索模型名称或 ID",
|
|
@@ -55,7 +56,6 @@ export const zh = {
|
|
|
55
56
|
"configuration.cancelled": "已接收撤销请求,正在恢复配置。",
|
|
56
57
|
"configuration.failed": "配置操作失败,请检查原因后重试。",
|
|
57
58
|
'stream.thinking': '思考中',
|
|
58
|
-
'stream.writing': '正在生成',
|
|
59
59
|
'stream.recovering': '部分记录,等待实时连接',
|
|
60
60
|
'stream.copy': '复制',
|
|
61
61
|
'stream.copied': '已复制',
|
|
@@ -87,6 +87,30 @@ export const zh = {
|
|
|
87
87
|
'settings.unsupported': '待支持',
|
|
88
88
|
'settings.rosterFailed': '无法读取本地 Agent 列表,请重试',
|
|
89
89
|
'settings.retry': '重试',
|
|
90
|
+
'family.title': '本机 Agent 委派',
|
|
91
|
+
'family.description': '本机安装的编码 agent CLI 的委派通道:端点凭据、默认模型与常驻模式',
|
|
92
|
+
'family.cliMissing': '未检测到 CLI',
|
|
93
|
+
'family.empty': '还没有已注册的委派通道',
|
|
94
|
+
'family.expand': '展开',
|
|
95
|
+
'family.collapse': '收起',
|
|
96
|
+
'models.title': '可用模型',
|
|
97
|
+
'models.info.aria': '可用模型说明',
|
|
98
|
+
'models.info': '列表从上到下是优先级:每轮委派默认使用第一个模型。点「添加模型」从端点当前供应的目录里勾选加入,所以列表里只会有端点真实供应的模型;拖动行调整顺序;留空则跟随原有默认(设置值或 CLI 内置默认)。列表保存在作用域目录(models.json),保存对下一轮委派生效。',
|
|
99
|
+
'models.empty': '列表为空 —— 跟随原有默认(设置值或 CLI 内置默认)',
|
|
100
|
+
'models.add': '+ 添加模型',
|
|
101
|
+
'models.delete': '移除',
|
|
102
|
+
'models.defaultChip': '默认',
|
|
103
|
+
'models.orderHint': '拖动行调整顺序,第一个为默认',
|
|
104
|
+
'models.applied': '已保存,下一轮委派生效;进行中的轮次不受影响',
|
|
105
|
+
'models.error': '保存失败,请重试',
|
|
106
|
+
'models.dialog.title': '选择要添加的模型',
|
|
107
|
+
'models.dialog.hint': '以下是端点当前供应的模型,勾选要添加的模型。',
|
|
108
|
+
'models.dialog.search': '搜索模型',
|
|
109
|
+
'models.dialog.selectAll': '全选',
|
|
110
|
+
'models.dialog.cancel': '取消',
|
|
111
|
+
'models.dialog.confirm': '添加所选',
|
|
112
|
+
'models.dialog.loading': '正在加载端点目录…',
|
|
113
|
+
'models.dialog.empty': '端点目录为空 —— 先保存凭据',
|
|
90
114
|
'member.checking': '正在确认成员身份…',
|
|
91
115
|
'member.readonly.title': '一次性子代理记录',
|
|
92
116
|
'member.readonly.body': '一次性任务不支持后续消息,可在这里查看完整执行记录。',
|
|
@@ -136,6 +160,7 @@ export const en = {
|
|
|
136
160
|
"configuration.details": "Model directory details",
|
|
137
161
|
"configuration.model": "Model",
|
|
138
162
|
"configuration.effort": "Reasoning effort",
|
|
163
|
+
"configuration.effortDefault": "Default",
|
|
139
164
|
"configuration.inherit": "Inherit member configuration",
|
|
140
165
|
"configuration.default": "Follow harness defaults",
|
|
141
166
|
"configuration.search": "Search model names or IDs",
|
|
@@ -167,7 +192,6 @@ export const en = {
|
|
|
167
192
|
"configuration.cancelled": "Cancellation accepted; restoring configuration.",
|
|
168
193
|
"configuration.failed": "Configuration failed; check the reason before retrying.",
|
|
169
194
|
'stream.thinking': 'Thinking',
|
|
170
|
-
'stream.writing': 'Writing',
|
|
171
195
|
'stream.recovering': 'Partial record, awaiting live connection',
|
|
172
196
|
'stream.copy': 'Copy',
|
|
173
197
|
'stream.copied': 'Copied',
|
|
@@ -199,6 +223,30 @@ export const en = {
|
|
|
199
223
|
'settings.unsupported': 'Coming soon',
|
|
200
224
|
'settings.rosterFailed': 'Could not read the local-agent roster; retry',
|
|
201
225
|
'settings.retry': 'Retry',
|
|
226
|
+
'family.title': 'Local Agent Delegation',
|
|
227
|
+
'family.description': 'Delegation channels of the coding-agent CLIs installed on this machine: endpoint credentials, default model, and resident mode',
|
|
228
|
+
'family.cliMissing': 'CLI not detected',
|
|
229
|
+
'family.empty': 'No delegation harnesses registered yet',
|
|
230
|
+
'family.expand': 'Expand',
|
|
231
|
+
'family.collapse': 'Collapse',
|
|
232
|
+
'models.title': 'Available models',
|
|
233
|
+
'models.info.aria': 'About the model list',
|
|
234
|
+
'models.info': "Order is priority: every delegation round starts with the FIRST model. \"Add model\" checks entries off the endpoint's served catalog, so the list can only hold what the endpoint actually serves; drag rows to reorder; leave empty to follow the previous default (the settings value or the CLI's built-in default). The list persists in the scoped home (models.json) and applies to the next delegation round.",
|
|
235
|
+
'models.empty': 'List is empty — following the previous default (settings value or the CLI built-in default)',
|
|
236
|
+
'models.add': '+ Add model',
|
|
237
|
+
'models.delete': 'Remove',
|
|
238
|
+
'models.defaultChip': 'Default',
|
|
239
|
+
'models.orderHint': 'Drag rows to reorder; the first is the default',
|
|
240
|
+
'models.applied': 'Saved — takes effect on the next delegation round; rounds in flight are unaffected',
|
|
241
|
+
'models.error': 'Save failed, please retry',
|
|
242
|
+
'models.dialog.title': 'Choose models to add',
|
|
243
|
+
'models.dialog.hint': 'These are the models the endpoint currently serves — check the ones to add.',
|
|
244
|
+
'models.dialog.search': 'Search models',
|
|
245
|
+
'models.dialog.selectAll': 'Select all',
|
|
246
|
+
'models.dialog.cancel': 'Cancel',
|
|
247
|
+
'models.dialog.confirm': 'Add selected',
|
|
248
|
+
'models.dialog.loading': 'Loading the endpoint catalog…',
|
|
249
|
+
'models.dialog.empty': 'The endpoint catalog is empty — save a credential first',
|
|
202
250
|
'member.checking': 'Checking membership…',
|
|
203
251
|
'member.readonly.title': 'One-shot subagent record',
|
|
204
252
|
'member.readonly.body': 'One-shot tasks do not accept follow-up messages; the full run record is available here.',
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { LocalAgentModelDirectory } from '../types.ts';
|
|
2
|
+
/**
|
|
3
|
+
* Scope a harness's served directory to its curated model list (models.json):
|
|
4
|
+
* the list IS the invite picker's vocabulary, in the list's own order — a
|
|
5
|
+
* listed value the endpoint no longer serves stays as a bare row (the member
|
|
6
|
+
* dialog shows it the same way). No list support, or none configured, keeps
|
|
7
|
+
* the directory as served. Mirrors the member dialog's scoping rule so the
|
|
8
|
+
* invite picker and the member configuration show the same candidates.
|
|
9
|
+
* @param directory - the harness's served directory.
|
|
10
|
+
* @param list - the curated shortlist values, or null when unsupported.
|
|
11
|
+
* @returns the scoped directory.
|
|
12
|
+
*/
|
|
13
|
+
export declare function scopeDirectoryToList(directory: LocalAgentModelDirectory, list: readonly string[] | null | undefined): LocalAgentModelDirectory;
|
|
14
|
+
//# sourceMappingURL=model-directory-scope.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scope a harness's served directory to its curated model list (models.json):
|
|
3
|
+
* the list IS the invite picker's vocabulary, in the list's own order — a
|
|
4
|
+
* listed value the endpoint no longer serves stays as a bare row (the member
|
|
5
|
+
* dialog shows it the same way). No list support, or none configured, keeps
|
|
6
|
+
* the directory as served. Mirrors the member dialog's scoping rule so the
|
|
7
|
+
* invite picker and the member configuration show the same candidates.
|
|
8
|
+
* @param directory - the harness's served directory.
|
|
9
|
+
* @param list - the curated shortlist values, or null when unsupported.
|
|
10
|
+
* @returns the scoped directory.
|
|
11
|
+
*/
|
|
12
|
+
export function scopeDirectoryToList(directory, list) {
|
|
13
|
+
if (list === undefined || list === null || list.length === 0)
|
|
14
|
+
return directory;
|
|
15
|
+
const byValue = new Map(directory.entries.flatMap(entry => entry.resolvedModel === undefined
|
|
16
|
+
? [[entry.value, entry]]
|
|
17
|
+
: [[entry.value, entry], [entry.resolvedModel, entry]]));
|
|
18
|
+
const entries = list.map(value => byValue.get(value) ?? { value, label: value, source: 'configuration' });
|
|
19
|
+
return { ...directory, entries };
|
|
20
|
+
}
|
package/lib/types/gateway.d.ts
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import type { Context } from '@deepseek-ai/cordis';
|
|
11
11
|
import { TypertRemoteService } from '@deepseek-ai/dsh-typert-protocol';
|
|
12
12
|
import type { LocalAgentDelegationView, LocalAgentModelInfo, LocalAgentModelDirectory, LocalAgentPromptResult, LocalAgentSessionRecord, LocalAgentStreamFrame, LocalAgentMemberControlState, LocalAgentMemberInbox, LocalAgentMemberConfiguration, LocalAgentControlReceipt, LocalAgentMemberFeedRequest, LocalAgentMemberFeedEvent } from './types.ts';
|
|
13
|
-
import type { LocalAgentRosterRow, LocalAgentStatus } from './types.ts';
|
|
13
|
+
import type { LocalAgentRosterRow, LocalAgentStatus, LocalAgentEndpointAuthFields, LocalAgentEndpointAuthState } from './types.ts';
|
|
14
14
|
export default class LocalAgentGateway extends TypertRemoteService {
|
|
15
15
|
static inject: string[];
|
|
16
16
|
constructor(ctx: Context);
|
|
@@ -103,6 +103,54 @@ export default class LocalAgentGateway extends TypertRemoteService {
|
|
|
103
103
|
* @returns the layer-by-layer surface, or null.
|
|
104
104
|
*/
|
|
105
105
|
harnessModel(name: string): Promise<LocalAgentModelInfo | null>;
|
|
106
|
+
/**
|
|
107
|
+
* Verify one harness's saved endpoint from the host — the settings card's
|
|
108
|
+
* verify button. The answer is the harness's human-readable verdict text.
|
|
109
|
+
* Session-less by design: the commands channel needs a main agent session,
|
|
110
|
+
* which a settings card may not have. Null when the harness is unknown or
|
|
111
|
+
* declares no probe (the card then hides the button — declare-and-degrade).
|
|
112
|
+
* @param name - the harness name.
|
|
113
|
+
* @returns the verdict text, or null.
|
|
114
|
+
*/
|
|
115
|
+
checkEndpoint(name: string): Promise<string | null>;
|
|
116
|
+
/**
|
|
117
|
+
* The settings card's read of one harness's resolved endpoint state —
|
|
118
|
+
* baseUrl verbatim, credentials as presence booleans (secrets never cross).
|
|
119
|
+
* Session-less like the rest of the gateway. Null when the harness is
|
|
120
|
+
* unknown or declares no endpoint face (the card then hides the form).
|
|
121
|
+
* @param name - the harness name.
|
|
122
|
+
* @returns the resolved per-field state, or null.
|
|
123
|
+
*/
|
|
124
|
+
endpointAuth(name: string): Promise<LocalAgentEndpointAuthState | null>;
|
|
125
|
+
/**
|
|
126
|
+
* Apply one endpoint-credential edit into the harness's own credential
|
|
127
|
+
* store (a string sets, null clears, absent leaves), answering the
|
|
128
|
+
* post-write resolved state so the card can flip immediately. The write
|
|
129
|
+
* deliberately bypasses the volatile row-config channel — a credential
|
|
130
|
+
* never lands in the profile patch document. Null when the harness is
|
|
131
|
+
* unknown or declares no endpoint face.
|
|
132
|
+
* @param name - the harness name.
|
|
133
|
+
* @param fields - the field edits.
|
|
134
|
+
* @returns the post-write resolved state, or null.
|
|
135
|
+
*/
|
|
136
|
+
configureEndpoint(name: string, fields: LocalAgentEndpointAuthFields): Promise<LocalAgentEndpointAuthState | null>;
|
|
137
|
+
/**
|
|
138
|
+
* The settings card's read of one harness's curated model list — ordered
|
|
139
|
+
* identifiers, first is the default. Null when the harness is unknown or
|
|
140
|
+
* declares no list face (the card then hides the editor).
|
|
141
|
+
* @param name - the harness name.
|
|
142
|
+
* @returns the ordered list, or null.
|
|
143
|
+
*/
|
|
144
|
+
modelList(name: string): Promise<readonly string[] | null>;
|
|
145
|
+
/**
|
|
146
|
+
* Replace one harness's curated model list wholesale (reorders, removals
|
|
147
|
+
* and additions all ride the same write), answering the list as persisted.
|
|
148
|
+
* Null when the harness is unknown or declares no list face.
|
|
149
|
+
* @param name - the harness name.
|
|
150
|
+
* @param models - the new ordered list.
|
|
151
|
+
* @returns the persisted list, or null.
|
|
152
|
+
*/
|
|
153
|
+
configureModelList(name: string, models: readonly string[]): Promise<readonly string[] | null>;
|
|
106
154
|
/**
|
|
107
155
|
* The model surface of one member — the composer's picker read. The
|
|
108
156
|
* delegation record's requested model rides in from the core so the broker
|