( ctx context.Context, call fantasy.ToolCall, )
| 240 | } |
| 241 | |
| 242 | func (t *computerUseTool) runOpenAIComputerUse( |
| 243 | ctx context.Context, |
| 244 | call fantasy.ToolCall, |
| 245 | ) (fantasy.ToolResponse, error) { |
| 246 | input, err := openaicomputeruse.ParseInput(call.Input) |
| 247 | if err != nil { |
| 248 | return fantasy.NewTextErrorResponse( |
| 249 | fmt.Sprintf("invalid computer use input: %v", err), |
| 250 | ), nil |
| 251 | } |
| 252 | conn, err := t.getWorkspaceConn(ctx) |
| 253 | if err != nil { |
| 254 | return fantasy.NewTextErrorResponse( |
| 255 | fmt.Sprintf("failed to connect to workspace: %v", err), |
| 256 | ), nil |
| 257 | } |
| 258 | |
| 259 | declaredWidth, declaredHeight := t.declaredActionDimensions() |
| 260 | actions, err := openaicomputeruse.DesktopActions( |
| 261 | input, |
| 262 | declaredWidth, |
| 263 | declaredHeight, |
| 264 | ) |
| 265 | if err != nil { |
| 266 | return fantasy.NewTextErrorResponse(err.Error()), nil |
| 267 | } |
| 268 | for _, action := range actions { |
| 269 | if action.WaitDurationMillis > 0 { |
| 270 | t.wait(ctx, action.WaitDurationMillis) |
| 271 | continue |
| 272 | } |
| 273 | if resp, done := t.executeDesktopAction(ctx, conn, action.Action); done { |
| 274 | if action.ReleaseMouseOnFailure { |
| 275 | _, err := conn.ExecuteDesktopAction( |
| 276 | ctx, |
| 277 | t.desktopAction("left_mouse_up", declaredWidth, declaredHeight), |
| 278 | ) |
| 279 | if err != nil { |
| 280 | t.logger.Warn(ctx, "failed to release mouse after OpenAI drag error", |
| 281 | slog.Error(err), |
| 282 | ) |
| 283 | } |
| 284 | } |
| 285 | t.releaseOpenAIModifierKeys(ctx, conn, action.ReleaseKeysOnFailure) |
| 286 | return resp, nil |
| 287 | } |
| 288 | } |
| 289 | return t.captureSharedScreenshot(ctx, conn, declaredWidth, declaredHeight) |
| 290 | } |
| 291 | |
| 292 | func (t *computerUseTool) releaseOpenAIModifierKeys( |
| 293 | ctx context.Context, |
no test coverage detected