agent-framework-typesafe 1.0.0a261002__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) Microsoft Corporation.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,240 @@
1
+ Metadata-Version: 2.4
2
+ Name: agent-framework-typesafe
3
+ Version: 1.0.0a261002
4
+ Summary: TypeSafe AI integration for Microsoft Agent Framework.
5
+ Author: Microsoft
6
+ Author-email: Microsoft <af-support@microsoft.com>
7
+ License-File: LICENSE
8
+ Classifier: License :: OSI Approved :: MIT License
9
+ Classifier: Development Status :: 3 - Alpha
10
+ Classifier: Intended Audience :: Developers
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Framework :: Pydantic :: 2
18
+ Classifier: Typing :: Typed
19
+ Requires-Dist: agent-framework-core>=1.19.0,<2
20
+ Requires-Dist: httpx2>=2.0.0,<3
21
+ Requires-Dist: typesafe-sdk>=0.7.1,<0.8.0
22
+ Requires-Python: >=3.10
23
+ Project-URL: homepage, https://aka.ms/agent-framework
24
+ Project-URL: source, https://github.com/microsoft/agent-framework/tree/main/python
25
+ Project-URL: release_notes, https://github.com/microsoft/agent-framework/releases?q=tag%3Apython-1&expanded=true
26
+ Project-URL: issues, https://github.com/microsoft/agent-framework/issues
27
+ Description-Content-Type: text/markdown
28
+
29
+ # Agent Framework TypeSafe AI
30
+
31
+ Use [TypeSafe AI](https://docs.typesafe.ai/) System One models, including Jev,
32
+ with Microsoft Agent Framework.
33
+
34
+ This alpha package adapts TypeSafe's structured decision API to the Agent Framework
35
+ chat client contract. Jev evaluates
36
+ [application state](https://docs.typesafe.ai/concepts/state.md) against explicit
37
+ [typed questions](https://docs.typesafe.ai/primitives.md) and returns
38
+ probabilities and scores. It does not generate ordinary chat text.
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ pip install agent-framework-typesafe --pre
44
+ ```
45
+
46
+ ## Quick start
47
+
48
+ Set `TYPESAFE_API_KEY`, then create TypeSafe questions and run them through an
49
+ Agent Framework `Agent`:
50
+
51
+ ```python
52
+ from agent_framework import Agent
53
+ from agent_framework_typesafe import TypeSafeChatClient
54
+ from typesafe_sdk import Choice, Noul
55
+
56
+ client = TypeSafeChatClient()
57
+ try:
58
+ agent = Agent(
59
+ client=client,
60
+ name="TicketEvaluator",
61
+ instructions="Evaluate the support request using the configured questions.",
62
+ )
63
+ response = await agent.run(
64
+ "Our checkout has failed for three days and we are losing sales.",
65
+ options={
66
+ "response_format": {
67
+ "department": Choice(
68
+ instructions="Which team should handle this request?",
69
+ criteria={"billing": None, "technical": None, "sales": None},
70
+ ),
71
+ "urgent": Noul(instructions="Does this request need urgent attention?"),
72
+ },
73
+ },
74
+ )
75
+ print(response.value)
76
+ finally:
77
+ await client.close()
78
+ ```
79
+
80
+ For this connector, Agent Framework's `response_format` option is the TypeSafe
81
+ [`Questions`](https://docs.typesafe.ai/sdk/python/api/types/questions.md)
82
+ mapping. The connector forwards it as the SDK's `questions` argument and
83
+ internally uses
84
+ [`SystemOneResponse`](https://docs.typesafe.ai/sdk/python/api/types/responses.md)
85
+ as the actual response model.
86
+
87
+ `AgentLoopMiddleware.with_judge(...)` supports provider-specific structured
88
+ judges through its `response_format` and `verdict_parser` arguments. Pass a
89
+ TypeSafe `Questions` mapping as the response format and convert the returned
90
+ `SystemOneResponse` into the framework's `JudgeVerdict` in the loop setup. This
91
+ keeps the connector focused on TypeSafe response primitives instead of making
92
+ it aware of framework-specific judge models.
93
+
94
+ Framework integrations with a fixed TypeSafe contract can configure
95
+ `default_questions` on the client and omit per-call `response_format`. For
96
+ example, `SecureAgentConfig` can use
97
+ `TypeSafeChatClient(default_questions=quarantine_questions)` directly as its
98
+ quarantine client; the framework's explicit `tool_choice="none"` forwarding is
99
+ honored.
100
+
101
+ ## Supported options
102
+
103
+ | Option | Description |
104
+ | --- | --- |
105
+ | `response_format` | Required non-empty TypeSafe `Questions` mapping containing `Noul`, `Choice`, or `Score` questions. |
106
+ | `model` | Optional per-call model override. |
107
+ | `instructions` | Agent instructions included in the structured state sent to TypeSafe. |
108
+
109
+ Streaming, non-text message content, and generative settings such as `temperature`
110
+ are rejected.
111
+
112
+ `TypeSafeChatClient` is the recommended client and layers function invocation,
113
+ middleware, and telemetry over `RawTypeSafeChatClient`. Use the raw client only
114
+ when composing a custom layer stack or intentionally opting out of those framework
115
+ layers. The raw client can inspect compatible tools and emit Agent Framework
116
+ function calls, but it does not execute them itself.
117
+
118
+ ## Function calling
119
+
120
+ TypeSafe converts tool selection and supported arguments into internal `Choice`
121
+ and `Noul` questions, emits Agent Framework function calls, and lets the standard
122
+ function-invocation loop execute them. The client defaults to one tool call per
123
+ run; opt into sequential round trips with
124
+ `function_invocation_configuration={"max_function_calls": N}`. Jev can select
125
+ another tool call after seeing each result, or select no tool to finish.
126
+
127
+ This follows TypeSafe's
128
+ [Function calling cookbook](https://docs.typesafe.ai/cookbooks/function_calling.md):
129
+ the model selects from closed sets, while application code owns validation and
130
+ execution.
131
+
132
+ The terminal response text consolidates the current turn's tool results and any
133
+ final TypeSafe `Choice` or `Score` decisions. The full terminal
134
+ `SystemOneResponse`, including `Noul` answers, remains available through
135
+ `response.value`.
136
+
137
+ Supported input-schema shapes:
138
+
139
+ - Empty/zero-argument object schemas.
140
+ - Fixed `const` values.
141
+ - `enum` or Python `Literal` arguments.
142
+ - Boolean arguments.
143
+ - Arrays whose items are `enum` or `Literal` values. These are treated as
144
+ set-like selections in schema order; duplicates and caller-defined ordering are
145
+ not supported. Arrays with `minItems`, `maxItems`, uniqueness, prefix, or
146
+ membership constraints are rejected because the connector cannot preserve those
147
+ semantics. Every enum member must match the declared item type.
148
+ - Optional versions of those shapes. A separate TypeSafe question decides whether
149
+ to omit the argument so the function's default can apply.
150
+
151
+ Required free-form strings, numbers, nested objects, general arrays, and required
152
+ nullable arguments are not supported. Schema constraints that the connector
153
+ cannot preserve, such as `allOf` on the root object, an argument, or an array
154
+ item, also exclude the entire tool. Assertion siblings beside `$ref` or nullable
155
+ `anyOf` are rejected rather than merged in a way that could broaden the schema.
156
+ A tool is excluded when any declared argument is unsupported, including optional
157
+ arguments, so invocation never falls back to an unintended default. In automatic
158
+ tool mode, unsupported tools are excluded with a warning. Required unsupported
159
+ tools fail the request.
160
+
161
+ Local tools can use inferred schemas or Pydantic input models:
162
+
163
+ ```python
164
+ from typing import Literal
165
+
166
+ from agent_framework import Agent, FunctionTool
167
+ from agent_framework_typesafe import TypeSafeChatClient
168
+ from pydantic import BaseModel
169
+ from typesafe_sdk import Noul
170
+
171
+
172
+ class WeatherArguments(BaseModel):
173
+ city: Literal["Seattle", "Paris"]
174
+ detailed: bool
175
+
176
+
177
+ weather = FunctionTool(
178
+ name="weather",
179
+ description="Get weather for a supported city.",
180
+ func=lambda city, detailed: f"Weather for {city}; detailed={detailed}",
181
+ input_model=WeatherArguments,
182
+ )
183
+ agent = Agent(client=TypeSafeChatClient(), tools=[weather])
184
+ response = await agent.run(
185
+ "Give me detailed Seattle weather.",
186
+ options={"response_format": {"succeeded": Noul(instructions="Did the tool result indicate success?")}},
187
+ )
188
+ ```
189
+
190
+ MCP tools are supported through `Agent`, which connects to the server and expands
191
+ discovered MCP functions into `FunctionTool` objects before TypeSafe routing:
192
+
193
+ ```python
194
+ from agent_framework import Agent, MCPStdioTool
195
+ from agent_framework_typesafe import TypeSafeChatClient
196
+
197
+ mcp = MCPStdioTool(name="my-server", command="my-mcp-server")
198
+ agent = Agent(client=TypeSafeChatClient(), tools=[mcp])
199
+ ```
200
+
201
+ Only discovered MCP functions whose JSON schemas fit the supported subset are
202
+ routable. Use `tool_choice.allowed_tools` to narrow large MCP servers; a request
203
+ supports at most 32 routable tools, 64 properties per tool, 64 enum members per
204
+ argument, and 128 generated internal questions. The routable-tool limit is
205
+ checked after tool-choice filtering and before any tool schemas are compiled. An
206
+ exact cumulative question budget is reserved before question objects are
207
+ constructed, so schemas that would exceed 128 questions fail without
208
+ materializing the excess. An explicitly empty `allowed_tools` list denies every
209
+ tool. Routing criteria always include the exact function name and its optional
210
+ description so identically described tools remain distinguishable.
211
+
212
+ ## Configuration and lifecycle
213
+
214
+ The internally created TypeSafe SDK client reads:
215
+
216
+ - `TYPESAFE_API_KEY` - required API key.
217
+ - `TYPESAFE_DEFAULT_MODEL` - optional default model; the SDK defaults to `jev-latest`.
218
+ - `TYPESAFE_BASE_URL` - optional API root override.
219
+
220
+ Constructor values take precedence over an explicitly selected `.env` file and
221
+ process environment variables. Credential requirements are evaluated only after
222
+ those sources are resolved. When `async_client` is supplied, the injected client
223
+ is authoritative and no API key, endpoint, or environment-resolved model is
224
+ applied by the connector. An explicitly passed per-request or constructor `model`
225
+ can still override the injected client's default.
226
+
227
+ For advanced SDK configuration, inject a configured `AsyncTypeSafeClient`:
228
+
229
+ ```python
230
+ from agent_framework_typesafe import TypeSafeChatClient
231
+ from typesafe_sdk import AsyncTypeSafeClient
232
+
233
+ sdk_client = AsyncTypeSafeClient(timeout=60)
234
+ client = TypeSafeChatClient(async_client=sdk_client)
235
+ ```
236
+
237
+ Injected SDK clients remain caller-owned. Use `close()` or `async with` to close
238
+ clients created by `TypeSafeChatClient`.
239
+
240
+ See the [package sample](samples/README.md) for a runnable direct-client and Agent example.
@@ -0,0 +1,212 @@
1
+ # Agent Framework TypeSafe AI
2
+
3
+ Use [TypeSafe AI](https://docs.typesafe.ai/) System One models, including Jev,
4
+ with Microsoft Agent Framework.
5
+
6
+ This alpha package adapts TypeSafe's structured decision API to the Agent Framework
7
+ chat client contract. Jev evaluates
8
+ [application state](https://docs.typesafe.ai/concepts/state.md) against explicit
9
+ [typed questions](https://docs.typesafe.ai/primitives.md) and returns
10
+ probabilities and scores. It does not generate ordinary chat text.
11
+
12
+ ## Installation
13
+
14
+ ```bash
15
+ pip install agent-framework-typesafe --pre
16
+ ```
17
+
18
+ ## Quick start
19
+
20
+ Set `TYPESAFE_API_KEY`, then create TypeSafe questions and run them through an
21
+ Agent Framework `Agent`:
22
+
23
+ ```python
24
+ from agent_framework import Agent
25
+ from agent_framework_typesafe import TypeSafeChatClient
26
+ from typesafe_sdk import Choice, Noul
27
+
28
+ client = TypeSafeChatClient()
29
+ try:
30
+ agent = Agent(
31
+ client=client,
32
+ name="TicketEvaluator",
33
+ instructions="Evaluate the support request using the configured questions.",
34
+ )
35
+ response = await agent.run(
36
+ "Our checkout has failed for three days and we are losing sales.",
37
+ options={
38
+ "response_format": {
39
+ "department": Choice(
40
+ instructions="Which team should handle this request?",
41
+ criteria={"billing": None, "technical": None, "sales": None},
42
+ ),
43
+ "urgent": Noul(instructions="Does this request need urgent attention?"),
44
+ },
45
+ },
46
+ )
47
+ print(response.value)
48
+ finally:
49
+ await client.close()
50
+ ```
51
+
52
+ For this connector, Agent Framework's `response_format` option is the TypeSafe
53
+ [`Questions`](https://docs.typesafe.ai/sdk/python/api/types/questions.md)
54
+ mapping. The connector forwards it as the SDK's `questions` argument and
55
+ internally uses
56
+ [`SystemOneResponse`](https://docs.typesafe.ai/sdk/python/api/types/responses.md)
57
+ as the actual response model.
58
+
59
+ `AgentLoopMiddleware.with_judge(...)` supports provider-specific structured
60
+ judges through its `response_format` and `verdict_parser` arguments. Pass a
61
+ TypeSafe `Questions` mapping as the response format and convert the returned
62
+ `SystemOneResponse` into the framework's `JudgeVerdict` in the loop setup. This
63
+ keeps the connector focused on TypeSafe response primitives instead of making
64
+ it aware of framework-specific judge models.
65
+
66
+ Framework integrations with a fixed TypeSafe contract can configure
67
+ `default_questions` on the client and omit per-call `response_format`. For
68
+ example, `SecureAgentConfig` can use
69
+ `TypeSafeChatClient(default_questions=quarantine_questions)` directly as its
70
+ quarantine client; the framework's explicit `tool_choice="none"` forwarding is
71
+ honored.
72
+
73
+ ## Supported options
74
+
75
+ | Option | Description |
76
+ | --- | --- |
77
+ | `response_format` | Required non-empty TypeSafe `Questions` mapping containing `Noul`, `Choice`, or `Score` questions. |
78
+ | `model` | Optional per-call model override. |
79
+ | `instructions` | Agent instructions included in the structured state sent to TypeSafe. |
80
+
81
+ Streaming, non-text message content, and generative settings such as `temperature`
82
+ are rejected.
83
+
84
+ `TypeSafeChatClient` is the recommended client and layers function invocation,
85
+ middleware, and telemetry over `RawTypeSafeChatClient`. Use the raw client only
86
+ when composing a custom layer stack or intentionally opting out of those framework
87
+ layers. The raw client can inspect compatible tools and emit Agent Framework
88
+ function calls, but it does not execute them itself.
89
+
90
+ ## Function calling
91
+
92
+ TypeSafe converts tool selection and supported arguments into internal `Choice`
93
+ and `Noul` questions, emits Agent Framework function calls, and lets the standard
94
+ function-invocation loop execute them. The client defaults to one tool call per
95
+ run; opt into sequential round trips with
96
+ `function_invocation_configuration={"max_function_calls": N}`. Jev can select
97
+ another tool call after seeing each result, or select no tool to finish.
98
+
99
+ This follows TypeSafe's
100
+ [Function calling cookbook](https://docs.typesafe.ai/cookbooks/function_calling.md):
101
+ the model selects from closed sets, while application code owns validation and
102
+ execution.
103
+
104
+ The terminal response text consolidates the current turn's tool results and any
105
+ final TypeSafe `Choice` or `Score` decisions. The full terminal
106
+ `SystemOneResponse`, including `Noul` answers, remains available through
107
+ `response.value`.
108
+
109
+ Supported input-schema shapes:
110
+
111
+ - Empty/zero-argument object schemas.
112
+ - Fixed `const` values.
113
+ - `enum` or Python `Literal` arguments.
114
+ - Boolean arguments.
115
+ - Arrays whose items are `enum` or `Literal` values. These are treated as
116
+ set-like selections in schema order; duplicates and caller-defined ordering are
117
+ not supported. Arrays with `minItems`, `maxItems`, uniqueness, prefix, or
118
+ membership constraints are rejected because the connector cannot preserve those
119
+ semantics. Every enum member must match the declared item type.
120
+ - Optional versions of those shapes. A separate TypeSafe question decides whether
121
+ to omit the argument so the function's default can apply.
122
+
123
+ Required free-form strings, numbers, nested objects, general arrays, and required
124
+ nullable arguments are not supported. Schema constraints that the connector
125
+ cannot preserve, such as `allOf` on the root object, an argument, or an array
126
+ item, also exclude the entire tool. Assertion siblings beside `$ref` or nullable
127
+ `anyOf` are rejected rather than merged in a way that could broaden the schema.
128
+ A tool is excluded when any declared argument is unsupported, including optional
129
+ arguments, so invocation never falls back to an unintended default. In automatic
130
+ tool mode, unsupported tools are excluded with a warning. Required unsupported
131
+ tools fail the request.
132
+
133
+ Local tools can use inferred schemas or Pydantic input models:
134
+
135
+ ```python
136
+ from typing import Literal
137
+
138
+ from agent_framework import Agent, FunctionTool
139
+ from agent_framework_typesafe import TypeSafeChatClient
140
+ from pydantic import BaseModel
141
+ from typesafe_sdk import Noul
142
+
143
+
144
+ class WeatherArguments(BaseModel):
145
+ city: Literal["Seattle", "Paris"]
146
+ detailed: bool
147
+
148
+
149
+ weather = FunctionTool(
150
+ name="weather",
151
+ description="Get weather for a supported city.",
152
+ func=lambda city, detailed: f"Weather for {city}; detailed={detailed}",
153
+ input_model=WeatherArguments,
154
+ )
155
+ agent = Agent(client=TypeSafeChatClient(), tools=[weather])
156
+ response = await agent.run(
157
+ "Give me detailed Seattle weather.",
158
+ options={"response_format": {"succeeded": Noul(instructions="Did the tool result indicate success?")}},
159
+ )
160
+ ```
161
+
162
+ MCP tools are supported through `Agent`, which connects to the server and expands
163
+ discovered MCP functions into `FunctionTool` objects before TypeSafe routing:
164
+
165
+ ```python
166
+ from agent_framework import Agent, MCPStdioTool
167
+ from agent_framework_typesafe import TypeSafeChatClient
168
+
169
+ mcp = MCPStdioTool(name="my-server", command="my-mcp-server")
170
+ agent = Agent(client=TypeSafeChatClient(), tools=[mcp])
171
+ ```
172
+
173
+ Only discovered MCP functions whose JSON schemas fit the supported subset are
174
+ routable. Use `tool_choice.allowed_tools` to narrow large MCP servers; a request
175
+ supports at most 32 routable tools, 64 properties per tool, 64 enum members per
176
+ argument, and 128 generated internal questions. The routable-tool limit is
177
+ checked after tool-choice filtering and before any tool schemas are compiled. An
178
+ exact cumulative question budget is reserved before question objects are
179
+ constructed, so schemas that would exceed 128 questions fail without
180
+ materializing the excess. An explicitly empty `allowed_tools` list denies every
181
+ tool. Routing criteria always include the exact function name and its optional
182
+ description so identically described tools remain distinguishable.
183
+
184
+ ## Configuration and lifecycle
185
+
186
+ The internally created TypeSafe SDK client reads:
187
+
188
+ - `TYPESAFE_API_KEY` - required API key.
189
+ - `TYPESAFE_DEFAULT_MODEL` - optional default model; the SDK defaults to `jev-latest`.
190
+ - `TYPESAFE_BASE_URL` - optional API root override.
191
+
192
+ Constructor values take precedence over an explicitly selected `.env` file and
193
+ process environment variables. Credential requirements are evaluated only after
194
+ those sources are resolved. When `async_client` is supplied, the injected client
195
+ is authoritative and no API key, endpoint, or environment-resolved model is
196
+ applied by the connector. An explicitly passed per-request or constructor `model`
197
+ can still override the injected client's default.
198
+
199
+ For advanced SDK configuration, inject a configured `AsyncTypeSafeClient`:
200
+
201
+ ```python
202
+ from agent_framework_typesafe import TypeSafeChatClient
203
+ from typesafe_sdk import AsyncTypeSafeClient
204
+
205
+ sdk_client = AsyncTypeSafeClient(timeout=60)
206
+ client = TypeSafeChatClient(async_client=sdk_client)
207
+ ```
208
+
209
+ Injected SDK clients remain caller-owned. Use `close()` or `async with` to close
210
+ clients created by `TypeSafeChatClient`.
211
+
212
+ See the [package sample](samples/README.md) for a runnable direct-client and Agent example.
@@ -0,0 +1,17 @@
1
+ # Copyright (c) Microsoft. All rights reserved.
2
+
3
+ import importlib.metadata
4
+
5
+ from ._chat_client import RawTypeSafeChatClient, TypeSafeChatClient, TypeSafeChatOptions
6
+
7
+ try:
8
+ __version__ = importlib.metadata.version(__name__)
9
+ except importlib.metadata.PackageNotFoundError:
10
+ __version__ = "0.0.0"
11
+
12
+ __all__ = [
13
+ "RawTypeSafeChatClient",
14
+ "TypeSafeChatClient",
15
+ "TypeSafeChatOptions",
16
+ "__version__",
17
+ ]