Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/typeagent/aitools/model_adapters.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ def _make_azure_provider(
azure_endpoint=azure_endpoint,
api_version=api_version,
api_key=raw_key,
default_headers={"Ocp-Apim-Subscription-Key": raw_key},
Comment thread
bmerkle marked this conversation as resolved.
Outdated
)
Comment thread
bmerkle marked this conversation as resolved.
return AzureProvider(openai_client=client)

Expand Down
18 changes: 13 additions & 5 deletions src/typeagent/aitools/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -195,9 +195,12 @@ def parse_azure_endpoint(
f"{endpoint_envvar}={azure_endpoint} doesn't contain valid api-version field"
)

# Strip query string — AsyncAzureOpenAI expects a clean base URL and
# receives api_version as a separate parameter.
# Strip query string and deployment path — AsyncAzureOpenAI expects a
# clean base URL and builds the deployment path internally.
clean_endpoint = azure_endpoint.split("?", 1)[0]
deployment_idx = clean_endpoint.find("/openai/deployments/")
if deployment_idx >= 0:
clean_endpoint = clean_endpoint[:deployment_idx]
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This handles /openai/deployments/{name} but misses a bare /openai suffix. AsyncAzureOpenAI always appends /openai to the base URL (see openai/lib/azure.py:226-228), so an endpoint like https://foo.openai.azure.com/openai?api-version=... would produce /openai/openai/....

Suggested addition after this line:

# Also strip a bare /openai suffix — the SDK always appends /openai.
clean_endpoint = re.sub(r"/openai$", "", clean_endpoint)

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think we should use:

   # Strip query string and /openai... path — AsyncAzureOpenAI expects a
    # clean base URL and builds the deployment path internally.
    clean_endpoint = azure_endpoint.split("?", 1)[0]
    clean_endpoint = re.sub(r"/openai(/deployments/.*)?$", "", clean_endpoint)


return clean_endpoint, m.group(1)

Expand Down Expand Up @@ -253,6 +256,7 @@ def create_async_openai_client(
api_version=api_version,
azure_endpoint=azure_endpoint,
api_key=azure_api_key,
default_headers={"Ocp-Apim-Subscription-Key": azure_api_key},
)

else:
Expand All @@ -264,6 +268,7 @@ def create_async_openai_client(
# The true return type is pydantic_ai.Agent[T], but that's an optional dependency.
def make_agent[T](cls: type[T]):
"""Create Pydantic AI agent using hardcoded preferences."""
from openai import AsyncAzureOpenAI
from pydantic_ai import Agent, NativeOutput, ToolOutput
from pydantic_ai.models.openai import OpenAIChatModel
from pydantic_ai.providers.azure import AzureProvider
Comment thread
bmerkle marked this conversation as resolved.
Outdated
Expand All @@ -285,9 +290,12 @@ def make_agent[T](cls: type[T]):
model = OpenAIChatModel(
"gpt-4o",
provider=AzureProvider(
azure_endpoint=azure_endpoint,
api_version=api_version,
api_key=azure_api_key,
openai_client=AsyncAzureOpenAI(
azure_endpoint=azure_endpoint,
api_version=api_version,
api_key=azure_api_key,
default_headers={"Ocp-Apim-Subscription-Key": azure_api_key},
),
),
)
Comment thread
bmerkle marked this conversation as resolved.
Outdated

Expand Down
4 changes: 3 additions & 1 deletion src/typeagent/knowpro/conversation_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@
answer_response_schema,
answers,
convknowledge,
knowledge_schema as kplib,
)
from . import (
search_query_schema,
searchlang,
secindex,
)
from . import knowledge_schema as kplib
from ..aitools import model_adapters, utils
from ..storage.memory import semrefindex
from .convsettings import ConversationSettings
Expand Down
3 changes: 2 additions & 1 deletion src/typeagent/knowpro/knowledge.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@

from typechat import Result, TypeChatLanguageModel

from . import convknowledge, knowledge_schema as kplib
from . import convknowledge
from . import knowledge_schema as kplib
from ..aitools import model_adapters
from .interfaces import IKnowledgeExtractor

Expand Down
4 changes: 3 additions & 1 deletion src/typeagent/storage/memory/semrefindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@

from typechat import Failure

from ...knowpro import convknowledge, knowledge_schema as kplib, secindex
from ...knowpro import convknowledge
from ...knowpro import knowledge_schema as kplib
from ...knowpro import secindex
from ...knowpro.convsettings import ConversationSettings, SemanticRefIndexSettings
from ...knowpro.interfaces import ( # Interfaces.; Other imports.
IConversation,
Expand Down
11 changes: 8 additions & 3 deletions tests/benchmarks/test_benchmark_vectorbase.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,11 @@
import pytest

from typeagent.aitools.model_adapters import create_test_embedding_model
from typeagent.aitools.vectorbase import ScoredInt, TextEmbeddingIndexSettings, VectorBase

from typeagent.aitools.vectorbase import (
ScoredInt,
TextEmbeddingIndexSettings,
VectorBase,
)

# -- Helpers ------------------------------------------------------------------

Expand Down Expand Up @@ -61,7 +64,9 @@ def test_1k_vectors(self, benchmark, vb_1k: tuple[VectorBase, np.ndarray]) -> No
assert len(result) == 10
assert all(isinstance(r, ScoredInt) for r in result)

def test_10k_vectors(self, benchmark, vb_10k: tuple[VectorBase, np.ndarray]) -> None:
def test_10k_vectors(
self, benchmark, vb_10k: tuple[VectorBase, np.ndarray]
) -> None:
vb, query = vb_10k
result = benchmark(vb.fuzzy_lookup_embedding, query, max_hits=10, min_score=0.0)
assert len(result) == 10
Expand Down
3 changes: 2 additions & 1 deletion tests/test_knowledge.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@

from typechat import Failure, Result, Success

from typeagent.knowpro import convknowledge, knowledge_schema as kplib
from typeagent.knowpro import convknowledge
from typeagent.knowpro import knowledge_schema as kplib
from typeagent.knowpro.knowledge import (
create_knowledge_extractor,
extract_knowledge_from_text,
Expand Down
42 changes: 18 additions & 24 deletions tests/test_online.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,36 +3,30 @@

import pytest

from typeagent.aitools.utils import create_async_openai_client
from pydantic_ai.messages import ModelRequest, TextPart, UserPromptPart
from pydantic_ai.models import ModelRequestParameters

from typeagent.aitools.model_adapters import create_chat_model


@pytest.mark.asyncio
async def test_why_is_sky_blue(really_needs_auth: None):
"""Test that chat agent responds correctly to 'why is the sky blue?'"""

# Create an async OpenAI client
try:
client = create_async_openai_client()
except RuntimeError as e:
if "Neither OPENAI_API_KEY nor AZURE_OPENAI_API_KEY was provided." in str(e):
pytest.skip("API keys not configured")
raise

# Send the user request
response = await client.chat.completions.create(
model="gpt-4o",
messages=[
{
"role": "user",
"content": "why is the sky blue?",
}
],
temperature=0,
"""Test that chat agent responds correctly to 'why is the sky blue?'

Uses create_chat_model (the pydantic-ai code path) so this test exercises
the same Azure provider wiring as the rest of the codebase.
"""
model = create_chat_model()

response = await model._model.request(
[ModelRequest(parts=[UserPromptPart(content="why is the sky blue?")])],
None,
ModelRequestParameters(),
)
Comment thread
bmerkle marked this conversation as resolved.
Outdated

# Get the response message
msg = response.choices[0].message.content
assert msg is not None, "Chat agent didn't respond"
text_parts = [p.content for p in response.parts if isinstance(p, TextPart)]
msg = "".join(text_parts)
assert msg, "Chat agent didn't respond"

print(f"Chat agent response: {msg}")

Expand Down
7 changes: 6 additions & 1 deletion tests/test_semrefindex.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,12 @@
ITermToSemanticRefIndex,
Topic,
)
from typeagent.knowpro.knowledge_schema import Action, ConcreteEntity, Facet, KnowledgeResponse
from typeagent.knowpro.knowledge_schema import (
Action,
ConcreteEntity,
Facet,
KnowledgeResponse,
)
from typeagent.storage import SqliteStorageProvider
from typeagent.storage.memory import MemoryStorageProvider
from typeagent.storage.memory.semrefindex import (
Expand Down
6 changes: 3 additions & 3 deletions tests/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ def test_api_version_after_question_mark(
)
endpoint, version = utils.parse_azure_endpoint("TEST_ENDPOINT")
assert version == "2025-01-01-preview"
assert endpoint == "https://myhost.openai.azure.com/openai/deployments/gpt-4"
assert endpoint == "https://myhost.openai.azure.com"

def test_api_version_after_ampersand(self, monkeypatch: pytest.MonkeyPatch) -> None:
"""api-version preceded by & (not the first query parameter)."""
Expand Down Expand Up @@ -121,13 +121,13 @@ def test_query_string_stripped_from_endpoint(
def test_query_string_stripped_with_path(
self, monkeypatch: pytest.MonkeyPatch
) -> None:
"""Query string stripped even when endpoint includes a path."""
"""Query string and deployment path stripped from endpoint."""
monkeypatch.setenv(
"TEST_ENDPOINT",
"https://myhost.openai.azure.com/openai/deployments/gpt-4?api-version=2025-01-01-preview",
)
endpoint, version = utils.parse_azure_endpoint("TEST_ENDPOINT")
assert endpoint == "https://myhost.openai.azure.com/openai/deployments/gpt-4"
assert endpoint == "https://myhost.openai.azure.com"
assert "?" not in endpoint
assert version == "2025-01-01-preview"

Expand Down
4 changes: 3 additions & 1 deletion tools/query.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,15 @@
from typeagent.knowpro import (
answer_response_schema,
answers,
knowledge_schema as kplib,
)
from typeagent.knowpro import (
query,
search,
search_query_schema,
searchlang,
serialization,
)
from typeagent.knowpro import knowledge_schema as kplib
Comment thread
bmerkle marked this conversation as resolved.
from typeagent.knowpro.convsettings import ConversationSettings
from typeagent.knowpro.interfaces import (
IConversation,
Expand Down
10 changes: 8 additions & 2 deletions tools/release.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,9 +450,15 @@ def main():

if exit_code != 0:
if args.force:
print("Warning: Failed to create PR -- you can create it yourself", file=sys.stderr)
print(
"Warning: Failed to create PR -- you can create it yourself",
file=sys.stderr,
)
else:
print("Error: Failed to create PR -- but you can create it yourself", file=sys.stderr)
print(
"Error: Failed to create PR -- but you can create it yourself",
file=sys.stderr,
)
return 1

if args.dry_run:
Expand Down
Loading
Loading