URL Context

Extract and use content from web URLs.

Overview

URL Context allows agents to:

  • Read webpage content

  • Extract article text

  • Access online documentation

  • Parse GitHub files

  • Process web resources

Basic Setup

Enable URL Context

agent.AddGoogleTool(GoogleToolType.UrlContext);

Read URLs

Simple URL Access

await agent.SendAsync("Read the content from https://docs.unity3d.com/Manual/index.html");
await agent.SendAsync("What does this page say: https://github.com/user/repo/README.md");

Extract Specific Information

await agent.SendAsync(@"
Read https://docs.unity3d.com/ScriptReference/Vector3.html
and explain the Vector3.Lerp method
");

Use Cases

Documentation Lookup

public async void LookupUnityAPI(string apiName)
{
    string url = $"https://docs.unity3d.com/ScriptReference/{apiName}.html";
    
    await agent.SendAsync($@"
Read the Unity documentation at: {url}
and provide:
1. Brief description
2. Key methods
3. Code example
4. Common use cases
");
}

// Usage
LookupUnityAPI("NavMeshAgent");
LookupUnityAPI("Rigidbody");

GitHub File Reading

public async void ReadGitHubFile(string owner, string repo, string filePath)
{
    string url = $"https://raw.githubusercontent.com/{owner}/{repo}/main/{filePath}";
    
    await agent.SendAsync($@"
Read the file from: {url}
and explain what this code does
");
}

// Usage
ReadGitHubFile("Cysharp", "UniTask", "README.md");

Tutorial Processing

public async void ProcessTutorial(string tutorialUrl)
{
    await agent.SendAsync($@"
Read the tutorial at: {tutorialUrl}

Provide:
1. Summary of key concepts
2. Step-by-step breakdown
3. Code examples mentioned
4. Prerequisites
");
}

// Usage
ProcessTutorial("https://learn.unity.com/tutorial/working-with-addressables");

Multiple URLs

Compare Documentation

public async void CompareAPIs(string url1, string url2)
{
    await agent.SendAsync($@"
Read both:
1. {url1}
2. {url2}

Compare and contrast these two APIs
");
}

// Usage
CompareAPIs(
    "https://docs.unity3d.com/ScriptReference/Coroutine.html",
    "https://github.com/Cysharp/UniTask"
);

Aggregate Information

public async void AggregateResources(string[] urls)
{
    string urlList = string.Join("\n", urls.Select((url, i) => $"{i + 1}. {url}"));
    
    await agent.SendAsync($@"
Read all these resources:
{urlList}

Provide a comprehensive summary combining information from all sources
");
}

URL Parsing

Parse Release Notes

public async void ParseReleaseNotes(string packageName, string version)
{
    string url = $"https://github.com/{packageName}/releases/tag/v{version}";
    
    await agent.SendAsync($@"
Read release notes from: {url}

Extract:
1. New features
2. Bug fixes
3. Breaking changes
4. Migration guide
");
}

// Usage
ParseReleaseNotes("Unity-Technologies/Addressables-Sample", "1.21.2");

Extract Code Examples

public async void ExtractCodeExamples(string docUrl)
{
    await agent.SendAsync($@"
Read: {docUrl}

Extract all code examples and explain each one
");
}

Content Filtering

Extract Specific Sections

public async void ExtractSection(string url, string sectionName)
{
    await agent.SendAsync($@"
Read: {url}

Find and extract only the '{sectionName}' section
");
}

// Usage
ExtractSection(
    "https://docs.unity3d.com/Manual/BestPracticeUnderstandingPerformanceInUnity.html",
    "Memory Management"
);

Get Table of Contents

public async void GetTableOfContents(string url)
{
    await agent.SendAsync($@"
Read: {url}

Extract the table of contents or main sections
");
}

Integration with Game Features

Dynamic Help System

public class ContextualHelp : MonoBehaviour
{
    [SerializeField] private AgentBehaviour agent;
    
    private Dictionary<string, string> helpUrls = new()
    {
        { "inventory", "https://docs.unity.com/example/inventory-system" },
        { "combat", "https://docs.unity.com/example/combat-mechanics" },
        { "quests", "https://docs.unity.com/example/quest-system" }
    };
    
    public async void ShowHelp(string topic)
    {
        if (!helpUrls.TryGetValue(topic, out string url))
        {
            Debug.LogWarning($"No help URL for topic: {topic}");
            return;
        }
        
        await agent.SendAsync($@"
Read the documentation at: {url}

Provide a concise explanation suitable for in-game help
");
    }
}

// Usage
contextualHelp.ShowHelp("inventory");

Asset Documentation Reader

public async void ReadAssetDocs(string assetUrl)
{
    await agent.SendAsync($@"
Read asset documentation from: {assetUrl}

Provide:
1. Installation instructions
2. Quick start guide
3. Key features
4. API overview
");
}

Error Handling

Handle URL Errors

agent.onUrlContextError.AddListener(error =>
{
    Debug.LogError($"URL context failed: {error}");
    
    if (error.Contains("not_found"))
    {
        ShowMessage("URL not found (404)");
    }
    else if (error.Contains("forbidden"))
    {
        ShowMessage("Access forbidden (403)");
    }
    else if (error.Contains("timeout"))
    {
        ShowMessage("Request timed out");
    }
    else
    {
        ShowMessage("Failed to read URL");
    }
});

Caching

Cache URL Content

public class UrlContentCache : MonoBehaviour
{
    private Dictionary<string, CachedContent> cache = new();
    private TimeSpan cacheExpiry = TimeSpan.FromHours(24);
    
    public async UniTask<string> GetOrFetch(AgentBehaviour agent, string url)
    {
        if (cache.TryGetValue(url, out var cached))
        {
            if (DateTime.Now - cached.Timestamp < cacheExpiry)
            {
                Debug.Log("Using cached URL content");
                return cached.Content;
            }
        }
        
        // Fetch new content
        string content = await FetchUrl(agent, url);
        
        cache[url] = new CachedContent
        {
            Content = content,
            Timestamp = DateTime.Now
        };
        
        return content;
    }
    
    async UniTask<string> FetchUrl(AgentBehaviour agent, string url)
    {
        // Implementation
        return "";
    }
    
    struct CachedContent
    {
        public string Content;
        public DateTime Timestamp;
    }
}

Complete Example

using UnityEngine;
using Glitch9.AIDevKit.Agents;
using Cysharp.Threading.Tasks;

public class UrlContextManager : MonoBehaviour
{
    [SerializeField] private AgentBehaviour agent;
    [SerializeField] private TMP_InputField urlInput;
    [SerializeField] private Button fetchButton;
    [SerializeField] private TMP_Text contentDisplay;
    
    private Dictionary<string, string> cache = new();
    
    async void Start()
    {
        await SetupUrlContext();
        
        fetchButton.onClick.AddListener(OnFetchClicked);
    }
    
    async UniTask SetupUrlContext()
    {
        // Add URL Context tool
        agent.AddGoogleTool(GoogleToolType.UrlContext);
        
        // Listen for events
        agent.onUrlContextCompleted.AddListener(OnContentFetched);
        agent.onUrlContextError.AddListener(OnFetchError);
        
        Debug.Log("✓ URL Context ready");
    }
    
    async void OnFetchClicked()
    {
        string url = urlInput.text.Trim();
        
        if (string.IsNullOrEmpty(url))
        {
            ShowMessage("Please enter a URL");
            return;
        }
        
        if (!IsValidUrl(url))
        {
            ShowMessage("Invalid URL format");
            return;
        }
        
        // Check cache
        if (cache.TryGetValue(url, out var cachedContent))
        {
            Debug.Log("Using cached content");
            DisplayContent(cachedContent);
            return;
        }
        
        // Fetch content
        Debug.Log($"📄 Fetching: {url}");
        fetchButton.interactable = false;
        contentDisplay.text = "Loading...";
        
        await agent.SendAsync($"Read and summarize the content from: {url}");
    }
    
    void OnContentFetched(string content)
    {
        Debug.Log($"✓ Content fetched ({content.Length} chars)");
        
        // Cache
        string url = urlInput.text.Trim();
        cache[url] = content;
        
        // Display
        DisplayContent(content);
        
        fetchButton.interactable = true;
    }
    
    void DisplayContent(string content)
    {
        // Limit display length
        const int maxLength = 5000;
        
        if (content.Length > maxLength)
        {
            content = content.Substring(0, maxLength) + "\n\n[Content truncated...]";
        }
        
        contentDisplay.text = content;
    }
    
    void OnFetchError(string error)
    {
        Debug.LogError($"Fetch error: {error}");
        contentDisplay.text = $"<color=red>Error: {error}</color>";
        fetchButton.interactable = true;
    }
    
    bool IsValidUrl(string url)
    {
        return Uri.TryCreate(url, UriKind.Absolute, out var uri) &&
               (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps);
    }
    
    void ShowMessage(string message)
    {
        contentDisplay.text = message;
    }
}

Next Steps

Last updated