@cydm/happy-elves 0.1.0-beta.247 → 0.1.0-beta.251
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/cli/dist/commands/memory.js +4 -3
- package/apps/cli/dist/commands/schedule.js +9 -1
- package/apps/cli/dist/commands/session.js +2 -1
- package/apps/cli/dist/commands/turn.js +11 -5
- package/apps/cli/dist/commands/workspace.js +6 -3
- package/apps/cli/package.json +1 -1
- package/apps/daemon/dist/gateway/runtime.js +2 -0
- package/apps/daemon/dist/relay/admission.d.ts +2 -0
- package/apps/daemon/dist/relay/connection.js +5 -1
- package/apps/daemon/dist/relay/register.js +2 -0
- package/apps/daemon/dist/runtime/external-provider.js +56 -14
- package/apps/daemon/dist/session/events.js +10 -0
- package/apps/daemon/dist/session/lifecycle.js +7 -0
- package/apps/daemon/dist/session/metadata.d.ts +1 -1
- package/apps/daemon/dist/session/metadata.js +2 -0
- package/apps/daemon/dist/session/prompt.d.ts +2 -1
- package/apps/daemon/dist/session/prompt.js +122 -2
- package/apps/daemon/dist/types.d.ts +3 -0
- package/apps/daemon/package.json +1 -1
- package/apps/relay/dist/controller-handlers.js +27 -0
- package/apps/relay/dist/http-routes.js +2 -0
- package/apps/relay/dist/http-schemas.d.ts +2 -0
- package/apps/relay/dist/http-schemas.js +2 -0
- package/apps/relay/dist/machine-handlers.js +14 -2
- package/package.json +1 -1
- package/packages/agent-sdk/dist/index.d.ts +39 -0
- package/packages/agent-sdk/dist/index.js +12 -0
- package/packages/client/dist/client.js +8 -0
- package/packages/client/dist/types.d.ts +2 -0
- package/packages/runtime/dist/index.d.ts +30 -0
- package/packages/runtime-cli/dist/claude-turn.d.ts +1 -0
- package/packages/runtime-cli/dist/claude-turn.js +1 -0
- package/packages/runtime-cli/dist/codex-app-server.d.ts +5 -2
- package/packages/runtime-cli/dist/codex-app-server.js +25 -16
- package/packages/runtime-cli/dist/codex-protocol.d.ts +2 -2
- package/packages/runtime-cli/dist/codex-protocol.js +4 -4
- package/packages/runtime-cli/dist/index.js +31 -2
- package/packages/runtime-cli/dist/session-store.d.ts +1 -0
- package/packages/runtime-cli/dist/session-store.js +9 -8
- package/packages/shared/dist/index.d.ts +1 -0
- package/packages/shared/dist/index.js +1 -0
- package/packages/shared/dist/protocol-schemas.d.ts +14 -0
- package/packages/shared/dist/protocol-schemas.js +7 -0
- package/packages/shared/dist/protocol-types.d.ts +32 -0
- package/packages/shared/dist/protocol.d.ts +26 -0
- package/packages/shared/dist/protocol.js +29 -0
|
@@ -147,9 +147,10 @@ function parseMemoryLayer(value) {
|
|
|
147
147
|
function parseMemoryMode(value) {
|
|
148
148
|
if (typeof value !== "string" || !value.trim())
|
|
149
149
|
return undefined;
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
150
|
+
const normalized = value.trim().toLowerCase().replace(/-/g, "");
|
|
151
|
+
if (normalized === "off" || normalized === "readonly" || normalized === "readwrite")
|
|
152
|
+
return normalized;
|
|
153
|
+
throw new CliError("Invalid --mode; expected off|readonly|readwrite|read-only|read-write", "INVALID_ARGUMENT");
|
|
153
154
|
}
|
|
154
155
|
function parsePromotionLayer(value) {
|
|
155
156
|
const layer = parseMemoryLayer(value);
|
|
@@ -10,7 +10,7 @@ export async function handleSchedule({ domain, action, positional, flags }) {
|
|
|
10
10
|
const schedule = parseScheduleSpec(flags);
|
|
11
11
|
const target = parseScheduleTarget(flags, sessionId);
|
|
12
12
|
const execution = parseChoice(flags.execution, "execution", ["continue", "isolated"]) ?? "continue";
|
|
13
|
-
const memoryMode =
|
|
13
|
+
const memoryMode = parseScheduleMemoryMode(flags.memory ?? flags["memory-mode"]) ?? "inherit";
|
|
14
14
|
const prompt = typeof flags.prompt === "string"
|
|
15
15
|
? flags.prompt
|
|
16
16
|
: typeof flags["prompt-file"] === "string"
|
|
@@ -220,6 +220,14 @@ function parseChoice(value, name, choices) {
|
|
|
220
220
|
return value;
|
|
221
221
|
throw new CliError(`Invalid --${name}; expected ${choices.join("|")}`, "INVALID_ARGUMENT");
|
|
222
222
|
}
|
|
223
|
+
function parseScheduleMemoryMode(value) {
|
|
224
|
+
if (typeof value !== "string" || !value.trim())
|
|
225
|
+
return undefined;
|
|
226
|
+
const normalized = value.trim().toLowerCase().replace(/-/g, "");
|
|
227
|
+
if (normalized === "inherit" || normalized === "off" || normalized === "readonly" || normalized === "readwrite")
|
|
228
|
+
return normalized;
|
|
229
|
+
throw new CliError("Invalid --memory; expected inherit|off|readonly|readwrite|read-only|read-write", "INVALID_ARGUMENT");
|
|
230
|
+
}
|
|
223
231
|
function parseStopOn(value) {
|
|
224
232
|
if (typeof value !== "string" || !value.trim())
|
|
225
233
|
return ["blocked", "failed", "permission"];
|
|
@@ -353,8 +353,9 @@ export async function handleSession({ domain, action, positional, flags }) {
|
|
|
353
353
|
const requestedRuntimeName = typeof flags.name === "string" ? flags.name : undefined;
|
|
354
354
|
const name = "main";
|
|
355
355
|
const permissionMode = parsePermissionMode(flags["permission-mode"] ?? flags.permission);
|
|
356
|
+
const model = typeof flags.model === "string" && flags.model.trim() ? flags.model.trim() : undefined;
|
|
356
357
|
const client = await makeClient();
|
|
357
|
-
const result = await client.createSession({ machineId, agent, cwd, name, runtimeName: requestedRuntimeName, permissionMode });
|
|
358
|
+
const result = await client.createSession({ machineId, agent, cwd, name, runtimeName: requestedRuntimeName, permissionMode, model });
|
|
358
359
|
const session = result.sessionId ? await client.getSession(result.sessionId) : undefined;
|
|
359
360
|
const projectedSession = session
|
|
360
361
|
? wantsVerbose(flags)
|
|
@@ -201,6 +201,8 @@ export async function handleTurn({ domain, action, positional, flags }) {
|
|
|
201
201
|
: "";
|
|
202
202
|
if (!continuation.trim())
|
|
203
203
|
throw new CliError("Missing --text or --text-file", "MISSING_ARGUMENT");
|
|
204
|
+
const permissionMode = parsePermissionMode(flags["permission-mode"] ?? flags.permission);
|
|
205
|
+
const model = typeof flags.model === "string" && flags.model.trim() ? flags.model.trim() : undefined;
|
|
204
206
|
const sourceSession = await requireProjectedSession(client, sessionId, "turn.recover");
|
|
205
207
|
const sourceMetadata = await client.decodeSessionMetadata(sourceSession);
|
|
206
208
|
const sourceName = sourceMetadata.name ?? sourceSession.name;
|
|
@@ -229,7 +231,8 @@ export async function handleTurn({ domain, action, positional, flags }) {
|
|
|
229
231
|
cwd: sourceMetadata.cwd ?? sourceSession.cwd,
|
|
230
232
|
name: recoveryName,
|
|
231
233
|
createdFrom: "turn.recover",
|
|
232
|
-
permissionMode
|
|
234
|
+
permissionMode,
|
|
235
|
+
model,
|
|
233
236
|
});
|
|
234
237
|
if (!created.sessionId)
|
|
235
238
|
throw new CliError("Recovery session create was acknowledged without sessionId", "RELAY_RESPONSE_INVALID");
|
|
@@ -237,7 +240,6 @@ export async function handleTurn({ domain, action, positional, flags }) {
|
|
|
237
240
|
promptText = recoveryPromptWithContext(turns, inputTurnId, continuation);
|
|
238
241
|
}
|
|
239
242
|
await client.wait(recoverySessionId, { timeoutMs: 120_000 });
|
|
240
|
-
const permissionMode = parsePermissionMode(flags["permission-mode"] ?? flags.permission);
|
|
241
243
|
const wait = flags.detach !== true && flags["no-wait"] !== true;
|
|
242
244
|
const memoryMode = parseMemoryModeFlag(flags["memory-mode"] ?? flags.memory) ?? "readonly";
|
|
243
245
|
const recoverySession = await client.getSession(recoverySessionId);
|
|
@@ -250,6 +252,7 @@ export async function handleTurn({ domain, action, positional, flags }) {
|
|
|
250
252
|
wait,
|
|
251
253
|
permissionMode,
|
|
252
254
|
memoryMode,
|
|
255
|
+
model,
|
|
253
256
|
...(memoryProject ? { memoryProjectKey: memoryProject } : {}),
|
|
254
257
|
memoryTopN: 3,
|
|
255
258
|
waitTimeoutMs: parseDurationMs(flags.timeout, DEFAULT_COMMAND_TIMEOUT_MS),
|
|
@@ -289,6 +292,7 @@ export async function handleTurn({ domain, action, positional, flags }) {
|
|
|
289
292
|
const ackTimeoutMs = 15_000;
|
|
290
293
|
const inactivityTimeoutMs = parseDurationMs(flags["inactivity-timeout"] ?? flags["runtime-timeout"], DEFAULT_COMMAND_TIMEOUT_MS);
|
|
291
294
|
const memoryMode = parseMemoryModeFlag(flags["memory-mode"] ?? flags.memory) ?? "readonly";
|
|
295
|
+
const model = typeof flags.model === "string" && flags.model.trim() ? flags.model.trim() : undefined;
|
|
292
296
|
const session = await client.getSession(sessionId);
|
|
293
297
|
const memoryProject = typeof flags["memory-project"] === "string"
|
|
294
298
|
? flags["memory-project"]
|
|
@@ -302,6 +306,7 @@ export async function handleTurn({ domain, action, positional, flags }) {
|
|
|
302
306
|
wait,
|
|
303
307
|
permissionMode,
|
|
304
308
|
memoryMode,
|
|
309
|
+
model,
|
|
305
310
|
...(memoryProject ? { memoryProjectKey: memoryProject } : {}),
|
|
306
311
|
memoryTopN,
|
|
307
312
|
waitTimeoutMs: watchTimeoutMs,
|
|
@@ -442,8 +447,9 @@ export async function handleTurn({ domain, action, positional, flags }) {
|
|
|
442
447
|
function parseMemoryModeFlag(value) {
|
|
443
448
|
if (typeof value !== "string" || !value.trim())
|
|
444
449
|
return undefined;
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
450
|
+
const normalized = value.trim().toLowerCase().replace(/-/g, "");
|
|
451
|
+
if (normalized === "off" || normalized === "readonly" || normalized === "readwrite")
|
|
452
|
+
return normalized;
|
|
453
|
+
throw new CliError("Invalid --memory-mode; expected off|readonly|readwrite|read-only|read-write", "INVALID_ARGUMENT");
|
|
448
454
|
}
|
|
449
455
|
//# sourceMappingURL=turn.js.map
|
|
@@ -58,8 +58,11 @@ export async function handleWorkspace({ domain, action, positional, flags }) {
|
|
|
58
58
|
function parseMemoryMode(value) {
|
|
59
59
|
if (value === undefined || value === false)
|
|
60
60
|
return undefined;
|
|
61
|
-
if (
|
|
62
|
-
return
|
|
63
|
-
|
|
61
|
+
if (typeof value !== "string" || !value.trim())
|
|
62
|
+
return undefined;
|
|
63
|
+
const normalized = value.trim().toLowerCase().replace(/-/g, "");
|
|
64
|
+
if (normalized === "off" || normalized === "readonly" || normalized === "readwrite")
|
|
65
|
+
return normalized;
|
|
66
|
+
throw new CliError("Invalid --memory-mode; expected off|readonly|readwrite|read-only|read-write", "INVALID_ARGUMENT");
|
|
64
67
|
}
|
|
65
68
|
//# sourceMappingURL=workspace.js.map
|
package/apps/cli/package.json
CHANGED
|
@@ -294,6 +294,7 @@ async function createGatewayMapping(config, channel, externalConversationId, cre
|
|
|
294
294
|
agent: channel.defaultAgent,
|
|
295
295
|
cwd: channel.targetCwd,
|
|
296
296
|
name: `Gateway ${channel.type}: ${externalConversationId}`,
|
|
297
|
+
...(channel.defaultModel ? { model: channel.defaultModel } : {}),
|
|
297
298
|
encryptedMetadata: await encryptJson(config.accountSecret, `gateway:create:${createRequestId}`, {
|
|
298
299
|
createdFrom: "gateway",
|
|
299
300
|
gateway: {
|
|
@@ -353,6 +354,7 @@ async function admitGatewayPromptNow(config, channel, input) {
|
|
|
353
354
|
text: input.text,
|
|
354
355
|
}),
|
|
355
356
|
permissionMode: "approve-reads",
|
|
357
|
+
...(channel.defaultModel ? { model: channel.defaultModel } : {}),
|
|
356
358
|
});
|
|
357
359
|
const turnId = sent.turnId ?? input.turnId;
|
|
358
360
|
const lastAdmitted = {
|
|
@@ -15,6 +15,7 @@ export declare function admitMachineCreateSession(config: DaemonConfig, input: {
|
|
|
15
15
|
agent: string;
|
|
16
16
|
cwd: string;
|
|
17
17
|
name: string;
|
|
18
|
+
model?: string;
|
|
18
19
|
encryptedMetadata?: EncryptedEnvelope;
|
|
19
20
|
}): Promise<MachineAdmissionAck>;
|
|
20
21
|
export declare function admitMachinePrompt(config: DaemonConfig, input: {
|
|
@@ -24,5 +25,6 @@ export declare function admitMachinePrompt(config: DaemonConfig, input: {
|
|
|
24
25
|
encryptedPrompt: EncryptedEnvelope;
|
|
25
26
|
encryptedMemoryOptions?: EncryptedEnvelope;
|
|
26
27
|
permissionMode?: PermissionMode;
|
|
28
|
+
model?: string;
|
|
27
29
|
timeoutMs?: number;
|
|
28
30
|
}): Promise<MachineAdmissionAck>;
|
|
@@ -7,7 +7,7 @@ import { tickSchedules } from "../schedule/runner.js";
|
|
|
7
7
|
import { handleListDirectory } from "../session/directory.js";
|
|
8
8
|
import { handlePreviewFile } from "../session/file-preview.js";
|
|
9
9
|
import { handleClose, handleCreateSession, handleImportHistoricalSession, handleListHistoricalSessions, handleResume } from "../session/lifecycle.js";
|
|
10
|
-
import { handleCancel, handlePrompt } from "../session/prompt.js";
|
|
10
|
+
import { handleCancel, handleOptionResponse, handlePrompt } from "../session/prompt.js";
|
|
11
11
|
import { handleFork, handleRename, handleRewind } from "../session/primitives.js";
|
|
12
12
|
import { handleReconcileTurn } from "../session/reconcile.js";
|
|
13
13
|
import { parseRelayMessage, relayWsUrl } from "../relay-http.js";
|
|
@@ -87,6 +87,10 @@ async function handleServerMessage(ws, config, message) {
|
|
|
87
87
|
await handleCancel(ws, config, message);
|
|
88
88
|
return;
|
|
89
89
|
}
|
|
90
|
+
if (message.type === "machine:optionResponse") {
|
|
91
|
+
await handleOptionResponse(ws, config, message);
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
90
94
|
if (message.type === "machine:reconcileTurn") {
|
|
91
95
|
await handleReconcileTurn(ws, config, message);
|
|
92
96
|
return;
|
|
@@ -22,6 +22,8 @@ function agentProfileForRegister(agent) {
|
|
|
22
22
|
id: agent.id,
|
|
23
23
|
label: agent.label,
|
|
24
24
|
...(agent.command ? { command: agent.command } : {}),
|
|
25
|
+
...(agent.defaultModel ? { defaultModel: agent.defaultModel } : {}),
|
|
26
|
+
...(agent.models && agent.models.length > 0 ? { models: agent.models } : {}),
|
|
25
27
|
...(agent.historyModel ? { historyModel: agent.historyModel } : {}),
|
|
26
28
|
...(agent.sessionPrimitives ? { sessionPrimitives: runtimeAgentPrimitives(agent.sessionPrimitives) } : {}),
|
|
27
29
|
};
|
|
@@ -226,6 +226,7 @@ export function createExternalAgentRuntimeProvider(options) {
|
|
|
226
226
|
agentSessionId: handle.sessionId,
|
|
227
227
|
externalProviderId: handle.provider,
|
|
228
228
|
externalHandle: handle,
|
|
229
|
+
...(handle.model ? { model: handle.model } : {}),
|
|
229
230
|
};
|
|
230
231
|
}
|
|
231
232
|
function sdkHandle(handle) {
|
|
@@ -282,20 +283,26 @@ export function createExternalAgentRuntimeProvider(options) {
|
|
|
282
283
|
return options.fallback.getCapabilities();
|
|
283
284
|
},
|
|
284
285
|
listAgents() {
|
|
285
|
-
const externalAgents = clients.flatMap((client) => client.listAgents()).map((agent) =>
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
286
|
+
const externalAgents = clients.flatMap((client) => client.listAgents()).map((agent) => {
|
|
287
|
+
const defaultModel = normalizedModelId(agent.defaultModel);
|
|
288
|
+
const models = normalizeModelOptions(agent.models);
|
|
289
|
+
return {
|
|
290
|
+
id: agent.id,
|
|
291
|
+
label: agent.label,
|
|
292
|
+
command: agent.command,
|
|
293
|
+
...(defaultModel ? { defaultModel } : {}),
|
|
294
|
+
...(models ? { models } : {}),
|
|
295
|
+
historyModel: normalizeHistoryModel(agent.historyModel),
|
|
296
|
+
sessionPrimitives: agent.capabilities?.sessionPrimitives
|
|
297
|
+
? {
|
|
298
|
+
resume: fromSdkPrimitive(agent.capabilities.sessionPrimitives.resume),
|
|
299
|
+
rewind: fromSdkPrimitive(agent.capabilities.sessionPrimitives.rewind),
|
|
300
|
+
fork: fromSdkPrimitive(agent.capabilities.sessionPrimitives.fork),
|
|
301
|
+
rename: agent.capabilities.sessionPrimitives.rename ? fromSdkPrimitive(agent.capabilities.sessionPrimitives.rename) : "unsupported",
|
|
302
|
+
}
|
|
303
|
+
: undefined,
|
|
304
|
+
};
|
|
305
|
+
});
|
|
299
306
|
const agentsById = new Map();
|
|
300
307
|
for (const agent of externalAgents)
|
|
301
308
|
agentsById.set(agent.id, agent);
|
|
@@ -318,6 +325,7 @@ export function createExternalAgentRuntimeProvider(options) {
|
|
|
318
325
|
...(input.resumeHandle ? { resumeHandle: sdkHandle(input.resumeHandle) } : {}),
|
|
319
326
|
cwd: input.cwd,
|
|
320
327
|
permissionMode: input.permissionMode,
|
|
328
|
+
model: input.model,
|
|
321
329
|
restartableEmptySession: input.restartableEmptySession,
|
|
322
330
|
});
|
|
323
331
|
return toRuntimeHandle(input.sessionKey, handle, input.cwd);
|
|
@@ -466,6 +474,7 @@ export function createExternalAgentRuntimeProvider(options) {
|
|
|
466
474
|
mode: input.mode,
|
|
467
475
|
permissionMode: input.permissionMode,
|
|
468
476
|
requestId: input.requestId,
|
|
477
|
+
model: input.model ?? input.handle.model,
|
|
469
478
|
});
|
|
470
479
|
},
|
|
471
480
|
cancel(input) {
|
|
@@ -523,6 +532,31 @@ function emptyPageUnlessCursorStale(error) {
|
|
|
523
532
|
throw error;
|
|
524
533
|
return { sessions: [] };
|
|
525
534
|
}
|
|
535
|
+
function normalizedModelId(value) {
|
|
536
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
537
|
+
}
|
|
538
|
+
function normalizeModelOptions(value) {
|
|
539
|
+
if (!Array.isArray(value))
|
|
540
|
+
return undefined;
|
|
541
|
+
const seen = new Set();
|
|
542
|
+
const models = value.flatMap((item) => {
|
|
543
|
+
if (!isRecord(item))
|
|
544
|
+
return [];
|
|
545
|
+
const id = normalizedModelId(item.id);
|
|
546
|
+
if (!id || seen.has(id))
|
|
547
|
+
return [];
|
|
548
|
+
seen.add(id);
|
|
549
|
+
const label = normalizedModelId(item.label);
|
|
550
|
+
const reason = normalizedModelId(item.reason);
|
|
551
|
+
return [{
|
|
552
|
+
id,
|
|
553
|
+
...(label ? { label } : {}),
|
|
554
|
+
...(item.unavailable === true ? { unavailable: true } : {}),
|
|
555
|
+
...(reason ? { reason } : {}),
|
|
556
|
+
}];
|
|
557
|
+
});
|
|
558
|
+
return models.length > 0 ? models : undefined;
|
|
559
|
+
}
|
|
526
560
|
class ExternalProviderClient {
|
|
527
561
|
config;
|
|
528
562
|
id;
|
|
@@ -653,6 +687,14 @@ class ExternalProviderClient {
|
|
|
653
687
|
cancel: async (input) => {
|
|
654
688
|
await this.request("cancel", { handle: params.handle, reason: input?.reason });
|
|
655
689
|
},
|
|
690
|
+
respondOption: async (input) => {
|
|
691
|
+
await this.request("respondOption", {
|
|
692
|
+
handle: params.handle,
|
|
693
|
+
optionRequestId: input.optionRequestId,
|
|
694
|
+
...(input.selectedOptionId ? { selectedOptionId: input.selectedOptionId } : {}),
|
|
695
|
+
...(input.text ? { text: input.text } : {}),
|
|
696
|
+
});
|
|
697
|
+
},
|
|
656
698
|
closeStream: async (input) => {
|
|
657
699
|
await this.request("cancel", { handle: params.handle, reason: input?.reason ?? "stream closed" });
|
|
658
700
|
},
|
|
@@ -147,6 +147,16 @@ export function runtimeEventToPayload(event) {
|
|
|
147
147
|
title: event.title,
|
|
148
148
|
};
|
|
149
149
|
}
|
|
150
|
+
if (event.type === "option_request") {
|
|
151
|
+
return {
|
|
152
|
+
type: "option_request",
|
|
153
|
+
optionRequestId: event.optionRequestId,
|
|
154
|
+
...(event.title ? { title: event.title } : {}),
|
|
155
|
+
message: event.message,
|
|
156
|
+
options: event.options,
|
|
157
|
+
...(event.allowFreeText ? { allowFreeText: true } : {}),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
150
160
|
if (event.type === "status") {
|
|
151
161
|
if (typeof event.used === "number" && Number.isFinite(event.used)) {
|
|
152
162
|
return {
|
|
@@ -15,6 +15,7 @@ export async function handleCreateSession(ws, config, command) {
|
|
|
15
15
|
const cwd = command.cwd || process.cwd();
|
|
16
16
|
try {
|
|
17
17
|
const metadata = await commandSessionMetadata(config, command.encryptedMetadata);
|
|
18
|
+
const model = modelFromCommand(command.model ?? metadata?.model);
|
|
18
19
|
const runtime = getRuntime(cwd);
|
|
19
20
|
let handle = await runtime.ensureSession({
|
|
20
21
|
sessionKey: command.sessionId,
|
|
@@ -22,6 +23,7 @@ export async function handleCreateSession(ws, config, command) {
|
|
|
22
23
|
mode: "persistent",
|
|
23
24
|
cwd,
|
|
24
25
|
permissionMode: metadata?.permissionMode,
|
|
26
|
+
model,
|
|
25
27
|
});
|
|
26
28
|
let providerName;
|
|
27
29
|
const requestedRuntimeName = metadata?.requestedRuntimeName;
|
|
@@ -39,6 +41,7 @@ export async function handleCreateSession(ws, config, command) {
|
|
|
39
41
|
agent: command.agent,
|
|
40
42
|
cwd,
|
|
41
43
|
name: providerName ?? command.name,
|
|
44
|
+
...(model ? { model } : {}),
|
|
42
45
|
handle,
|
|
43
46
|
};
|
|
44
47
|
sessions.set(command.sessionId, state);
|
|
@@ -53,6 +56,7 @@ export async function handleCreateSession(ws, config, command) {
|
|
|
53
56
|
agent: command.agent,
|
|
54
57
|
cwd,
|
|
55
58
|
name: state.name,
|
|
59
|
+
model,
|
|
56
60
|
requestedRuntimeName: requestedRuntimeName ? true : undefined,
|
|
57
61
|
runtime: {
|
|
58
62
|
acpxRecordId: handle.acpxRecordId,
|
|
@@ -78,6 +82,9 @@ export async function handleCreateSession(ws, config, command) {
|
|
|
78
82
|
await sendCommandResponse(ws, createSessionFailureResponse(command, error));
|
|
79
83
|
}
|
|
80
84
|
}
|
|
85
|
+
function modelFromCommand(value) {
|
|
86
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
87
|
+
}
|
|
81
88
|
export async function handleImportHistoricalSession(ws, config, command) {
|
|
82
89
|
if (command.type !== "machine:importHistoricalSession")
|
|
83
90
|
return;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { type EncryptedEnvelope, type MachineCommand } from "../../../../packages/shared/dist/index.js";
|
|
2
2
|
import type { DaemonConfig, SessionFallback, SessionMetadata, SessionState } from "../types.js";
|
|
3
|
-
export declare function encryptedSessionMetadata(config: DaemonConfig, sessionId: string, state: Pick<SessionState, "agent" | "cwd" | "name" | "handle">, extra: Record<string, unknown>): Promise<EncryptedEnvelope>;
|
|
3
|
+
export declare function encryptedSessionMetadata(config: DaemonConfig, sessionId: string, state: Pick<SessionState, "agent" | "cwd" | "name" | "handle" | "model">, extra: Record<string, unknown>): Promise<EncryptedEnvelope>;
|
|
4
4
|
export declare function commandSessionMetadata(config: DaemonConfig, encryptedMetadata?: EncryptedEnvelope): Promise<SessionMetadata | undefined>;
|
|
5
5
|
export declare function sessionFallbackFromCommand(config: DaemonConfig, command: Extract<MachineCommand, {
|
|
6
6
|
type: "machine:prompt" | "machine:resume" | "machine:rewind" | "machine:fork" | "machine:renameSession" | "machine:close";
|
|
@@ -4,6 +4,7 @@ export function encryptedSessionMetadata(config, sessionId, state, extra) {
|
|
|
4
4
|
agent: state.agent,
|
|
5
5
|
cwd: state.cwd,
|
|
6
6
|
name: state.name,
|
|
7
|
+
...(state.model ? { model: state.model } : {}),
|
|
7
8
|
runtime: {
|
|
8
9
|
backend: state.handle.backend,
|
|
9
10
|
runtimeSessionName: state.handle.runtimeSessionName,
|
|
@@ -36,6 +37,7 @@ export async function sessionFallbackFromCommand(config, command) {
|
|
|
36
37
|
agent: metadata.agent ?? "codex",
|
|
37
38
|
cwd: metadata.cwd || process.cwd(),
|
|
38
39
|
name: metadata.name ?? command.sessionId,
|
|
40
|
+
...(typeof metadata.model === "string" && metadata.model.trim() ? { model: metadata.model.trim() } : {}),
|
|
39
41
|
emptyRuntimeSession: metadata.emptyRuntimeSession === true,
|
|
40
42
|
historicalBackfill: historicalBackfillStateFromMetadata(metadata),
|
|
41
43
|
runtime: metadata.runtime,
|
|
@@ -3,8 +3,9 @@ import type { DaemonConfig } from "../types.js";
|
|
|
3
3
|
type PromptCommand = Extract<MachineCommand, {
|
|
4
4
|
type: "machine:prompt";
|
|
5
5
|
}>;
|
|
6
|
-
type PromptExecutionPhase = "decrypt-prompt" | "decrypt-memory-options" | "prepare-memory-context" | "emit-submitted" | "emit-memory-status" | "start-turn" | "attach-turn" | "audit-turn-start" | "stream-turn" | "await-turn-result" | "write-memory" | "refresh-runtime-metadata" | "emit-terminal" | "refresh-authoritative-transcript" | "send-turn-done" | "terminal-hooks";
|
|
6
|
+
type PromptExecutionPhase = "decrypt-prompt" | "prepare-attachments" | "decrypt-memory-options" | "prepare-memory-context" | "emit-submitted" | "emit-memory-status" | "start-turn" | "attach-turn" | "audit-turn-start" | "stream-turn" | "await-turn-result" | "write-memory" | "refresh-runtime-metadata" | "emit-terminal" | "refresh-authoritative-transcript" | "send-turn-done" | "terminal-hooks";
|
|
7
7
|
export declare function handlePrompt(ws: WebSocket, config: DaemonConfig, command: MachineCommand): Promise<void>;
|
|
8
|
+
export declare function handleOptionResponse(ws: WebSocket, config: DaemonConfig, command: MachineCommand): Promise<void>;
|
|
8
9
|
export declare function promptFailureResponse(command: PromptCommand, phase: PromptExecutionPhase, error: unknown): {
|
|
9
10
|
type: "machine:error";
|
|
10
11
|
requestId: string;
|
|
@@ -56,12 +56,15 @@ export async function handlePrompt(ws, config, command) {
|
|
|
56
56
|
try {
|
|
57
57
|
const prompt = await decryptJson(config.accountSecret, command.encryptedPrompt);
|
|
58
58
|
const rawText = prompt.type === "user_prompt" ? prompt.text : JSON.stringify(prompt);
|
|
59
|
+
const promptAttachments = prompt.type === "user_prompt" ? normalizePromptAttachments(prompt.attachments) : [];
|
|
60
|
+
phase = "prepare-attachments";
|
|
61
|
+
const preparedPrompt = preparePromptAttachments(rawText, promptAttachments);
|
|
59
62
|
phase = "decrypt-memory-options";
|
|
60
63
|
const memoryOptions = await decryptMemoryOptions(config, command);
|
|
61
64
|
phase = "prepare-memory-context";
|
|
62
65
|
const memoryContext = memoryOptions
|
|
63
|
-
? await prepareMemoryContext(memoryOptions,
|
|
64
|
-
: { text:
|
|
66
|
+
? await prepareMemoryContext(memoryOptions, preparedPrompt.text)
|
|
67
|
+
: { text: preparedPrompt.text, used: [], options: undefined };
|
|
65
68
|
const text = memoryContext.text;
|
|
66
69
|
phase = "emit-submitted";
|
|
67
70
|
await emitEvent(ws, config, command.sessionId, command.turnId, {
|
|
@@ -95,12 +98,15 @@ export async function handlePrompt(ws, config, command) {
|
|
|
95
98
|
}
|
|
96
99
|
}
|
|
97
100
|
const previousBackendSessionId = session.handle.backendSessionId;
|
|
101
|
+
const model = modelFromCommand(command.model) ?? session.model ?? session.handle.model;
|
|
98
102
|
phase = "start-turn";
|
|
99
103
|
const turn = getRuntime(session.cwd).startTurn({
|
|
100
104
|
handle: session.handle,
|
|
101
105
|
text,
|
|
102
106
|
mode: "prompt",
|
|
103
107
|
permissionMode: command.permissionMode,
|
|
108
|
+
model,
|
|
109
|
+
attachments: preparedPrompt.runtimeAttachments,
|
|
104
110
|
requestId: command.requestId,
|
|
105
111
|
timeoutMs: command.timeoutMs,
|
|
106
112
|
});
|
|
@@ -120,7 +126,10 @@ export async function handlePrompt(ws, config, command) {
|
|
|
120
126
|
turnId: command.turnId,
|
|
121
127
|
promptChars: text.length,
|
|
122
128
|
rawPromptChars: rawText.length,
|
|
129
|
+
attachmentCount: promptAttachments.length,
|
|
130
|
+
runtimeAttachmentCount: preparedPrompt.runtimeAttachments.length,
|
|
123
131
|
permissionMode: command.permissionMode ?? "approve-reads",
|
|
132
|
+
model,
|
|
124
133
|
memoryMode: memoryOptions?.mode,
|
|
125
134
|
usedMemories: memoryContext.used.map((item) => ({ path: item.path, citation: item.citation })),
|
|
126
135
|
},
|
|
@@ -258,6 +267,53 @@ export async function handlePrompt(ws, config, command) {
|
|
|
258
267
|
releasePromptTurn();
|
|
259
268
|
}
|
|
260
269
|
}
|
|
270
|
+
export async function handleOptionResponse(ws, config, command) {
|
|
271
|
+
if (command.type !== "machine:optionResponse")
|
|
272
|
+
return;
|
|
273
|
+
const activeTurnId = sessionTurns.activeTurnId(command.sessionId);
|
|
274
|
+
const activeTurn = sessionTurns.activeTurn(command.sessionId);
|
|
275
|
+
if (!activeTurn || activeTurnId !== command.turnId) {
|
|
276
|
+
await sendCommandResponse(ws, {
|
|
277
|
+
type: "machine:error",
|
|
278
|
+
requestId: command.requestId,
|
|
279
|
+
sessionId: command.sessionId,
|
|
280
|
+
code: "OPTION_REQUEST_NOT_ACTIVE",
|
|
281
|
+
message: "No matching active turn is waiting for this option response",
|
|
282
|
+
});
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (!activeTurn.respondOption) {
|
|
286
|
+
await sendCommandResponse(ws, {
|
|
287
|
+
type: "machine:error",
|
|
288
|
+
requestId: command.requestId,
|
|
289
|
+
sessionId: command.sessionId,
|
|
290
|
+
code: "OPTION_RESPONSE_UNSUPPORTED",
|
|
291
|
+
message: "This runtime does not support Happy Elves option responses",
|
|
292
|
+
});
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
await activeTurn.respondOption({
|
|
296
|
+
optionRequestId: command.optionRequestId,
|
|
297
|
+
...(command.selectedOptionId ? { selectedOptionId: command.selectedOptionId } : {}),
|
|
298
|
+
...(command.text ? { text: command.text } : {}),
|
|
299
|
+
});
|
|
300
|
+
await emitEvent(ws, config, command.sessionId, command.turnId, {
|
|
301
|
+
type: "option_response",
|
|
302
|
+
optionRequestId: command.optionRequestId,
|
|
303
|
+
...(command.selectedOptionId ? { selectedOptionId: command.selectedOptionId } : {}),
|
|
304
|
+
...(command.text ? { text: command.text } : {}),
|
|
305
|
+
});
|
|
306
|
+
await sendCommandResponse(ws, {
|
|
307
|
+
type: "machine:optionResponded",
|
|
308
|
+
requestId: command.requestId,
|
|
309
|
+
sessionId: command.sessionId,
|
|
310
|
+
turnId: command.turnId,
|
|
311
|
+
optionRequestId: command.optionRequestId,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
function modelFromCommand(value) {
|
|
315
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
316
|
+
}
|
|
261
317
|
export function promptFailureResponse(command, phase, error) {
|
|
262
318
|
const code = promptFailureCode(phase, error);
|
|
263
319
|
return {
|
|
@@ -433,4 +489,68 @@ function truncateOutputPreview(value, maxChars) {
|
|
|
433
489
|
return value;
|
|
434
490
|
return value.slice(value.length - maxChars);
|
|
435
491
|
}
|
|
492
|
+
function normalizePromptAttachments(value) {
|
|
493
|
+
if (!Array.isArray(value))
|
|
494
|
+
return [];
|
|
495
|
+
return value.flatMap((attachment) => {
|
|
496
|
+
if (!attachment ||
|
|
497
|
+
typeof attachment.id !== "string" ||
|
|
498
|
+
typeof attachment.name !== "string" ||
|
|
499
|
+
typeof attachment.mediaType !== "string" ||
|
|
500
|
+
typeof attachment.data !== "string" ||
|
|
501
|
+
typeof attachment.sizeBytes !== "number")
|
|
502
|
+
return [];
|
|
503
|
+
return [{
|
|
504
|
+
id: attachment.id,
|
|
505
|
+
name: attachment.name,
|
|
506
|
+
mediaType: attachment.mediaType,
|
|
507
|
+
sizeBytes: attachment.sizeBytes,
|
|
508
|
+
data: attachment.data,
|
|
509
|
+
}];
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
function preparePromptAttachments(text, attachments) {
|
|
513
|
+
const textBlocks = [];
|
|
514
|
+
const runtimeAttachments = [];
|
|
515
|
+
for (const attachment of attachments) {
|
|
516
|
+
const decodedText = decodeTextAttachment(attachment);
|
|
517
|
+
if (decodedText !== undefined) {
|
|
518
|
+
textBlocks.push([
|
|
519
|
+
`--- Attachment: ${attachment.name} (${attachment.mediaType}, ${attachment.sizeBytes} bytes) ---`,
|
|
520
|
+
decodedText,
|
|
521
|
+
"--- End attachment ---",
|
|
522
|
+
].join("\n"));
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
runtimeAttachments.push({
|
|
526
|
+
name: attachment.name,
|
|
527
|
+
mediaType: attachment.mediaType,
|
|
528
|
+
sizeBytes: attachment.sizeBytes,
|
|
529
|
+
data: attachment.data,
|
|
530
|
+
});
|
|
531
|
+
}
|
|
532
|
+
return {
|
|
533
|
+
text: textBlocks.length > 0
|
|
534
|
+
? `${text}\n\nAttached text files:\n\n${textBlocks.join("\n\n")}`
|
|
535
|
+
: text,
|
|
536
|
+
runtimeAttachments,
|
|
537
|
+
};
|
|
538
|
+
}
|
|
539
|
+
function decodeTextAttachment(attachment) {
|
|
540
|
+
const mediaType = attachment.mediaType.toLowerCase();
|
|
541
|
+
const textLike = mediaType.startsWith("text/") ||
|
|
542
|
+
mediaType.includes("json") ||
|
|
543
|
+
mediaType.includes("xml") ||
|
|
544
|
+
mediaType.includes("yaml") ||
|
|
545
|
+
mediaType.includes("csv") ||
|
|
546
|
+
/\.(txt|md|markdown|json|jsonl|yaml|yml|csv|tsv|log|xml|html|css|js|ts|tsx|jsx|vue|py|rb|go|rs|java|c|cc|cpp|h|hpp|sh|zsh|bash|ps1)$/iu.test(attachment.name);
|
|
547
|
+
if (!textLike)
|
|
548
|
+
return undefined;
|
|
549
|
+
try {
|
|
550
|
+
return Buffer.from(attachment.data, "base64").toString("utf8").slice(0, 64 * 1024);
|
|
551
|
+
}
|
|
552
|
+
catch {
|
|
553
|
+
return undefined;
|
|
554
|
+
}
|
|
555
|
+
}
|
|
436
556
|
//# sourceMappingURL=prompt.js.map
|
|
@@ -31,6 +31,7 @@ export type SessionState = {
|
|
|
31
31
|
agent: string;
|
|
32
32
|
cwd: string;
|
|
33
33
|
name: string;
|
|
34
|
+
model?: string;
|
|
34
35
|
handle: RuntimeHandle;
|
|
35
36
|
historicalBackfill?: HistoricalBackfillState;
|
|
36
37
|
};
|
|
@@ -53,6 +54,7 @@ export type SessionMetadata = {
|
|
|
53
54
|
cwd?: string;
|
|
54
55
|
name?: string;
|
|
55
56
|
providerName?: string;
|
|
57
|
+
model?: string;
|
|
56
58
|
requestedRuntimeName?: string;
|
|
57
59
|
permissionMode?: PermissionMode;
|
|
58
60
|
importedFromRuntimeSessionId?: string;
|
|
@@ -83,6 +85,7 @@ export type SessionMetadata = {
|
|
|
83
85
|
};
|
|
84
86
|
};
|
|
85
87
|
export type SessionFallback = Pick<SessionState, "agent" | "cwd" | "name"> & {
|
|
88
|
+
model?: string;
|
|
86
89
|
emptyRuntimeSession?: boolean;
|
|
87
90
|
historicalBackfill?: HistoricalBackfillState;
|
|
88
91
|
runtime?: SessionMetadata["runtime"];
|