Skip to content

Commit 75e7f11

Browse files
authored
Merge branch 'main' into django-snippet
2 parents f677067 + 2d5a21a commit 75e7f11

File tree

11 files changed

+246
-77
lines changed

11 files changed

+246
-77
lines changed

CHANGELOG.md

+4-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1515

1616
- `opentelemetry-instrumentation-openai-v2` Update doc for OpenAI Instrumentation to support OpenAI Compatible Platforms
1717
([#3279](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3279))
18-
- `opentelemetry-instrumentation-system-metrics` Add `process` metrics and deprecated `process.runtime` prefixed ones
18+
- `opentelemetry-instrumentation-system-metrics` Add `process` metrics and deprecated `process.runtime` prefixed ones
1919
([#3250](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3250))
2020
- `opentelemetry-instrumentation-botocore` Add support for GenAI user events and lazy initialize tracer
2121
([#3258](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3258))
@@ -41,6 +41,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4141
([#3247](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3247))
4242
- `opentelemetry-instrumentation-asyncpg` Fix fallback for empty queries.
4343
([#3253](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3253))
44+
- `opentelemetry-instrumentation-requests` always record span status code in duration metric
45+
([#3323](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3323))
4446

4547
## Version 1.30.0/0.51b0 (2025-02-03)
4648

@@ -100,7 +102,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
100102

101103
### Breaking changes
102104

103-
- `opentelemetry-exporter-prometheus-remote-write` updated protobuf required version from 4.21 to 5.26 and regenerated protobufs
105+
- `opentelemetry-exporter-prometheus-remote-write` updated protobuf required version from 4.21 to 5.26 and regenerated protobufs
104106
([#3219](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3219))
105107
- `opentelemetry-instrumentation-sqlalchemy` including sqlcomment in `db.statement` span attribute value is now opt-in
106108
([#3112](https://github.com/open-telemetry/opentelemetry-python-contrib/pull/3112))

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ To release a package as `1.0` stable, the package:
101101

102102
## Semantic Convention status of instrumentations
103103

104-
In our efforts to maintain optimal user experience and prevent breaking changes for transitioning into stable semantic conventions, OpenTelemetry Python is adopting the semantic convention migration plan for several instrumentations. Currently this plan is only being adopted for [HTTP-related instrumentations](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/non-normative/http-migration.md), but will eventually cover all types. Please refer to the `semconv status` column of the [instrumentation README](instrumentation/README.md) of the current status of instrumentations' semantic conventions. The possible values are `experimental`, `stable` and `migration` referring to [status](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.31.0/specification/document-status.md#lifecycle-status) of that particular semantic convention. `Migration` refers to an instrumentation that currently supports the migration plan.
104+
In our efforts to maintain optimal user experience and prevent breaking changes for transitioning into stable semantic conventions, OpenTelemetry Python is adopting the semantic convention migration plan for several instrumentations. Currently this plan is only being adopted for [HTTP-related instrumentations](https://github.com/open-telemetry/semantic-conventions/blob/main/docs/non-normative/http-migration.md), but will eventually cover all types. Please refer to the `semconv status` column of the [instrumentation README](instrumentation/README.md) of the current status of instrumentations' semantic conventions. The possible values are `development`, `stable` and `migration` referring to [status](https://github.com/open-telemetry/opentelemetry-specification/blob/v1.31.0/specification/document-status.md#lifecycle-status) of that particular semantic convention. `Migration` refers to an instrumentation that currently supports the migration plan.
105105

106106
## Contributing
107107

@@ -113,7 +113,7 @@ Meeting notes are available as a public [Google doc](https://docs.google.com/doc
113113

114114
Approvers ([@open-telemetry/python-approvers](https://github.com/orgs/open-telemetry/teams/python-approvers)):
115115

116-
- [Emídio Neto](https://github.com/emdneto), Zenvia
116+
- [Emídio Neto](https://github.com/emdneto), PicPay
117117
- [Jeremy Voss](https://github.com/jeremydvoss), Microsoft
118118
- [Owais Lone](https://github.com/owais), Splunk
119119
- [Pablo Collins](https://github.com/pmcollins), Splunk

gen-requirements.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
-c dev-requirements.txt
22
astor==0.8.1
3-
jinja2==3.1.4
3+
jinja2==3.1.6
44
markupsafe==2.0.1
55
ruff==0.6.9
66
requests

instrumentation/README.md

+40-40
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,53 @@
11

22
| Instrumentation | Supported Packages | Metrics support | Semconv status |
33
| --------------- | ------------------ | --------------- | -------------- |
4-
| [opentelemetry-instrumentation-aio-pika](./opentelemetry-instrumentation-aio-pika) | aio_pika >= 7.2.0, < 10.0.0 | No | experimental
4+
| [opentelemetry-instrumentation-aio-pika](./opentelemetry-instrumentation-aio-pika) | aio_pika >= 7.2.0, < 10.0.0 | No | development
55
| [opentelemetry-instrumentation-aiohttp-client](./opentelemetry-instrumentation-aiohttp-client) | aiohttp ~= 3.0 | No | migration
6-
| [opentelemetry-instrumentation-aiohttp-server](./opentelemetry-instrumentation-aiohttp-server) | aiohttp ~= 3.0 | No | experimental
7-
| [opentelemetry-instrumentation-aiokafka](./opentelemetry-instrumentation-aiokafka) | aiokafka >= 0.8, < 1.0 | No | experimental
8-
| [opentelemetry-instrumentation-aiopg](./opentelemetry-instrumentation-aiopg) | aiopg >= 0.13.0, < 2.0.0 | No | experimental
6+
| [opentelemetry-instrumentation-aiohttp-server](./opentelemetry-instrumentation-aiohttp-server) | aiohttp ~= 3.0 | No | development
7+
| [opentelemetry-instrumentation-aiokafka](./opentelemetry-instrumentation-aiokafka) | aiokafka >= 0.8, < 1.0 | No | development
8+
| [opentelemetry-instrumentation-aiopg](./opentelemetry-instrumentation-aiopg) | aiopg >= 0.13.0, < 2.0.0 | No | development
99
| [opentelemetry-instrumentation-asgi](./opentelemetry-instrumentation-asgi) | asgiref ~= 3.0 | Yes | migration
10-
| [opentelemetry-instrumentation-asyncio](./opentelemetry-instrumentation-asyncio) | asyncio | No | experimental
11-
| [opentelemetry-instrumentation-asyncpg](./opentelemetry-instrumentation-asyncpg) | asyncpg >= 0.12.0 | No | experimental
12-
| [opentelemetry-instrumentation-aws-lambda](./opentelemetry-instrumentation-aws-lambda) | aws_lambda | No | experimental
13-
| [opentelemetry-instrumentation-boto](./opentelemetry-instrumentation-boto) | boto~=2.0 | No | experimental
14-
| [opentelemetry-instrumentation-boto3sqs](./opentelemetry-instrumentation-boto3sqs) | boto3 ~= 1.0 | No | experimental
15-
| [opentelemetry-instrumentation-botocore](./opentelemetry-instrumentation-botocore) | botocore ~= 1.0 | No | experimental
16-
| [opentelemetry-instrumentation-cassandra](./opentelemetry-instrumentation-cassandra) | cassandra-driver ~= 3.25,scylla-driver ~= 3.25 | No | experimental
17-
| [opentelemetry-instrumentation-celery](./opentelemetry-instrumentation-celery) | celery >= 4.0, < 6.0 | No | experimental
18-
| [opentelemetry-instrumentation-click](./opentelemetry-instrumentation-click) | click >= 8.1.3, < 9.0.0 | No | experimental
19-
| [opentelemetry-instrumentation-confluent-kafka](./opentelemetry-instrumentation-confluent-kafka) | confluent-kafka >= 1.8.2, <= 2.7.0 | No | experimental
20-
| [opentelemetry-instrumentation-dbapi](./opentelemetry-instrumentation-dbapi) | dbapi | No | experimental
21-
| [opentelemetry-instrumentation-django](./opentelemetry-instrumentation-django) | django >= 1.10 | Yes | experimental
22-
| [opentelemetry-instrumentation-elasticsearch](./opentelemetry-instrumentation-elasticsearch) | elasticsearch >= 6.0 | No | experimental
10+
| [opentelemetry-instrumentation-asyncio](./opentelemetry-instrumentation-asyncio) | asyncio | No | development
11+
| [opentelemetry-instrumentation-asyncpg](./opentelemetry-instrumentation-asyncpg) | asyncpg >= 0.12.0 | No | development
12+
| [opentelemetry-instrumentation-aws-lambda](./opentelemetry-instrumentation-aws-lambda) | aws_lambda | No | development
13+
| [opentelemetry-instrumentation-boto](./opentelemetry-instrumentation-boto) | boto~=2.0 | No | development
14+
| [opentelemetry-instrumentation-boto3sqs](./opentelemetry-instrumentation-boto3sqs) | boto3 ~= 1.0 | No | development
15+
| [opentelemetry-instrumentation-botocore](./opentelemetry-instrumentation-botocore) | botocore ~= 1.0 | No | development
16+
| [opentelemetry-instrumentation-cassandra](./opentelemetry-instrumentation-cassandra) | cassandra-driver ~= 3.25,scylla-driver ~= 3.25 | No | development
17+
| [opentelemetry-instrumentation-celery](./opentelemetry-instrumentation-celery) | celery >= 4.0, < 6.0 | No | development
18+
| [opentelemetry-instrumentation-click](./opentelemetry-instrumentation-click) | click >= 8.1.3, < 9.0.0 | No | development
19+
| [opentelemetry-instrumentation-confluent-kafka](./opentelemetry-instrumentation-confluent-kafka) | confluent-kafka >= 1.8.2, <= 2.7.0 | No | development
20+
| [opentelemetry-instrumentation-dbapi](./opentelemetry-instrumentation-dbapi) | dbapi | No | development
21+
| [opentelemetry-instrumentation-django](./opentelemetry-instrumentation-django) | django >= 1.10 | Yes | development
22+
| [opentelemetry-instrumentation-elasticsearch](./opentelemetry-instrumentation-elasticsearch) | elasticsearch >= 6.0 | No | development
2323
| [opentelemetry-instrumentation-falcon](./opentelemetry-instrumentation-falcon) | falcon >= 1.4.1, < 5.0.0 | Yes | migration
2424
| [opentelemetry-instrumentation-fastapi](./opentelemetry-instrumentation-fastapi) | fastapi ~= 0.58 | Yes | migration
2525
| [opentelemetry-instrumentation-flask](./opentelemetry-instrumentation-flask) | flask >= 1.0 | Yes | migration
26-
| [opentelemetry-instrumentation-grpc](./opentelemetry-instrumentation-grpc) | grpcio >= 1.42.0 | No | experimental
26+
| [opentelemetry-instrumentation-grpc](./opentelemetry-instrumentation-grpc) | grpcio >= 1.42.0 | No | development
2727
| [opentelemetry-instrumentation-httpx](./opentelemetry-instrumentation-httpx) | httpx >= 0.18.0 | No | migration
28-
| [opentelemetry-instrumentation-jinja2](./opentelemetry-instrumentation-jinja2) | jinja2 >= 2.7, < 4.0 | No | experimental
29-
| [opentelemetry-instrumentation-kafka-python](./opentelemetry-instrumentation-kafka-python) | kafka-python >= 2.0, < 3.0,kafka-python-ng >= 2.0, < 3.0 | No | experimental
30-
| [opentelemetry-instrumentation-logging](./opentelemetry-instrumentation-logging) | logging | No | experimental
31-
| [opentelemetry-instrumentation-mysql](./opentelemetry-instrumentation-mysql) | mysql-connector-python >= 8.0, < 10.0 | No | experimental
32-
| [opentelemetry-instrumentation-mysqlclient](./opentelemetry-instrumentation-mysqlclient) | mysqlclient < 3 | No | experimental
33-
| [opentelemetry-instrumentation-pika](./opentelemetry-instrumentation-pika) | pika >= 0.12.0 | No | experimental
34-
| [opentelemetry-instrumentation-psycopg](./opentelemetry-instrumentation-psycopg) | psycopg >= 3.1.0 | No | experimental
35-
| [opentelemetry-instrumentation-psycopg2](./opentelemetry-instrumentation-psycopg2) | psycopg2 >= 2.7.3.1,psycopg2-binary >= 2.7.3.1 | No | experimental
36-
| [opentelemetry-instrumentation-pymemcache](./opentelemetry-instrumentation-pymemcache) | pymemcache >= 1.3.5, < 5 | No | experimental
37-
| [opentelemetry-instrumentation-pymongo](./opentelemetry-instrumentation-pymongo) | pymongo >= 3.1, < 5.0 | No | experimental
38-
| [opentelemetry-instrumentation-pymssql](./opentelemetry-instrumentation-pymssql) | pymssql >= 2.1.5, < 3 | No | experimental
39-
| [opentelemetry-instrumentation-pymysql](./opentelemetry-instrumentation-pymysql) | PyMySQL < 2 | No | experimental
40-
| [opentelemetry-instrumentation-pyramid](./opentelemetry-instrumentation-pyramid) | pyramid >= 1.7 | Yes | experimental
41-
| [opentelemetry-instrumentation-redis](./opentelemetry-instrumentation-redis) | redis >= 2.6 | No | experimental
42-
| [opentelemetry-instrumentation-remoulade](./opentelemetry-instrumentation-remoulade) | remoulade >= 0.50 | No | experimental
28+
| [opentelemetry-instrumentation-jinja2](./opentelemetry-instrumentation-jinja2) | jinja2 >= 2.7, < 4.0 | No | development
29+
| [opentelemetry-instrumentation-kafka-python](./opentelemetry-instrumentation-kafka-python) | kafka-python >= 2.0, < 3.0,kafka-python-ng >= 2.0, < 3.0 | No | development
30+
| [opentelemetry-instrumentation-logging](./opentelemetry-instrumentation-logging) | logging | No | development
31+
| [opentelemetry-instrumentation-mysql](./opentelemetry-instrumentation-mysql) | mysql-connector-python >= 8.0, < 10.0 | No | development
32+
| [opentelemetry-instrumentation-mysqlclient](./opentelemetry-instrumentation-mysqlclient) | mysqlclient < 3 | No | development
33+
| [opentelemetry-instrumentation-pika](./opentelemetry-instrumentation-pika) | pika >= 0.12.0 | No | development
34+
| [opentelemetry-instrumentation-psycopg](./opentelemetry-instrumentation-psycopg) | psycopg >= 3.1.0 | No | development
35+
| [opentelemetry-instrumentation-psycopg2](./opentelemetry-instrumentation-psycopg2) | psycopg2 >= 2.7.3.1,psycopg2-binary >= 2.7.3.1 | No | development
36+
| [opentelemetry-instrumentation-pymemcache](./opentelemetry-instrumentation-pymemcache) | pymemcache >= 1.3.5, < 5 | No | development
37+
| [opentelemetry-instrumentation-pymongo](./opentelemetry-instrumentation-pymongo) | pymongo >= 3.1, < 5.0 | No | development
38+
| [opentelemetry-instrumentation-pymssql](./opentelemetry-instrumentation-pymssql) | pymssql >= 2.1.5, < 3 | No | development
39+
| [opentelemetry-instrumentation-pymysql](./opentelemetry-instrumentation-pymysql) | PyMySQL < 2 | No | development
40+
| [opentelemetry-instrumentation-pyramid](./opentelemetry-instrumentation-pyramid) | pyramid >= 1.7 | Yes | development
41+
| [opentelemetry-instrumentation-redis](./opentelemetry-instrumentation-redis) | redis >= 2.6 | No | development
42+
| [opentelemetry-instrumentation-remoulade](./opentelemetry-instrumentation-remoulade) | remoulade >= 0.50 | No | development
4343
| [opentelemetry-instrumentation-requests](./opentelemetry-instrumentation-requests) | requests ~= 2.0 | Yes | migration
44-
| [opentelemetry-instrumentation-sqlalchemy](./opentelemetry-instrumentation-sqlalchemy) | sqlalchemy >= 1.0.0, < 2.1.0 | Yes | experimental
45-
| [opentelemetry-instrumentation-sqlite3](./opentelemetry-instrumentation-sqlite3) | sqlite3 | No | experimental
46-
| [opentelemetry-instrumentation-starlette](./opentelemetry-instrumentation-starlette) | starlette >= 0.13, <0.15 | Yes | experimental
47-
| [opentelemetry-instrumentation-system-metrics](./opentelemetry-instrumentation-system-metrics) | psutil >= 5 | No | experimental
48-
| [opentelemetry-instrumentation-threading](./opentelemetry-instrumentation-threading) | threading | No | experimental
49-
| [opentelemetry-instrumentation-tornado](./opentelemetry-instrumentation-tornado) | tornado >= 5.1.1 | Yes | experimental
50-
| [opentelemetry-instrumentation-tortoiseorm](./opentelemetry-instrumentation-tortoiseorm) | tortoise-orm >= 0.17.0 | No | experimental
44+
| [opentelemetry-instrumentation-sqlalchemy](./opentelemetry-instrumentation-sqlalchemy) | sqlalchemy >= 1.0.0, < 2.1.0 | Yes | development
45+
| [opentelemetry-instrumentation-sqlite3](./opentelemetry-instrumentation-sqlite3) | sqlite3 | No | development
46+
| [opentelemetry-instrumentation-starlette](./opentelemetry-instrumentation-starlette) | starlette >= 0.13, <0.15 | Yes | development
47+
| [opentelemetry-instrumentation-system-metrics](./opentelemetry-instrumentation-system-metrics) | psutil >= 5 | No | development
48+
| [opentelemetry-instrumentation-threading](./opentelemetry-instrumentation-threading) | threading | No | development
49+
| [opentelemetry-instrumentation-tornado](./opentelemetry-instrumentation-tornado) | tornado >= 5.1.1 | Yes | development
50+
| [opentelemetry-instrumentation-tortoiseorm](./opentelemetry-instrumentation-tortoiseorm) | tortoise-orm >= 0.17.0 | No | development
5151
| [opentelemetry-instrumentation-urllib](./opentelemetry-instrumentation-urllib) | urllib | Yes | migration
5252
| [opentelemetry-instrumentation-urllib3](./opentelemetry-instrumentation-urllib3) | urllib3 >= 1.0.0, < 3.0.0 | Yes | migration
5353
| [opentelemetry-instrumentation-wsgi](./opentelemetry-instrumentation-wsgi) | wsgi | Yes | migration

instrumentation/opentelemetry-instrumentation-botocore/src/opentelemetry/instrumentation/botocore/extensions/bedrock_utils.py

+4
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,10 @@ def extract_tool_results(
386386
if not content:
387387
return
388388

389+
# langchain sends content as string with InvokeModel and Anthropic Claude
390+
if isinstance(content, str):
391+
return
392+
389393
# Converse format
390394
tool_results = [
391395
item["toolResult"] for item in content if "toolResult" in item
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
interactions:
2+
- request:
3+
body: |-
4+
{
5+
"messages": [
6+
{
7+
"role": "user",
8+
"content": "say this is a test"
9+
}
10+
],
11+
"max_tokens": 10,
12+
"anthropic_version": "bedrock-2023-05-31"
13+
}
14+
headers:
15+
Content-Length:
16+
- '126'
17+
User-Agent:
18+
- Boto3/1.35.56 md/Botocore#1.35.56 ua/2.0 os/linux#6.1.0-1034-oem md/arch#x86_64
19+
lang/python#3.10.12 md/pyimpl#CPython cfg/retry-mode#legacy Botocore/1.35.56
20+
X-Amz-Date:
21+
- 20250306T091535Z
22+
X-Amz-Security-Token:
23+
- test_aws_security_token
24+
X-Amzn-Trace-Id:
25+
- Root=1-fcd0825a-03f328cca8cde3e741cd83b4;Parent=5a8eccf8d7b031e7;Sampled=1
26+
amz-sdk-invocation-id:
27+
- e8a6c9c5-8a45-4ad7-881b-0761d121abc7
28+
amz-sdk-request:
29+
- attempt=1
30+
authorization:
31+
- Bearer test_aws_authorization
32+
method: POST
33+
uri: https://bedrock-runtime.us-east-1.amazonaws.com/model/us.anthropic.claude-3-5-sonnet-20240620-v1%3A0/invoke
34+
response:
35+
body:
36+
string: |-
37+
{
38+
"id": "msg_bdrk_01SjMAZgb8kNMweUzf3moSbU",
39+
"type": "message",
40+
"role": "assistant",
41+
"model": "claude-3-5-sonnet-20240620",
42+
"content": [
43+
{
44+
"type": "text",
45+
"text": "This is a test."
46+
}
47+
],
48+
"stop_reason": "end_turn",
49+
"stop_sequence": null,
50+
"usage": {
51+
"input_tokens": 12,
52+
"output_tokens": 8
53+
}
54+
}
55+
headers:
56+
Connection:
57+
- keep-alive
58+
Content-Type:
59+
- application/json
60+
Date:
61+
- Thu, 06 Mar 2025 09:15:36 GMT
62+
Set-Cookie: test_set_cookie
63+
X-Amzn-Bedrock-Input-Token-Count:
64+
- '12'
65+
X-Amzn-Bedrock-Invocation-Latency:
66+
- '544'
67+
X-Amzn-Bedrock-Output-Token-Count:
68+
- '8'
69+
x-amzn-RequestId:
70+
- e97cb4f9-61fe-4a62-a29a-a582ddd17414
71+
status:
72+
code: 200
73+
message: OK
74+
version: 1

instrumentation/opentelemetry-instrumentation-botocore/tests/test_botocore_bedrock.py

+47
Original file line numberDiff line numberDiff line change
@@ -1256,6 +1256,53 @@ def test_invoke_model_with_content(
12561256
assert_message_in_logs(logs[1], "gen_ai.choice", choice_body, span)
12571257

12581258

1259+
@pytest.mark.vcr()
1260+
def test_invoke_model_with_content_user_content_as_string(
1261+
span_exporter,
1262+
log_exporter,
1263+
bedrock_runtime_client,
1264+
instrument_with_content,
1265+
):
1266+
llm_model_value = "us.anthropic.claude-3-5-sonnet-20240620-v1:0"
1267+
max_tokens = 10
1268+
body = json.dumps(
1269+
{
1270+
"messages": [{"role": "user", "content": "say this is a test"}],
1271+
"max_tokens": max_tokens,
1272+
"anthropic_version": "bedrock-2023-05-31",
1273+
}
1274+
)
1275+
response = bedrock_runtime_client.invoke_model(
1276+
body=body,
1277+
modelId=llm_model_value,
1278+
)
1279+
1280+
(span,) = span_exporter.get_finished_spans()
1281+
assert_completion_attributes_from_streaming_body(
1282+
span,
1283+
llm_model_value,
1284+
response,
1285+
"chat",
1286+
request_max_tokens=max_tokens,
1287+
)
1288+
1289+
logs = log_exporter.get_finished_logs()
1290+
assert len(logs) == 2
1291+
user_content = {"content": "say this is a test"}
1292+
assert_message_in_logs(logs[0], "gen_ai.user.message", user_content, span)
1293+
1294+
message = {
1295+
"role": "assistant",
1296+
"content": [{"type": "text", "text": "This is a test."}],
1297+
}
1298+
choice_body = {
1299+
"index": 0,
1300+
"finish_reason": "end_turn",
1301+
"message": message,
1302+
}
1303+
assert_message_in_logs(logs[1], "gen_ai.choice", choice_body, span)
1304+
1305+
12591306
@pytest.mark.parametrize(
12601307
"model_family",
12611308
["amazon.nova", "anthropic.claude"],

0 commit comments

Comments
 (0)