@mindstudio-ai/remy 0.1.337 → 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 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
- let lastToolResult = "";
4118
- let watchedBlocks = [];
4119
- let watchedToolNames = "";
4120
- const statusWatcher = startStatusWatcher({
4121
- apiConfig,
4122
- getContext: () => {
4123
- const parts = [];
4124
- if (task) {
4125
- parts.push(`Task: ${sanitizeStatusText(task).slice(-200)}`);
4126
- }
4127
- const text = getPartialText(watchedBlocks);
4128
- if (text) {
4129
- parts.push(`Assistant text: ${text.slice(-500)}`);
4130
- }
4131
- if (watchedToolNames) {
4132
- parts.push(`Tool: ${watchedToolNames}`);
4133
- }
4134
- const toolResult = sanitizeStatusText(lastToolResult);
4135
- if (toolResult) {
4136
- parts.push(`Tool result: ${toolResult.slice(-200)}`);
4137
- }
4138
- return parts.join("\n");
4139
- },
4140
- onStatus: (label) => emit({ type: "status", message: label }),
4141
- signal
4142
- });
4143
- try {
4144
- while (true) {
4145
- turns++;
4146
- if (signal?.aborted) {
4147
- return abortResult([]);
4148
- }
4149
- const iterStart = Date.now();
4150
- const contentBlocks = [];
4151
- let thinkingStartedAt = 0;
4152
- let lastThinkingRelatedStartedAt;
4153
- let stopReason = "end_turn";
4154
- let lastUsage;
4155
- let lastProviderMetadata;
4156
- let lastModelId;
4157
- watchedBlocks = contentBlocks;
4158
- watchedToolNames = "";
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: "redacted_thinking",
4218
- data: event.data,
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
- case "tool_use":
4226
- contentBlocks.push({
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
- } catch (err) {
4278
- if (!signal?.aborted) {
4279
- throw err;
4280
- }
4281
- }
4282
- if (signal?.aborted) {
4283
- statusWatcher.stop();
4284
- return abortResult(contentBlocks);
4285
- }
4286
- messages.push({
4287
- role: "assistant",
4288
- content: contentBlocks,
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
- if (objection && !validationRetried && !signal?.aborted) {
4311
- validationRetried = true;
4312
- log8.info("Result rejected by validator, retrying once", {
4313
- requestId,
4314
- parentToolId,
4315
- agentName,
4316
- objection: objection.slice(0, 200)
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: "status",
4320
- message: "Response failed validation, revising"
4091
+ type: "tool_start",
4092
+ id: event.id,
4093
+ name: event.name,
4094
+ input: event.input
4321
4095
  });
4322
- messages.push({ role: "user", content: objection });
4323
- continue;
4324
- }
4325
- if (objection) {
4326
- text = `${text}
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
- log8.info("Tools executing", {
4340
- requestId,
4341
- parentToolId,
4342
- count: toolCalls.length,
4343
- tools: toolCalls.map((tc) => tc.name)
4344
- });
4345
- watchedToolNames = toolCalls.map((tc) => tc.name).join(", ");
4346
- const results = await Promise.all(
4347
- toolCalls.map(async (tc) => {
4348
- if (signal?.aborted) {
4349
- return {
4350
- id: tc.id,
4351
- result: cancelledToolResult(signal),
4352
- isError: true
4353
- };
4354
- }
4355
- let settle;
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
- name: tc.name,
4414
- input: tc.input,
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
- toolRegistry?.register(entry);
4431
- const toolStart = Date.now();
4432
- run2(tc.input);
4433
- const r = await resultPromise;
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
- name: tc.name,
4447
- result: r.result,
4448
- isError: r.isError,
4449
- ...r.recording ? { recording: r.recording } : {}
4212
+ result,
4213
+ isError,
4214
+ ...recording ? { recording } : {}
4450
4215
  });
4451
- return r;
4452
- })
4453
- );
4454
- lastToolResult = results.at(-1)?.result ?? "";
4455
- for (const r of results) {
4456
- const block = contentBlocks.find(
4457
- (b) => b.type === "tool" && b.id === r.id
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
- if (captureArtifacts?.includes(block.name) && !r.isError) {
4471
- try {
4472
- artifacts[block.name] = JSON.parse(r.result);
4473
- } catch {
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
- messages.push({
4478
- role: "user",
4479
- content: r.result,
4480
- toolCallId: r.id,
4481
- isToolError: r.isError
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",