Repository: browserbase/stagehand
File: lib/handlers/actHandler.ts (TypeScript)

Code before:
          trace: { value: err.stack, type: "string" },
          observeResult: { value: JSON.stringify(observe), type: "object" },
        },
      });
      try {
        const actCommand = observe.description
          .toLowerCase()
          .startsWith(method.toLowerCase())
          ? observe.description
          : method
            ? `${method} ${observe.description}`
            : observe.description;
        await this.stagehandPage.act(actCommand);
      } catch (err) {
        this.logger({
          category: "action",
          message: "Error performing act from an ObserveResult",
          level: 1,
          auxiliary: {
            error: { value: err.message, type: "string" },
            trace: { value: err.stack, type: "string" },
          },
        });
        return {
          success: false,
          message: `Failed to perform act: ${err.message}`,
          action: observe.description || `ObserveResult action (${method})`,
        };
      }
    }
  }

  private async _recordAction(action: string, result: string): Promise<string> {
    const id = generateId(action);

    this.actions[id] = { result, action };

    return id;
  }

  private async _verifyActionCompletion({
    completed,
    requestId,
    action,
    steps,
    llmClient,
    domSettleTimeoutMs,
  }: {
    completed: boolean;
    requestId: string;
    action: string;

Review comment (suggestion):
let's put this behind an opt-out flag. we are telling people that `act` from `observe` has no LLM inference, so we should adhere to that. i think it's ok to default `true` though (i.e. default this behavior)

Code after:
          message: "Error performing act from an ObserveResult",
          level: 1,
          auxiliary: {
            error: { value: err.message, type: "string" },
            trace: { value: err.stack, type: "string" },
          },
        });
        return {
          success: false,
          message: `Failed to perform act: ${err.message}`,
          action: observe.description || `ObserveResult action (${method})`,
        };
      }
      // We will try to use regular act on a failed ObserveResult-act if selfHeal is true
      this.logger({
        category: "action",
        message:
          "Error performing act from an ObserveResult. Trying again with regular act method",
        level: 1,
        auxiliary: {
          error: { value: err.message, type: "string" },
          trace: { value: err.stack, type: "string" },
          observeResult: { value: JSON.stringify(observe), type: "object" },
        },
      });
      try {
        // Remove redundancy from method-description
        const actCommand = observe.description
          .toLowerCase()
          .startsWith(method.toLowerCase())
          ? observe.description
          : method
            ? `${method} ${observe.description}`
            : observe.description;
        // Call act with the ObserveResult description
        await this.stagehandPage.act(actCommand);
      } catch (err) {
        this.logger({
          category: "action",
          message: "Error performing act from an ObserveResult",
          level: 1,
          auxiliary: {
            error: { value: err.message, type: "string" },
            trace: { value: err.stack, type: "string" },
          },
        });
        return {
          success: false,
          message: `Failed to perform act: ${err.message}`,
          action: observe.description || `ObserveResult action (${method})`,
        };