fix(ci): lock blocking interaction SDK for dependent checks

This commit is contained in:
fdc310
2026-10-31 13:59:02 +08:00
parent 07fcdb35b5
commit 27d4184bef
10 changed files with 260 additions and 202 deletions
+2 -2
View File
@@ -40,8 +40,8 @@ jobs:
- name: Install dependencies
run: uv sync --locked --dev
- name: Verify published SDK pin
run: uv run --no-sync python -c 'from importlib.metadata import version; assert version("langbot-plugin") == "0.7.4"; print("langbot-plugin", version("langbot-plugin"))'
- name: Verify SDK snapshot
run: uv run --no-sync python -c 'from importlib.metadata import version; assert version("langbot-plugin") == "0.7.19"; print("langbot-plugin", version("langbot-plugin"))'
- name: Prepare isolated certified coding Runner SDK environment
run: |
uv venv "$RUNNER_TEMP/coding-074"
@@ -453,24 +453,30 @@ class ClaudeCodeExternalTools(AgentRunExternalTools):
)
async def ask_user_question(self, args: AskUserQuestionArgs) -> dict[str, typing.Any]:
request, continuation = _interaction_from_claude_tool(
uuid.uuid4().hex, args.model_dump(mode='json', by_alias=True)
uuid.uuid4().hex, args.model_dump(mode="json", by_alias=True)
)
answers: list[dict[str, typing.Any]] = []
for field in request.fields:
step = request.model_copy(update={
'interaction_id': f'{request.interaction_id}-{field.id}'[:255],
'fields': [field],
'actions': [],
})
result = await self.ctx.request_interaction(step, timeout=3600, on_unsupported='degrade')
if result.status != 'submitted' or result.submission is None:
raise NativeCliError(f'User interaction {result.status}', code='claude_code.interaction_expired')
answers.append({
'id': field.id,
'question': next((item['question'] for item in continuation['questions'] if item['id'] == field.id), field.label),
'answer': result.submission.values.get(field.id),
})
return {'status': 'submitted', 'answers': answers}
step = request.model_copy(
update={
"interaction_id": f"{request.interaction_id}-{field.id}"[:255],
"fields": [field],
"actions": [],
}
)
result = await self.ctx.request_interaction(step, timeout=3600, on_unsupported="degrade")
if result.status != "submitted" or result.submission is None:
raise NativeCliError(f"User interaction {result.status}", code="claude_code.interaction_expired")
answers.append(
{
"id": field.id,
"question": next(
(item["question"] for item in continuation["questions"] if item["id"] == field.id), field.label
),
"answer": result.submission.values.get(field.id),
}
)
return {"status": "submitted", "answers": answers}
class NativeClaudeCodeRunner(Runner):
+36 -26
View File
@@ -1193,26 +1193,28 @@ class _CodexAppServerClient:
async def _wait_for_user(self, request: InteractionRequest) -> InteractionSubmission:
if self.ctx is None:
raise NativeCliError('No active run for interaction', code='codex.interaction_invalid')
raise NativeCliError("No active run for interaction", code="codex.interaction_invalid")
loop = asyncio.get_running_loop()
if self.timeout_scope is not None:
self.timeout_scope.reschedule(loop.time() + 3600 + self.operation_timeout)
try:
if request.actions and not request.fields:
result = await self.ctx.request_interaction(request, timeout=3600, on_unsupported='degrade')
if result.status != 'submitted' or result.submission is None:
raise NativeCliError(f'User interaction {result.status}', code='codex.interaction_expired')
result = await self.ctx.request_interaction(request, timeout=3600, on_unsupported="degrade")
if result.status != "submitted" or result.submission is None:
raise NativeCliError(f"User interaction {result.status}", code="codex.interaction_expired")
return result.submission
values: dict[str, typing.Any] = {}
for field in request.fields:
step = request.model_copy(update={
'interaction_id': f'{request.interaction_id}-{field.id}'[:255],
'fields': [field],
'actions': [],
})
result = await self.ctx.request_interaction(step, timeout=3600, on_unsupported='degrade')
if result.status != 'submitted' or result.submission is None:
raise NativeCliError(f'User interaction {result.status}', code='codex.interaction_expired')
step = request.model_copy(
update={
"interaction_id": f"{request.interaction_id}-{field.id}"[:255],
"fields": [field],
"actions": [],
}
)
result = await self.ctx.request_interaction(step, timeout=3600, on_unsupported="degrade")
if result.status != "submitted" or result.submission is None:
raise NativeCliError(f"User interaction {result.status}", code="codex.interaction_expired")
values[field.id] = result.submission.values.get(field.id)
return InteractionSubmission(interaction_id=request.interaction_id, values=values)
finally:
@@ -1400,9 +1402,9 @@ class _CodexAppServerClient:
request, continuation = _interaction_from_codex_approval(method, params, item)
if self.ctx is not None:
submission = await self._wait_for_user(request)
await self.respond(request_id, {
'decision': 'accept' if submission.action_id == APPROVE_ONCE_ACTION else 'cancel'
})
await self.respond(
request_id, {"decision": "accept" if submission.action_id == APPROVE_ONCE_ACTION else "cancel"}
)
return
self.interaction_request = request
self.interaction_continuation = continuation
@@ -1423,18 +1425,26 @@ class _CodexAppServerClient:
return
if self.ctx is not None:
submission = await self._wait_for_user(request)
if method == 'item/tool/call':
await self.respond(request_id, {
'success': True,
'contentItems': [{'type': 'inputText', 'text': json.dumps(submission.values, ensure_ascii=False)}],
})
if method == "item/tool/call":
await self.respond(
request_id,
{
"success": True,
"contentItems": [
{"type": "inputText", "text": json.dumps(submission.values, ensure_ascii=False)}
],
},
)
else:
await self.respond(request_id, {
'answers': {
field_id: {'answers': value if isinstance(value, list) else [str(value)]}
for field_id, value in submission.values.items()
}
})
await self.respond(
request_id,
{
"answers": {
field_id: {"answers": value if isinstance(value, list) else [str(value)]}
for field_id, value in submission.values.items()
}
},
)
return
self.interaction_request = request
self.interaction_continuation = continuation
@@ -908,41 +908,51 @@ class DefaultRunner(Runner):
return RunnerResult.interaction_requested(ctx.run_id, request)
async def _wait_and_resume_workflow(
self, ctx: RunnerContext, client: AsyncDifyClient,
event: dict[str, typing.Any], user: str, remove_think: bool,
self,
ctx: RunnerContext,
client: AsyncDifyClient,
event: dict[str, typing.Any],
user: str,
remove_think: bool,
) -> typing.AsyncGenerator[RunnerResult, None]:
reason = _human_input_reason(event)
if reason is None:
raise DifyAPIError('Dify paused without a supported human-input reason', code='dify.response_invalid')
raise DifyAPIError("Dify paused without a supported human-input reason", code="dify.response_invalid")
_, continuation = self._build_interaction_request(reason, _workflow_run_id(event), user)
while continuation['phase'] == 'field':
while continuation["phase"] == "field":
request = self._request_from_continuation(continuation)
result = await ctx.request_interaction(request, timeout=3600, on_unsupported='degrade')
if result.status != 'submitted' or result.submission is None:
raise DifyAPIError(f'Dify human input {result.status}', code='dify.interaction_expired')
field_map = continuation['field_map']
inputs = continuation['default_inputs']
result = await ctx.request_interaction(request, timeout=3600, on_unsupported="degrade")
if result.status != "submitted" or result.submission is None:
raise DifyAPIError(f"Dify human input {result.status}", code="dify.interaction_expired")
field_map = continuation["field_map"]
inputs = continuation["default_inputs"]
for field_id, value in result.submission.values.items():
if field_id in field_map:
inputs[field_map[field_id]] = value
current_field = InteractionField.model_validate(continuation['current_fields'][0])
current_field = InteractionField.model_validate(continuation["current_fields"][0])
provider_name = field_map.get(current_field.id)
if current_field.required and provider_name and inputs.get(provider_name) in (None, '', []):
raise DifyAPIError(f'Dify human-input field is required: {current_field.label}', code='dify.interaction_invalid')
remaining = continuation['remaining_fields']
continuation['interaction_id'] = f'dify-{uuid.uuid4().hex}'
if current_field.required and provider_name and inputs.get(provider_name) in (None, "", []):
raise DifyAPIError(
f"Dify human-input field is required: {current_field.label}", code="dify.interaction_invalid"
)
remaining = continuation["remaining_fields"]
continuation["interaction_id"] = f"dify-{uuid.uuid4().hex}"
if remaining:
continuation['current_fields'] = [remaining.pop(0)]
continuation["current_fields"] = [remaining.pop(0)]
else:
continuation['phase'] = 'action'
continuation['current_fields'] = []
continuation["phase"] = "action"
continuation["current_fields"] = []
request = self._request_from_continuation(continuation)
result = await ctx.request_interaction(request, timeout=3600, on_unsupported='degrade')
if result.status != 'submitted' or result.submission is None:
raise DifyAPIError(f'Dify human input {result.status}', code='dify.interaction_expired')
result = await ctx.request_interaction(request, timeout=3600, on_unsupported="degrade")
if result.status != "submitted" or result.submission is None:
raise DifyAPIError(f"Dify human input {result.status}", code="dify.interaction_expired")
async for item in self._resume_workflow_once(
ctx, client, result.submission, remove_think,
continuation=continuation, blocking=True,
ctx,
client,
result.submission,
remove_think,
continuation=continuation,
blocking=True,
):
yield item
@@ -1459,7 +1469,9 @@ class DefaultRunner(Runner):
blocking: bool = False,
) -> typing.AsyncGenerator[RunnerResult, None]:
interaction_id = str(submission.interaction_id)
continuation = continuation if continuation is not None else await self._load_interaction_continuation(ctx, interaction_id)
continuation = (
continuation if continuation is not None else await self._load_interaction_continuation(ctx, interaction_id)
)
if continuation.get("phase") == "field":
yield await self._advance_field_interaction(ctx, continuation, submission)
return
@@ -1560,17 +1572,23 @@ class DefaultRunner(Runner):
}
if blocking:
async for result in self._wait_and_resume_workflow(
ctx, client, event, str(continuation['user']), remove_think,
ctx,
client,
event,
str(continuation["user"]),
remove_think,
):
yield result
else:
interaction_result = await self._interaction_result_for_pause(
ctx, event, str(continuation['user']),
ctx,
event,
str(continuation["user"]),
)
if interaction_result is None:
raise DifyAPIError(
'Dify paused the workflow without a supported reason',
code='dify.response_invalid',
"Dify paused the workflow without a supported reason",
code="dify.response_invalid",
)
await self._delete_interaction_continuation(ctx, interaction_id)
yield interaction_result
+5 -1
View File
@@ -9,7 +9,7 @@ authors = [{ name = "LangBot Team" }]
keywords = ["langbot", "agent", "runner", "plugin"]
dependencies = [
"langbot-plugin==0.7.4",
"langbot-plugin==0.7.19",
"pydantic>=2.0.0",
]
@@ -24,6 +24,10 @@ dev = [
"tboxsdk>=0.0.12",
]
# Replace this source with the released SDK version before merging #2787.
[tool.uv.sources]
langbot-plugin = { git = "https://github.com/fdc310/langbot-plugin-sdk.git", rev = "42ef9c72a212d4398b3153a08550d22e4b7476cb" }
[tool.pytest.ini_options]
# LocalAgent and RunnerDemo run in fresh interpreters via tests/test_migrated_runners.py.
# Their generic pkg/components/tests imports must not share the external Runner process.
+37 -13
View File
@@ -17,8 +17,8 @@ from langbot_plugin.api.entities.builtin.runner import (
AgentRuntimeContext,
AgentTrigger,
DeliveryContext,
InteractionSubmission,
InteractionResult,
InteractionSubmission,
RunnerContext,
)
@@ -1252,7 +1252,7 @@ def _interaction_context(config, text, *, action_id=None, values=None):
async def request_interaction(request, **kwargs):
return InteractionResult(
status='submitted',
status="submitted",
submission=InteractionSubmission(
interaction_id=request.interaction_id,
action_id=action_id,
@@ -1280,12 +1280,20 @@ def test_codex_runner_answers_dynamic_question_in_live_turn(tmp_path: Path) -> N
"sandbox-mode": "read-only",
}
resumed = asyncio.run(_collect_async(runner.run(_interaction_context(
config, 'ASK_INTERACTION', values={'environment': 'production'},
))))
resumed = asyncio.run(
_collect_async(
runner.run(
_interaction_context(
config,
"ASK_INTERACTION",
values={"environment": "production"},
)
)
)
)
assert resumed[-1].type == "run.completed"
assert not any(item.type == 'action.requested' for item in resumed)
assert not any(item.type == "action.requested" for item in resumed)
assert any(
"production" in str(item.data.get("chunk", {}).get("content") or "")
for item in resumed
@@ -1309,12 +1317,20 @@ def test_codex_runner_approves_native_request_in_live_turn(tmp_path: Path) -> No
"sandbox-mode": "read-only",
}
resumed = asyncio.run(_collect_async(runner.run(_interaction_context(
config, 'TRIGGER_COMMAND_APPROVAL', action_id='approve_once',
))))
resumed = asyncio.run(
_collect_async(
runner.run(
_interaction_context(
config,
"TRIGGER_COMMAND_APPROVAL",
action_id="approve_once",
)
)
)
)
assert resumed[-1].type == "run.completed"
assert not any(item.type == 'action.requested' for item in resumed)
assert not any(item.type == "action.requested" for item in resumed)
assert any(
"APPROVAL_EXECUTED" in str(item.data.get("chunk", {}).get("content") or "")
for item in resumed
@@ -1337,9 +1353,17 @@ def test_codex_runner_rejects_native_request_in_live_turn(tmp_path: Path) -> Non
"approval-policy": "on-request",
"sandbox-mode": "read-only",
}
resumed = asyncio.run(_collect_async(runner.run(_interaction_context(
config, 'TRIGGER_COMMAND_APPROVAL', action_id='reject',
))))
resumed = asyncio.run(
_collect_async(
runner.run(
_interaction_context(
config,
"TRIGGER_COMMAND_APPROVAL",
action_id="reject",
)
)
)
)
assert resumed[-1].type == "run.completed"
assert any(
@@ -21,8 +21,8 @@ from langbot_plugin.api.entities.builtin.runner import (
AgentTrigger,
ConversationContext,
DeliveryContext,
InteractionSubmission,
InteractionResult,
InteractionSubmission,
RunnerContext,
)
@@ -100,11 +100,11 @@ def _dify_interaction_ctx():
async def request_interaction(request, **kwargs):
requests.append(request)
return InteractionResult(
status='submitted',
status="submitted",
submission=InteractionSubmission(
interaction_id=request.interaction_id,
action_id=request.actions[0].id if request.actions else None,
values={request.fields[0].id: 'high'} if request.fields else {},
values={request.fields[0].id: "high"} if request.fields else {},
),
)
@@ -252,24 +252,24 @@ def test_dify_workflow_pause_requests_host_interaction_and_hides_provider_tokens
}
async def workflow_submit(self, **kwargs):
assert kwargs['form_token'] == 'form-private'
assert kwargs['workflow_run_id'] == 'workflow-private'
assert kwargs['inputs']['priority'] == 'high'
assert kwargs['action'] == 'approve-private'
yield {'event': 'node_finished', 'data': {'node_type': 'answer', 'outputs': {'answer': 'Approved'}}}
yield {'event': 'workflow_finished', 'data': {'outputs': {}}}
assert kwargs["form_token"] == "form-private"
assert kwargs["workflow_run_id"] == "workflow-private"
assert kwargs["inputs"]["priority"] == "high"
assert kwargs["action"] == "approve-private"
yield {"event": "node_finished", "data": {"node_type": "answer", "outputs": {"answer": "Approved"}}}
yield {"event": "workflow_finished", "data": {"outputs": {}}}
ctx, requests = _dify_interaction_ctx()
results = asyncio.run(_collect_async(runner._run_workflow(ctx, FakeClient(), {}, "hello", "user_1", [], False)))
assert _type(results[0]) == "tool.call.started"
assert results[0].data["tool_name"] == "Manual review"
assert requests[0].fields[0].options[0].value == 'high'
assert requests[1].actions[0].label == 'Approve'
assert 'form-private' not in str(requests)
assert 'workflow-private' not in str(requests)
assert requests[0].fields[0].options[0].value == "high"
assert requests[1].actions[0].label == "Approve"
assert "form-private" not in str(requests)
assert "workflow-private" not in str(requests)
assert storage.values == {}
assert _type(results[-1]) == 'run.completed'
assert _type(results[-1]) == "run.completed"
def test_dify_current_human_input_event_requests_host_interaction() -> None:
@@ -299,18 +299,18 @@ def test_dify_current_human_input_event_requests_host_interaction() -> None:
}
async def workflow_submit(self, **kwargs):
assert kwargs['inputs']['priority'] == 'high'
yield {'event': 'node_finished', 'data': {'node_type': 'answer', 'outputs': {'answer': 'Approved'}}}
yield {'event': 'workflow_finished', 'data': {'outputs': {}}}
assert kwargs["inputs"]["priority"] == "high"
yield {"event": "node_finished", "data": {"node_type": "answer", "outputs": {"answer": "Approved"}}}
yield {"event": "workflow_finished", "data": {"outputs": {}}}
ctx, requests = _dify_interaction_ctx()
results = asyncio.run(_collect_async(runner._run_workflow(ctx, FakeClient(), {}, "hello", "user_1", [], False)))
assert _type(results[-1]) == 'run.completed'
assert requests[0].title == 'Manual review'
assert requests[0].fields[0].options[0].value == 'high'
assert 'form-private' not in str(requests)
assert 'workflow-private' not in str(requests)
assert _type(results[-1]) == "run.completed"
assert requests[0].title == "Manual review"
assert requests[0].fields[0].options[0].value == "high"
assert "form-private" not in str(requests)
assert "workflow-private" not in str(requests)
assert storage.values == {}
+4 -8
View File
@@ -1,5 +1,5 @@
version = 1
revision = 3
revision = 5
requires-python = ">=3.11, <4.0"
[[package]]
@@ -830,7 +830,7 @@ dev = [
[package.metadata]
requires-dist = [
{ name = "langbot-plugin", specifier = "==0.7.4" },
{ name = "langbot-plugin", git = "https://github.com/fdc310/langbot-plugin-sdk.git?rev=42ef9c72a212d4398b3153a08550d22e4b7476cb" },
{ name = "pydantic", specifier = ">=2.0.0" },
]
@@ -847,8 +847,8 @@ dev = [
[[package]]
name = "langbot-plugin"
version = "0.7.4"
source = { registry = "https://pypi.org/simple" }
version = "0.7.19"
source = { git = "https://github.com/fdc310/langbot-plugin-sdk.git?rev=42ef9c72a212d4398b3153a08550d22e4b7476cb#42ef9c72a212d4398b3153a08550d22e4b7476cb" }
dependencies = [
{ name = "aiofiles" },
{ name = "aiohttp" },
@@ -868,10 +868,6 @@ dependencies = [
{ name = "watchdog" },
{ name = "websockets" },
]
sdist = { url = "https://files.pythonhosted.org/packages/92/71/b4bed3cfe28ba7a24e1108465429d833c1f702e33fdbc0d31d7bea3587d9/langbot_plugin-0.7.4.tar.gz", hash = "sha256:af3a0bcb9711fd734af811c0e178d259ae4a0d3e45d25e844661aba3dd574f96", size = 673043, upload-time = "2026-09-28T10:43:41.289Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/f2/c7/c870377771cbe27e047b19778b5f249b15efef52409358901af94d13e6c0/langbot_plugin-0.7.4-py3-none-any.whl", hash = "sha256:596ecd776c13efa6f6cfe178463dc4a967653238548c9569195cdbb5aa47506e", size = 433419, upload-time = "2026-09-28T10:43:40.073Z" },
]
[[package]]
name = "linkify-it-py"
+4
View File
@@ -124,6 +124,10 @@ Repository = "https://github.com/langbot-app/LangBot"
[project.scripts]
langbot = "langbot.__main__:main"
# Replace this source with the released SDK version before merging #2787.
[tool.uv.sources]
langbot-plugin = { git = "https://github.com/fdc310/langbot-plugin-sdk.git", rev = "42ef9c72a212d4398b3153a08550d22e4b7476cb" }
[build-system]
requires = ["setuptools>=61.0", "wheel"]
build-backend = "setuptools.build_meta"
Generated
+84 -88
View File
@@ -1,5 +1,5 @@
version = 1
revision = 3
revision = 5
requires-python = ">=3.11, <4.0"
resolution-markers = [
"python_full_version >= '3.14' and sys_platform == 'win32'",
@@ -12,10 +12,10 @@ resolution-markers = [
"python_full_version == '3.12.*' and sys_platform == 'emscripten'",
"python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'",
"python_full_version >= '3.11.5' and python_full_version < '3.12' and sys_platform == 'win32'",
"python_full_version < '3.11.5' and sys_platform == 'win32'",
"python_full_version >= '3.11.5' and python_full_version < '3.12' and sys_platform == 'emscripten'",
"python_full_version < '3.11.5' and sys_platform == 'emscripten'",
"python_full_version >= '3.11.5' and python_full_version < '3.12' and sys_platform != 'emscripten' and sys_platform != 'win32'",
"python_full_version < '3.11.5' and sys_platform == 'win32'",
"python_full_version < '3.11.5' and sys_platform == 'emscripten'",
"python_full_version < '3.11.5' and sys_platform != 'emscripten' and sys_platform != 'win32'",
]
@@ -317,7 +317,7 @@ wheels = [
[package.optional-dependencies]
trio = [
{ name = "trio", marker = "sys_platform != 'win32'" },
{ name = "trio" },
]
[[package]]
@@ -1119,7 +1119,7 @@ name = "cuda-bindings"
version = "13.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cuda-pathfinder", marker = "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'" },
{ name = "cuda-pathfinder" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/51/6b/457ca12dad3ee9bfcc9a545cfd6b64b359ba49de40f776f6e028e678f262/cuda_bindings-13.3.1-cp311-cp311-manylinux_2_24_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c5879712accf6e14bb01aa5e67440eb84998b8d104b509cc7a6dc0b8f656a474", size = 6053539, upload-time = "2026-05-29T23:11:43.19Z" },
@@ -1152,43 +1152,43 @@ wheels = [
[package.optional-dependencies]
cublas = [
{ name = "nvidia-cublas", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-cuda-nvrtc", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-cublas", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
{ name = "nvidia-cuda-nvrtc", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
cudart = [
{ name = "nvidia-cuda-runtime", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-cuda-runtime", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
cufft = [
{ name = "nvidia-cufft", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-nvjitlink", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-cufft", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
{ name = "nvidia-nvjitlink", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
cufile = [
{ name = "nvidia-cufile", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-cufile", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
cupti = [
{ name = "nvidia-cuda-cupti", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-cuda-cupti", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
curand = [
{ name = "nvidia-curand", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-curand", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
cusolver = [
{ name = "nvidia-cublas", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-cusolver", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-cusparse", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-nvjitlink", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-cublas", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
{ name = "nvidia-cusolver", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
{ name = "nvidia-cusparse", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
{ name = "nvidia-nvjitlink", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
cusparse = [
{ name = "nvidia-cusparse", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-nvjitlink", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-cusparse", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
{ name = "nvidia-nvjitlink", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
nvjitlink = [
{ name = "nvidia-nvjitlink", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-nvjitlink", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
nvrtc = [
{ name = "nvidia-cuda-nvrtc", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-cuda-nvrtc", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
nvtx = [
{ name = "nvidia-nvtx", marker = "(python_full_version >= '3.14' and platform_machine == 'aarch64' and sys_platform == 'linux') or (python_full_version >= '3.14' and platform_machine == 'x86_64' and sys_platform == 'linux')" },
{ name = "nvidia-nvtx", marker = "platform_machine == 'aarch64' or platform_machine == 'x86_64'" },
]
[[package]]
@@ -2241,7 +2241,7 @@ requires-dist = [
{ name = "gewechat-client", specifier = ">=0.1.5" },
{ name = "html2text", specifier = ">=2024.2.26" },
{ name = "httpx", extras = ["socks"], specifier = ">=0.28.1" },
{ name = "langbot-plugin", specifier = "==0.7.19" },
{ name = "langbot-plugin", git = "https://github.com/fdc310/langbot-plugin-sdk.git?rev=42ef9c72a212d4398b3153a08550d22e4b7476cb" },
{ name = "langchain", specifier = ">=1.3.9" },
{ name = "langchain-core", specifier = ">=1.3.3" },
{ name = "langchain-text-splitters", specifier = ">=1.1.2" },
@@ -2312,7 +2312,7 @@ dev = [
[[package]]
name = "langbot-plugin"
version = "0.7.19"
source = { registry = "https://pypi.org/simple" }
source = { git = "https://github.com/fdc310/langbot-plugin-sdk.git?rev=42ef9c72a212d4398b3153a08550d22e4b7476cb#42ef9c72a212d4398b3153a08550d22e4b7476cb" }
dependencies = [
{ name = "aiofiles" },
{ name = "aiohttp" },
@@ -2332,10 +2332,6 @@ dependencies = [
{ name = "watchdog" },
{ name = "websockets" },
]
sdist = { url = "https://files.pythonhosted.org/packages/f5/23/ffce65a9c333a6545b47d8364bbd5083f6517292b95bdfffc7ac87b702c3/langbot_plugin-0.7.19.tar.gz", hash = "sha256:62a972592e2160dee963ecbfc4276719e43178e137273ea29af1a43152b8353e", size = 749638, upload-time = "2026-10-28T10:52:04.63Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/4c/99/e32e004c6869a40e63276440de3b31a8d22bf89a22a1ae1133f0233e55e3/langbot_plugin-0.7.19-py3-none-any.whl", hash = "sha256:a94037c766e0f4bc2f108edfa0e1c075fc28d480217b6794a652d2532be5ca1f", size = 474676, upload-time = "2026-10-28T10:52:02.788Z" },
]
[[package]]
name = "langchain"
@@ -3417,7 +3413,7 @@ name = "nvidia-cublas"
version = "13.1.1.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "nvidia-cuda-nvrtc", marker = "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'" },
{ name = "nvidia-cuda-nvrtc" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/a7/a1/0bd24ee8c8d03adac032fd2909426a00c88f8c57961b1277ded97f91119f/nvidia_cublas-13.1.1.3-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:b7a210458267ac818974c53038fbec2e969d5c99f305ab15c72522fa9f001dd5", size = 542848918, upload-time = "2026-04-08T18:46:22.985Z" },
@@ -3456,7 +3452,7 @@ name = "nvidia-cudnn-cu13"
version = "9.24.0.43"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "nvidia-cublas", marker = "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'" },
{ name = "nvidia-cublas" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/ca/30/7c257e3d5cb4fecb147b93895c66e29c93f8e76d74b45bb418ff0587c4ec/nvidia_cudnn_cu13-9.24.0.43-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:a6812a554a1ff0413e9c52b84c26c050380649ab9615f9c16bded368ce9f421f", size = 650976863, upload-time = "2026-07-02T16:23:39.248Z" },
@@ -3468,7 +3464,7 @@ name = "nvidia-cufft"
version = "12.0.0.61"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "nvidia-nvjitlink", marker = "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'" },
{ name = "nvidia-nvjitlink" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/8b/ae/f417a75c0259e85c1d2f83ca4e960289a5f814ed0cea74d18c353d3e989d/nvidia_cufft-12.0.0.61-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:2708c852ef8cd89d1d2068bdbece0aa188813a0c934db3779b9b1faa8442e5f5", size = 214053554, upload-time = "2025-09-04T08:31:38.196Z" },
@@ -3498,9 +3494,9 @@ name = "nvidia-cusolver"
version = "12.0.4.66"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "nvidia-cublas", marker = "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'" },
{ name = "nvidia-cusparse", marker = "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'" },
{ name = "nvidia-nvjitlink", marker = "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'" },
{ name = "nvidia-cublas" },
{ name = "nvidia-cusparse" },
{ name = "nvidia-nvjitlink" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/c8/c3/b30c9e935fc01e3da443ec0116ed1b2a009bb867f5324d3f2d7e533e776b/nvidia_cusolver-12.0.4.66-py3-none-manylinux_2_27_aarch64.whl", hash = "sha256:02c2457eaa9e39de20f880f4bd8820e6a1cfb9f9a34f820eb12a155aa5bc92d2", size = 223467760, upload-time = "2025-09-04T08:33:04.222Z" },
@@ -3512,7 +3508,7 @@ name = "nvidia-cusparse"
version = "12.6.3.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "nvidia-nvjitlink", marker = "python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'" },
{ name = "nvidia-nvjitlink" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/f8/94/5c26f33738ae35276672f12615a64bd008ed5be6d1ebcb23579285d960a9/nvidia_cusparse-12.6.3.3-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:80bcc4662f23f1054ee334a15c72b8940402975e0eab63178fc7e670aa59472c", size = 162155568, upload-time = "2025-09-04T08:33:42.864Z" },
@@ -3852,7 +3848,7 @@ name = "outcome"
version = "1.3.0.post0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "attrs", marker = "sys_platform != 'win32'" },
{ name = "attrs" },
]
sdist = { url = "https://files.pythonhosted.org/packages/98/df/77698abfac98571e65ffeb0c1fba8ffd692ab8458d617a0eed7d9a8d38f2/outcome-1.3.0.post0.tar.gz", hash = "sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8", size = 21060, upload-time = "2023-10-26T04:26:04.361Z" }
wheels = [
@@ -4616,7 +4612,7 @@ name = "pylibseekdb"
version = "1.4.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pymysql", marker = "sys_platform != 'emscripten' and sys_platform != 'win32'" },
{ name = "pymysql" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/ae/a8/7413d33218aff55a14ec9d20532b49243ffd0579e7a92244922c1885444e/pylibseekdb-1.4.0-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:5cb2efab9f1321cdb4b034d3a2bd92e41a402fc95e7dc9579c7473a426f96e24", size = 52173499, upload-time = "2026-08-27T13:05:09.347Z" },
@@ -5398,10 +5394,10 @@ name = "scikit-learn"
version = "1.8.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "joblib", marker = "python_full_version >= '3.14'" },
{ name = "numpy", marker = "python_full_version >= '3.14'" },
{ name = "scipy", marker = "python_full_version >= '3.14'" },
{ name = "threadpoolctl", marker = "python_full_version >= '3.14'" },
{ name = "joblib" },
{ name = "numpy" },
{ name = "scipy" },
{ name = "threadpoolctl" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0e/d4/40988bf3b8e34feec1d0e6a051446b1f66225f8529b9309becaeef62b6c4/scikit_learn-1.8.0.tar.gz", hash = "sha256:9bccbb3b40e3de10351f8f5068e105d0f4083b1a65fa07b6634fbc401a6287fd", size = 7335585, upload-time = "2025-12-10T07:08:53.618Z" }
wheels = [
@@ -5448,7 +5444,7 @@ name = "scipy"
version = "1.17.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "numpy", marker = "python_full_version >= '3.14'" },
{ name = "numpy" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" }
wheels = [
@@ -5519,15 +5515,15 @@ name = "sentence-transformers"
version = "6.2.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "huggingface-hub", marker = "python_full_version >= '3.14'" },
{ name = "numpy", marker = "python_full_version >= '3.14'" },
{ name = "scikit-learn", marker = "python_full_version >= '3.14'" },
{ name = "scipy", marker = "python_full_version >= '3.14'" },
{ name = "tokenizers", version = "0.23.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.14'" },
{ name = "torch", marker = "python_full_version >= '3.14'" },
{ name = "tqdm", marker = "python_full_version >= '3.14'" },
{ name = "transformers", marker = "python_full_version >= '3.14'" },
{ name = "typing-extensions", marker = "python_full_version >= '3.14'" },
{ name = "huggingface-hub" },
{ name = "numpy" },
{ name = "scikit-learn" },
{ name = "scipy" },
{ name = "tokenizers", version = "0.23.3", source = { registry = "https://pypi.org/simple" } },
{ name = "torch" },
{ name = "tqdm" },
{ name = "transformers" },
{ name = "typing-extensions" },
]
sdist = { url = "https://files.pythonhosted.org/packages/7f/66/635443b9b1d7ea618c4699c8ad4c43b022ceac0c0a1dc4404b7597b38754/sentence_transformers-6.2.0.tar.gz", hash = "sha256:1e3cd8796ab7bcad4cfa2f51e2083d8b37b15d6b68e6fa6b91a147c67380574d", size = 600810, upload-time = "2026-10-21T12:26:50.404Z" }
wheels = [
@@ -5873,14 +5869,14 @@ resolution-markers = [
"python_full_version == '3.12.*' and sys_platform == 'emscripten'",
"python_full_version == '3.12.*' and sys_platform != 'emscripten' and sys_platform != 'win32'",
"python_full_version >= '3.11.5' and python_full_version < '3.12' and sys_platform == 'win32'",
"python_full_version < '3.11.5' and sys_platform == 'win32'",
"python_full_version >= '3.11.5' and python_full_version < '3.12' and sys_platform == 'emscripten'",
"python_full_version < '3.11.5' and sys_platform == 'emscripten'",
"python_full_version >= '3.11.5' and python_full_version < '3.12' and sys_platform != 'emscripten' and sys_platform != 'win32'",
"python_full_version < '3.11.5' and sys_platform == 'win32'",
"python_full_version < '3.11.5' and sys_platform == 'emscripten'",
"python_full_version < '3.11.5' and sys_platform != 'emscripten' and sys_platform != 'win32'",
]
dependencies = [
{ name = "huggingface-hub", marker = "python_full_version < '3.14'" },
{ name = "huggingface-hub" },
]
sdist = { url = "https://files.pythonhosted.org/packages/73/6f/f80cfef4a312e1fb34baf7d85c72d4411afde10978d4657f8cdd811d3ccc/tokenizers-0.22.2.tar.gz", hash = "sha256:473b83b915e547aa366d1eee11806deaf419e17be16310ac0a14077f1e28f917", size = 372115, upload-time = "2026-01-05T10:45:15.988Z" }
wheels = [
@@ -5911,7 +5907,7 @@ resolution-markers = [
"python_full_version >= '3.14' and sys_platform != 'emscripten' and sys_platform != 'win32'",
]
dependencies = [
{ name = "huggingface-hub", marker = "python_full_version >= '3.14'" },
{ name = "huggingface-hub" },
]
sdist = { url = "https://files.pythonhosted.org/packages/e0/7c/2cabb2174e772636683008f2c5621949b645da7d303c596589e84516a184/tokenizers-0.23.3.tar.gz", hash = "sha256:cded33237c77caeef62944d32aa9a7ef42bdce2b3497e18d137e072a8c4be438", size = 385286, upload-time = "2026-10-09T10:16:55.759Z" }
wheels = [
@@ -5999,20 +5995,20 @@ name = "torch"
version = "2.14.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "cuda-bindings", marker = "python_full_version == '3.14.*' and sys_platform == 'linux'" },
{ name = "cuda-toolkit", extra = ["cublas", "cudart", "cufft", "cufile", "cupti", "curand", "cusolver", "cusparse", "nvjitlink", "nvrtc", "nvtx"], marker = "python_full_version >= '3.14' and sys_platform == 'linux'" },
{ name = "filelock", marker = "python_full_version >= '3.14'" },
{ name = "fsspec", marker = "python_full_version >= '3.14'" },
{ name = "jinja2", marker = "python_full_version >= '3.14'" },
{ name = "networkx", marker = "python_full_version >= '3.14'" },
{ name = "nvidia-cudnn-cu13", marker = "python_full_version >= '3.14' and sys_platform == 'linux'" },
{ name = "nvidia-cusparselt-cu13", marker = "python_full_version >= '3.14' and sys_platform == 'linux'" },
{ name = "nvidia-nccl-cu13", marker = "python_full_version >= '3.14' and sys_platform == 'linux'" },
{ name = "nvidia-nvshmem-cu13", marker = "python_full_version >= '3.14' and sys_platform == 'linux'" },
{ name = "setuptools", marker = "python_full_version >= '3.14'" },
{ name = "sympy", marker = "python_full_version >= '3.14'" },
{ name = "triton", marker = "python_full_version == '3.14.*' and sys_platform == 'linux'" },
{ name = "typing-extensions", marker = "python_full_version >= '3.14'" },
{ name = "cuda-bindings", marker = "python_full_version < '3.15' and sys_platform == 'linux'" },
{ name = "cuda-toolkit", extra = ["cublas", "cudart", "cufft", "cufile", "cupti", "curand", "cusolver", "cusparse", "nvjitlink", "nvrtc", "nvtx"], marker = "sys_platform == 'linux'" },
{ name = "filelock" },
{ name = "fsspec" },
{ name = "jinja2" },
{ name = "networkx" },
{ name = "nvidia-cudnn-cu13", marker = "sys_platform == 'linux'" },
{ name = "nvidia-cusparselt-cu13", marker = "sys_platform == 'linux'" },
{ name = "nvidia-nccl-cu13", marker = "sys_platform == 'linux'" },
{ name = "nvidia-nvshmem-cu13", marker = "sys_platform == 'linux'" },
{ name = "setuptools" },
{ name = "sympy" },
{ name = "triton", marker = "python_full_version < '3.15' and sys_platform == 'linux'" },
{ name = "typing-extensions" },
]
wheels = [
{ url = "https://files.pythonhosted.org/packages/5d/9b/fd1cd143a7bda5abc1fc352ed7b431f6f52aa3c454293211a33656db2cb5/torch-2.14.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:b6074b130fd26bc50f5d171f07dfed70db22dd0c354ab34767729249f9e0f042", size = 127281154, upload-time = "2026-09-30T17:43:58.328Z" },
@@ -6054,15 +6050,15 @@ name = "transformers"
version = "5.20.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "huggingface-hub", marker = "python_full_version >= '3.14'" },
{ name = "numpy", marker = "python_full_version >= '3.14'" },
{ name = "packaging", marker = "python_full_version >= '3.14'" },
{ name = "pyyaml", marker = "python_full_version >= '3.14'" },
{ name = "regex", marker = "python_full_version >= '3.14'" },
{ name = "safetensors", marker = "python_full_version >= '3.14'" },
{ name = "tokenizers", version = "0.23.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.14'" },
{ name = "tqdm", marker = "python_full_version >= '3.14'" },
{ name = "typer", marker = "python_full_version >= '3.14'" },
{ name = "huggingface-hub" },
{ name = "numpy" },
{ name = "packaging" },
{ name = "pyyaml" },
{ name = "regex" },
{ name = "safetensors" },
{ name = "tokenizers", version = "0.23.3", source = { registry = "https://pypi.org/simple" } },
{ name = "tqdm" },
{ name = "typer" },
]
sdist = { url = "https://files.pythonhosted.org/packages/8c/4e/3cd6f08cc84ee612d40f3cdb1649475e7c997f2d5cbd95ade8780708af62/transformers-5.20.2.tar.gz", hash = "sha256:080871e061546d720be57f5846fce426f46b44d61574907cc7404c2cba49d180", size = 10225379, upload-time = "2026-10-19T17:46:03.092Z" }
wheels = [
@@ -6074,12 +6070,12 @@ name = "trio"
version = "0.34.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "attrs", marker = "sys_platform != 'win32'" },
{ name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt' and sys_platform != 'win32'" },
{ name = "idna", marker = "sys_platform != 'win32'" },
{ name = "outcome", marker = "sys_platform != 'win32'" },
{ name = "sniffio", marker = "sys_platform != 'win32'" },
{ name = "sortedcontainers", marker = "sys_platform != 'win32'" },
{ name = "attrs" },
{ name = "cffi", marker = "implementation_name != 'pypy' and os_name == 'nt'" },
{ name = "idna" },
{ name = "outcome" },
{ name = "sniffio" },
{ name = "sortedcontainers" },
]
sdist = { url = "https://files.pythonhosted.org/packages/92/dc/a2d25ed73ad49cfd79bf18d262577c3731c98e382284e28d522f49a0df35/trio-0.34.0.tar.gz", hash = "sha256:63b9485408bdfdde544fced107045a8c0086cdc4bd0ef2f797b9e0dd111b964b", size = 607457, upload-time = "2026-08-11T00:33:42.198Z" }
wheels = [
@@ -6327,10 +6323,10 @@ name = "valkey-glide"
version = "2.5.3"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "anyio", extra = ["trio"], marker = "sys_platform != 'win32'" },
{ name = "cffi", marker = "sys_platform != 'win32'" },
{ name = "protobuf", marker = "sys_platform != 'win32'" },
{ name = "sniffio", marker = "sys_platform != 'win32'" },
{ name = "anyio", extra = ["trio"] },
{ name = "cffi" },
{ name = "protobuf" },
{ name = "sniffio" },
]
sdist = { url = "https://files.pythonhosted.org/packages/b0/d8/ed10fa0fe319daf0651c69221372b8523cfa865df5b9b1040c9a9a41b518/valkey_glide-2.5.3.tar.gz", hash = "sha256:ce3da1a0a927631385d6bc0a1ac8ab4e8e2efa9f41404bf54bbcf82904f3ea98", size = 1012668, upload-time = "2026-09-25T02:10:19.611Z" }
wheels = [