@auvira.ai/sdk 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +105 -0
- package/dist/agent/Agent.d.ts.map +1 -1
- package/dist/agent/Agent.js +9 -0
- package/dist/agent/Agent.js.map +1 -1
- package/dist/agent/attachmentContext.d.ts +9 -0
- package/dist/agent/attachmentContext.d.ts.map +1 -0
- package/dist/agent/attachmentContext.js +72 -0
- package/dist/agent/attachmentContext.js.map +1 -0
- package/dist/agent/editCompletion.d.ts +18 -3
- package/dist/agent/editCompletion.d.ts.map +1 -1
- package/dist/agent/editCompletion.js +113 -1
- package/dist/agent/editCompletion.js.map +1 -1
- package/dist/agent/evaluateTaskCompletion.d.ts +2 -0
- package/dist/agent/evaluateTaskCompletion.d.ts.map +1 -1
- package/dist/agent/evaluateTaskCompletion.js +4 -1
- package/dist/agent/evaluateTaskCompletion.js.map +1 -1
- package/dist/agent/events.d.ts +2 -2
- package/dist/agent/events.d.ts.map +1 -1
- package/dist/agent/events.js +2 -0
- package/dist/agent/events.js.map +1 -1
- package/dist/agent/hostTools.d.ts +46 -0
- package/dist/agent/hostTools.d.ts.map +1 -0
- package/dist/agent/hostTools.js +98 -0
- package/dist/agent/hostTools.js.map +1 -0
- package/dist/agent/parseSendPayload.d.ts +3 -1
- package/dist/agent/parseSendPayload.d.ts.map +1 -1
- package/dist/agent/parseSendPayload.js +16 -0
- package/dist/agent/parseSendPayload.js.map +1 -1
- package/dist/agent/runAgentTask.d.ts +4 -1
- package/dist/agent/runAgentTask.d.ts.map +1 -1
- package/dist/agent/runAgentTask.js +16 -0
- package/dist/agent/runAgentTask.js.map +1 -1
- package/dist/agent/runValidationWithRepair.d.ts.map +1 -1
- package/dist/agent/runValidationWithRepair.js +6 -0
- package/dist/agent/runValidationWithRepair.js.map +1 -1
- package/dist/agent/tools/assetPathValidation.d.ts +19 -0
- package/dist/agent/tools/assetPathValidation.d.ts.map +1 -0
- package/dist/agent/tools/assetPathValidation.js +124 -0
- package/dist/agent/tools/assetPathValidation.js.map +1 -0
- package/dist/agent/tools/executeTool.d.ts +1 -1
- package/dist/agent/tools/executeTool.d.ts.map +1 -1
- package/dist/agent/tools/executeTool.js +31 -1
- package/dist/agent/tools/executeTool.js.map +1 -1
- package/dist/agent/tools/generateImage.d.ts +11 -0
- package/dist/agent/tools/generateImage.d.ts.map +1 -0
- package/dist/agent/tools/generateImage.js +98 -0
- package/dist/agent/tools/generateImage.js.map +1 -0
- package/dist/agent/tools/publishReferenceImage.d.ts +9 -0
- package/dist/agent/tools/publishReferenceImage.d.ts.map +1 -0
- package/dist/agent/tools/publishReferenceImage.js +61 -0
- package/dist/agent/tools/publishReferenceImage.js.map +1 -0
- package/dist/agent/tools/saveAsset.d.ts +11 -0
- package/dist/agent/tools/saveAsset.d.ts.map +1 -0
- package/dist/agent/tools/saveAsset.js +30 -0
- package/dist/agent/tools/saveAsset.js.map +1 -0
- package/dist/agent/tools/types.d.ts +7 -0
- package/dist/agent/tools/types.d.ts.map +1 -1
- package/dist/agent/types.d.ts +37 -0
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/agent/validateOptions.d.ts.map +1 -1
- package/dist/agent/validateOptions.js +10 -1
- package/dist/agent/validateOptions.js.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/providers/agentic/AgenticCustomProvider.d.ts.map +1 -1
- package/dist/providers/agentic/AgenticCustomProvider.js +26 -0
- package/dist/providers/agentic/AgenticCustomProvider.js.map +1 -1
- package/dist/providers/agentic/agentLoop.d.ts +4 -1
- package/dist/providers/agentic/agentLoop.d.ts.map +1 -1
- package/dist/providers/agentic/agentLoop.js +295 -256
- package/dist/providers/agentic/agentLoop.js.map +1 -1
- package/dist/providers/agentic/toolSchemas.d.ts +438 -0
- package/dist/providers/agentic/toolSchemas.d.ts.map +1 -1
- package/dist/providers/agentic/toolSchemas.js +62 -0
- package/dist/providers/agentic/toolSchemas.js.map +1 -1
- package/dist/providers/types.d.ts +4 -1
- package/dist/providers/types.d.ts.map +1 -1
- package/dist/providers/types.js.map +1 -1
- package/dist/runner/jobTypes.d.ts +3 -2
- package/dist/runner/jobTypes.d.ts.map +1 -1
- package/dist/runner/run.d.ts.map +1 -1
- package/dist/runner/run.js +6 -2
- package/dist/runner/run.js.map +1 -1
- package/dist/runner/validateJob.d.ts.map +1 -1
- package/dist/runner/validateJob.js +83 -0
- package/dist/runner/validateJob.js.map +1 -1
- package/dist/util/minimaxImageClient.d.ts +25 -0
- package/dist/util/minimaxImageClient.d.ts.map +1 -0
- package/dist/util/minimaxImageClient.js +114 -0
- package/dist/util/minimaxImageClient.js.map +1 -0
- package/dist/workspace/referenceImages.d.ts +14 -0
- package/dist/workspace/referenceImages.d.ts.map +1 -0
- package/dist/workspace/referenceImages.js +60 -0
- package/dist/workspace/referenceImages.js.map +1 -0
- package/dist/workspace/workspaceCheckpoint.d.ts.map +1 -1
- package/dist/workspace/workspaceCheckpoint.js +148 -16
- package/dist/workspace/workspaceCheckpoint.js.map +1 -1
- package/dist/workspace/writeScreenshot.d.ts.map +1 -1
- package/dist/workspace/writeScreenshot.js +15 -7
- package/dist/workspace/writeScreenshot.js.map +1 -1
- package/docs/host-integration-image-placement.md +141 -0
- package/docs/sandbox-runner.md +43 -1
- package/package.json +6 -1
|
@@ -2,7 +2,8 @@ import { buildAssistantEvent } from "../../agent/assistantEvent.js";
|
|
|
2
2
|
import { throwIfCancelled } from "../../agent/cancellation.js";
|
|
3
3
|
import { emitAgentCompletionCheckThinking, emitAgentPlanningThinking, emitAgentRawModelTrace, emitAgentReflectionThinking, emitAgentToolSelectionThinking, } from "../../agent/emitAgentThinking.js";
|
|
4
4
|
import { buildIncompleteContinuationNudge, computeCompletionEvaluationKey, evaluateTaskCompletion, getCompletionMaxContinues, getTaskCompletionConfidenceThreshold, } from "../../agent/evaluateTaskCompletion.js";
|
|
5
|
-
import { evaluateHarnessCompletionGate, getWiringIncompleteNudge, isStyleOnlyDiff, } from "../../agent/editCompletion.js";
|
|
5
|
+
import { evaluateHarnessCompletionGate, getAssetPublishIncompleteNudge, getCompletionRulesIncompleteNudge, getWiringIncompleteNudge, isStyleOnlyDiff, } from "../../agent/editCompletion.js";
|
|
6
|
+
import { clearHostToolsForRun, hostToolsToOpenAiDefinitions, registerHostToolsForRun, resolveHostToolsForRun, } from "../../agent/hostTools.js";
|
|
6
7
|
import { executeAgentTool, parseToolArguments, } from "../../agent/tools/executeTool.js";
|
|
7
8
|
import { filterAllowlistedChangedFiles, } from "../../agent/tools/pathGuard.js";
|
|
8
9
|
import { gitDiff } from "../../git/gitDiff.js";
|
|
@@ -12,7 +13,7 @@ import { formatRateLimitReport, formatTimingReport, postJsonWithRetry, } from ".
|
|
|
12
13
|
import { applyCustomModelRequestDefaults, bumpMaxCompletionTokensForLengthRetry, getMaxCompletionTokens, } from "../custom/modelRequestDefaults.js";
|
|
13
14
|
import { evaluateToolPolicy, getPrimaryMaxToolCalls, } from "./toolPolicy.js";
|
|
14
15
|
import { trimAgentHistory, } from "./trimAgentHistory.js";
|
|
15
|
-
import {
|
|
16
|
+
import { buildAgentToolDefinitions } from "./toolSchemas.js";
|
|
16
17
|
const MAX_LOOP_TURNS = 25;
|
|
17
18
|
const LENGTH_RETRY_NUDGE = "Your previous response was truncated (length limit). Call one tool with minimal arguments.";
|
|
18
19
|
function buildUserMessage(userPrompt, imageDataUrls) {
|
|
@@ -100,7 +101,7 @@ function buildEarlyFinishResult(input) {
|
|
|
100
101
|
};
|
|
101
102
|
}
|
|
102
103
|
async function applyDeterministicCompletionGate(input) {
|
|
103
|
-
const gate = evaluateHarnessCompletionGate({
|
|
104
|
+
const gate = await evaluateHarnessCompletionGate({
|
|
104
105
|
changedFiles: input.allowlistedFiles,
|
|
105
106
|
toolCallCount: input.policyState.toolCallCount,
|
|
106
107
|
modelTurnCount: input.modelTurnCount,
|
|
@@ -108,12 +109,17 @@ async function applyDeterministicCompletionGate(input) {
|
|
|
108
109
|
selectedDom: input.selectedDom,
|
|
109
110
|
completion: input.completion,
|
|
110
111
|
deferredFinishCount: input.completionState.deferredFinishCount,
|
|
112
|
+
repoPath: input.repoPath,
|
|
111
113
|
});
|
|
112
114
|
if (gate.action === "continue") {
|
|
113
115
|
input.completionState.deferredFinishCount += 1;
|
|
114
|
-
emitAgentReflectionThinking(input.bus, input.modelTurnCount, gate.continueReason === "
|
|
115
|
-
? "
|
|
116
|
-
:
|
|
116
|
+
emitAgentReflectionThinking(input.bus, input.modelTurnCount, gate.continueReason === "asset_publish_incomplete"
|
|
117
|
+
? "Wiring references an image; continuing until publish_reference_image writes public/assets."
|
|
118
|
+
: gate.continueReason === "style_only_incomplete"
|
|
119
|
+
? "Style changes are in place; continuing to wire components and config."
|
|
120
|
+
: gate.continueReason === "completion_callback"
|
|
121
|
+
? "Completion rules not satisfied; continuing until required files change."
|
|
122
|
+
: undefined);
|
|
117
123
|
input.bus?.emit({
|
|
118
124
|
type: "run.continue",
|
|
119
125
|
reason: gate.continueReason ?? "style_only_incomplete",
|
|
@@ -125,7 +131,11 @@ async function applyDeterministicCompletionGate(input) {
|
|
|
125
131
|
});
|
|
126
132
|
input.messages.push({
|
|
127
133
|
role: "user",
|
|
128
|
-
content:
|
|
134
|
+
content: gate.continueReason === "asset_publish_incomplete"
|
|
135
|
+
? getAssetPublishIncompleteNudge()
|
|
136
|
+
: gate.continueReason === "completion_callback"
|
|
137
|
+
? getCompletionRulesIncompleteNudge()
|
|
138
|
+
: getWiringIncompleteNudge(),
|
|
129
139
|
});
|
|
130
140
|
return undefined;
|
|
131
141
|
}
|
|
@@ -172,7 +182,7 @@ async function tryHarnessEarlyFinish(input) {
|
|
|
172
182
|
if (allowlistedFiles.length === 0) {
|
|
173
183
|
return undefined;
|
|
174
184
|
}
|
|
175
|
-
const gateContext = evaluateHarnessCompletionGate({
|
|
185
|
+
const gateContext = await evaluateHarnessCompletionGate({
|
|
176
186
|
changedFiles: allowlistedFiles,
|
|
177
187
|
toolCallCount: input.policyState.toolCallCount,
|
|
178
188
|
modelTurnCount: input.modelTurnCount,
|
|
@@ -180,6 +190,7 @@ async function tryHarnessEarlyFinish(input) {
|
|
|
180
190
|
selectedDom: input.selectedDom,
|
|
181
191
|
completion: input.completion,
|
|
182
192
|
deferredFinishCount: input.completionState.deferredFinishCount,
|
|
193
|
+
repoPath: input.repoPath,
|
|
183
194
|
});
|
|
184
195
|
const useLlm = shouldUseLlmCompletionEvaluator({
|
|
185
196
|
harnessMode: input.harnessMode,
|
|
@@ -316,6 +327,7 @@ async function tryHarnessEarlyFinish(input) {
|
|
|
316
327
|
selectedDom: input.selectedDom,
|
|
317
328
|
completion: input.completion,
|
|
318
329
|
completionState: input.completionState,
|
|
330
|
+
repoPath: input.repoPath,
|
|
319
331
|
});
|
|
320
332
|
}
|
|
321
333
|
/** Runs a multi-turn tool-calling loop against an OpenAI-compatible chat API. */
|
|
@@ -334,235 +346,295 @@ export async function runAgentToolLoop(input) {
|
|
|
334
346
|
recentToolResults: [],
|
|
335
347
|
evaluationCallCount: 0,
|
|
336
348
|
};
|
|
349
|
+
const resolvedHostTools = resolveHostToolsForRun({
|
|
350
|
+
hostTools: input.hostTools,
|
|
351
|
+
includeAttachmentUrlsTool: Boolean(input.attachments?.length),
|
|
352
|
+
});
|
|
353
|
+
registerHostToolsForRun(resolvedHostTools);
|
|
354
|
+
const toolDefinitions = buildAgentToolDefinitions(hostToolsToOpenAiDefinitions(resolvedHostTools));
|
|
337
355
|
const toolCtx = {
|
|
338
356
|
repoPath: input.repoPath,
|
|
339
357
|
allowedWritePaths: input.allowedWritePaths,
|
|
340
358
|
enforceAllowlist: input.enforceAllowlist,
|
|
359
|
+
apiKey: input.apiKey,
|
|
360
|
+
signal: input.signal,
|
|
361
|
+
imageGenCount: 0,
|
|
362
|
+
attachments: input.attachments,
|
|
363
|
+
selectedDom: input.selectedDom,
|
|
341
364
|
};
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
365
|
+
try {
|
|
366
|
+
for (let turn = 0; turn < MAX_LOOP_TURNS; turn += 1) {
|
|
367
|
+
throwIfCancelled(input.signal);
|
|
368
|
+
const modelTurnCount = turn + 1;
|
|
369
|
+
if (policyState.abortReason) {
|
|
370
|
+
const early = await tryHarnessEarlyFinish({
|
|
371
|
+
harnessMode: input.harnessMode,
|
|
372
|
+
allowedWritePaths: input.allowedWritePaths,
|
|
373
|
+
repoPath: input.repoPath,
|
|
374
|
+
workspaceCheckpoint: input.workspaceCheckpoint,
|
|
375
|
+
bus: input.bus,
|
|
376
|
+
policyState,
|
|
377
|
+
editsApplied,
|
|
378
|
+
lastAssistantText,
|
|
379
|
+
loopStartMs,
|
|
380
|
+
lastUsage,
|
|
381
|
+
messages,
|
|
382
|
+
modelTurnCount,
|
|
383
|
+
hasVision: input.hasVision,
|
|
384
|
+
selectedDom: input.selectedDom,
|
|
385
|
+
completion: input.completion,
|
|
386
|
+
completionAuto: input.completionAuto,
|
|
387
|
+
completionEvaluationEnabled: input.completionEvaluationEnabled,
|
|
388
|
+
completionConfidenceThreshold: input.completionConfidenceThreshold,
|
|
389
|
+
referenceImages: input.referenceImages,
|
|
390
|
+
ownerRequest: input.ownerRequest,
|
|
391
|
+
model: input.model,
|
|
392
|
+
timeoutMs: input.timeoutMs,
|
|
393
|
+
signal: input.signal,
|
|
394
|
+
completionState,
|
|
395
|
+
});
|
|
396
|
+
if (early) {
|
|
397
|
+
return early;
|
|
398
|
+
}
|
|
399
|
+
break;
|
|
374
400
|
}
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
let maxCompletionTokensOverride;
|
|
379
|
-
let lengthRetryUsed = false;
|
|
380
|
-
input.bus?.emit({
|
|
381
|
-
type: "model.attempt",
|
|
382
|
-
attempt: turn + 1,
|
|
383
|
-
maxAttempts: MAX_LOOP_TURNS,
|
|
384
|
-
});
|
|
385
|
-
emitAgentPlanningThinking(input.bus, turn + 1);
|
|
386
|
-
const requestBody = {
|
|
387
|
-
model: input.modelId,
|
|
388
|
-
messages: trimmedMessages,
|
|
389
|
-
tools: AGENT_TOOL_DEFINITIONS,
|
|
390
|
-
tool_choice: "auto",
|
|
391
|
-
temperature: 0.2,
|
|
392
|
-
};
|
|
393
|
-
applyCustomModelRequestDefaults(requestBody, {
|
|
394
|
-
profile,
|
|
395
|
-
modelId: input.modelId,
|
|
396
|
-
maxCompletionTokensOverride,
|
|
397
|
-
});
|
|
398
|
-
const callModel = async () => {
|
|
401
|
+
const trimmedMessages = trimAgentHistory(messages);
|
|
402
|
+
let maxCompletionTokensOverride;
|
|
403
|
+
let lengthRetryUsed = false;
|
|
399
404
|
input.bus?.emit({
|
|
400
|
-
type: "model.
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
hasVision: Boolean(input.hasVision),
|
|
405
|
+
type: "model.attempt",
|
|
406
|
+
attempt: turn + 1,
|
|
407
|
+
maxAttempts: MAX_LOOP_TURNS,
|
|
404
408
|
});
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
timeoutMs: input.timeoutMs ?? 300_000,
|
|
413
|
-
signal: input.signal,
|
|
414
|
-
}, queueWaitMs));
|
|
415
|
-
if (result.ok && result.data) {
|
|
416
|
-
const content = result.data.choices?.[0]?.message?.content?.trim() ?? "";
|
|
417
|
-
input.bus?.emit({
|
|
418
|
-
type: "model.response",
|
|
419
|
-
contentPreview: content.slice(0, 500),
|
|
420
|
-
timingMs: result.totalMs,
|
|
421
|
-
httpRetries: result.retries,
|
|
422
|
-
});
|
|
423
|
-
}
|
|
424
|
-
return result;
|
|
425
|
-
};
|
|
426
|
-
let apiResult = input.bus
|
|
427
|
-
? await input.bus.withTool("model_completion", { turn: turn + 1, model: input.modelId }, callModel)
|
|
428
|
-
: await callModel();
|
|
429
|
-
throwIfCancelled(input.signal);
|
|
430
|
-
if (!apiResult.ok || !apiResult.data) {
|
|
431
|
-
const rateLimit = apiResult.rateLimit;
|
|
432
|
-
return {
|
|
433
|
-
ok: false,
|
|
434
|
-
response: "",
|
|
435
|
-
summary: rateLimit ? "MiniMax rate limit exceeded" : "Model API request failed",
|
|
436
|
-
editsApplied,
|
|
437
|
-
toolCallCount: policyState.toolCallCount,
|
|
438
|
-
error: {
|
|
439
|
-
message: rateLimit
|
|
440
|
-
? formatRateLimitReport(rateLimit)
|
|
441
|
-
: `${apiResult.errorMessage ?? "Model API request failed"} | ${formatTimingReport(apiResult)}`,
|
|
442
|
-
code: rateLimit ? "RATE_LIMIT" : "PROVIDER_ERROR",
|
|
443
|
-
},
|
|
409
|
+
emitAgentPlanningThinking(input.bus, turn + 1);
|
|
410
|
+
const requestBody = {
|
|
411
|
+
model: input.modelId,
|
|
412
|
+
messages: trimmedMessages,
|
|
413
|
+
tools: toolDefinitions,
|
|
414
|
+
tool_choice: "auto",
|
|
415
|
+
temperature: 0.2,
|
|
444
416
|
};
|
|
445
|
-
}
|
|
446
|
-
let payload = apiResult.data;
|
|
447
|
-
let choice = payload.choices?.[0];
|
|
448
|
-
let finishReason = choice?.finish_reason;
|
|
449
|
-
if (finishReason === "length" && !lengthRetryUsed) {
|
|
450
|
-
lengthRetryUsed = true;
|
|
451
|
-
const currentCap = requestBody.max_completion_tokens ??
|
|
452
|
-
getMaxCompletionTokens(profile);
|
|
453
|
-
maxCompletionTokensOverride = bumpMaxCompletionTokensForLengthRetry(profile, currentCap);
|
|
454
|
-
messages.push({ role: "user", content: LENGTH_RETRY_NUDGE });
|
|
455
417
|
applyCustomModelRequestDefaults(requestBody, {
|
|
456
418
|
profile,
|
|
457
419
|
modelId: input.modelId,
|
|
458
420
|
maxCompletionTokensOverride,
|
|
459
421
|
});
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
422
|
+
const callModel = async () => {
|
|
423
|
+
input.bus?.emit({
|
|
424
|
+
type: "model.request",
|
|
425
|
+
provider: "custom",
|
|
426
|
+
model: input.modelId,
|
|
427
|
+
hasVision: Boolean(input.hasVision),
|
|
428
|
+
});
|
|
429
|
+
const { value: result } = await withApiConcurrencyLimit((queueWaitMs) => postJsonWithRetry({
|
|
430
|
+
url: `${input.baseURL}/chat/completions`,
|
|
431
|
+
headers: {
|
|
432
|
+
Authorization: `Bearer ${input.apiKey}`,
|
|
433
|
+
"Content-Type": "application/json",
|
|
434
|
+
},
|
|
435
|
+
body: requestBody,
|
|
436
|
+
timeoutMs: input.timeoutMs ?? 300_000,
|
|
437
|
+
signal: input.signal,
|
|
438
|
+
}, queueWaitMs));
|
|
439
|
+
if (result.ok && result.data) {
|
|
440
|
+
const content = result.data.choices?.[0]?.message?.content?.trim() ?? "";
|
|
441
|
+
input.bus?.emit({
|
|
442
|
+
type: "model.response",
|
|
443
|
+
contentPreview: content.slice(0, 500),
|
|
444
|
+
timingMs: result.totalMs,
|
|
445
|
+
httpRetries: result.retries,
|
|
446
|
+
});
|
|
447
|
+
}
|
|
448
|
+
return result;
|
|
449
|
+
};
|
|
450
|
+
let apiResult = input.bus
|
|
451
|
+
? await input.bus.withTool("model_completion", { turn: turn + 1, model: input.modelId }, callModel)
|
|
468
452
|
: await callModel();
|
|
453
|
+
throwIfCancelled(input.signal);
|
|
469
454
|
if (!apiResult.ok || !apiResult.data) {
|
|
470
455
|
const rateLimit = apiResult.rateLimit;
|
|
471
456
|
return {
|
|
472
457
|
ok: false,
|
|
473
|
-
response:
|
|
474
|
-
summary: "Model API request failed
|
|
458
|
+
response: "",
|
|
459
|
+
summary: rateLimit ? "MiniMax rate limit exceeded" : "Model API request failed",
|
|
475
460
|
editsApplied,
|
|
476
461
|
toolCallCount: policyState.toolCallCount,
|
|
477
462
|
error: {
|
|
478
|
-
message: rateLimit
|
|
479
|
-
|
|
480
|
-
"Model API request failed"
|
|
463
|
+
message: rateLimit
|
|
464
|
+
? formatRateLimitReport(rateLimit)
|
|
465
|
+
: `${apiResult.errorMessage ?? "Model API request failed"} | ${formatTimingReport(apiResult)}`,
|
|
481
466
|
code: rateLimit ? "RATE_LIMIT" : "PROVIDER_ERROR",
|
|
482
467
|
},
|
|
483
468
|
};
|
|
484
469
|
}
|
|
485
|
-
payload = apiResult.data;
|
|
486
|
-
choice = payload.choices?.[0];
|
|
487
|
-
finishReason = choice?.finish_reason;
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
if (
|
|
470
|
+
let payload = apiResult.data;
|
|
471
|
+
let choice = payload.choices?.[0];
|
|
472
|
+
let finishReason = choice?.finish_reason;
|
|
473
|
+
if (finishReason === "length" && !lengthRetryUsed) {
|
|
474
|
+
lengthRetryUsed = true;
|
|
475
|
+
const currentCap = requestBody.max_completion_tokens ??
|
|
476
|
+
getMaxCompletionTokens(profile);
|
|
477
|
+
maxCompletionTokensOverride = bumpMaxCompletionTokensForLengthRetry(profile, currentCap);
|
|
478
|
+
messages.push({ role: "user", content: LENGTH_RETRY_NUDGE });
|
|
479
|
+
applyCustomModelRequestDefaults(requestBody, {
|
|
480
|
+
profile,
|
|
481
|
+
modelId: input.modelId,
|
|
482
|
+
maxCompletionTokensOverride,
|
|
483
|
+
});
|
|
484
|
+
requestBody.messages = trimAgentHistory(messages);
|
|
485
|
+
input.bus?.emit({
|
|
486
|
+
type: "model.repair",
|
|
487
|
+
reason: "length",
|
|
488
|
+
priorOutputSnippet: (choice?.message?.content ?? "").slice(0, 200),
|
|
489
|
+
});
|
|
490
|
+
apiResult = input.bus
|
|
491
|
+
? await input.bus.withTool("model_completion", { turn: turn + 1, model: input.modelId, lengthRetry: true }, callModel)
|
|
492
|
+
: await callModel();
|
|
493
|
+
if (!apiResult.ok || !apiResult.data) {
|
|
494
|
+
const rateLimit = apiResult.rateLimit;
|
|
495
|
+
return {
|
|
496
|
+
ok: false,
|
|
497
|
+
response: lastAssistantText,
|
|
498
|
+
summary: "Model API request failed after length retry",
|
|
499
|
+
editsApplied,
|
|
500
|
+
toolCallCount: policyState.toolCallCount,
|
|
501
|
+
error: {
|
|
502
|
+
message: rateLimit?.message ??
|
|
503
|
+
apiResult.errorMessage ??
|
|
504
|
+
"Model API request failed",
|
|
505
|
+
code: rateLimit ? "RATE_LIMIT" : "PROVIDER_ERROR",
|
|
506
|
+
},
|
|
507
|
+
};
|
|
508
|
+
}
|
|
509
|
+
payload = apiResult.data;
|
|
510
|
+
choice = payload.choices?.[0];
|
|
511
|
+
finishReason = choice?.finish_reason;
|
|
512
|
+
}
|
|
513
|
+
lastUsage = payload.usage;
|
|
514
|
+
const message = choice?.message;
|
|
515
|
+
if (!message) {
|
|
516
|
+
return {
|
|
517
|
+
ok: false,
|
|
518
|
+
response: lastAssistantText,
|
|
519
|
+
summary: "Model returned empty message",
|
|
520
|
+
editsApplied,
|
|
521
|
+
toolCallCount: policyState.toolCallCount,
|
|
522
|
+
error: { message: "Empty model response", code: "PROVIDER_ERROR" },
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
const toolCalls = message.tool_calls ?? [];
|
|
526
|
+
const assistantContent = typeof message.content === "string" ? message.content.trim() : "";
|
|
527
|
+
emitAgentRawModelTrace(input.bus, turn + 1, "custom", message);
|
|
528
|
+
if (assistantContent) {
|
|
529
|
+
lastAssistantText = assistantContent;
|
|
530
|
+
input.bus?.emit(buildAssistantEvent(assistantContent));
|
|
531
|
+
}
|
|
532
|
+
messages.push(toAssistantHistoryMessage(message));
|
|
533
|
+
if (toolCalls.length > 0) {
|
|
534
|
+
emitAgentToolSelectionThinking(input.bus, turn + 1, toolCalls.map((tc) => tc.function.name));
|
|
535
|
+
}
|
|
536
|
+
if (toolCalls.length === 0) {
|
|
537
|
+
const harnessOk = input.harnessMode && input.allowedWritePaths?.length
|
|
538
|
+
? editsApplied > 0
|
|
539
|
+
: editsApplied > 0 || assistantContent.length > 0;
|
|
540
|
+
return {
|
|
541
|
+
ok: harnessOk,
|
|
542
|
+
response: assistantContent || lastAssistantText || "Agent completed",
|
|
543
|
+
summary: editsApplied > 0 ? `Applied ${editsApplied} edit(s)` : assistantContent.slice(0, 200),
|
|
544
|
+
editsApplied,
|
|
545
|
+
toolCallCount: policyState.toolCallCount,
|
|
546
|
+
usage: lastUsage,
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
let mutatingEditsThisTurn = 0;
|
|
550
|
+
for (const toolCall of toolCalls) {
|
|
551
|
+
throwIfCancelled(input.signal);
|
|
552
|
+
const toolName = toolCall.function.name;
|
|
553
|
+
policyState = evaluateToolPolicy(toolName, policyState, maxToolCalls);
|
|
554
|
+
if (policyState.abortReason) {
|
|
555
|
+
messages.push({
|
|
556
|
+
role: "tool",
|
|
557
|
+
tool_call_id: toolCall.id,
|
|
558
|
+
content: `Tool blocked: ${policyState.abortReason}`,
|
|
559
|
+
});
|
|
560
|
+
break;
|
|
561
|
+
}
|
|
562
|
+
const args = parseToolArguments(toolCall.function.arguments);
|
|
563
|
+
const result = await executeAgentTool(toolName, args, toolCtx, input.bus);
|
|
564
|
+
const toolPath = typeof args.path === "string"
|
|
565
|
+
? args.path
|
|
566
|
+
: typeof args.file_path === "string"
|
|
567
|
+
? args.file_path
|
|
568
|
+
: typeof args.destPath === "string"
|
|
569
|
+
? args.destPath
|
|
570
|
+
: typeof args.dest_path === "string"
|
|
571
|
+
? args.dest_path
|
|
572
|
+
: typeof result.path === "string"
|
|
573
|
+
? result.path
|
|
574
|
+
: undefined;
|
|
575
|
+
const meta = result.meta ?? {};
|
|
576
|
+
const publicUrl = typeof meta.publicUrl === "string" ? meta.publicUrl : undefined;
|
|
577
|
+
const destPath = typeof meta.destPath === "string" ? meta.destPath : toolPath;
|
|
578
|
+
completionState.recentToolResults.push({
|
|
579
|
+
name: toolName,
|
|
580
|
+
ok: result.ok,
|
|
581
|
+
output: result.output,
|
|
582
|
+
path: destPath,
|
|
583
|
+
publicUrl,
|
|
584
|
+
meta,
|
|
585
|
+
});
|
|
586
|
+
if (completionState.recentToolResults.length > 5) {
|
|
587
|
+
completionState.recentToolResults.shift();
|
|
588
|
+
}
|
|
589
|
+
if (result.applied) {
|
|
590
|
+
editsApplied += 1;
|
|
591
|
+
mutatingEditsThisTurn += 1;
|
|
592
|
+
invalidateWorkspaceCheckpointCache(input.workspaceCheckpoint);
|
|
593
|
+
}
|
|
531
594
|
messages.push({
|
|
532
595
|
role: "tool",
|
|
533
596
|
tool_call_id: toolCall.id,
|
|
534
|
-
content:
|
|
597
|
+
content: result.output,
|
|
535
598
|
});
|
|
536
|
-
break;
|
|
537
599
|
}
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
:
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
600
|
+
if (mutatingEditsThisTurn > 0) {
|
|
601
|
+
const early = await tryHarnessEarlyFinish({
|
|
602
|
+
harnessMode: input.harnessMode,
|
|
603
|
+
allowedWritePaths: input.allowedWritePaths,
|
|
604
|
+
repoPath: input.repoPath,
|
|
605
|
+
workspaceCheckpoint: input.workspaceCheckpoint,
|
|
606
|
+
bus: input.bus,
|
|
607
|
+
policyState,
|
|
608
|
+
editsApplied,
|
|
609
|
+
lastAssistantText,
|
|
610
|
+
loopStartMs,
|
|
611
|
+
lastUsage,
|
|
612
|
+
messages,
|
|
613
|
+
modelTurnCount,
|
|
614
|
+
hasVision: input.hasVision,
|
|
615
|
+
selectedDom: input.selectedDom,
|
|
616
|
+
completion: input.completion,
|
|
617
|
+
completionAuto: input.completionAuto,
|
|
618
|
+
completionEvaluationEnabled: input.completionEvaluationEnabled,
|
|
619
|
+
completionConfidenceThreshold: input.completionConfidenceThreshold,
|
|
620
|
+
referenceImages: input.referenceImages,
|
|
621
|
+
ownerRequest: input.ownerRequest,
|
|
622
|
+
model: input.model,
|
|
623
|
+
timeoutMs: input.timeoutMs,
|
|
624
|
+
signal: input.signal,
|
|
625
|
+
completionState,
|
|
626
|
+
});
|
|
627
|
+
if (early) {
|
|
628
|
+
return early;
|
|
629
|
+
}
|
|
553
630
|
}
|
|
554
|
-
if (
|
|
555
|
-
|
|
556
|
-
mutatingEditsThisTurn += 1;
|
|
557
|
-
invalidateWorkspaceCheckpointCache(input.workspaceCheckpoint);
|
|
631
|
+
if (editsApplied > 0 && toolCalls.every((call) => !isMutatingTool(call.function.name))) {
|
|
632
|
+
continue;
|
|
558
633
|
}
|
|
559
|
-
messages.push({
|
|
560
|
-
role: "tool",
|
|
561
|
-
tool_call_id: toolCall.id,
|
|
562
|
-
content: result.output,
|
|
563
|
-
});
|
|
564
634
|
}
|
|
565
|
-
if (
|
|
635
|
+
if (input.harnessMode &&
|
|
636
|
+
input.allowedWritePaths?.length &&
|
|
637
|
+
editsApplied > 0) {
|
|
566
638
|
const early = await tryHarnessEarlyFinish({
|
|
567
639
|
harnessMode: input.harnessMode,
|
|
568
640
|
allowedWritePaths: input.allowedWritePaths,
|
|
@@ -575,7 +647,7 @@ export async function runAgentToolLoop(input) {
|
|
|
575
647
|
loopStartMs,
|
|
576
648
|
lastUsage,
|
|
577
649
|
messages,
|
|
578
|
-
modelTurnCount,
|
|
650
|
+
modelTurnCount: MAX_LOOP_TURNS,
|
|
579
651
|
hasVision: input.hasVision,
|
|
580
652
|
selectedDom: input.selectedDom,
|
|
581
653
|
completion: input.completion,
|
|
@@ -593,60 +665,27 @@ export async function runAgentToolLoop(input) {
|
|
|
593
665
|
return early;
|
|
594
666
|
}
|
|
595
667
|
}
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
editsApplied > 0) {
|
|
603
|
-
const early = await tryHarnessEarlyFinish({
|
|
604
|
-
harnessMode: input.harnessMode,
|
|
605
|
-
allowedWritePaths: input.allowedWritePaths,
|
|
606
|
-
repoPath: input.repoPath,
|
|
607
|
-
workspaceCheckpoint: input.workspaceCheckpoint,
|
|
608
|
-
bus: input.bus,
|
|
609
|
-
policyState,
|
|
668
|
+
return {
|
|
669
|
+
ok: editsApplied > 0,
|
|
670
|
+
response: lastAssistantText || "Agent loop ended",
|
|
671
|
+
summary: editsApplied > 0
|
|
672
|
+
? `Applied ${editsApplied} edit(s) via tools`
|
|
673
|
+
: policyState.abortReason ?? "Agent loop ended without edits",
|
|
610
674
|
editsApplied,
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
lastUsage,
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
model: input.model,
|
|
625
|
-
timeoutMs: input.timeoutMs,
|
|
626
|
-
signal: input.signal,
|
|
627
|
-
completionState,
|
|
628
|
-
});
|
|
629
|
-
if (early) {
|
|
630
|
-
return early;
|
|
631
|
-
}
|
|
675
|
+
toolCallCount: policyState.toolCallCount,
|
|
676
|
+
abortReason: policyState.abortReason,
|
|
677
|
+
usage: lastUsage,
|
|
678
|
+
error: editsApplied === 0
|
|
679
|
+
? {
|
|
680
|
+
message: policyState.abortReason ?? "No edits applied",
|
|
681
|
+
code: "EDIT_NOT_APPLIED",
|
|
682
|
+
}
|
|
683
|
+
: undefined,
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
finally {
|
|
687
|
+
clearHostToolsForRun();
|
|
632
688
|
}
|
|
633
|
-
return {
|
|
634
|
-
ok: editsApplied > 0,
|
|
635
|
-
response: lastAssistantText || "Agent loop ended",
|
|
636
|
-
summary: editsApplied > 0
|
|
637
|
-
? `Applied ${editsApplied} edit(s) via tools`
|
|
638
|
-
: policyState.abortReason ?? "Agent loop ended without edits",
|
|
639
|
-
editsApplied,
|
|
640
|
-
toolCallCount: policyState.toolCallCount,
|
|
641
|
-
abortReason: policyState.abortReason,
|
|
642
|
-
usage: lastUsage,
|
|
643
|
-
error: editsApplied === 0
|
|
644
|
-
? {
|
|
645
|
-
message: policyState.abortReason ?? "No edits applied",
|
|
646
|
-
code: "EDIT_NOT_APPLIED",
|
|
647
|
-
}
|
|
648
|
-
: undefined,
|
|
649
|
-
};
|
|
650
689
|
}
|
|
651
690
|
function isMutatingTool(toolName) {
|
|
652
691
|
const name = toolName.toLowerCase();
|