clams-python 1.7.2__tar.gz → 1.7.3__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 (103) hide show
  1. {clams_python-1.7.2 → clams_python-1.7.3}/CHANGELOG.md +12 -0
  2. {clams_python-1.7.2/clams_python.egg-info → clams_python-1.7.3}/PKG-INFO +2 -2
  3. {clams_python-1.7.2 → clams_python-1.7.3}/clams/app/__init__.py +63 -21
  4. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/templates/app/cli.py.template +21 -4
  5. {clams_python-1.7.2 → clams_python-1.7.3/clams_python.egg-info}/PKG-INFO +2 -2
  6. {clams_python-1.7.2 → clams_python-1.7.3}/clams_python.egg-info/requires.txt +1 -1
  7. clams_python-1.7.3/clams_python.egg-info/scm_version.json +8 -0
  8. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/app-baseclasses.rst +61 -1
  9. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/conf.py +3 -1
  10. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/target-versions.csv +1 -0
  11. {clams_python-1.7.2 → clams_python-1.7.3}/pyproject.toml +1 -1
  12. {clams_python-1.7.2 → clams_python-1.7.3}/tests/test_promptable.py +22 -0
  13. clams_python-1.7.2/clams_python.egg-info/scm_version.json +0 -8
  14. {clams_python-1.7.2 → clams_python-1.7.3}/.github/workflows/codecov.yml +0 -0
  15. {clams_python-1.7.2 → clams_python-1.7.3}/.github/workflows/container.yml +0 -0
  16. {clams_python-1.7.2 → clams_python-1.7.3}/.github/workflows/containers.yml +0 -0
  17. {clams_python-1.7.2 → clams_python-1.7.3}/.github/workflows/issue-assign.yml +0 -0
  18. {clams_python-1.7.2 → clams_python-1.7.3}/.github/workflows/issue-close.yml +0 -0
  19. {clams_python-1.7.2 → clams_python-1.7.3}/.github/workflows/issue-infra-project.yml +0 -0
  20. {clams_python-1.7.2 → clams_python-1.7.3}/.github/workflows/publish.yml +0 -0
  21. {clams_python-1.7.2 → clams_python-1.7.3}/.github/workflows/release-check.yml +0 -0
  22. {clams_python-1.7.2 → clams_python-1.7.3}/.gitignore +0 -0
  23. {clams_python-1.7.2 → clams_python-1.7.3}/.pytype.cfg +0 -0
  24. {clams_python-1.7.2 → clams_python-1.7.3}/CONTRIBUTING.md +0 -0
  25. {clams_python-1.7.2 → clams_python-1.7.3}/LICENSE +0 -0
  26. {clams_python-1.7.2 → clams_python-1.7.3}/README.md +0 -0
  27. {clams_python-1.7.2 → clams_python-1.7.3}/build-tools/build.py +0 -0
  28. {clams_python-1.7.2 → clams_python-1.7.3}/build-tools/clean.py +0 -0
  29. {clams_python-1.7.2 → clams_python-1.7.3}/build-tools/docs.py +0 -0
  30. {clams_python-1.7.2 → clams_python-1.7.3}/build-tools/prep_release.py +0 -0
  31. {clams_python-1.7.2 → clams_python-1.7.3}/build-tools/publish.py +0 -0
  32. {clams_python-1.7.2 → clams_python-1.7.3}/build-tools/test.py +0 -0
  33. {clams_python-1.7.2 → clams_python-1.7.3}/clams/__init__.py +0 -0
  34. {clams_python-1.7.2 → clams_python-1.7.3}/clams/appmetadata/__init__.py +0 -0
  35. {clams_python-1.7.2 → clams_python-1.7.3}/clams/backends/__init__.py +0 -0
  36. {clams_python-1.7.2 → clams_python-1.7.3}/clams/backends/hf.py +0 -0
  37. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/__init__.py +0 -0
  38. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/templates/app/.dockerignore.template +0 -0
  39. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/templates/app/.gitignore.template +0 -0
  40. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/templates/app/Containerfile.template +0 -0
  41. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/templates/app/LICENSE.template +0 -0
  42. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/templates/app/README.md.template +0 -0
  43. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/templates/app/app.py.template +0 -0
  44. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/templates/app/metadata.py.template +0 -0
  45. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/templates/app/requirements.txt.template +0 -0
  46. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/templates/gha/for-clams-team.md.template +0 -0
  47. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/templates/gha/workflows/issue-apps-project.yml.template +0 -0
  48. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/templates/gha/workflows/issue-assign.yml.template +0 -0
  49. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/templates/gha/workflows/issue-close.yml.template +0 -0
  50. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/templates/gha/workflows/publish.yml.template +0 -0
  51. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/templates/utl-tf/__init__.py.template +0 -0
  52. {clams_python-1.7.2 → clams_python-1.7.3}/clams/develop/templates/utl-tf/timeframe.py.template +0 -0
  53. {clams_python-1.7.2 → clams_python-1.7.3}/clams/envelop/__init__.py +0 -0
  54. {clams_python-1.7.2 → clams_python-1.7.3}/clams/restify/__init__.py +0 -0
  55. {clams_python-1.7.2 → clams_python-1.7.3}/clams/serve/__init__.py +0 -0
  56. {clams_python-1.7.2 → clams_python-1.7.3}/clams/ver/__init__.py +0 -0
  57. {clams_python-1.7.2 → clams_python-1.7.3}/clams_python.egg-info/SOURCES.txt +0 -0
  58. {clams_python-1.7.2 → clams_python-1.7.3}/clams_python.egg-info/dependency_links.txt +0 -0
  59. {clams_python-1.7.2 → clams_python-1.7.3}/clams_python.egg-info/entry_points.txt +0 -0
  60. {clams_python-1.7.2 → clams_python-1.7.3}/clams_python.egg-info/scm_file_list.json +0 -0
  61. {clams_python-1.7.2 → clams_python-1.7.3}/clams_python.egg-info/top_level.txt +0 -0
  62. {clams_python-1.7.2 → clams_python-1.7.3}/container/Containerfile +0 -0
  63. {clams_python-1.7.2 → clams_python-1.7.3}/container/ffmpeg-hf.containerfile +0 -0
  64. {clams_python-1.7.2 → clams_python-1.7.3}/container/ffmpeg-hf4.containerfile +0 -0
  65. {clams_python-1.7.2 → clams_python-1.7.3}/container/ffmpeg-hf5.containerfile +0 -0
  66. {clams_python-1.7.2 → clams_python-1.7.3}/container/ffmpeg-tf2.containerfile +0 -0
  67. {clams_python-1.7.2 → clams_python-1.7.3}/container/ffmpeg-torch2.containerfile +0 -0
  68. {clams_python-1.7.2 → clams_python-1.7.3}/container/ffmpeg.containerfile +0 -0
  69. {clams_python-1.7.2 → clams_python-1.7.3}/container/generate_containers_yml.py +0 -0
  70. {clams_python-1.7.2 → clams_python-1.7.3}/container/hf.containerfile +0 -0
  71. {clams_python-1.7.2 → clams_python-1.7.3}/container/hf4.containerfile +0 -0
  72. {clams_python-1.7.2 → clams_python-1.7.3}/container/hf5.containerfile +0 -0
  73. {clams_python-1.7.2 → clams_python-1.7.3}/container/jdk8.containerfile +0 -0
  74. {clams_python-1.7.2 → clams_python-1.7.3}/container/opencv4-hf.containerfile +0 -0
  75. {clams_python-1.7.2 → clams_python-1.7.3}/container/opencv4-hf4.containerfile +0 -0
  76. {clams_python-1.7.2 → clams_python-1.7.3}/container/opencv4-hf5.containerfile +0 -0
  77. {clams_python-1.7.2 → clams_python-1.7.3}/container/opencv4-tf2.containerfile +0 -0
  78. {clams_python-1.7.2 → clams_python-1.7.3}/container/opencv4-torch2.containerfile +0 -0
  79. {clams_python-1.7.2 → clams_python-1.7.3}/container/opencv4.containerfile +0 -0
  80. {clams_python-1.7.2 → clams_python-1.7.3}/container/tf2.containerfile +0 -0
  81. {clams_python-1.7.2 → clams_python-1.7.3}/container/torch2.containerfile +0 -0
  82. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/appdirectory.rst +0 -0
  83. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/appmetadata.rst +0 -0
  84. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/autodoc/clams.app.rst +0 -0
  85. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/autodoc/clams.appmetadata.rst +0 -0
  86. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/autodoc/clams.backends.rst +0 -0
  87. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/autodoc/clams.mmif_utils.rst +0 -0
  88. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/autodoc/clams.restify.rst +0 -0
  89. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/clamsapp.rst +0 -0
  90. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/cli.rst +0 -0
  91. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/gpu-apps.rst +0 -0
  92. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/index.rst +0 -0
  93. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/input-output.rst +0 -0
  94. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/introduction.rst +0 -0
  95. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/modules.rst +0 -0
  96. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/runtime-params.rst +0 -0
  97. {clams_python-1.7.2 → clams_python-1.7.3}/documentation/tutorial.md +0 -0
  98. {clams_python-1.7.2 → clams_python-1.7.3}/setup.cfg +0 -0
  99. {clams_python-1.7.2 → clams_python-1.7.3}/tests/metadata.py +0 -0
  100. {clams_python-1.7.2 → clams_python-1.7.3}/tests/pillow-logo.png +0 -0
  101. {clams_python-1.7.2 → clams_python-1.7.3}/tests/test_backends_hf.py +0 -0
  102. {clams_python-1.7.2 → clams_python-1.7.3}/tests/test_clamsapp.py +0 -0
  103. {clams_python-1.7.2 → clams_python-1.7.3}/tests/test_envelope.py +0 -0
@@ -1,4 +1,16 @@
1
1
 
2
+ ## releasing 1.7.2 (2026-07-07)
3
+ ### Overview
4
+ This patch adds experimental handling of "reasoning traces" of propmtable apps
5
+
6
+ ### Additions
7
+ * common parameter `useReasoning` (bool) is added
8
+ * when reasoning is on, in-line tagged reasoning traces (commonly within `<think>...</think>`) are separately stored in `modelReasoningTrace` of the TextDocument
9
+
10
+ > [!NOTE]
11
+ > The new names are tentative and can be changed in the near future.
12
+
13
+
2
14
  ## releasing 1.7.1 (2026-06-19)
3
15
  ### Overview
4
16
  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.3
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
@@ -711,6 +711,26 @@ class ClamsPromptableApp(ClamsApp):
711
711
  'values grow the KV cache linearly and increase GPU memory '
712
712
  'usage; reduce if VRAM is constrained.',
713
713
  },
714
+ {
715
+ 'name': 'useReasoning', 'type': 'boolean', 'default': False,
716
+ 'description':
717
+ 'Request the model\'s reasoning ("thinking") mode. Off by '
718
+ 'default. Honored only by apps whose backing model has a '
719
+ 'distinct reasoning mode; apps without one ignore it. When '
720
+ 'honored and enabled, the reasoning trace is split from the '
721
+ 'answer and stored in the ``modelReasoningTrace`` property of '
722
+ 'the output ``TextDocument`` (kept out of the document text). '
723
+ 'Reasoning is markedly slower and far more token-hungry: the '
724
+ 'whole trace is generated before the answer and drawn from the '
725
+ 'same budget capped by ``maxNewTokens``, so raise '
726
+ '``maxNewTokens`` substantially (thousands of tokens, not '
727
+ 'hundreds) when enabling this, or the trace may consume the '
728
+ 'entire budget and the answer be truncated or empty. Small '
729
+ 'reasoning models (as a rule of thumb, roughly 4B parameters '
730
+ 'and under) are especially prone to non-terminating "thinking '
731
+ 'loops" that exhaust the budget without producing an answer; '
732
+ 'validate termination per model before relying on it.',
733
+ },
714
734
  {
715
735
  'name': 'temperature', 'type': 'number', 'default': 0.0,
716
736
  'description':
@@ -1109,37 +1129,56 @@ class ClamsPromptableApp(ClamsApp):
1109
1129
  text: str,
1110
1130
  open_tag: str = '<think>',
1111
1131
  close_tag: str = '</think>',
1132
+ assume_open: bool = False,
1112
1133
  ) -> Tuple[str, Optional[str]]:
1113
1134
  """
1114
1135
  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)``.
1136
+ inline XML-tag style: a reasoning block delimited by ``open_tag`` /
1137
+ ``close_tag`` (default ``<think>`` / ``</think>``), e.g. as emitted
1138
+ by DeepSeek-R1 or Qwen3.5.
1139
+
1140
+ Prefilled opening tags: some chat templates inject the OPENING tag
1141
+ into the prompt when reasoning is enabled (Qwen3.5 does this), so the
1142
+ decoded output carries only the CLOSING tag -- the model never emits
1143
+ the opener. Pass ``assume_open=True`` in that situation (typically
1144
+ wired to the app's reasoning toggle) so the trace is still recovered.
1145
+ The cases:
1146
+
1147
+ * close tag present: ``answer`` is the text after it; ``trace`` is the
1148
+ text between the tags, or everything before the close tag when the
1149
+ opening tag is absent (prefilled).
1150
+ * close tag absent, ``assume_open=True``: the output is unterminated
1151
+ reasoning (e.g. the trace overran ``maxNewTokens`` before closing) --
1152
+ there is no answer, so returns ``('', text.strip())``.
1153
+ * close tag absent, ``assume_open=False`` (default): treated as a
1154
+ plain, non-reasoning answer -- returns ``(text.strip(), None)``.
1155
+
1156
+ Only the inline-tag style is handled; models that isolate reasoning in
1157
+ a separate token-delimited channel (e.g. gpt-oss, Gemma) need their own
1158
+ parsing in the app.
1130
1159
 
1131
1160
  :param text: raw decoded model output.
1132
1161
  :param open_tag: opening marker of the inline reasoning block.
1133
1162
  :param close_tag: closing marker of the inline reasoning block.
1163
+ :param assume_open: treat the text as the body of a reasoning block
1164
+ whose opening tag was prefilled into the prompt, so a missing close
1165
+ tag means unterminated reasoning (empty answer) rather than a plain
1166
+ answer.
1134
1167
  :return: ``(answer, trace_or_None)``.
1135
1168
  """
1136
1169
  ci = text.rfind(close_tag)
1137
1170
  if ci == -1:
1138
- return text.strip(), None
1171
+ return ('', text.strip()) if assume_open else (text.strip(), None)
1139
1172
  answer = text[ci + len(close_tag):].strip()
1140
1173
  oi = text.find(open_tag)
1141
- trace = (text[oi + len(open_tag):ci].strip()
1142
- if oi != -1 and oi < ci else None)
1174
+ if oi != -1 and oi < ci:
1175
+ trace = text[oi + len(open_tag):ci].strip()
1176
+ elif assume_open:
1177
+ # opening tag was prefilled into the prompt (not generated), so the
1178
+ # trace is everything up to the close tag
1179
+ trace = text[:ci].strip()
1180
+ else:
1181
+ trace = None
1143
1182
  return answer, trace
1144
1183
  class ClamsHFPromptableApp(ClamsPromptableApp):
1145
1184
  """
@@ -1511,10 +1550,13 @@ class ClamsHFPromptableApp(ClamsPromptableApp):
1511
1550
  implementation returns ``{}``.
1512
1551
 
1513
1552
  Override to inject model-specific chat-template controls without
1514
- having to reimplement :py:meth:`generate`. Common cases:
1553
+ having to reimplement :py:meth:`generate`. This is where an app
1554
+ honors the SDK ``useReasoning`` parameter, mapping it onto the
1555
+ backend's reasoning switch. Common cases:
1515
1556
 
1516
- * ``{'enable_thinking': False}`` to run a reasoning ("thinking")
1517
- model in non-thinking mode;
1557
+ * ``{'enable_thinking': bool(generation_params.get('use_reasoning'))}``
1558
+ to bind ``useReasoning`` to a reasoning ("thinking") model's
1559
+ template switch;
1518
1560
  * ``{'tools': [...]}`` or ``{'documents': [...]}`` for tool-use /
1519
1561
  RAG chat templates.
1520
1562
 
@@ -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.3
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
@@ -0,0 +1,8 @@
1
+ {
2
+ "tag": "1.7.3",
3
+ "distance": 0,
4
+ "node": "gea1bca511e70720b1f46476fbb5f41ff2d9329cd",
5
+ "dirty": false,
6
+ "branch": "HEAD",
7
+ "node_date": "2026-07-09"
8
+ }
@@ -174,6 +174,17 @@ from :class:`~clams.app.ClamsApp`. These names are reserved; see
174
174
  - Maximum number of new tokens generated per inference call. Larger values
175
175
  grow the KV cache linearly and add to GPU memory usage; reduce if VRAM
176
176
  is constrained.
177
+ * - ``useReasoning``
178
+ - boolean
179
+ - ``false``
180
+ - no
181
+ - Request the model's reasoning ("thinking") mode. Off by default;
182
+ honored only by apps whose model has a distinct reasoning mode
183
+ (others ignore it). Much slower and more token-hungry -- the trace is
184
+ generated before the answer and drawn from the ``maxNewTokens`` budget,
185
+ and small models can loop without terminating. When honored, the trace
186
+ is stored in the ``modelReasoningTrace`` property of the output
187
+ ``TextDocument``. See :ref:`promptable-reasoning`.
177
188
  * - ``temperature``
178
189
  - number
179
190
  - ``0.0``
@@ -320,6 +331,52 @@ inferences, final reply returned.
320
331
  ``turn-taking`` is the default because it costs a single inference call
321
332
  and is the more common multi-element pattern.
322
333
 
334
+ .. _promptable-reasoning:
335
+
336
+ Reasoning traces (``useReasoning``)
337
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
338
+
339
+ Some models expose a distinct reasoning ("thinking") mode that emits an
340
+ intermediate reasoning trace before the answer. ``useReasoning`` is the
341
+ standard toggle for that mode. It is inert unless the app honors it, and
342
+ honoring is a per-app choice with three wiring points:
343
+
344
+ - map ``useReasoning`` onto the backend's reasoning switch (for HF chat
345
+ templates, typically ``enable_thinking``) by overriding
346
+ :meth:`~clams.app.ClamsHFPromptableApp.build_template_kwargs`;
347
+ - split the trace from the answer with
348
+ :meth:`~clams.app.ClamsPromptableApp.split_tagged_reasoning_trace`
349
+ (inline ``<think>...</think>``-style traces only; channel-delimited
350
+ formats need app-specific parsing). Many chat templates prefill the
351
+ opening ``<think>`` into the prompt, so only the closing tag appears in
352
+ the output; pass ``assume_open=True`` (wired to the reasoning toggle) so
353
+ the trace is still recovered and a missing close tag is read as
354
+ unterminated reasoning (empty answer) rather than a plain answer;
355
+ - pass the trace to
356
+ :meth:`~clams.app.ClamsPromptableApp.response_to_grounded_textdocument`
357
+ through its ``reasoning_trace`` argument, which stores it in the
358
+ ``modelReasoningTrace`` property of the produced ``TextDocument``,
359
+ separate from the document text.
360
+
361
+ An app whose model has no reasoning mode leaves ``useReasoning`` unwired;
362
+ callers may still set it and it has no effect, like ``topK`` under greedy
363
+ decoding.
364
+
365
+ Cost and failure modes
366
+ """"""""""""""""""""""
367
+
368
+ Reasoning is much slower and far more token-hungry than a direct answer:
369
+ the entire trace is generated first, from the same budget capped by
370
+ ``maxNewTokens``. Enabling ``useReasoning`` without raising ``maxNewTokens``
371
+ substantially (thousands of tokens, not hundreds) risks the trace consuming
372
+ the whole budget, leaving the answer truncated or empty. Small reasoning
373
+ models (as a rule of thumb, roughly 4B parameters and under) are especially
374
+ prone to non-terminating "thinking loops" that never reach an answer; budget
375
+ generously and validate termination per model. When the trace overruns the
376
+ budget before closing, ``assume_open=True`` yields an empty answer plus the
377
+ unterminated trace -- an app should surface that (e.g. a warning and an empty
378
+ ``TextDocument``) rather than emitting the raw reasoning as the answer.
379
+
323
380
  Helpers
324
381
  ^^^^^^^
325
382
 
@@ -512,7 +569,10 @@ supplies:
512
569
  * a default
513
570
  :py:meth:`~clams.app.ClamsHFPromptableApp.build_gen_kwargs` that
514
571
  maps the SDK promptable parameters to HF ``model.generate()``
515
- kwargs.
572
+ kwargs;
573
+ * a :py:meth:`~clams.app.ClamsHFPromptableApp.build_template_kwargs`
574
+ hook for chat-template controls, the override point for honoring
575
+ ``useReasoning`` (see :ref:`promptable-reasoning`).
516
576
 
517
577
  See each method's docstring for full details.
518
578
 
@@ -26,7 +26,9 @@ sys.path.insert(0, str(proj_root_dir))
26
26
 
27
27
  # -- Project information -----------------------------------------------------
28
28
 
29
- project = proj_root_dir.name
29
+ # The canonical package name — NOT derived from the checkout directory,
30
+ # which is `clone-repo` when the shared docs-publish workflow builds here.
31
+ project = 'clams-python'
30
32
  blob_base_url = f'https://github.com/clamsproject/{project}/blob'
31
33
  copyright = f'{datetime.date.today().year}, Brandeis LLC'
32
34
  author = 'Brandeis LLC'
@@ -1,4 +1,5 @@
1
1
  "``clams-python`` version","``mmif-python`` version","Target MMIF Specification"
2
+ `1.7.3 <https://pypi.org/project/clams-python/1.7.3/>`__,`1.5.1 <https://pypi.org/project/mmif-python/1.5.1/>`__,`1.2.0 <https://mmif.clams.ai/1.2.0/>`__
2
3
  `1.7.2 <https://pypi.org/project/clams-python/1.7.2/>`__,`1.5.1 <https://pypi.org/project/mmif-python/1.5.1/>`__,`1.2.0 <https://mmif.clams.ai/1.2.0/>`__
3
4
  `1.7.1 <https://pypi.org/project/clams-python/1.7.1/>`__,`1.5.1 <https://pypi.org/project/mmif-python/1.5.1/>`__,`1.2.0 <https://mmif.clams.ai/1.2.0/>`__
4
5
  `1.7.0 <https://pypi.org/project/clams-python/1.7.0/>`__,`1.5.0 <https://pypi.org/project/mmif-python/1.5.0/>`__,`1.2.0 <https://mmif.clams.ai/1.2.0/>`__
@@ -19,7 +19,7 @@ classifiers = [
19
19
  "Programming Language :: Python :: 3 :: Only",
20
20
  ]
21
21
  dependencies = [
22
- "mmif-python==1.5.1",
22
+ "mmif-python==1.5.3",
23
23
  "Flask>=2",
24
24
  "Flask-RESTful>=0.3.9",
25
25
  "gunicorn>=20",
@@ -446,6 +446,28 @@ class TestSplitReasoningTrace(unittest.TestCase):
446
446
  self.assertEqual(answer, 'plain caption')
447
447
  self.assertIsNone(trace)
448
448
 
449
+ def test_assume_open_close_present_open_absent(self):
450
+ # Prefilled opening tag (e.g. Qwen3.5): only the close tag is emitted.
451
+ answer, trace = self.split(
452
+ 'reasoning body</think>The answer.', assume_open=True)
453
+ self.assertEqual(answer, 'The answer.')
454
+ self.assertEqual(trace, 'reasoning body')
455
+
456
+ def test_assume_open_no_close_is_unterminated_reasoning(self):
457
+ # Trace overran the budget before closing: empty answer, whole text is
458
+ # the unterminated trace.
459
+ raw = 'still thinking, never closed'
460
+ answer, trace = self.split(raw, assume_open=True)
461
+ self.assertEqual(answer, '')
462
+ self.assertEqual(trace, raw)
463
+
464
+ def test_open_absent_default_keeps_backward_compatible(self):
465
+ # Without assume_open, a lone close tag is not treated as a prefilled
466
+ # block: answer after the close, no trace.
467
+ answer, trace = self.split('reasoning body</think>The answer.')
468
+ self.assertEqual(answer, 'The answer.')
469
+ self.assertIsNone(trace)
470
+
449
471
 
450
472
  # ---------------------------------------------------------------------------
451
473
  # Transport-neutral parameter casting
@@ -1,8 +0,0 @@
1
- {
2
- "tag": "1.7.2",
3
- "distance": 0,
4
- "node": "g874f55164c482ad4c7896c6bfd8d6a69649eb66b",
5
- "dirty": false,
6
- "branch": "HEAD",
7
- "node_date": "2026-07-07"
8
- }
File without changes
File without changes
File without changes
File without changes
File without changes