@runtypelabs/sdk 1.8.2 → 1.9.1

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/index.cjs CHANGED
@@ -3084,7 +3084,9 @@ var deployPhase = {
3084
3084
  " 4. If the deploy fails, read the error output, fix the code, and call deploy_sandbox again.",
3085
3085
  " 5. The sandbox is persistent \u2014 subsequent calls reuse the same sandbox.",
3086
3086
  " 6. When the deploy succeeds and the preview URL is live, tell the user and end with TASK_COMPLETE.",
3087
- " 7. For apps with HTML frontends, use the `files` parameter to write HTML/CSS/JS to separate files and serve them with express.static, rather than embedding HTML in template literals."
3087
+ " 7. For apps with HTML frontends, use the `files` parameter to write HTML/CSS/JS to separate files and serve them with express.static, rather than embedding HTML in template literals.",
3088
+ " 8. If the prompt asks for a multi-route app or names concrete output paths (for example `public/v1/index.html`), mirror that structure in the `files` payload.",
3089
+ " 9. If the prompt asks you to verify specific routes after deploy, check those paths against the preview URL before TASK_COMPLETE and iterate until they work."
3088
3090
  ].join("\n");
3089
3091
  },
3090
3092
  buildToolGuidance(_state) {
@@ -3092,6 +3094,7 @@ var deployPhase = {
3092
3094
  "Your primary tool is deploy_sandbox. Call it with code, packageJson, language, and port.",
3093
3095
  "Do NOT use write_file, read_file, search_repo, glob_files, tree_directory, or list_directory \u2014 you are deploying to a sandbox, not editing local files.",
3094
3096
  "You may use run_sandbox_code for quick one-off script execution if needed.",
3097
+ "For static or multi-page sites, use `files` to create the requested folder structure and have the server expose those routes.",
3095
3098
  "When deploy_sandbox returns successfully with a previewUrl, tell the user the URL and end with TASK_COMPLETE."
3096
3099
  ];
3097
3100
  },
@@ -3141,34 +3144,7 @@ var deployPhase = {
3141
3144
  return void 0;
3142
3145
  }
3143
3146
  };
3144
- function classifyVariant2(message) {
3145
- const lower = message.toLowerCase();
3146
- const deployPatterns = [
3147
- /\bdeploy\b/,
3148
- /\bsandbox\b/,
3149
- /\bpreview\s*url\b/,
3150
- /\blive\s*preview\b/,
3151
- /\bhost\b.*\b(?:app|server|api|site)\b/,
3152
- /\b(?:app|server|api|site)\b.*\bhost\b/,
3153
- /\brun\b.*\b(?:server|web\s*app)\b/,
3154
- /\blaunch\b.*\b(?:app|server|api|site)\b/,
3155
- /\bstart\b.*\b(?:server|web\s*app)\b/
3156
- ];
3157
- if (deployPatterns.some((p) => p.test(lower))) {
3158
- return "deploy";
3159
- }
3160
- const webAppPatterns = [
3161
- /\bbuild\b.*\b(?:web\s*app|website|api|server|express|hono|fastify)\b/,
3162
- /\bcreate\b.*\b(?:web\s*app|website|api|server|express|hono|fastify)\b/,
3163
- /\bmake\b.*\b(?:web\s*app|website|api|server|express|hono|fastify)\b/
3164
- ];
3165
- const repoPatterns = [
3166
- /\b(?:file|repo|repository|codebase|project|directory|folder)\b/,
3167
- /\b(?:edit|modify|update|fix|refactor|change)\b/
3168
- ];
3169
- if (webAppPatterns.some((p) => p.test(lower)) && !repoPatterns.some((p) => p.test(lower))) {
3170
- return "deploy";
3171
- }
3147
+ function classifyVariant2(_message) {
3172
3148
  return "deploy";
3173
3149
  }
3174
3150
  var deployWorkflow = {
@@ -4280,6 +4256,12 @@ function dispatchAgentEvent(event, callbacks) {
4280
4256
  case "agent_tool_delta":
4281
4257
  callbacks.onToolDelta?.(typedData);
4282
4258
  break;
4259
+ case "agent_tool_input_delta":
4260
+ callbacks.onToolInputDelta?.(typedData);
4261
+ break;
4262
+ case "agent_tool_input_complete":
4263
+ callbacks.onToolInputComplete?.(typedData);
4264
+ break;
4283
4265
  case "agent_tool_complete":
4284
4266
  callbacks.onToolComplete?.(typedData);
4285
4267
  break;
@@ -4663,6 +4645,15 @@ var _AgentsEndpoint = class _AgentsEndpoint {
4663
4645
  String(current).slice(0, 200)
4664
4646
  );
4665
4647
  }
4648
+ const localExecutionStartedAt = (/* @__PURE__ */ new Date()).toISOString();
4649
+ const localExecutionStartedAtMs = Date.now();
4650
+ callbacks?.onLocalToolExecutionStart?.({
4651
+ executionId,
4652
+ toolCallId: toolId,
4653
+ toolName,
4654
+ parameters: parsedParams,
4655
+ startedAt: localExecutionStartedAt
4656
+ });
4666
4657
  let toolResult;
4667
4658
  try {
4668
4659
  toolResult = await toolDef.execute(parsedParams);
@@ -4672,20 +4663,24 @@ var _AgentsEndpoint = class _AgentsEndpoint {
4672
4663
  toolMessages.push({
4673
4664
  role: "assistant",
4674
4665
  content: "",
4675
- toolCalls: [{
4676
- toolCallId: toolId,
4677
- toolName,
4678
- args: parsedParams
4679
- }]
4666
+ toolCalls: [
4667
+ {
4668
+ toolCallId: toolId,
4669
+ toolName,
4670
+ args: parsedParams
4671
+ }
4672
+ ]
4680
4673
  });
4681
4674
  toolMessages.push({
4682
4675
  role: "tool",
4683
4676
  content: "",
4684
- toolResults: [{
4685
- toolCallId: toolId,
4686
- toolName,
4687
- result: toolResult
4688
- }]
4677
+ toolResults: [
4678
+ {
4679
+ toolCallId: toolId,
4680
+ toolName,
4681
+ result: toolResult
4682
+ }
4683
+ ]
4689
4684
  });
4690
4685
  pauseCount += 1;
4691
4686
  const toolNameCount = (toolNameCounts[toolName] || 0) + 1;
@@ -4717,6 +4712,16 @@ var _AgentsEndpoint = class _AgentsEndpoint {
4717
4712
  recentActionKeys
4718
4713
  });
4719
4714
  if (forcedCompleteEvent) {
4715
+ callbacks?.onLocalToolExecutionComplete?.({
4716
+ executionId,
4717
+ toolCallId: toolId,
4718
+ toolName,
4719
+ parameters: parsedParams,
4720
+ result: toolResult,
4721
+ success: true,
4722
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
4723
+ durationMs: Date.now() - localExecutionStartedAtMs
4724
+ });
4720
4725
  if (!forcedCompleteEvent.finalOutput && accumulatedOutput) {
4721
4726
  forcedCompleteEvent.finalOutput = accumulatedOutput;
4722
4727
  }
@@ -4736,6 +4741,16 @@ var _AgentsEndpoint = class _AgentsEndpoint {
4736
4741
  const error = await resumeResponse.json().catch(() => ({ error: "Unknown error" }));
4737
4742
  throw new Error(error.error || `HTTP ${resumeResponse.status}`);
4738
4743
  }
4744
+ callbacks?.onLocalToolExecutionComplete?.({
4745
+ executionId,
4746
+ toolCallId: toolId,
4747
+ toolName,
4748
+ parameters: parsedParams,
4749
+ result: toolResult,
4750
+ success: true,
4751
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
4752
+ durationMs: Date.now() - localExecutionStartedAtMs
4753
+ });
4739
4754
  currentBody = resumeResponse.body;
4740
4755
  continue;
4741
4756
  }
@@ -4958,7 +4973,10 @@ var _AgentsEndpoint = class _AgentsEndpoint {
4958
4973
  }
4959
4974
  const currentPhase = workflow.phases.find((p) => p.name === state.workflowPhase);
4960
4975
  if (currentPhase?.canAcceptCompletion) {
4961
- return currentPhase.canAcceptCompletion(state, sessionTrace);
4976
+ return currentPhase.canAcceptCompletion(
4977
+ state,
4978
+ sessionTrace
4979
+ );
4962
4980
  }
4963
4981
  return true;
4964
4982
  }
@@ -5030,7 +5048,10 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5030
5048
  compactOneResult(tr, taskName, mode) {
5031
5049
  if (typeof tr.result === "string" && tr.result.startsWith("[")) return tr;
5032
5050
  if (mode === "hot-tail") {
5033
- return { ...tr, result: this.offloadToolResult(taskName, tr.toolCallId, tr.toolName, tr.result) };
5051
+ return {
5052
+ ...tr,
5053
+ result: this.offloadToolResult(taskName, tr.toolCallId, tr.toolName, tr.result)
5054
+ };
5034
5055
  }
5035
5056
  return { ...tr, result: `[Output from ${tr.toolName} masked \u2014 re-run the tool if needed]` };
5036
5057
  }
@@ -5129,7 +5150,9 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5129
5150
  }
5130
5151
  };
5131
5152
  const baseDir = sourcePath ? this.dirnameOfCandidatePath(sourcePath) : "";
5132
- for (const match of text.matchAll(/(?:href|src)=["']([^"']+\.(?:html|tsx|ts|jsx|js|md|json))["']/gi)) {
5153
+ for (const match of text.matchAll(
5154
+ /(?:href|src)=["']([^"']+\.(?:html|tsx|ts|jsx|js|md|json))["']/gi
5155
+ )) {
5133
5156
  const target = match[1] || "";
5134
5157
  const resolved = baseDir ? this.joinCandidatePath(baseDir, target) : target;
5135
5158
  add(resolved, `linked from ${sourcePath || "discovery result"} via ${target}`);
@@ -5169,7 +5192,9 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5169
5192
  if (!bootstrapContext) return void 0;
5170
5193
  const candidates = this.parseSearchRepoResultForCandidates(bootstrapContext);
5171
5194
  if (candidates.length === 0) return void 0;
5172
- return candidates.sort((a, b) => this.scoreCandidatePath(b.path) - this.scoreCandidatePath(a.path))[0];
5195
+ return candidates.sort(
5196
+ (a, b) => this.scoreCandidatePath(b.path) - this.scoreCandidatePath(a.path)
5197
+ )[0];
5173
5198
  }
5174
5199
  sanitizeResumeState(resumeState, taskName) {
5175
5200
  if (!resumeState) return void 0;
@@ -5276,10 +5301,17 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5276
5301
  isArtifactPath: this.isMarathonArtifactPath.bind(this),
5277
5302
  isDiscoveryTool: this.isDiscoveryToolName.bind(this)
5278
5303
  };
5279
- const blockedMessage = currentPhase.interceptToolCall(toolName, args, ctx);
5304
+ const blockedMessage = currentPhase.interceptToolCall(
5305
+ toolName,
5306
+ args,
5307
+ ctx
5308
+ );
5280
5309
  if (blockedMessage) {
5281
5310
  if (isWriteLikeTool) trace.attemptedWrite = true;
5282
- this.pushToolTraceEntry(trace, `${toolName}${pathArg}${queryArg}${patternArg} -> ${blockedMessage}`);
5311
+ this.pushToolTraceEntry(
5312
+ trace,
5313
+ `${toolName}${pathArg}${queryArg}${patternArg} -> ${blockedMessage}`
5314
+ );
5283
5315
  return blockedMessage;
5284
5316
  }
5285
5317
  }
@@ -5336,7 +5368,10 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5336
5368
  verificationResult.error || verificationResult.output
5337
5369
  ].filter(Boolean).join(" | ").slice(0, 240) : this.summarizeTextBlockForTrace(result);
5338
5370
  const resultSuffix = summarizedResult ? ` -> ${summarizedResult}` : "";
5339
- this.pushToolTraceEntry(trace, `${toolName}${pathArg}${queryArg}${patternArg}${resultSuffix}`);
5371
+ this.pushToolTraceEntry(
5372
+ trace,
5373
+ `${toolName}${pathArg}${queryArg}${patternArg}${resultSuffix}`
5374
+ );
5340
5375
  const textResult = typeof result === "string" ? result : "";
5341
5376
  if (toolName === "read_file" && normalizedPathArg && normalizedBestCandidatePath && normalizedPathArg === normalizedBestCandidatePath && (trace.bestCandidateWritten || state.bestCandidateNeedsVerification)) {
5342
5377
  trace.bestCandidateVerified = true;
@@ -5427,7 +5462,9 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5427
5462
  return [
5428
5463
  "Session working memory:",
5429
5464
  ...flags.length > 0 ? [`- ${flags.join("; ")}`] : [],
5430
- ...trace.bestCandidatePath ? [`- best candidate: ${trace.bestCandidatePath}${trace.bestCandidateReason ? ` (${trace.bestCandidateReason})` : ""}`] : [],
5465
+ ...trace.bestCandidatePath ? [
5466
+ `- best candidate: ${trace.bestCandidatePath}${trace.bestCandidateReason ? ` (${trace.bestCandidateReason})` : ""}`
5467
+ ] : [],
5431
5468
  ...lines
5432
5469
  ].join("\n").slice(0, 1200);
5433
5470
  }
@@ -5501,12 +5538,7 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5501
5538
  }
5502
5539
  };
5503
5540
  const lowerMessage = message.toLowerCase();
5504
- const phraseHints = [
5505
- "agent editor",
5506
- "theme.html",
5507
- "/theme.html",
5508
- "style it visually"
5509
- ];
5541
+ const phraseHints = ["agent editor", "theme.html", "/theme.html", "style it visually"];
5510
5542
  for (const hint of phraseHints) {
5511
5543
  if (lowerMessage.includes(hint.toLowerCase())) push(hint);
5512
5544
  }
@@ -5533,7 +5565,9 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5533
5565
  for (const match of message.matchAll(/\b([a-z0-9]+(?:\s+[a-z0-9]+){1,2})\b/gi)) {
5534
5566
  const phrase = (match[1] || "").toLowerCase();
5535
5567
  const words = phrase.split(" ");
5536
- if (words.some((word) => ["editor", "page", "screen", "view", "route", "component"].includes(word))) {
5568
+ if (words.some(
5569
+ (word) => ["editor", "page", "screen", "view", "route", "component"].includes(word)
5570
+ )) {
5537
5571
  push(match[1] || "");
5538
5572
  }
5539
5573
  }
@@ -5563,7 +5597,11 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5563
5597
  }
5564
5598
  if (globTool && /\./.test(query)) {
5565
5599
  try {
5566
- const result = await globTool.execute({ pattern: `**/${query}`, path: ".", maxResults: 5 });
5600
+ const result = await globTool.execute({
5601
+ pattern: `**/${query}`,
5602
+ path: ".",
5603
+ maxResults: 5
5604
+ });
5567
5605
  const summary = this.summarizeTextBlockForTrace(result, 3);
5568
5606
  if (summary && !summary.startsWith("No files matched")) {
5569
5607
  lines.push(`glob_files "**/${query}": ${summary}`);
@@ -5664,7 +5702,9 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5664
5702
  state.isCreationTask || state.workflowVariant === "external"
5665
5703
  );
5666
5704
  }
5667
- const bootstrapCandidate = this.extractBestCandidateFromBootstrapContext(state.bootstrapContext);
5705
+ const bootstrapCandidate = this.extractBestCandidateFromBootstrapContext(
5706
+ state.bootstrapContext
5707
+ );
5668
5708
  if (bootstrapCandidate) {
5669
5709
  state.bestCandidatePath = bootstrapCandidate.path;
5670
5710
  state.bestCandidateReason = bootstrapCandidate.reason;
@@ -5673,7 +5713,12 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5673
5713
  }
5674
5714
  for (let session = 0; session < maxSessions; session++) {
5675
5715
  const sessionTrace = this.createEmptyToolTrace();
5676
- const sessionLocalTools = this.wrapLocalToolsForTrace(options.localTools, sessionTrace, state, workflow);
5716
+ const sessionLocalTools = this.wrapLocalToolsForTrace(
5717
+ options.localTools,
5718
+ sessionTrace,
5719
+ state,
5720
+ workflow
5721
+ );
5677
5722
  const sessionCallbacks = this.createTraceCallbacks(options.streamCallbacks, sessionTrace);
5678
5723
  const continuationContext = session === 0 && options.previousMessages ? {
5679
5724
  previousMessages: options.previousMessages,
@@ -5704,11 +5749,7 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5704
5749
  onContextNotice: options.onContextNotice
5705
5750
  }
5706
5751
  );
5707
- const {
5708
- messages,
5709
- requestContextManagement,
5710
- pendingNativeCompactionEvent
5711
- } = preparedSession;
5752
+ const { messages, requestContextManagement, pendingNativeCompactionEvent } = preparedSession;
5712
5753
  let sessionResult;
5713
5754
  const sessionData = {
5714
5755
  messages,
@@ -5831,7 +5872,10 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5831
5872
  ).slice(-20);
5832
5873
  }
5833
5874
  if (sessionTrace.actionKeys.length > 0) {
5834
- state.recentActionKeys = [...state.recentActionKeys || [], ...sessionTrace.actionKeys].slice(-20);
5875
+ state.recentActionKeys = [
5876
+ ...state.recentActionKeys || [],
5877
+ ...sessionTrace.actionKeys
5878
+ ].slice(-20);
5835
5879
  }
5836
5880
  if (sessionTrace.planWritten) {
5837
5881
  state.planWritten = true;
@@ -5860,7 +5904,11 @@ var _AgentsEndpoint = class _AgentsEndpoint {
5860
5904
  const latestSession = state.sessions[state.sessions.length - 1];
5861
5905
  if (latestSession) {
5862
5906
  latestSession.outputPreview = [phaseTransitionSummary, "", latestSession.outputPreview].join("\n").slice(0, 300);
5863
- latestSession.toolTraceSummary = [phaseTransitionSummary, "", latestSession.toolTraceSummary || ""].join("\n").trim().slice(0, 1200);
5907
+ latestSession.toolTraceSummary = [
5908
+ phaseTransitionSummary,
5909
+ "",
5910
+ latestSession.toolTraceSummary || ""
5911
+ ].join("\n").trim().slice(0, 1200);
5864
5912
  }
5865
5913
  }
5866
5914
  if (!state.messages) state.messages = [];
@@ -6097,7 +6145,9 @@ var _AgentsEndpoint = class _AgentsEndpoint {
6097
6145
  details.builtinToolSchemas
6098
6146
  );
6099
6147
  const reservedOutputTokens = this.resolveReservedOutputTokens(details.contextLimitTokens);
6100
- const effectiveInputBudgetTokens = this.resolveEffectiveInputBudgetTokens(details.contextLimitTokens);
6148
+ const effectiveInputBudgetTokens = this.resolveEffectiveInputBudgetTokens(
6149
+ details.contextLimitTokens
6150
+ );
6101
6151
  const summaryTokens = details.summaryText ? this.estimateTextTokens(
6102
6152
  `${_AgentsEndpoint.AUTO_COMPACT_SUMMARY_PREFIX}
6103
6153
 
@@ -6218,7 +6268,9 @@ Do NOT redo any of the above work.`
6218
6268
  "",
6219
6269
  "Changed Files / Candidate Paths",
6220
6270
  ...candidatePaths.length > 0 ? candidatePaths.map((candidatePath) => `- ${candidatePath}`) : ["- No candidate paths recorded yet."],
6221
- ...state.planPath ? [`- ${state.workflowVariant === "external" ? "Report path" : "Plan path"}: ${state.planPath}`] : [],
6271
+ ...state.planPath ? [
6272
+ `- ${state.workflowVariant === "external" ? "Report path" : "Plan path"}: ${state.planPath}`
6273
+ ] : [],
6222
6274
  ...state.planWritten ? ["- Planning artifact has been written."] : [],
6223
6275
  ...state.bestCandidateReason ? [`- Best candidate rationale: ${state.bestCandidateReason}`] : [],
6224
6276
  "",
@@ -6239,6 +6291,79 @@ Do NOT redo any of the above work.`
6239
6291
  (state.lastOutput || "").slice(0, 1800) || "- No final output recorded yet."
6240
6292
  ].join("\n");
6241
6293
  }
6294
+ isAssistantToolCallMessage(message) {
6295
+ return Boolean(
6296
+ message?.role === "assistant" && message.toolCalls && message.toolCalls.length > 0
6297
+ );
6298
+ }
6299
+ isToolResultMessage(message) {
6300
+ return Boolean(
6301
+ message?.role === "tool" && message.toolResults && message.toolResults.length > 0
6302
+ );
6303
+ }
6304
+ /**
6305
+ * Replay only complete adjacent tool-call/result pairs so provider validation
6306
+ * never sees an orphaned tool result after history trimming or resume.
6307
+ */
6308
+ sanitizeReplayHistoryMessages(messages) {
6309
+ const sanitized = [];
6310
+ for (let index = 0; index < messages.length; index++) {
6311
+ const message = messages[index];
6312
+ if (this.isAssistantToolCallMessage(message)) {
6313
+ const nextMessage = messages[index + 1];
6314
+ if (!this.isToolResultMessage(nextMessage)) {
6315
+ continue;
6316
+ }
6317
+ const matchedResultIds = new Set(
6318
+ nextMessage.toolResults.filter(
6319
+ (toolResult) => message.toolCalls.some((toolCall) => toolCall.toolCallId === toolResult.toolCallId)
6320
+ ).map((toolResult) => toolResult.toolCallId)
6321
+ );
6322
+ if (matchedResultIds.size === 0) {
6323
+ continue;
6324
+ }
6325
+ const matchedToolCalls = message.toolCalls.filter(
6326
+ (toolCall) => matchedResultIds.has(toolCall.toolCallId)
6327
+ );
6328
+ const matchedToolResults = nextMessage.toolResults.filter(
6329
+ (toolResult) => matchedResultIds.has(toolResult.toolCallId)
6330
+ );
6331
+ sanitized.push(
6332
+ matchedToolCalls.length === message.toolCalls.length ? message : { ...message, toolCalls: matchedToolCalls }
6333
+ );
6334
+ sanitized.push(
6335
+ matchedToolResults.length === nextMessage.toolResults.length ? nextMessage : { ...nextMessage, toolResults: matchedToolResults }
6336
+ );
6337
+ index += 1;
6338
+ continue;
6339
+ }
6340
+ if (this.isToolResultMessage(message)) {
6341
+ continue;
6342
+ }
6343
+ sanitized.push(message);
6344
+ }
6345
+ return sanitized;
6346
+ }
6347
+ /**
6348
+ * Keep replay trimming on a pair boundary. If the trim cut would start on a
6349
+ * tool-result message, slide back to include the matching assistant tool call.
6350
+ */
6351
+ trimReplayHistoryMessages(messages, maxMessages) {
6352
+ if (messages.length <= maxMessages) {
6353
+ return {
6354
+ historyMessages: messages,
6355
+ trimmedCount: 0
6356
+ };
6357
+ }
6358
+ let startIndex = messages.length - maxMessages;
6359
+ while (startIndex > 0 && messages[startIndex]?.role === "tool") {
6360
+ startIndex -= 1;
6361
+ }
6362
+ return {
6363
+ historyMessages: messages.slice(startIndex),
6364
+ trimmedCount: startIndex
6365
+ };
6366
+ }
6242
6367
  /**
6243
6368
  * Build messages for a session, injecting progress context for continuation sessions.
6244
6369
  * Optionally accepts continuation context for marathon resume scenarios.
@@ -6322,7 +6447,9 @@ Do NOT redo any of the above work.`
6322
6447
  "Use these tools to inspect the existing repository and make real file edits \u2014 not just code in your response."
6323
6448
  ],
6324
6449
  ...toolGuidanceLines,
6325
- ...isDeployWorkflow ? [] : isExternalTask2 ? ["Use write_file only if you want to save the final deliverable into the workspace."] : ["Always use write_file to save your output so the user can run it immediately."]
6450
+ ...isDeployWorkflow ? [] : isExternalTask2 ? [
6451
+ "Use write_file only if you want to save the final deliverable into the workspace."
6452
+ ] : ["Always use write_file to save your output so the user can run it immediately."]
6326
6453
  ].join("\n") : "";
6327
6454
  const builtinToolNames = builtinToolIds?.map((id) => id.replace(/^builtin:/, ""));
6328
6455
  const builtinToolsBlock = builtinToolNames?.length ? [
@@ -6341,6 +6468,9 @@ Do NOT redo any of the above work.`
6341
6468
  const candidateBlock = wf.buildCandidateBlock?.(state) ?? "";
6342
6469
  const multiSessionInstruction = `This is a multi-session task (session ${sessionIndex + 1}/${maxSessions}). When you have fully completed the task, end your response with TASK_COMPLETE on its own line.`;
6343
6470
  if (continuationContext && sessionIndex === 0) {
6471
+ const replayHistoryMessages = this.sanitizeReplayHistoryMessages(
6472
+ continuationContext.previousMessages
6473
+ );
6344
6474
  const defaultContinueMessage = "Continue the task. Review your prior work above and proceed with any remaining work. If everything is already complete, respond with TASK_COMPLETE.";
6345
6475
  const userMessage = continuationContext.newUserMessage || defaultContinueMessage;
6346
6476
  const userContent = [
@@ -6353,7 +6483,7 @@ Do NOT redo any of the above work.`
6353
6483
  multiSessionInstruction
6354
6484
  ].join("\n");
6355
6485
  const fullHistoryMessages = [
6356
- ...continuationContext.previousMessages,
6486
+ ...replayHistoryMessages,
6357
6487
  {
6358
6488
  role: "system",
6359
6489
  content: "IMPORTANT: You are continuing a previously completed task. The conversation above shows your prior work. Do NOT redo any of it. Build on what was already accomplished. If there is nothing new to do, respond with TASK_COMPLETE."
@@ -6365,7 +6495,7 @@ Do NOT redo any of the above work.`
6365
6495
  ];
6366
6496
  const summaryText = this.generateCompactSummary(state, compactInstructions);
6367
6497
  const breakdown = this.buildContextBudgetBreakdown({
6368
- historyMessages: continuationContext.previousMessages,
6498
+ historyMessages: replayHistoryMessages,
6369
6499
  currentTurnContent: userContent,
6370
6500
  localTools: compactionOptions?.localTools,
6371
6501
  builtinToolSchemas: compactionOptions?.builtinToolSchemas || [],
@@ -6428,7 +6558,15 @@ Do NOT redo any of the above work.`
6428
6558
  };
6429
6559
  }
6430
6560
  if (sessionIndex === 0) {
6431
- const content2 = [originalMessage, phaseBlock, toolsBlock, bootstrapBlock, candidateBlock, "", multiSessionInstruction].join("\n");
6561
+ const content2 = [
6562
+ originalMessage,
6563
+ phaseBlock,
6564
+ toolsBlock,
6565
+ bootstrapBlock,
6566
+ candidateBlock,
6567
+ "",
6568
+ multiSessionInstruction
6569
+ ].join("\n");
6432
6570
  return {
6433
6571
  messages: [{ role: "user", content: content2 }],
6434
6572
  requestContextManagement
@@ -6455,16 +6593,19 @@ Do NOT redo any of the above work.`
6455
6593
  "Do not redo previous work. If the task is already complete, respond with TASK_COMPLETE."
6456
6594
  ].join("\n");
6457
6595
  const MAX_HISTORY_MESSAGES = 60;
6458
- let historyMessages = state.messages;
6596
+ let historyMessages = this.sanitizeReplayHistoryMessages(state.messages);
6459
6597
  if (historyMessages.length > MAX_HISTORY_MESSAGES) {
6460
- const trimmedCount = historyMessages.length - MAX_HISTORY_MESSAGES;
6461
- historyMessages = [
6462
- {
6463
- role: "system",
6464
- content: `[${trimmedCount} earlier messages trimmed to stay within context limits. Original task: ${(state.originalMessage || originalMessage).slice(0, 500)}]`
6465
- },
6466
- ...historyMessages.slice(-MAX_HISTORY_MESSAGES)
6467
- ];
6598
+ const trimmedHistory = this.trimReplayHistoryMessages(historyMessages, MAX_HISTORY_MESSAGES);
6599
+ historyMessages = trimmedHistory.historyMessages;
6600
+ if (trimmedHistory.trimmedCount > 0) {
6601
+ historyMessages = [
6602
+ {
6603
+ role: "system",
6604
+ content: `[${trimmedHistory.trimmedCount} earlier messages trimmed to stay within context limits. Original task: ${(state.originalMessage || originalMessage).slice(0, 500)}]`
6605
+ },
6606
+ ...historyMessages
6607
+ ];
6608
+ }
6468
6609
  }
6469
6610
  const summaryText = this.generateCompactSummary(state, compactInstructions);
6470
6611
  const breakdown = this.buildContextBudgetBreakdown({
@@ -6476,10 +6617,7 @@ Do NOT redo any of the above work.`
6476
6617
  contextLimitTokens: compactionOptions?.contextLimitTokens
6477
6618
  });
6478
6619
  await maybeEmitToolDefinitionWarning(breakdown);
6479
- const messages = [
6480
- ...historyMessages,
6481
- { role: "user", content: continuationContent }
6482
- ];
6620
+ const messages = [...historyMessages, { role: "user", content: continuationContent }];
6483
6621
  if (resolvedStrategy === "summary_fallback" && typeof compactionOptions?.autoCompactTokenThreshold === "number" && compactionOptions.autoCompactTokenThreshold > 0 && breakdown.estimatedInputTokens >= compactionOptions.autoCompactTokenThreshold) {
6484
6622
  return {
6485
6623
  messages: await this.buildCompactHistoryMessagesWithLifecycle(
@@ -6726,6 +6864,42 @@ var FlowBuilder = class {
6726
6864
  );
6727
6865
  return this;
6728
6866
  }
6867
+ /**
6868
+ * Add a crawl step
6869
+ */
6870
+ crawl(config) {
6871
+ this.addStep(
6872
+ "crawl",
6873
+ config.name,
6874
+ {
6875
+ url: config.url,
6876
+ limit: config.limit,
6877
+ depth: config.depth,
6878
+ source: config.source,
6879
+ formats: config.formats,
6880
+ render: config.render,
6881
+ maxAge: config.maxAge,
6882
+ modifiedSince: config.modifiedSince,
6883
+ options: config.options,
6884
+ authenticate: config.authenticate,
6885
+ cookies: config.cookies,
6886
+ setExtraHTTPHeaders: config.setExtraHTTPHeaders,
6887
+ gotoOptions: config.gotoOptions,
6888
+ waitForSelector: config.waitForSelector,
6889
+ rejectResourceTypes: config.rejectResourceTypes,
6890
+ rejectRequestPattern: config.rejectRequestPattern,
6891
+ userAgent: config.userAgent,
6892
+ jsonOptions: config.jsonOptions,
6893
+ outputVariable: config.outputVariable,
6894
+ errorHandling: config.errorHandling,
6895
+ streamOutput: config.streamOutput,
6896
+ pollIntervalMs: config.pollIntervalMs,
6897
+ completionTimeoutMs: config.completionTimeoutMs
6898
+ },
6899
+ config.enabled
6900
+ );
6901
+ return this;
6902
+ }
6729
6903
  /**
6730
6904
  * Add a fetch URL step
6731
6905
  */
@@ -7068,7 +7242,7 @@ var ClientFlowBuilder = class extends FlowBuilder {
7068
7242
  this.boundClient = client;
7069
7243
  this.createFlow({ name });
7070
7244
  }
7071
- async run(arg1, arg2, arg3, arg4) {
7245
+ async run(arg1, arg2, arg3, _arg4) {
7072
7246
  const config = this.build();
7073
7247
  let runOptions;
7074
7248
  let runCallbacks;