Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 4 additions & 4 deletions .github/workflows/validate_examples.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -65,14 +65,14 @@ jobs:
repository: ${{ env.CHECKOUT_REPO }}
ref: ${{ env.CHECKOUT_REF }}
- uses: azure/setup-helm@v4
- name: Determine latest Dapr Runtime version (including prerelease)
- name: Determine latest Dapr Runtime version
run: |
RUNTIME_VERSION=$(curl -s "https://api.github.com/repos/dapr/dapr/releases" | grep '"tag_name"' | head -n 1 | cut -d ':' -f2 | tr -d '",v ')
RUNTIME_VERSION=$(curl -s "https://api.github.com/repos/dapr/dapr/releases" | grep '"tag_name"' | cut -d ':' -f2 | tr -d '",v ' | grep -v -E '\-rc|\-alpha|\-beta|\-pre' | sort -V | tail -1)
echo "DAPR_RUNTIME_VER=$RUNTIME_VERSION" >> $GITHUB_ENV
echo "Found $RUNTIME_VERSION"
- name: Determine latest Dapr Cli version (including prerelease)
- name: Determine latest Dapr Cli version
run: |
CLI_VERSION=$(curl -s "https://api.github.com/repos/dapr/cli/releases" | grep '"tag_name"' | head -n 1 | cut -d ':' -f2 | tr -d '",v ')
CLI_VERSION=$(curl -s "https://api.github.com/repos/dapr/cli/releases" | grep '"tag_name"' | cut -d ':' -f2 | tr -d '",v ' | grep -v -E '\-rc|\-alpha|\-beta|\-pre' | sort -V | tail -1)
echo "DAPR_CLI_VER=$CLI_VERSION" >> $GITHUB_ENV
echo "Found $CLI_VERSION"
- name: Set up Python ${{ matrix.python_ver }}
Expand Down
19 changes: 13 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,14 @@ git clone https://github.com/dapr/python-sdk.git
cd python-sdk
```

2. Install a project in a editable mode
2. Create and activate a virtual environment

```bash
python3 -m venv .venv
source .venv/bin/activate # On Windows: .venv\Scripts\activate
```

3. Install a project in editable mode

```bash
pip3 install -e .
Expand All @@ -90,31 +97,31 @@ pip3 install -e ./ext/dapr-ext-langgraph/
pip3 install -e ./ext/dapr-ext-strands/
```

3. Install required packages
4. Install required packages

```bash
pip3 install -r dev-requirements.txt
```

4. Run linter and autofix
5. Run linter and autofix

```bash
tox -e ruff
```

5. Run unit-test
6. Run unit-test

```bash
tox -e py311
```

6. Run type check
7. Run type check

```bash
tox -e type
```

7. Run examples
8. Run examples

```bash
tox -e examples
Expand Down
10 changes: 10 additions & 0 deletions dapr/clients/grpc/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@

import grpc # type: ignore
from google.protobuf.any_pb2 import Any as GrpcAny
from google.protobuf.duration_pb2 import Duration as GrpcDuration
from google.protobuf.empty_pb2 import Empty as GrpcEmpty
from google.protobuf.message import Message as GrpcMessage
from google.protobuf.struct_pb2 import Struct as GrpcStruct
from grpc import ( # type: ignore
RpcError,
StatusCode,
Expand Down Expand Up @@ -1880,6 +1882,8 @@ def converse_alpha2(
temperature: Optional[float] = None,
tools: Optional[List[conversation.ConversationTools]] = None,
tool_choice: Optional[str] = None,
response_format: Optional[GrpcStruct] = None,
prompt_cache_retention: Optional[GrpcDuration] = None,
) -> conversation.ConversationResponseAlpha2:
"""Invoke an LLM using the conversation API (Alpha2) with tool calling support.

Expand All @@ -1893,6 +1897,8 @@ def converse_alpha2(
temperature: Optional temperature setting for the LLM to optimize for creativity or predictability
tools: Optional list of tools available for the LLM to call
tool_choice: Optional control over which tools can be called ('none', 'auto', 'required', or specific tool name)
response_format: Optional response format (google.protobuf.struct_pb2.Struct, ex: json_schema for structured output)
prompt_cache_retention: Optional retention for prompt cache (google.protobuf.duration_pb2.Duration)

Returns:
ConversationResponseAlpha2 containing the conversation results with choices and tool calls
Expand Down Expand Up @@ -1949,6 +1955,10 @@ def converse_alpha2(
request.temperature = temperature
if tool_choice is not None:
request.tool_choice = tool_choice
if response_format is not None and hasattr(request, 'response_format'):
request.response_format.CopyFrom(response_format)
if prompt_cache_retention is not None and hasattr(request, 'prompt_cache_retention'):
request.prompt_cache_retention.CopyFrom(prompt_cache_retention)

try:
response, call = self.retry_policy.run_rpc(self._stub.ConverseAlpha2.with_call, request)
Expand Down
70 changes: 69 additions & 1 deletion dapr/clients/grpc/conversation.py
Original file line number Diff line number Diff line change
Expand Up @@ -338,11 +338,46 @@ class ConversationResultAlpha2Choices:
message: ConversationResultAlpha2Message


@dataclass
class ConversationResultAlpha2CompletionUsageCompletionTokensDetails:
"""Breakdown of tokens used in the completion."""

accepted_prediction_tokens: int = 0
audio_tokens: int = 0
reasoning_tokens: int = 0
rejected_prediction_tokens: int = 0


@dataclass
class ConversationResultAlpha2CompletionUsagePromptTokensDetails:
"""Breakdown of tokens used in the prompt."""

audio_tokens: int = 0
cached_tokens: int = 0


@dataclass
class ConversationResultAlpha2CompletionUsage:
"""Token usage for one Alpha2 conversation result."""

completion_tokens: int = 0
prompt_tokens: int = 0
total_tokens: int = 0
completion_tokens_details: Optional[
ConversationResultAlpha2CompletionUsageCompletionTokensDetails
] = None
prompt_tokens_details: Optional[ConversationResultAlpha2CompletionUsagePromptTokensDetails] = (
None
)


@dataclass
class ConversationResultAlpha2:
"""One of the outputs in Alpha2 response from conversation input."""

choices: List[ConversationResultAlpha2Choices] = field(default_factory=list)
model: Optional[str] = None
usage: Optional[ConversationResultAlpha2CompletionUsage] = None


@dataclass
Expand Down Expand Up @@ -657,5 +692,38 @@ def _get_outputs_from_grpc_response(
)
)

outputs.append(ConversationResultAlpha2(choices=choices))
model: Optional[str] = None
usage: Optional[ConversationResultAlpha2CompletionUsage] = None
if hasattr(output, 'model') and getattr(output, 'model', None):
model = output.model
if hasattr(output, 'usage') and output.usage:
u = output.usage
completion_details: Optional[
ConversationResultAlpha2CompletionUsageCompletionTokensDetails
] = None
prompt_details: Optional[ConversationResultAlpha2CompletionUsagePromptTokensDetails] = (
None
)
if hasattr(u, 'completion_tokens_details') and u.completion_tokens_details:
cd = u.completion_tokens_details
completion_details = ConversationResultAlpha2CompletionUsageCompletionTokensDetails(
accepted_prediction_tokens=getattr(cd, 'accepted_prediction_tokens', 0) or 0,
audio_tokens=getattr(cd, 'audio_tokens', 0) or 0,
reasoning_tokens=getattr(cd, 'reasoning_tokens', 0) or 0,
rejected_prediction_tokens=getattr(cd, 'rejected_prediction_tokens', 0) or 0,
)
if hasattr(u, 'prompt_tokens_details') and u.prompt_tokens_details:
pd = u.prompt_tokens_details
prompt_details = ConversationResultAlpha2CompletionUsagePromptTokensDetails(
audio_tokens=getattr(pd, 'audio_tokens', 0) or 0,
cached_tokens=getattr(pd, 'cached_tokens', 0) or 0,
)
usage = ConversationResultAlpha2CompletionUsage(
completion_tokens=getattr(u, 'completion_tokens', 0) or 0,
prompt_tokens=getattr(u, 'prompt_tokens', 0) or 0,
total_tokens=getattr(u, 'total_tokens', 0) or 0,
completion_tokens_details=completion_details,
prompt_tokens_details=prompt_details,
)
outputs.append(ConversationResultAlpha2(choices=choices, model=model, usage=usage))
return outputs
14 changes: 7 additions & 7 deletions examples/configuration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,10 @@ To run this example, use the following command:
name: Run get configuration example
match_order: none
expected_stdout_lines:
- "== APP == Got key=orderId1 value=100 version=1 metadata={}"
- "== APP == Got key=orderId2 value=200 version=1 metadata={}"
- "== APP == Subscribe key=orderId2 value=210 version=2 metadata={}"
- "== APP == Unsubscribed successfully? True"
- "Got key=orderId1 value=100 version=1 metadata={}"
- "Got key=orderId2 value=200 version=1 metadata={}"
- "Subscribe key=orderId2 value=210 version=2 metadata={}"
- "Unsubscribed successfully? True"
background: true
timeout_seconds: 30
sleep: 3
Expand All @@ -75,7 +75,7 @@ docker exec dapr_redis redis-cli SET orderId2 "210||2"

You should be able to see the following output:
```
== APP == Got key=orderId1 value=100 version=1
== APP == Got key=orderId2 value=200 version=1
== APP == Subscribe key=orderId2 value=210 version=2
Got key=orderId1 value=100 version=1
Got key=orderId2 value=200 version=1
Subscribe key=orderId2 value=210 version=2
```
8 changes: 4 additions & 4 deletions examples/conversation/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ The Conversation API supports real LLM providers including:
<!-- STEP
name: Run Conversation Alpha V1
expected_stdout_lines:
- "== APP == Result: What's Dapr?"
- "== APP == Give a brief overview."
- "Result: What's Dapr?"
- "Give a brief overview."
background: true
timeout_seconds: 60
-->
Expand All @@ -47,8 +47,8 @@ The Conversation API supports real LLM providers including:
<!-- STEP
name: Run Conversation Alpha V2
expected_stdout_lines:
- "== APP == Result: What's Dapr?"
- "== APP == Give a brief overview."
- "Result: What's Dapr?"
- "Give a brief overview."
background: true
timeout_seconds: 60
-->
Expand Down
64 changes: 32 additions & 32 deletions examples/crypto/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,14 @@ openssl rand -out keys/symmetric-key-256 32
<!-- STEP
name: Run crypto example
expected_stdout_lines:
- '== APP == Running gRPC client synchronous API'
- '== APP == Running encrypt/decrypt operation on string'
- '== APP == Encrypted the message, got 856 bytes'
- '== APP == Decrypted the message, got 24 bytes'
- '== APP == The secret is "passw0rd"'
- '== APP == Running encrypt/decrypt operation on file'
- '== APP == Wrote encrypted data to encrypted.out'
- '== APP == Wrote decrypted data to decrypted.out.jpg'
- 'Running gRPC client synchronous API'
- 'Running encrypt/decrypt operation on string'
- 'Encrypted the message, got 856 bytes'
- 'Decrypted the message, got 24 bytes'
- 'The secret is "passw0rd"'
- 'Running encrypt/decrypt operation on file'
- 'Wrote encrypted data to encrypted.out'
- 'Wrote decrypted data to decrypted.out.jpg'
- "Exited App successfully"
output_match_mode: substring
timeout_seconds: 10
Expand All @@ -63,14 +63,14 @@ dapr run --app-id crypto --resources-path ./components/ -- python3 crypto.py
<!-- STEP
name: Run async crypto example
expected_stdout_lines:
- '== APP == Running gRPC client asynchronous API'
- '== APP == Running encrypt/decrypt operation on string'
- '== APP == Encrypted the message, got 856 bytes'
- '== APP == Decrypted the message, got 24 bytes'
- '== APP == The secret is "passw0rd"'
- '== APP == Running encrypt/decrypt operation on file'
- '== APP == Wrote encrypted data to encrypted.out'
- '== APP == Wrote decrypted data to decrypted.out.jpg'
- 'Running gRPC client asynchronous API'
- 'Running encrypt/decrypt operation on string'
- 'Encrypted the message, got 856 bytes'
- 'Decrypted the message, got 24 bytes'
- 'The secret is "passw0rd"'
- 'Running encrypt/decrypt operation on file'
- 'Wrote encrypted data to encrypted.out'
- 'Wrote decrypted data to decrypted.out.jpg'
- "Exited App successfully"
output_match_mode: substring
timeout_seconds: 10
Expand Down Expand Up @@ -102,20 +102,20 @@ rm decrypted.out.jpg
The output should be as follows:

```shell
== APP == Running gRPC client synchronous API
== APP == Running encrypt/decrypt operation on string
== APP == Encrypted the message, got 856 bytes
== APP == Decrypted the message, got 24 bytes
== APP == b'The secret is "passw0rd"'
== APP == Running encrypt/decrypt operation on file
== APP == Wrote encrypted data to encrypted.out
== APP == Wrote decrypted data to decrypted.out.jpg
== APP == Running gRPC client asynchronous API
== APP == Running encrypt/decrypt operation on string
== APP == Encrypted the message, got 856 bytes
== APP == Decrypted the message, got 24 bytes
== APP == b'The secret is "passw0rd"'
== APP == Running encrypt/decrypt operation on file
== APP == Wrote encrypted data to encrypted.out
== APP == Wrote decrypted data to decrypted.out.jpg
Running gRPC client synchronous API
Running encrypt/decrypt operation on string
Encrypted the message, got 856 bytes
Decrypted the message, got 24 bytes
b'The secret is "passw0rd"'
Running encrypt/decrypt operation on file
Wrote encrypted data to encrypted.out
Wrote decrypted data to decrypted.out.jpg
Running gRPC client asynchronous API
Running encrypt/decrypt operation on string
Encrypted the message, got 856 bytes
Decrypted the message, got 24 bytes
b'The secret is "passw0rd"'
Running encrypt/decrypt operation on file
Wrote encrypted data to encrypted.out
Wrote decrypted data to decrypted.out.jpg
```
Loading
Loading