@mindstudio-ai/remy 0.1.177 → 0.1.178
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/dist/headless.d.ts +6 -0
- package/dist/headless.js +113 -43
- package/dist/index.js +113 -43
- package/package.json +1 -1
package/dist/headless.d.ts
CHANGED
|
@@ -131,6 +131,12 @@ declare class HeadlessSession {
|
|
|
131
131
|
*/
|
|
132
132
|
private kickDrain;
|
|
133
133
|
private handleClear;
|
|
134
|
+
/** Archive the current session and seed a fresh one with the given
|
|
135
|
+
* per-agent model overrides. Models are immutable for the life of a
|
|
136
|
+
* session — this is the only way to change them. Omitting `models`
|
|
137
|
+
* (or sending an empty object) resets to "use server defaults for
|
|
138
|
+
* every agent". */
|
|
139
|
+
private handleNewSession;
|
|
134
140
|
/** Cancel the running turn and drain the queue. Returns the drained items. */
|
|
135
141
|
private handleCancel;
|
|
136
142
|
private handleStdinLine;
|
package/dist/headless.js
CHANGED
|
@@ -400,16 +400,17 @@ ${loadPlanStatus()}
|
|
|
400
400
|
// src/api.ts
|
|
401
401
|
var log2 = createLogger("api");
|
|
402
402
|
async function* streamChat(params) {
|
|
403
|
-
const { baseUrl: baseUrl2, apiKey, signal, requestId, ...
|
|
403
|
+
const { baseUrl: baseUrl2, apiKey, signal, requestId, model, ...rest } = params;
|
|
404
404
|
const url = `${baseUrl2}/_internal/v2/agent/remy/chat`;
|
|
405
405
|
const startTime = Date.now();
|
|
406
|
-
const subAgentId =
|
|
406
|
+
const subAgentId = rest.subAgentId;
|
|
407
|
+
const requestBody = { ...rest, ...model && { modelId: model } };
|
|
407
408
|
log2.info("API request", {
|
|
408
409
|
requestId,
|
|
409
410
|
...subAgentId && { subAgentId },
|
|
410
|
-
model
|
|
411
|
-
messageCount:
|
|
412
|
-
toolCount:
|
|
411
|
+
model,
|
|
412
|
+
messageCount: rest.messages.length,
|
|
413
|
+
toolCount: rest.tools.length
|
|
413
414
|
});
|
|
414
415
|
let res;
|
|
415
416
|
try {
|
|
@@ -419,7 +420,7 @@ async function* streamChat(params) {
|
|
|
419
420
|
"Content-Type": "application/json",
|
|
420
421
|
Authorization: `Bearer ${apiKey}`
|
|
421
422
|
},
|
|
422
|
-
body: JSON.stringify(
|
|
423
|
+
body: JSON.stringify(requestBody),
|
|
423
424
|
signal
|
|
424
425
|
});
|
|
425
426
|
} catch (err) {
|
|
@@ -447,13 +448,21 @@ async function* streamChat(params) {
|
|
|
447
448
|
});
|
|
448
449
|
if (!res.ok) {
|
|
449
450
|
let errorMessage = `HTTP ${res.status}`;
|
|
451
|
+
let errorCode;
|
|
452
|
+
let badModelId;
|
|
450
453
|
try {
|
|
451
|
-
const
|
|
452
|
-
if (
|
|
453
|
-
errorMessage =
|
|
454
|
+
const body = await res.json();
|
|
455
|
+
if (body.error) {
|
|
456
|
+
errorMessage = body.error;
|
|
457
|
+
}
|
|
458
|
+
if (body.errorMessage) {
|
|
459
|
+
errorMessage = body.errorMessage;
|
|
460
|
+
}
|
|
461
|
+
if (typeof body.code === "string") {
|
|
462
|
+
errorCode = body.code;
|
|
454
463
|
}
|
|
455
|
-
if (
|
|
456
|
-
|
|
464
|
+
if (typeof body.modelId === "string") {
|
|
465
|
+
badModelId = body.modelId;
|
|
457
466
|
}
|
|
458
467
|
} catch {
|
|
459
468
|
}
|
|
@@ -461,9 +470,16 @@ async function* streamChat(params) {
|
|
|
461
470
|
requestId,
|
|
462
471
|
...subAgentId && { subAgentId },
|
|
463
472
|
status: res.status,
|
|
464
|
-
error: errorMessage
|
|
473
|
+
error: errorMessage,
|
|
474
|
+
...errorCode && { code: errorCode },
|
|
475
|
+
...badModelId && { badModelId }
|
|
465
476
|
});
|
|
466
|
-
yield {
|
|
477
|
+
yield {
|
|
478
|
+
type: "error",
|
|
479
|
+
error: errorMessage,
|
|
480
|
+
...errorCode && { code: errorCode },
|
|
481
|
+
...badModelId && { badModelId }
|
|
482
|
+
};
|
|
467
483
|
return;
|
|
468
484
|
}
|
|
469
485
|
const STALL_TIMEOUT_MS = 3e5;
|
|
@@ -654,7 +670,7 @@ var log3 = createLogger("compaction");
|
|
|
654
670
|
var CONVERSATION_SUMMARY_PROMPT = readAsset("compaction", "conversation.md");
|
|
655
671
|
var SUBAGENT_SUMMARY_PROMPT = readAsset("compaction", "subagent.md");
|
|
656
672
|
var SUMMARIZABLE_SUBAGENTS = ["visualDesignExpert", "productVision"];
|
|
657
|
-
async function compactConversation(messages, apiConfig, system, tools2) {
|
|
673
|
+
async function compactConversation(messages, apiConfig, system, tools2, model) {
|
|
658
674
|
const endIndex = findSafeInsertionPoint(messages);
|
|
659
675
|
const summaries = [];
|
|
660
676
|
const tasks = [];
|
|
@@ -670,7 +686,8 @@ async function compactConversation(messages, apiConfig, system, tools2) {
|
|
|
670
686
|
CONVERSATION_SUMMARY_PROMPT,
|
|
671
687
|
conversationMessages,
|
|
672
688
|
system,
|
|
673
|
-
tools2
|
|
689
|
+
tools2,
|
|
690
|
+
model
|
|
674
691
|
).then((text) => {
|
|
675
692
|
if (text) {
|
|
676
693
|
summaries.push({ name: "conversation", text });
|
|
@@ -692,7 +709,8 @@ async function compactConversation(messages, apiConfig, system, tools2) {
|
|
|
692
709
|
SUBAGENT_SUMMARY_PROMPT,
|
|
693
710
|
subagentMessages,
|
|
694
711
|
system,
|
|
695
|
-
tools2
|
|
712
|
+
tools2,
|
|
713
|
+
model
|
|
696
714
|
).then((text) => {
|
|
697
715
|
if (text) {
|
|
698
716
|
summaries.push({ name, text });
|
|
@@ -814,7 +832,7 @@ function serializeForSummary(messages) {
|
|
|
814
832
|
}).join("\n\n");
|
|
815
833
|
}
|
|
816
834
|
var CHUNK_CHAR_LIMIT = 24e5;
|
|
817
|
-
async function generateSummary(apiConfig, name, compactionPrompt, messagesToSummarize, mainSystem, mainTools) {
|
|
835
|
+
async function generateSummary(apiConfig, name, compactionPrompt, messagesToSummarize, mainSystem, mainTools, model) {
|
|
818
836
|
const serialized = serializeForSummary(messagesToSummarize);
|
|
819
837
|
if (!serialized.trim()) {
|
|
820
838
|
return null;
|
|
@@ -833,7 +851,8 @@ async function generateSummary(apiConfig, name, compactionPrompt, messagesToSumm
|
|
|
833
851
|
compactionPrompt,
|
|
834
852
|
messagesToSummarize.slice(0, mid),
|
|
835
853
|
mainSystem,
|
|
836
|
-
mainTools
|
|
854
|
+
mainTools,
|
|
855
|
+
model
|
|
837
856
|
),
|
|
838
857
|
generateSummary(
|
|
839
858
|
apiConfig,
|
|
@@ -841,7 +860,8 @@ async function generateSummary(apiConfig, name, compactionPrompt, messagesToSumm
|
|
|
841
860
|
compactionPrompt,
|
|
842
861
|
messagesToSummarize.slice(mid),
|
|
843
862
|
mainSystem,
|
|
844
|
-
mainTools
|
|
863
|
+
mainTools,
|
|
864
|
+
model
|
|
845
865
|
)
|
|
846
866
|
]);
|
|
847
867
|
const parts = [first, second].filter((p) => !!p);
|
|
@@ -866,6 +886,7 @@ ${serialized}` : serialized;
|
|
|
866
886
|
const iterStart = Date.now();
|
|
867
887
|
for await (const event of streamChat({
|
|
868
888
|
...apiConfig,
|
|
889
|
+
model,
|
|
869
890
|
subAgentId: "conversationSummarizer",
|
|
870
891
|
system,
|
|
871
892
|
messages: [{ role: "user", content: userContent }],
|
|
@@ -3110,6 +3131,9 @@ ${content}` : attachmentHeader;
|
|
|
3110
3131
|
if (thinking.length > 0) {
|
|
3111
3132
|
cleaned2.thinking = thinking;
|
|
3112
3133
|
}
|
|
3134
|
+
if (msg.providerMetadata) {
|
|
3135
|
+
cleaned2.providerMetadata = msg.providerMetadata;
|
|
3136
|
+
}
|
|
3113
3137
|
if (msg.hidden) {
|
|
3114
3138
|
cleaned2.hidden = true;
|
|
3115
3139
|
}
|
|
@@ -3196,6 +3220,7 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
|
|
|
3196
3220
|
let stopReason = "end_turn";
|
|
3197
3221
|
let currentToolNames = "";
|
|
3198
3222
|
let lastUsage;
|
|
3223
|
+
let lastProviderMetadata;
|
|
3199
3224
|
const statusWatcher = startStatusWatcher({
|
|
3200
3225
|
apiConfig,
|
|
3201
3226
|
getContext: () => {
|
|
@@ -3308,6 +3333,7 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
|
|
|
3308
3333
|
cacheReadTokens: event.usage.cacheReadTokens,
|
|
3309
3334
|
llmCalls: 1
|
|
3310
3335
|
};
|
|
3336
|
+
lastProviderMetadata = event.providerMetadata;
|
|
3311
3337
|
recordUsage({
|
|
3312
3338
|
ts: Date.now(),
|
|
3313
3339
|
requestId,
|
|
@@ -3345,7 +3371,8 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
|
|
|
3345
3371
|
messages.push({
|
|
3346
3372
|
role: "assistant",
|
|
3347
3373
|
content: contentBlocks,
|
|
3348
|
-
...lastUsage ? { usage: lastUsage } : {}
|
|
3374
|
+
...lastUsage ? { usage: lastUsage } : {},
|
|
3375
|
+
...lastProviderMetadata ? { providerMetadata: lastProviderMetadata } : {}
|
|
3349
3376
|
});
|
|
3350
3377
|
const toolCalls = contentBlocks.filter(
|
|
3351
3378
|
(b) => b.type === "tool"
|
|
@@ -3746,7 +3773,7 @@ var browserAutomationTool = {
|
|
|
3746
3773
|
return `Error: unknown local tool "${name}"`;
|
|
3747
3774
|
},
|
|
3748
3775
|
apiConfig: context.apiConfig,
|
|
3749
|
-
model: context.model,
|
|
3776
|
+
model: context.models?.browserAutomation ?? context.model,
|
|
3750
3777
|
subAgentId: "browserAutomation",
|
|
3751
3778
|
signal: context.signal,
|
|
3752
3779
|
parentToolId: context.toolCallId,
|
|
@@ -4962,7 +4989,7 @@ var designExpertTool = {
|
|
|
4962
4989
|
);
|
|
4963
4990
|
},
|
|
4964
4991
|
apiConfig: context.apiConfig,
|
|
4965
|
-
model: context.model,
|
|
4992
|
+
model: context.models?.visualDesignExpert ?? context.model,
|
|
4966
4993
|
subAgentId: "visualDesignExpert",
|
|
4967
4994
|
signal: context.signal,
|
|
4968
4995
|
parentToolId: context.toolCallId,
|
|
@@ -5180,7 +5207,7 @@ var productVisionTool = {
|
|
|
5180
5207
|
return executeVisionTool(name, input2, childCtx);
|
|
5181
5208
|
},
|
|
5182
5209
|
apiConfig: context.apiConfig,
|
|
5183
|
-
model: context.model,
|
|
5210
|
+
model: context.models?.productVision ?? context.model,
|
|
5184
5211
|
subAgentId: "productVision",
|
|
5185
5212
|
signal: context.signal,
|
|
5186
5213
|
parentToolId: context.toolCallId,
|
|
@@ -5288,7 +5315,7 @@ var codeSanityCheckTool = {
|
|
|
5288
5315
|
externalTools: /* @__PURE__ */ new Set(),
|
|
5289
5316
|
executeTool: (name, toolInput) => executeTool(name, toolInput, context),
|
|
5290
5317
|
apiConfig: context.apiConfig,
|
|
5291
|
-
model: context.model,
|
|
5318
|
+
model: context.models?.codeSanityCheck ?? context.model,
|
|
5292
5319
|
subAgentId: "codeSanityCheck",
|
|
5293
5320
|
signal: context.signal,
|
|
5294
5321
|
parentToolId: context.toolCallId,
|
|
@@ -5419,7 +5446,7 @@ function triggerCompaction(state, apiConfig, opts = {}) {
|
|
|
5419
5446
|
if (inflightCompaction) {
|
|
5420
5447
|
return inflightCompaction;
|
|
5421
5448
|
}
|
|
5422
|
-
const { blocking = false, requestId } = opts;
|
|
5449
|
+
const { blocking = false, requestId, model } = opts;
|
|
5423
5450
|
listener?.({ type: "started", blocking, requestId });
|
|
5424
5451
|
const system = buildSystemPrompt("onboardingFinished");
|
|
5425
5452
|
const tools2 = getToolDefinitions("onboardingFinished");
|
|
@@ -5427,7 +5454,8 @@ function triggerCompaction(state, apiConfig, opts = {}) {
|
|
|
5427
5454
|
state.messages,
|
|
5428
5455
|
apiConfig,
|
|
5429
5456
|
system,
|
|
5430
|
-
tools2
|
|
5457
|
+
tools2,
|
|
5458
|
+
state.models?.conversationSummarizer ?? model
|
|
5431
5459
|
).then((summaries) => {
|
|
5432
5460
|
pendingSummaries.push(...summaries);
|
|
5433
5461
|
listener?.({ type: "complete", requestId });
|
|
@@ -5451,7 +5479,7 @@ var log8 = createLogger("brandExtraction");
|
|
|
5451
5479
|
var EXTRACT_PROMPT = readAsset("brandExtraction", "extract.md");
|
|
5452
5480
|
var BRAND_FILE = ".remy-brand.json";
|
|
5453
5481
|
var CACHE_FILE = ".remy-brand.cache.json";
|
|
5454
|
-
async function runExtraction(apiConfig) {
|
|
5482
|
+
async function runExtraction(apiConfig, model) {
|
|
5455
5483
|
const inputHash = computeInputHash();
|
|
5456
5484
|
const cached2 = readCache();
|
|
5457
5485
|
if (cached2 && cached2.inputHash === inputHash) {
|
|
@@ -5459,7 +5487,7 @@ async function runExtraction(apiConfig) {
|
|
|
5459
5487
|
return null;
|
|
5460
5488
|
}
|
|
5461
5489
|
log8.info("Extracting brand", { inputHash });
|
|
5462
|
-
const brand = await extractBrand(apiConfig);
|
|
5490
|
+
const brand = await extractBrand(apiConfig, model);
|
|
5463
5491
|
if (!brand) {
|
|
5464
5492
|
log8.warn("Brand extraction failed \u2014 leaving cache untouched");
|
|
5465
5493
|
return null;
|
|
@@ -5528,7 +5556,7 @@ function parseFrontmatter3(filePath) {
|
|
|
5528
5556
|
return { type: "" };
|
|
5529
5557
|
}
|
|
5530
5558
|
}
|
|
5531
|
-
async function extractBrand(apiConfig) {
|
|
5559
|
+
async function extractBrand(apiConfig, model) {
|
|
5532
5560
|
const corpus = buildCorpus();
|
|
5533
5561
|
if (!corpus.trim()) {
|
|
5534
5562
|
log8.debug("No spec corpus \u2014 emitting empty brand");
|
|
@@ -5539,6 +5567,7 @@ async function extractBrand(apiConfig) {
|
|
|
5539
5567
|
try {
|
|
5540
5568
|
for await (const event of streamChat({
|
|
5541
5569
|
...apiConfig,
|
|
5570
|
+
model,
|
|
5542
5571
|
subAgentId: "brandExtractor",
|
|
5543
5572
|
system: EXTRACT_PROMPT,
|
|
5544
5573
|
messages: [{ role: "user", content: corpus }],
|
|
@@ -5716,19 +5745,19 @@ function readCache() {
|
|
|
5716
5745
|
var log9 = createLogger("brandExtraction:trigger");
|
|
5717
5746
|
var inflight = false;
|
|
5718
5747
|
var dirty = false;
|
|
5719
|
-
function triggerBrandExtraction(apiConfig) {
|
|
5748
|
+
function triggerBrandExtraction(apiConfig, model) {
|
|
5720
5749
|
if (inflight) {
|
|
5721
5750
|
dirty = true;
|
|
5722
5751
|
return;
|
|
5723
5752
|
}
|
|
5724
5753
|
inflight = true;
|
|
5725
|
-
void runExtraction(apiConfig).catch((err) => {
|
|
5754
|
+
void runExtraction(apiConfig, model).catch((err) => {
|
|
5726
5755
|
log9.error("Brand extraction failed", { error: err?.message });
|
|
5727
5756
|
}).finally(() => {
|
|
5728
5757
|
inflight = false;
|
|
5729
5758
|
if (dirty) {
|
|
5730
5759
|
dirty = false;
|
|
5731
|
-
triggerBrandExtraction(apiConfig);
|
|
5760
|
+
triggerBrandExtraction(apiConfig, model);
|
|
5732
5761
|
}
|
|
5733
5762
|
});
|
|
5734
5763
|
}
|
|
@@ -5743,9 +5772,15 @@ function loadSession(state) {
|
|
|
5743
5772
|
try {
|
|
5744
5773
|
const raw = fs21.readFileSync(SESSION_FILE, "utf-8");
|
|
5745
5774
|
const data = JSON.parse(raw);
|
|
5775
|
+
if (data.models && typeof data.models === "object") {
|
|
5776
|
+
state.models = data.models;
|
|
5777
|
+
}
|
|
5746
5778
|
if (Array.isArray(data.messages) && data.messages.length > 0) {
|
|
5747
5779
|
state.messages = sanitizeMessages(data.messages);
|
|
5748
|
-
log10.info("Session loaded", {
|
|
5780
|
+
log10.info("Session loaded", {
|
|
5781
|
+
messageCount: state.messages.length,
|
|
5782
|
+
...state.models && { models: state.models }
|
|
5783
|
+
});
|
|
5749
5784
|
return true;
|
|
5750
5785
|
}
|
|
5751
5786
|
} catch {
|
|
@@ -5790,11 +5825,11 @@ function sanitizeMessages(messages) {
|
|
|
5790
5825
|
}
|
|
5791
5826
|
function saveSession(state) {
|
|
5792
5827
|
try {
|
|
5793
|
-
|
|
5794
|
-
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
);
|
|
5828
|
+
const payload = { messages: state.messages };
|
|
5829
|
+
if (state.models && Object.keys(state.models).length > 0) {
|
|
5830
|
+
payload.models = state.models;
|
|
5831
|
+
}
|
|
5832
|
+
fs21.writeFileSync(SESSION_FILE, JSON.stringify(payload, null, 2), "utf-8");
|
|
5798
5833
|
log10.info("Session saved", { messageCount: state.messages.length });
|
|
5799
5834
|
} catch (err) {
|
|
5800
5835
|
log10.warn("Session save failed", { error: err.message });
|
|
@@ -6135,6 +6170,7 @@ async function runTurn(params) {
|
|
|
6135
6170
|
let textBlockOpen = false;
|
|
6136
6171
|
const toolInputAccumulators = /* @__PURE__ */ new Map();
|
|
6137
6172
|
let stopReason = "end_turn";
|
|
6173
|
+
let turnProviderMetadata;
|
|
6138
6174
|
let subAgentText = "";
|
|
6139
6175
|
let currentToolNames = "";
|
|
6140
6176
|
const statusWatcher = isFirstMessage ? { stop() {
|
|
@@ -6216,11 +6252,12 @@ async function runTurn(params) {
|
|
|
6216
6252
|
onEvent({ type: "tool_input_delta", id, name, result: content });
|
|
6217
6253
|
}
|
|
6218
6254
|
}
|
|
6255
|
+
const parentModel = state.models?.parent ?? model;
|
|
6219
6256
|
try {
|
|
6220
6257
|
for await (const event of streamChatWithRetry(
|
|
6221
6258
|
{
|
|
6222
6259
|
...apiConfig,
|
|
6223
|
-
model,
|
|
6260
|
+
model: parentModel,
|
|
6224
6261
|
requestId,
|
|
6225
6262
|
system,
|
|
6226
6263
|
messages: cleanMessagesForApi(state.messages),
|
|
@@ -6332,6 +6369,7 @@ async function runTurn(params) {
|
|
|
6332
6369
|
}
|
|
6333
6370
|
case "done":
|
|
6334
6371
|
stopReason = event.stopReason;
|
|
6372
|
+
turnProviderMetadata = event.providerMetadata;
|
|
6335
6373
|
turnLlmCalls++;
|
|
6336
6374
|
lastCallInputTokens = event.usage.inputTokens;
|
|
6337
6375
|
lastCallCacheCreation = event.usage.cacheCreationTokens ?? 0;
|
|
@@ -6385,6 +6423,9 @@ async function runTurn(params) {
|
|
|
6385
6423
|
cacheCreationTokens: turnCacheCreation || void 0,
|
|
6386
6424
|
cacheReadTokens: turnCacheRead || void 0,
|
|
6387
6425
|
llmCalls: turnLlmCalls
|
|
6426
|
+
},
|
|
6427
|
+
...turnProviderMetadata && {
|
|
6428
|
+
providerMetadata: turnProviderMetadata
|
|
6388
6429
|
}
|
|
6389
6430
|
});
|
|
6390
6431
|
}
|
|
@@ -6402,7 +6443,8 @@ async function runTurn(params) {
|
|
|
6402
6443
|
cacheCreationTokens: turnCacheCreation || void 0,
|
|
6403
6444
|
cacheReadTokens: turnCacheRead || void 0,
|
|
6404
6445
|
llmCalls: turnLlmCalls
|
|
6405
|
-
}
|
|
6446
|
+
},
|
|
6447
|
+
...turnProviderMetadata && { providerMetadata: turnProviderMetadata }
|
|
6406
6448
|
});
|
|
6407
6449
|
}
|
|
6408
6450
|
const toolCalls = getToolCalls(contentBlocks);
|
|
@@ -6491,6 +6533,7 @@ async function runTurn(params) {
|
|
|
6491
6533
|
result = await executeTool(tc.name, input, {
|
|
6492
6534
|
apiConfig,
|
|
6493
6535
|
model,
|
|
6536
|
+
models: state.models,
|
|
6494
6537
|
signal: toolAbort.signal,
|
|
6495
6538
|
onEvent: wrappedOnEvent,
|
|
6496
6539
|
resolveExternalTool,
|
|
@@ -6995,10 +7038,14 @@ var HeadlessSession = class {
|
|
|
6995
7038
|
if (resumed) {
|
|
6996
7039
|
this.emit("session_restored", {
|
|
6997
7040
|
messageCount: this.state.messages.length,
|
|
7041
|
+
...this.state.models && { models: this.state.models },
|
|
6998
7042
|
...this.queueFields()
|
|
6999
7043
|
});
|
|
7000
7044
|
}
|
|
7001
|
-
triggerBrandExtraction(
|
|
7045
|
+
triggerBrandExtraction(
|
|
7046
|
+
this.config,
|
|
7047
|
+
this.state.models?.brandExtractor ?? this.opts.model
|
|
7048
|
+
);
|
|
7002
7049
|
this.toolRegistry.onEvent = this.onEvent;
|
|
7003
7050
|
setCompactionListener((event) => {
|
|
7004
7051
|
if (event.type === "started") {
|
|
@@ -7151,7 +7198,8 @@ var HeadlessSession = class {
|
|
|
7151
7198
|
try {
|
|
7152
7199
|
await triggerCompaction(this.state, this.config, {
|
|
7153
7200
|
blocking: true,
|
|
7154
|
-
requestId
|
|
7201
|
+
requestId,
|
|
7202
|
+
model: this.opts.model
|
|
7155
7203
|
});
|
|
7156
7204
|
this.applyPendingSummaries();
|
|
7157
7205
|
} catch {
|
|
@@ -7589,6 +7637,17 @@ var HeadlessSession = class {
|
|
|
7589
7637
|
clearSession(this.state);
|
|
7590
7638
|
return {};
|
|
7591
7639
|
}
|
|
7640
|
+
/** Archive the current session and seed a fresh one with the given
|
|
7641
|
+
* per-agent model overrides. Models are immutable for the life of a
|
|
7642
|
+
* session — this is the only way to change them. Omitting `models`
|
|
7643
|
+
* (or sending an empty object) resets to "use server defaults for
|
|
7644
|
+
* every agent". */
|
|
7645
|
+
handleNewSession(models) {
|
|
7646
|
+
clearSession(this.state);
|
|
7647
|
+
this.state.models = models && Object.keys(models).length > 0 ? models : void 0;
|
|
7648
|
+
saveSession(this.state);
|
|
7649
|
+
return {};
|
|
7650
|
+
}
|
|
7592
7651
|
/** Cancel the running turn and drain the queue. Returns the drained items. */
|
|
7593
7652
|
handleCancel() {
|
|
7594
7653
|
if (this.currentAbort) {
|
|
@@ -7662,6 +7721,7 @@ var HeadlessSession = class {
|
|
|
7662
7721
|
totalMessageCount: total,
|
|
7663
7722
|
running: this.running,
|
|
7664
7723
|
...this.running && this.currentRequestId ? { currentRequestId: this.currentRequestId } : {},
|
|
7724
|
+
...this.state.models && { models: this.state.models },
|
|
7665
7725
|
...this.queueFields()
|
|
7666
7726
|
}));
|
|
7667
7727
|
return;
|
|
@@ -7674,6 +7734,15 @@ var HeadlessSession = class {
|
|
|
7674
7734
|
);
|
|
7675
7735
|
return;
|
|
7676
7736
|
}
|
|
7737
|
+
if (action === "newSession") {
|
|
7738
|
+
const models = parsed.models;
|
|
7739
|
+
this.dispatchSimple(
|
|
7740
|
+
requestId,
|
|
7741
|
+
"session_cleared",
|
|
7742
|
+
() => this.handleNewSession(models)
|
|
7743
|
+
);
|
|
7744
|
+
return;
|
|
7745
|
+
}
|
|
7677
7746
|
if (action === "cancel") {
|
|
7678
7747
|
const cancelled = this.handleCancel();
|
|
7679
7748
|
this.emit(
|
|
@@ -7720,7 +7789,8 @@ var HeadlessSession = class {
|
|
|
7720
7789
|
try {
|
|
7721
7790
|
await triggerCompaction(this.state, this.config, {
|
|
7722
7791
|
blocking: false,
|
|
7723
|
-
requestId
|
|
7792
|
+
requestId,
|
|
7793
|
+
model: this.opts.model
|
|
7724
7794
|
});
|
|
7725
7795
|
if (!this.running) {
|
|
7726
7796
|
this.applyPendingSummaries();
|
package/dist/index.js
CHANGED
|
@@ -86,16 +86,17 @@ var init_logger = __esm({
|
|
|
86
86
|
|
|
87
87
|
// src/api.ts
|
|
88
88
|
async function* streamChat(params) {
|
|
89
|
-
const { baseUrl: baseUrl2, apiKey, signal, requestId, ...
|
|
89
|
+
const { baseUrl: baseUrl2, apiKey, signal, requestId, model, ...rest } = params;
|
|
90
90
|
const url = `${baseUrl2}/_internal/v2/agent/remy/chat`;
|
|
91
91
|
const startTime = Date.now();
|
|
92
|
-
const subAgentId =
|
|
92
|
+
const subAgentId = rest.subAgentId;
|
|
93
|
+
const requestBody = { ...rest, ...model && { modelId: model } };
|
|
93
94
|
log.info("API request", {
|
|
94
95
|
requestId,
|
|
95
96
|
...subAgentId && { subAgentId },
|
|
96
|
-
model
|
|
97
|
-
messageCount:
|
|
98
|
-
toolCount:
|
|
97
|
+
model,
|
|
98
|
+
messageCount: rest.messages.length,
|
|
99
|
+
toolCount: rest.tools.length
|
|
99
100
|
});
|
|
100
101
|
let res;
|
|
101
102
|
try {
|
|
@@ -105,7 +106,7 @@ async function* streamChat(params) {
|
|
|
105
106
|
"Content-Type": "application/json",
|
|
106
107
|
Authorization: `Bearer ${apiKey}`
|
|
107
108
|
},
|
|
108
|
-
body: JSON.stringify(
|
|
109
|
+
body: JSON.stringify(requestBody),
|
|
109
110
|
signal
|
|
110
111
|
});
|
|
111
112
|
} catch (err) {
|
|
@@ -133,13 +134,21 @@ async function* streamChat(params) {
|
|
|
133
134
|
});
|
|
134
135
|
if (!res.ok) {
|
|
135
136
|
let errorMessage = `HTTP ${res.status}`;
|
|
137
|
+
let errorCode;
|
|
138
|
+
let badModelId;
|
|
136
139
|
try {
|
|
137
|
-
const
|
|
138
|
-
if (
|
|
139
|
-
errorMessage =
|
|
140
|
+
const body = await res.json();
|
|
141
|
+
if (body.error) {
|
|
142
|
+
errorMessage = body.error;
|
|
143
|
+
}
|
|
144
|
+
if (body.errorMessage) {
|
|
145
|
+
errorMessage = body.errorMessage;
|
|
140
146
|
}
|
|
141
|
-
if (
|
|
142
|
-
|
|
147
|
+
if (typeof body.code === "string") {
|
|
148
|
+
errorCode = body.code;
|
|
149
|
+
}
|
|
150
|
+
if (typeof body.modelId === "string") {
|
|
151
|
+
badModelId = body.modelId;
|
|
143
152
|
}
|
|
144
153
|
} catch {
|
|
145
154
|
}
|
|
@@ -147,9 +156,16 @@ async function* streamChat(params) {
|
|
|
147
156
|
requestId,
|
|
148
157
|
...subAgentId && { subAgentId },
|
|
149
158
|
status: res.status,
|
|
150
|
-
error: errorMessage
|
|
159
|
+
error: errorMessage,
|
|
160
|
+
...errorCode && { code: errorCode },
|
|
161
|
+
...badModelId && { badModelId }
|
|
151
162
|
});
|
|
152
|
-
yield {
|
|
163
|
+
yield {
|
|
164
|
+
type: "error",
|
|
165
|
+
error: errorMessage,
|
|
166
|
+
...errorCode && { code: errorCode },
|
|
167
|
+
...badModelId && { badModelId }
|
|
168
|
+
};
|
|
153
169
|
return;
|
|
154
170
|
}
|
|
155
171
|
const STALL_TIMEOUT_MS = 3e5;
|
|
@@ -1471,7 +1487,7 @@ var init_assets = __esm({
|
|
|
1471
1487
|
});
|
|
1472
1488
|
|
|
1473
1489
|
// src/compaction/index.ts
|
|
1474
|
-
async function compactConversation(messages, apiConfig, system, tools2) {
|
|
1490
|
+
async function compactConversation(messages, apiConfig, system, tools2, model) {
|
|
1475
1491
|
const endIndex = findSafeInsertionPoint(messages);
|
|
1476
1492
|
const summaries = [];
|
|
1477
1493
|
const tasks = [];
|
|
@@ -1487,7 +1503,8 @@ async function compactConversation(messages, apiConfig, system, tools2) {
|
|
|
1487
1503
|
CONVERSATION_SUMMARY_PROMPT,
|
|
1488
1504
|
conversationMessages,
|
|
1489
1505
|
system,
|
|
1490
|
-
tools2
|
|
1506
|
+
tools2,
|
|
1507
|
+
model
|
|
1491
1508
|
).then((text) => {
|
|
1492
1509
|
if (text) {
|
|
1493
1510
|
summaries.push({ name: "conversation", text });
|
|
@@ -1509,7 +1526,8 @@ async function compactConversation(messages, apiConfig, system, tools2) {
|
|
|
1509
1526
|
SUBAGENT_SUMMARY_PROMPT,
|
|
1510
1527
|
subagentMessages,
|
|
1511
1528
|
system,
|
|
1512
|
-
tools2
|
|
1529
|
+
tools2,
|
|
1530
|
+
model
|
|
1513
1531
|
).then((text) => {
|
|
1514
1532
|
if (text) {
|
|
1515
1533
|
summaries.push({ name, text });
|
|
@@ -1630,7 +1648,7 @@ function serializeForSummary(messages) {
|
|
|
1630
1648
|
return `[${msg.role}]: ${parts.join("\n")}`;
|
|
1631
1649
|
}).join("\n\n");
|
|
1632
1650
|
}
|
|
1633
|
-
async function generateSummary(apiConfig, name, compactionPrompt, messagesToSummarize, mainSystem, mainTools) {
|
|
1651
|
+
async function generateSummary(apiConfig, name, compactionPrompt, messagesToSummarize, mainSystem, mainTools, model) {
|
|
1634
1652
|
const serialized = serializeForSummary(messagesToSummarize);
|
|
1635
1653
|
if (!serialized.trim()) {
|
|
1636
1654
|
return null;
|
|
@@ -1649,7 +1667,8 @@ async function generateSummary(apiConfig, name, compactionPrompt, messagesToSumm
|
|
|
1649
1667
|
compactionPrompt,
|
|
1650
1668
|
messagesToSummarize.slice(0, mid),
|
|
1651
1669
|
mainSystem,
|
|
1652
|
-
mainTools
|
|
1670
|
+
mainTools,
|
|
1671
|
+
model
|
|
1653
1672
|
),
|
|
1654
1673
|
generateSummary(
|
|
1655
1674
|
apiConfig,
|
|
@@ -1657,7 +1676,8 @@ async function generateSummary(apiConfig, name, compactionPrompt, messagesToSumm
|
|
|
1657
1676
|
compactionPrompt,
|
|
1658
1677
|
messagesToSummarize.slice(mid),
|
|
1659
1678
|
mainSystem,
|
|
1660
|
-
mainTools
|
|
1679
|
+
mainTools,
|
|
1680
|
+
model
|
|
1661
1681
|
)
|
|
1662
1682
|
]);
|
|
1663
1683
|
const parts = [first, second].filter((p) => !!p);
|
|
@@ -1682,6 +1702,7 @@ ${serialized}` : serialized;
|
|
|
1682
1702
|
const iterStart = Date.now();
|
|
1683
1703
|
for await (const event of streamChat({
|
|
1684
1704
|
...apiConfig,
|
|
1705
|
+
model,
|
|
1685
1706
|
subAgentId: "conversationSummarizer",
|
|
1686
1707
|
system,
|
|
1687
1708
|
messages: [{ role: "user", content: userContent }],
|
|
@@ -2014,7 +2035,7 @@ function triggerCompaction(state, apiConfig, opts = {}) {
|
|
|
2014
2035
|
if (inflightCompaction) {
|
|
2015
2036
|
return inflightCompaction;
|
|
2016
2037
|
}
|
|
2017
|
-
const { blocking = false, requestId } = opts;
|
|
2038
|
+
const { blocking = false, requestId, model } = opts;
|
|
2018
2039
|
listener?.({ type: "started", blocking, requestId });
|
|
2019
2040
|
const system = buildSystemPrompt("onboardingFinished");
|
|
2020
2041
|
const tools2 = getToolDefinitions("onboardingFinished");
|
|
@@ -2022,7 +2043,8 @@ function triggerCompaction(state, apiConfig, opts = {}) {
|
|
|
2022
2043
|
state.messages,
|
|
2023
2044
|
apiConfig,
|
|
2024
2045
|
system,
|
|
2025
|
-
tools2
|
|
2046
|
+
tools2,
|
|
2047
|
+
state.models?.conversationSummarizer ?? model
|
|
2026
2048
|
).then((summaries) => {
|
|
2027
2049
|
pendingSummaries.push(...summaries);
|
|
2028
2050
|
listener?.({ type: "complete", requestId });
|
|
@@ -3437,6 +3459,9 @@ ${content}` : attachmentHeader;
|
|
|
3437
3459
|
if (thinking.length > 0) {
|
|
3438
3460
|
cleaned2.thinking = thinking;
|
|
3439
3461
|
}
|
|
3462
|
+
if (msg.providerMetadata) {
|
|
3463
|
+
cleaned2.providerMetadata = msg.providerMetadata;
|
|
3464
|
+
}
|
|
3440
3465
|
if (msg.hidden) {
|
|
3441
3466
|
cleaned2.hidden = true;
|
|
3442
3467
|
}
|
|
@@ -3528,6 +3553,7 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
|
|
|
3528
3553
|
let stopReason = "end_turn";
|
|
3529
3554
|
let currentToolNames = "";
|
|
3530
3555
|
let lastUsage;
|
|
3556
|
+
let lastProviderMetadata;
|
|
3531
3557
|
const statusWatcher = startStatusWatcher({
|
|
3532
3558
|
apiConfig,
|
|
3533
3559
|
getContext: () => {
|
|
@@ -3640,6 +3666,7 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
|
|
|
3640
3666
|
cacheReadTokens: event.usage.cacheReadTokens,
|
|
3641
3667
|
llmCalls: 1
|
|
3642
3668
|
};
|
|
3669
|
+
lastProviderMetadata = event.providerMetadata;
|
|
3643
3670
|
recordUsage({
|
|
3644
3671
|
ts: Date.now(),
|
|
3645
3672
|
requestId,
|
|
@@ -3677,7 +3704,8 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
|
|
|
3677
3704
|
messages.push({
|
|
3678
3705
|
role: "assistant",
|
|
3679
3706
|
content: contentBlocks,
|
|
3680
|
-
...lastUsage ? { usage: lastUsage } : {}
|
|
3707
|
+
...lastUsage ? { usage: lastUsage } : {},
|
|
3708
|
+
...lastProviderMetadata ? { providerMetadata: lastProviderMetadata } : {}
|
|
3681
3709
|
});
|
|
3682
3710
|
const toolCalls = contentBlocks.filter(
|
|
3683
3711
|
(b) => b.type === "tool"
|
|
@@ -4116,7 +4144,7 @@ var init_browserAutomation = __esm({
|
|
|
4116
4144
|
return `Error: unknown local tool "${name}"`;
|
|
4117
4145
|
},
|
|
4118
4146
|
apiConfig: context.apiConfig,
|
|
4119
|
-
model: context.model,
|
|
4147
|
+
model: context.models?.browserAutomation ?? context.model,
|
|
4120
4148
|
subAgentId: "browserAutomation",
|
|
4121
4149
|
signal: context.signal,
|
|
4122
4150
|
parentToolId: context.toolCallId,
|
|
@@ -5494,7 +5522,7 @@ Visual design expert. Describe the situation and what you need \u2014 the agent
|
|
|
5494
5522
|
);
|
|
5495
5523
|
},
|
|
5496
5524
|
apiConfig: context.apiConfig,
|
|
5497
|
-
model: context.model,
|
|
5525
|
+
model: context.models?.visualDesignExpert ?? context.model,
|
|
5498
5526
|
subAgentId: "visualDesignExpert",
|
|
5499
5527
|
signal: context.signal,
|
|
5500
5528
|
parentToolId: context.toolCallId,
|
|
@@ -5751,7 +5779,7 @@ var init_productVision = __esm({
|
|
|
5751
5779
|
return executeVisionTool(name, input2, childCtx);
|
|
5752
5780
|
},
|
|
5753
5781
|
apiConfig: context.apiConfig,
|
|
5754
|
-
model: context.model,
|
|
5782
|
+
model: context.models?.productVision ?? context.model,
|
|
5755
5783
|
subAgentId: "productVision",
|
|
5756
5784
|
signal: context.signal,
|
|
5757
5785
|
parentToolId: context.toolCallId,
|
|
@@ -5877,7 +5905,7 @@ var init_codeSanityCheck = __esm({
|
|
|
5877
5905
|
externalTools: /* @__PURE__ */ new Set(),
|
|
5878
5906
|
executeTool: (name, toolInput) => executeTool(name, toolInput, context),
|
|
5879
5907
|
apiConfig: context.apiConfig,
|
|
5880
|
-
model: context.model,
|
|
5908
|
+
model: context.models?.codeSanityCheck ?? context.model,
|
|
5881
5909
|
subAgentId: "codeSanityCheck",
|
|
5882
5910
|
signal: context.signal,
|
|
5883
5911
|
parentToolId: context.toolCallId,
|
|
@@ -6048,9 +6076,15 @@ function loadSession(state) {
|
|
|
6048
6076
|
try {
|
|
6049
6077
|
const raw = fs19.readFileSync(SESSION_FILE, "utf-8");
|
|
6050
6078
|
const data = JSON.parse(raw);
|
|
6079
|
+
if (data.models && typeof data.models === "object") {
|
|
6080
|
+
state.models = data.models;
|
|
6081
|
+
}
|
|
6051
6082
|
if (Array.isArray(data.messages) && data.messages.length > 0) {
|
|
6052
6083
|
state.messages = sanitizeMessages(data.messages);
|
|
6053
|
-
log7.info("Session loaded", {
|
|
6084
|
+
log7.info("Session loaded", {
|
|
6085
|
+
messageCount: state.messages.length,
|
|
6086
|
+
...state.models && { models: state.models }
|
|
6087
|
+
});
|
|
6054
6088
|
return true;
|
|
6055
6089
|
}
|
|
6056
6090
|
} catch {
|
|
@@ -6095,11 +6129,11 @@ function sanitizeMessages(messages) {
|
|
|
6095
6129
|
}
|
|
6096
6130
|
function saveSession(state) {
|
|
6097
6131
|
try {
|
|
6098
|
-
|
|
6099
|
-
|
|
6100
|
-
|
|
6101
|
-
|
|
6102
|
-
);
|
|
6132
|
+
const payload = { messages: state.messages };
|
|
6133
|
+
if (state.models && Object.keys(state.models).length > 0) {
|
|
6134
|
+
payload.models = state.models;
|
|
6135
|
+
}
|
|
6136
|
+
fs19.writeFileSync(SESSION_FILE, JSON.stringify(payload, null, 2), "utf-8");
|
|
6103
6137
|
log7.info("Session saved", { messageCount: state.messages.length });
|
|
6104
6138
|
} catch (err) {
|
|
6105
6139
|
log7.warn("Session save failed", { error: err.message });
|
|
@@ -6345,7 +6379,7 @@ var init_errors = __esm({
|
|
|
6345
6379
|
import fs20 from "fs";
|
|
6346
6380
|
import path10 from "path";
|
|
6347
6381
|
import { createHash } from "crypto";
|
|
6348
|
-
async function runExtraction(apiConfig) {
|
|
6382
|
+
async function runExtraction(apiConfig, model) {
|
|
6349
6383
|
const inputHash = computeInputHash();
|
|
6350
6384
|
const cached2 = readCache();
|
|
6351
6385
|
if (cached2 && cached2.inputHash === inputHash) {
|
|
@@ -6353,7 +6387,7 @@ async function runExtraction(apiConfig) {
|
|
|
6353
6387
|
return null;
|
|
6354
6388
|
}
|
|
6355
6389
|
log8.info("Extracting brand", { inputHash });
|
|
6356
|
-
const brand = await extractBrand(apiConfig);
|
|
6390
|
+
const brand = await extractBrand(apiConfig, model);
|
|
6357
6391
|
if (!brand) {
|
|
6358
6392
|
log8.warn("Brand extraction failed \u2014 leaving cache untouched");
|
|
6359
6393
|
return null;
|
|
@@ -6422,7 +6456,7 @@ function parseFrontmatter3(filePath) {
|
|
|
6422
6456
|
return { type: "" };
|
|
6423
6457
|
}
|
|
6424
6458
|
}
|
|
6425
|
-
async function extractBrand(apiConfig) {
|
|
6459
|
+
async function extractBrand(apiConfig, model) {
|
|
6426
6460
|
const corpus = buildCorpus();
|
|
6427
6461
|
if (!corpus.trim()) {
|
|
6428
6462
|
log8.debug("No spec corpus \u2014 emitting empty brand");
|
|
@@ -6433,6 +6467,7 @@ async function extractBrand(apiConfig) {
|
|
|
6433
6467
|
try {
|
|
6434
6468
|
for await (const event of streamChat({
|
|
6435
6469
|
...apiConfig,
|
|
6470
|
+
model,
|
|
6436
6471
|
subAgentId: "brandExtractor",
|
|
6437
6472
|
system: EXTRACT_PROMPT,
|
|
6438
6473
|
messages: [{ role: "user", content: corpus }],
|
|
@@ -6621,19 +6656,19 @@ var init_brandExtraction = __esm({
|
|
|
6621
6656
|
});
|
|
6622
6657
|
|
|
6623
6658
|
// src/brandExtraction/trigger.ts
|
|
6624
|
-
function triggerBrandExtraction(apiConfig) {
|
|
6659
|
+
function triggerBrandExtraction(apiConfig, model) {
|
|
6625
6660
|
if (inflight) {
|
|
6626
6661
|
dirty = true;
|
|
6627
6662
|
return;
|
|
6628
6663
|
}
|
|
6629
6664
|
inflight = true;
|
|
6630
|
-
void runExtraction(apiConfig).catch((err) => {
|
|
6665
|
+
void runExtraction(apiConfig, model).catch((err) => {
|
|
6631
6666
|
log9.error("Brand extraction failed", { error: err?.message });
|
|
6632
6667
|
}).finally(() => {
|
|
6633
6668
|
inflight = false;
|
|
6634
6669
|
if (dirty) {
|
|
6635
6670
|
dirty = false;
|
|
6636
|
-
triggerBrandExtraction(apiConfig);
|
|
6671
|
+
triggerBrandExtraction(apiConfig, model);
|
|
6637
6672
|
}
|
|
6638
6673
|
});
|
|
6639
6674
|
}
|
|
@@ -6752,6 +6787,7 @@ async function runTurn(params) {
|
|
|
6752
6787
|
let textBlockOpen = false;
|
|
6753
6788
|
const toolInputAccumulators = /* @__PURE__ */ new Map();
|
|
6754
6789
|
let stopReason = "end_turn";
|
|
6790
|
+
let turnProviderMetadata;
|
|
6755
6791
|
let subAgentText = "";
|
|
6756
6792
|
let currentToolNames = "";
|
|
6757
6793
|
const statusWatcher = isFirstMessage ? { stop() {
|
|
@@ -6833,11 +6869,12 @@ async function runTurn(params) {
|
|
|
6833
6869
|
onEvent({ type: "tool_input_delta", id, name, result: content });
|
|
6834
6870
|
}
|
|
6835
6871
|
}
|
|
6872
|
+
const parentModel = state.models?.parent ?? model;
|
|
6836
6873
|
try {
|
|
6837
6874
|
for await (const event of streamChatWithRetry(
|
|
6838
6875
|
{
|
|
6839
6876
|
...apiConfig,
|
|
6840
|
-
model,
|
|
6877
|
+
model: parentModel,
|
|
6841
6878
|
requestId,
|
|
6842
6879
|
system,
|
|
6843
6880
|
messages: cleanMessagesForApi(state.messages),
|
|
@@ -6949,6 +6986,7 @@ async function runTurn(params) {
|
|
|
6949
6986
|
}
|
|
6950
6987
|
case "done":
|
|
6951
6988
|
stopReason = event.stopReason;
|
|
6989
|
+
turnProviderMetadata = event.providerMetadata;
|
|
6952
6990
|
turnLlmCalls++;
|
|
6953
6991
|
lastCallInputTokens = event.usage.inputTokens;
|
|
6954
6992
|
lastCallCacheCreation = event.usage.cacheCreationTokens ?? 0;
|
|
@@ -7002,6 +7040,9 @@ async function runTurn(params) {
|
|
|
7002
7040
|
cacheCreationTokens: turnCacheCreation || void 0,
|
|
7003
7041
|
cacheReadTokens: turnCacheRead || void 0,
|
|
7004
7042
|
llmCalls: turnLlmCalls
|
|
7043
|
+
},
|
|
7044
|
+
...turnProviderMetadata && {
|
|
7045
|
+
providerMetadata: turnProviderMetadata
|
|
7005
7046
|
}
|
|
7006
7047
|
});
|
|
7007
7048
|
}
|
|
@@ -7019,7 +7060,8 @@ async function runTurn(params) {
|
|
|
7019
7060
|
cacheCreationTokens: turnCacheCreation || void 0,
|
|
7020
7061
|
cacheReadTokens: turnCacheRead || void 0,
|
|
7021
7062
|
llmCalls: turnLlmCalls
|
|
7022
|
-
}
|
|
7063
|
+
},
|
|
7064
|
+
...turnProviderMetadata && { providerMetadata: turnProviderMetadata }
|
|
7023
7065
|
});
|
|
7024
7066
|
}
|
|
7025
7067
|
const toolCalls = getToolCalls(contentBlocks);
|
|
@@ -7108,6 +7150,7 @@ async function runTurn(params) {
|
|
|
7108
7150
|
result = await executeTool(tc.name, input, {
|
|
7109
7151
|
apiConfig,
|
|
7110
7152
|
model,
|
|
7153
|
+
models: state.models,
|
|
7111
7154
|
signal: toolAbort.signal,
|
|
7112
7155
|
onEvent: wrappedOnEvent,
|
|
7113
7156
|
resolveExternalTool,
|
|
@@ -7767,10 +7810,14 @@ var init_headless = __esm({
|
|
|
7767
7810
|
if (resumed) {
|
|
7768
7811
|
this.emit("session_restored", {
|
|
7769
7812
|
messageCount: this.state.messages.length,
|
|
7813
|
+
...this.state.models && { models: this.state.models },
|
|
7770
7814
|
...this.queueFields()
|
|
7771
7815
|
});
|
|
7772
7816
|
}
|
|
7773
|
-
triggerBrandExtraction(
|
|
7817
|
+
triggerBrandExtraction(
|
|
7818
|
+
this.config,
|
|
7819
|
+
this.state.models?.brandExtractor ?? this.opts.model
|
|
7820
|
+
);
|
|
7774
7821
|
this.toolRegistry.onEvent = this.onEvent;
|
|
7775
7822
|
setCompactionListener((event) => {
|
|
7776
7823
|
if (event.type === "started") {
|
|
@@ -7923,7 +7970,8 @@ var init_headless = __esm({
|
|
|
7923
7970
|
try {
|
|
7924
7971
|
await triggerCompaction(this.state, this.config, {
|
|
7925
7972
|
blocking: true,
|
|
7926
|
-
requestId
|
|
7973
|
+
requestId,
|
|
7974
|
+
model: this.opts.model
|
|
7927
7975
|
});
|
|
7928
7976
|
this.applyPendingSummaries();
|
|
7929
7977
|
} catch {
|
|
@@ -8361,6 +8409,17 @@ var init_headless = __esm({
|
|
|
8361
8409
|
clearSession(this.state);
|
|
8362
8410
|
return {};
|
|
8363
8411
|
}
|
|
8412
|
+
/** Archive the current session and seed a fresh one with the given
|
|
8413
|
+
* per-agent model overrides. Models are immutable for the life of a
|
|
8414
|
+
* session — this is the only way to change them. Omitting `models`
|
|
8415
|
+
* (or sending an empty object) resets to "use server defaults for
|
|
8416
|
+
* every agent". */
|
|
8417
|
+
handleNewSession(models) {
|
|
8418
|
+
clearSession(this.state);
|
|
8419
|
+
this.state.models = models && Object.keys(models).length > 0 ? models : void 0;
|
|
8420
|
+
saveSession(this.state);
|
|
8421
|
+
return {};
|
|
8422
|
+
}
|
|
8364
8423
|
/** Cancel the running turn and drain the queue. Returns the drained items. */
|
|
8365
8424
|
handleCancel() {
|
|
8366
8425
|
if (this.currentAbort) {
|
|
@@ -8434,6 +8493,7 @@ var init_headless = __esm({
|
|
|
8434
8493
|
totalMessageCount: total,
|
|
8435
8494
|
running: this.running,
|
|
8436
8495
|
...this.running && this.currentRequestId ? { currentRequestId: this.currentRequestId } : {},
|
|
8496
|
+
...this.state.models && { models: this.state.models },
|
|
8437
8497
|
...this.queueFields()
|
|
8438
8498
|
}));
|
|
8439
8499
|
return;
|
|
@@ -8446,6 +8506,15 @@ var init_headless = __esm({
|
|
|
8446
8506
|
);
|
|
8447
8507
|
return;
|
|
8448
8508
|
}
|
|
8509
|
+
if (action === "newSession") {
|
|
8510
|
+
const models = parsed.models;
|
|
8511
|
+
this.dispatchSimple(
|
|
8512
|
+
requestId,
|
|
8513
|
+
"session_cleared",
|
|
8514
|
+
() => this.handleNewSession(models)
|
|
8515
|
+
);
|
|
8516
|
+
return;
|
|
8517
|
+
}
|
|
8449
8518
|
if (action === "cancel") {
|
|
8450
8519
|
const cancelled = this.handleCancel();
|
|
8451
8520
|
this.emit(
|
|
@@ -8492,7 +8561,8 @@ var init_headless = __esm({
|
|
|
8492
8561
|
try {
|
|
8493
8562
|
await triggerCompaction(this.state, this.config, {
|
|
8494
8563
|
blocking: false,
|
|
8495
|
-
requestId
|
|
8564
|
+
requestId,
|
|
8565
|
+
model: this.opts.model
|
|
8496
8566
|
});
|
|
8497
8567
|
if (!this.running) {
|
|
8498
8568
|
this.applyPendingSummaries();
|