opencode-muse 0.0.0-stage → 0.1.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/LICENSE +21 -0
- package/README.md +120 -2
- package/dist/catalog.d.ts +47 -0
- package/dist/catalog.js +159 -0
- package/dist/errors.d.ts +92 -0
- package/dist/errors.js +181 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +17 -0
- package/dist/model/agent-context.d.ts +10 -0
- package/dist/model/agent-context.js +35 -0
- package/dist/model/context.d.ts +26 -0
- package/dist/model/context.js +87 -0
- package/dist/model/language-model.d.ts +48 -0
- package/dist/model/language-model.js +540 -0
- package/dist/model/meta.d.ts +16 -0
- package/dist/model/meta.js +171 -0
- package/dist/model/prompt.d.ts +68 -0
- package/dist/model/prompt.js +175 -0
- package/dist/model/stream.d.ts +46 -0
- package/dist/model/stream.js +235 -0
- package/dist/msp/client.d.ts +49 -0
- package/dist/msp/client.js +229 -0
- package/dist/msp/host.d.ts +55 -0
- package/dist/msp/host.js +173 -0
- package/dist/provider.d.ts +18 -0
- package/dist/provider.js +112 -0
- package/dist/session/fingerprint.d.ts +9 -0
- package/dist/session/fingerprint.js +83 -0
- package/dist/session/manager.d.ts +40 -0
- package/dist/session/manager.js +353 -0
- package/dist/session/registry.d.ts +55 -0
- package/dist/session/registry.js +330 -0
- package/dist/session/workspace-lock.d.ts +26 -0
- package/dist/session/workspace-lock.js +288 -0
- package/dist/types.d.ts +27 -0
- package/dist/types.js +1 -0
- package/package.json +58 -4
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
const STOCK_AGENT_PROMPT = /^\s*You are (?:an AI agent running in OpenCode|OpenCode|opencode)\b/i;
|
|
2
|
+
const MODEL_IDENTITY_HEADING = /^# Your Model[\t ]*$/im;
|
|
3
|
+
const KNOWN_BUILTIN_AGENTS = new Set(["build", "plan", "general", "explore"]);
|
|
4
|
+
function systemText(systemParts) {
|
|
5
|
+
return systemParts
|
|
6
|
+
.map((part) => {
|
|
7
|
+
if (typeof part !== "object" || part === null)
|
|
8
|
+
return "";
|
|
9
|
+
const value = part;
|
|
10
|
+
return value.type === "text" && typeof value.text === "string" ? value.text : "";
|
|
11
|
+
})
|
|
12
|
+
.filter((text) => text.length > 0)
|
|
13
|
+
.join("\n");
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Forward only a custom agent's bounded prompt prefix. Stock OpenCode prompts,
|
|
17
|
+
* tool catalogs, and unknown system layouts are never copied into Muse input.
|
|
18
|
+
*/
|
|
19
|
+
export function extractAllowedAgentContext(agent, systemParts) {
|
|
20
|
+
const system = systemText(systemParts);
|
|
21
|
+
const identity = MODEL_IDENTITY_HEADING.exec(system);
|
|
22
|
+
if (identity) {
|
|
23
|
+
const prefix = system.slice(0, identity.index).trim();
|
|
24
|
+
if (!prefix || STOCK_AGENT_PROMPT.test(prefix))
|
|
25
|
+
return { supported: true, fragments: [] };
|
|
26
|
+
return {
|
|
27
|
+
supported: true,
|
|
28
|
+
fragments: [{ label: "OpenCode agent instructions", text: prefix }],
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
if (STOCK_AGENT_PROMPT.test(system) || KNOWN_BUILTIN_AGENTS.has(agent)) {
|
|
32
|
+
return { supported: true, fragments: [] };
|
|
33
|
+
}
|
|
34
|
+
return { supported: false, fragments: [] };
|
|
35
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { MuseModelSelection, RequestContext, ContextError } from "../types.js";
|
|
2
|
+
export declare const MUSE_CONTEXT_HEADERS: Readonly<{
|
|
3
|
+
sessionID: "x-opencode-muse-session-id";
|
|
4
|
+
directory: "x-opencode-muse-directory";
|
|
5
|
+
kind: "x-opencode-muse-kind";
|
|
6
|
+
modelID: "x-opencode-muse-model-id";
|
|
7
|
+
providerID: "x-opencode-muse-provider-id";
|
|
8
|
+
variant: "x-opencode-muse-variant";
|
|
9
|
+
}>;
|
|
10
|
+
export interface ModelRequestHookInput {
|
|
11
|
+
sessionID: string;
|
|
12
|
+
kind: string;
|
|
13
|
+
model: {
|
|
14
|
+
id: string;
|
|
15
|
+
providerID: string;
|
|
16
|
+
variant?: string;
|
|
17
|
+
};
|
|
18
|
+
headers: Record<string, string>;
|
|
19
|
+
}
|
|
20
|
+
export interface LanguageModelCallContext {
|
|
21
|
+
headers?: Record<string, string | undefined>;
|
|
22
|
+
}
|
|
23
|
+
/** Stamp per-call metadata into headers proven to survive model.request → V3 call options. */
|
|
24
|
+
export declare function addRequestContextHeaders(headers: Record<string, string>, request: ModelRequestHookInput, directory: string): boolean;
|
|
25
|
+
/** Decode only the namespaced, per-call carrier; never guess from global request state. */
|
|
26
|
+
export declare function readRequestContext(callOptions: LanguageModelCallContext, selectionIndex: ReadonlyMap<string, MuseModelSelection>): RequestContext | ContextError;
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export const MUSE_CONTEXT_HEADERS = Object.freeze({
|
|
2
|
+
sessionID: "x-opencode-muse-session-id",
|
|
3
|
+
directory: "x-opencode-muse-directory",
|
|
4
|
+
kind: "x-opencode-muse-kind",
|
|
5
|
+
modelID: "x-opencode-muse-model-id",
|
|
6
|
+
providerID: "x-opencode-muse-provider-id",
|
|
7
|
+
variant: "x-opencode-muse-variant",
|
|
8
|
+
});
|
|
9
|
+
const REQUEST_KINDS = new Set(["primary", "title", "compaction", "generate"]);
|
|
10
|
+
function readHeader(headers, target) {
|
|
11
|
+
if (!headers)
|
|
12
|
+
return undefined;
|
|
13
|
+
const direct = headers[target];
|
|
14
|
+
if (typeof direct === "string")
|
|
15
|
+
return direct;
|
|
16
|
+
const normalized = target.toLowerCase();
|
|
17
|
+
for (const [key, value] of Object.entries(headers)) {
|
|
18
|
+
if (key.toLowerCase() === normalized && typeof value === "string")
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
function contextError(code, field) {
|
|
24
|
+
return { type: "context-error", code, field };
|
|
25
|
+
}
|
|
26
|
+
/** Stamp per-call metadata into headers proven to survive model.request → V3 call options. */
|
|
27
|
+
export function addRequestContextHeaders(headers, request, directory) {
|
|
28
|
+
if (request.model.providerID !== "muse")
|
|
29
|
+
return false;
|
|
30
|
+
headers[MUSE_CONTEXT_HEADERS.sessionID] = request.sessionID;
|
|
31
|
+
headers[MUSE_CONTEXT_HEADERS.directory] = directory;
|
|
32
|
+
headers[MUSE_CONTEXT_HEADERS.kind] = request.kind;
|
|
33
|
+
headers[MUSE_CONTEXT_HEADERS.modelID] = request.model.id;
|
|
34
|
+
headers[MUSE_CONTEXT_HEADERS.providerID] = request.model.providerID;
|
|
35
|
+
if (request.model.variant)
|
|
36
|
+
headers[MUSE_CONTEXT_HEADERS.variant] = request.model.variant;
|
|
37
|
+
else
|
|
38
|
+
delete headers[MUSE_CONTEXT_HEADERS.variant];
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
/** Decode only the namespaced, per-call carrier; never guess from global request state. */
|
|
42
|
+
export function readRequestContext(callOptions, selectionIndex) {
|
|
43
|
+
const headers = callOptions.headers;
|
|
44
|
+
if (!headers)
|
|
45
|
+
return contextError("missing", "headers");
|
|
46
|
+
const sessionID = readHeader(headers, MUSE_CONTEXT_HEADERS.sessionID);
|
|
47
|
+
if (!sessionID)
|
|
48
|
+
return contextError("missing", "sessionID");
|
|
49
|
+
const directory = readHeader(headers, MUSE_CONTEXT_HEADERS.directory);
|
|
50
|
+
if (!directory)
|
|
51
|
+
return contextError("missing", "directory");
|
|
52
|
+
const kind = readHeader(headers, MUSE_CONTEXT_HEADERS.kind);
|
|
53
|
+
if (!kind)
|
|
54
|
+
return contextError("missing", "kind");
|
|
55
|
+
if (!REQUEST_KINDS.has(kind))
|
|
56
|
+
return contextError("invalid", "kind");
|
|
57
|
+
const modelID = readHeader(headers, MUSE_CONTEXT_HEADERS.modelID);
|
|
58
|
+
if (!modelID)
|
|
59
|
+
return contextError("missing", "modelID");
|
|
60
|
+
const providerID = readHeader(headers, MUSE_CONTEXT_HEADERS.providerID);
|
|
61
|
+
if (!providerID)
|
|
62
|
+
return contextError("missing", "providerID");
|
|
63
|
+
if (providerID !== "muse")
|
|
64
|
+
return contextError("invalid", "providerID");
|
|
65
|
+
const museSelection = selectionIndex.get(modelID);
|
|
66
|
+
if (!museSelection)
|
|
67
|
+
return contextError("unknown-model", "modelID");
|
|
68
|
+
const rawVariant = readHeader(headers, MUSE_CONTEXT_HEADERS.variant);
|
|
69
|
+
const variant = rawVariant || undefined;
|
|
70
|
+
// OpenCode's default agent sends the synthetic "default" variant when the user
|
|
71
|
+
// did not choose one; resolve it to the catalog row's default reasoning effort.
|
|
72
|
+
const resolvedVariant = variant === "default"
|
|
73
|
+
? (museSelection.defaultReasoningEffort ?? undefined)
|
|
74
|
+
: variant;
|
|
75
|
+
if (resolvedVariant && (!museSelection.variantsKnown || !museSelection.variants.includes(resolvedVariant))) {
|
|
76
|
+
return contextError("unsupported-variant", "variant");
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
sessionID,
|
|
80
|
+
directory,
|
|
81
|
+
kind: kind,
|
|
82
|
+
modelID,
|
|
83
|
+
providerID,
|
|
84
|
+
...(resolvedVariant ? { variant: resolvedVariant, effort: resolvedVariant } : {}),
|
|
85
|
+
museSelection,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import type { LanguageModelV3, LanguageModelV3CallOptions } from "@ai-sdk/provider";
|
|
2
|
+
import type { MspNotification } from "../msp/client.js";
|
|
3
|
+
import { type ContextFragment, type ExtractedTurnPart } from "./prompt.js";
|
|
4
|
+
import type { MuseModelSelection, RequestContext } from "../types.js";
|
|
5
|
+
export interface MuseTurnHost {
|
|
6
|
+
mintCommandId(): string;
|
|
7
|
+
command<TResult extends object = Record<string, unknown>>(method: string, params: Record<string, unknown> & {
|
|
8
|
+
commandId: string;
|
|
9
|
+
}): Promise<TResult>;
|
|
10
|
+
request<TResult extends object = Record<string, unknown>>(method: string, params?: Record<string, unknown>): Promise<TResult>;
|
|
11
|
+
subscribe(sessionId: string, after?: string, signal?: AbortSignal): AsyncIterable<MspNotification>;
|
|
12
|
+
close?(): Promise<void>;
|
|
13
|
+
}
|
|
14
|
+
export interface MuseTurnSession {
|
|
15
|
+
host: MuseTurnHost;
|
|
16
|
+
sessionId: string;
|
|
17
|
+
previousTranscriptFingerprints: readonly string[];
|
|
18
|
+
compactionFingerprints?: readonly string[];
|
|
19
|
+
commitTranscriptFingerprints?(fingerprints: readonly string[]): Promise<void>;
|
|
20
|
+
contextAllowlist: readonly ContextFragment[];
|
|
21
|
+
contextError?: string;
|
|
22
|
+
replayAfterCursor?: string;
|
|
23
|
+
currentSelection?: Pick<MuseModelSelection, "providerId" | "modelId" | "profileId">;
|
|
24
|
+
recordPendingCommand?(input: {
|
|
25
|
+
commandId: string;
|
|
26
|
+
method: string;
|
|
27
|
+
fingerprint: string;
|
|
28
|
+
}): Promise<void>;
|
|
29
|
+
clearPendingCommand?(commandId: string): Promise<void>;
|
|
30
|
+
recordTurnAccepted?(commandId: string, turnId: string): Promise<void>;
|
|
31
|
+
updateCursor?(cursor: string): Promise<void>;
|
|
32
|
+
recordTurnCompleted?(turnId: string, terminal: string, usage?: Record<string, unknown>): Promise<void>;
|
|
33
|
+
release?(): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
export interface MuseLanguageRuntime {
|
|
36
|
+
selectionIndex: ReadonlyMap<string, MuseModelSelection>;
|
|
37
|
+
resolveSession(context: RequestContext): Promise<MuseTurnSession>;
|
|
38
|
+
videoChunkBytes?: number;
|
|
39
|
+
}
|
|
40
|
+
export interface MuseTurnExecution {
|
|
41
|
+
turnId: string;
|
|
42
|
+
commandId: string;
|
|
43
|
+
disposition: string;
|
|
44
|
+
events: AsyncIterable<MspNotification>;
|
|
45
|
+
cancel(): Promise<void>;
|
|
46
|
+
}
|
|
47
|
+
export declare function runMuseTurn(context: RequestContext, input: readonly ExtractedTurnPart[], options: Pick<LanguageModelV3CallOptions, "abortSignal">, runtime: MuseLanguageRuntime, transcriptFingerprints?: readonly string[]): Promise<MuseTurnExecution>;
|
|
48
|
+
export declare function createMuseLanguageModel(runtime: MuseLanguageRuntime, modelID: string): LanguageModelV3;
|