(tool_input: dict[str, Any], context: ToolContext)
| 445 | |
| 446 | |
| 447 | def _web_fetch_call(tool_input: dict[str, Any], context: ToolContext) -> ToolResult: |
| 448 | url = tool_input.get("url", "") |
| 449 | prompt = tool_input.get("prompt", "") |
| 450 | fmt = tool_input.get("format") or "markdown" |
| 451 | if fmt not in _VALID_FORMATS: |
| 452 | fmt = "markdown" |
| 453 | |
| 454 | if not isinstance(url, str) or not url: |
| 455 | raise ToolInputError("url must be a non-empty string") |
| 456 | |
| 457 | url = _validate_url(url) |
| 458 | |
| 459 | start_time = time.time() |
| 460 | |
| 461 | # Cache the *converted* content; key by format so a markdown fetch and a text |
| 462 | # fetch of the same URL don't collide. |
| 463 | cache_key = f"{fmt}:{url}" |
| 464 | cached = _cache_get(cache_key) |
| 465 | if cached: |
| 466 | content, content_type, status = cached |
| 467 | else: |
| 468 | raw, content_type, status = _fetch_with_redirect_handling(url, fmt=fmt) |
| 469 | content = _convert(raw, content_type, fmt) |
| 470 | _cache_set(cache_key, content, content_type, status) |
| 471 | |
| 472 | if len(content) > 100_000: |
| 473 | content = content[:100_000] + "\n\n... [truncated] ..." |
| 474 | |
| 475 | duration_ms = int((time.time() - start_time) * 1000) |
| 476 | |
| 477 | result_text = content |
| 478 | if prompt and isinstance(prompt, str): |
| 479 | result_text = f"User prompt: {prompt}\n\nContent from {url}:\n\n{content}" |
| 480 | |
| 481 | return ToolResult( |
| 482 | name="WebFetch", |
| 483 | output={ |
| 484 | "url": url, |
| 485 | "content_type": content_type, |
| 486 | "result": result_text, |
| 487 | "bytes": len(content.encode("utf-8")), |
| 488 | "code": status, |
| 489 | "duration_ms": duration_ms, |
| 490 | }, |
| 491 | ) |
| 492 | |
| 493 | |
| 494 | # -- Prompt -------------------------------------------------------------------- |
nothing calls this directly
no test coverage detected