clay-server 5.2.0-beta.5 → 5.2.0-beta.7
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/claude-hook-installer.js +1 -267
- package/lib/claude-jsonl-watcher.js +1 -204
- package/lib/clay-control-presentation-binding.js +96 -0
- package/lib/clay-control-presentation.js +128 -0
- package/lib/clay-control-target-projection.js +26 -0
- package/lib/clay-mate-chat.js +1 -0
- package/lib/clay-mate-knowledge.js +1 -1
- package/lib/clay-product-control-tools.js +1 -1
- package/lib/clay-product-control.js +22 -12
- package/lib/clay-project-records.js +2 -1
- package/lib/clay-scheduling.js +1 -1
- package/lib/clay-screen-controls.js +13 -5
- package/lib/clay-skill-install.js +1 -33
- package/lib/clay-workspace-controls.js +2 -1
- package/lib/cli-sessions.js +1 -300
- package/lib/codex-defaults.js +1 -28
- package/lib/context-usage.js +3 -2
- package/lib/contextual-screen-snapshot.js +38 -0
- package/lib/daemon.js +5 -55
- package/lib/default-ai-runtime.js +4 -8
- package/lib/email-mcp-server.js +1 -1
- package/lib/kiro-defaults.js +1 -22
- package/lib/mate-context-service.js +138 -0
- package/lib/mate-context-tools.js +21 -0
- package/lib/mcp-proxy.js +2 -32
- package/lib/mcp-query-bridge.js +1 -1
- package/lib/mcp-source-adapters.js +1 -91
- package/lib/mcp-source-context.js +1 -42
- package/lib/mcp-source-discovery.js +1 -169
- package/lib/mcp-source-plugins.js +1 -68
- package/lib/mcp-source-restrictions.js +1 -47
- package/lib/mcp-tool-policy.js +1 -26
- package/lib/os-user-diagnostics.js +2 -4
- package/lib/os-users.js +4 -65
- package/lib/project-connection.js +14 -10
- package/lib/project-control-git-view.js +12 -0
- package/lib/project-filesystem.js +5 -1
- package/lib/project-http.js +7 -4
- package/lib/project-mcp.js +2 -2
- package/lib/project-notifications.js +5 -4
- package/lib/project-pair-result-delivery.js +2 -2
- package/lib/project-pair-usage.js +12 -13
- package/lib/project-pending-message-queue.js +3 -1
- package/lib/project-product-control.js +3 -1
- package/lib/project-scheduled-messages.js +4 -4
- package/lib/project-scheduled-task-control.js +1 -1
- package/lib/project-session-document.js +20 -5
- package/lib/project-session-history-actions.js +5 -3
- package/lib/project-session-pair.js +1 -1
- package/lib/project-session-runtime-actions.js +2 -1
- package/lib/project-session-spawn.js +2 -3
- package/lib/project-session-vendor.js +2 -1
- package/lib/project-sessions.js +18 -26
- package/lib/project-shared-browser.js +22 -5
- package/lib/project-studio-presentation.js +58 -0
- package/lib/project-user-message.js +37 -0
- package/lib/project-vendor-login.js +6 -36
- package/lib/project-workspace-query.js +11 -1
- package/lib/project.js +24 -7
- package/lib/public/app.js +25 -0
- package/lib/public/appearance-bootstrap.js +2 -0
- package/lib/public/css/contextual-clay.css +240 -0
- package/lib/public/css/messages.css +6 -2
- package/lib/public/modules/app-favicon.js +18 -9
- package/lib/public/modules/app-header.js +4 -2
- package/lib/public/modules/app-loop-ui.js +2 -0
- package/lib/public/modules/app-message-router.js +5 -1
- package/lib/public/modules/app-messages.js +50 -6
- package/lib/public/modules/app-notifications.js +11 -5
- package/lib/public/modules/app-panels.js +61 -123
- package/lib/public/modules/app-projects.js +3 -0
- package/lib/public/modules/app-rate-limit.js +7 -27
- package/lib/public/modules/chat-render-runtime.js +3 -0
- package/lib/public/modules/clay-control-activity.js +214 -0
- package/lib/public/modules/clay-control-copy.js +36 -0
- package/lib/public/modules/clay-control-detail-targets.js +44 -0
- package/lib/public/modules/clay-control-object-targets.js +52 -0
- package/lib/public/modules/clay-control-target-visibility.js +12 -0
- package/lib/public/modules/clay-control-targets.js +44 -0
- package/lib/public/modules/clay-navigation-render.js +52 -0
- package/lib/public/modules/clay-owner-navigation.js +11 -2
- package/lib/public/modules/clay-session-links.js +31 -0
- package/lib/public/modules/clay-studio-bridge.js +20 -0
- package/lib/public/modules/clay-studio-document.js +67 -0
- package/lib/public/modules/clay-studio-render.js +144 -0
- package/lib/public/modules/clay-tool-presentation.js +4 -0
- package/lib/public/modules/command-palette.js +26 -31
- package/lib/public/modules/contextual-ask-session.js +26 -0
- package/lib/public/modules/contextual-clay-geometry.js +155 -0
- package/lib/public/modules/contextual-clay-session.js +130 -0
- package/lib/public/modules/contextual-clay-workspace.js +157 -0
- package/lib/public/modules/contextual-clay.js +237 -0
- package/lib/public/modules/contextual-composer.js +91 -0
- package/lib/public/modules/contextual-mate-context.js +115 -0
- package/lib/public/modules/contextual-mate-hint.js +40 -0
- package/lib/public/modules/contextual-mate-identity.js +23 -0
- package/lib/public/modules/contextual-mate-sessions.js +134 -0
- package/lib/public/modules/contextual-search.js +137 -0
- package/lib/public/modules/contextual-session-citations.js +58 -0
- package/lib/public/modules/filebrowser.js +20 -1
- package/lib/public/modules/generation-stop.js +8 -5
- package/lib/public/modules/git-panel.js +3 -1
- package/lib/public/modules/icon-strip-tooltip.js +2 -1
- package/lib/public/modules/input.js +35 -1
- package/lib/public/modules/issues-render.js +3 -2
- package/lib/public/modules/knowledge-db-workbench.js +4 -4
- package/lib/public/modules/markdown.js +2 -34
- package/lib/public/modules/mate-knowledge-workbench.js +1 -1
- package/lib/public/modules/mcp-connection-view.js +1 -1
- package/lib/public/modules/message-delivery.js +10 -0
- package/lib/public/modules/pane-bridge.js +2 -2
- package/lib/public/modules/pending-message-queue.js +1 -0
- package/lib/public/modules/permission-control.js +5 -4
- package/lib/public/modules/product-review.js +26 -0
- package/lib/public/modules/project-chat-identity.js +13 -4
- package/lib/public/modules/project-logs-render.js +3 -0
- package/lib/public/modules/project-mate-navigation.js +58 -21
- package/lib/public/modules/scheduled-tasks.js +2 -0
- package/lib/public/modules/scheduler.js +2 -0
- package/lib/public/modules/search-clay-chat.js +5 -454
- package/lib/public/modules/session-create-form.js +10 -10
- package/lib/public/modules/settings-defaults.js +27 -28
- package/lib/public/modules/shared-browser.js +2 -0
- package/lib/public/modules/sidebar-mobile.js +4 -3
- package/lib/public/modules/sidebar-projects.js +1 -0
- package/lib/public/modules/sidebar-sessions.js +1 -0
- package/lib/public/modules/split-view.js +7 -16
- package/lib/public/modules/terminal.js +9 -0
- package/lib/public/modules/tools.js +6 -2
- package/lib/public/modules/tui-grab.js +1 -2
- package/lib/public/modules/vendor-login-browser.js +5 -3
- package/lib/public/modules/vendor-login.js +2 -2
- package/lib/public/modules/vendor-priority.js +15 -1
- package/lib/public/modules/wireframe-workbench.js +5 -2
- package/lib/public/muse-avatar.svg +4 -0
- package/lib/public/style.css +2 -0
- package/lib/safe-bash-commands.js +3 -45
- package/lib/sdk-bridge.js +131 -395
- package/lib/sdk-foreground-admission.js +16 -0
- package/lib/sdk-mcp-descriptors.js +2 -37
- package/lib/sdk-message-processor.js +50 -17
- package/lib/sdk-quota-snapshot.js +1 -1
- package/lib/sdk-response-recovery.js +1 -155
- package/lib/sdk-worker.js +2 -677
- package/lib/server-contextual-clay-settings.js +40 -0
- package/lib/server-contextual-mate-sessions.js +70 -0
- package/lib/server-home-chat.js +7 -1
- package/lib/server-home-clay-entry.js +23 -4
- package/lib/server-home-clay-session-links.js +12 -0
- package/lib/server-owner-ui.js +49 -8
- package/lib/server-settings.js +2 -0
- package/lib/server.js +18 -1
- package/lib/session-fork-history.js +21 -0
- package/lib/session-hygiene.js +3 -35
- package/lib/session-permission-mode.js +4 -3
- package/lib/session-skill-scope.js +11 -0
- package/lib/sessions.js +24 -89
- package/lib/terminal-manager.js +18 -11
- package/lib/tool-llm.js +1 -1
- package/lib/tui-transcript-index.js +1 -132
- package/lib/users-contextual-clay-preferences.js +31 -0
- package/lib/users.js +3 -0
- package/lib/vendor-login-browser.js +1 -11
- package/lib/workspace-assignment-service.js +25 -0
- package/lib/workspace-query-mcp-server.js +1 -1
- package/lib/ws-request.js +1 -0
- package/lib/ws-schema.js +10 -0
- package/lib/yoke/acp-agent-profiles.js +5 -3
- package/lib/yoke/adapters/antigravity.js +3 -14
- package/lib/yoke/adapters/claude-query-contract.js +9 -0
- package/lib/yoke/adapters/claude.js +7 -42
- package/lib/yoke/adapters/codex-query-contract.js +24 -0
- package/lib/yoke/adapters/codex.js +1 -0
- package/lib/yoke/adapters/kiro.js +3 -1
- package/lib/yoke/adapters/muse-query-contract.js +7 -0
- package/lib/yoke/adapters/muse.js +122 -0
- package/lib/yoke/auth-events.js +17 -0
- package/lib/yoke/claude-hook-installer.js +271 -0
- package/lib/yoke/claude-jsonl-watcher.js +204 -0
- package/lib/yoke/claude-maintenance.js +55 -0
- package/lib/yoke/claude-permission-patterns.js +53 -0
- package/lib/yoke/claude-response-recovery.js +155 -0
- package/lib/yoke/claude-transcript-hygiene.js +34 -0
- package/lib/yoke/clay-skill-install.js +33 -0
- package/lib/yoke/cli-sessions.js +300 -0
- package/lib/yoke/codex-app-server.js +7 -12
- package/lib/yoke/configuration.js +13 -0
- package/lib/yoke/discovery.js +70 -0
- package/lib/yoke/errors.js +8 -0
- package/lib/yoke/host-environment.js +7 -0
- package/lib/yoke/index.js +9 -51
- package/lib/yoke/interface.js +116 -0
- package/lib/yoke/kiro-acp-server.js +5 -5
- package/lib/yoke/legacy-sessions.js +89 -0
- package/lib/yoke/login-protocol.js +25 -0
- package/lib/yoke/maintenance.js +12 -0
- package/lib/yoke/mcp-proxy.js +32 -0
- package/lib/yoke/mcp-source-adapters.js +91 -0
- package/lib/yoke/mcp-source-context.js +42 -0
- package/lib/yoke/mcp-source-discovery.js +169 -0
- package/lib/yoke/mcp-source-plugins.js +68 -0
- package/lib/yoke/mcp-source-restrictions.js +47 -0
- package/lib/yoke/mcp-tool-policy-normalize.js +28 -0
- package/lib/yoke/model-preferences.js +6 -0
- package/lib/yoke/muse-artifacts.js +36 -0
- package/lib/yoke/muse-controls.js +50 -0
- package/lib/yoke/muse-input.js +64 -0
- package/lib/yoke/muse-items.js +157 -0
- package/lib/yoke/muse-policy.js +52 -0
- package/lib/yoke/muse-query.js +428 -0
- package/lib/yoke/muse-runtime.js +211 -0
- package/lib/yoke/muse-services.js +79 -0
- package/lib/yoke/muse-skills.js +79 -0
- package/lib/yoke/muse-turns.js +71 -0
- package/lib/yoke/options/acp.js +2 -0
- package/lib/yoke/options/antigravity.js +2 -0
- package/lib/yoke/options/claude.js +21 -0
- package/lib/yoke/options/codex-defaults.js +29 -0
- package/lib/yoke/options/codex-settings.js +21 -0
- package/lib/yoke/options/codex.js +6 -0
- package/lib/yoke/options/kiro-defaults.js +22 -0
- package/lib/yoke/options/kiro.js +5 -0
- package/lib/yoke/options/muse.js +5 -0
- package/lib/yoke/provider-contract.js +5 -0
- package/lib/yoke/providers/antigravity-executable.js +8 -0
- package/lib/yoke/providers/claude-executable.js +40 -0
- package/lib/yoke/providers/claude-model-descriptions.js +14 -0
- package/lib/yoke/providers/claude-process.js +97 -0
- package/lib/yoke/providers/claude-provision.js +75 -0
- package/lib/yoke/providers/codex-errors.js +8 -0
- package/lib/yoke/providers/muse-executable.js +17 -0
- package/lib/yoke/provisioning.js +6 -0
- package/lib/yoke/query-options.js +10 -0
- package/lib/yoke/response-recovery.js +41 -0
- package/lib/yoke/sdk-mcp-descriptors.js +37 -0
- package/lib/yoke/sdk-server-factory.js +7 -0
- package/lib/yoke/session-history.js +8 -0
- package/lib/yoke/session-tool-transport.js +31 -13
- package/lib/yoke/settings.js +23 -0
- package/lib/yoke/source-locations.js +4 -0
- package/lib/yoke/title-query.js +18 -7
- package/lib/yoke/tui-transcript-index.js +132 -0
- package/lib/yoke/usage.js +48 -0
- package/lib/yoke/user-input.js +13 -0
- package/lib/yoke/vendor-registry.js +81 -1
- package/package.json +3 -2
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
var itemInput = require("./muse-items").itemInput;
|
|
2
|
+
|
|
3
|
+
function normalizeMcpServers(servers) {
|
|
4
|
+
var config = {};
|
|
5
|
+
if (servers == null) return config;
|
|
6
|
+
if (!Array.isArray(servers)) throw new Error("Invalid Muse session MCP servers");
|
|
7
|
+
for (var i = 0; i < servers.length; i++) {
|
|
8
|
+
var server = servers[i] || {};
|
|
9
|
+
if (!server.name || !server.command || typeof server.name !== "string" || typeof server.command !== "string" || !Array.isArray(server.args || [])) throw new Error("Invalid Muse session MCP server");
|
|
10
|
+
if (["__proto__", "constructor", "prototype"].includes(server.name) || Object.prototype.hasOwnProperty.call(config, server.name)) throw new Error("Invalid or duplicate Muse MCP server name");
|
|
11
|
+
var env = {};
|
|
12
|
+
var entries = Array.isArray(server.env) ? server.env : [];
|
|
13
|
+
for (var j = 0; j < entries.length; j++) if (entries[j] && entries[j].name) env[entries[j].name] = String(entries[j].value == null ? "" : entries[j].value);
|
|
14
|
+
config[server.name] = {
|
|
15
|
+
transport: "stdio",
|
|
16
|
+
command: server.command,
|
|
17
|
+
args: server.args || [],
|
|
18
|
+
env: env,
|
|
19
|
+
mode: "required"
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
return config;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function chooseApprovalDecision(request, canUseTool, signal) {
|
|
26
|
+
var choices = Array.isArray(request && request.availableChoices) ? request.availableChoices : [];
|
|
27
|
+
if (!choices.length || typeof canUseTool !== "function") return Promise.reject(new Error("Muse approval cannot be decided safely"));
|
|
28
|
+
if (signal && signal.aborted) return Promise.reject(new Error("Muse approval cancelled"));
|
|
29
|
+
return Promise.resolve(canUseTool(request.toolName || "Tool", itemInput({
|
|
30
|
+
args: request.rawArgs
|
|
31
|
+
}), {
|
|
32
|
+
request: request,
|
|
33
|
+
signal: signal
|
|
34
|
+
})).then(function(result) {
|
|
35
|
+
if (signal && signal.aborted) throw new Error("Muse approval cancelled");
|
|
36
|
+
var allowed = result && result.behavior === "allow";
|
|
37
|
+
if (!allowed && !(result && result.behavior === "deny")) throw new Error("Muse approval returned an unsupported decision");
|
|
38
|
+
for (var i = 0; i < choices.length; i++) if (choices[i].scope === "once" && (choices[i].decision === (allowed ? "approved" : "denied") || !allowed && choices[i].decision === "abort")) {
|
|
39
|
+
var decision = {
|
|
40
|
+
choiceId: choices[i].choiceId
|
|
41
|
+
};
|
|
42
|
+
if (choices[i].acceptsFeedback && result.message) decision.feedback = result.message;
|
|
43
|
+
return decision;
|
|
44
|
+
}
|
|
45
|
+
throw new Error("Muse approval has no matching safe choice");
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
module.exports = {
|
|
50
|
+
normalizeMcpServers: normalizeMcpServers,
|
|
51
|
+
chooseApprovalDecision: chooseApprovalDecision
|
|
52
|
+
};
|
|
@@ -0,0 +1,428 @@
|
|
|
1
|
+
var queryAbort = require("./query-abort");
|
|
2
|
+
|
|
3
|
+
var runtimeTools = require("./muse-runtime");
|
|
4
|
+
|
|
5
|
+
var policy = require("./muse-policy");
|
|
6
|
+
|
|
7
|
+
function createMuseQueryHandle(adapter, queryOpts) {
|
|
8
|
+
var state = {
|
|
9
|
+
client: null,
|
|
10
|
+
connection: null,
|
|
11
|
+
session: null,
|
|
12
|
+
sessionId: queryOpts.resumeSessionId || null,
|
|
13
|
+
model: queryOpts.model || null,
|
|
14
|
+
effort: queryOpts.effort || null,
|
|
15
|
+
toolPolicy: "ask",
|
|
16
|
+
messages: [],
|
|
17
|
+
messageSequence: 0,
|
|
18
|
+
active: false,
|
|
19
|
+
ended: false,
|
|
20
|
+
inputEnded: false,
|
|
21
|
+
stopped: false,
|
|
22
|
+
events: [],
|
|
23
|
+
waiter: null,
|
|
24
|
+
textBlocks: {},
|
|
25
|
+
thinkingBlocks: {},
|
|
26
|
+
toolBlocks: {},
|
|
27
|
+
activeTurn: null,
|
|
28
|
+
liveTurnIds: new Set(),
|
|
29
|
+
abortController: queryOpts.abortController || new AbortController(),
|
|
30
|
+
started: false
|
|
31
|
+
};
|
|
32
|
+
var removeAbort = function() {};
|
|
33
|
+
var handle;
|
|
34
|
+
var failure = null;
|
|
35
|
+
var cleanup = null;
|
|
36
|
+
var runtime = null;
|
|
37
|
+
var itemFrames = [];
|
|
38
|
+
var skillDelivery = require("./muse-skills").create(Object.assign({}, queryOpts, { cwd: queryOpts.cwd || adapter.cwd }), function() { return runtime; }, push, assertLive);
|
|
39
|
+
var emitArtifact = require("./muse-artifacts").create(function() { return runtime; }, push);
|
|
40
|
+
var renderer = require("./muse-items").createRenderer(state, push);
|
|
41
|
+
var turns = require("./muse-turns").create({ state: state, renderer: renderer, emitArtifact: emitArtifact,
|
|
42
|
+
runtime: function() { return runtime; }, ready: flushFrames, push: push, outcomeEvent: outcomeEvent, fail: fail, close: function() { return handle.close(); } });
|
|
43
|
+
function push(event) {
|
|
44
|
+
if (state.stopped || state.ended) return;
|
|
45
|
+
if (state.waiter) {
|
|
46
|
+
var resolve = state.waiter;
|
|
47
|
+
state.waiter = null;
|
|
48
|
+
resolve({
|
|
49
|
+
value: event,
|
|
50
|
+
done: false
|
|
51
|
+
});
|
|
52
|
+
} else state.events.push(event);
|
|
53
|
+
}
|
|
54
|
+
function finish() {
|
|
55
|
+
if (state.waiter) {
|
|
56
|
+
var resolve = state.waiter;
|
|
57
|
+
state.waiter = null;
|
|
58
|
+
resolve({
|
|
59
|
+
value: undefined,
|
|
60
|
+
done: true
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function assertLive() {
|
|
65
|
+
if (state.stopped || state.ended || adapter.shuttingDown) throw new Error("Muse Code query was stopped");
|
|
66
|
+
}
|
|
67
|
+
function activateTurn(turn) {
|
|
68
|
+
state.activeTurn = turn;
|
|
69
|
+
}
|
|
70
|
+
function flushFrames() {
|
|
71
|
+
var frames = itemFrames.splice(0);
|
|
72
|
+
for (var i = 0; i < frames.length; i++) renderer.renderFrame(frames[i]);
|
|
73
|
+
}
|
|
74
|
+
function chooseApproval(request) {
|
|
75
|
+
if (state.stopped || state.abortController.signal.aborted) return Promise.reject(new Error("Muse approval cancelled"));
|
|
76
|
+
return runtime.wait(policy.chooseApprovalDecision(request, queryOpts.canUseTool, state.abortController.signal));
|
|
77
|
+
}
|
|
78
|
+
function fail(error) {
|
|
79
|
+
if (state.stopped || failure) return;
|
|
80
|
+
failure = error;
|
|
81
|
+
state.messages = [];
|
|
82
|
+
push(runtimeTools.isAuthError(error) ? {
|
|
83
|
+
yokeType: "auth_required",
|
|
84
|
+
vendor: "muse"
|
|
85
|
+
} : {
|
|
86
|
+
yokeType: "error",
|
|
87
|
+
text: error.message || String(error)
|
|
88
|
+
});
|
|
89
|
+
handle.close().catch(function(closeError) {
|
|
90
|
+
adapter.lastCloseError = closeError;
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
async function selectModel(model) {
|
|
94
|
+
if (!model) return null;
|
|
95
|
+
if (!adapter.catalog.some(function(row) {
|
|
96
|
+
return row.value === model;
|
|
97
|
+
})) {
|
|
98
|
+
var result = await runtime.waitRequest(state.connection.request("model/list", {}));
|
|
99
|
+
adapter.catalog = runtimeTools.normalizeCatalog(result);
|
|
100
|
+
}
|
|
101
|
+
assertLive();
|
|
102
|
+
return runtimeTools.modelSelection(adapter.catalog, model);
|
|
103
|
+
}
|
|
104
|
+
function validateEffort(effort) {
|
|
105
|
+
var vocabulary = [ "none", "minimal", "low", "medium", "high", "xhigh", "max", "ultra" ];
|
|
106
|
+
if (!vocabulary.includes(effort)) throw new Error("Unsupported Muse reasoning effort: " + effort);
|
|
107
|
+
var row = adapter.catalog.find(function(model) {
|
|
108
|
+
return model.value === state.model;
|
|
109
|
+
});
|
|
110
|
+
if (row && !row.effortUnknown && !row.supportedEffortLevels.includes(effort)) {
|
|
111
|
+
throw new Error("Muse model does not support reasoning effort: " + effort);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
async function ensureSession() {
|
|
115
|
+
assertLive();
|
|
116
|
+
if (state.session) return state.session;
|
|
117
|
+
var sdk = await adapter.loadSdk();
|
|
118
|
+
assertLive();
|
|
119
|
+
runtime = runtimeTools.createRuntime(adapter, sdk, {
|
|
120
|
+
command: adapter.binaryPath,
|
|
121
|
+
args: [ "serve" ],
|
|
122
|
+
cwd: queryOpts.cwd || adapter.cwd,
|
|
123
|
+
userInputDialogs: queryOpts.userInputMode !== "fallback" && typeof queryOpts.onUserInputRequest === "function",
|
|
124
|
+
env: Object.assign({}, process.env, queryOpts.env || {})
|
|
125
|
+
});
|
|
126
|
+
runtime.fail = fail;
|
|
127
|
+
runtime.onUserInput = require("./muse-input").createRouter(runtime, queryOpts, state.abortController.signal);
|
|
128
|
+
runtime.onFrame = function(frame) {
|
|
129
|
+
turns.onFrame(frame);
|
|
130
|
+
if (frame.method.indexOf("item/") === 0) {
|
|
131
|
+
if (!renderer.renderFrame(frame)) itemFrames.push(frame);
|
|
132
|
+
}
|
|
133
|
+
if (frame.method === "session/modelChanged") {
|
|
134
|
+
var previousModel = state.model;
|
|
135
|
+
state.model = frame.params.modelId;
|
|
136
|
+
if (typeof queryOpts.onModelSwitch === "function" && previousModel && previousModel !== state.model) queryOpts.onModelSwitch({ fromModel: previousModel, toModel: state.model, source: frame.params.source });
|
|
137
|
+
}
|
|
138
|
+
if (frame.method === "userInput/settled") runtime.onUserInput.settle(frame.params.userInputId);
|
|
139
|
+
if (frame.method === "userInput/requested") runtime.onUserInput(frame.params).catch(fail);
|
|
140
|
+
if (frame.method === "usage/changed") {
|
|
141
|
+
var quota = require("./muse-services").quotaEvent(frame.params);
|
|
142
|
+
if (quota) push(quota);
|
|
143
|
+
}
|
|
144
|
+
if (frame.method === "session/contextUsage") state.contextUsage = frame.params;
|
|
145
|
+
if (frame.method === "approval/requested" && queryOpts.resumeSessionId && !state.started) {
|
|
146
|
+
state.resumedTurnId = state.resumedTurnId || frame.params.turnId;
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
var spawned = await runtime.initialize();
|
|
150
|
+
assertLive();
|
|
151
|
+
state.connection = spawned.connection;
|
|
152
|
+
var museOpts = queryOpts.adapterOptions && queryOpts.adapterOptions.MUSE || {};
|
|
153
|
+
var mcpServers = policy.normalizeMcpServers(museOpts.mcpServers);
|
|
154
|
+
var hasMcp = Object.keys(mcpServers).length > 0;
|
|
155
|
+
var config = hasMcp ? {
|
|
156
|
+
mcpServers: mcpServers
|
|
157
|
+
} : undefined;
|
|
158
|
+
if (hasMcp && !(spawned.initializeResult.grantedCapabilities || []).includes("sessionMcp")) {
|
|
159
|
+
throw new Error("Muse host does not support the required sessionMcp capability");
|
|
160
|
+
}
|
|
161
|
+
var selection = await selectModel(state.model);
|
|
162
|
+
if (state.effort) validateEffort(state.effort);
|
|
163
|
+
var verb = state.sessionId ? "session/resume" : "session/start";
|
|
164
|
+
var params = state.sessionId ? {
|
|
165
|
+
sessionId: state.sessionId,
|
|
166
|
+
config: config,
|
|
167
|
+
history: "inline"
|
|
168
|
+
} : {
|
|
169
|
+
workspaceRoot: queryOpts.cwd || adapter.cwd,
|
|
170
|
+
config: config,
|
|
171
|
+
approvalMode: museOpts.readOnly ? "denyUnmatched" : "onRequest"
|
|
172
|
+
};
|
|
173
|
+
if (selection && verb === "session/start") {
|
|
174
|
+
params.modelId = selection.modelId;
|
|
175
|
+
if (selection.providerId) params.providerId = selection.providerId;
|
|
176
|
+
}
|
|
177
|
+
var result = await runtime.waitRequest(state.connection.command(verb, params));
|
|
178
|
+
assertLive();
|
|
179
|
+
state.sessionId = result.session.sessionId;
|
|
180
|
+
var opening = {
|
|
181
|
+
verb: verb,
|
|
182
|
+
result: result
|
|
183
|
+
};
|
|
184
|
+
state.session = new sdk.Session({
|
|
185
|
+
connection: state.connection,
|
|
186
|
+
durability: sdk.readSessionDurability(spawned.initializeResult),
|
|
187
|
+
opening: opening,
|
|
188
|
+
sessionId: state.sessionId
|
|
189
|
+
});
|
|
190
|
+
runtime.session = state.session;
|
|
191
|
+
state.session.onApproval(chooseApproval);
|
|
192
|
+
state.session.onApprovalError(function(problem) {
|
|
193
|
+
fail(problem.error || new Error("Muse approval failed: " + problem.kind));
|
|
194
|
+
});
|
|
195
|
+
state.session.onGapError(function(problem) {
|
|
196
|
+
fail(problem.error || new Error("Muse view gap could not be filled"));
|
|
197
|
+
});
|
|
198
|
+
runtimeTools.seedHistory(state.session, opening, runtime.onFrame);
|
|
199
|
+
state.resumedTurnId = state.session.fold.activeTurnId;
|
|
200
|
+
state.contextUsage = result.history && result.history.snapshot && result.history.snapshot.state.contextUsage || null;
|
|
201
|
+
runtime.opening = false;
|
|
202
|
+
var held = runtime.held.splice(0);
|
|
203
|
+
for (var i = 0; i < held.length; i++) runtime.apply(held[i]);
|
|
204
|
+
assertLive();
|
|
205
|
+
if (runtime.dead) throw new Error("Muse host exited while opening the session");
|
|
206
|
+
if (verb === "session/resume") {
|
|
207
|
+
await runtime.waitRequest(state.connection.command("session/setApprovalMode", {
|
|
208
|
+
sessionId: state.sessionId,
|
|
209
|
+
mode: museOpts.readOnly ? "denyUnmatched" : "onRequest"
|
|
210
|
+
}));
|
|
211
|
+
if (selection) await runtime.waitRequest(state.connection.command("session/setModel", {
|
|
212
|
+
sessionId: state.sessionId,
|
|
213
|
+
model: selection
|
|
214
|
+
}));
|
|
215
|
+
}
|
|
216
|
+
assertLive();
|
|
217
|
+
if (verb === "session/resume") {
|
|
218
|
+
state.resumedTurnId = state.resumedTurnId || result.session.activeTurnId || state.session.fold.activeTurnId;
|
|
219
|
+
if ((result.pendingRequests || []).length) {
|
|
220
|
+
var pending = await runtime.waitRequest(state.connection.request("approval/listPending", {
|
|
221
|
+
sessionId: state.sessionId
|
|
222
|
+
}));
|
|
223
|
+
for (var promptIndex = 0; promptIndex < (pending.userInputs || []).length; promptIndex++) {
|
|
224
|
+
var promptRequest = pending.userInputs[promptIndex];
|
|
225
|
+
state.resumedTurnId = state.resumedTurnId || promptRequest.turnId;
|
|
226
|
+
runtime.onUserInput(promptRequest).catch(fail);
|
|
227
|
+
}
|
|
228
|
+
for (var pendingIndex = 0; pendingIndex < (pending.approvals || []).length; pendingIndex++) {
|
|
229
|
+
var approval = pending.approvals[pendingIndex];
|
|
230
|
+
state.resumedTurnId = state.resumedTurnId || approval.turnId;
|
|
231
|
+
runtime.apply({
|
|
232
|
+
method: "approval/requested",
|
|
233
|
+
params: approval
|
|
234
|
+
});
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
assertLive();
|
|
239
|
+
push({
|
|
240
|
+
yokeType: "session_started",
|
|
241
|
+
sessionId: state.sessionId
|
|
242
|
+
});
|
|
243
|
+
return state.session;
|
|
244
|
+
}
|
|
245
|
+
function outcomeEvent(outcome) {
|
|
246
|
+
if (!outcome || outcome.kind === "unqueued" || outcome.kind === "completed" && outcome.params && (outcome.params.terminal === "cancelled" || outcome.params.terminal === "cancelledByUser")) return {
|
|
247
|
+
yokeType: "interrupted"
|
|
248
|
+
};
|
|
249
|
+
if (outcome.kind === "terminalUnknown") return {
|
|
250
|
+
yokeType: "error",
|
|
251
|
+
text: "Muse host exited before the turn outcome was known"
|
|
252
|
+
};
|
|
253
|
+
var params = outcome.params || {};
|
|
254
|
+
if (params.terminal === "failed") return params.error && params.error.kind === "authRequired" ? {
|
|
255
|
+
yokeType: "auth_required",
|
|
256
|
+
vendor: "muse"
|
|
257
|
+
} : {
|
|
258
|
+
yokeType: "error",
|
|
259
|
+
text: params.error && params.error.message || params.reason || "Muse Code turn failed."
|
|
260
|
+
};
|
|
261
|
+
if (params.terminal !== "completed") return {
|
|
262
|
+
yokeType: "error",
|
|
263
|
+
text: "Unknown Muse turn outcome: " + params.terminal
|
|
264
|
+
};
|
|
265
|
+
return {
|
|
266
|
+
yokeType: "result",
|
|
267
|
+
messageType: "assistant",
|
|
268
|
+
sessionId: state.sessionId,
|
|
269
|
+
usage: params.usage ? {
|
|
270
|
+
input_tokens: params.usage.inputTokens,
|
|
271
|
+
output_tokens: params.usage.outputTokens,
|
|
272
|
+
cache_read_input_tokens: params.usage.cacheReadTokens == null ? params.usage.cachedTokens : params.usage.cacheReadTokens,
|
|
273
|
+
cache_creation_input_tokens: params.usage.cacheWriteTokens || 0
|
|
274
|
+
} : null,
|
|
275
|
+
cost: null,
|
|
276
|
+
duration: params.durationMs || null
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
async function runMessage(text, images, skill, sequence) {
|
|
280
|
+
state.active = true;
|
|
281
|
+
try {
|
|
282
|
+
var session = await ensureSession();
|
|
283
|
+
assertLive();
|
|
284
|
+
if (state.resumedTurnId) {
|
|
285
|
+
var resumed = session.turn(state.resumedTurnId);
|
|
286
|
+
state.resumedTurnId = null;
|
|
287
|
+
activateTurn(resumed);
|
|
288
|
+
var resumedBoundary = await turns.follow(resumed, false);
|
|
289
|
+
assertLive();
|
|
290
|
+
if (resumedBoundary.kind === "failed" || resumedBoundary.event && resumedBoundary.event.yokeType !== "result") return;
|
|
291
|
+
push({ yokeType: "runtime_specific", vendor: "muse",
|
|
292
|
+
eventType: resumedBoundary.kind === "foreground" ? "resumed_foreground_completed" : "resumed_turn_completed", raw: resumedBoundary.outcome });
|
|
293
|
+
}
|
|
294
|
+
var prepared = await skillDelivery.prepare(text || "", skill);
|
|
295
|
+
assertLive();
|
|
296
|
+
skill = prepared.skill;
|
|
297
|
+
var prompt = prepared.text;
|
|
298
|
+
if (!state.started) {
|
|
299
|
+
state.started = true;
|
|
300
|
+
prompt = [ queryOpts.systemPrompt, queryOpts.appendSystemPrompt, prompt ].filter(function(part) {
|
|
301
|
+
return !!part;
|
|
302
|
+
}).join("\n\n");
|
|
303
|
+
}
|
|
304
|
+
state.activeTurn = null;
|
|
305
|
+
if (prepared.scoped) skillDelivery.check();
|
|
306
|
+
push({ yokeType: "turn_activity", phase: "waiting" });
|
|
307
|
+
var turn = await runtime.wait(session.sendUserTurn({
|
|
308
|
+
input: require("./muse-input").inputParts(prompt, images).concat(skill ? [{ type: "skill", selector: skill.selector, arguments: skill.arguments }] : []),
|
|
309
|
+
reasoningEffort: state.effort || undefined
|
|
310
|
+
}));
|
|
311
|
+
assertLive();
|
|
312
|
+
activateTurn(turn);
|
|
313
|
+
await turns.follow(turn, true, sequence);
|
|
314
|
+
} catch (e) {
|
|
315
|
+
fail(e);
|
|
316
|
+
} finally {
|
|
317
|
+
state.active = false;
|
|
318
|
+
state.activeTurn = null;
|
|
319
|
+
if (state.messages.length && !state.stopped) {
|
|
320
|
+
var next = state.messages.shift();
|
|
321
|
+
runMessage(next.text, next.images, next.skill, next.sequence).catch(function(error) {
|
|
322
|
+
adapter.lastCloseError = error;
|
|
323
|
+
});
|
|
324
|
+
} else if (state.inputEnded && !turns.pending()) await handle.close();
|
|
325
|
+
else if (!state.stopped && turns.background()) push({ yokeType: "foreground_available" });
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
handle = {
|
|
329
|
+
[Symbol.asyncIterator]: function() {
|
|
330
|
+
return {
|
|
331
|
+
next: function() {
|
|
332
|
+
if (state.events.length) return Promise.resolve({
|
|
333
|
+
value: state.events.shift(),
|
|
334
|
+
done: false
|
|
335
|
+
});
|
|
336
|
+
if (state.ended) return Promise.resolve({
|
|
337
|
+
value: undefined,
|
|
338
|
+
done: true
|
|
339
|
+
});
|
|
340
|
+
return new Promise(function(resolve) {
|
|
341
|
+
state.waiter = resolve;
|
|
342
|
+
});
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
},
|
|
346
|
+
pushMessage: function(text, images, skill) {
|
|
347
|
+
if (state.stopped || state.ended || state.inputEnded) return false;
|
|
348
|
+
state.messages.push({
|
|
349
|
+
text: text, sequence: ++state.messageSequence,
|
|
350
|
+
images: images, skill: skill
|
|
351
|
+
});
|
|
352
|
+
if (!state.active) {
|
|
353
|
+
var next = state.messages.shift();
|
|
354
|
+
runMessage(next.text, next.images, next.skill, next.sequence).catch(function(error) {
|
|
355
|
+
adapter.lastCloseError = error;
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
return true;
|
|
359
|
+
},
|
|
360
|
+
// Clay's callback remains the authority even when its UI permits all tools.
|
|
361
|
+
setToolPolicy: async function(value) {
|
|
362
|
+
assertLive();
|
|
363
|
+
if (["ask", "allow-all"].indexOf(value) < 0) throw new Error("Unsupported Muse tool policy: " + value);
|
|
364
|
+
state.toolPolicy = value;
|
|
365
|
+
return { policy: value, nativeApprovalMode: "onRequest", authority: "canUseTool" };
|
|
366
|
+
},
|
|
367
|
+
stopTask: async function(taskId) {
|
|
368
|
+
assertLive();
|
|
369
|
+
if (!taskId) return handle.abort();
|
|
370
|
+
if (!state.connection || !state.session) throw new Error("Muse task stop requires an opened session");
|
|
371
|
+
await runtime.waitRequest(state.connection.command("task/stop", {
|
|
372
|
+
sessionId: state.sessionId,
|
|
373
|
+
taskId: taskId
|
|
374
|
+
}));
|
|
375
|
+
},
|
|
376
|
+
getContextUsage: function() {
|
|
377
|
+
var context = state.contextUsage;
|
|
378
|
+
return Promise.resolve(context ? {
|
|
379
|
+
input_tokens: context.usedTokens,
|
|
380
|
+
contextWindow: context.windowTokens
|
|
381
|
+
} : null);
|
|
382
|
+
},
|
|
383
|
+
endInput: function() {
|
|
384
|
+
state.inputEnded = true;
|
|
385
|
+
if (!state.active && !state.messages.length && !turns.pending()) handle.close().catch(function(error) {
|
|
386
|
+
adapter.lastCloseError = error;
|
|
387
|
+
});
|
|
388
|
+
},
|
|
389
|
+
abort: function() {
|
|
390
|
+
if (state.ended || state.stopped) return cleanup;
|
|
391
|
+
state.events = [];
|
|
392
|
+
var liveTurns = new Set(state.liveTurnIds);
|
|
393
|
+
if (state.activeTurn) liveTurns.add(state.activeTurn.turnId);
|
|
394
|
+
if (state.connection) liveTurns.forEach(function(turnId) {
|
|
395
|
+
state.connection.command("turn/cancel", { sessionId: state.sessionId, turnId: turnId }).catch(function(error) {
|
|
396
|
+
adapter.lastCancelError = error;
|
|
397
|
+
});
|
|
398
|
+
});
|
|
399
|
+
push({
|
|
400
|
+
yokeType: "interrupted"
|
|
401
|
+
});
|
|
402
|
+
return handle.close();
|
|
403
|
+
},
|
|
404
|
+
close: function() {
|
|
405
|
+
if (cleanup) return cleanup;
|
|
406
|
+
state.stopped = true;
|
|
407
|
+
state.inputEnded = true;
|
|
408
|
+
state.messages = [];
|
|
409
|
+
state.ended = true;
|
|
410
|
+
removeAbort();
|
|
411
|
+
state.abortController.abort();
|
|
412
|
+
finish();
|
|
413
|
+
adapter.handles.delete(handle);
|
|
414
|
+
cleanup = runtime ? runtime.close() : Promise.resolve();
|
|
415
|
+
return cleanup;
|
|
416
|
+
}
|
|
417
|
+
};
|
|
418
|
+
Object.assign(handle, require("./muse-controls").create({ state: state, assertLive: assertLive, selectModel: selectModel, validateEffort: validateEffort, skills: skillDelivery, runtime: function() { return runtime; }, handle: handle }));
|
|
419
|
+
adapter.handles.add(handle);
|
|
420
|
+
removeAbort = queryAbort.bindAbort(state.abortController, function() {
|
|
421
|
+
handle.abort();
|
|
422
|
+
});
|
|
423
|
+
return handle;
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
module.exports = {
|
|
427
|
+
createMuseQueryHandle: createMuseQueryHandle
|
|
428
|
+
};
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
var queryAbort = require("./query-abort");
|
|
2
|
+
|
|
3
|
+
var initializeTimeoutMs = require("./interface").INITIALIZE_TIMEOUT_MS;
|
|
4
|
+
|
|
5
|
+
function isAuthError(error) {
|
|
6
|
+
var kind = error && (error.kind || error.data && error.data.kind);
|
|
7
|
+
return kind === "authRequired" || /authentication|not authenticated|sign[ -]?in|log[ -]?in|credential|unauthorized|forbidden|api.?key|401/i.test(String(error && error.message || error || ""));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function closeResource(resource) {
|
|
11
|
+
if (!resource || typeof resource.close !== "function") return Promise.resolve();
|
|
12
|
+
return Promise.resolve().then(function() {
|
|
13
|
+
return resource.close();
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
// Own the process before initialize starts, including callers still opening a session.
|
|
17
|
+
|
|
18
|
+
function createRuntime(adapter, sdk, options) {
|
|
19
|
+
var scope = queryAbort.createAbortScope();
|
|
20
|
+
var handshake = sdk.spawnMspConnection(Object.assign({}, options, {
|
|
21
|
+
shutdownTimeoutMs: adapter.shutdownTimeoutMs
|
|
22
|
+
}));
|
|
23
|
+
var closing = null;
|
|
24
|
+
var runtime = {
|
|
25
|
+
handshake: handshake,
|
|
26
|
+
spawned: null,
|
|
27
|
+
connection: null,
|
|
28
|
+
session: null,
|
|
29
|
+
held: [],
|
|
30
|
+
opening: true,
|
|
31
|
+
dead: false,
|
|
32
|
+
wait: scope.wait,
|
|
33
|
+
check: scope.check,
|
|
34
|
+
waitRequest: async function(promise, timeoutMs) {
|
|
35
|
+
var timer;
|
|
36
|
+
try {
|
|
37
|
+
return await scope.wait(Promise.race([ promise, new Promise(function(resolve, reject) {
|
|
38
|
+
timer = setTimeout(function() {
|
|
39
|
+
reject(new Error("Muse Code request timed out"));
|
|
40
|
+
}, timeoutMs || adapter.requestTimeoutMs);
|
|
41
|
+
}) ]));
|
|
42
|
+
} finally {
|
|
43
|
+
clearTimeout(timer);
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
fail: function(error) {},
|
|
47
|
+
onFrame: function(frame) {},
|
|
48
|
+
apply: function(frame) {
|
|
49
|
+
if (!runtime.session || scope.stopped()) return;
|
|
50
|
+
var named = frame.params && frame.params.sessionId;
|
|
51
|
+
if (named !== runtime.session.sessionId) return;
|
|
52
|
+
if (frame.method === "view/gap") {
|
|
53
|
+
runtime.fail(new Error("Muse view stream has a gap; Stop retired this attempt. Resume explicitly to reconcile the session."));
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
try {
|
|
57
|
+
var applied = runtime.session.apply(frame);
|
|
58
|
+
if (applied.fold.kind !== "item" || applied.fold.outcome.kind !== "ignoredStaleRevision") runtime.onFrame(frame);
|
|
59
|
+
} catch (error) {
|
|
60
|
+
runtime.fail(error);
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
close: function() {
|
|
64
|
+
if (closing) return closing;
|
|
65
|
+
scope.stop();
|
|
66
|
+
if (runtime.session) runtime.session.hostExited({
|
|
67
|
+
kind: "transportEof"
|
|
68
|
+
});
|
|
69
|
+
closing = closeResource(handshake).finally(function() {
|
|
70
|
+
adapter.clients.delete(runtime);
|
|
71
|
+
});
|
|
72
|
+
return closing;
|
|
73
|
+
},
|
|
74
|
+
initialize: async function() {
|
|
75
|
+
try {
|
|
76
|
+
runtime.spawned = await runtime.waitRequest(handshake.initialize({
|
|
77
|
+
clientInfo: {
|
|
78
|
+
name: "clay",
|
|
79
|
+
title: "Clay",
|
|
80
|
+
version: "1.0.0"
|
|
81
|
+
},
|
|
82
|
+
capabilities: {
|
|
83
|
+
requestedCapabilities: [ "sessionMcp" ],
|
|
84
|
+
userInputDialogs: options.userInputDialogs === true
|
|
85
|
+
}
|
|
86
|
+
}), initializeTimeoutMs);
|
|
87
|
+
runtime.connection = runtime.spawned.connection;
|
|
88
|
+
runtime.connection.onProtocolError(function(error) {
|
|
89
|
+
runtime.fail(error);
|
|
90
|
+
});
|
|
91
|
+
runtime.connection.closed.then(function() {
|
|
92
|
+
if (scope.stopped()) return;
|
|
93
|
+
runtime.dead = true;
|
|
94
|
+
if (runtime.session) runtime.session.hostExited({
|
|
95
|
+
kind: "transportEof"
|
|
96
|
+
});
|
|
97
|
+
runtime.fail(new Error("Muse Code transport closed unexpectedly"));
|
|
98
|
+
});
|
|
99
|
+
return runtime.spawned;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
await runtime.close();
|
|
102
|
+
throw error;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
function route(frame) {
|
|
107
|
+
if (scope.stopped()) return;
|
|
108
|
+
if (frame.method === "usage/changed") { runtime.onFrame(frame); return; }
|
|
109
|
+
if (runtime.opening) runtime.held.push(frame); else runtime.apply(frame);
|
|
110
|
+
}
|
|
111
|
+
handshake.onServerRequest(async function(request) {
|
|
112
|
+
if (request.method === "approval/request") {
|
|
113
|
+
route({
|
|
114
|
+
method: "approval/requested",
|
|
115
|
+
params: request.params
|
|
116
|
+
});
|
|
117
|
+
return {};
|
|
118
|
+
}
|
|
119
|
+
if (request.method === "userInput/request" && typeof runtime.onUserInput === "function") {
|
|
120
|
+
route({ method: "userInput/requested", params: request.params });
|
|
121
|
+
return {};
|
|
122
|
+
}
|
|
123
|
+
var error = new Error("Muse host requested an unsupported client dialog: " + request.method);
|
|
124
|
+
runtime.fail(error);
|
|
125
|
+
throw error;
|
|
126
|
+
});
|
|
127
|
+
adapter.clients.add(runtime);
|
|
128
|
+
handshake.onNotification(route);
|
|
129
|
+
if (typeof handshake.onProtocolError === "function") handshake.onProtocolError(function(error) {
|
|
130
|
+
runtime.fail(error);
|
|
131
|
+
});
|
|
132
|
+
if (handshake.child && handshake.child.exit) handshake.child.exit.then(function(exit) {
|
|
133
|
+
runtime.dead = true;
|
|
134
|
+
if (runtime.session) runtime.session.hostExited(exit);
|
|
135
|
+
if (!scope.stopped()) runtime.fail(new Error("Muse Code host exited: " + exit.kind));
|
|
136
|
+
}, function(error) {
|
|
137
|
+
if (!scope.stopped()) runtime.fail(error);
|
|
138
|
+
});
|
|
139
|
+
return runtime;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function normalizeCatalog(result) {
|
|
143
|
+
return (result.models || []).map(function(model) {
|
|
144
|
+
return {
|
|
145
|
+
value: model.modelId,
|
|
146
|
+
displayName: model.displayLabel || model.modelId,
|
|
147
|
+
description: model.description || "",
|
|
148
|
+
supportedEffortLevels: Array.isArray(model.variants) ? model.variants.filter(function(tier) {
|
|
149
|
+
return ["none", "minimal", "low", "medium", "high", "xhigh", "max", "ultra"].includes(tier);
|
|
150
|
+
}) : [],
|
|
151
|
+
providerId: model.providerId || result.providerId,
|
|
152
|
+
profileId: model.profileId == null ? result.profileId : model.profileId,
|
|
153
|
+
defaultReasoningEffort: model.defaultReasoningEffort,
|
|
154
|
+
isDefault: model.isDefault === true,
|
|
155
|
+
effortUnknown: !Array.isArray(model.variants),
|
|
156
|
+
catalogSource: result.source
|
|
157
|
+
};
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function modelSelection(catalog, model) {
|
|
162
|
+
for (var i = 0; i < catalog.length; i++) {
|
|
163
|
+
if (catalog[i].value !== model) continue;
|
|
164
|
+
var selection = {
|
|
165
|
+
modelId: model,
|
|
166
|
+
displayLabel: catalog[i].displayName
|
|
167
|
+
};
|
|
168
|
+
if (catalog[i].providerId) selection.providerId = catalog[i].providerId;
|
|
169
|
+
if (catalog[i].profileId != null) selection.profileId = catalog[i].profileId;
|
|
170
|
+
return selection;
|
|
171
|
+
}
|
|
172
|
+
throw new Error("Muse model is not in the live model catalog: " + model);
|
|
173
|
+
}
|
|
174
|
+
// SDK 1.4.7 retains opening metadata but does not ingest its history. Seed once,
|
|
175
|
+
// before the buffered live suffix; pending pointers await the host's full reissue.
|
|
176
|
+
|
|
177
|
+
function seedHistory(session, opening, onFrame) {
|
|
178
|
+
if (opening.verb !== "session/resume") return;
|
|
179
|
+
var history = opening.result.history || {};
|
|
180
|
+
var snapshot = history.snapshot;
|
|
181
|
+
if (snapshot && snapshot.schemaVersion !== 1) throw new Error("Unsupported Muse snapshot schema version");
|
|
182
|
+
var items = history.items || snapshot && snapshot.state.items || [];
|
|
183
|
+
for (var i = 0; i < items.length; i++) {
|
|
184
|
+
var frame = {
|
|
185
|
+
method: "item/updated",
|
|
186
|
+
params: {
|
|
187
|
+
sessionId: session.sessionId,
|
|
188
|
+
item: items[i],
|
|
189
|
+
viewCursor: opening.result.viewCursor
|
|
190
|
+
}
|
|
191
|
+
};
|
|
192
|
+
session.apply(frame);
|
|
193
|
+
if (onFrame) onFrame(frame);
|
|
194
|
+
}
|
|
195
|
+
var active = snapshot && snapshot.state.activeTurn;
|
|
196
|
+
if (active) session.apply({
|
|
197
|
+
method: "turn/started",
|
|
198
|
+
params: Object.assign({}, active, {
|
|
199
|
+
sessionId: session.sessionId,
|
|
200
|
+
viewCursor: snapshot.viewCursor
|
|
201
|
+
})
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
module.exports = {
|
|
206
|
+
isAuthError: isAuthError,
|
|
207
|
+
createRuntime: createRuntime,
|
|
208
|
+
normalizeCatalog: normalizeCatalog,
|
|
209
|
+
modelSelection: modelSelection,
|
|
210
|
+
seedHistory: seedHistory
|
|
211
|
+
};
|