inspect-ai 0.3.103__py3-none-any.whl → 0.3.105__py3-none-any.whl
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.
- inspect_ai/_cli/common.py +2 -1
- inspect_ai/_cli/eval.py +2 -2
- inspect_ai/_display/core/active.py +3 -0
- inspect_ai/_display/core/config.py +1 -0
- inspect_ai/_display/core/panel.py +21 -13
- inspect_ai/_display/core/results.py +3 -7
- inspect_ai/_display/core/rich.py +3 -5
- inspect_ai/_display/log/__init__.py +0 -0
- inspect_ai/_display/log/display.py +173 -0
- inspect_ai/_display/plain/display.py +2 -2
- inspect_ai/_display/rich/display.py +2 -4
- inspect_ai/_display/textual/app.py +1 -6
- inspect_ai/_display/textual/widgets/task_detail.py +3 -14
- inspect_ai/_display/textual/widgets/tasks.py +1 -1
- inspect_ai/_eval/eval.py +1 -1
- inspect_ai/_eval/evalset.py +3 -3
- inspect_ai/_eval/registry.py +6 -1
- inspect_ai/_eval/run.py +5 -1
- inspect_ai/_eval/task/constants.py +1 -0
- inspect_ai/_eval/task/log.py +2 -0
- inspect_ai/_eval/task/run.py +65 -39
- inspect_ai/_util/citation.py +88 -0
- inspect_ai/_util/content.py +24 -2
- inspect_ai/_util/json.py +17 -2
- inspect_ai/_util/registry.py +19 -4
- inspect_ai/_view/schema.py +0 -6
- inspect_ai/_view/server.py +17 -0
- inspect_ai/_view/www/dist/assets/index.css +93 -31
- inspect_ai/_view/www/dist/assets/index.js +10639 -10011
- inspect_ai/_view/www/log-schema.json +418 -1
- inspect_ai/_view/www/node_modules/flatted/python/flatted.py +149 -0
- inspect_ai/_view/www/node_modules/katex/src/fonts/generate_fonts.py +58 -0
- inspect_ai/_view/www/node_modules/katex/src/metrics/extract_tfms.py +114 -0
- inspect_ai/_view/www/node_modules/katex/src/metrics/extract_ttfs.py +122 -0
- inspect_ai/_view/www/node_modules/katex/src/metrics/format_json.py +28 -0
- inspect_ai/_view/www/node_modules/katex/src/metrics/parse_tfm.py +211 -0
- inspect_ai/_view/www/package.json +2 -2
- inspect_ai/_view/www/src/@types/log.d.ts +140 -39
- inspect_ai/_view/www/src/app/content/RecordTree.tsx +13 -0
- inspect_ai/_view/www/src/app/log-view/LogView.tsx +1 -1
- inspect_ai/_view/www/src/app/routing/logNavigation.ts +31 -0
- inspect_ai/_view/www/src/app/routing/{navigationHooks.ts → sampleNavigation.ts} +39 -86
- inspect_ai/_view/www/src/app/samples/SampleDialog.tsx +1 -1
- inspect_ai/_view/www/src/app/samples/SampleDisplay.tsx +1 -1
- inspect_ai/_view/www/src/app/samples/chat/ChatMessage.module.css +4 -0
- inspect_ai/_view/www/src/app/samples/chat/ChatMessage.tsx +17 -0
- inspect_ai/_view/www/src/app/samples/chat/MessageCitations.module.css +16 -0
- inspect_ai/_view/www/src/app/samples/chat/MessageCitations.tsx +63 -0
- inspect_ai/_view/www/src/app/samples/chat/MessageContent.module.css +6 -0
- inspect_ai/_view/www/src/app/samples/chat/MessageContent.tsx +174 -25
- inspect_ai/_view/www/src/app/samples/chat/MessageContents.tsx +21 -3
- inspect_ai/_view/www/src/app/samples/chat/content-data/ContentDataView.module.css +7 -0
- inspect_ai/_view/www/src/app/samples/chat/content-data/ContentDataView.tsx +111 -0
- inspect_ai/_view/www/src/app/samples/chat/content-data/WebSearch.module.css +10 -0
- inspect_ai/_view/www/src/app/samples/chat/content-data/WebSearch.tsx +14 -0
- inspect_ai/_view/www/src/app/samples/chat/content-data/WebSearchResults.module.css +19 -0
- inspect_ai/_view/www/src/app/samples/chat/content-data/WebSearchResults.tsx +49 -0
- inspect_ai/_view/www/src/app/samples/chat/messages.ts +7 -1
- inspect_ai/_view/www/src/app/samples/chat/tools/ToolCallView.tsx +12 -2
- inspect_ai/_view/www/src/app/samples/chat/types.ts +4 -0
- inspect_ai/_view/www/src/app/samples/list/SampleList.tsx +1 -1
- inspect_ai/_view/www/src/app/samples/sample-tools/filters.ts +26 -0
- inspect_ai/_view/www/src/app/samples/sample-tools/sample-filter/SampleFilter.tsx +14 -3
- inspect_ai/_view/www/src/app/samples/sample-tools/sample-filter/completions.ts +359 -7
- inspect_ai/_view/www/src/app/samples/sample-tools/sample-filter/language.ts +6 -0
- inspect_ai/_view/www/src/app/samples/sampleLimit.ts +2 -2
- inspect_ai/_view/www/src/app/samples/transcript/ModelEventView.tsx +1 -1
- inspect_ai/_view/www/src/app/samples/transcript/SampleLimitEventView.tsx +4 -4
- inspect_ai/_view/www/src/app/samples/transcript/outline/OutlineRow.tsx +1 -1
- inspect_ai/_view/www/src/app/samples/transcript/outline/TranscriptOutline.tsx +1 -1
- inspect_ai/_view/www/src/client/api/api-browser.ts +25 -0
- inspect_ai/_view/www/src/client/api/api-http.ts +3 -0
- inspect_ai/_view/www/src/client/api/api-vscode.ts +6 -0
- inspect_ai/_view/www/src/client/api/client-api.ts +3 -0
- inspect_ai/_view/www/src/client/api/jsonrpc.ts +1 -0
- inspect_ai/_view/www/src/client/api/types.ts +3 -0
- inspect_ai/_view/www/src/components/MarkdownDiv.tsx +15 -2
- inspect_ai/_view/www/src/state/samplePolling.ts +17 -1
- inspect_ai/_view/www/src/tests/README.md +2 -2
- inspect_ai/_view/www/src/utils/git.ts +3 -1
- inspect_ai/_view/www/src/utils/html.ts +6 -0
- inspect_ai/agent/_handoff.py +8 -5
- inspect_ai/agent/_react.py +5 -5
- inspect_ai/dataset/_dataset.py +1 -1
- inspect_ai/log/_condense.py +5 -0
- inspect_ai/log/_file.py +4 -1
- inspect_ai/log/_log.py +9 -4
- inspect_ai/log/_recorders/json.py +4 -2
- inspect_ai/log/_samples.py +5 -0
- inspect_ai/log/_util.py +2 -0
- inspect_ai/model/__init__.py +14 -0
- inspect_ai/model/_call_tools.py +17 -8
- inspect_ai/model/_chat_message.py +3 -0
- inspect_ai/model/_openai_responses.py +80 -34
- inspect_ai/model/_providers/_anthropic_citations.py +158 -0
- inspect_ai/model/_providers/_google_citations.py +100 -0
- inspect_ai/model/_providers/anthropic.py +219 -36
- inspect_ai/model/_providers/google.py +98 -22
- inspect_ai/model/_providers/mistral.py +20 -7
- inspect_ai/model/_providers/openai.py +11 -10
- inspect_ai/model/_providers/openai_compatible.py +3 -2
- inspect_ai/model/_providers/openai_responses.py +2 -5
- inspect_ai/model/_providers/perplexity.py +123 -0
- inspect_ai/model/_providers/providers.py +13 -2
- inspect_ai/model/_providers/vertex.py +3 -0
- inspect_ai/model/_trim.py +5 -0
- inspect_ai/tool/__init__.py +14 -0
- inspect_ai/tool/_mcp/_mcp.py +5 -2
- inspect_ai/tool/_mcp/sampling.py +19 -3
- inspect_ai/tool/_mcp/server.py +1 -1
- inspect_ai/tool/_tool.py +10 -1
- inspect_ai/tool/_tools/_web_search/_base_http_provider.py +104 -0
- inspect_ai/tool/_tools/_web_search/_exa.py +78 -0
- inspect_ai/tool/_tools/_web_search/_google.py +22 -25
- inspect_ai/tool/_tools/_web_search/_tavily.py +47 -65
- inspect_ai/tool/_tools/_web_search/_web_search.py +83 -36
- inspect_ai/tool/_tools/_web_search/_web_search_provider.py +7 -0
- inspect_ai/util/__init__.py +8 -0
- inspect_ai/util/_background.py +64 -0
- inspect_ai/util/_display.py +11 -2
- inspect_ai/util/_limit.py +72 -5
- inspect_ai/util/_sandbox/__init__.py +2 -0
- inspect_ai/util/_sandbox/docker/compose.py +2 -2
- inspect_ai/util/_sandbox/service.py +28 -7
- inspect_ai/util/_span.py +12 -1
- inspect_ai/util/_subprocess.py +51 -38
- {inspect_ai-0.3.103.dist-info → inspect_ai-0.3.105.dist-info}/METADATA +2 -2
- {inspect_ai-0.3.103.dist-info → inspect_ai-0.3.105.dist-info}/RECORD +134 -109
- /inspect_ai/model/{_openai_computer_use.py → _providers/_openai_computer_use.py} +0 -0
- /inspect_ai/model/{_openai_web_search.py → _providers/_openai_web_search.py} +0 -0
- {inspect_ai-0.3.103.dist-info → inspect_ai-0.3.105.dist-info}/WHEEL +0 -0
- {inspect_ai-0.3.103.dist-info → inspect_ai-0.3.105.dist-info}/entry_points.txt +0 -0
- {inspect_ai-0.3.103.dist-info → inspect_ai-0.3.105.dist-info}/licenses/LICENSE +0 -0
- {inspect_ai-0.3.103.dist-info → inspect_ai-0.3.105.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,158 @@
|
|
1
|
+
from anthropic.types import (
|
2
|
+
CitationCharLocation,
|
3
|
+
CitationCharLocationParam,
|
4
|
+
CitationContentBlockLocation,
|
5
|
+
CitationContentBlockLocationParam,
|
6
|
+
CitationPageLocation,
|
7
|
+
CitationPageLocationParam,
|
8
|
+
CitationsWebSearchResultLocation,
|
9
|
+
CitationWebSearchResultLocationParam,
|
10
|
+
TextCitation,
|
11
|
+
TextCitationParam,
|
12
|
+
)
|
13
|
+
|
14
|
+
from inspect_ai._util.citation import (
|
15
|
+
Citation,
|
16
|
+
DocumentCitation,
|
17
|
+
DocumentRange,
|
18
|
+
UrlCitation,
|
19
|
+
)
|
20
|
+
|
21
|
+
|
22
|
+
def to_inspect_citation(input: TextCitation) -> Citation:
|
23
|
+
match input:
|
24
|
+
case CitationsWebSearchResultLocation(
|
25
|
+
cited_text=cited_text,
|
26
|
+
title=title,
|
27
|
+
url=url,
|
28
|
+
encrypted_index=encrypted_index,
|
29
|
+
):
|
30
|
+
# Sanitize a citation to work around https://github.com/anthropics/anthropic-sdk-python/issues/965.
|
31
|
+
return UrlCitation(
|
32
|
+
cited_text=cited_text,
|
33
|
+
title=title
|
34
|
+
if title is None or len(title) <= 255
|
35
|
+
else title[:254] + "…",
|
36
|
+
url=url,
|
37
|
+
internal={"encrypted_index": encrypted_index},
|
38
|
+
)
|
39
|
+
|
40
|
+
case CitationCharLocation(
|
41
|
+
cited_text=cited_text,
|
42
|
+
document_index=document_index,
|
43
|
+
document_title=title,
|
44
|
+
end_char_index=end_char_index,
|
45
|
+
start_char_index=start_char_index,
|
46
|
+
):
|
47
|
+
return DocumentCitation(
|
48
|
+
cited_text=cited_text,
|
49
|
+
title=title,
|
50
|
+
range=DocumentRange(
|
51
|
+
type="char", start_index=start_char_index, end_index=end_char_index
|
52
|
+
),
|
53
|
+
internal={"document_index": document_index},
|
54
|
+
)
|
55
|
+
|
56
|
+
case CitationContentBlockLocation(
|
57
|
+
cited_text=cited_text,
|
58
|
+
document_index=document_index,
|
59
|
+
document_title=title,
|
60
|
+
end_block_index=end_block_index,
|
61
|
+
start_block_index=start_block_index,
|
62
|
+
):
|
63
|
+
return DocumentCitation(
|
64
|
+
cited_text=cited_text,
|
65
|
+
title=title,
|
66
|
+
range=DocumentRange(
|
67
|
+
type="block",
|
68
|
+
start_index=start_block_index,
|
69
|
+
end_index=end_block_index,
|
70
|
+
),
|
71
|
+
internal={"document_index": document_index},
|
72
|
+
)
|
73
|
+
|
74
|
+
case CitationPageLocation(
|
75
|
+
cited_text=cited_text,
|
76
|
+
document_index=document_index,
|
77
|
+
document_title=title,
|
78
|
+
end_page_number=end_page_number,
|
79
|
+
start_page_number=start_page_number,
|
80
|
+
):
|
81
|
+
return DocumentCitation(
|
82
|
+
cited_text=cited_text,
|
83
|
+
title=title,
|
84
|
+
range=DocumentRange(
|
85
|
+
type="page",
|
86
|
+
start_index=start_page_number - 1,
|
87
|
+
end_index=end_page_number - 1,
|
88
|
+
),
|
89
|
+
internal={"document_index": document_index},
|
90
|
+
)
|
91
|
+
|
92
|
+
assert False, f"Unexpected citation type: {input.type}"
|
93
|
+
|
94
|
+
|
95
|
+
def to_anthropic_citation(input: Citation) -> TextCitationParam:
|
96
|
+
cited_text = input.cited_text
|
97
|
+
assert isinstance(cited_text, str), (
|
98
|
+
"anthropic citations must have a string cited_text"
|
99
|
+
)
|
100
|
+
|
101
|
+
match input:
|
102
|
+
case UrlCitation(title=title, url=url, internal=internal):
|
103
|
+
assert internal, "UrlCitation must have internal field"
|
104
|
+
encrypted_index = internal.get("encrypted_index", None)
|
105
|
+
assert isinstance(encrypted_index, str), (
|
106
|
+
"URL citations require encrypted_index in internal field"
|
107
|
+
)
|
108
|
+
|
109
|
+
return CitationWebSearchResultLocationParam(
|
110
|
+
type="web_search_result_location",
|
111
|
+
cited_text=cited_text,
|
112
|
+
title=title,
|
113
|
+
url=url,
|
114
|
+
encrypted_index=encrypted_index,
|
115
|
+
)
|
116
|
+
|
117
|
+
case DocumentCitation(title=title, range=range, internal=internal):
|
118
|
+
assert internal, "DocumentCharCitation must have internal field"
|
119
|
+
document_index = internal.get("document_index", None)
|
120
|
+
assert isinstance(document_index, int), (
|
121
|
+
"DocumentCharCitation require encrypted_index in internal field"
|
122
|
+
)
|
123
|
+
assert range, "DocumentCitation must have a range"
|
124
|
+
|
125
|
+
start_index = range.start_index
|
126
|
+
end_index = range.end_index
|
127
|
+
|
128
|
+
match range.type:
|
129
|
+
case "char":
|
130
|
+
return CitationCharLocationParam(
|
131
|
+
type="char_location",
|
132
|
+
cited_text=cited_text,
|
133
|
+
document_title=title,
|
134
|
+
document_index=document_index,
|
135
|
+
start_char_index=start_index,
|
136
|
+
end_char_index=end_index,
|
137
|
+
)
|
138
|
+
case "block":
|
139
|
+
return CitationContentBlockLocationParam(
|
140
|
+
type="content_block_location",
|
141
|
+
cited_text=cited_text,
|
142
|
+
document_title=title,
|
143
|
+
document_index=document_index,
|
144
|
+
start_block_index=start_index,
|
145
|
+
end_block_index=end_index,
|
146
|
+
)
|
147
|
+
case "page":
|
148
|
+
return CitationPageLocationParam(
|
149
|
+
type="page_location",
|
150
|
+
cited_text=cited_text,
|
151
|
+
document_title=title,
|
152
|
+
document_index=document_index,
|
153
|
+
start_page_number=start_index + 1,
|
154
|
+
end_page_number=end_index + 1,
|
155
|
+
)
|
156
|
+
|
157
|
+
# If we can't handle this citation type, raise an error
|
158
|
+
raise ValueError(f"Unsupported citation type: {input.type}")
|
@@ -0,0 +1,100 @@
|
|
1
|
+
from typing import Sequence
|
2
|
+
|
3
|
+
from google.genai.types import (
|
4
|
+
Candidate,
|
5
|
+
GroundingChunk,
|
6
|
+
GroundingSupport,
|
7
|
+
Segment,
|
8
|
+
)
|
9
|
+
|
10
|
+
from inspect_ai._util.citation import Citation, UrlCitation
|
11
|
+
|
12
|
+
|
13
|
+
def get_candidate_citations(candidate: Candidate) -> list[Citation]:
|
14
|
+
"""Extract citations from Google AI candidate grounding metadata.
|
15
|
+
|
16
|
+
Understanding Google API Grounding Citations: `GroundingChunk`'s, `GroundingSupport`, and `Segment`'s
|
17
|
+
|
18
|
+
1. Grounding Chunks (`GroundingChunk`)
|
19
|
+
What they are: The raw source material that the AI retrieved to support its response.
|
20
|
+
Structure:
|
21
|
+
- Web (`GroundingChunkWeb`): Content from web searches
|
22
|
+
- domain: The website domain
|
23
|
+
- title: Page title
|
24
|
+
- uri: Web page URL
|
25
|
+
Think of chunks as: The library books or web pages that contain the information.
|
26
|
+
|
27
|
+
2. Segments (`Segment`)
|
28
|
+
What they are: Specific portions of the AI's generated response text.
|
29
|
+
Structure:
|
30
|
+
- start_index & end_index: Byte positions in the response text
|
31
|
+
- text: The actual text from the response that this segment represents
|
32
|
+
Think of segments as: Specific sentences or paragraphs in the AI's response that need citations.
|
33
|
+
|
34
|
+
3. Grounding Support (`GroundingSupport`)
|
35
|
+
What they are: The bridge that connects segments of the AI's response to the chunks that support them.
|
36
|
+
Structure:
|
37
|
+
- grounding_chunk_indices: Array of integers pointing to specific chunks (e.g., [1,3,4] means chunks 1, 3, and 4 support this claim)
|
38
|
+
- segment: Which part of the response this support applies to
|
39
|
+
Think of support as: The footnotes that say "this claim in my response is backed up by these specific sources."
|
40
|
+
|
41
|
+
Args:
|
42
|
+
candidate: The Google AI candidate response containing grounding metadata
|
43
|
+
|
44
|
+
Returns:
|
45
|
+
A list of `Citation` objects linking response segments to their web sources.
|
46
|
+
Currently only handles `GroundingChunkWeb` sources.
|
47
|
+
"""
|
48
|
+
return (
|
49
|
+
[]
|
50
|
+
if (
|
51
|
+
not candidate.content
|
52
|
+
or not candidate.content.parts
|
53
|
+
or not (metadata := candidate.grounding_metadata)
|
54
|
+
or not (chunks := metadata.grounding_chunks)
|
55
|
+
or not (supports := metadata.grounding_supports)
|
56
|
+
)
|
57
|
+
else [
|
58
|
+
citation
|
59
|
+
for support in supports
|
60
|
+
for citation in _citations_from_support(support, chunks)
|
61
|
+
]
|
62
|
+
)
|
63
|
+
|
64
|
+
|
65
|
+
def _create_citation_from_chunk_and_segment(
|
66
|
+
chunk: GroundingChunk, segment: Segment
|
67
|
+
) -> UrlCitation | None:
|
68
|
+
"""Create a citation from a chunk and segment, returning None if chunk is not web-based."""
|
69
|
+
return (
|
70
|
+
UrlCitation(
|
71
|
+
url=chunk.web.uri,
|
72
|
+
title=chunk.web.title,
|
73
|
+
cited_text=(
|
74
|
+
(segment.start_index or 0, segment.end_index)
|
75
|
+
if segment.end_index is not None
|
76
|
+
else None
|
77
|
+
),
|
78
|
+
)
|
79
|
+
if (chunk.web and chunk.web.uri)
|
80
|
+
else None
|
81
|
+
)
|
82
|
+
|
83
|
+
|
84
|
+
def _citations_from_support(
|
85
|
+
support: GroundingSupport, chunks: Sequence[GroundingChunk]
|
86
|
+
) -> list[Citation]:
|
87
|
+
return (
|
88
|
+
[]
|
89
|
+
if support.segment is None or support.grounding_chunk_indices is None
|
90
|
+
else [
|
91
|
+
citation
|
92
|
+
for chunk_index in support.grounding_chunk_indices
|
93
|
+
if chunk_index < len(chunks)
|
94
|
+
if (
|
95
|
+
citation := _create_citation_from_chunk_and_segment(
|
96
|
+
chunks[chunk_index], support.segment
|
97
|
+
)
|
98
|
+
)
|
99
|
+
]
|
100
|
+
)
|