Assert.That(instructions,Does.Not.Contain($"`{toolId}`"),"The web search would name tools the request may not offer, and each of these words the rule itself.");
Assert.That(newSearchMailsTool(null!,null!,null!,null!,NullLogger<SearchMailsTool>.Instance).GetDefinition().SystemPromptInstructions,Does.Contain("search the web before you use the mail tools"),"The token count assumes a request which offers the web search.");
Assert.That(newCountMailsTool(null!,null!,null!,null!,NullLogger<CountMailsTool>.Instance).GetDefinition().SystemPromptInstructions,Does.Not.Contain("web_search"),"The collection is always offered together, so the rule would stand twice in the same request.");
Assert.That(instructions.Contains("search the web before you search the wiki",StringComparison.Ordinal),Is.EqualTo(expected),"Without a restriction, the search leaves the web search in place, and the rule would only cost the model a detour.");
Assert.That(instructions,Does.Not.Contain("web_search"),"The request does not offer the web search, so a rule about it would only confuse the model.");
Assert.That(instructions.Contains("search the web before you search the data sources",StringComparison.Ordinal),Is.EqualTo(expected),"Without a restriction, a search leaves the web search in place, and the rule would only cost the model a detour.");
Assert.That(SemanticSearchTool.EndsWebSearch(this.ResolutionContext(selected),settings),Is.False,"The project files are not selected, so the model cannot find anything in them.");
Assert.That(SemanticSearchTool.EndsWebSearch(this.ResolutionContext(automatic),settings),Is.True,"With the automatic selection, the model may search the project files as well.");
Assert.That(instructions,Does.Contain("search the web before you search the data sources"),"The token count assumes a request which offers the web search and a data source which ends it.");
Assert.That(instructions.Contains("search the web before you read such a page",StringComparison.Ordinal),Is.EqualTo(internalPageEndsWebSearch));
}
[TestCase(OutboundDataRestriction.ONLY_LINKS_FROM_CHAT, true, true, false, true, TestName = "An internal page of the wiki ends the web search")]
[TestCase(OutboundDataRestriction.ONLY_CONFIGURED_SERVICES, true, false, true, true, TestName = "An internal page on an allowed private host ends the web search")]
[TestCase(OutboundDataRestriction.UNRESTRICTED, true, true, true, false, TestName = "Without a restriction, an internal page leaves the web search in place")]
[TestCase(OutboundDataRestriction.ONLY_LINKS_FROM_CHAT, false, true, true, false, TestName = "A request without a web search has none to lose")]
[TestCase(OutboundDataRestriction.ONLY_LINKS_FROM_CHAT, true, false, false, false, TestName = "Without a wiki and without allowed private hosts, no internal page can be read")]
Assert.That(restricted,Is.EquivalentTo(new[]{"wiki_search_test"}),"The chat may no longer search the web, so no tool may tell the model to search it first.");
Assert.That(configuredServices,Does.Contain($"only reads pages of the wiki at {WIKI} or on the internal hosts intranet.example.org, *.corp.example.org, whatever the rules above allow"));
Assert.That(linksFromChat,Does.Contain("or a page on the internal hosts intranet.example.org, whatever the rules above allow"),"Without a wiki, the allowed hosts are the addresses the model may still choose.");
Assert.That(configuredServices,Does.Contain("This chat holds internal content").And.Not.Contain("content of e-mails"),"The restriction may come from the wiki or an internal page as well.");
Assert.That(instructions,Does.Contain("only reads pages on the internal hosts intranet.example.org, *.corp.example.org, whatever the rules above allow"));
Assert.That(withoutWiki,Does.Contain("only reads pages on the internal hosts intranet.example.org whose URL appears word for word in this conversation, and refuses every other URL."));
Assert.That(withoutWiki,Does.Not.Contain("wiki search"),"There is no wiki whose hits could be meant.");
Assert.That(withWiki,Does.Contain("whose URL appears word for word in this conversation, such as the hits of a wiki search, and refuses every other URL."));
});
}
/// <param name="thread">The chat the request continues.</param>
/// <param name="candidateToolIds">The tools the request may offer; when left out, unknown, so every tool may be there.</param>