clams-python 1.7.2__tar.gz → 1.7.4__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.
Files changed (106) hide show
  1. {clams_python-1.7.2 → clams_python-1.7.4}/CHANGELOG.md +21 -0
  2. {clams_python-1.7.2/clams_python.egg-info → clams_python-1.7.4}/PKG-INFO +2 -2
  3. {clams_python-1.7.2 → clams_python-1.7.4}/clams/app/__init__.py +140 -39
  4. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/templates/app/Containerfile.template +1 -1
  5. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/templates/app/cli.py.template +21 -4
  6. {clams_python-1.7.2 → clams_python-1.7.4/clams_python.egg-info}/PKG-INFO +2 -2
  7. {clams_python-1.7.2 → clams_python-1.7.4}/clams_python.egg-info/requires.txt +1 -1
  8. {clams_python-1.7.2 → clams_python-1.7.4}/clams_python.egg-info/scm_file_list.json +67 -67
  9. clams_python-1.7.4/clams_python.egg-info/scm_version.json +8 -0
  10. clams_python-1.7.4/container/ffmpeg-torch2.containerfile +13 -0
  11. clams_python-1.7.4/container/opencv4-torch2.containerfile +13 -0
  12. clams_python-1.7.4/container/torch2.containerfile +13 -0
  13. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/app-baseclasses.rst +66 -1
  14. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/clamsapp.rst +12 -0
  15. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/conf.py +3 -1
  16. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/introduction.rst +1 -1
  17. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/runtime-params.rst +9 -1
  18. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/target-versions.csv +2 -0
  19. {clams_python-1.7.2 → clams_python-1.7.4}/pyproject.toml +1 -1
  20. {clams_python-1.7.2 → clams_python-1.7.4}/tests/test_clamsapp.py +77 -0
  21. {clams_python-1.7.2 → clams_python-1.7.4}/tests/test_envelope.py +13 -0
  22. {clams_python-1.7.2 → clams_python-1.7.4}/tests/test_promptable.py +22 -0
  23. clams_python-1.7.2/clams_python.egg-info/scm_version.json +0 -8
  24. clams_python-1.7.2/container/ffmpeg-torch2.containerfile +0 -6
  25. clams_python-1.7.2/container/opencv4-torch2.containerfile +0 -6
  26. clams_python-1.7.2/container/torch2.containerfile +0 -6
  27. {clams_python-1.7.2 → clams_python-1.7.4}/.github/workflows/codecov.yml +0 -0
  28. {clams_python-1.7.2 → clams_python-1.7.4}/.github/workflows/container.yml +0 -0
  29. {clams_python-1.7.2 → clams_python-1.7.4}/.github/workflows/containers.yml +0 -0
  30. {clams_python-1.7.2 → clams_python-1.7.4}/.github/workflows/issue-assign.yml +0 -0
  31. {clams_python-1.7.2 → clams_python-1.7.4}/.github/workflows/issue-close.yml +0 -0
  32. {clams_python-1.7.2 → clams_python-1.7.4}/.github/workflows/issue-infra-project.yml +0 -0
  33. {clams_python-1.7.2 → clams_python-1.7.4}/.github/workflows/publish.yml +0 -0
  34. {clams_python-1.7.2 → clams_python-1.7.4}/.github/workflows/release-check.yml +0 -0
  35. {clams_python-1.7.2 → clams_python-1.7.4}/.gitignore +0 -0
  36. {clams_python-1.7.2 → clams_python-1.7.4}/.pytype.cfg +0 -0
  37. {clams_python-1.7.2 → clams_python-1.7.4}/CONTRIBUTING.md +0 -0
  38. {clams_python-1.7.2 → clams_python-1.7.4}/LICENSE +0 -0
  39. {clams_python-1.7.2 → clams_python-1.7.4}/README.md +0 -0
  40. {clams_python-1.7.2 → clams_python-1.7.4}/build-tools/build.py +0 -0
  41. {clams_python-1.7.2 → clams_python-1.7.4}/build-tools/clean.py +0 -0
  42. {clams_python-1.7.2 → clams_python-1.7.4}/build-tools/docs.py +0 -0
  43. {clams_python-1.7.2 → clams_python-1.7.4}/build-tools/prep_release.py +0 -0
  44. {clams_python-1.7.2 → clams_python-1.7.4}/build-tools/publish.py +0 -0
  45. {clams_python-1.7.2 → clams_python-1.7.4}/build-tools/test.py +0 -0
  46. {clams_python-1.7.2 → clams_python-1.7.4}/clams/__init__.py +0 -0
  47. {clams_python-1.7.2 → clams_python-1.7.4}/clams/appmetadata/__init__.py +0 -0
  48. {clams_python-1.7.2 → clams_python-1.7.4}/clams/backends/__init__.py +0 -0
  49. {clams_python-1.7.2 → clams_python-1.7.4}/clams/backends/hf.py +0 -0
  50. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/__init__.py +0 -0
  51. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/templates/app/.dockerignore.template +0 -0
  52. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/templates/app/.gitignore.template +0 -0
  53. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/templates/app/LICENSE.template +0 -0
  54. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/templates/app/README.md.template +0 -0
  55. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/templates/app/app.py.template +0 -0
  56. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/templates/app/metadata.py.template +0 -0
  57. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/templates/app/requirements.txt.template +0 -0
  58. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/templates/gha/for-clams-team.md.template +0 -0
  59. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/templates/gha/workflows/issue-apps-project.yml.template +0 -0
  60. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/templates/gha/workflows/issue-assign.yml.template +0 -0
  61. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/templates/gha/workflows/issue-close.yml.template +0 -0
  62. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/templates/gha/workflows/publish.yml.template +0 -0
  63. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/templates/utl-tf/__init__.py.template +0 -0
  64. {clams_python-1.7.2 → clams_python-1.7.4}/clams/develop/templates/utl-tf/timeframe.py.template +0 -0
  65. {clams_python-1.7.2 → clams_python-1.7.4}/clams/envelop/__init__.py +0 -0
  66. {clams_python-1.7.2 → clams_python-1.7.4}/clams/restify/__init__.py +0 -0
  67. {clams_python-1.7.2 → clams_python-1.7.4}/clams/serve/__init__.py +0 -0
  68. {clams_python-1.7.2 → clams_python-1.7.4}/clams/ver/__init__.py +0 -0
  69. {clams_python-1.7.2 → clams_python-1.7.4}/clams_python.egg-info/SOURCES.txt +0 -0
  70. {clams_python-1.7.2 → clams_python-1.7.4}/clams_python.egg-info/dependency_links.txt +0 -0
  71. {clams_python-1.7.2 → clams_python-1.7.4}/clams_python.egg-info/entry_points.txt +0 -0
  72. {clams_python-1.7.2 → clams_python-1.7.4}/clams_python.egg-info/top_level.txt +0 -0
  73. {clams_python-1.7.2 → clams_python-1.7.4}/container/Containerfile +0 -0
  74. {clams_python-1.7.2 → clams_python-1.7.4}/container/ffmpeg-hf.containerfile +0 -0
  75. {clams_python-1.7.2 → clams_python-1.7.4}/container/ffmpeg-hf4.containerfile +0 -0
  76. {clams_python-1.7.2 → clams_python-1.7.4}/container/ffmpeg-hf5.containerfile +0 -0
  77. {clams_python-1.7.2 → clams_python-1.7.4}/container/ffmpeg-tf2.containerfile +0 -0
  78. {clams_python-1.7.2 → clams_python-1.7.4}/container/ffmpeg.containerfile +0 -0
  79. {clams_python-1.7.2 → clams_python-1.7.4}/container/generate_containers_yml.py +0 -0
  80. {clams_python-1.7.2 → clams_python-1.7.4}/container/hf.containerfile +0 -0
  81. {clams_python-1.7.2 → clams_python-1.7.4}/container/hf4.containerfile +0 -0
  82. {clams_python-1.7.2 → clams_python-1.7.4}/container/hf5.containerfile +0 -0
  83. {clams_python-1.7.2 → clams_python-1.7.4}/container/jdk8.containerfile +0 -0
  84. {clams_python-1.7.2 → clams_python-1.7.4}/container/opencv4-hf.containerfile +0 -0
  85. {clams_python-1.7.2 → clams_python-1.7.4}/container/opencv4-hf4.containerfile +0 -0
  86. {clams_python-1.7.2 → clams_python-1.7.4}/container/opencv4-hf5.containerfile +0 -0
  87. {clams_python-1.7.2 → clams_python-1.7.4}/container/opencv4-tf2.containerfile +0 -0
  88. {clams_python-1.7.2 → clams_python-1.7.4}/container/opencv4.containerfile +0 -0
  89. {clams_python-1.7.2 → clams_python-1.7.4}/container/tf2.containerfile +0 -0
  90. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/appdirectory.rst +0 -0
  91. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/appmetadata.rst +0 -0
  92. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/autodoc/clams.app.rst +0 -0
  93. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/autodoc/clams.appmetadata.rst +0 -0
  94. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/autodoc/clams.backends.rst +0 -0
  95. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/autodoc/clams.mmif_utils.rst +0 -0
  96. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/autodoc/clams.restify.rst +0 -0
  97. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/cli.rst +0 -0
  98. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/gpu-apps.rst +0 -0
  99. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/index.rst +0 -0
  100. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/input-output.rst +0 -0
  101. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/modules.rst +0 -0
  102. {clams_python-1.7.2 → clams_python-1.7.4}/documentation/tutorial.md +0 -0
  103. {clams_python-1.7.2 → clams_python-1.7.4}/setup.cfg +0 -0
  104. {clams_python-1.7.2 → clams_python-1.7.4}/tests/metadata.py +0 -0
  105. {clams_python-1.7.2 → clams_python-1.7.4}/tests/pillow-logo.png +0 -0
  106. {clams_python-1.7.2 → clams_python-1.7.4}/tests/test_backends_hf.py +0 -0
@@ -1,4 +1,25 @@
1
1
 
2
+ ## releasing 1.7.3 (2026-07-09)
3
+ ### Overview
4
+ This patch includes critical bugfixes. See changes below.
5
+
6
+ ### Changes
7
+ * fixes handling of error during `annotate()` (and `_annotate()`) when running an app via cli.py (#297)
8
+ * added the `useReasoning` common parameter for promptable apps (#299) Note that release 1.7.2 was supposed to include this parameter (and the release note says so), but it was omitted by mistake.
9
+
10
+
11
+ ## releasing 1.7.2 (2026-07-07)
12
+ ### Overview
13
+ This patch adds experimental handling of "reasoning traces" of propmtable apps
14
+
15
+ ### Additions
16
+ * common parameter `useReasoning` (bool) is added
17
+ * when reasoning is on, in-line tagged reasoning traces (commonly within `<think>...</think>`) are separately stored in `modelReasoningTrace` of the TextDocument
18
+
19
+ > [!NOTE]
20
+ > The new names are tentative and can be changed in the near future.
21
+
22
+
2
23
  ## releasing 1.7.1 (2026-06-19)
3
24
  ### Overview
4
25
  Updates the `mmif-python` SDK dependency to 1.5.1 to incorporate a bugfix in VDH, with some other minor documentation generation improvements.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clams-python
3
- Version: 1.7.2
3
+ Version: 1.7.4
4
4
  Summary: A collection of APIs to develop CLAMS app for python
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: homepage, https://clams.ai
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
13
13
  Requires-Python: >=3.10
14
14
  Description-Content-Type: text/markdown
15
15
  License-File: LICENSE
16
- Requires-Dist: mmif-python==1.5.1
16
+ Requires-Dist: mmif-python==1.5.3
17
17
  Requires-Dist: Flask>=2
18
18
  Requires-Dist: Flask-RESTful>=0.3.9
19
19
  Requires-Dist: gunicorn>=20
@@ -49,6 +49,10 @@ falsy_values = [
49
49
  ]
50
50
 
51
51
 
52
+ class EmptyOutputWarning(UserWarning):
53
+ """Raised when an app's ``_annotate()`` produces no non-empty views."""
54
+
55
+
52
56
  class ClamsApp(ABC):
53
57
  """
54
58
  An abstract class to define API's for ClamsApps. A CLAMS app should inherit
@@ -191,6 +195,15 @@ class ClamsApp(ABC):
191
195
  t = datetime.now()
192
196
  with warnings.catch_warnings(record=True) as ws:
193
197
  annotated, cuda_profiler = self._profile_cuda_memory(self._annotate)(mmif, **refined)
198
+ new_views = [v for v in annotated.views if v.id not in existing_view_ids]
199
+ is_empty = lambda v: len(v.annotations) == 0 and not v.has_error() and not v.has_warnings()
200
+ for v in new_views:
201
+ if is_empty(v):
202
+ del annotated.views._items[v.id] # no public API to remove a view (mmif-python)
203
+ if all(is_empty(v) for v in new_views):
204
+ warnings.warn(f'App "{self.metadata.identifier}" produced no annotations for this '
205
+ f'input; the input may lack expected content, or there may genuinely '
206
+ f'be nothing to annotate.', EmptyOutputWarning)
194
207
  if ws:
195
208
  issued_warnings.extend(ws)
196
209
  if issued_warnings:
@@ -301,35 +314,81 @@ class ClamsApp(ABC):
301
314
  """
302
315
  A method to "sign" a new view that this app creates at the beginning of annotation.
303
316
  Signing will populate the view metadata with information and configuration of this app.
304
- The parameters passed to the :meth:`~clams.app.ClamsApp._annotate` must be
305
- passed to this method. This means all parameters for "common" configuration that
306
- are consumed in :meth:`~clams.app.ClamsApp.annotate` should not be recorded in the
307
- view metadata.
317
+
318
+ The ``runtime_conf`` argument can be either "refined" or "raw" parameters,
319
+ and what ends up recorded in the view metadata differs accordingly:
320
+
321
+ * "refined" params: the output of :meth:`~clams.app.ClamsApp._refine_params`,
322
+ identifiable by the presence of the internal ``_RAW_PARAMS_KEY`` marker.
323
+ These carry both the user's raw input and the fully resolved configuration
324
+ (declared parameters with their defaults filled in). Signing then populates
325
+ **two** metadata fields: ``parameters`` with the raw user input (before
326
+ defaults), and ``appConfiguration`` with the resolved configuration,
327
+ including the universal parameters (e.g. ``pretty``, ``runningTime``,
328
+ ``hwFetch``, ``tfSamplingMode``).
329
+ * "raw" params: an unrefined ``Dict[str, List[str]]``. Only the
330
+ ``parameters`` field is populated; there is no resolved configuration
331
+ to record. See :meth:`~clams.app.ClamsApp.add_parameters_to_metadata`
332
+ for the input channels these values come from and how each is recorded.
333
+
334
+ These two cases exist because of two distinct execution paths. On the normal
335
+ annotation path, :meth:`~clams.app.ClamsApp.annotate` refines the parameters
336
+ before invoking :meth:`~clams.app.ClamsApp._annotate`, so a well-behaved app
337
+ forwards those already-refined params here and gets the full two-field record.
338
+ On the error path (:meth:`~clams.app.ClamsApp.set_error_view`), refinement may
339
+ be exactly what failed (:meth:`~clams.app.ClamsApp._refine_params` raises on a
340
+ missing required parameter or an invalid choice) so the error view is signed
341
+ with the raw params to guarantee the error is still recorded.
342
+
308
343
  :param view: a view to sign
309
- :param runtime_conf: runtime configuration of the app as k-v pairs
344
+ :param runtime_conf: runtime configuration of the app, either refined
345
+ (output of :meth:`~clams.app.ClamsApp._refine_params`) or raw k-v pairs
310
346
  """
311
347
  view.metadata.app = str(self.metadata.identifier)
312
348
  if self.metadata.app_tags:
313
349
  view.metadata.set_additional_property('appTags', list(self.metadata.app_tags))
314
- params_map = {p.name: p for p in self.metadata.parameters}
315
350
  if self._RAW_PARAMS_KEY in runtime_conf:
316
351
  for k, v in runtime_conf.items():
317
352
  if k == self._RAW_PARAMS_KEY:
318
- for orik, oriv in v.items():
319
- if orik in params_map and params_map[orik].multivalued:
320
- view.metadata.add_parameter(orik, str(oriv))
321
- else:
322
- view.metadata.add_parameter(orik, oriv[0])
353
+ self.add_parameters_to_metadata(view, v)
323
354
  else:
324
355
  view.metadata.add_app_configuration(k, v)
325
356
  else:
326
- # meaning the parameters directly from flask or argparser and values are in lists
327
- for k, v in runtime_conf.items():
328
- if k in params_map and params_map[k].multivalued:
329
- view.metadata.add_parameter(k, str(v))
330
- else:
331
- view.metadata.add_parameter(k, v[0])
332
-
357
+ # unrefined params passed directly (no _RAW_PARAMS_KEY marker), e.g.
358
+ # the error path; values are lists
359
+ self.add_parameters_to_metadata(view, runtime_conf)
360
+
361
+ def add_parameters_to_metadata(self, view: View, parameters: dict):
362
+ """
363
+ Record raw runtime parameters into the view's ``parameters`` metadata.
364
+
365
+ The ``parameters`` argument reaches an app through one of three channels:
366
+
367
+ #. a query string, when the app runs as an HTTP server (``app.py``, via
368
+ :class:`~clams.restify.Restifier`);
369
+ #. shell arguments, when the app runs as a CLI program (``cli.py``);
370
+ #. a JSON envelope built with the ``clams envelop`` command (see
371
+ :mod:`clams.envelop`), whose values are flattened by
372
+ :func:`~clams.envelop.normalize_params`.
373
+
374
+ In every case the values arrive as ``List[str]`` (the shape
375
+ :meth:`~clams.app.ClamsApp._refine_params` consumes). A single value is
376
+ recorded bare with the ``List`` wrapper stripped, multiple values as the
377
+ serialized list, and an empty list skipped as unset (only an envelope
378
+ such as ``{"x": []}`` produces one, guarding against an ``IndexError``
379
+ on ``v[0]``).
380
+
381
+ :param view: the view being signed
382
+ :param parameters: raw runtime parameters as ``Dict[str, List[str]]``
383
+ """
384
+ for k, v in parameters.items():
385
+ if len(v) == 0:
386
+ continue
387
+ elif len(v) == 1:
388
+ view.metadata.add_parameter(k, v[0])
389
+ else:
390
+ view.metadata.add_parameter(k, str(v))
391
+
333
392
  def set_error_view(self, mmif: Union[str, dict, Mmif], **runtime_conf: List[str]) -> Mmif:
334
393
  """
335
394
  A method to record an error instead of annotation results in the view
@@ -711,6 +770,26 @@ class ClamsPromptableApp(ClamsApp):
711
770
  'values grow the KV cache linearly and increase GPU memory '
712
771
  'usage; reduce if VRAM is constrained.',
713
772
  },
773
+ {
774
+ 'name': 'useReasoning', 'type': 'boolean', 'default': False,
775
+ 'description':
776
+ 'Request the model\'s reasoning ("thinking") mode. Off by '
777
+ 'default. Honored only by apps whose backing model has a '
778
+ 'distinct reasoning mode; apps without one ignore it. When '
779
+ 'honored and enabled, the reasoning trace is split from the '
780
+ 'answer and stored in the ``modelReasoningTrace`` property of '
781
+ 'the output ``TextDocument`` (kept out of the document text). '
782
+ 'Reasoning is markedly slower and far more token-hungry: the '
783
+ 'whole trace is generated before the answer and drawn from the '
784
+ 'same budget capped by ``maxNewTokens``, so raise '
785
+ '``maxNewTokens`` substantially (thousands of tokens, not '
786
+ 'hundreds) when enabling this, or the trace may consume the '
787
+ 'entire budget and the answer be truncated or empty. Small '
788
+ 'reasoning models (as a rule of thumb, roughly 4B parameters '
789
+ 'and under) are especially prone to non-terminating "thinking '
790
+ 'loops" that exhaust the budget without producing an answer; '
791
+ 'validate termination per model before relying on it.',
792
+ },
714
793
  {
715
794
  'name': 'temperature', 'type': 'number', 'default': 0.0,
716
795
  'description':
@@ -1109,37 +1188,56 @@ class ClamsPromptableApp(ClamsApp):
1109
1188
  text: str,
1110
1189
  open_tag: str = '<think>',
1111
1190
  close_tag: str = '</think>',
1191
+ assume_open: bool = False,
1112
1192
  ) -> Tuple[str, Optional[str]]:
1113
1193
  """
1114
1194
  Split a reasoning model's output into ``(answer, trace)`` for the
1115
- inline XML-tag style: a single reasoning block delimited by
1116
- ``open_tag`` / ``close_tag`` (default ``<think>`` / ``</think>``)
1117
- embedded in the decoded text, e.g. as emitted by DeepSeek-R1 or
1118
- Qwen3.
1119
-
1120
- It does NOT handle models that isolate reasoning in a separate
1121
- token-delimited channel rather than an inline tag block (e.g.
1122
- gpt-oss, Gemma 4); those need their own parsing in the app. Trace
1123
- handling is the app's responsibility either way -- call this when
1124
- the model fits the inline-tag style, or parse it yourself.
1125
-
1126
- ``answer`` is everything after the final ``close_tag`` (stripped);
1127
- ``trace`` is the text between the tags, or ``None`` when no closed
1128
- block is present -- so it is safe to call on non-reasoning output,
1129
- which returns ``(text.strip(), None)``.
1195
+ inline XML-tag style: a reasoning block delimited by ``open_tag`` /
1196
+ ``close_tag`` (default ``<think>`` / ``</think>``), e.g. as emitted
1197
+ by DeepSeek-R1 or Qwen3.5.
1198
+
1199
+ Prefilled opening tags: some chat templates inject the OPENING tag
1200
+ into the prompt when reasoning is enabled (Qwen3.5 does this), so the
1201
+ decoded output carries only the CLOSING tag -- the model never emits
1202
+ the opener. Pass ``assume_open=True`` in that situation (typically
1203
+ wired to the app's reasoning toggle) so the trace is still recovered.
1204
+ The cases:
1205
+
1206
+ * close tag present: ``answer`` is the text after it; ``trace`` is the
1207
+ text between the tags, or everything before the close tag when the
1208
+ opening tag is absent (prefilled).
1209
+ * close tag absent, ``assume_open=True``: the output is unterminated
1210
+ reasoning (e.g. the trace overran ``maxNewTokens`` before closing) --
1211
+ there is no answer, so returns ``('', text.strip())``.
1212
+ * close tag absent, ``assume_open=False`` (default): treated as a
1213
+ plain, non-reasoning answer -- returns ``(text.strip(), None)``.
1214
+
1215
+ Only the inline-tag style is handled; models that isolate reasoning in
1216
+ a separate token-delimited channel (e.g. gpt-oss, Gemma) need their own
1217
+ parsing in the app.
1130
1218
 
1131
1219
  :param text: raw decoded model output.
1132
1220
  :param open_tag: opening marker of the inline reasoning block.
1133
1221
  :param close_tag: closing marker of the inline reasoning block.
1222
+ :param assume_open: treat the text as the body of a reasoning block
1223
+ whose opening tag was prefilled into the prompt, so a missing close
1224
+ tag means unterminated reasoning (empty answer) rather than a plain
1225
+ answer.
1134
1226
  :return: ``(answer, trace_or_None)``.
1135
1227
  """
1136
1228
  ci = text.rfind(close_tag)
1137
1229
  if ci == -1:
1138
- return text.strip(), None
1230
+ return ('', text.strip()) if assume_open else (text.strip(), None)
1139
1231
  answer = text[ci + len(close_tag):].strip()
1140
1232
  oi = text.find(open_tag)
1141
- trace = (text[oi + len(open_tag):ci].strip()
1142
- if oi != -1 and oi < ci else None)
1233
+ if oi != -1 and oi < ci:
1234
+ trace = text[oi + len(open_tag):ci].strip()
1235
+ elif assume_open:
1236
+ # opening tag was prefilled into the prompt (not generated), so the
1237
+ # trace is everything up to the close tag
1238
+ trace = text[:ci].strip()
1239
+ else:
1240
+ trace = None
1143
1241
  return answer, trace
1144
1242
  class ClamsHFPromptableApp(ClamsPromptableApp):
1145
1243
  """
@@ -1511,10 +1609,13 @@ class ClamsHFPromptableApp(ClamsPromptableApp):
1511
1609
  implementation returns ``{}``.
1512
1610
 
1513
1611
  Override to inject model-specific chat-template controls without
1514
- having to reimplement :py:meth:`generate`. Common cases:
1612
+ having to reimplement :py:meth:`generate`. This is where an app
1613
+ honors the SDK ``useReasoning`` parameter, mapping it onto the
1614
+ backend's reasoning switch. Common cases:
1515
1615
 
1516
- * ``{'enable_thinking': False}`` to run a reasoning ("thinking")
1517
- model in non-thinking mode;
1616
+ * ``{'enable_thinking': bool(generation_params.get('use_reasoning'))}``
1617
+ to bind ``useReasoning`` to a reasoning ("thinking") model's
1618
+ template switch;
1518
1619
  * ``{'tools': [...]}`` or ``{'documents': [...]}`` for tool-use /
1519
1620
  RAG chat templates.
1520
1621
 
@@ -3,7 +3,7 @@ FROM ghcr.io/clamsproject/clams-python:$CLAMS_VERSION
3
3
  # See https://github.com/orgs/clamsproject/packages?tab=packages&q=clams-python for more base images
4
4
  # IF you want to automatically publish this image to the clamsproject organization,
5
5
  # 1. you should have generated this template without --no-github-actions flag
6
- # 1. to add arm64 support, change relevant line in .github/workflows/container.yml
6
+ # 1. to add arm64 support, set `arm64: true` in .github/workflows/publish.yml
7
7
  # * NOTE that a lots of software doesn't install/compile or run on arm64 architecture out of the box
8
8
  # * make sure you locally test the compatibility of all software dependencies before using arm64 support
9
9
  # 1. use a git tag to trigger the github action. You need to use git tag to properly set app version anyway
@@ -6,13 +6,17 @@ DO NOT CHANGE the name of the file
6
6
  """
7
7
 
8
8
  import argparse
9
+ import json
9
10
  import sys
10
11
  from contextlib import redirect_stdout
11
12
 
13
+ import jsonschema
14
+
12
15
  import app
13
16
 
14
17
  import clams.app
15
18
  from clams import AppMetadata
19
+ from clams.envelop import EnvelopeError
16
20
 
17
21
 
18
22
  def metadata_to_argparser(app_metadata: AppMetadata) -> argparse.ArgumentParser:
@@ -81,11 +85,24 @@ if __name__ == "__main__":
81
85
  params[pname] = pvalue
82
86
  else:
83
87
  params[pname] = [pvalue]
84
- if args.OUT_MMIF_FILE.name == '<stdout>':
85
- with redirect_stdout(sys.stderr):
88
+ # Mirror the HTTP server's error handling (see clams.restify): an invalid
89
+ # input is reported and exits non-zero, while an app-level failure is
90
+ # recorded as an error view instead of crashing with a raw traceback.
91
+ try:
92
+ if args.OUT_MMIF_FILE.name == '<stdout>':
93
+ with redirect_stdout(sys.stderr):
94
+ out_mmif = clamsapp.annotate(in_data, **params)
95
+ else:
86
96
  out_mmif = clamsapp.annotate(in_data, **params)
87
- else:
88
- out_mmif = clamsapp.annotate(in_data, **params)
97
+ except (jsonschema.exceptions.ValidationError, json.JSONDecodeError, EnvelopeError) as e:
98
+ detail = e.message if isinstance(e, jsonschema.exceptions.ValidationError) else str(e)
99
+ print(f"Invalid input data. See below for validation error.\n\n{detail}", file=sys.stderr)
100
+ sys.exit(1)
101
+ except Exception:
102
+ clamsapp.logger.exception("Error in annotation")
103
+ out_mmif = clamsapp.record_error(in_data, **params).serialize(pretty=True)
104
+ args.OUT_MMIF_FILE.write(out_mmif)
105
+ sys.exit(1)
89
106
  args.OUT_MMIF_FILE.write(out_mmif)
90
107
  else:
91
108
  arg_parser.print_help()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clams-python
3
- Version: 1.7.2
3
+ Version: 1.7.4
4
4
  Summary: A collection of APIs to develop CLAMS app for python
5
5
  License-Expression: Apache-2.0
6
6
  Project-URL: homepage, https://clams.ai
@@ -13,7 +13,7 @@ Classifier: Programming Language :: Python :: 3 :: Only
13
13
  Requires-Python: >=3.10
14
14
  Description-Content-Type: text/markdown
15
15
  License-File: LICENSE
16
- Requires-Dist: mmif-python==1.5.1
16
+ Requires-Dist: mmif-python==1.5.3
17
17
  Requires-Dist: Flask>=2
18
18
  Requires-Dist: Flask-RESTful>=0.3.9
19
19
  Requires-Dist: gunicorn>=20
@@ -1,4 +1,4 @@
1
- mmif-python==1.5.1
1
+ mmif-python==1.5.3
2
2
  Flask>=2
3
3
  Flask-RESTful>=0.3.9
4
4
  gunicorn>=20
@@ -1,96 +1,96 @@
1
1
  {
2
2
  "files": [
3
- "README.md",
4
- "LICENSE",
5
- "pyproject.toml",
3
+ ".github/workflows/codecov.yml",
4
+ ".github/workflows/container.yml",
5
+ ".github/workflows/containers.yml",
6
+ ".github/workflows/issue-assign.yml",
7
+ ".github/workflows/issue-close.yml",
8
+ ".github/workflows/issue-infra-project.yml",
9
+ ".github/workflows/publish.yml",
10
+ ".github/workflows/release-check.yml",
11
+ ".gitignore",
6
12
  ".pytype.cfg",
7
13
  "CHANGELOG.md",
8
14
  "CONTRIBUTING.md",
9
- ".gitignore",
10
- "build-tools/publish.py",
11
- "build-tools/prep_release.py",
15
+ "LICENSE",
16
+ "README.md",
12
17
  "build-tools/build.py",
13
- "build-tools/docs.py",
14
18
  "build-tools/clean.py",
19
+ "build-tools/docs.py",
20
+ "build-tools/prep_release.py",
21
+ "build-tools/publish.py",
15
22
  "build-tools/test.py",
16
23
  "clams/__init__.py",
24
+ "clams/app/__init__.py",
25
+ "clams/appmetadata/__init__.py",
26
+ "clams/backends/__init__.py",
27
+ "clams/backends/hf.py",
17
28
  "clams/develop/__init__.py",
29
+ "clams/develop/templates/app/.dockerignore.template",
30
+ "clams/develop/templates/app/.gitignore.template",
31
+ "clams/develop/templates/app/Containerfile.template",
32
+ "clams/develop/templates/app/LICENSE.template",
33
+ "clams/develop/templates/app/README.md.template",
34
+ "clams/develop/templates/app/app.py.template",
35
+ "clams/develop/templates/app/cli.py.template",
36
+ "clams/develop/templates/app/metadata.py.template",
37
+ "clams/develop/templates/app/requirements.txt.template",
18
38
  "clams/develop/templates/gha/for-clams-team.md.template",
19
- "clams/develop/templates/gha/workflows/issue-assign.yml.template",
20
- "clams/develop/templates/gha/workflows/publish.yml.template",
21
39
  "clams/develop/templates/gha/workflows/issue-apps-project.yml.template",
40
+ "clams/develop/templates/gha/workflows/issue-assign.yml.template",
22
41
  "clams/develop/templates/gha/workflows/issue-close.yml.template",
42
+ "clams/develop/templates/gha/workflows/publish.yml.template",
23
43
  "clams/develop/templates/utl-tf/__init__.py.template",
24
44
  "clams/develop/templates/utl-tf/timeframe.py.template",
25
- "clams/develop/templates/app/Containerfile.template",
26
- "clams/develop/templates/app/metadata.py.template",
27
- "clams/develop/templates/app/README.md.template",
28
- "clams/develop/templates/app/.dockerignore.template",
29
- "clams/develop/templates/app/requirements.txt.template",
30
- "clams/develop/templates/app/LICENSE.template",
31
- "clams/develop/templates/app/.gitignore.template",
32
- "clams/develop/templates/app/app.py.template",
33
- "clams/develop/templates/app/cli.py.template",
34
- "clams/restify/__init__.py",
35
45
  "clams/envelop/__init__.py",
36
- "clams/appmetadata/__init__.py",
37
- "clams/app/__init__.py",
46
+ "clams/restify/__init__.py",
38
47
  "clams/serve/__init__.py",
39
48
  "clams/ver/__init__.py",
40
- "clams/backends/__init__.py",
41
- "clams/backends/hf.py",
42
- "documentation/modules.rst",
43
- "documentation/target-versions.csv",
49
+ "container/Containerfile",
50
+ "container/ffmpeg-hf.containerfile",
51
+ "container/ffmpeg-hf4.containerfile",
52
+ "container/ffmpeg-hf5.containerfile",
53
+ "container/ffmpeg-tf2.containerfile",
54
+ "container/ffmpeg-torch2.containerfile",
55
+ "container/ffmpeg.containerfile",
56
+ "container/generate_containers_yml.py",
57
+ "container/hf.containerfile",
58
+ "container/hf4.containerfile",
59
+ "container/hf5.containerfile",
60
+ "container/jdk8.containerfile",
61
+ "container/opencv4-hf.containerfile",
62
+ "container/opencv4-hf4.containerfile",
63
+ "container/opencv4-hf5.containerfile",
64
+ "container/opencv4-tf2.containerfile",
65
+ "container/opencv4-torch2.containerfile",
66
+ "container/opencv4.containerfile",
67
+ "container/tf2.containerfile",
68
+ "container/torch2.containerfile",
44
69
  "documentation/app-baseclasses.rst",
45
- "documentation/gpu-apps.rst",
46
- "documentation/clamsapp.rst",
47
70
  "documentation/appdirectory.rst",
48
- "documentation/index.rst",
49
- "documentation/tutorial.md",
50
- "documentation/introduction.rst",
51
71
  "documentation/appmetadata.rst",
52
- "documentation/cli.rst",
53
- "documentation/runtime-params.rst",
54
- "documentation/input-output.rst",
55
- "documentation/conf.py",
56
- "documentation/autodoc/clams.restify.rst",
57
72
  "documentation/autodoc/clams.app.rst",
73
+ "documentation/autodoc/clams.appmetadata.rst",
58
74
  "documentation/autodoc/clams.backends.rst",
59
75
  "documentation/autodoc/clams.mmif_utils.rst",
60
- "documentation/autodoc/clams.appmetadata.rst",
61
- "tests/test_promptable.py",
76
+ "documentation/autodoc/clams.restify.rst",
77
+ "documentation/clamsapp.rst",
78
+ "documentation/cli.rst",
79
+ "documentation/conf.py",
80
+ "documentation/gpu-apps.rst",
81
+ "documentation/index.rst",
82
+ "documentation/input-output.rst",
83
+ "documentation/introduction.rst",
84
+ "documentation/modules.rst",
85
+ "documentation/runtime-params.rst",
86
+ "documentation/target-versions.csv",
87
+ "documentation/tutorial.md",
88
+ "pyproject.toml",
89
+ "tests/metadata.py",
62
90
  "tests/pillow-logo.png",
63
91
  "tests/test_backends_hf.py",
64
- "tests/test_envelope.py",
65
- "tests/metadata.py",
66
92
  "tests/test_clamsapp.py",
67
- "container/tf2.containerfile",
68
- "container/opencv4-hf.containerfile",
69
- "container/torch2.containerfile",
70
- "container/opencv4-hf4.containerfile",
71
- "container/Containerfile",
72
- "container/hf4.containerfile",
73
- "container/ffmpeg-hf.containerfile",
74
- "container/ffmpeg-tf2.containerfile",
75
- "container/generate_containers_yml.py",
76
- "container/opencv4-tf2.containerfile",
77
- "container/opencv4-torch2.containerfile",
78
- "container/hf.containerfile",
79
- "container/jdk8.containerfile",
80
- "container/hf5.containerfile",
81
- "container/ffmpeg.containerfile",
82
- "container/ffmpeg-hf5.containerfile",
83
- "container/ffmpeg-hf4.containerfile",
84
- "container/opencv4-hf5.containerfile",
85
- "container/ffmpeg-torch2.containerfile",
86
- "container/opencv4.containerfile",
87
- ".github/workflows/container.yml",
88
- ".github/workflows/containers.yml",
89
- ".github/workflows/issue-close.yml",
90
- ".github/workflows/codecov.yml",
91
- ".github/workflows/release-check.yml",
92
- ".github/workflows/issue-infra-project.yml",
93
- ".github/workflows/issue-assign.yml",
94
- ".github/workflows/publish.yml"
93
+ "tests/test_envelope.py",
94
+ "tests/test_promptable.py"
95
95
  ]
96
96
  }
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "1.7.4",
3
+ "distance": 0,
4
+ "node": "g4a9316fc63b59287b43542fd15047a9a28028510",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-09-01"
8
+ }
@@ -0,0 +1,13 @@
1
+ ARG clams_version
2
+ FROM ghcr.io/clamsproject/clams-python-ffmpeg:$clams_version
3
+ LABEL org.opencontainers.image.description="clams-python-ffmpeg-torch2 image is shipped with clams-python, ffmpeg, and PyTorch2"
4
+
5
+ RUN pip install --no-cache-dir torch==2.*
6
+
7
+ # PyTorch ships Triton, which JIT-compiles a small host-side CUDA driver shim
8
+ # at runtime -- that needs a C compiler + libc headers. Keep it minimal
9
+ # (gcc + libc6-dev); build-essential is not required.
10
+ RUN apt-get update \
11
+ && apt-get install -y --no-install-recommends gcc libc6-dev \
12
+ && rm -rf /var/lib/apt/lists/*
13
+
@@ -0,0 +1,13 @@
1
+ ARG clams_version
2
+ FROM ghcr.io/clamsproject/clams-python-opencv4:$clams_version
3
+ LABEL org.opencontainers.image.description="clams-python-opencv4-torch2 image is shipped with clams-python, opencv4 (ffmpeg backend), and PyTorch2"
4
+
5
+ RUN pip install --no-cache-dir torch==2.*
6
+
7
+ # PyTorch ships Triton, which JIT-compiles a small host-side CUDA driver shim
8
+ # at runtime -- that needs a C compiler + libc headers. Keep it minimal
9
+ # (gcc + libc6-dev); build-essential is not required.
10
+ RUN apt-get update \
11
+ && apt-get install -y --no-install-recommends gcc libc6-dev \
12
+ && rm -rf /var/lib/apt/lists/*
13
+
@@ -0,0 +1,13 @@
1
+ ARG clams_version
2
+ FROM ghcr.io/clamsproject/clams-python:$clams_version
3
+ LABEL org.opencontainers.image.description="clams-python-torch2 image is shipped with clams-python and PyTorch2"
4
+
5
+ RUN pip install --no-cache-dir torch==2.*
6
+
7
+ # PyTorch ships Triton, which JIT-compiles a small host-side CUDA driver shim
8
+ # at runtime -- that needs a C compiler + libc headers. Keep it minimal
9
+ # (gcc + libc6-dev); build-essential is not required.
10
+ RUN apt-get update \
11
+ && apt-get install -y --no-install-recommends gcc libc6-dev \
12
+ && rm -rf /var/lib/apt/lists/*
13
+