@mindstudio-ai/remy 0.1.336 → 0.1.338
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.js +449 -461
- package/dist/index.js +458 -470
- package/dist/prompt/compiled/sdk-actions.md +14 -0
- package/dist/prompt/skills/files.md +4 -2
- package/dist/prompt/static/coding.md +2 -2
- package/package.json +1 -1
package/dist/headless.js
CHANGED
|
@@ -3776,120 +3776,6 @@ var ROTATE_THRESHOLD_BYTES = 32 * 1024 * 1024;
|
|
|
3776
3776
|
var RETAIN_TAIL_BYTES = 16 * 1024 * 1024;
|
|
3777
3777
|
var ARCHIVE_RETENTION_BYTES = 64 * 1024 * 1024;
|
|
3778
3778
|
|
|
3779
|
-
// src/statusWatcher.ts
|
|
3780
|
-
var INTERNAL_PAYLOAD_MARKERS = [
|
|
3781
|
-
"[USER CANCELLED]",
|
|
3782
|
-
"[INTERRUPTED]",
|
|
3783
|
-
"[INTERRUPTED - PARTIAL OUTPUT RETRIEVED]",
|
|
3784
|
-
"<background_results>",
|
|
3785
|
-
"<workspace_status>",
|
|
3786
|
-
"<tool_result"
|
|
3787
|
-
];
|
|
3788
|
-
function sanitizeStatusText(text) {
|
|
3789
|
-
if (!text) {
|
|
3790
|
-
return "";
|
|
3791
|
-
}
|
|
3792
|
-
for (const marker of INTERNAL_PAYLOAD_MARKERS) {
|
|
3793
|
-
if (text.includes(marker)) {
|
|
3794
|
-
return "";
|
|
3795
|
-
}
|
|
3796
|
-
}
|
|
3797
|
-
const truncIdx = text.indexOf("(tool result truncated at");
|
|
3798
|
-
return truncIdx === -1 ? text : text.slice(0, truncIdx);
|
|
3799
|
-
}
|
|
3800
|
-
function startStatusWatcher(config) {
|
|
3801
|
-
const { apiConfig, getContext, onStatus, interval = 5e3, signal } = config;
|
|
3802
|
-
let inflight2 = false;
|
|
3803
|
-
let stopped = false;
|
|
3804
|
-
let pauseCount = 0;
|
|
3805
|
-
const url = `${apiConfig.baseUrl}/_internal/v2/agent/remy/generate-status`;
|
|
3806
|
-
let consecutiveFailures = 0;
|
|
3807
|
-
let backoffMs = 0;
|
|
3808
|
-
let nextAllowedAt = 0;
|
|
3809
|
-
const MAX_CONSECUTIVE_FAILURES = 10;
|
|
3810
|
-
const MAX_BACKOFF_MS = 6e4;
|
|
3811
|
-
function recordFailure() {
|
|
3812
|
-
consecutiveFailures++;
|
|
3813
|
-
backoffMs = Math.min(
|
|
3814
|
-
backoffMs === 0 ? interval : backoffMs * 2,
|
|
3815
|
-
MAX_BACKOFF_MS
|
|
3816
|
-
);
|
|
3817
|
-
nextAllowedAt = Date.now() + backoffMs;
|
|
3818
|
-
if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES && !stopped) {
|
|
3819
|
-
stopped = true;
|
|
3820
|
-
clearInterval(timer);
|
|
3821
|
-
}
|
|
3822
|
-
}
|
|
3823
|
-
async function tick() {
|
|
3824
|
-
if (stopped || signal?.aborted || inflight2 || pauseCount > 0) {
|
|
3825
|
-
return;
|
|
3826
|
-
}
|
|
3827
|
-
if (Date.now() < nextAllowedAt) {
|
|
3828
|
-
return;
|
|
3829
|
-
}
|
|
3830
|
-
inflight2 = true;
|
|
3831
|
-
try {
|
|
3832
|
-
const context = getContext();
|
|
3833
|
-
if (!context) {
|
|
3834
|
-
return;
|
|
3835
|
-
}
|
|
3836
|
-
const res = await fetch(url, {
|
|
3837
|
-
method: "POST",
|
|
3838
|
-
headers: {
|
|
3839
|
-
"Content-Type": "application/json",
|
|
3840
|
-
Authorization: `Bearer ${apiConfig.apiKey}`,
|
|
3841
|
-
// Also a liveness signal for this box, and the most frequent one there is — this ticks
|
|
3842
|
-
// every few seconds for as long as the agent is working, which is exactly the window in
|
|
3843
|
-
// which the user may have backgrounded the tab and stopped its own keepalive.
|
|
3844
|
-
...sandboxSessionHeader()
|
|
3845
|
-
},
|
|
3846
|
-
body: JSON.stringify({ appId: apiConfig.appId, context }),
|
|
3847
|
-
signal
|
|
3848
|
-
});
|
|
3849
|
-
if (stopped) {
|
|
3850
|
-
return;
|
|
3851
|
-
}
|
|
3852
|
-
if (!res.ok) {
|
|
3853
|
-
recordFailure();
|
|
3854
|
-
return;
|
|
3855
|
-
}
|
|
3856
|
-
const data = await res.json();
|
|
3857
|
-
if (!data.label) {
|
|
3858
|
-
recordFailure();
|
|
3859
|
-
return;
|
|
3860
|
-
}
|
|
3861
|
-
consecutiveFailures = 0;
|
|
3862
|
-
backoffMs = 0;
|
|
3863
|
-
nextAllowedAt = 0;
|
|
3864
|
-
if (pauseCount > 0 || stopped || signal?.aborted) {
|
|
3865
|
-
return;
|
|
3866
|
-
}
|
|
3867
|
-
onStatus(data.label);
|
|
3868
|
-
} catch {
|
|
3869
|
-
if (!stopped && !signal?.aborted) {
|
|
3870
|
-
recordFailure();
|
|
3871
|
-
}
|
|
3872
|
-
} finally {
|
|
3873
|
-
inflight2 = false;
|
|
3874
|
-
}
|
|
3875
|
-
}
|
|
3876
|
-
const timer = setInterval(tick, interval);
|
|
3877
|
-
tick().catch(() => {
|
|
3878
|
-
});
|
|
3879
|
-
return {
|
|
3880
|
-
stop() {
|
|
3881
|
-
stopped = true;
|
|
3882
|
-
clearInterval(timer);
|
|
3883
|
-
},
|
|
3884
|
-
pause() {
|
|
3885
|
-
pauseCount++;
|
|
3886
|
-
},
|
|
3887
|
-
resume() {
|
|
3888
|
-
pauseCount = Math.max(0, pauseCount - 1);
|
|
3889
|
-
}
|
|
3890
|
-
};
|
|
3891
|
-
}
|
|
3892
|
-
|
|
3893
3779
|
// src/subagents/common/cleanMessages.ts
|
|
3894
3780
|
function findLastSummaryCheckpoint(messages, name) {
|
|
3895
3781
|
for (let i = messages.length - 1; i >= 0; i--) {
|
|
@@ -4114,376 +4000,339 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
|
|
|
4114
4000
|
}
|
|
4115
4001
|
return { text: cancelledToolResult(signal), messages: thisInvocation() };
|
|
4116
4002
|
}
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4144
|
-
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
try {
|
|
4160
|
-
for await (const event of streamChatWithRetry(
|
|
4161
|
-
{
|
|
4162
|
-
...apiConfig,
|
|
4163
|
-
model,
|
|
4164
|
-
requestId,
|
|
4165
|
-
subAgentId,
|
|
4166
|
-
system: fullSystem,
|
|
4167
|
-
messages: cleanMessagesForApi(messages),
|
|
4168
|
-
tools: tools2,
|
|
4169
|
-
cachePolicy,
|
|
4170
|
-
signal
|
|
4171
|
-
},
|
|
4172
|
-
{
|
|
4173
|
-
onRetry: (attempt) => emit({
|
|
4174
|
-
type: "status",
|
|
4175
|
-
message: `Lost connection, retrying (attempt ${attempt + 2} of 3)`
|
|
4176
|
-
})
|
|
4177
|
-
}
|
|
4178
|
-
)) {
|
|
4179
|
-
if (signal?.aborted) {
|
|
4180
|
-
break;
|
|
4181
|
-
}
|
|
4182
|
-
switch (event.type) {
|
|
4183
|
-
case "text": {
|
|
4184
|
-
const lastBlock = contentBlocks.at(-1);
|
|
4185
|
-
if (lastBlock?.type === "text") {
|
|
4186
|
-
lastBlock.text += event.text;
|
|
4187
|
-
} else {
|
|
4188
|
-
contentBlocks.push({
|
|
4189
|
-
type: "text",
|
|
4190
|
-
text: event.text,
|
|
4191
|
-
startedAt: event.ts
|
|
4192
|
-
});
|
|
4193
|
-
}
|
|
4194
|
-
emit({ type: "text", text: event.text });
|
|
4195
|
-
break;
|
|
4196
|
-
}
|
|
4197
|
-
case "thinking":
|
|
4198
|
-
if (!thinkingStartedAt) {
|
|
4199
|
-
thinkingStartedAt = event.ts;
|
|
4200
|
-
}
|
|
4201
|
-
emit({ type: "thinking", text: event.text });
|
|
4202
|
-
break;
|
|
4203
|
-
case "thinking_complete":
|
|
4204
|
-
contentBlocks.push({
|
|
4205
|
-
type: "thinking",
|
|
4206
|
-
thinking: event.thinking,
|
|
4207
|
-
signature: event.signature,
|
|
4208
|
-
startedAt: thinkingStartedAt,
|
|
4209
|
-
completedAt: event.ts
|
|
4210
|
-
});
|
|
4211
|
-
lastThinkingRelatedStartedAt = thinkingStartedAt;
|
|
4212
|
-
thinkingStartedAt = 0;
|
|
4213
|
-
break;
|
|
4214
|
-
case "redacted_thinking_complete": {
|
|
4215
|
-
const startedAt = lastThinkingRelatedStartedAt !== void 0 ? lastThinkingRelatedStartedAt + 1 : event.ts;
|
|
4003
|
+
while (true) {
|
|
4004
|
+
turns++;
|
|
4005
|
+
if (signal?.aborted) {
|
|
4006
|
+
return abortResult([]);
|
|
4007
|
+
}
|
|
4008
|
+
const iterStart = Date.now();
|
|
4009
|
+
const contentBlocks = [];
|
|
4010
|
+
let thinkingStartedAt = 0;
|
|
4011
|
+
let lastThinkingRelatedStartedAt;
|
|
4012
|
+
let stopReason = "end_turn";
|
|
4013
|
+
let lastUsage;
|
|
4014
|
+
let lastProviderMetadata;
|
|
4015
|
+
let lastModelId;
|
|
4016
|
+
try {
|
|
4017
|
+
for await (const event of streamChatWithRetry(
|
|
4018
|
+
{
|
|
4019
|
+
...apiConfig,
|
|
4020
|
+
model,
|
|
4021
|
+
requestId,
|
|
4022
|
+
subAgentId,
|
|
4023
|
+
system: fullSystem,
|
|
4024
|
+
messages: cleanMessagesForApi(messages),
|
|
4025
|
+
tools: tools2,
|
|
4026
|
+
cachePolicy,
|
|
4027
|
+
signal
|
|
4028
|
+
},
|
|
4029
|
+
{
|
|
4030
|
+
onRetry: (attempt) => emit({
|
|
4031
|
+
type: "status",
|
|
4032
|
+
message: `Lost connection, retrying (attempt ${attempt + 2} of 3)`
|
|
4033
|
+
})
|
|
4034
|
+
}
|
|
4035
|
+
)) {
|
|
4036
|
+
if (signal?.aborted) {
|
|
4037
|
+
break;
|
|
4038
|
+
}
|
|
4039
|
+
switch (event.type) {
|
|
4040
|
+
case "text": {
|
|
4041
|
+
const lastBlock = contentBlocks.at(-1);
|
|
4042
|
+
if (lastBlock?.type === "text") {
|
|
4043
|
+
lastBlock.text += event.text;
|
|
4044
|
+
} else {
|
|
4216
4045
|
contentBlocks.push({
|
|
4217
|
-
type: "
|
|
4218
|
-
|
|
4219
|
-
startedAt
|
|
4220
|
-
completedAt: event.ts
|
|
4046
|
+
type: "text",
|
|
4047
|
+
text: event.text,
|
|
4048
|
+
startedAt: event.ts
|
|
4221
4049
|
});
|
|
4222
|
-
lastThinkingRelatedStartedAt = startedAt;
|
|
4223
|
-
break;
|
|
4224
4050
|
}
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
type: "tool",
|
|
4228
|
-
id: event.id,
|
|
4229
|
-
name: event.name,
|
|
4230
|
-
input: event.input,
|
|
4231
|
-
startedAt: Date.now()
|
|
4232
|
-
});
|
|
4233
|
-
emit({
|
|
4234
|
-
type: "tool_start",
|
|
4235
|
-
id: event.id,
|
|
4236
|
-
name: event.name,
|
|
4237
|
-
input: event.input
|
|
4238
|
-
});
|
|
4239
|
-
break;
|
|
4240
|
-
case "done":
|
|
4241
|
-
stopReason = event.stopReason;
|
|
4242
|
-
lastUsage = {
|
|
4243
|
-
inputTokens: event.usage.inputTokens,
|
|
4244
|
-
outputTokens: event.usage.outputTokens,
|
|
4245
|
-
cacheCreationTokens: event.usage.cacheCreationTokens,
|
|
4246
|
-
cacheReadTokens: event.usage.cacheReadTokens,
|
|
4247
|
-
llmCalls: 1
|
|
4248
|
-
};
|
|
4249
|
-
lastProviderMetadata = event.providerMetadata;
|
|
4250
|
-
lastModelId = event.modelId;
|
|
4251
|
-
recordUsage({
|
|
4252
|
-
ts: Date.now(),
|
|
4253
|
-
requestId,
|
|
4254
|
-
agentName: subAgentId || "sub-agent",
|
|
4255
|
-
parentToolId,
|
|
4256
|
-
modelId: event.modelId,
|
|
4257
|
-
inputTokens: event.usage.inputTokens,
|
|
4258
|
-
outputTokens: event.usage.outputTokens,
|
|
4259
|
-
cacheCreationTokens: event.usage.cacheCreationTokens,
|
|
4260
|
-
cacheReadTokens: event.usage.cacheReadTokens,
|
|
4261
|
-
cost: nanoToDollars(event.cost),
|
|
4262
|
-
billingEvents: event.billingEvents,
|
|
4263
|
-
durationMs: Date.now() - iterStart,
|
|
4264
|
-
toolNames: contentBlocks.filter(
|
|
4265
|
-
(b) => b.type === "tool"
|
|
4266
|
-
).map((b) => b.name)
|
|
4267
|
-
});
|
|
4268
|
-
break;
|
|
4269
|
-
case "error":
|
|
4270
|
-
statusWatcher.stop();
|
|
4271
|
-
return {
|
|
4272
|
-
text: `Error: ${event.error}`,
|
|
4273
|
-
messages: thisInvocation()
|
|
4274
|
-
};
|
|
4051
|
+
emit({ type: "text", text: event.text });
|
|
4052
|
+
break;
|
|
4275
4053
|
}
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
...lastUsage ? { usage: lastUsage } : {},
|
|
4290
|
-
...lastProviderMetadata ? { providerMetadata: lastProviderMetadata } : {},
|
|
4291
|
-
model: lastModelId ?? model
|
|
4292
|
-
});
|
|
4293
|
-
const toolCalls = contentBlocks.filter(
|
|
4294
|
-
(b) => b.type === "tool"
|
|
4295
|
-
);
|
|
4296
|
-
if (stopReason !== "tool_use" || toolCalls.length === 0) {
|
|
4297
|
-
let text = getPartialText(contentBlocks);
|
|
4298
|
-
if (validateResult) {
|
|
4299
|
-
let objection = null;
|
|
4300
|
-
try {
|
|
4301
|
-
objection = await validateResult(text, thisInvocation());
|
|
4302
|
-
} catch (err) {
|
|
4303
|
-
log8.warn("Result validator failed, accepting response", {
|
|
4304
|
-
requestId,
|
|
4305
|
-
parentToolId,
|
|
4306
|
-
agentName,
|
|
4307
|
-
error: err.message
|
|
4054
|
+
case "thinking":
|
|
4055
|
+
if (!thinkingStartedAt) {
|
|
4056
|
+
thinkingStartedAt = event.ts;
|
|
4057
|
+
}
|
|
4058
|
+
emit({ type: "thinking", text: event.text });
|
|
4059
|
+
break;
|
|
4060
|
+
case "thinking_complete":
|
|
4061
|
+
contentBlocks.push({
|
|
4062
|
+
type: "thinking",
|
|
4063
|
+
thinking: event.thinking,
|
|
4064
|
+
signature: event.signature,
|
|
4065
|
+
startedAt: thinkingStartedAt,
|
|
4066
|
+
completedAt: event.ts
|
|
4308
4067
|
});
|
|
4068
|
+
lastThinkingRelatedStartedAt = thinkingStartedAt;
|
|
4069
|
+
thinkingStartedAt = 0;
|
|
4070
|
+
break;
|
|
4071
|
+
case "redacted_thinking_complete": {
|
|
4072
|
+
const startedAt = lastThinkingRelatedStartedAt !== void 0 ? lastThinkingRelatedStartedAt + 1 : event.ts;
|
|
4073
|
+
contentBlocks.push({
|
|
4074
|
+
type: "redacted_thinking",
|
|
4075
|
+
data: event.data,
|
|
4076
|
+
startedAt,
|
|
4077
|
+
completedAt: event.ts
|
|
4078
|
+
});
|
|
4079
|
+
lastThinkingRelatedStartedAt = startedAt;
|
|
4080
|
+
break;
|
|
4309
4081
|
}
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4082
|
+
case "tool_use":
|
|
4083
|
+
contentBlocks.push({
|
|
4084
|
+
type: "tool",
|
|
4085
|
+
id: event.id,
|
|
4086
|
+
name: event.name,
|
|
4087
|
+
input: event.input,
|
|
4088
|
+
startedAt: Date.now()
|
|
4317
4089
|
});
|
|
4318
4090
|
emit({
|
|
4319
|
-
type: "
|
|
4320
|
-
|
|
4091
|
+
type: "tool_start",
|
|
4092
|
+
id: event.id,
|
|
4093
|
+
name: event.name,
|
|
4094
|
+
input: event.input
|
|
4321
4095
|
});
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
|
|
4325
|
-
|
|
4326
|
-
|
|
4096
|
+
break;
|
|
4097
|
+
case "done":
|
|
4098
|
+
stopReason = event.stopReason;
|
|
4099
|
+
lastUsage = {
|
|
4100
|
+
inputTokens: event.usage.inputTokens,
|
|
4101
|
+
outputTokens: event.usage.outputTokens,
|
|
4102
|
+
cacheCreationTokens: event.usage.cacheCreationTokens,
|
|
4103
|
+
cacheReadTokens: event.usage.cacheReadTokens,
|
|
4104
|
+
llmCalls: 1
|
|
4105
|
+
};
|
|
4106
|
+
lastProviderMetadata = event.providerMetadata;
|
|
4107
|
+
lastModelId = event.modelId;
|
|
4108
|
+
recordUsage({
|
|
4109
|
+
ts: Date.now(),
|
|
4110
|
+
requestId,
|
|
4111
|
+
agentName: subAgentId || "sub-agent",
|
|
4112
|
+
parentToolId,
|
|
4113
|
+
modelId: event.modelId,
|
|
4114
|
+
inputTokens: event.usage.inputTokens,
|
|
4115
|
+
outputTokens: event.usage.outputTokens,
|
|
4116
|
+
cacheCreationTokens: event.usage.cacheCreationTokens,
|
|
4117
|
+
cacheReadTokens: event.usage.cacheReadTokens,
|
|
4118
|
+
cost: nanoToDollars(event.cost),
|
|
4119
|
+
billingEvents: event.billingEvents,
|
|
4120
|
+
durationMs: Date.now() - iterStart,
|
|
4121
|
+
toolNames: contentBlocks.filter(
|
|
4122
|
+
(b) => b.type === "tool"
|
|
4123
|
+
).map((b) => b.name)
|
|
4124
|
+
});
|
|
4125
|
+
break;
|
|
4126
|
+
case "error":
|
|
4127
|
+
return {
|
|
4128
|
+
text: `Error: ${event.error}`,
|
|
4129
|
+
messages: thisInvocation()
|
|
4130
|
+
};
|
|
4131
|
+
}
|
|
4132
|
+
}
|
|
4133
|
+
} catch (err) {
|
|
4134
|
+
if (!signal?.aborted) {
|
|
4135
|
+
throw err;
|
|
4136
|
+
}
|
|
4137
|
+
}
|
|
4138
|
+
if (signal?.aborted) {
|
|
4139
|
+
return abortResult(contentBlocks);
|
|
4140
|
+
}
|
|
4141
|
+
messages.push({
|
|
4142
|
+
role: "assistant",
|
|
4143
|
+
content: contentBlocks,
|
|
4144
|
+
...lastUsage ? { usage: lastUsage } : {},
|
|
4145
|
+
...lastProviderMetadata ? { providerMetadata: lastProviderMetadata } : {},
|
|
4146
|
+
model: lastModelId ?? model
|
|
4147
|
+
});
|
|
4148
|
+
const toolCalls = contentBlocks.filter(
|
|
4149
|
+
(b) => b.type === "tool"
|
|
4150
|
+
);
|
|
4151
|
+
if (stopReason !== "tool_use" || toolCalls.length === 0) {
|
|
4152
|
+
let text = getPartialText(contentBlocks);
|
|
4153
|
+
if (validateResult) {
|
|
4154
|
+
let objection = null;
|
|
4155
|
+
try {
|
|
4156
|
+
objection = await validateResult(text, thisInvocation());
|
|
4157
|
+
} catch (err) {
|
|
4158
|
+
log8.warn("Result validator failed, accepting response", {
|
|
4159
|
+
requestId,
|
|
4160
|
+
parentToolId,
|
|
4161
|
+
agentName,
|
|
4162
|
+
error: err.message
|
|
4163
|
+
});
|
|
4164
|
+
}
|
|
4165
|
+
if (objection && !validationRetried && !signal?.aborted) {
|
|
4166
|
+
validationRetried = true;
|
|
4167
|
+
log8.info("Result rejected by validator, retrying once", {
|
|
4168
|
+
requestId,
|
|
4169
|
+
parentToolId,
|
|
4170
|
+
agentName,
|
|
4171
|
+
objection: objection.slice(0, 200)
|
|
4172
|
+
});
|
|
4173
|
+
emit({
|
|
4174
|
+
type: "status",
|
|
4175
|
+
message: "Response failed validation, revising"
|
|
4176
|
+
});
|
|
4177
|
+
messages.push({ role: "user", content: objection });
|
|
4178
|
+
continue;
|
|
4179
|
+
}
|
|
4180
|
+
if (objection) {
|
|
4181
|
+
text = `${text}
|
|
4327
4182
|
|
|
4328
4183
|
[Response validator: ${objection}]`;
|
|
4329
|
-
}
|
|
4330
4184
|
}
|
|
4331
|
-
statusWatcher.stop();
|
|
4332
|
-
const hasArtifacts = Object.keys(artifacts).length > 0;
|
|
4333
|
-
return {
|
|
4334
|
-
text,
|
|
4335
|
-
messages: thisInvocation(),
|
|
4336
|
-
...hasArtifacts ? { artifacts } : {}
|
|
4337
|
-
};
|
|
4338
4185
|
}
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
|
|
4343
|
-
|
|
4344
|
-
}
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
|
|
4356
|
-
const resultPromise = new Promise((res) => {
|
|
4357
|
-
settle = (result, isError, recording) => res({
|
|
4358
|
-
id: tc.id,
|
|
4359
|
-
result,
|
|
4360
|
-
isError,
|
|
4361
|
-
...recording ? { recording } : {}
|
|
4362
|
-
});
|
|
4363
|
-
});
|
|
4364
|
-
let toolAbort = new AbortController();
|
|
4365
|
-
const cascadeAbort = () => toolAbort.abort();
|
|
4366
|
-
signal?.addEventListener("abort", cascadeAbort, { once: true });
|
|
4367
|
-
let settled = false;
|
|
4368
|
-
const safeSettle = (result, isError, recording) => {
|
|
4369
|
-
if (settled) {
|
|
4370
|
-
return;
|
|
4371
|
-
}
|
|
4372
|
-
settled = true;
|
|
4373
|
-
signal?.removeEventListener("abort", cascadeAbort);
|
|
4374
|
-
settle(result, isError, recording);
|
|
4375
|
-
};
|
|
4376
|
-
const run2 = async (input) => {
|
|
4377
|
-
try {
|
|
4378
|
-
let result;
|
|
4379
|
-
let recording;
|
|
4380
|
-
if (externalTools.has(tc.name) && resolveExternalTool) {
|
|
4381
|
-
result = await resolveExternalTool(tc.id, tc.name, input);
|
|
4382
|
-
if (tc.name === "browserCommand") {
|
|
4383
|
-
const lifted = liftRecording(result);
|
|
4384
|
-
result = lifted.result;
|
|
4385
|
-
recording = lifted.recording;
|
|
4386
|
-
}
|
|
4387
|
-
} else {
|
|
4388
|
-
const onLog = (line) => emit({
|
|
4389
|
-
type: "tool_input_delta",
|
|
4390
|
-
id: tc.id,
|
|
4391
|
-
name: tc.name,
|
|
4392
|
-
result: line
|
|
4393
|
-
});
|
|
4394
|
-
result = await executeTool2(
|
|
4395
|
-
tc.name,
|
|
4396
|
-
input,
|
|
4397
|
-
tc.id,
|
|
4398
|
-
onLog,
|
|
4399
|
-
subAgentMessages
|
|
4400
|
-
);
|
|
4401
|
-
}
|
|
4402
|
-
safeSettle(
|
|
4403
|
-
capToolResult(result),
|
|
4404
|
-
result.startsWith("Error"),
|
|
4405
|
-
recording
|
|
4406
|
-
);
|
|
4407
|
-
} catch (err) {
|
|
4408
|
-
safeSettle(`Error: ${err.message}`, true);
|
|
4409
|
-
}
|
|
4410
|
-
};
|
|
4411
|
-
const entry = {
|
|
4186
|
+
const hasArtifacts = Object.keys(artifacts).length > 0;
|
|
4187
|
+
return {
|
|
4188
|
+
text,
|
|
4189
|
+
messages: thisInvocation(),
|
|
4190
|
+
...hasArtifacts ? { artifacts } : {}
|
|
4191
|
+
};
|
|
4192
|
+
}
|
|
4193
|
+
log8.info("Tools executing", {
|
|
4194
|
+
requestId,
|
|
4195
|
+
parentToolId,
|
|
4196
|
+
count: toolCalls.length,
|
|
4197
|
+
tools: toolCalls.map((tc) => tc.name)
|
|
4198
|
+
});
|
|
4199
|
+
const results = await Promise.all(
|
|
4200
|
+
toolCalls.map(async (tc) => {
|
|
4201
|
+
if (signal?.aborted) {
|
|
4202
|
+
return {
|
|
4412
4203
|
id: tc.id,
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
parentToolId,
|
|
4416
|
-
abortController: toolAbort,
|
|
4417
|
-
startedAt: Date.now(),
|
|
4418
|
-
settle: safeSettle,
|
|
4419
|
-
rerun: (newInput) => {
|
|
4420
|
-
settled = false;
|
|
4421
|
-
toolAbort = new AbortController();
|
|
4422
|
-
signal?.addEventListener("abort", () => toolAbort.abort(), {
|
|
4423
|
-
once: true
|
|
4424
|
-
});
|
|
4425
|
-
entry.abortController = toolAbort;
|
|
4426
|
-
entry.input = newInput;
|
|
4427
|
-
run2(newInput);
|
|
4428
|
-
}
|
|
4204
|
+
result: cancelledToolResult(signal),
|
|
4205
|
+
isError: true
|
|
4429
4206
|
};
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
toolRegistry?.unregister(tc.id);
|
|
4435
|
-
log8.info("Tool completed", {
|
|
4436
|
-
requestId,
|
|
4437
|
-
parentToolId,
|
|
4438
|
-
toolCallId: tc.id,
|
|
4439
|
-
name: tc.name,
|
|
4440
|
-
durationMs: Date.now() - toolStart,
|
|
4441
|
-
isError: r.isError
|
|
4442
|
-
});
|
|
4443
|
-
emit({
|
|
4444
|
-
type: "tool_done",
|
|
4207
|
+
}
|
|
4208
|
+
let settle;
|
|
4209
|
+
const resultPromise = new Promise((res) => {
|
|
4210
|
+
settle = (result, isError, recording) => res({
|
|
4445
4211
|
id: tc.id,
|
|
4446
|
-
|
|
4447
|
-
|
|
4448
|
-
|
|
4449
|
-
...r.recording ? { recording: r.recording } : {}
|
|
4212
|
+
result,
|
|
4213
|
+
isError,
|
|
4214
|
+
...recording ? { recording } : {}
|
|
4450
4215
|
});
|
|
4451
|
-
|
|
4452
|
-
|
|
4453
|
-
|
|
4454
|
-
|
|
4455
|
-
|
|
4456
|
-
const
|
|
4457
|
-
(
|
|
4458
|
-
|
|
4459
|
-
if (block?.type === "tool") {
|
|
4460
|
-
block.result = r.result;
|
|
4461
|
-
block.isError = r.isError;
|
|
4462
|
-
block.completedAt = Date.now();
|
|
4463
|
-
if (r.recording) {
|
|
4464
|
-
block.recording = r.recording;
|
|
4465
|
-
}
|
|
4466
|
-
const innerMsgs = subAgentMessages.get(r.id);
|
|
4467
|
-
if (innerMsgs) {
|
|
4468
|
-
attachSubAgentTranscript(block, innerMsgs);
|
|
4216
|
+
});
|
|
4217
|
+
let toolAbort = new AbortController();
|
|
4218
|
+
const cascadeAbort = () => toolAbort.abort();
|
|
4219
|
+
signal?.addEventListener("abort", cascadeAbort, { once: true });
|
|
4220
|
+
let settled = false;
|
|
4221
|
+
const safeSettle = (result, isError, recording) => {
|
|
4222
|
+
if (settled) {
|
|
4223
|
+
return;
|
|
4469
4224
|
}
|
|
4470
|
-
|
|
4471
|
-
|
|
4472
|
-
|
|
4473
|
-
|
|
4225
|
+
settled = true;
|
|
4226
|
+
signal?.removeEventListener("abort", cascadeAbort);
|
|
4227
|
+
settle(result, isError, recording);
|
|
4228
|
+
};
|
|
4229
|
+
const run2 = async (input) => {
|
|
4230
|
+
try {
|
|
4231
|
+
let result;
|
|
4232
|
+
let recording;
|
|
4233
|
+
if (externalTools.has(tc.name) && resolveExternalTool) {
|
|
4234
|
+
result = await resolveExternalTool(tc.id, tc.name, input);
|
|
4235
|
+
if (tc.name === "browserCommand") {
|
|
4236
|
+
const lifted = liftRecording(result);
|
|
4237
|
+
result = lifted.result;
|
|
4238
|
+
recording = lifted.recording;
|
|
4239
|
+
}
|
|
4240
|
+
} else {
|
|
4241
|
+
const onLog = (line) => emit({
|
|
4242
|
+
type: "tool_input_delta",
|
|
4243
|
+
id: tc.id,
|
|
4244
|
+
name: tc.name,
|
|
4245
|
+
result: line
|
|
4246
|
+
});
|
|
4247
|
+
result = await executeTool2(
|
|
4248
|
+
tc.name,
|
|
4249
|
+
input,
|
|
4250
|
+
tc.id,
|
|
4251
|
+
onLog,
|
|
4252
|
+
subAgentMessages
|
|
4253
|
+
);
|
|
4474
4254
|
}
|
|
4255
|
+
safeSettle(
|
|
4256
|
+
capToolResult(result),
|
|
4257
|
+
result.startsWith("Error"),
|
|
4258
|
+
recording
|
|
4259
|
+
);
|
|
4260
|
+
} catch (err) {
|
|
4261
|
+
safeSettle(`Error: ${err.message}`, true);
|
|
4475
4262
|
}
|
|
4476
|
-
}
|
|
4477
|
-
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4263
|
+
};
|
|
4264
|
+
const entry = {
|
|
4265
|
+
id: tc.id,
|
|
4266
|
+
name: tc.name,
|
|
4267
|
+
input: tc.input,
|
|
4268
|
+
parentToolId,
|
|
4269
|
+
abortController: toolAbort,
|
|
4270
|
+
startedAt: Date.now(),
|
|
4271
|
+
settle: safeSettle,
|
|
4272
|
+
rerun: (newInput) => {
|
|
4273
|
+
settled = false;
|
|
4274
|
+
toolAbort = new AbortController();
|
|
4275
|
+
signal?.addEventListener("abort", () => toolAbort.abort(), {
|
|
4276
|
+
once: true
|
|
4277
|
+
});
|
|
4278
|
+
entry.abortController = toolAbort;
|
|
4279
|
+
entry.input = newInput;
|
|
4280
|
+
run2(newInput);
|
|
4281
|
+
}
|
|
4282
|
+
};
|
|
4283
|
+
toolRegistry?.register(entry);
|
|
4284
|
+
const toolStart = Date.now();
|
|
4285
|
+
run2(tc.input);
|
|
4286
|
+
const r = await resultPromise;
|
|
4287
|
+
toolRegistry?.unregister(tc.id);
|
|
4288
|
+
log8.info("Tool completed", {
|
|
4289
|
+
requestId,
|
|
4290
|
+
parentToolId,
|
|
4291
|
+
toolCallId: tc.id,
|
|
4292
|
+
name: tc.name,
|
|
4293
|
+
durationMs: Date.now() - toolStart,
|
|
4294
|
+
isError: r.isError
|
|
4295
|
+
});
|
|
4296
|
+
emit({
|
|
4297
|
+
type: "tool_done",
|
|
4298
|
+
id: tc.id,
|
|
4299
|
+
name: tc.name,
|
|
4300
|
+
result: r.result,
|
|
4301
|
+
isError: r.isError,
|
|
4302
|
+
...r.recording ? { recording: r.recording } : {}
|
|
4482
4303
|
});
|
|
4304
|
+
return r;
|
|
4305
|
+
})
|
|
4306
|
+
);
|
|
4307
|
+
for (const r of results) {
|
|
4308
|
+
const block = contentBlocks.find(
|
|
4309
|
+
(b) => b.type === "tool" && b.id === r.id
|
|
4310
|
+
);
|
|
4311
|
+
if (block?.type === "tool") {
|
|
4312
|
+
block.result = r.result;
|
|
4313
|
+
block.isError = r.isError;
|
|
4314
|
+
block.completedAt = Date.now();
|
|
4315
|
+
if (r.recording) {
|
|
4316
|
+
block.recording = r.recording;
|
|
4317
|
+
}
|
|
4318
|
+
const innerMsgs = subAgentMessages.get(r.id);
|
|
4319
|
+
if (innerMsgs) {
|
|
4320
|
+
attachSubAgentTranscript(block, innerMsgs);
|
|
4321
|
+
}
|
|
4322
|
+
if (captureArtifacts?.includes(block.name) && !r.isError) {
|
|
4323
|
+
try {
|
|
4324
|
+
artifacts[block.name] = JSON.parse(r.result);
|
|
4325
|
+
} catch {
|
|
4326
|
+
}
|
|
4327
|
+
}
|
|
4483
4328
|
}
|
|
4329
|
+
messages.push({
|
|
4330
|
+
role: "user",
|
|
4331
|
+
content: r.result,
|
|
4332
|
+
toolCallId: r.id,
|
|
4333
|
+
isToolError: r.isError
|
|
4334
|
+
});
|
|
4484
4335
|
}
|
|
4485
|
-
} finally {
|
|
4486
|
-
statusWatcher.stop();
|
|
4487
4336
|
}
|
|
4488
4337
|
};
|
|
4489
4338
|
const wrapRun = async () => {
|
|
@@ -9055,6 +8904,145 @@ function parsePartialJson(jsonString) {
|
|
|
9055
8904
|
return parseAny();
|
|
9056
8905
|
}
|
|
9057
8906
|
|
|
8907
|
+
// src/statusWatcher.ts
|
|
8908
|
+
import { createHash as createHash2 } from "crypto";
|
|
8909
|
+
var INTERNAL_PAYLOAD_MARKERS = [
|
|
8910
|
+
"[USER CANCELLED]",
|
|
8911
|
+
"[INTERRUPTED]",
|
|
8912
|
+
"[INTERRUPTED - PARTIAL OUTPUT RETRIEVED]",
|
|
8913
|
+
"<background_results>",
|
|
8914
|
+
"<workspace_status>",
|
|
8915
|
+
"<tool_result"
|
|
8916
|
+
];
|
|
8917
|
+
function sanitizeStatusText(text) {
|
|
8918
|
+
if (!text) {
|
|
8919
|
+
return "";
|
|
8920
|
+
}
|
|
8921
|
+
for (const marker of INTERNAL_PAYLOAD_MARKERS) {
|
|
8922
|
+
if (text.includes(marker)) {
|
|
8923
|
+
return "";
|
|
8924
|
+
}
|
|
8925
|
+
}
|
|
8926
|
+
const truncIdx = text.indexOf("(tool result truncated at");
|
|
8927
|
+
return truncIdx === -1 ? text : text.slice(0, truncIdx);
|
|
8928
|
+
}
|
|
8929
|
+
function startStatusWatcher(config) {
|
|
8930
|
+
const { apiConfig, getContext, onStatus, interval = 5e3, signal } = config;
|
|
8931
|
+
let inflight2 = false;
|
|
8932
|
+
let stopped = false;
|
|
8933
|
+
let pauseCount = 0;
|
|
8934
|
+
let labeledContextHash = null;
|
|
8935
|
+
const url = `${apiConfig.baseUrl}/_internal/v2/agent/remy/generate-status`;
|
|
8936
|
+
let consecutiveFailures = 0;
|
|
8937
|
+
let backoffMs = 0;
|
|
8938
|
+
let nextAllowedAt = 0;
|
|
8939
|
+
const MAX_CONSECUTIVE_FAILURES = 10;
|
|
8940
|
+
const MAX_BACKOFF_MS = 6e4;
|
|
8941
|
+
function recordFailure() {
|
|
8942
|
+
consecutiveFailures++;
|
|
8943
|
+
backoffMs = Math.min(
|
|
8944
|
+
backoffMs === 0 ? interval : backoffMs * 2,
|
|
8945
|
+
MAX_BACKOFF_MS
|
|
8946
|
+
);
|
|
8947
|
+
nextAllowedAt = Date.now() + backoffMs;
|
|
8948
|
+
if (consecutiveFailures >= MAX_CONSECUTIVE_FAILURES && !stopped) {
|
|
8949
|
+
stopped = true;
|
|
8950
|
+
clearInterval(timer);
|
|
8951
|
+
}
|
|
8952
|
+
}
|
|
8953
|
+
async function tick() {
|
|
8954
|
+
if (stopped || signal?.aborted || inflight2 || pauseCount > 0) {
|
|
8955
|
+
return;
|
|
8956
|
+
}
|
|
8957
|
+
if (Date.now() < nextAllowedAt) {
|
|
8958
|
+
return;
|
|
8959
|
+
}
|
|
8960
|
+
inflight2 = true;
|
|
8961
|
+
try {
|
|
8962
|
+
const context = getContext();
|
|
8963
|
+
if (!context) {
|
|
8964
|
+
return;
|
|
8965
|
+
}
|
|
8966
|
+
const contextHash = createHash2("sha1").update(context).digest("hex");
|
|
8967
|
+
const unchanged = contextHash === labeledContextHash;
|
|
8968
|
+
const startedAt = Date.now();
|
|
8969
|
+
const res = await fetch(url, {
|
|
8970
|
+
method: "POST",
|
|
8971
|
+
headers: {
|
|
8972
|
+
"Content-Type": "application/json",
|
|
8973
|
+
Authorization: `Bearer ${apiConfig.apiKey}`,
|
|
8974
|
+
// Also a liveness signal for this box, and the most frequent one there is — this ticks
|
|
8975
|
+
// every few seconds for as long as the agent is working, which is exactly the window in
|
|
8976
|
+
// which the user may have backgrounded the tab and stopped its own keepalive.
|
|
8977
|
+
...sandboxSessionHeader()
|
|
8978
|
+
},
|
|
8979
|
+
body: JSON.stringify({
|
|
8980
|
+
appId: apiConfig.appId,
|
|
8981
|
+
...unchanged ? {} : { context }
|
|
8982
|
+
}),
|
|
8983
|
+
signal
|
|
8984
|
+
});
|
|
8985
|
+
if (stopped) {
|
|
8986
|
+
return;
|
|
8987
|
+
}
|
|
8988
|
+
if (unchanged) {
|
|
8989
|
+
await res.body?.cancel().catch(() => {
|
|
8990
|
+
});
|
|
8991
|
+
return;
|
|
8992
|
+
}
|
|
8993
|
+
if (!res.ok) {
|
|
8994
|
+
recordFailure();
|
|
8995
|
+
return;
|
|
8996
|
+
}
|
|
8997
|
+
const data = await res.json();
|
|
8998
|
+
if (!data.label) {
|
|
8999
|
+
recordFailure();
|
|
9000
|
+
return;
|
|
9001
|
+
}
|
|
9002
|
+
recordUsage({
|
|
9003
|
+
ts: Date.now(),
|
|
9004
|
+
agentName: "statusLabel",
|
|
9005
|
+
modelId: data.modelId,
|
|
9006
|
+
inputTokens: data.usage?.inputTokens ?? 0,
|
|
9007
|
+
outputTokens: data.usage?.outputTokens ?? 0,
|
|
9008
|
+
cost: nanoToDollars(data.cost),
|
|
9009
|
+
billingEvents: data.billingEvents,
|
|
9010
|
+
durationMs: Date.now() - startedAt,
|
|
9011
|
+
toolNames: []
|
|
9012
|
+
});
|
|
9013
|
+
consecutiveFailures = 0;
|
|
9014
|
+
backoffMs = 0;
|
|
9015
|
+
nextAllowedAt = 0;
|
|
9016
|
+
if (pauseCount > 0 || stopped || signal?.aborted) {
|
|
9017
|
+
return;
|
|
9018
|
+
}
|
|
9019
|
+
onStatus(data.label);
|
|
9020
|
+
labeledContextHash = contextHash;
|
|
9021
|
+
} catch {
|
|
9022
|
+
if (!stopped && !signal?.aborted) {
|
|
9023
|
+
recordFailure();
|
|
9024
|
+
}
|
|
9025
|
+
} finally {
|
|
9026
|
+
inflight2 = false;
|
|
9027
|
+
}
|
|
9028
|
+
}
|
|
9029
|
+
const timer = setInterval(tick, interval);
|
|
9030
|
+
tick().catch(() => {
|
|
9031
|
+
});
|
|
9032
|
+
return {
|
|
9033
|
+
stop() {
|
|
9034
|
+
stopped = true;
|
|
9035
|
+
clearInterval(timer);
|
|
9036
|
+
},
|
|
9037
|
+
pause() {
|
|
9038
|
+
pauseCount++;
|
|
9039
|
+
},
|
|
9040
|
+
resume() {
|
|
9041
|
+
pauseCount = Math.max(0, pauseCount - 1);
|
|
9042
|
+
}
|
|
9043
|
+
};
|
|
9044
|
+
}
|
|
9045
|
+
|
|
9058
9046
|
// src/automatedActions/resolve.ts
|
|
9059
9047
|
var NON_ACTION_SENTINELS = /* @__PURE__ */ new Set([
|
|
9060
9048
|
"background_results",
|