diff --git a/agents/aqcat/README.md b/agents/aqcat/README.md index b20953e..09db2e0 100644 --- a/agents/aqcat/README.md +++ b/agents/aqcat/README.md @@ -10,7 +10,7 @@ This agent gives Discovery users conversational access to that capability. A res **Intended user:** computational chemists, catalysis researchers, and materials scientists doing candidate triage. -**Related agents.** [`aqpotency`](../aqpotency/README.md) covers small-molecule potency and selectivity on the same platform and the same connection. [`sandboxaq`](../sandboxaq/README.md) is separate — it prompts a SandboxAQ model you have subscribed to in Azure AI Foundry, and needs no platform tenant. +**Related agents.** [`aqpotency`](../aqpotency/README.md) covers small-molecule potency and selectivity on the same platform and the same connection. **Successful outcome:** a ranked, correctly-attributed set of adsorption energies with units intact, each reported with its convergence status and the resolved bulk identifier, plus an explicit statement of which systems fall outside the model's applicability. @@ -40,9 +40,10 @@ The agent holds no compute of its own and ships no container. It is a prompt age - An Azure AI Foundry project with a chat model deployment, supplied as `{{CHAT-MODEL}}`. - Access to a SandboxAQ AI Simulation Platform tenant with AQCat enabled. Contact if your organization does not have one. -- The MCP server URL for your tenant, and a credential that server accepts as a **request header**, stored as a connection in your Azure AI Foundry project. The agent references that connection by name; the credential never enters the agent definition. +- The MCP server URL for your tenant, configured as a connection in your Azure AI Foundry project. The agent references that connection by name. +- A SandboxAQ account for each user. Sign-in is per-user OAuth; no API keys or service tokens are issued or accepted. -> **Authentication note.** Foundry's MCP tool authenticates with a stored connection or static headers; it cannot complete an interactive browser OAuth flow. If your tenant is configured for interactive consent only, request a service token or equivalent header credential from your platform administrator before deploying. +> **Authentication note.** Each user signs in with their own SandboxAQ account through a browser OAuth flow. Discovery does not yet support per-user sign-in for MCP tools, so this agent cannot connect from Discovery until it does; until then, validate it in the Azure AI Foundry playground. Foundry supports browser sign-in, but each connection needs its own OAuth client, and the platform must accept the redirect URL Foundry generates for that connection (these begin with `https://global.consent.azure-apim.net/redirect/`). Contact to have a redirect URL accepted. ## Configuration @@ -50,9 +51,9 @@ The agent holds no compute of its own and ships no container. It is a prompt age |---|---|---| | `{{CHAT-MODEL}}` | Azure AI Foundry chat model deployment name | `gpt-4o-deployment` | | `{{AQ_MCP_SERVER_URL}}` | Base URL of your tenant's SandboxAQ AI Simulation Platform MCP server | `https://mcp.demo.aisim.sandboxaq.com` | -| `{{AQ_MCP_CONNECTION}}` | Name of the connection in your Foundry project holding the MCP server credential | `sandboxaq-aisim` | +| `{{AQ_MCP_CONNECTION}}` | Name of the MCP server connection in your Foundry project | `sandboxaq-aisim` | -Create the connection in your own Azure AI Foundry project before deploying. The agent definition references it by name and never carries the credential itself, so no secret appears in this catalog entry or in your deployed agent's configuration. +Create the connection in your own Azure AI Foundry project before deploying. The agent definition references it by name, so no secret appears in this catalog entry or in your deployed agent's configuration. ## Usage @@ -103,7 +104,7 @@ For comparative questions the agent submits one `AQCat` job per candidate surfac - **Applicability is bounded by training data.** Unusual elements, heavily distorted cells, and exotic oxidation states may produce confident-looking numbers with no basis. The agent flags these where it can recognize them, but the boundary is not sharply defined and the check is not exhaustive. - **Asynchronous jobs may outlive a conversation.** Long relaxations will not complete within a single turn; the agent returns a job identifier for later retrieval. - **No offline mode.** Every calculation requires network access to the platform, and the agent has no local fallback. -- **Interactive-OAuth tenants are not supported** without a header credential — see the authentication note under Prerequisites. +- **Not yet usable from Discovery.** Sign-in is per-user OAuth, which Discovery does not yet support for MCP tools — see the authentication note under Prerequisites. - **The `aqcat-adsorption-spin` skill does not transfer.** Discovery has no skill loader; the workflow it encodes is reproduced in this agent's `instructions` block and may diverge from the skill over time. ## Support diff --git a/agents/aqpotency/README.md b/agents/aqpotency/README.md index e2982a2..a1c9997 100644 --- a/agents/aqpotency/README.md +++ b/agents/aqpotency/README.md @@ -10,7 +10,7 @@ This agent gives Discovery users conversational access to three framings of that **Intended user:** medicinal chemists, computational chemists, and computational biologists prioritizing compounds and assessing off-target liabilities. -**Related agents.** [`aqcat`](../aqcat/README.md) covers catalysis and surface reactivity on the same platform and the same connection. [`sandboxaq`](../sandboxaq/README.md) is separate — it prompts a SandboxAQ model you have subscribed to in Azure AI Foundry, and needs no platform tenant. +**Related agents.** [`aqcat`](../aqcat/README.md) covers catalysis and surface reactivity on the same platform and the same connection. **Successful outcome:** predicted potencies with uncertainty, correctly attributed to molecule and target, with weakly-supported predictions clearly marked so they are not ranked as though they were confident. @@ -39,10 +39,11 @@ The agent holds no compute of its own and ships no container. It is a prompt age - An Azure AI Foundry project with a chat model deployment, supplied as `{{CHAT-MODEL}}`. - Access to a SandboxAQ AI Simulation Platform tenant with AQPotency enabled. Contact if your organization does not have one. -- The MCP server URL for your tenant, and a credential that server accepts as a **request header**, stored as a connection in your Azure AI Foundry project. The agent references that connection by name; the credential never enters the agent definition. +- The MCP server URL for your tenant, configured as a connection in your Azure AI Foundry project. The agent references that connection by name. +- A SandboxAQ account for each user. Sign-in is per-user OAuth; no API keys or service tokens are issued or accepted. - Awareness of your organization's data-handling policy for proprietary chemical matter: the SMILES you submit are sent to the platform. -> **Authentication note.** Foundry's MCP tool authenticates with a stored connection or static headers; it cannot complete an interactive browser OAuth flow. If your tenant is configured for interactive consent only, request a service token or equivalent header credential from your platform administrator before deploying. +> **Authentication note.** Each user signs in with their own SandboxAQ account through a browser OAuth flow. Discovery does not yet support per-user sign-in for MCP tools, so this agent cannot connect from Discovery until it does; until then, validate it in the Azure AI Foundry playground. Foundry supports browser sign-in, but each connection needs its own OAuth client, and the platform must accept the redirect URL Foundry generates for that connection (these begin with `https://global.consent.azure-apim.net/redirect/`). Contact to have a redirect URL accepted. ## Configuration @@ -50,9 +51,9 @@ The agent holds no compute of its own and ships no container. It is a prompt age |---|---|---| | `{{CHAT-MODEL}}` | Azure AI Foundry chat model deployment name | `gpt-4o-deployment` | | `{{AQ_MCP_SERVER_URL}}` | Base URL of your tenant's SandboxAQ AI Simulation Platform MCP server | `https://mcp.demo.aisim.sandboxaq.com` | -| `{{AQ_MCP_CONNECTION}}` | Name of the connection in your Foundry project holding the MCP server credential | `sandboxaq-aisim` | +| `{{AQ_MCP_CONNECTION}}` | Name of the MCP server connection in your Foundry project | `sandboxaq-aisim` | -Create the connection in your own Azure AI Foundry project before deploying. The agent definition references it by name and never carries the credential itself, so no secret appears in this catalog entry or in your deployed agent's configuration. +Create the connection in your own Azure AI Foundry project before deploying. The agent definition references it by name, so no secret appears in this catalog entry or in your deployed agent's configuration. ## Usage @@ -111,7 +112,7 @@ Provided by the SandboxAQ AI Simulation Platform MCP server; no container images - **Accession mapping is a failure mode.** Prose target names must be resolved to accessions; the agent confirms its intended accession rather than assuming, but a wrong accession produces a plausible number for the wrong protein. - **Jobs can outlive a conversation.** Panel scans in particular may not complete within a turn; the agent returns a job identifier for later retrieval. - **Submitted molecules leave your environment.** Every prediction sends chemical matter to the platform. Confirm this is permitted under your organization's data-handling policy before submitting proprietary structures. -- **Interactive-OAuth tenants are not supported** without a header credential — see the authentication note under Prerequisites. +- **Not yet usable from Discovery.** Sign-in is per-user OAuth, which Discovery does not yet support for MCP tools — see the authentication note under Prerequisites. ## Support diff --git a/agents/sandboxaq/README.md b/agents/sandboxaq/README.md deleted file mode 100644 index 0d7dbb8..0000000 --- a/agents/sandboxaq/README.md +++ /dev/null @@ -1,196 +0,0 @@ -# SandboxAQ Foundry Model Agent Deployment Guide - -This guide provides step-by-step instructions for deploying the SandboxAQ -Foundry Model tool and its associated agent to the Microsoft Discovery -platform. - -## Overview - -This agent invokes a SandboxAQ model that your organization has subscribed to -through Azure AI Foundry, calling the OpenAI-compatible chat-completions -endpoint from a Discovery-managed tool container. This deployment includes: - -- **Dockerfile**: Used for creation of the SandboxAQ model tool container image -- **Tool Definition**: Configuration for the `sandboxaq-model` tool -- **Agent Definition**: AI agent configuration for the SandboxAQ agent - -### Which SandboxAQ agent do I want? - -Three SandboxAQ agents are published in this catalog. Choose by what you have access to: - -| Agent | Use it when | Requires | -|---|---|---| -| **`sandboxaq`** (this one) | You have subscribed to a SandboxAQ model in Azure AI Foundry and want to prompt it directly | A SandboxAQ model subscription in Foundry | -| [**`aqcat`**](../aqcat/README.md) | You want adsorption energies and surface reactivity for catalysis | A SandboxAQ AI Simulation Platform tenant | -| [**`aqpotency`**](../aqpotency/README.md) | You want small-molecule potency, panel scans, or selectivity | A SandboxAQ AI Simulation Platform tenant | - -This agent is general-purpose inference against a model deployment you control. The other two are domain agents that reach specific scientific tools on the SandboxAQ platform. - -## Prerequisites - -Before starting the deployment, ensure you have: - -1. Access to Microsoft Discovery platform -2. An active SandboxAQ model subscription deployed in Azure AI Foundry -3. Azure Container Registry (ACR) with appropriate permissions -4. Docker installed locally for image building -5. Azure CLI or PowerShell for resource management - -## Build Docker Image - -### Step 1: Build and Publish Docker Image - -1. **Build the image** from this tool directory: - - ```bash - docker build -t sandboxaq-model:latest . - ``` - -2. **Tag the image** for your Azure Container Registry: - - ```bash - docker tag sandboxaq-model:latest mycontainerregistry.azurecr.io/sandboxaq-model:latest - ``` - - > Replace `mycontainerregistry` with your actual ACR name - -3. **Login to Azure Container Registry**: - - ```bash - az acr login --name mycontainerregistry - ``` - -4. **Push the image** to your container registry: - - ```bash - docker push mycontainerregistry.azurecr.io/sandboxaq-model:latest - ``` - -## File Structure - -```text -sandboxaq/ -├── agent.yaml # Agent configuration (YAML) -├── metadata.yaml # Catalog metadata -├── tools/ -│ └── sandboxaq-model/ -│ ├── Dockerfile # Container image definition -│ ├── tool.yaml # Tool configuration (YAML) -│ └── sandboxaq_utils.py # Foundry client helper module -└── README.md # This deployment guide -``` - -## Key Configuration Details - -### Agent Capabilities - -The SandboxAQ agent provides: - -- **Model Invocation**: Sends prompts to the subscribed SandboxAQ deployment -- **Structured Output**: Preserves JSON returned by the endpoint and writes - results to `/output/final_results.json` -- **Sensitive-Data Handling**: Applies access, privacy, and human-review - guidance when working with HR or other confidential business data - -## Usage - -### Basic Queries - -| Prompt | Description | -|--------|-------------| -| "Run the SandboxAQ model on this prompt and return the result as JSON." | Direct invocation | -| "Summarize this HR policy using the subscribed SandboxAQ deployment." | Summarization | -| "Ask the SandboxAQ model to classify these support tickets." | Classification | - -### Advanced Queries - -| Prompt | Description | -|--------|-------------| -| "Run this prompt at temperature 0.7 and cap the output at 1000 tokens." | Tuned sampling parameters | -| "Use a system prompt of 'You are a concise policy analyst' for this request." | Custom system instruction | -| "Invoke the model on each of these five prompts and collect the results." | Batch invocation in one script | - -## Architecture - -This agent operates as a `kind: prompt` agent within Discovery Studio. - - User Input → SandboxAQ Agent (LLM) → sandboxaq-model Tool (Container) → Azure AI Foundry → Results - -- **Model:** Configured via the `{{CHAT-MODEL}}` parameter at deploy time -- **Tool:** `sandboxaq-model` container exposing a `python3` code environment - -The tool exposes a Python code environment rather than a fixed action. The -agent writes a script that imports `sandboxaq_utils` and calls -`invoke_model(prompt, system_prompt=..., temperature=..., max_tokens=...)`, -which returns a dict with `model`, `content`, `finish_reason`, `usage`, and -`raw_response`. - -Prompts therefore travel as Python string literals and are never interpolated -into a shell command, so text containing apostrophes, double quotes, `$`, or -newlines reaches the deployment unmodified. - -## Configuration - -| Parameter | Description | Example | -|---|---|---| -| `{{CHAT-MODEL}}` | Azure AI Foundry model deployment name for the agent | `gpt-4o` | - -The tool reads its endpoint and credential from runtime environment -variables. They are deliberately absent from `tool.yaml`: the tool schema only -supports static, committed values, and the credential must never be committed. -Set them in your deployment's environment-variable configuration (for -example a `sandboxaq-model-EnvVars.json` file), as the PubMed agent does: - -```json -{ - "FOUNDRY_ENDPOINT": "https://.openai.azure.com/openai", - "FOUNDRY_API_KEY": "", - "FOUNDRY_DEPLOYMENT": "" -} -``` - -| Environment variable | Required | Description | -|---|---:|---| -| `FOUNDRY_ENDPOINT` | Yes | Endpoint base URL. For `azure-openai`, include the `/openai` API base; for `serverless`, the URL that `/chat/completions` is appended to | -| `FOUNDRY_API_KEY` | Yes | Secret for the subscribed deployment | -| `FOUNDRY_DEPLOYMENT` | `azure-openai`: Yes; `serverless`: No | SandboxAQ model deployment name. Sent as the `model` field for `serverless` | -| `FOUNDRY_API_STYLE` | No | `azure-openai` (default): `/deployments/{name}/chat/completions` with an `api-key` header. `serverless`: `/chat/completions` with a Bearer token, for Foundry serverless and Foundry Models endpoints | -| `FOUNDRY_API_VERSION` | No | API version. Defaults to `2024-10-21` for `azure-openai`; omitted for `serverless` unless set | - -The endpoint must be reachable from the Discovery tool container. Error -messages from the tool report the HTTP status and response body but never the -endpoint URL or credential. - -## Support - -For issues or questions with this agent, contact SandboxAQ: - - -SandboxAQ contact: support@sandboxaq.com - -For platform issues, open a GitHub issue: - - -## Tools - -| Tool | Path | Description | -|---|---|---| -| `sandboxaq-model` | `tools/sandboxaq-model/` | Invokes a subscribed SandboxAQ model through its Azure AI Foundry OpenAI-compatible chat-completions endpoint. | - -## Known Limitations - -- Requires an existing SandboxAQ subscription in Azure AI Foundry; the agent - cannot provision or discover deployments on your behalf. -- Supports the chat-completions API surface only. Embeddings, batch, and - streaming endpoints are not exposed. -- Credentials are supplied as environment variables on the deployed tool, so - rotating a key requires updating the tool configuration. -- For sensitive HR data, apply your organization's privacy, access-control, - and human-review requirements. This agent does not make employment - decisions. - -## Contributing - -This project welcomes contributions and suggestions. Please see the -repository's top-level [CONTRIBUTING guidelines](https://github.com/microsoft/discovery/blob/main/CONTRIBUTING.md) -for details on how to contribute. diff --git a/agents/sandboxaq/agent.yaml b/agents/sandboxaq/agent.yaml deleted file mode 100644 index 46ebc0f..0000000 --- a/agents/sandboxaq/agent.yaml +++ /dev/null @@ -1,78 +0,0 @@ -kind: prompt -name: sandboxaq -displayName: SandboxAQ Foundry Model Agent -description: > - Invokes subscribed SandboxAQ models through an Azure AI Foundry endpoint. -model: - id: '{{CHAT-MODEL}}' - options: - temperature: 0 - topP: 0 - maxOutputTokens: 4096 -instructions: |- - You are the SandboxAQ Foundry Model Agent. You reach the subscribed - SandboxAQ deployment by writing Python scripts that run in the tool's code - environment. - - # INSTALLED PYTHON PACKAGES - `requests`, `json` (stdlib), and `sandboxaq_utils` (custom module). - **NOT available:** pandas, numpy, rdkit, matplotlib. Do NOT import these. - - **ALWAYS use `from sandboxaq_utils import invoke_model`** -- this is the - ONLY supported way to call the deployment. Never build the request URL, - headers, or credential yourself, and never invoke the model through a shell - command; passing prompt text through a shell corrupts any prompt containing - quotes or `$`. - - ## CRITICAL RULES - - 1. Put the prompt in a Python variable, not in a shell command. Triple-quoted - string literals handle apostrophes, quotes, and newlines correctly. - 2. Write results to `/output/final_results.json` with `save_json()`. - 3. Do not claim a model was invoked unless the script completed and returned - a response. - 4. Keep user inputs and model outputs clearly separated in your report. - Preserve structured output when the endpoint returns JSON. - 5. Never expose endpoint URLs, API keys, authorization headers, or other - deployment secrets -- not in scripts, logs, or your reply. - 6. If the request is missing information the endpoint requires, ask one - focused clarifying question before running anything. - - ### Script template - - ```python - from sandboxaq_utils import invoke_model, save_json - - prompt = """Summarize the attached policy in five bullet points.""" - - result = invoke_model( - prompt, - system_prompt="You are a concise policy analyst.", - temperature=0, - max_tokens=4096, - ) - - print(result["content"]) - save_json(result, "/output/final_results.json") - ``` - - `invoke_model` returns a dict with `model`, `content`, `finish_reason`, - `usage`, and `raw_response`. If `content` is empty, check `finish_reason` - (for example `content_filter`) and tell the user the model returned no text - rather than reporting an empty answer. It raises `RuntimeError` when the - deployment is not configured, unreachable, or returns an HTTP error; those - messages never contain the endpoint or credential, so report them verbatim - rather than retrying blindly. - - For HR or other sensitive business data: - - Follow the user's organization's access and data-handling policies. - - Do not infer protected attributes or make employment decisions. - - State when the model response is uncertain or requires human review. - - Return only the minimum sensitive information needed for the request. -discoveryExtensions: - humanInTheLoop: Disabled - tools: - - toolId: '{{sandboxaqModelToolId}}' - confirmation: Disabled - disableDataHandlingTools: false - disableDiscoveryInjectedTools: false diff --git a/agents/sandboxaq/metadata.yaml b/agents/sandboxaq/metadata.yaml deleted file mode 100644 index 1a100e1..0000000 --- a/agents/sandboxaq/metadata.yaml +++ /dev/null @@ -1,15 +0,0 @@ -name: sandboxaq -type: agent -version: 1.0.0 -associated_tools: - - agents/sandboxaq/tools/sandboxaq-model -publisher: - name: SandboxAQ - contact: support@sandboxaq.com - support_url: https://www.sandboxaq.com/contact - party: 3p -description: > - Invokes SandboxAQ models subscribed through Azure AI Foundry for secure, - structured inference workflows. -tags: - - language-model diff --git a/agents/sandboxaq/tools/sandboxaq-model/Dockerfile b/agents/sandboxaq/tools/sandboxaq-model/Dockerfile deleted file mode 100644 index 5bd04db..0000000 --- a/agents/sandboxaq/tools/sandboxaq-model/Dockerfile +++ /dev/null @@ -1,21 +0,0 @@ -FROM mcr.microsoft.com/azurelinux/base/python:3.12 - -WORKDIR /app - -# System update + TLS certificates (MUST be first RUN for layer sharing) -RUN tdnf -y update && \ - tdnf -y install ca-certificates && \ - update-ca-trust && \ - tdnf clean all -RUN pip3 install --no-cache-dir requests - -# Create working directories -RUN mkdir -p /input /output /workdir - -# /app: safe from volume mounts, reachable via PYTHONPATH -COPY sandboxaq_utils.py /app/ - -WORKDIR /workdir -ENV PYTHONPATH="/app" - -CMD ["/bin/bash"] diff --git a/agents/sandboxaq/tools/sandboxaq-model/sandboxaq_utils.py b/agents/sandboxaq/tools/sandboxaq-model/sandboxaq_utils.py deleted file mode 100644 index 0efe073..0000000 --- a/agents/sandboxaq/tools/sandboxaq-model/sandboxaq_utils.py +++ /dev/null @@ -1,128 +0,0 @@ -"""Helpers for calling a subscribed SandboxAQ model through Azure AI Foundry. - -Agent scripts import from this module rather than shelling out, so prompt text -is never interpreted by a shell: - - from sandboxaq_utils import invoke_model, save_json - - result = invoke_model("Summarize this policy") - save_json(result, "/output/final_results.json") -""" - -import json -import os - -import requests - -DEFAULT_API_VERSION = "2024-10-21" -DEFAULT_TIMEOUT_SECONDS = 300 - - -def required_env(name): - value = os.environ.get(name) - if not value: - raise RuntimeError(f"Required environment variable is not set: {name}") - return value - - -def build_request(deployment): - """Return the chat-completions URL and auth headers for the configured endpoint. - - FOUNDRY_API_STYLE selects the request shape: - - `azure-openai` (default): {endpoint}/deployments/{deployment}/chat/completions - with an `api-key` header. The endpoint includes the `/openai` API base. - - `serverless`: {endpoint}/chat/completions with a Bearer token, for - Foundry serverless / Foundry Models endpoints. The deployment, when - set, is sent as the `model` field. - """ - endpoint = required_env("FOUNDRY_ENDPOINT").rstrip("/") - api_key = required_env("FOUNDRY_API_KEY") - style = (os.environ.get("FOUNDRY_API_STYLE") or "azure-openai").strip().lower() - if style == "azure-openai": - if not deployment: - raise RuntimeError( - "Required environment variable is not set: FOUNDRY_DEPLOYMENT" - ) - api_version = os.environ.get("FOUNDRY_API_VERSION") or DEFAULT_API_VERSION - url = ( - f"{endpoint}/deployments/{deployment}/chat/completions" - f"?api-version={api_version}" - ) - auth = {"api-key": api_key} - elif style == "serverless": - api_version = os.environ.get("FOUNDRY_API_VERSION") - url = f"{endpoint}/chat/completions" - if api_version: - url += f"?api-version={api_version}" - auth = {"Authorization": f"Bearer {api_key}"} - else: - raise RuntimeError( - "FOUNDRY_API_STYLE must be 'azure-openai' or 'serverless'" - ) - return url, {**auth, "Content-Type": "application/json"} - - -def invoke_model( - prompt, - system_prompt="", - temperature=0, - max_tokens=4096, - timeout=DEFAULT_TIMEOUT_SECONDS, -): - """Send a prompt to the configured SandboxAQ deployment. - - Returns a dict with `model`, `content`, `finish_reason`, `usage`, and - `raw_response`. `content` is an empty string when the endpoint returns no - text (for example a `content_filter` finish reason). Raises RuntimeError on - missing configuration, transport or HTTP failures, and empty responses; - error messages never include the endpoint URL or credential. - """ - deployment = os.environ.get("FOUNDRY_DEPLOYMENT", "") - url, headers = build_request(deployment) - messages = [] - if system_prompt: - messages.append({"role": "system", "content": system_prompt}) - messages.append({"role": "user", "content": prompt}) - body = { - "messages": messages, - "temperature": temperature, - "max_tokens": max_tokens, - } - if deployment and "Authorization" in headers: - body["model"] = deployment - try: - response = requests.post(url, headers=headers, json=body, timeout=timeout) - except requests.RequestException as error: - # requests embeds the URL in its messages; report only the error type. - raise RuntimeError( - f"Could not reach the SandboxAQ deployment ({type(error).__name__})" - ) from None - if not response.ok: - detail = response.text[:500] if response.text else "" - raise RuntimeError( - f"SandboxAQ deployment returned HTTP {response.status_code} " - f"{response.reason}: {detail}" - ) - payload = response.json() - choices = payload.get("choices") - if not choices: - raise RuntimeError("Foundry response did not contain any choices") - choice = choices[0] or {} - message = choice.get("message") or {} - return { - "model": payload.get("model") or deployment, - "content": message.get("content") or "", - "finish_reason": choice.get("finish_reason"), - "usage": payload.get("usage"), - "raw_response": payload, - } - - -def save_json(data, path): - """Write `data` to `path` as UTF-8 JSON, creating parent directories.""" - parent = os.path.dirname(path) - if parent: - os.makedirs(parent, exist_ok=True) - with open(path, "w", encoding="utf-8") as handle: - json.dump(data, handle, indent=2, ensure_ascii=False) - return path diff --git a/agents/sandboxaq/tools/sandboxaq-model/tool.yaml b/agents/sandboxaq/tools/sandboxaq-model/tool.yaml deleted file mode 100644 index a789fe1..0000000 --- a/agents/sandboxaq/tools/sandboxaq-model/tool.yaml +++ /dev/null @@ -1,37 +0,0 @@ -name: sandboxaq-model -description: > - Invokes a subscribed SandboxAQ model through its Azure AI Foundry - OpenAI-compatible chat-completions endpoint. -version: 1.0.0 -license: MIT -category: "Model Inference" -infra: - - name: worker - infra_type: container - image: - acr: "{name}.azurecr.io/sandboxaq-model:latest" - compute: - min_resources: - cpu: 1 - ram: 4Gi - storage: 8Gi - gpu: 0 - max_resources: - cpu: 2 - ram: 8Gi - storage: 32Gi - gpu: 0 - infiniband: false - recommended_sku: - - Standard_D4s_v6 - pool_type: static - pool_size: 1 -code_environments: - - language: python3 - command: "python3 -u \"/{{scriptName}}\"" - description: > - Python code environment on the SandboxAQ model container image. Scripts - import `sandboxaq_utils` to reach the configured Azure AI Foundry - deployment; the endpoint, deployment name, and credential are supplied - as runtime environment variables. - infra_node: worker