maka-agent 0.2.0-dev.43.20260919 → 0.2.0-dev.45.20260921
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/LICENSE +12 -6
- package/dist/mcp-capability-provider.js +7 -0
- package/dist/runtime-host-service-manager.js +1 -6
- package/dist/runtime-host-tui-command.js +1 -1
- package/dist/runtime-host-update-command.js +39 -27
- package/native/runtime-host-windows-task-launcher/prebuilds/win32-x64/maka-runtime-host-task-launcher.exe +0 -0
- package/node_modules/@maka/core/dist/artifacts.js +1 -0
- package/node_modules/@maka/core/dist/chat-model-choice.js +3 -0
- package/node_modules/@maka/core/dist/llm-connections.js +3 -21
- package/node_modules/@maka/core/dist/model-catalog.js +8 -20
- package/node_modules/@maka/core/dist/model-metadata.generated.js +304 -304
- package/node_modules/@maka/core/dist/model-metadata.js +1 -2
- package/node_modules/@maka/core/dist/model-thinking.js +16 -1
- package/node_modules/@maka/core/dist/models-dev-projection.js +0 -1
- package/node_modules/@maka/core/dist/provider-auth.js +1 -7
- package/node_modules/@maka/core/dist/provider-registry.js +20 -58
- package/node_modules/@maka/core/dist/recall.js +5 -1
- package/node_modules/@maka/core/dist/runtime-policy/connection-catalog-codec.js +7 -0
- package/node_modules/@maka/core/dist/runtime-policy/model-catalog-entry-codec.js +14 -1
- package/node_modules/@maka/core/dist/session-start-mode.js +2 -5
- package/node_modules/@maka/core/dist/session.js +0 -1
- package/node_modules/@maka/core/dist/settings.js +19 -3
- package/node_modules/@maka/core/dist/tool-quiet-preview.js +2 -16
- package/node_modules/@maka/core/dist/transcript-search.js +46 -0
- package/node_modules/@maka/core/package.json +1 -4
- package/node_modules/@maka/mcp/dist/index.js +22 -0
- package/node_modules/@maka/mcp/dist/oauth.js +4 -2
- package/node_modules/@maka/mcp/dist/tool-progress.js +45 -0
- package/node_modules/@maka/runtime/dist/model-factory.js +0 -16
- package/node_modules/@maka/runtime/dist/model-fetcher.js +1 -4
- package/node_modules/@maka/runtime/dist/model-runtime.js +0 -8
- package/node_modules/@maka/runtime/dist/opencode-session-header.js +2 -3
- package/node_modules/@maka/runtime/dist/recall-tools.js +4 -0
- package/node_modules/@maka/runtime/dist/session-manager.js +5 -57
- package/node_modules/@maka/runtime/dist/subagent-tools.js +69 -11
- package/node_modules/@maka/runtime/dist/test-connection.js +4 -114
- package/node_modules/@maka/runtime/package.json +0 -1
- package/node_modules/@maka/runtime-host/dist/client/client-capability-channel.js +44 -9
- package/node_modules/@maka/runtime-host/dist/client/host-handoff-copy.js +25 -18
- package/node_modules/@maka/runtime-host/dist/client/host-handoff.js +3 -1
- package/node_modules/@maka/runtime-host/dist/client/index.js +1 -1
- package/node_modules/@maka/runtime-host/dist/client/session-subscription.js +33 -3
- package/node_modules/@maka/runtime-host/dist/protocol/connection-effects.js +0 -108
- package/node_modules/@maka/runtime-host/dist/protocol/index.js +12 -1
- package/node_modules/@maka/runtime-host/dist/protocol/message.js +10 -0
- package/node_modules/@maka/runtime-host/dist/protocol/operations.js +4 -6
- package/node_modules/@maka/runtime-host/dist/protocol/recall.js +270 -0
- package/node_modules/@maka/runtime-host/dist/protocol/session-catalog.js +1 -1
- package/node_modules/@maka/runtime-host/dist/protocol/session-continuity.js +1 -7
- package/node_modules/@maka/runtime-host/dist/protocol/turn.js +0 -33
- package/node_modules/@maka/runtime-host/dist/protocol/usage-screen.js +12 -4
- package/node_modules/@maka/runtime-host/dist/server/access-credential-store.js +6 -0
- package/node_modules/@maka/runtime-host/dist/server/bootstrap-runtime-policy.js +31 -104
- package/node_modules/@maka/runtime-host/dist/server/connection-effect-coordinator.js +1 -57
- package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +11 -35
- package/node_modules/@maka/runtime-host/dist/server/interactive-run-composer.js +3 -20
- package/node_modules/@maka/runtime-host/dist/server/interactive-turn-coordinator.js +1 -16
- package/node_modules/@maka/runtime-host/dist/server/message-coordinator.js +46 -28
- package/node_modules/@maka/runtime-host/dist/server/recall-coordinator.js +117 -0
- package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +5 -16
- package/node_modules/@maka/runtime-host/dist/server/session-catalog-coordinator.js +21 -12
- package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +0 -4
- package/node_modules/@maka/runtime-host/dist/server/session-turn-access-request-coordinator.js +7 -17
- package/node_modules/@maka/storage/dist/artifact-metadata-codec.js +4 -3
- package/node_modules/@maka/storage/dist/artifact-store.js +1 -11
- package/node_modules/@maka/storage/dist/process-lifetime-file-update-lock.js +0 -41
- package/node_modules/@maka/storage/dist/runtime-policy/connection-catalog-document.js +0 -62
- package/node_modules/@maka/storage/dist/runtime-policy/coordinator.js +0 -31
- package/node_modules/@maka/storage/dist/runtime-policy-stores.js +0 -3
- package/node_modules/@maka/storage/dist/sqlite-usage-schema.js +29 -5
- package/node_modules/@maka/storage/dist/sqlite-workflow-schema.js +2 -0
- package/node_modules/@maka/storage/dist/storage-writer-composition.js +0 -3
- package/node_modules/@maka/storage/dist/telemetry-file-schema.js +5 -3
- package/node_modules/@maka/storage/dist/usage-screen.js +5 -6
- package/node_modules/@maka/storage/dist/usage-stores.js +14 -4
- package/node_modules/@maka/storage/package.json +0 -2
- package/package.json +1 -1
- package/node_modules/@maka/core/dist/connection-usage.js +0 -27
- package/node_modules/@maka/core/dist/deep-research-client-progress.js +0 -132
- package/node_modules/@maka/core/dist/deep-research-run.js +0 -625
- package/node_modules/@maka/core/dist/deep-research.js +0 -208
- package/node_modules/@maka/core/dist/thread-search.js +0 -498
- package/node_modules/@maka/runtime/dist/commandcode-cli-language-model.js +0 -837
- package/node_modules/@maka/runtime/dist/connection-usage.js +0 -232
- package/node_modules/@maka/runtime/dist/deep-research-tools.js +0 -732
- package/node_modules/@maka/runtime-host/dist/protocol/deep-research.js +0 -233
- package/node_modules/@maka/runtime-host/dist/server/deep-research-coordinator.js +0 -116
- package/node_modules/@maka/storage/dist/deep-research-authority.js +0 -129
- package/node_modules/@maka/storage/dist/deep-research-store.js +0 -343
|
@@ -17,11 +17,10 @@
|
|
|
17
17
|
* under the License.
|
|
18
18
|
*/
|
|
19
19
|
export const OPENCODE_SESSION_HEADER = 'x-opencode-session';
|
|
20
|
-
/** Adds OpenCode Go
|
|
20
|
+
/** Adds OpenCode Go session identity without overriding an explicit header. */
|
|
21
21
|
export function withOpenCodeSessionHeader(providerType, sessionId, headers) {
|
|
22
22
|
const normalizedSessionId = sessionId?.trim();
|
|
23
|
-
if (
|
|
24
|
-
!normalizedSessionId) {
|
|
23
|
+
if (providerType !== 'opencode-go' || !normalizedSessionId) {
|
|
25
24
|
return headers;
|
|
26
25
|
}
|
|
27
26
|
if (Object.keys(headers ?? {}).some((name) => name.toLowerCase() === OPENCODE_SESSION_HEADER)) {
|
|
@@ -230,6 +230,10 @@ function projectPassage(passage, activeSessionId) {
|
|
|
230
230
|
title: passage.sessionTitle,
|
|
231
231
|
...(passage.turnId ? { turn_id: passage.turnId } : {}),
|
|
232
232
|
anchor_message_id: passage.anchorMessageId,
|
|
233
|
+
// The anchor's index in its Session transcript. Carried for the same
|
|
234
|
+
// reason a UI needs it: a caller that wants to point at the passage in a
|
|
235
|
+
// transcript scrolls by sequence, and this spares it a second lookup.
|
|
236
|
+
sequence: passage.sequence,
|
|
233
237
|
is_current_session: passage.sessionId === activeSessionId,
|
|
234
238
|
...(passage.lastMessageAt !== undefined ? { last_message_at: passage.lastMessageAt } : {}),
|
|
235
239
|
matched_terms: passage.matchedTerms,
|
|
@@ -20,12 +20,11 @@ import { countRecallSearchableMessages, listRecallCandidateSessions, } from './r
|
|
|
20
20
|
import { createHash } from 'node:crypto';
|
|
21
21
|
import { isDeepStrictEqual } from 'node:util';
|
|
22
22
|
import { setTimeout as delay } from 'node:timers/promises';
|
|
23
|
-
import { messageContentsEqual
|
|
23
|
+
import { messageContentsEqual } from '@maka/core/events';
|
|
24
24
|
import { isCanonicalReadOnlyPermissionProfile } from '@maka/core/permission-profile';
|
|
25
25
|
import { DEFAULT_TOOL_MODE } from '@maka/core/tool-mode';
|
|
26
26
|
import { PLAN_USER_ABANDON_REASON, PLAN_USER_CANCEL_REASON, PlanConflictError, activePlanExecution, } from '@maka/core/plan';
|
|
27
27
|
import { DEFAULT_SESSION_NAME } from '@maka/core/session-name';
|
|
28
|
-
import { DEEP_RESEARCH_SESSION_LABEL, isDeepResearchSession } from '@maka/core/deep-research';
|
|
29
28
|
import { SUBAGENT_SESSION_RUNTIME_SCHEMA_VERSION, SUBAGENT_SESSION_SPAWN_SCHEMA_VERSION, childSessionsForParent, subagentSessionRuntimeSummary, } from '@maka/core/session';
|
|
30
29
|
import { decodeAgentGraphIntentClaim } from '@maka/core/agent-graph-control';
|
|
31
30
|
import { executionBoundaryContains } from '@maka/core/sandbox-boundary';
|
|
@@ -97,14 +96,6 @@ export class SessionConfigurationRevisionConflictError extends Error {
|
|
|
97
96
|
this.actualRevision = actualRevision;
|
|
98
97
|
}
|
|
99
98
|
}
|
|
100
|
-
export class RuntimeRegenerateTurnError extends Error {
|
|
101
|
-
code;
|
|
102
|
-
name = 'RuntimeRegenerateTurnError';
|
|
103
|
-
constructor(code, message) {
|
|
104
|
-
super(message);
|
|
105
|
-
this.code = code;
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
99
|
export class BackendRegistry {
|
|
109
100
|
registrations = new Map();
|
|
110
101
|
register(kind, registration) {
|
|
@@ -355,11 +346,7 @@ export class SessionManager {
|
|
|
355
346
|
throw new SessionConfigurationTransitionError('session_busy', 'Session has a pending Interaction');
|
|
356
347
|
}
|
|
357
348
|
await this.assertCollaborationTransition(current.header, input.configuration.collaborationMode);
|
|
358
|
-
const
|
|
359
|
-
input.configuration.permissionMode !== 'explore';
|
|
360
|
-
const labels = leavingDeepResearch
|
|
361
|
-
? current.header.labels.filter((label) => label !== DEEP_RESEARCH_SESSION_LABEL)
|
|
362
|
-
: current.header.labels;
|
|
349
|
+
const labels = current.header.labels;
|
|
363
350
|
return () => store.updateSessionConfiguration(sessionId, {
|
|
364
351
|
expectedVersion: input.expectedRevision,
|
|
365
352
|
configuration: {
|
|
@@ -713,15 +700,11 @@ export class SessionManager {
|
|
|
713
700
|
async setPermissionModeWithLegacyStore(sessionId, mode) {
|
|
714
701
|
const previous = await this.deps.store.readHeader(sessionId);
|
|
715
702
|
const boundary = await this.deps.store.readExecutionBoundary(sessionId);
|
|
716
|
-
const leavingDeepResearch = isDeepResearchSession(previous.labels) && mode !== 'explore';
|
|
717
703
|
if (previous.permissionMode === mode &&
|
|
718
|
-
executionBoundaryMatchesPermissionMode(boundary, mode)
|
|
719
|
-
!leavingDeepResearch) {
|
|
704
|
+
executionBoundaryMatchesPermissionMode(boundary, mode)) {
|
|
720
705
|
return headerToSummary(previous);
|
|
721
706
|
}
|
|
722
|
-
const labels =
|
|
723
|
-
? previous.labels.filter((label) => label !== DEEP_RESEARCH_SESSION_LABEL)
|
|
724
|
-
: previous.labels;
|
|
707
|
+
const labels = previous.labels;
|
|
725
708
|
const kind = mode === 'bypass' ? 'bypass' : 'managed';
|
|
726
709
|
await this.commitExecutionBoundaryTransition(sessionId, boundary, mode, async () => {
|
|
727
710
|
const current = await this.deps.store.readHeader(sessionId);
|
|
@@ -1463,7 +1446,7 @@ export class SessionManager {
|
|
|
1463
1446
|
}
|
|
1464
1447
|
const resolvedPreset = await this.deps.subagentCatalog.resolve(input.subagentId);
|
|
1465
1448
|
if (resolvedPreset.profile !== input.agentProfile) {
|
|
1466
|
-
throw new Error(`Subagent preset "${input.subagentId}" profile changed during spawn
|
|
1449
|
+
throw new Error(`Subagent preset "${input.subagentId}" profile changed during spawn. Retry the same agent_spawn call.`);
|
|
1467
1450
|
}
|
|
1468
1451
|
return { ...input, resolvedPreset };
|
|
1469
1452
|
}
|
|
@@ -2752,41 +2735,6 @@ export class SessionManager {
|
|
|
2752
2735
|
? authority.stopRoot(identity, input)
|
|
2753
2736
|
: this.runtimeKernel.stopSession(identity.sessionId, input);
|
|
2754
2737
|
}
|
|
2755
|
-
async *regenerateTurn(sessionId, input) {
|
|
2756
|
-
const execution = this.runtimeKernel.claimExecution(sessionId);
|
|
2757
|
-
try {
|
|
2758
|
-
const source = await this.prepareRegenerateTurn(sessionId, input.sourceTurnId);
|
|
2759
|
-
yield* this.sendMessage(sessionId, {
|
|
2760
|
-
turnId: input.turnId ?? this.deps.newId(),
|
|
2761
|
-
...source.content,
|
|
2762
|
-
parentTurnId: source.sourceTurnId,
|
|
2763
|
-
regeneratedFromTurnId: source.sourceTurnId,
|
|
2764
|
-
}, { execution });
|
|
2765
|
-
}
|
|
2766
|
-
finally {
|
|
2767
|
-
execution.release();
|
|
2768
|
-
}
|
|
2769
|
-
}
|
|
2770
|
-
async prepareRegenerateTurn(sessionId, sourceTurnId) {
|
|
2771
|
-
const view = await this.getSessionView(sessionId);
|
|
2772
|
-
const source = view.turns.find((candidate) => candidate.turnId === sourceTurnId);
|
|
2773
|
-
if (!source) {
|
|
2774
|
-
throw new RuntimeRegenerateTurnError('not_found', `Cannot regenerate unknown Turn ${sourceTurnId}`);
|
|
2775
|
-
}
|
|
2776
|
-
if (source.status !== 'failed' &&
|
|
2777
|
-
source.status !== 'aborted' &&
|
|
2778
|
-
source.status !== 'completed') {
|
|
2779
|
-
throw new RuntimeRegenerateTurnError('operation_conflict', `Cannot regenerate Turn ${sourceTurnId} while it is ${source.status}`);
|
|
2780
|
-
}
|
|
2781
|
-
const user = view.messages.find((message) => message.type === 'user' && message.turnId === sourceTurnId);
|
|
2782
|
-
if (!user) {
|
|
2783
|
-
throw new RuntimeRegenerateTurnError('operation_conflict', `Turn ${sourceTurnId} has no UserMessage`);
|
|
2784
|
-
}
|
|
2785
|
-
return {
|
|
2786
|
-
sourceTurnId,
|
|
2787
|
-
content: normalizeMessageContent(user),
|
|
2788
|
-
};
|
|
2789
|
-
}
|
|
2790
2738
|
/** Canonical, repaired source view for a Host-owned cross-Session copy. */
|
|
2791
2739
|
async readConversationCopySnapshot(sessionId) {
|
|
2792
2740
|
return this.getSessionView(sessionId);
|
|
@@ -46,6 +46,7 @@ const AGENT_LIST_PAGE_SIZE = 8;
|
|
|
46
46
|
const AGENT_LIST_MAX_RESPONSE_CHARS = 7_000;
|
|
47
47
|
const AGENT_LIST_DESCRIPTION_MAX_CHARS = 240;
|
|
48
48
|
const AGENT_LIST_MODEL_MAX_CHARS = 160;
|
|
49
|
+
const CHILD_EXECUTOR_SELECTION_GUIDANCE = 'Use executor_mode=inherit for the preset or inherited execution route; executor_id is then ignored. Use executor_mode=plugin only for an explicitly selected registered plugin executor. Without executor_mode, omit executor_id to inherit; "default" is not a default selector.';
|
|
49
50
|
/**
|
|
50
51
|
* Which schema fields each `agent_output` locator needs. A rejection that only
|
|
51
52
|
* says "its matching identity fields" leaves the model guessing which of the
|
|
@@ -76,22 +77,34 @@ export function buildSubagentSpawnTool(deps = {}) {
|
|
|
76
77
|
return {
|
|
77
78
|
name: AGENT_SPAWN_TOOL_NAME,
|
|
78
79
|
displayName: 'Agent',
|
|
79
|
-
description:
|
|
80
|
+
description: "Run one bounded foreground child task. Call agent_list and copy an available choice's spawn_args, then add task. target_kind=profile uses profile; target_kind=preset uses subagent_id. The unused selector is ignored. Empty presets does not disable built-in profiles. Without target_kind, subagent_id takes precedence for legacy callers. Independent child tasks may be called together in one parallel batch, including corrected retries after selector errors. " +
|
|
81
|
+
CHILD_EXECUTOR_SELECTION_GUIDANCE,
|
|
80
82
|
parameters: z.preprocess(cleanSubagentSpawnInput, z
|
|
81
83
|
.object({
|
|
82
|
-
|
|
84
|
+
target_kind: z
|
|
85
|
+
.enum(['profile', 'preset'])
|
|
86
|
+
.optional()
|
|
87
|
+
.describe('Choose profile for legacy_profiles or preset for presets. Only the selected identity field is used; the other is ignored even if populated.'),
|
|
88
|
+
profile: z
|
|
89
|
+
.enum(profiles)
|
|
90
|
+
.optional()
|
|
91
|
+
.describe('Built-in child capability: copy legacy_profiles[].profile from agent_list.'),
|
|
83
92
|
subagent_id: z
|
|
84
93
|
.string()
|
|
85
94
|
.min(1)
|
|
86
95
|
.max(128)
|
|
87
96
|
.refine(isSafeSubagentPresetId)
|
|
88
97
|
.optional()
|
|
89
|
-
.describe('
|
|
98
|
+
.describe('For target_kind=preset, copy presets[].subagent_id from agent_list. Ignored for target_kind=profile.'),
|
|
99
|
+
executor_mode: z
|
|
100
|
+
.enum(['inherit', 'plugin'])
|
|
101
|
+
.optional()
|
|
102
|
+
.describe(CHILD_EXECUTOR_SELECTION_GUIDANCE),
|
|
90
103
|
executor_id: z
|
|
91
104
|
.string()
|
|
92
105
|
.refine(isExecutorId)
|
|
93
106
|
.optional()
|
|
94
|
-
.describe(
|
|
107
|
+
.describe(CHILD_EXECUTOR_SELECTION_GUIDANCE),
|
|
95
108
|
task: z
|
|
96
109
|
.string()
|
|
97
110
|
.min(1)
|
|
@@ -108,12 +121,30 @@ export function buildSubagentSpawnTool(deps = {}) {
|
|
|
108
121
|
})
|
|
109
122
|
.strip()
|
|
110
123
|
.superRefine((input, ctx) => {
|
|
111
|
-
if (
|
|
124
|
+
if (input.executor_mode === 'plugin' && !input.executor_id) {
|
|
112
125
|
ctx.addIssue({
|
|
113
126
|
code: z.ZodIssueCode.custom,
|
|
114
|
-
|
|
115
|
-
|
|
127
|
+
path: ['executor_id'],
|
|
128
|
+
message: 'executor_mode=plugin requires a registered executor_id. Use executor_mode=inherit for normal child execution.',
|
|
116
129
|
});
|
|
130
|
+
}
|
|
131
|
+
if (!input.profile && !input.subagent_id) {
|
|
132
|
+
if (input.target_kind) {
|
|
133
|
+
const selector = input.target_kind === 'profile' ? 'profile' : 'subagent_id';
|
|
134
|
+
const catalogSection = input.target_kind === 'profile' ? 'legacy_profiles' : 'presets';
|
|
135
|
+
ctx.addIssue({
|
|
136
|
+
code: z.ZodIssueCode.custom,
|
|
137
|
+
path: [selector],
|
|
138
|
+
message: `target_kind=${input.target_kind} requires ${selector}. Call agent_list and copy an available ${catalogSection} choice's spawn_args, then add task.`,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
else {
|
|
142
|
+
ctx.addIssue({
|
|
143
|
+
code: z.ZodIssueCode.custom,
|
|
144
|
+
message: 'No child selector was provided. Call agent_list and pass a returned subagent_id to agent_spawn, ' +
|
|
145
|
+
`or pass one legacy profile: ${profiles.join(', ')}.`,
|
|
146
|
+
});
|
|
147
|
+
}
|
|
117
148
|
return;
|
|
118
149
|
}
|
|
119
150
|
if (input.subagent_id)
|
|
@@ -185,8 +216,12 @@ function cleanSubagentSpawnInput(input) {
|
|
|
185
216
|
if (!input || typeof input !== 'object' || Array.isArray(input))
|
|
186
217
|
return input;
|
|
187
218
|
const cleaned = { ...input };
|
|
188
|
-
if (cleaned.
|
|
219
|
+
if (cleaned.target_kind === 'profile')
|
|
220
|
+
delete cleaned.subagent_id;
|
|
221
|
+
else if (cleaned.target_kind === 'preset' || cleaned.subagent_id !== undefined)
|
|
189
222
|
delete cleaned.profile;
|
|
223
|
+
if (cleaned.executor_mode === 'inherit')
|
|
224
|
+
delete cleaned.executor_id;
|
|
190
225
|
return cleaned;
|
|
191
226
|
}
|
|
192
227
|
async function resolvePresetDefinition(subagentId, ctx, definitions) {
|
|
@@ -205,8 +240,13 @@ async function resolvePresetDefinition(subagentId, ctx, definitions) {
|
|
|
205
240
|
!Array.isArray(candidate) &&
|
|
206
241
|
candidate.id === subagentId &&
|
|
207
242
|
typeof candidate.profile === 'string');
|
|
208
|
-
if (!preset)
|
|
209
|
-
|
|
243
|
+
if (!preset) {
|
|
244
|
+
const legacy = definitions.find((definition) => definition.profile === subagentId || definition.id === subagentId);
|
|
245
|
+
const recovery = legacy
|
|
246
|
+
? `"${subagentId}" identifies a built-in agent, not a configured preset. Use ${JSON.stringify({ target_kind: 'profile', profile: legacy.profile, executor_mode: 'inherit' })}, keeping your task. The unused subagent_id and executor_id fields are ignored in these modes.`
|
|
247
|
+
: "Call agent_list and copy an available choice's spawn_args, then add task. presets use subagent_id; legacy_profiles use profile.";
|
|
248
|
+
throw new Error(`Unknown subagent_id "${subagentId}". No child was started. ${recovery} ${CHILD_EXECUTOR_SELECTION_GUIDANCE}`);
|
|
249
|
+
}
|
|
210
250
|
if (preset.availability?.status !== 'available') {
|
|
211
251
|
throw new Error(`Subagent preset "${subagentId}" is unavailable.`);
|
|
212
252
|
}
|
|
@@ -249,7 +289,7 @@ export function buildSubagentListTool() {
|
|
|
249
289
|
return {
|
|
250
290
|
name: AGENT_LIST_TOOL_NAME,
|
|
251
291
|
displayName: 'Agent List',
|
|
252
|
-
description:
|
|
292
|
+
description: "List a compact page of subagents to select. Copy an available choice's spawn_args into agent_spawn and add task. presets use subagent_id; legacy_profiles use profile, including when presets is empty. agent_id is for Graph only. Use view=catalog only to diagnose unavailable routes. Child execution history is intentionally excluded; use refs returned by agent_spawn or asynchronous graph work with agent_output.",
|
|
253
293
|
parameters: z
|
|
254
294
|
.object({
|
|
255
295
|
view: z
|
|
@@ -309,6 +349,15 @@ function projectAgentList(catalog, input) {
|
|
|
309
349
|
return [
|
|
310
350
|
{
|
|
311
351
|
subagent_id: preset.id,
|
|
352
|
+
...(availability.status === 'available'
|
|
353
|
+
? {
|
|
354
|
+
spawn_args: {
|
|
355
|
+
target_kind: 'preset',
|
|
356
|
+
subagent_id: preset.id,
|
|
357
|
+
executor_mode: 'inherit',
|
|
358
|
+
},
|
|
359
|
+
}
|
|
360
|
+
: {}),
|
|
312
361
|
name: boundedCatalogText(preset.name, 128),
|
|
313
362
|
description: boundedCatalogText(preset.description, AGENT_LIST_DESCRIPTION_MAX_CHARS),
|
|
314
363
|
profile: preset.profile,
|
|
@@ -345,6 +394,15 @@ function projectAgentList(catalog, input) {
|
|
|
345
394
|
{
|
|
346
395
|
agent_id: definition.id,
|
|
347
396
|
profile: definition.profile,
|
|
397
|
+
...(availability.status === 'available'
|
|
398
|
+
? {
|
|
399
|
+
spawn_args: {
|
|
400
|
+
target_kind: 'profile',
|
|
401
|
+
profile: definition.profile,
|
|
402
|
+
executor_mode: 'inherit',
|
|
403
|
+
},
|
|
404
|
+
}
|
|
405
|
+
: {}),
|
|
348
406
|
name: boundedCatalogText(definition.name, 128),
|
|
349
407
|
description: boundedCatalogText(definition.description, AGENT_LIST_DESCRIPTION_MAX_CHARS),
|
|
350
408
|
...(typeof contract?.workspace === 'string'
|
|
@@ -17,12 +17,11 @@
|
|
|
17
17
|
* under the License.
|
|
18
18
|
*/
|
|
19
19
|
import { randomUUID } from 'node:crypto';
|
|
20
|
-
import { buildCommandCodeCliRequest, commandCodeCliGenerateUrl, commandCodeCliHeaders, summarizeCommandCodeCliStream, } from './commandcode-cli-language-model.js';
|
|
21
20
|
import { PROVIDER_REGISTRY, effectiveBaseUrl, providerDefaultsOf, providerFallbackModelIds, connectionModelsEnumerateAccount, connectionEnabledModelIds, } from '@maka/core/llm-connections';
|
|
22
21
|
import { openResponsesUrl } from './provider-urls.js';
|
|
23
22
|
import { resolveModelRuntime } from './model-runtime.js';
|
|
24
23
|
import { fetchGitHubCopilotModels } from './model-fetcher.js';
|
|
25
|
-
import { CONNECTION_EFFECT_ERROR_BODY_MAX_BYTES,
|
|
24
|
+
import { CONNECTION_EFFECT_ERROR_BODY_MAX_BYTES, ConnectionEffectFetchError, fetchForConnectionEffect, } from './connection-effect-fetch.js';
|
|
26
25
|
import { ConnectionEffectHttpError, ConnectionEffectInvalidResponseError, classifyConnectionEffectStatus, } from './connection-effect-outcome.js';
|
|
27
26
|
import { withOpenCodeSessionHeader } from './opencode-session-header.js';
|
|
28
27
|
const CONNECTION_TEST_TIMEOUT_MS = 15_000;
|
|
@@ -106,47 +105,15 @@ async function testConnectionStrict(connection, apiKey, model, fetchFn, t0, time
|
|
|
106
105
|
if (!defaults) {
|
|
107
106
|
return { ok: false, errorMessage: `Unknown provider type "${connection.providerType}"` };
|
|
108
107
|
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
108
|
+
if (defaults.retired)
|
|
109
|
+
return retiredProviderTestResult(connection.providerType);
|
|
110
|
+
const sessionId = connection.providerType === 'opencode-go' ? randomUUID() : undefined;
|
|
112
111
|
const auth = defaults.authKind;
|
|
113
112
|
const secret = auth === 'none' ? '' : apiKey;
|
|
114
113
|
const testModel = resolveConnectionTestModel(connection, model, providerFallbackModelIds(defaults));
|
|
115
114
|
if (!testModel) {
|
|
116
115
|
return { ok: false, errorMessage: 'No model to test' };
|
|
117
116
|
}
|
|
118
|
-
if (connection.providerType === 'opencode-free' && !model?.trim()) {
|
|
119
|
-
const brokenModelIds = new Set(defaults.brokenModelIds ?? []);
|
|
120
|
-
const candidates = [
|
|
121
|
-
...new Set([
|
|
122
|
-
...connectionEnabledModelIds(connection).filter((id) => !brokenModelIds.has(id)),
|
|
123
|
-
...providerFallbackModelIds(defaults),
|
|
124
|
-
]),
|
|
125
|
-
];
|
|
126
|
-
if (candidates.length === 0) {
|
|
127
|
-
return { ok: false, errorMessage: 'No model to test' };
|
|
128
|
-
}
|
|
129
|
-
let lastFailure;
|
|
130
|
-
for (let index = 0; index < candidates.length; index += 1) {
|
|
131
|
-
const candidate = candidates[index];
|
|
132
|
-
const remainingMs = timeoutMs - (Date.now() - t0);
|
|
133
|
-
if (remainingMs <= 0) {
|
|
134
|
-
return connectionTestFailure(new ConnectionEffectFetchError('timeout'), t0);
|
|
135
|
-
}
|
|
136
|
-
const remainingCandidates = candidates.length - index;
|
|
137
|
-
const attemptTimeoutMs = Math.max(1, Math.floor(remainingMs / remainingCandidates));
|
|
138
|
-
try {
|
|
139
|
-
const result = await testConnectionModel(connection, secret, candidate, fetchFn, t0, attemptTimeoutMs, sessionId);
|
|
140
|
-
if (result.ok)
|
|
141
|
-
return result;
|
|
142
|
-
lastFailure = result;
|
|
143
|
-
}
|
|
144
|
-
catch (error) {
|
|
145
|
-
lastFailure = connectionTestFailure(error, t0, true);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
return lastFailure ?? connectionTestFailure(new ConnectionEffectFetchError('timeout'), t0);
|
|
149
|
-
}
|
|
150
117
|
return await testConnectionModel(connection, secret, testModel, fetchFn, t0, timeoutMs, sessionId);
|
|
151
118
|
}
|
|
152
119
|
async function testConnectionModel(connection, secret, testModel, fetchFn, t0, timeoutMs = CONNECTION_TEST_TIMEOUT_MS, sessionId) {
|
|
@@ -179,54 +146,8 @@ async function testConnectionModel(connection, secret, testModel, fetchFn, t0, t
|
|
|
179
146
|
return await probeGoogle(baseUrl, secret, testModel, t0, adapter.normalizeBaseUrl !== false, fetchFn);
|
|
180
147
|
case 'cohere':
|
|
181
148
|
return await probeCohere(baseUrl, secret, testModel, t0, fetchFn);
|
|
182
|
-
case 'commandcode-cli':
|
|
183
|
-
return await probeCommandCodeCli(baseUrl, secret, testModel, t0, fetchFn, requestHeaders);
|
|
184
149
|
}
|
|
185
150
|
}
|
|
186
|
-
async function probeCommandCodeCli(baseUrl, apiKey, model, t0, fetchFn, requestHeaders) {
|
|
187
|
-
const { body } = buildCommandCodeCliRequest({ prompt: [{ role: 'user', content: [{ type: 'text', text: 'Hi' }] }], maxOutputTokens: 16 }, { modelId: model });
|
|
188
|
-
const r = await fetchForConnectionEffect(fetchFn, commandCodeCliGenerateUrl(baseUrl), {
|
|
189
|
-
method: 'POST',
|
|
190
|
-
headers: { ...commandCodeCliHeaders(apiKey, 'maka'), ...(requestHeaders ?? {}) },
|
|
191
|
-
body: JSON.stringify(body),
|
|
192
|
-
timeoutMs: CONNECTION_TEST_TIMEOUT_MS,
|
|
193
|
-
});
|
|
194
|
-
if (!r.ok)
|
|
195
|
-
return httpFailure(r, t0);
|
|
196
|
-
// HTTP 200 is only the handshake on this wire. The generation adapter fails
|
|
197
|
-
// the send on an in-band `error` event and on a stream that ends without a
|
|
198
|
-
// `finish`, so a probe that stopped at the status would store a connection
|
|
199
|
-
// as verified whose very next send is rejected.
|
|
200
|
-
const outcome = summarizeCommandCodeCliStream(await r.readText(CONNECTION_EFFECT_JSON_BODY_MAX_BYTES));
|
|
201
|
-
const latencyMs = Date.now() - t0;
|
|
202
|
-
if (outcome.error) {
|
|
203
|
-
const { message, statusCode } = outcome.error;
|
|
204
|
-
return {
|
|
205
|
-
ok: false,
|
|
206
|
-
latencyMs,
|
|
207
|
-
errorMessage: message.slice(0, 200),
|
|
208
|
-
...(statusCode === undefined ? {} : { statusCode }),
|
|
209
|
-
errorClass: commandCodeCliStreamErrorClass(statusCode),
|
|
210
|
-
};
|
|
211
|
-
}
|
|
212
|
-
if (!outcome.finished) {
|
|
213
|
-
return {
|
|
214
|
-
ok: false,
|
|
215
|
-
latencyMs,
|
|
216
|
-
errorMessage: 'The Command Code GO stream ended before the turn finished',
|
|
217
|
-
errorClass: 'network',
|
|
218
|
-
};
|
|
219
|
-
}
|
|
220
|
-
return { ok: true, latencyMs, modelTested: model };
|
|
221
|
-
}
|
|
222
|
-
function commandCodeCliStreamErrorClass(statusCode) {
|
|
223
|
-
if (statusCode === 401 || statusCode === 403)
|
|
224
|
-
return 'auth';
|
|
225
|
-
if (statusCode === 429 || (statusCode !== undefined && statusCode >= 500)) {
|
|
226
|
-
return 'provider_unavailable';
|
|
227
|
-
}
|
|
228
|
-
return 'unknown';
|
|
229
|
-
}
|
|
230
151
|
async function probeGitHubCopilot(baseUrl, apiKey, model, t0, fetchFn) {
|
|
231
152
|
const models = await fetchGitHubCopilotModels(baseUrl, apiKey, fetchFn);
|
|
232
153
|
if (!models.some(({ id }) => id === model)) {
|
|
@@ -332,40 +253,9 @@ async function probeOpenAI(connection, baseUrl, apiKey, model, t0, fetchFn, time
|
|
|
332
253
|
});
|
|
333
254
|
if (!r.ok)
|
|
334
255
|
return httpFailure(r, t0);
|
|
335
|
-
if (connection.providerType === 'opencode-free') {
|
|
336
|
-
const body = await r.readJson();
|
|
337
|
-
if (!isOpenAIChatCompletion(body)) {
|
|
338
|
-
return {
|
|
339
|
-
ok: false,
|
|
340
|
-
errorMessage: 'OpenCode Free returned no valid chat completion',
|
|
341
|
-
errorClass: 'provider_unavailable',
|
|
342
|
-
latencyMs: Date.now() - t0,
|
|
343
|
-
modelTested: model,
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
return { ok: true, latencyMs: Date.now() - t0, modelTested: model };
|
|
347
|
-
}
|
|
348
256
|
await r.cancel();
|
|
349
257
|
return { ok: true, latencyMs: Date.now() - t0, modelTested: model };
|
|
350
258
|
}
|
|
351
|
-
function isOpenAIChatCompletion(value) {
|
|
352
|
-
if (!value || typeof value !== 'object')
|
|
353
|
-
return false;
|
|
354
|
-
const choices = value.choices;
|
|
355
|
-
return (Array.isArray(choices) &&
|
|
356
|
-
choices.some((choice) => {
|
|
357
|
-
if (!choice || typeof choice !== 'object')
|
|
358
|
-
return false;
|
|
359
|
-
const message = choice.message;
|
|
360
|
-
if (!message || typeof message !== 'object')
|
|
361
|
-
return false;
|
|
362
|
-
const completion = message;
|
|
363
|
-
return (typeof completion.content === 'string' ||
|
|
364
|
-
typeof completion.reasoning === 'string' ||
|
|
365
|
-
typeof completion.reasoning_content === 'string' ||
|
|
366
|
-
(Array.isArray(completion.tool_calls) && completion.tool_calls.length > 0));
|
|
367
|
-
}));
|
|
368
|
-
}
|
|
369
259
|
async function probeGoogle(baseUrl, apiKey, model, t0, normalizeBaseUrl, fetchFn) {
|
|
370
260
|
const url = `${stripTrailing(baseUrl)}/models/${encodeURIComponent(model)}:generateContent${normalizeBaseUrl ? `?key=${encodeURIComponent(apiKey)}` : ''}`;
|
|
371
261
|
const r = await fetchForConnectionEffect(fetchFn, url, {
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
"./shell-tools": "./dist/shell-tools.js",
|
|
14
14
|
"./shell-run-manager": "./dist/shell-run-manager.js",
|
|
15
15
|
"./background-task-health-tool": "./dist/background-task-health-tool.js",
|
|
16
|
-
"./deep-research-tools": "./dist/deep-research-tools.js",
|
|
17
16
|
"./durable-tool-result-projection": "./dist/durable-tool-result-projection.js",
|
|
18
17
|
"./tool-artifacts": "./dist/tool-artifacts.js",
|
|
19
18
|
"./model-factory": "./dist/model-factory.js",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* under the License.
|
|
18
18
|
*/
|
|
19
19
|
import { randomUUID } from 'node:crypto';
|
|
20
|
-
import { CLIENT_CAPABILITY_MAX_RESULT_BYTES, CLIENT_CAPABILITY_RESULT_CHUNK_MAX_BYTES, decodeClientCapabilityClientFrame, decodeClientCapabilityReplaceInput, decodeClientCapabilityResult, } from '../protocol/index.js';
|
|
20
|
+
import { CLIENT_CAPABILITY_MAX_PROGRESS_TOTAL, CLIENT_CAPABILITY_MAX_RESULT_BYTES, CLIENT_CAPABILITY_RESULT_CHUNK_MAX_BYTES, decodeClientCapabilityClientFrame, decodeClientCapabilityReplaceInput, decodeClientCapabilityResult, } from '../protocol/index.js';
|
|
21
21
|
/** Client-owned registration, reverse invocation, and teardown lifecycle. */
|
|
22
22
|
export class ClientCapabilityChannel {
|
|
23
23
|
#options;
|
|
@@ -247,6 +247,40 @@ export class ClientCapabilityChannel {
|
|
|
247
247
|
});
|
|
248
248
|
return accepting;
|
|
249
249
|
};
|
|
250
|
+
let pendingProgress;
|
|
251
|
+
let progressWriting = false;
|
|
252
|
+
let progressWrite = Promise.resolve();
|
|
253
|
+
const scheduleProgressWrite = () => {
|
|
254
|
+
if (progressWriting)
|
|
255
|
+
return;
|
|
256
|
+
progressWriting = true;
|
|
257
|
+
progressWrite = (async () => {
|
|
258
|
+
while (pendingProgress) {
|
|
259
|
+
const next = pendingProgress;
|
|
260
|
+
pendingProgress = undefined;
|
|
261
|
+
try {
|
|
262
|
+
await this.#options.write({
|
|
263
|
+
kind: 'client.capability.progress',
|
|
264
|
+
invocationId,
|
|
265
|
+
current: next.current,
|
|
266
|
+
total: next.total,
|
|
267
|
+
});
|
|
268
|
+
}
|
|
269
|
+
catch {
|
|
270
|
+
// Progress is advisory: a failed write must not fail the invocation.
|
|
271
|
+
return;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
})().finally(() => {
|
|
275
|
+
progressWriting = false;
|
|
276
|
+
});
|
|
277
|
+
};
|
|
278
|
+
const flushProgress = async () => {
|
|
279
|
+
do {
|
|
280
|
+
scheduleProgressWrite();
|
|
281
|
+
await progressWrite;
|
|
282
|
+
} while (pendingProgress);
|
|
283
|
+
};
|
|
250
284
|
try {
|
|
251
285
|
const progress = (current, total) => {
|
|
252
286
|
if (!accepted ||
|
|
@@ -255,17 +289,17 @@ export class ClientCapabilityChannel {
|
|
|
255
289
|
!Number.isInteger(total) ||
|
|
256
290
|
current < 0 ||
|
|
257
291
|
total < 1 ||
|
|
292
|
+
total > CLIENT_CAPABILITY_MAX_PROGRESS_TOTAL ||
|
|
258
293
|
current > total) {
|
|
259
294
|
return;
|
|
260
295
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
.catch((error) => this.#options.onFailure(asError(error)));
|
|
296
|
+
const previous = invocation.progress;
|
|
297
|
+
if (previous && (previous.total !== total || current <= previous.current)) {
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
invocation.progress = { current, total };
|
|
301
|
+
pendingProgress = { current, total };
|
|
302
|
+
scheduleProgressWrite();
|
|
269
303
|
};
|
|
270
304
|
const requestInteraction = async (request) => {
|
|
271
305
|
if (!accepted) {
|
|
@@ -315,6 +349,7 @@ export class ClientCapabilityChannel {
|
|
|
315
349
|
throw new Error('Client Capability provider returned with a pending interaction');
|
|
316
350
|
}
|
|
317
351
|
await accept({ kind: 'none' });
|
|
352
|
+
await flushProgress();
|
|
318
353
|
await this.#sendResult(invocationId, result, invocation);
|
|
319
354
|
}
|
|
320
355
|
catch (error) {
|
|
@@ -186,6 +186,25 @@ const COPY = {
|
|
|
186
186
|
/** Shared consequence-oriented copy, not a second lifecycle policy. */
|
|
187
187
|
export function formatHostHandoff(view, locale) {
|
|
188
188
|
const copy = COPY[locale];
|
|
189
|
+
const labels = {
|
|
190
|
+
cancel: copy.labels.cancel,
|
|
191
|
+
retry: view.manualRecheck ? copy.labels.recheck : copy.labels.retry,
|
|
192
|
+
replace: copy.labels.replace,
|
|
193
|
+
interrupt: view.manualRecheck
|
|
194
|
+
? copy.labels.interruptRecheck
|
|
195
|
+
: view.operation === 'repair'
|
|
196
|
+
? copy.labels.interruptRepair
|
|
197
|
+
: copy.labels.interrupt,
|
|
198
|
+
};
|
|
199
|
+
const actions = view.actions.map((action) => ({ action, label: labels[action] }));
|
|
200
|
+
if (view.state === 'progress') {
|
|
201
|
+
return {
|
|
202
|
+
title: copy.progressTitle,
|
|
203
|
+
description: copy.phases[view.phase],
|
|
204
|
+
detail: copy.progressDetail,
|
|
205
|
+
actions,
|
|
206
|
+
};
|
|
207
|
+
}
|
|
189
208
|
let title = copy.titles[view.reason];
|
|
190
209
|
let description = copy.descriptions(view.target.name)[view.reason];
|
|
191
210
|
if (view.recoveryBlocker && view.reason === 'operator_required') {
|
|
@@ -215,24 +234,12 @@ export function formatHostHandoff(view, locale) {
|
|
|
215
234
|
? copy.waiting.natural
|
|
216
235
|
: copy.waiting.blocked;
|
|
217
236
|
const repairNotice = view.operation === 'repair' ? copy.repairNotice : '';
|
|
218
|
-
const labels = {
|
|
219
|
-
cancel: copy.labels.cancel,
|
|
220
|
-
retry: view.manualRecheck ? copy.labels.recheck : copy.labels.retry,
|
|
221
|
-
replace: copy.labels.replace,
|
|
222
|
-
interrupt: view.manualRecheck
|
|
223
|
-
? copy.labels.interruptRecheck
|
|
224
|
-
: view.operation === 'repair'
|
|
225
|
-
? copy.labels.interruptRepair
|
|
226
|
-
: copy.labels.interrupt,
|
|
227
|
-
};
|
|
228
237
|
return {
|
|
229
|
-
title
|
|
230
|
-
description
|
|
231
|
-
detail: view.
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
.join('\n'),
|
|
236
|
-
actions: view.actions.map((action) => ({ action, label: labels[action] })),
|
|
238
|
+
title,
|
|
239
|
+
description,
|
|
240
|
+
detail: [packageChange, facts, backgroundFacts, waiting, repairNotice, view.operatorStep]
|
|
241
|
+
.filter(Boolean)
|
|
242
|
+
.join('\n'),
|
|
243
|
+
actions,
|
|
237
244
|
};
|
|
238
245
|
}
|
|
@@ -172,11 +172,13 @@ export async function runHostHandoff(input) {
|
|
|
172
172
|
? AbortSignal.any([input.signal, attemptAbort.signal])
|
|
173
173
|
: attemptAbort.signal;
|
|
174
174
|
const progress = (phase) => publish({
|
|
175
|
-
...current,
|
|
176
175
|
revision: randomUUID(),
|
|
176
|
+
target: current.target,
|
|
177
177
|
state: 'progress',
|
|
178
178
|
phase: cooperative && !interrupt && phase === 'retiring' ? 'pausing' : phase,
|
|
179
179
|
actions: cancelled ? [] : ['cancel'],
|
|
180
|
+
defaultAction: 'cancel',
|
|
181
|
+
mayExitNaturally: false,
|
|
180
182
|
});
|
|
181
183
|
if (input.openSurface)
|
|
182
184
|
surface ??= input.openSurface(submit);
|
|
@@ -30,7 +30,7 @@ export { RuntimeHostSshOperatorActivationError, activateRuntimeHostSshOperator,
|
|
|
30
30
|
export { normalizeRuntimeHostSshDestination, openRuntimeHostSshTunnel, } from './ssh-tunnel.js';
|
|
31
31
|
export { RuntimeHostPermanentReconnectError, startRuntimeHostReconnectLifecycle, } from './reconnect-lifecycle.js';
|
|
32
32
|
export { RUNTIME_HOST_REMOTE_INCOMPATIBLE_CODE, RuntimeHostRemoteCompatibilityError, } from './remote-compatibility-error.js';
|
|
33
|
-
export { RuntimeHostSubscriptionError, } from './session-subscription.js';
|
|
33
|
+
export { RuntimeHostSubscriptionError, SessionRemovedSubscriptionError, subscriptionClosedError, } from './session-subscription.js';
|
|
34
34
|
export { RuntimeHostStartupError, runtimeHostStartupError, } from './startup-error.js';
|
|
35
35
|
export { connectRuntimeHostWslEnvironment, listRuntimeHostWslDistributions, normalizeRuntimeHostWslDistribution, resolveSystemRuntimeHostWslExecutable, } from './wsl-environment.js';
|
|
36
36
|
export { RuntimeHostCatalogReadError, RuntimeHostSessionCatalogRevisionChangedError, readRuntimeHostConnectionCatalog, readRuntimeHostInvocableSkills, readRuntimeHostProjectDetails, readRuntimeHostResources, readRuntimeHostProjects, readRuntimeHostSessionCatalogPage, readRuntimeHostSessions, readRuntimeHostSkillCatalog, } from './catalog-reader.js';
|