hedit 0.7.11.dev6__tar.gz → 0.7.11.dev7__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.
- {hedit-0.7.11.dev6/hedit.egg-info → hedit-0.7.11.dev7}/PKG-INFO +1 -1
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7/hedit.egg-info}/PKG-INFO +1 -1
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/pyproject.toml +1 -1
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/api/main.py +10 -1
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/version.py +1 -1
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_api_endpoints.py +81 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/LICENSE +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/PKG_README.md +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/README.md +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/hedit.egg-info/SOURCES.txt +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/hedit.egg-info/dependency_links.txt +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/hedit.egg-info/entry_points.txt +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/hedit.egg-info/requires.txt +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/hedit.egg-info/top_level.txt +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/setup.cfg +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/__init__.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/agents/__init__.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/agents/annotation_agent.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/agents/assessment_agent.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/agents/evaluation_agent.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/agents/feedback_summarizer.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/agents/feedback_triage_agent.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/agents/state.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/agents/validation_agent.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/agents/vision_agent.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/agents/workflow.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/api/__init__.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/api/models.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/api/security.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/cli/__init__.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/cli/api_executor.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/cli/client.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/cli/commands/__init__.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/cli/commands/lsp.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/cli/config.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/cli/executor.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/cli/local_executor.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/cli/main.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/cli/output.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/data/__init__.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/data/hed-docs/02_Terminology.md +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/data/hed-docs/HedAnnotationSemantics.md +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/data/hed-docs/manifest.json +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/lsp/__init__.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/lsp/client.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/lsp/daemon.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/lsp/protocol.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/scripts/__init__.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/scripts/process_feedback.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/telemetry/__init__.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/telemetry/collector.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/telemetry/schema.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/telemetry/storage.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/utils/__init__.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/utils/anthropic_llm.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/utils/error_remediation.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/utils/github_client.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/utils/hed_comprehensive_guide.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/utils/hed_docs_loader.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/utils/image_processing.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/utils/json_schema_loader.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/utils/llm_usage.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/utils/schema_loader.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/validation/__init__.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/validation/hed_lsp.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/src/validation/hed_validator.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_annotation_agent.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_anthropic_llm.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_cli_client.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_cli_config.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_cli_integration.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_cli_main.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_cli_usage_report.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_comprehensive_guide.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_error_remediation.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_feedback_integration.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_feedback_triage.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_fetch_hed_docs.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_github_client.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_hed_docs_loader.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_integration_anthropic.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_json_schema_loader.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_llm_usage.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_no_extend_propagation.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_schema_loader.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_security.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_state.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_telemetry.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_validation.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_validation_agent.py +0 -0
- {hedit-0.7.11.dev6 → hedit-0.7.11.dev7}/tests/test_version.py +0 -0
|
@@ -82,6 +82,11 @@ def _describe_llm_error(exc: Exception) -> tuple[int, str, str]:
|
|
|
82
82
|
key gets a 401 pointing at their key, not a generic 500. Order matters --
|
|
83
83
|
AnthropicContextOverflowError subclasses BadRequestError, and the timeout
|
|
84
84
|
and rate-limit types must be checked before their parent classes.
|
|
85
|
+
|
|
86
|
+
Every message here is a fixed string. Exception text never reaches the
|
|
87
|
+
client, because a provider error can carry request details and the web app
|
|
88
|
+
renders the message as HTML. Callers log the exception, so the provider's
|
|
89
|
+
own wording stays available in the server log for whoever debugs it.
|
|
85
90
|
"""
|
|
86
91
|
if isinstance(exc, APITimeoutError):
|
|
87
92
|
return 504, "timeout", "LLM request timed out. Try again or use a faster model."
|
|
@@ -98,7 +103,11 @@ def _describe_llm_error(exc: Exception) -> tuple[int, str, str]:
|
|
|
98
103
|
if isinstance(exc, AnthropicContextOverflowError):
|
|
99
104
|
return 413, "context_overflow", "The input is too long for this model. Try shortening it."
|
|
100
105
|
if isinstance(exc, anthropic.BadRequestError):
|
|
101
|
-
return
|
|
106
|
+
return (
|
|
107
|
+
400,
|
|
108
|
+
"bad_request",
|
|
109
|
+
"The LLM rejected the request. Check the model and request parameters, then try again.",
|
|
110
|
+
)
|
|
102
111
|
if isinstance(exc, anthropic.APIConnectionError):
|
|
103
112
|
return 502, "upstream_unreachable", "Could not reach the LLM service. Please try again."
|
|
104
113
|
return 500, "internal", "An error occurred during annotation processing."
|
|
@@ -1469,3 +1469,84 @@ class TestMetricsEndpoint:
|
|
|
1469
1469
|
)
|
|
1470
1470
|
assert response.status_code == 403
|
|
1471
1471
|
assert "server API key" in response.json()["detail"]
|
|
1472
|
+
|
|
1473
|
+
|
|
1474
|
+
class TestLLMErrorMessages:
|
|
1475
|
+
"""Error responses classify the failure without quoting the provider.
|
|
1476
|
+
|
|
1477
|
+
CodeQL flagged the streaming error path (py/stack-trace-exposure) because
|
|
1478
|
+
exception text reached the client. The web app renders these messages as
|
|
1479
|
+
HTML, and a provider error can echo request details, so every branch has
|
|
1480
|
+
to return a fixed string.
|
|
1481
|
+
"""
|
|
1482
|
+
|
|
1483
|
+
@staticmethod
|
|
1484
|
+
def _response(status: int):
|
|
1485
|
+
import httpx
|
|
1486
|
+
|
|
1487
|
+
request = httpx.Request("POST", "https://api.anthropic.com/v1/messages")
|
|
1488
|
+
return httpx.Response(status, request=request)
|
|
1489
|
+
|
|
1490
|
+
def test_bad_request_does_not_quote_the_provider(self):
|
|
1491
|
+
import anthropic
|
|
1492
|
+
|
|
1493
|
+
from src.api.main import _describe_llm_error
|
|
1494
|
+
|
|
1495
|
+
detail = (
|
|
1496
|
+
"Error code: 400 - thinking.type.enabled is not supported for this model; "
|
|
1497
|
+
"workspace wrkspc_01Rayuq1JvjaMYusRvUsn6vk"
|
|
1498
|
+
)
|
|
1499
|
+
exc = anthropic.BadRequestError(detail, response=self._response(400), body=None)
|
|
1500
|
+
|
|
1501
|
+
status, error_type, message = _describe_llm_error(exc)
|
|
1502
|
+
|
|
1503
|
+
assert status == 400
|
|
1504
|
+
assert error_type == "bad_request"
|
|
1505
|
+
assert "wrkspc_01Rayuq1JvjaMYusRvUsn6vk" not in message
|
|
1506
|
+
assert "thinking.type.enabled" not in message
|
|
1507
|
+
assert "Error code" not in message
|
|
1508
|
+
|
|
1509
|
+
def test_context_overflow_still_precedes_bad_request(self):
|
|
1510
|
+
from langchain_anthropic.chat_models import AnthropicContextOverflowError
|
|
1511
|
+
|
|
1512
|
+
from src.api.main import _describe_llm_error
|
|
1513
|
+
|
|
1514
|
+
exc = AnthropicContextOverflowError(
|
|
1515
|
+
"prompt is too long: 250000 tokens > 200000 maximum",
|
|
1516
|
+
response=self._response(400),
|
|
1517
|
+
body=None,
|
|
1518
|
+
)
|
|
1519
|
+
|
|
1520
|
+
status, error_type, _message = _describe_llm_error(exc)
|
|
1521
|
+
|
|
1522
|
+
assert status == 413
|
|
1523
|
+
assert error_type == "context_overflow"
|
|
1524
|
+
|
|
1525
|
+
def test_auth_failure_points_at_the_key(self):
|
|
1526
|
+
import anthropic
|
|
1527
|
+
|
|
1528
|
+
from src.api.main import _describe_llm_error
|
|
1529
|
+
|
|
1530
|
+
exc = anthropic.AuthenticationError(
|
|
1531
|
+
"invalid x-api-key sk-ant-api03-secretmaterial",
|
|
1532
|
+
response=self._response(401),
|
|
1533
|
+
body=None,
|
|
1534
|
+
)
|
|
1535
|
+
|
|
1536
|
+
status, error_type, message = _describe_llm_error(exc)
|
|
1537
|
+
|
|
1538
|
+
assert status == 401
|
|
1539
|
+
assert error_type == "auth"
|
|
1540
|
+
assert "sk-ant-api03-secretmaterial" not in message
|
|
1541
|
+
|
|
1542
|
+
def test_unknown_failure_is_generic(self):
|
|
1543
|
+
from src.api.main import _describe_llm_error
|
|
1544
|
+
|
|
1545
|
+
status, error_type, message = _describe_llm_error(
|
|
1546
|
+
RuntimeError("Traceback (most recent call last): File /srv/hedit/main.py")
|
|
1547
|
+
)
|
|
1548
|
+
|
|
1549
|
+
assert status == 500
|
|
1550
|
+
assert error_type == "internal"
|
|
1551
|
+
assert "Traceback" not in message
|
|
1552
|
+
assert "/srv/hedit" not in message
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|