@cydm/happy-elves 0.1.0-beta.50 → 0.1.0-beta.51
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/apps/daemon/dist/relay/register.js +1 -0
- package/apps/daemon/dist/runtime/external-provider.js +8 -2
- package/apps/daemon/dist/session/lifecycle.js +5 -0
- package/apps/daemon/dist/session/prompt.js +11 -1
- package/apps/daemon/dist/types.d.ts +4 -1
- package/apps/daemon/package.json +1 -1
- package/apps/relay/dist/connections.d.ts +2 -0
- package/apps/relay/dist/controller-handlers.js +32 -1
- package/apps/relay/dist/projections.js +33 -0
- package/apps/relay/dist/relay-context.js +9 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/packages/agent-sdk/dist/index.d.ts +7 -1
- package/packages/client/dist/client.js +4 -0
- package/packages/client/dist/live-types.d.ts +2 -0
- package/packages/client/dist/live.js +2 -0
- package/packages/client/dist/types.d.ts +8 -1
- package/packages/pie-provider/dist/index.js +59 -4
- package/packages/provider-protocol/dist/index.d.ts +67 -0
- package/packages/provider-protocol/dist/index.js +16 -0
- package/packages/runtime/dist/index.d.ts +8 -2
- package/packages/runtime-cli/dist/claude-turn.d.ts +2 -0
- package/packages/runtime-cli/dist/claude-turn.js +18 -0
- package/packages/runtime-cli/dist/codex-app-server.d.ts +8 -3
- package/packages/runtime-cli/dist/codex-app-server.js +85 -17
- package/packages/runtime-cli/dist/codex-protocol.d.ts +5 -3
- package/packages/runtime-cli/dist/codex-protocol.js +24 -5
- package/packages/runtime-cli/dist/index.js +46 -2
- package/packages/runtime-cli/dist/session-store.d.ts +2 -0
- package/packages/runtime-cli/dist/session-store.js +6 -4
- package/packages/shared/dist/protocol-schemas.d.ts +28 -0
- package/packages/shared/dist/protocol-schemas.js +12 -0
- package/packages/shared/dist/protocol-types.d.ts +12 -0
- package/packages/shared/dist/protocol.d.ts +5 -1
- package/packages/shared/dist/protocol.js +4 -0
|
@@ -24,6 +24,7 @@ function agentProfileForRegister(agent) {
|
|
|
24
24
|
...(agent.command ? { command: agent.command } : {}),
|
|
25
25
|
...(agent.historyModel ? { historyModel: agent.historyModel } : {}),
|
|
26
26
|
...(agent.sessionPrimitives ? { sessionPrimitives: runtimeAgentPrimitives(agent.sessionPrimitives) } : {}),
|
|
27
|
+
...(agent.runtimeOptions ? { runtimeOptions: agent.runtimeOptions } : {}),
|
|
27
28
|
};
|
|
28
29
|
}
|
|
29
30
|
function runtimeAgentPrimitives(primitives) {
|
|
@@ -10,7 +10,7 @@ const maxJsonLineChars = 1024 * 1024;
|
|
|
10
10
|
const stderrRingChars = 16 * 1024;
|
|
11
11
|
const historicalEventPageLimit = 200;
|
|
12
12
|
const historicalEventPageSafetyLimit = 1_000;
|
|
13
|
-
const pieMinimumVersion = "1.0.
|
|
13
|
+
const pieMinimumVersion = "1.0.21";
|
|
14
14
|
const pieAutoProbeTimeoutMs = 5_000;
|
|
15
15
|
export function externalProviderConfigsFromEnv() {
|
|
16
16
|
const raw = process.env.HAPPY_ELVES_AGENT_PROVIDERS_JSON?.trim();
|
|
@@ -74,11 +74,12 @@ function pieCommandSupportsProvider(command) {
|
|
|
74
74
|
const listResult = runPieProbe(command, ["sessions", "list", "--json", "--limit", "1"]);
|
|
75
75
|
if (listResult.status !== 0)
|
|
76
76
|
return false;
|
|
77
|
-
const modelsResult = runPieProbe(command, ["models", "validate"]);
|
|
77
|
+
const modelsResult = runPieProbe(command, ["models", "validate", "--json"]);
|
|
78
78
|
if (modelsResult.status !== 0)
|
|
79
79
|
return false;
|
|
80
80
|
try {
|
|
81
81
|
JSON.parse(listResult.stdout);
|
|
82
|
+
JSON.parse(modelsResult.stdout);
|
|
82
83
|
return true;
|
|
83
84
|
}
|
|
84
85
|
catch {
|
|
@@ -315,6 +316,7 @@ export function createExternalAgentRuntimeProvider(options) {
|
|
|
315
316
|
rename: agent.capabilities.sessionPrimitives.rename ?? "unsupported",
|
|
316
317
|
}
|
|
317
318
|
: { resume: "unsupported", rewind: "unsupported", fork: "unsupported", rename: "unsupported" },
|
|
319
|
+
runtimeOptions: agent.capabilities?.runtimeOptions,
|
|
318
320
|
}));
|
|
319
321
|
const agentsById = new Map();
|
|
320
322
|
for (const agent of externalAgents)
|
|
@@ -338,6 +340,8 @@ export function createExternalAgentRuntimeProvider(options) {
|
|
|
338
340
|
...(input.resumeHandle ? { resumeHandle: sdkHandle(input.resumeHandle) } : {}),
|
|
339
341
|
cwd: input.cwd,
|
|
340
342
|
permissionMode: input.permissionMode,
|
|
343
|
+
model: input.model,
|
|
344
|
+
thoughtLevel: input.thoughtLevel,
|
|
341
345
|
restartableEmptySession: input.restartableEmptySession,
|
|
342
346
|
}), "ensureSession result handle");
|
|
343
347
|
return toRuntimeHandle(input.sessionKey, handle, input.cwd);
|
|
@@ -429,6 +433,8 @@ export function createExternalAgentRuntimeProvider(options) {
|
|
|
429
433
|
attachments: input.attachments,
|
|
430
434
|
mode: input.mode,
|
|
431
435
|
permissionMode: input.permissionMode,
|
|
436
|
+
model: input.model,
|
|
437
|
+
thoughtLevel: input.thoughtLevel,
|
|
432
438
|
requestId: input.requestId,
|
|
433
439
|
timeoutMs: input.timeoutMs,
|
|
434
440
|
});
|
|
@@ -22,6 +22,8 @@ export async function handleCreateSession(ws, config, command) {
|
|
|
22
22
|
mode: "persistent",
|
|
23
23
|
cwd,
|
|
24
24
|
permissionMode: metadata?.permissionMode,
|
|
25
|
+
model: metadata?.modelMode,
|
|
26
|
+
thoughtLevel: metadata?.thoughtLevel,
|
|
25
27
|
});
|
|
26
28
|
let providerName;
|
|
27
29
|
const requestedRuntimeName = metadata?.requestedRuntimeName;
|
|
@@ -68,6 +70,9 @@ export async function handleCreateSession(ws, config, command) {
|
|
|
68
70
|
...(providerName ? { name: providerName } : {}),
|
|
69
71
|
encryptedMetadata: await encryptedSessionMetadata(config, command.sessionId, state, {
|
|
70
72
|
emptyRuntimeSession: true,
|
|
73
|
+
modelMode: metadata?.modelMode,
|
|
74
|
+
thoughtLevel: metadata?.thoughtLevel,
|
|
75
|
+
runtimeOptions: handle.runtimeOptions,
|
|
71
76
|
...(providerName ? { providerName, renamedAt: new Date().toISOString() } : {}),
|
|
72
77
|
readyAt: new Date().toISOString(),
|
|
73
78
|
}),
|
|
@@ -6,7 +6,7 @@ import { activePromptRequests, completedPromptRequests, sessions, sessionTurns }
|
|
|
6
6
|
import { attachClaimedTurn, claimSessionTurn, releaseSessionTurn, sendCommandResponse, sendReliable } from "../relay/send.js";
|
|
7
7
|
import { emitEvent, runtimeEventToPayload } from "./events.js";
|
|
8
8
|
import { replaceAuthoritativeTranscript, resumeSession, usesAuthoritativeTranscript } from "./lifecycle.js";
|
|
9
|
-
import { encryptedSessionMetadata, sessionFallbackFromCommand } from "./metadata.js";
|
|
9
|
+
import { commandSessionMetadata, encryptedSessionMetadata, sessionFallbackFromCommand } from "./metadata.js";
|
|
10
10
|
export async function handlePrompt(ws, config, command) {
|
|
11
11
|
if (command.type !== "machine:prompt")
|
|
12
12
|
return;
|
|
@@ -60,6 +60,8 @@ export async function handlePrompt(ws, config, command) {
|
|
|
60
60
|
text,
|
|
61
61
|
mode: "prompt",
|
|
62
62
|
permissionMode: command.permissionMode,
|
|
63
|
+
model: command.model,
|
|
64
|
+
thoughtLevel: command.thoughtLevel,
|
|
63
65
|
requestId: command.requestId,
|
|
64
66
|
timeoutMs: command.timeoutMs,
|
|
65
67
|
});
|
|
@@ -78,6 +80,8 @@ export async function handlePrompt(ws, config, command) {
|
|
|
78
80
|
turnId: command.turnId,
|
|
79
81
|
promptChars: text.length,
|
|
80
82
|
permissionMode: command.permissionMode ?? "approve-reads",
|
|
83
|
+
model: command.model ?? undefined,
|
|
84
|
+
thoughtLevel: command.thoughtLevel ?? undefined,
|
|
81
85
|
},
|
|
82
86
|
});
|
|
83
87
|
pumpRuntimeEvents(turn, ws, config, command);
|
|
@@ -175,9 +179,15 @@ async function refreshedRuntimeMetadata(config, command, session, result) {
|
|
|
175
179
|
if (!session.handle.backendSessionId)
|
|
176
180
|
return undefined;
|
|
177
181
|
try {
|
|
182
|
+
const previousMetadata = await commandSessionMetadata(config, command.encryptedMetadata);
|
|
183
|
+
const modelMode = command.model !== undefined ? command.model : previousMetadata?.modelMode;
|
|
184
|
+
const thoughtLevel = command.thoughtLevel !== undefined ? command.thoughtLevel : previousMetadata?.thoughtLevel;
|
|
178
185
|
return await encryptedSessionMetadata(config, command.sessionId, session, {
|
|
179
186
|
currentHead: result.currentHead,
|
|
180
187
|
emptyRuntimeSession: result.status === "failed" && !result.currentHead && !result.lastTurnId,
|
|
188
|
+
...(modelMode !== undefined ? { modelMode } : {}),
|
|
189
|
+
...(thoughtLevel !== undefined ? { thoughtLevel } : {}),
|
|
190
|
+
...(previousMetadata?.runtimeOptions !== undefined ? { runtimeOptions: previousMetadata.runtimeOptions } : {}),
|
|
181
191
|
runtimeMetadataRefreshedAt: new Date().toISOString(),
|
|
182
192
|
});
|
|
183
193
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { SessionHeadAdvanceBasis } from "../../../packages/shared/dist/index.js";
|
|
2
|
-
import type { RuntimeHandle, RuntimeTurn } from "../../../packages/runtime/dist/index.js";
|
|
2
|
+
import type { RuntimeHandle, RuntimeOptions, RuntimeTurn } from "../../../packages/runtime/dist/index.js";
|
|
3
3
|
export type DirectoryListResult = {
|
|
4
4
|
machineId: string;
|
|
5
5
|
path: string;
|
|
@@ -57,6 +57,9 @@ export type SessionMetadata = {
|
|
|
57
57
|
providerName?: string;
|
|
58
58
|
requestedRuntimeName?: string;
|
|
59
59
|
permissionMode?: PermissionMode;
|
|
60
|
+
modelMode?: string | null;
|
|
61
|
+
thoughtLevel?: string | null;
|
|
62
|
+
runtimeOptions?: RuntimeOptions;
|
|
60
63
|
importedFromRuntimeSessionId?: string;
|
|
61
64
|
importedSummary?: string;
|
|
62
65
|
sourceSessionId?: string;
|
package/apps/daemon/package.json
CHANGED
|
@@ -9,6 +9,7 @@ export type PendingCommandContext = {
|
|
|
9
9
|
command?: string;
|
|
10
10
|
cwd?: string;
|
|
11
11
|
machineId: string;
|
|
12
|
+
model?: string | null;
|
|
12
13
|
name?: string;
|
|
13
14
|
promptHash?: string;
|
|
14
15
|
recipientDeviceId?: string;
|
|
@@ -19,6 +20,7 @@ export type PendingCommandContext = {
|
|
|
19
20
|
sourceSessionId?: string;
|
|
20
21
|
targetSessionId?: string;
|
|
21
22
|
timeoutMs?: number;
|
|
23
|
+
thoughtLevel?: string | null;
|
|
22
24
|
turnId?: string;
|
|
23
25
|
};
|
|
24
26
|
export declare function machineKey(accountId: string, machineId: string): string;
|
|
@@ -169,12 +169,16 @@ export function handleControllerMessage(context, connection, message) {
|
|
|
169
169
|
return;
|
|
170
170
|
}
|
|
171
171
|
rememberAcceptedRun(connection, { machineId: sessionRow.machine_id, sessionId: sessionRow.id, turnId: message.turnId });
|
|
172
|
+
const model = normalizeRuntimeSelectionContext(message.model);
|
|
173
|
+
const thoughtLevel = normalizeRuntimeSelectionContext(message.thoughtLevel);
|
|
172
174
|
markCommandPending(connection.accountId, sessionRow.machine_id, message.requestId, {
|
|
173
175
|
action: "session.run",
|
|
174
176
|
blocksSessionTurn: true,
|
|
177
|
+
model,
|
|
175
178
|
promptHash: message.promptHash,
|
|
176
179
|
recipientDeviceId: connection.deviceId ?? undefined,
|
|
177
180
|
sessionId: sessionRow.id,
|
|
181
|
+
thoughtLevel,
|
|
178
182
|
turnId: message.turnId,
|
|
179
183
|
});
|
|
180
184
|
sendAck(connection, { type: "server:ack", requestId: message.requestId, ok: true, machineId: sessionRow.machine_id, sessionId: sessionRow.id, action: "session.run" });
|
|
@@ -198,6 +202,8 @@ export function handleControllerMessage(context, connection, message) {
|
|
|
198
202
|
encryptedPrompt: message.encryptedPrompt,
|
|
199
203
|
encryptedMetadata: sessionRow.encrypted_metadata ? parseJson(sessionRow.encrypted_metadata, undefined) : undefined,
|
|
200
204
|
permissionMode: message.permissionMode,
|
|
205
|
+
model,
|
|
206
|
+
thoughtLevel,
|
|
201
207
|
timeoutMs: message.timeoutMs,
|
|
202
208
|
});
|
|
203
209
|
return;
|
|
@@ -730,7 +736,15 @@ function controllerMessageCommandContext(message, targetMachineId) {
|
|
|
730
736
|
case "controller:createSession":
|
|
731
737
|
return { action: "session.create", agent: message.agent, cwd: message.cwd, machineId: message.machineId, name: message.name };
|
|
732
738
|
case "controller:prompt":
|
|
733
|
-
return {
|
|
739
|
+
return {
|
|
740
|
+
action: "session.run",
|
|
741
|
+
machineId: targetMachineId,
|
|
742
|
+
model: normalizeRuntimeSelectionContext(message.model),
|
|
743
|
+
promptHash: message.promptHash,
|
|
744
|
+
sessionId: message.sessionId,
|
|
745
|
+
thoughtLevel: normalizeRuntimeSelectionContext(message.thoughtLevel),
|
|
746
|
+
turnId: message.turnId,
|
|
747
|
+
};
|
|
734
748
|
case "controller:cancel":
|
|
735
749
|
return { action: "session.cancel", machineId: targetMachineId, sessionId: message.sessionId, turnId: message.turnId };
|
|
736
750
|
case "controller:resume":
|
|
@@ -791,6 +805,8 @@ function pendingCommandMatchesMessage(pending, expected) {
|
|
|
791
805
|
return false;
|
|
792
806
|
if (!matchesDefined(pending.name, expected.name))
|
|
793
807
|
return false;
|
|
808
|
+
if (expected.action === "session.run" && !matchesRuntimeSelection(pending.model, expected.model))
|
|
809
|
+
return false;
|
|
794
810
|
if (!matchesDefined(pending.promptHash, expected.promptHash))
|
|
795
811
|
return false;
|
|
796
812
|
if (!matchesDefined(pending.runtimeSessionId, expected.runtimeSessionId))
|
|
@@ -801,6 +817,8 @@ function pendingCommandMatchesMessage(pending, expected) {
|
|
|
801
817
|
return false;
|
|
802
818
|
if (!matchesDefined(pending.targetSessionId, expected.targetSessionId))
|
|
803
819
|
return false;
|
|
820
|
+
if (expected.action === "session.run" && !matchesRuntimeSelection(pending.thoughtLevel, expected.thoughtLevel))
|
|
821
|
+
return false;
|
|
804
822
|
if (!matchesDefined(pending.turnId, expected.turnId))
|
|
805
823
|
return false;
|
|
806
824
|
if (!matchesDefined(pending.checkpoint, expected.checkpoint))
|
|
@@ -833,6 +851,8 @@ function retainedResponseMatchesCommand(previous, expected) {
|
|
|
833
851
|
return false;
|
|
834
852
|
if (!matchesDefined(responseTurnId(response), expected.turnId))
|
|
835
853
|
return false;
|
|
854
|
+
if (expected.action === "session.run" && (expected.model !== undefined || expected.thoughtLevel !== undefined))
|
|
855
|
+
return false;
|
|
836
856
|
if (expected.action === "machine.devExec" && !legacyDevExecResponseMatches(response, expected))
|
|
837
857
|
return false;
|
|
838
858
|
return true;
|
|
@@ -911,6 +931,17 @@ function responseTurnId(response) {
|
|
|
911
931
|
function matchesDefined(actual, expected) {
|
|
912
932
|
return expected === undefined || actual === expected;
|
|
913
933
|
}
|
|
934
|
+
function matchesRuntimeSelection(actual, expected) {
|
|
935
|
+
return actual === expected;
|
|
936
|
+
}
|
|
937
|
+
function normalizeRuntimeSelectionContext(value) {
|
|
938
|
+
if (value === undefined)
|
|
939
|
+
return undefined;
|
|
940
|
+
if (value === null)
|
|
941
|
+
return null;
|
|
942
|
+
const normalized = value.trim();
|
|
943
|
+
return normalized.length === 0 || normalized.toLowerCase() === "default" ? null : normalized;
|
|
944
|
+
}
|
|
914
945
|
function sendRequestIdConflict(connection, send, requestId) {
|
|
915
946
|
send(connection.socket, {
|
|
916
947
|
type: "server:error",
|
|
@@ -21,6 +21,38 @@ function primitiveSupport(value) {
|
|
|
21
21
|
function historyModel(value) {
|
|
22
22
|
return value === "append-only" || value === "authoritative-linear" ? value : undefined;
|
|
23
23
|
}
|
|
24
|
+
function runtimeSelectionOption(value) {
|
|
25
|
+
if (!isRecord(value) || typeof value.key !== "string" || value.key.length === 0 || typeof value.label !== "string" || value.label.length === 0) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
key: value.key,
|
|
30
|
+
label: value.label,
|
|
31
|
+
...(typeof value.description === "string" || value.description === null ? { description: value.description } : {}),
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function runtimeSelectionOptions(value) {
|
|
35
|
+
if (!Array.isArray(value))
|
|
36
|
+
return undefined;
|
|
37
|
+
const options = value.flatMap((item) => {
|
|
38
|
+
const option = runtimeSelectionOption(item);
|
|
39
|
+
return option ? [option] : [];
|
|
40
|
+
});
|
|
41
|
+
return options.length > 0 ? options : undefined;
|
|
42
|
+
}
|
|
43
|
+
function runtimeOptions(value) {
|
|
44
|
+
if (!isRecord(value))
|
|
45
|
+
return undefined;
|
|
46
|
+
const models = runtimeSelectionOptions(value.models);
|
|
47
|
+
const thoughtLevels = runtimeSelectionOptions(value.thoughtLevels);
|
|
48
|
+
const normalized = {
|
|
49
|
+
...(models ? { models } : {}),
|
|
50
|
+
...(thoughtLevels ? { thoughtLevels } : {}),
|
|
51
|
+
...(typeof value.currentModel === "string" && value.currentModel.length > 0 ? { currentModel: value.currentModel } : {}),
|
|
52
|
+
...(typeof value.currentThoughtLevel === "string" && value.currentThoughtLevel.length > 0 ? { currentThoughtLevel: value.currentThoughtLevel } : {}),
|
|
53
|
+
};
|
|
54
|
+
return Object.keys(normalized).length > 0 ? normalized : undefined;
|
|
55
|
+
}
|
|
24
56
|
export function normalizeMachineCapabilities(value) {
|
|
25
57
|
const record = isRecord(value) ? value : {};
|
|
26
58
|
const agents = Array.isArray(record.agents)
|
|
@@ -32,6 +64,7 @@ export function normalizeMachineCapabilities(value) {
|
|
|
32
64
|
label: agent.label,
|
|
33
65
|
...(typeof agent.command === "string" ? { command: agent.command } : {}),
|
|
34
66
|
...(historyModel(agent.historyModel) ? { historyModel: historyModel(agent.historyModel) } : {}),
|
|
67
|
+
...(runtimeOptions(agent.runtimeOptions) ? { runtimeOptions: runtimeOptions(agent.runtimeOptions) } : {}),
|
|
35
68
|
...(isRecord(agent.sessionPrimitives)
|
|
36
69
|
? {
|
|
37
70
|
sessionPrimitives: {
|
|
@@ -285,6 +285,7 @@ export function createRelayContext(options) {
|
|
|
285
285
|
...(pending.command !== undefined ? { command: pending.command } : {}),
|
|
286
286
|
...(pending.cwd !== undefined ? { cwd: pending.cwd } : {}),
|
|
287
287
|
machineId: pending.machineId,
|
|
288
|
+
...(pending.model !== undefined ? { model: pending.model } : {}),
|
|
288
289
|
...(pending.name !== undefined ? { name: pending.name } : {}),
|
|
289
290
|
...(pending.promptHash !== undefined ? { promptHash: pending.promptHash } : {}),
|
|
290
291
|
...(pending.runtimeSessionId !== undefined ? { runtimeSessionId: pending.runtimeSessionId } : {}),
|
|
@@ -293,6 +294,7 @@ export function createRelayContext(options) {
|
|
|
293
294
|
...(pending.sourceSessionId !== undefined ? { sourceSessionId: pending.sourceSessionId } : {}),
|
|
294
295
|
...(pending.targetSessionId !== undefined ? { targetSessionId: pending.targetSessionId } : {}),
|
|
295
296
|
...(pending.timeoutMs !== undefined ? { timeoutMs: pending.timeoutMs } : {}),
|
|
297
|
+
...(pending.thoughtLevel !== undefined ? { thoughtLevel: pending.thoughtLevel } : {}),
|
|
296
298
|
...(pending.turnId !== undefined ? { turnId: pending.turnId } : {}),
|
|
297
299
|
});
|
|
298
300
|
}
|
|
@@ -319,6 +321,7 @@ export function createRelayContext(options) {
|
|
|
319
321
|
...(typeof parsed.command === "string" ? { command: parsed.command } : {}),
|
|
320
322
|
...(typeof parsed.cwd === "string" ? { cwd: parsed.cwd } : {}),
|
|
321
323
|
machineId: parsed.machineId,
|
|
324
|
+
...(runtimeSelectionContext(parsed.model) !== undefined ? { model: runtimeSelectionContext(parsed.model) } : {}),
|
|
322
325
|
...(typeof parsed.name === "string" ? { name: parsed.name } : {}),
|
|
323
326
|
...(typeof parsed.promptHash === "string" ? { promptHash: parsed.promptHash } : {}),
|
|
324
327
|
requestId: "",
|
|
@@ -328,6 +331,7 @@ export function createRelayContext(options) {
|
|
|
328
331
|
...(typeof parsed.sourceSessionId === "string" ? { sourceSessionId: parsed.sourceSessionId } : {}),
|
|
329
332
|
...(typeof parsed.targetSessionId === "string" ? { targetSessionId: parsed.targetSessionId } : {}),
|
|
330
333
|
...(typeof parsed.timeoutMs === "number" ? { timeoutMs: parsed.timeoutMs } : {}),
|
|
334
|
+
...(runtimeSelectionContext(parsed.thoughtLevel) !== undefined ? { thoughtLevel: runtimeSelectionContext(parsed.thoughtLevel) } : {}),
|
|
331
335
|
...(typeof parsed.turnId === "string" ? { turnId: parsed.turnId } : {}),
|
|
332
336
|
};
|
|
333
337
|
}
|
|
@@ -335,6 +339,11 @@ export function createRelayContext(options) {
|
|
|
335
339
|
return undefined;
|
|
336
340
|
}
|
|
337
341
|
}
|
|
342
|
+
function runtimeSelectionContext(value) {
|
|
343
|
+
if (value === null)
|
|
344
|
+
return null;
|
|
345
|
+
return typeof value === "string" ? value : undefined;
|
|
346
|
+
}
|
|
338
347
|
function rememberDirectCommandResponse(accountId, machineId, requestId, response) {
|
|
339
348
|
const pending = pendingWithMachine(accountId, machineId, requestId);
|
|
340
349
|
const recipientDeviceId = pending?.recipientDeviceId;
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cydm/happy-elves",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.51",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@cydm/happy-elves",
|
|
9
|
-
"version": "0.1.0-beta.
|
|
9
|
+
"version": "0.1.0-beta.51",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@fastify/cors": "11.2.0",
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Readable, Writable } from "node:stream";
|
|
2
|
-
import { type ProviderAgentCapability, type ProviderAgentProfile, type ProviderDiagnostics, type ProviderErrorCode, type ProviderHistoricalEvent as HistoricalEvent, type ProviderHistoricalEventPage as HistoricalEventPage, type ProviderHistoricalSession as HistoricalSession, type ProviderHistoricalSessionPage as HistoricalSessionPage, type ProviderInfo, type ProviderMethod, type ProviderPermissionMode, type ProviderPrimitiveSupport, type ProviderPromptMode, type ProviderRequest, type ProviderResponse, type ProviderRuntimeAttachment, type ProviderRuntimeEvent, type ProviderRuntimeHandle, type ProviderRuntimeTurnResult, type ProviderSessionMode, type ProviderStreamMessage } from "../../provider-protocol/dist/index.js";
|
|
2
|
+
import { type ProviderAgentCapability, type ProviderAgentProfile, type ProviderDiagnostics, type ProviderErrorCode, type ProviderHistoricalEvent as HistoricalEvent, type ProviderHistoricalEventPage as HistoricalEventPage, type ProviderHistoricalSession as HistoricalSession, type ProviderHistoricalSessionPage as HistoricalSessionPage, type ProviderInfo, type ProviderMethod, type ProviderPermissionMode, type ProviderPrimitiveSupport, type ProviderPromptMode, type ProviderRequest, type ProviderResponse, type ProviderRuntimeAttachment, type ProviderRuntimeEvent, type ProviderRuntimeOptions, type ProviderRuntimeSelectionOption, type ProviderRuntimeHandle, type ProviderRuntimeTurnResult, type ProviderSessionMode, type ProviderStreamMessage } from "../../provider-protocol/dist/index.js";
|
|
3
3
|
export type PrimitiveSupport = ProviderPrimitiveSupport;
|
|
4
4
|
export type PermissionMode = ProviderPermissionMode;
|
|
5
5
|
export type PromptMode = ProviderPromptMode;
|
|
@@ -7,6 +7,8 @@ export type SessionMode = ProviderSessionMode;
|
|
|
7
7
|
export type AgentCapability = ProviderAgentCapability;
|
|
8
8
|
export type AgentProfile = ProviderAgentProfile;
|
|
9
9
|
export type { ProviderInfo };
|
|
10
|
+
export type RuntimeOptions = ProviderRuntimeOptions;
|
|
11
|
+
export type RuntimeSelectionOption = ProviderRuntimeSelectionOption;
|
|
10
12
|
export type RuntimeHandle = ProviderRuntimeHandle;
|
|
11
13
|
export type RuntimeAttachment = ProviderRuntimeAttachment;
|
|
12
14
|
export type RuntimeEvent = ProviderRuntimeEvent;
|
|
@@ -43,6 +45,8 @@ export interface HappyElvesAgentProvider {
|
|
|
43
45
|
resumeHandle?: RuntimeHandle;
|
|
44
46
|
cwd?: string;
|
|
45
47
|
permissionMode?: PermissionMode;
|
|
48
|
+
model?: string | null;
|
|
49
|
+
thoughtLevel?: string | null;
|
|
46
50
|
restartableEmptySession?: boolean;
|
|
47
51
|
}): Promise<RuntimeHandle>;
|
|
48
52
|
startTurn(input: {
|
|
@@ -51,6 +55,8 @@ export interface HappyElvesAgentProvider {
|
|
|
51
55
|
attachments?: RuntimeAttachment[];
|
|
52
56
|
mode: PromptMode;
|
|
53
57
|
permissionMode?: PermissionMode;
|
|
58
|
+
model?: string | null;
|
|
59
|
+
thoughtLevel?: string | null;
|
|
54
60
|
requestId: string;
|
|
55
61
|
timeoutMs?: number;
|
|
56
62
|
signal?: AbortSignal;
|
|
@@ -149,6 +149,8 @@ export class ControllerClient {
|
|
|
149
149
|
createdFrom: input.createdFrom ?? "cli",
|
|
150
150
|
createRequestId: requestId,
|
|
151
151
|
permissionMode: input.permissionMode,
|
|
152
|
+
modelMode: input.model,
|
|
153
|
+
thoughtLevel: input.thoughtLevel,
|
|
152
154
|
}),
|
|
153
155
|
});
|
|
154
156
|
if (result.sessionId) {
|
|
@@ -416,6 +418,8 @@ export class ControllerClient {
|
|
|
416
418
|
}),
|
|
417
419
|
...(options.promptHash === undefined ? {} : { promptHash: requireNonEmpty(options.promptHash, "promptHash") }),
|
|
418
420
|
permissionMode: options.permissionMode ?? "approve-reads",
|
|
421
|
+
model: options.model,
|
|
422
|
+
thoughtLevel: options.thoughtLevel,
|
|
419
423
|
timeoutMs: options.runtimeTimeoutMs,
|
|
420
424
|
}, wait, timeoutMs);
|
|
421
425
|
if (wait) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DirectoryListing, EncryptedSessionEvent, FilePreviewMode, FilePreviewResult, HistoricalSessionSnapshot, MachineSnapshot, MachineDevExecResult, MachineDiagnostics, ServerMessage, SessionEventPayload, SessionSnapshot } from "../../shared/dist/index.js";
|
|
1
|
+
import type { DirectoryListing, EncryptedSessionEvent, FilePreviewMode, FilePreviewResult, HistoricalSessionSnapshot, MachineSnapshot, MachineDevExecResult, MachineDiagnostics, RuntimeOptions, ServerMessage, SessionEventPayload, SessionSnapshot } from "../../shared/dist/index.js";
|
|
2
2
|
export type ControllerClientConfig = {
|
|
3
3
|
relayUrl: string;
|
|
4
4
|
controllerToken: string;
|
|
@@ -123,6 +123,9 @@ export type SessionMetadata = {
|
|
|
123
123
|
cwd?: string;
|
|
124
124
|
agent?: string;
|
|
125
125
|
permissionMode?: PermissionMode;
|
|
126
|
+
modelMode?: string | null;
|
|
127
|
+
thoughtLevel?: string | null;
|
|
128
|
+
runtimeOptions?: RuntimeOptions;
|
|
126
129
|
[key: string]: unknown;
|
|
127
130
|
};
|
|
128
131
|
export type SessionFilter = {
|
|
@@ -139,10 +142,14 @@ export type CreateSessionInput = {
|
|
|
139
142
|
runtimeName?: string;
|
|
140
143
|
createdFrom?: string;
|
|
141
144
|
permissionMode?: PermissionMode;
|
|
145
|
+
model?: string | null;
|
|
146
|
+
thoughtLevel?: string | null;
|
|
142
147
|
};
|
|
143
148
|
export type RunOptions = {
|
|
144
149
|
wait?: boolean;
|
|
145
150
|
permissionMode?: PermissionMode;
|
|
151
|
+
model?: string | null;
|
|
152
|
+
thoughtLevel?: string | null;
|
|
146
153
|
requestId?: string;
|
|
147
154
|
turnId?: string;
|
|
148
155
|
promptHash?: string;
|
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { spawn, spawnSync } from "node:child_process";
|
|
3
3
|
import fs from "node:fs";
|
|
4
|
+
import os from "node:os";
|
|
4
5
|
import path from "node:path";
|
|
5
6
|
import readline from "node:readline";
|
|
6
7
|
import { ProviderError, serveHappyElvesProvider, } from "../../agent-sdk/dist/index.js";
|
|
7
8
|
const providerId = "pie";
|
|
8
9
|
const pieCommand = process.env.HAPPY_ELVES_PIE_COMMAND || "pie";
|
|
9
10
|
const pieConfigDir = process.env.HAPPY_ELVES_PIE_CONFIG_DIR;
|
|
10
|
-
const minimumPieVersion = "1.0.
|
|
11
|
+
const minimumPieVersion = "1.0.21";
|
|
11
12
|
const stderrRingChars = 16 * 1024;
|
|
12
13
|
const defaultTurnTimeoutMs = 10 * 60 * 1000;
|
|
13
14
|
const pieCommandTimeoutMs = 60_000;
|
|
@@ -18,6 +19,55 @@ let stderrRing = "";
|
|
|
18
19
|
let lastError;
|
|
19
20
|
let pieVersion = process.env.HAPPY_ELVES_PIE_VERSION || readPieVersionSync();
|
|
20
21
|
let pieSupportCheck;
|
|
22
|
+
function normalizeRuntimeSelection(value) {
|
|
23
|
+
if (value === null)
|
|
24
|
+
return null;
|
|
25
|
+
const normalized = value.trim();
|
|
26
|
+
return normalized && normalized !== "default" ? normalized : null;
|
|
27
|
+
}
|
|
28
|
+
function pieRuntimeOptions() {
|
|
29
|
+
const models = readPieModelOptions();
|
|
30
|
+
return {
|
|
31
|
+
...(models.length > 0 ? { models: [{ key: "default", label: "Default" }, ...models] } : {}),
|
|
32
|
+
thoughtLevels: [
|
|
33
|
+
{ key: "default", label: "Default" },
|
|
34
|
+
{ key: "off", label: "Off" },
|
|
35
|
+
{ key: "minimal", label: "Minimal" },
|
|
36
|
+
{ key: "low", label: "Low" },
|
|
37
|
+
{ key: "medium", label: "Medium" },
|
|
38
|
+
{ key: "high", label: "High" },
|
|
39
|
+
{ key: "xhigh", label: "X High" },
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
function readPieModelOptions() {
|
|
44
|
+
const modelsPath = path.join(pieConfigDir || path.join(os.homedir(), ".pie"), "models.json");
|
|
45
|
+
let parsed;
|
|
46
|
+
try {
|
|
47
|
+
parsed = JSON.parse(fs.readFileSync(modelsPath, "utf8"));
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return [];
|
|
51
|
+
}
|
|
52
|
+
if (!isRecord(parsed) || !isRecord(parsed.profiles))
|
|
53
|
+
return [];
|
|
54
|
+
const options = [];
|
|
55
|
+
for (const [profileId, profile] of Object.entries(parsed.profiles)) {
|
|
56
|
+
if (!isRecord(profile) || !Array.isArray(profile.models))
|
|
57
|
+
continue;
|
|
58
|
+
for (const model of profile.models) {
|
|
59
|
+
if (!isRecord(model) || typeof model.id !== "string" || model.id.length === 0)
|
|
60
|
+
continue;
|
|
61
|
+
const label = typeof model.name === "string" && model.name.trim() ? model.name.trim() : `${profileId}/${model.id}`;
|
|
62
|
+
options.push({
|
|
63
|
+
key: `${profileId}/${model.id}`,
|
|
64
|
+
label,
|
|
65
|
+
...(model.reasoning === true ? { description: "Supports thinking levels" } : {}),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return options;
|
|
70
|
+
}
|
|
21
71
|
const provider = {
|
|
22
72
|
getProviderInfo() {
|
|
23
73
|
return { id: providerId, label: "Pie", version: pieVersion || "unknown" };
|
|
@@ -32,6 +82,7 @@ const provider = {
|
|
|
32
82
|
sessionPrimitives: { resume: "authoritative", rewind: "authoritative", fork: "authoritative", rename: "provider" },
|
|
33
83
|
permissionModes: ["approve-reads", "approve-all"],
|
|
34
84
|
history: true,
|
|
85
|
+
runtimeOptions: pieRuntimeOptions(),
|
|
35
86
|
},
|
|
36
87
|
}];
|
|
37
88
|
},
|
|
@@ -149,7 +200,11 @@ const provider = {
|
|
|
149
200
|
turnId,
|
|
150
201
|
prompt: input.text,
|
|
151
202
|
cwd: input.handle.cwd,
|
|
152
|
-
metadata: {
|
|
203
|
+
metadata: {
|
|
204
|
+
permissionMode,
|
|
205
|
+
...(input.model !== undefined ? { model: normalizeRuntimeSelection(input.model) } : {}),
|
|
206
|
+
...(input.thoughtLevel !== undefined ? { thinkingLevel: normalizeRuntimeSelection(input.thoughtLevel) } : {}),
|
|
207
|
+
},
|
|
153
208
|
});
|
|
154
209
|
};
|
|
155
210
|
void run().catch((error) => {
|
|
@@ -529,14 +584,14 @@ async function checkPieSessionsSupport() {
|
|
|
529
584
|
throw new ProviderError("PROVIDER_UNAVAILABLE", `Pie CLI version ${pieVersion} is too old; expected >= ${minimumPieVersion}`, { detailCode: "PIE_VERSION_TOO_OLD", retryable: false });
|
|
530
585
|
}
|
|
531
586
|
await runPieJson(["sessions", "list", "--json", "--limit", "1"]);
|
|
532
|
-
await
|
|
587
|
+
await runPieJson(["models", "validate", "--json"]);
|
|
533
588
|
}
|
|
534
589
|
catch (error) {
|
|
535
590
|
if (error instanceof ProviderError && (error.detailCode === "PIE_VERSION_TOO_OLD" || error.retryable === false)) {
|
|
536
591
|
lastError = error.message;
|
|
537
592
|
throw error;
|
|
538
593
|
}
|
|
539
|
-
const message = `Pie command is unavailable or not fully configured; expected \`pie sessions list --json\` and \`pie models validate\` to succeed. ${normalizeError(error).message}`;
|
|
594
|
+
const message = `Pie command is unavailable or not fully configured; expected \`pie sessions list --json\` and \`pie models validate --json\` to succeed. ${normalizeError(error).message}`;
|
|
540
595
|
lastError = message;
|
|
541
596
|
throw new ProviderError("PROVIDER_UNAVAILABLE", message, { detailCode: "PIE_SESSIONS_UNAVAILABLE", retryable: true });
|
|
542
597
|
}
|