coala-cli 0.2.4__tar.gz → 0.2.5__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.
@@ -0,0 +1,6 @@
1
+ __pycache__/
2
+ dist/
3
+ docs
4
+ Pipfile.lock
5
+ *archieve*
6
+ .pypirc
@@ -1,21 +1,21 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: coala-cli
3
- Version: 0.2.4
3
+ Version: 0.2.5
4
4
  Summary: Command-line LLM-agent Adapter
5
- License: MIT
6
5
  Author: Qiang
7
- Requires-Python: >=3.12,<3.15
6
+ License-Expression: MIT
8
7
  Classifier: License :: OSI Approved :: MIT License
9
8
  Classifier: Programming Language :: Python :: 3
10
9
  Classifier: Programming Language :: Python :: 3.12
11
10
  Classifier: Programming Language :: Python :: 3.13
12
11
  Classifier: Programming Language :: Python :: 3.14
13
- Requires-Dist: cwltool (>=3.2.20260413085819,<4.0.0)
14
- Requires-Dist: fastapi (>=0.115.0)
15
- Requires-Dist: mcp (>=1.12.0,<2.0.0)
16
- Requires-Dist: pydantic (>=2.10.0,<3.0.0)
17
- Requires-Dist: requests (>=2.33.0,<3.0.0)
18
- Requires-Dist: uvicorn (>=0.32.0,<0.33.0)
12
+ Requires-Python: <3.15,>=3.12
13
+ Requires-Dist: cwltool<4.0.0,>=3.2.20260413085819
14
+ Requires-Dist: fastapi>=0.115.0
15
+ Requires-Dist: mcp<2.0.0,>=1.12.0
16
+ Requires-Dist: pydantic<3.0.0,>=2.10.0
17
+ Requires-Dist: requests<3.0.0,>=2.33.0
18
+ Requires-Dist: uvicorn<0.33.0,>=0.32.0
19
19
  Description-Content-Type: text/markdown
20
20
 
21
21
  # Coala: Command-line LLM-agent Adapter
@@ -29,4 +29,3 @@ Coala integrates the [Common Workflow Language (CWL)](https://www.commonwl.org/s
29
29
 
30
30
  Please find Coala documuentations through [Coala website](https://coala.info/), including [overview](https://coala.info/guide/), [installation](https://coala.info/guide/installation.html), [quick start](https://coala.info/guide/quick-start.html), and [use cases](https://coala.info/use-cases/).
31
31
 
32
-
@@ -6,6 +6,7 @@ from pathlib import Path
6
6
  from urllib.parse import urlparse, unquote
7
7
  from urllib.request import url2pathname
8
8
  from cwltool.context import RuntimeContext
9
+ from cwltool.factory import WorkflowStatus
9
10
 
10
11
 
11
12
  def _canonical_file_uri(uri: str) -> str:
@@ -57,6 +58,66 @@ def configure_container_runner(runtime_context: RuntimeContext, container_runner
57
58
  or shutil.which('xcrunner') or 'xcrunner'
58
59
  )
59
60
 
61
+ class ToolRunFailed(RuntimeError):
62
+ """A CWL run that exited non-zero, carrying what the tool itself printed."""
63
+
64
+
65
+ # Enough to hold a tool's closing error and the lines that lead to it, without flooding the
66
+ # caller with a long progress log.
67
+ _FAILED_OUTPUT_LINES = 40
68
+ _FAILED_OUTPUT_CHARS = 6000
69
+
70
+
71
+ def _captured_stream_outputs(tool) -> dict:
72
+ """``{output id: "stdout" | "stderr"}`` for outputs that capture the tool's own streams.
73
+
74
+ cwltool rewrites ``type: stdout`` into a ``File`` whose glob is the tool's ``stdout`` value,
75
+ so the glob, not the type, identifies it — and still does when that value is an expression.
76
+ """
77
+ spec = getattr(getattr(tool, "t", None), "tool", None) or {}
78
+ streams = {spec.get(s): s for s in ("stdout", "stderr") if spec.get(s)}
79
+ found = {}
80
+ for out in spec.get("outputs") or []:
81
+ glob = (out.get("outputBinding") or {}).get("glob")
82
+ if isinstance(glob, str) and glob in streams:
83
+ found[str(out.get("id", "")).rsplit("#", 1)[-1]] = streams[glob]
84
+ return found
85
+
86
+
87
+ def _tail(path: str) -> str:
88
+ try:
89
+ with open(path, "r", encoding="utf-8", errors="replace") as fh:
90
+ lines = fh.read().splitlines()
91
+ except OSError:
92
+ return ""
93
+ text = "\n".join(lines[-_FAILED_OUTPUT_LINES:]).strip()
94
+ return text[-_FAILED_OUTPUT_CHARS:]
95
+
96
+
97
+ def _failed_run_output(tool, partial) -> str:
98
+ """The tail of the tool's own stdout/stderr capture files from a failed run, or ``""``.
99
+
100
+ A tool that prints its error to standard output, into a file the CWL declares with
101
+ ``stdout:``, leaves cwltool's log with nothing but "exited with status: 1": cellranger-arc
102
+ ``mkref`` reported an unknown GTF contig that way, and the caller retried blind for three
103
+ hours. cwltool still collects that file when the run fails and passes it in the exception,
104
+ so read it back.
105
+ """
106
+ if not isinstance(partial, dict):
107
+ return ""
108
+ parts = []
109
+ for out_id, stream in _captured_stream_outputs(tool).items():
110
+ entry = partial.get(out_id)
111
+ location = entry.get("location") if isinstance(entry, dict) else None
112
+ if not isinstance(location, str) or not location.startswith("file://"):
113
+ continue
114
+ text = _tail(url2pathname(urlparse(location).path))
115
+ if text:
116
+ name = entry.get("basename") or out_id
117
+ parts.append(f"The tool's {stream} ({name}), last lines:\n{text}")
118
+ return "\n\n".join(parts)
119
+
120
+
60
121
  def _read_file_content(filepath):
61
122
  """Read file content, handling gzipped files."""
62
123
  try:
@@ -198,7 +259,13 @@ def run_tool(tool, params, outputs, read_outs=False, container_runner=None):
198
259
  configure_container_runner(original_runtime_context, container_runner)
199
260
 
200
261
  # Execute tool (no need to pass runtime_context if we modified it in place)
201
- res = tool(**params)
262
+ try:
263
+ res = tool(**params)
264
+ except WorkflowStatus as exc:
265
+ detail = _failed_run_output(tool, exc.out)
266
+ if not detail:
267
+ raise
268
+ raise ToolRunFailed(f"Completed {exc.status}.\n\n{detail}") from exc
202
269
  outs = {}
203
270
  for ot in outputs:
204
271
  out_content = res[ot['name']]
@@ -0,0 +1,42 @@
1
+ [project]
2
+ name = "coala-cli"
3
+ version = "0.2.5"
4
+ description = "Command-line LLM-agent Adapter"
5
+ authors = [{ name = "Qiang" }]
6
+ license = "MIT"
7
+ readme = "README.md"
8
+ requires-python = ">=3.12,<3.15"
9
+ classifiers = [
10
+ "License :: OSI Approved :: MIT License",
11
+ "Programming Language :: Python :: 3",
12
+ "Programming Language :: Python :: 3.12",
13
+ "Programming Language :: Python :: 3.13",
14
+ "Programming Language :: Python :: 3.14",
15
+ ]
16
+ dependencies = [
17
+ "fastapi>=0.115.0",
18
+ "requests>=2.33.0,<3.0.0",
19
+ "pydantic>=2.10.0,<3.0.0",
20
+ "uvicorn>=0.32.0,<0.33.0",
21
+ "cwltool>=3.2.20260413085819,<4.0.0",
22
+ "mcp>=1.12.0,<2.0.0",
23
+ ]
24
+
25
+ [dependency-groups]
26
+ dev = ["pytest>=8.0.0", "pytest-asyncio>=0.24.0"]
27
+
28
+ [build-system]
29
+ requires = ["hatchling"]
30
+ build-backend = "hatchling.build"
31
+
32
+ # The sdist carries what the Poetry build did: the package and the README.
33
+ [tool.hatch.build.targets.sdist]
34
+ include = ["coala", "README.md"]
35
+
36
+ [tool.hatch.build.targets.wheel]
37
+ packages = ["coala"]
38
+
39
+ [tool.pytest.ini_options]
40
+ filterwarnings = [
41
+ "ignore::pydantic.warnings.UnsupportedFieldAttributeWarning",
42
+ ]
@@ -1,27 +0,0 @@
1
- [tool.poetry]
2
- name = "coala-cli"
3
- version = "0.2.4"
4
- description = "Command-line LLM-agent Adapter"
5
- authors = ["Qiang"]
6
- license = "MIT"
7
- readme = "README.md"
8
- packages = [{ include = "coala" }]
9
-
10
- [tool.poetry.dependencies]
11
- python = ">=3.12,<3.15"
12
- fastapi = ">=0.115.0"
13
- requests = "^2.33.0"
14
- pydantic = "^2.10.0"
15
- uvicorn = "^0.32.0"
16
- cwltool = "^3.2.20260413085819"
17
- mcp = "^1.12.0"
18
-
19
-
20
- [build-system]
21
- requires = ["poetry-core"]
22
- build-backend = "poetry.core.masonry.api"
23
-
24
- [tool.pytest.ini_options]
25
- filterwarnings = [
26
- "ignore::pydantic.warnings.UnsupportedFieldAttributeWarning",
27
- ]
File without changes
File without changes
File without changes
File without changes
File without changes