Skip to content

Commit 45f19aa

Browse files
chore(py): bump versions to 0.5.2 and more fixes (#5005)
Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com>
1 parent 463d097 commit 45f19aa

26 files changed

Lines changed: 621 additions & 170 deletions

File tree

py/bin/release_check

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ fi
187187

188188
echo -e "\n${CYAN}Checking plugins...${NC}"
189189
for d in plugins/*/; do
190-
if [ -d "$d" ]; then
190+
if [ -d "$d" ] && [ -f "${d}pyproject.toml" ]; then
191191
if ! check_package_metadata "$d" "plugin"; then
192192
ERRORS=$((ERRORS + 1))
193193
elif [ "$VERBOSE" = true ]; then
@@ -234,8 +234,8 @@ for pkg in plugins/*/; do
234234
# DEP002: unused deps (may be false positives for optional features)
235235
# DEP003: transitive deps (expected in workspace setup)
236236
# Exclude tests/ and test/ directories (they use dev deps like pytest)
237-
deptry_output=$(uv run deptry "$pkg" --ignore DEP002,DEP003 -ee ".*/tests/" -ee ".*/test/" 2>&1)
238-
deptry_exit=$?
237+
deptry_exit=0
238+
deptry_output=$(uv run deptry "$pkg" --ignore DEP002,DEP003 -ee ".*/tests/" -ee ".*/test/" 2>&1) || deptry_exit=$?
239239
if [ $deptry_exit -ne 0 ]; then
240240
# Only report if there are actual errors (DEP001: missing deps)
241241
if echo "$deptry_output" | grep -qE "DEP001"; then

py/packages/genkit/pyproject.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ dependencies = [
5454
"pillow>=12.1.1",
5555
"typing_extensions>=4.0",
5656
"strenum>=0.4.15; python_version < '3.11'",
57+
5758
"dotpromptz>=0.1.5",
5859
"uvicorn>=0.34.0",
5960
"uvloop>=0.21.0; sys_platform != 'win32'",
@@ -75,7 +76,7 @@ license = "Apache-2.0"
7576
name = "genkit"
7677
readme = "README.md"
7778
requires-python = ">=3.10"
78-
version = "0.5.1"
79+
version = "0.5.2"
7980

8081
[project.optional-dependencies]
8182
flask = ["genkit-plugin-flask"]

py/packages/genkit/src/genkit/_ai/_aio.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,8 @@ async def _run_server() -> None:
669669
def _initialize_registry(self, model: str | None, plugins: list[Plugin] | None) -> None:
670670
"""Initialize the registry with default model and plugins."""
671671
self.registry.default_model = model
672+
if model:
673+
self.registry.register_value('defaultModel', model, model)
672674
for fmt in built_in_formats:
673675
self.define_format(fmt)
674676

py/packages/genkit/src/genkit/_ai/_generate.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
"""Generate action."""
1818

19+
import contextlib
1920
import copy
2021
import inspect
2122
import re
@@ -41,10 +42,12 @@
4142
from genkit._core._logger import get_logger
4243
from genkit._core._model import GenerateActionOptions
4344
from genkit._core._registry import Registry
45+
from genkit._core._tracing import run_in_new_span
4446
from genkit._core._typing import (
4547
FinishReason,
4648
Part,
4749
Role,
50+
SpanMetadata,
4851
ToolDefinition,
4952
ToolRequest,
5053
ToolRequestPart,
@@ -111,6 +114,32 @@ async def generate_action(
111114
current_turn: int = 0,
112115
middleware: list[ModelMiddleware] | None = None,
113116
context: dict[str, Any] | None = None,
117+
) -> ModelResponse:
118+
"""Execute a generation request with tool calling and middleware support."""
119+
span_name = 'generate'
120+
with run_in_new_span(
121+
SpanMetadata(name=span_name),
122+
labels={'genkit:type': 'util'},
123+
) as span:
124+
span.set_attribute('genkit:name', span_name)
125+
with contextlib.suppress(Exception):
126+
span.set_attribute('genkit:input', raw_request.model_dump_json(by_alias=True, exclude_none=True))
127+
result = await _generate_action(
128+
registry, raw_request, on_chunk, message_index, current_turn, middleware, context
129+
)
130+
with contextlib.suppress(Exception):
131+
span.set_attribute('genkit:output', result.model_dump_json(by_alias=True, exclude_none=True))
132+
return result
133+
134+
135+
async def _generate_action(
136+
registry: Registry,
137+
raw_request: GenerateActionOptions,
138+
on_chunk: Callable[[ModelResponseChunk], None] | None = None,
139+
message_index: int = 0,
140+
current_turn: int = 0,
141+
middleware: list[ModelMiddleware] | None = None,
142+
context: dict[str, Any] | None = None,
114143
) -> ModelResponse:
115144
"""Execute a generation request with tool calling and middleware support."""
116145
model, tools, format_def = await resolve_parameters(registry, raw_request)
@@ -290,6 +319,24 @@ def message_parser(msg: Message) -> Any: # noqa: ANN401
290319
# No message in response, return as-is
291320
return response
292321

322+
# Stamp output format metadata on message for Dev UI rendering.
323+
# Mirrors JS GenerateResponse constructor which sets message.metadata.generate.output
324+
# so the Dev UI knows to render the output as formatted JSON vs plain text.
325+
out = raw_request.output
326+
if out and (out.content_type or out.format):
327+
generate_output: dict[str, str] = {}
328+
if out.content_type:
329+
generate_output['contentType'] = out.content_type
330+
if out.format:
331+
generate_output['format'] = out.format
332+
existing_meta = dict(generated_msg.metadata) if isinstance(generated_msg.metadata, dict) else {}
333+
generate_meta = existing_meta.get('generate')
334+
if not isinstance(generate_meta, dict):
335+
generate_meta = {}
336+
generate_meta['output'] = generate_output
337+
existing_meta['generate'] = generate_meta
338+
generated_msg.metadata = existing_meta
339+
293340
tool_requests = [x for x in generated_msg.content if x.root.tool_request]
294341

295342
if raw_request.return_tool_requests or len(tool_requests) == 0:
@@ -344,7 +391,7 @@ def message_parser(msg: Message) -> Any: # noqa: ANN401
344391
next_request = apply_transfer_preamble(next_request, transfer_preamble)
345392

346393
# then recursively call for another loop
347-
return await generate_action(
394+
return await _generate_action(
348395
registry,
349396
raw_request=next_request,
350397
# middleware: middleware,

py/packages/genkit/src/genkit/_core/_action.py

Lines changed: 56 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
from genkit._core._compat import StrEnum
3737
from genkit._core._error import GenkitError
3838
from genkit._core._trace._path import build_path
39+
from genkit._core._trace._suppress import suppress_telemetry
3940
from genkit._core._tracing import tracer
4041

4142
# =============================================================================
@@ -554,52 +555,60 @@ async def tracing_wrapper(
554555
) -> ActionResponse[Any]:
555556
start_time = time.perf_counter()
556557

557-
with _save_parent_path():
558-
with tracer.start_as_current_span(name) as span:
559-
# Format trace_id and span_id as hex strings (OpenTelemetry standard format)
560-
trace_id = format(span.get_span_context().trace_id, '032x')
561-
span_id = format(span.get_span_context().span_id, '016x')
562-
if on_trace_start:
563-
on_trace_start(trace_id, span_id)
564-
565-
# Set telemetry labels as direct span attributes (matches JS/Go behavior)
566-
if telemetry_labels:
567-
for key, value in telemetry_labels.items():
568-
span.set_attribute(key, str(value))
569-
570-
_record_input_metadata(
571-
span=span,
572-
kind=kind,
573-
name=name,
574-
span_metadata=span_metadata,
575-
input=input,
576-
)
577-
578-
try:
579-
match n_action_args:
580-
case 0:
581-
output = await fn()
582-
case 1:
583-
output = await fn(input)
584-
case 2:
585-
output = await fn(input, ctx)
586-
case _:
587-
raise ValueError('action fn must have 0-2 args')
588-
except Exception as e:
589-
span.set_attribute('genkit:state', 'error')
590-
span.set_status(status=trace_api.StatusCode.ERROR, description=str(e))
591-
span.record_exception(e)
592-
# Re-raise existing GenkitError instances to avoid double-wrapping
593-
if isinstance(e, GenkitError):
594-
raise
595-
raise GenkitError(
596-
cause=e,
597-
message=f'Error while running action {name}',
598-
trace_id=trace_id,
599-
) from e
600-
601-
output = _record_latency(output, start_time)
602-
_record_output_metadata(span, output=output)
603-
return ActionResponse(response=output, trace_id=trace_id, span_id=span_id)
558+
suppress = str((telemetry_labels or {}).get('genkitx:ignore-trace', '')).lower() == 'true'
559+
suppress_token = suppress_telemetry.set(True) if suppress else None
560+
try:
561+
with _save_parent_path():
562+
with tracer.start_as_current_span(name) as span:
563+
# Format trace_id and span_id as hex strings (OpenTelemetry standard format)
564+
trace_id = format(span.get_span_context().trace_id, '032x')
565+
span_id = format(span.get_span_context().span_id, '016x')
566+
if on_trace_start:
567+
on_trace_start(trace_id, span_id)
568+
569+
# Set telemetry labels as direct span attributes (matches JS/Go behavior)
570+
if telemetry_labels:
571+
for key, value in telemetry_labels.items():
572+
span.set_attribute(key, str(value))
573+
574+
_record_input_metadata(
575+
span=span,
576+
kind=kind,
577+
name=name,
578+
span_metadata=span_metadata,
579+
input=input,
580+
)
581+
582+
try:
583+
match n_action_args:
584+
case 0:
585+
output = await fn()
586+
case 1:
587+
output = await fn(input)
588+
case 2:
589+
output = await fn(input, ctx)
590+
case _:
591+
raise ValueError('action fn must have 0-2 args')
592+
except Exception as e:
593+
span.set_attribute('genkit:state', 'error')
594+
# Bundled Dev UI reads timeEvents.exception.attributes only; stash text for export synthesis.
595+
span.set_status(trace_api.StatusCode.ERROR, description=str(e))
596+
span.record_exception(e)
597+
if isinstance(e, GenkitError):
598+
span.set_attribute('genkit:error', e.original_message)
599+
raise
600+
span.set_attribute('genkit:error', str(e))
601+
raise GenkitError(
602+
cause=e,
603+
message=f'Error while running action {name}',
604+
trace_id=trace_id,
605+
) from e
606+
607+
output = _record_latency(output, start_time)
608+
_record_output_metadata(span, output=output)
609+
return ActionResponse(response=output, trace_id=trace_id, span_id=span_id)
610+
finally:
611+
if suppress_token is not None:
612+
suppress_telemetry.reset(suppress_token)
604613

605614
return tracing_wrapper

py/packages/genkit/src/genkit/_core/_compat.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@
2828
# Note: override was added to typing in Python 3.12, but typing_extensions has it for all versions
2929
from typing import overload as overload # noqa: E402
3030

31-
from strenum import StrEnum as StrEnum # noqa: E402
31+
if sys.version_info >= (3, 11):
32+
from enum import StrEnum as StrEnum # noqa: E402
33+
else:
34+
from strenum import StrEnum as StrEnum # noqa: E402
3235
from typing_extensions import override as override # noqa: E402
3336

3437

py/packages/genkit/src/genkit/_core/_reflection.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ async def execute(self) -> None:
9494
on_chunk=on_chunk,
9595
context=self.payload.get('context', {}),
9696
on_trace_start=self.on_trace_start,
97+
telemetry_labels=self.payload.get('telemetryLabels'),
9798
)
9899
result = (
99100
output.response.model_dump(by_alias=True, exclude_none=True)

0 commit comments

Comments
 (0)