Skip to content

[bug] urml translate should not exception error out on KeyboardInterrupt #558

Description

@slowrunner

What component is affected

urml application

What I expected

Issuing ctrl-c should cleanly stop urml operations that are long running

What actually happened

issued ctrl-c to urml translate ...:

(gopigo3) ubuntu@U26LDave:~/LyricalDave/systests/urml/mygopigo3$ ./gopigo3_t3_remote.sh 
 15:30:27 up 13 days, 15:27,  3 users,  load average: 0.82, 1.11, 1.22
Starting remote translate
phrase: Announce 'Measuring distance',wait 3, measure distance, wait 3, announce the distance the sensor returned.
^CTraceback (most recent call last):
  File "/home/ubuntu/.venv/gopigo3/bin/urml", line 6, in <module>
    sys.exit(main())
             ~~~~^^
  File "/home/ubuntu/LyricalDave/systests/urml/URML/reference/validator/src/urml_validator/cli.py", line 503, in main
    rc: int = args.func(args)
              ~~~~~~~~~^^^^^^
  File "/home/ubuntu/LyricalDave/systests/urml/URML/reference/validator/src/urml_validator/cli.py", line 995, in cmd_translate
    result = bridge.translate(args.request)
  File "/home/ubuntu/LyricalDave/systests/urml/URML/reference/llm-bridge/src/urml_llm_bridge/bridge.py", line 150, in translate
    raw = self._provider.complete(
        system=system_prompt,
        user=user_request,
        schema=self._schema,
    )
  File "/home/ubuntu/LyricalDave/systests/urml/URML/reference/llm-bridge/src/urml_llm_bridge/providers/openai.py", line 123, in complete
    response = self._client.chat.completions.create(
        model=self._model,
    ...<5 lines>...
        max_tokens=max_tokens or self._default_max_tokens,
    )
  File "/home/ubuntu/.venv/gopigo3/lib/python3.14/site-packages/openai/_utils/_utils.py", line 298, in wrapper
    return func(*args, **kwargs)
  File "/home/ubuntu/.venv/gopigo3/lib/python3.14/site-packages/openai/resources/chat/completions/completions.py", line 1251, in create
    return self._post(
           ~~~~~~~~~~^
        "/chat/completions",
        ^^^^^^^^^^^^^^^^^^^^
    ...<52 lines>...
        stream_cls=Stream[ChatCompletionChunk],
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/home/ubuntu/.venv/gopigo3/lib/python3.14/site-packages/openai/_base_client.py", line 1332, in post
    return cast(ResponseT, self.request(cast_to, opts, stream=stream, stream_cls=stream_cls))
                           ~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/ubuntu/.venv/gopigo3/lib/python3.14/site-packages/openai/_base_client.py", line 1037, in request
    response = self._send_request(
        request,
        stream=stream or self._should_stream_response_body(request=request),
        **kwargs,
    )
  File "/home/ubuntu/.venv/gopigo3/lib/python3.14/site-packages/openai/_client.py", line 478, in _send_request
    response = self._send_with_auth_retry(request, stream=stream, **kwargs)
  File "/home/ubuntu/.venv/gopigo3/lib/python3.14/site-packages/openai/_client.py", line 456, in _send_with_auth_retry
    response = super()._send_request(request, stream=stream, **kwargs)
  File "/home/ubuntu/.venv/gopigo3/lib/python3.14/site-packages/openai/_base_client.py", line 964, in _send_request
    return self._client.send(request, stream=stream, **kwargs)
           ~~~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/httpx/_client.py", line 914, in send
    response = self._send_handling_auth(
        request,
    ...<2 lines>...
        history=[],
    )
  File "/usr/lib/python3/dist-packages/httpx/_client.py", line 942, in _send_handling_auth
    response = self._send_handling_redirects(
        request,
        follow_redirects=follow_redirects,
        history=history,
    )
  File "/usr/lib/python3/dist-packages/httpx/_client.py", line 979, in _send_handling_redirects
    response = self._send_single_request(request)
  File "/usr/lib/python3/dist-packages/httpx/_client.py", line 1014, in _send_single_request
    response = transport.handle_request(request)
  File "/usr/lib/python3/dist-packages/httpx/_transports/default.py", line 250, in handle_request
    resp = self._pool.handle_request(req)
  File "/usr/lib/python3/dist-packages/httpcore/_sync/connection_pool.py", line 256, in handle_request
    raise exc from None
  File "/usr/lib/python3/dist-packages/httpcore/_sync/connection_pool.py", line 236, in handle_request
    response = connection.handle_request(
        pool_request.request
    )
  File "/usr/lib/python3/dist-packages/httpcore/_sync/connection.py", line 103, in handle_request
    return self._connection.handle_request(request)
           ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^
  File "/usr/lib/python3/dist-packages/httpcore/_sync/http11.py", line 136, in handle_request
    raise exc
  File "/usr/lib/python3/dist-packages/httpcore/_sync/http11.py", line 106, in handle_request
    ) = self._receive_response_headers(**kwargs)
        ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/httpcore/_sync/http11.py", line 177, in _receive_response_headers
    event = self._receive_event(timeout=timeout)
  File "/usr/lib/python3/dist-packages/httpcore/_sync/http11.py", line 217, in _receive_event
    data = self._network_stream.read(
        self.READ_NUM_BYTES, timeout=timeout
    )
  File "/usr/lib/python3/dist-packages/httpcore/_backends/sync.py", line 128, in read
    return self._sock.recv(max_bytes)
           ~~~~~~~~~~~~~~~^^^^^^^^^^^
KeyboardInterrupt

Minimum reproduction

Not sure of minimum steps to repro. Steps I used:

  1. Set environment vars for remote OpenAI LLM
URML_OPENAI_TIMEOUT=600
OPENAI_API_KEY=qwen3.5:9b
OPENAI_BASE_URL=http://10.0.0.xx:11434/v1
  1. Issue urml translate with a phrase:

The script that invokes urml-translate:

#!/bin/bash

# optional:      --envelope envelope.yaml \

testnum=3
phrase="Announce 'Measuring distance',wait 3, measure distance, wait 3, announce the distance the sensor returned." \
model="qwen3.5:9b"
fn="${model//:/_}"

uptime
echo "Starting remote translate"
echo -e "phrase: $phrase"

time urml translate "$phrase" \
    --manifest gopigo3.manifest.yaml \
    --profile educational \
    --no-policy \
    --provider openai \
    --model $model \
    --save-rejected remote.$fn.gopigo3_t$testnum.rejected.out \
    --out remote.$fn.gopigo3_t$testnum.program.urml.yaml

uptime
echo "Done"

  1. Invoke a long running (7 minutes expected) urml translate:
(gopigo3) ubuntu@U26LDave:~/LyricalDave/systests/urml/mygopigo3$ ./gopigo3_t3_remote.sh 
 15:30:27 up 13 days, 15:27,  3 users,  load average: 0.82, 1.11, 1.22
Starting remote translate
phrase: Announce 'Measuring distance',wait 3, measure distance, wait 3, announce the distance the sensor returned.

  1. Ctrl-C
^C
(EXCEPTIONAL BARFING)

Environment

  • URML version / commit: 0.2.0
  • Operating system: Ubuntu 26.04
  • Python / C++ / Rust toolchain version (if relevant): 3.14
  • Substrate version (ROS 2 distro, PX4 release, etc., if relevant): GoPiGo3 manifest

Additional context

none

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions