From ac5204e93a1d3a02cd04521113e6dd2b34c949f2 Mon Sep 17 00:00:00 2001 From: Christopher Clendening Date: Fri, 3 Oct 2025 01:11:39 -0400 Subject: [PATCH] Initial commit: Original Python LLMTester project --- .DS_Store | Bin 0 -> 10244 bytes .../__pycache__/v1.cpython-313.pyc | Bin 0 -> 7338 bytes .core/.engine/.apple_silicon/v1.py | 170 ++ .core/.engine/.cpu/v1.py | 72 + .core/.engine/.cuda/v1.py | 74 + .core/.engine/.rocm/v1.py | 74 + .core/__pycache__/config.cpython-313.pyc | Bin 0 -> 2067 bytes .../__pycache__/engine_loader.cpython-313.pyc | Bin 0 -> 6373 bytes .../markdown_linter.cpython-313.pyc | Bin 0 -> 6848 bytes .core/__pycache__/prompts.cpython-313.pyc | Bin 0 -> 1996 bytes .core/__pycache__/reporting.cpython-313.pyc | Bin 0 -> 10150 bytes .core/__pycache__/runner.cpython-313.pyc | Bin 0 -> 5666 bytes .core/__pycache__/settings.cpython-313.pyc | Bin 0 -> 3399 bytes .core/config.py | 36 + .core/engine_loader.py | 108 ++ .core/markdown_linter.py | 203 +++ .core/prompts.py | 46 + .core/providers/__init__.py | 34 + .../__pycache__/__init__.cpython-313.pyc | Bin 0 -> 1359 bytes .../__pycache__/base.cpython-313.pyc | Bin 0 -> 1785 bytes .../__pycache__/lmstudio.cpython-313.pyc | Bin 0 -> 5696 bytes .../__pycache__/local_engine.cpython-313.pyc | Bin 0 -> 4595 bytes .core/providers/base.py | 29 + .core/providers/lmstudio.py | 100 ++ .core/providers/local_engine.py | 80 + .core/reporting.py | 206 +++ .core/runner.py | 121 ++ .core/settings.py | 67 + .core/templates/test-block.md | 18 + README.md | 77 + auto-test.py | 13 + index.py | 339 ++++ requirements.txt | 3 + results/.DS_Store | Bin 0 -> 6148 bytes ..._DeepSeek-Coder-V2-Lite-Instruct-IQ2_XS.md | 304 ++++ ...ort_Qwen3-Coder-30B-A3B-Instruct-Q3_K_L.md | 1382 ++++++++++++++++ ...Qwen3-Coder-30B-A3B-Instruct-UD-IQ2_XXS.md | 1468 +++++++++++++++++ ...Qwen3-Coder-30B-A3B-Instruct-UD-IQ3_XXS.md | 1468 +++++++++++++++++ ...automated_report_codellama-13b-instruct.md | 648 ++++++++ .../automated_report_google_gemma-3-12b.md | 1141 +++++++++++++ .../automated_report_ibm_granite-4-h-tiny.md | 1148 +++++++++++++ ...ted_report_mistralai_codestral-22b-v0.1.md | 775 +++++++++ ...mated_report_phi-3-medium-128k-instruct.md | 988 +++++++++++ ...ted_report_starcoder2-15b-instruct-v0.1.md | 621 +++++++ tests/test1.txt | 14 + tests/test10.txt | 5 + tests/test2.txt | 10 + tests/test3.txt | 23 + tests/test4.txt | 5 + tests/test5.txt | 7 + tests/test6.txt | 9 + tests/test7.txt | 17 + tests/test8.txt | 1 + tests/test9.txt | 7 + 54 files changed, 11911 insertions(+) create mode 100644 .DS_Store create mode 100644 .core/.engine/.apple_silicon/__pycache__/v1.cpython-313.pyc create mode 100644 .core/.engine/.apple_silicon/v1.py create mode 100644 .core/.engine/.cpu/v1.py create mode 100644 .core/.engine/.cuda/v1.py create mode 100644 .core/.engine/.rocm/v1.py create mode 100644 .core/__pycache__/config.cpython-313.pyc create mode 100644 .core/__pycache__/engine_loader.cpython-313.pyc create mode 100644 .core/__pycache__/markdown_linter.cpython-313.pyc create mode 100644 .core/__pycache__/prompts.cpython-313.pyc create mode 100644 .core/__pycache__/reporting.cpython-313.pyc create mode 100644 .core/__pycache__/runner.cpython-313.pyc create mode 100644 .core/__pycache__/settings.cpython-313.pyc create mode 100644 .core/config.py create mode 100644 .core/engine_loader.py create mode 100644 .core/markdown_linter.py create mode 100644 .core/prompts.py create mode 100644 .core/providers/__init__.py create mode 100644 .core/providers/__pycache__/__init__.cpython-313.pyc create mode 100644 .core/providers/__pycache__/base.cpython-313.pyc create mode 100644 .core/providers/__pycache__/lmstudio.cpython-313.pyc create mode 100644 .core/providers/__pycache__/local_engine.cpython-313.pyc create mode 100644 .core/providers/base.py create mode 100644 .core/providers/lmstudio.py create mode 100644 .core/providers/local_engine.py create mode 100644 .core/reporting.py create mode 100644 .core/runner.py create mode 100644 .core/settings.py create mode 100644 .core/templates/test-block.md create mode 100644 README.md create mode 100644 auto-test.py create mode 100644 index.py create mode 100644 requirements.txt create mode 100644 results/.DS_Store create mode 100644 results/Modern-Apple-Dev/automated_report_DeepSeek-Coder-V2-Lite-Instruct-IQ2_XS.md create mode 100644 results/Modern-Apple-Dev/automated_report_Qwen3-Coder-30B-A3B-Instruct-Q3_K_L.md create mode 100644 results/Modern-Apple-Dev/automated_report_Qwen3-Coder-30B-A3B-Instruct-UD-IQ2_XXS.md create mode 100644 results/Modern-Apple-Dev/automated_report_Qwen3-Coder-30B-A3B-Instruct-UD-IQ3_XXS.md create mode 100644 results/Modern-Apple-Dev/automated_report_codellama-13b-instruct.md create mode 100644 results/Modern-Apple-Dev/automated_report_google_gemma-3-12b.md create mode 100644 results/Modern-Apple-Dev/automated_report_ibm_granite-4-h-tiny.md create mode 100644 results/Modern-Apple-Dev/automated_report_mistralai_codestral-22b-v0.1.md create mode 100644 results/Modern-Apple-Dev/automated_report_phi-3-medium-128k-instruct.md create mode 100644 results/Modern-Apple-Dev/automated_report_starcoder2-15b-instruct-v0.1.md create mode 100644 tests/test1.txt create mode 100644 tests/test10.txt create mode 100644 tests/test2.txt create mode 100644 tests/test3.txt create mode 100644 tests/test4.txt create mode 100644 tests/test5.txt create mode 100644 tests/test6.txt create mode 100644 tests/test7.txt create mode 100644 tests/test8.txt create mode 100644 tests/test9.txt diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..65e19399fae970e841fc092c5db8f4ad56484660 GIT binary patch literal 10244 zcmeHMYit}>6+UO|#537VGIs37*=D^PZ}VvEq|UQ>H1T?ECvjrONo>cjB%9rxi8IRV zjI%Rq#|;6u`~VtSXc6Vv@UOHK$}^=90pZaSphcoeBU&CUAVHBTkrpUIAj-LSW;Xk9 zejr*D(Y?~lz4zR6?#!IIkMBDd05FzS)&PV7K%|T1vJaqg4nRHS`H8i&t0YyB1nHVj z7nNlI3$mbt4VG?|XqN?L50pJ{BY8lemtpg_lCCPqfSNylC&rVynFJ6nB*%5lvRhhS zM4_T`*6b=#n&b1&4ejdMy~p1Zmun_8b+UKd)=a}XsAeq6t=Y!R!`Zit)yva#4JMSzm z%UMf3pi*DjgxWzpT0gbmeX9H*JdzrOb3%HEe4@ zPb5`+aKd@}QH8o{&!}`)`Yr105EJy6igrvR$qCI+`i(?dJ;KD@3Cr#sR}EFUT)!xA z^WvaCG(ZaKsewsNv5yZYtdwdfnlUywp;=l|SLLc|Y?ef>y`<3}l4r?^TV1xCsz$17RlbAvU(`e#J%%Fwu!gu2| z-i3GLS-clNgdfKH@ss#zdQy68;!}g3sWycm-d= zSMaa+hVzC38^kQ_bu#acZ#u*25Fd=Tn(i`=nb#e#1w(LXIFZRDj4?Gfb(jy1UL$7O zwwcb2u+lLeX}#(^ITGFD6;?O}8FGFXONM6TV(KDS>o-h8CCBe`j3n}W6SP4O9E1~a zC)^JY!J}{iF2S$hPw;oFLKz#e3D@H`Y{gyJg(KwSTOY!7u{`SL(@xHp4!SW2!P*&w;EBq7H=#Vt1e8bJeA>xLLJ1vH z${ka5DF!;`BoDiKQ8%ApEyKbiV*pNuX;LH=}-hq*dn)XB^DvIoi@DD}WB5*1

7z5R}8XIIbu%Zxqve04W@IQ|;4caZ*w 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 literal 0 HcmV?d00001 diff --git a/.core/.engine/.apple_silicon/v1.py b/.core/.engine/.apple_silicon/v1.py new file mode 100644 index 0000000..43e9640 --- /dev/null +++ b/.core/.engine/.apple_silicon/v1.py @@ -0,0 +1,170 @@ +from __future__ import annotations + +import os +import time +from pathlib import Path +from typing import TYPE_CHECKING, Optional + +try: # Optional dependency for GGUF execution + from llama_cpp import Llama +except ImportError: # pragma: no cover + Llama = None # type: ignore + +if TYPE_CHECKING: + from llama_cpp import Llama as LlamaType +else: # pragma: no cover + class LlamaType: # type: ignore + ... + +from engine_loader import BaseRuntime + + +class EngineRuntime(BaseRuntime): + name = "mlx_apple_silicon" + + def __init__(self, *, max_tokens: int = 1024, context_window: int = 4096) -> None: + super().__init__() + self.max_tokens = max_tokens + self.context_window = context_window + self.threads = max(os.cpu_count() or 1, 1) + + self._mode: Optional[str] = None # "mlx" or "llama_cpp" + self._model = None + self._tokenizer = None + self._llm: Optional[LlamaType] = None + self._model_path: Path | None = None + + def discover_gguf_models(self, search_paths: list[Path]) -> list[Path]: + candidates: list[Path] = [] + seen: set[Path] = set() + for root in search_paths: + if not root.exists(): + continue + for path in root.rglob("*.gguf"): + if path.is_file(): + resolved = path.resolve() + if resolved not in seen: + seen.add(resolved) + candidates.append(resolved) + for path in root.iterdir(): + if path.is_dir() and (path / "config.json").exists(): + resolved = path.resolve() + if resolved not in seen: + seen.add(resolved) + candidates.append(resolved) + return candidates + + def load_model(self, model_path: Path) -> None: + if self._model_path == model_path: + if self._mode == "mlx" and self._model is not None: + return + if self._mode == "llama_cpp" and self._llm is not None: + return + + self.unload() + resolved_path = model_path.resolve() + + if resolved_path.is_file() and resolved_path.suffix.lower() == ".gguf": + if Llama is None: + raise RuntimeError( + "llama-cpp-python is required to run GGUF models on Apple Silicon. Install it with 'pip install llama-cpp-python'." + ) + self._llm = Llama( + model_path=str(resolved_path), + n_ctx=self.context_window, + n_gpu_layers=-1, + n_threads=self.threads, + use_gpu=True, + verbose=False, + ) + self._mode = "llama_cpp" + else: + try: + from mlx_lm import load # type: ignore import-not-found + except ImportError as exc: # pragma: no cover - environment validation + raise RuntimeError( + "mlx-lm is required for MLX models. Install it with 'pip install mlx-lm'." + ) from exc + + self._model, self._tokenizer = load(str(resolved_path)) + self._mode = "mlx" + + self._model_path = resolved_path + + def generate(self, prompt: str, *, temperature: float) -> dict: + if self._mode == "llama_cpp": + if self._llm is None: + raise RuntimeError("Model must be loaded before calling generate().") + + start_time = time.time() + response = self._llm.create_chat_completion( + messages=[{"role": "user", "content": prompt}], + temperature=temperature, + ) + elapsed = max(time.time() - start_time, 1e-5) + + content = response["choices"][0]["message"]["content"] + usage = response.get("usage", {}) + completion_tokens = usage.get("completion_tokens", 0) + total_tokens = usage.get("total_tokens", completion_tokens) + + return { + "response": content, + "metrics": { + "tokens_per_second": round(completion_tokens / elapsed, 2) if completion_tokens else 0, + "total_tokens": total_tokens, + "time_to_first_token": round(usage.get("prompt_eval_duration", 0) / 1_000_000_000, 2) + if "prompt_eval_duration" in usage + else 0, + "stop_reason": response["choices"][0].get("finish_reason", "unknown"), + }, + } + + if self._mode == "mlx": + if self._model is None or self._tokenizer is None: + raise RuntimeError("Model must be loaded before calling generate().") + + start_time = time.time() + try: + from mlx_lm import generate # type: ignore import-not-found + except ImportError as exc: # pragma: no cover + raise RuntimeError( + "mlx-lm is required for MLX models. Install it with 'pip install mlx-lm'." + ) from exc + + completion = generate( + self._model, + self._tokenizer, + prompt, + max_tokens=self.max_tokens, + temperature=temperature, + ) + elapsed = max(time.time() - start_time, 1e-5) + + if isinstance(completion, str): + text = completion + else: + text = str(completion) + + prompt_tokens = len(self._tokenizer.encode(prompt)) + completion_tokens = max(len(self._tokenizer.encode(text)) - prompt_tokens, 0) + total_tokens = prompt_tokens + completion_tokens + + return { + "response": text, + "metrics": { + "tokens_per_second": round(completion_tokens / elapsed, 2) if completion_tokens else 0, + "total_tokens": total_tokens, + "time_to_first_token": 0, + "stop_reason": "stop", + }, + } + + raise RuntimeError("No model is currently loaded. Call load_model() first.") + + def unload(self) -> None: + self._model = None + self._tokenizer = None + self._llm = None + self._model_path = None + self._mode = None diff --git a/.core/.engine/.cpu/v1.py b/.core/.engine/.cpu/v1.py new file mode 100644 index 0000000..19cec20 --- /dev/null +++ b/.core/.engine/.cpu/v1.py @@ -0,0 +1,72 @@ +from __future__ import annotations + +import os +import time +from pathlib import Path + +try: + from llama_cpp import Llama +except ImportError as exc: # pragma: no cover - dependency validation + raise RuntimeError( + "llama-cpp-python is required for the CPU engine runtime. Install it with 'pip install llama-cpp-python'." + ) from exc + +from engine_loader import BaseRuntime + + +class EngineRuntime(BaseRuntime): + name = "llama_cpp_cpu" + + def __init__(self, *, context_window: int = 4096) -> None: + super().__init__() + self.context_window = context_window + self.threads = max(os.cpu_count() or 1, 1) + self._llm: Llama | None = None + self._model_path: Path | None = None + + def load_model(self, model_path: Path) -> None: + if self._model_path == model_path and self._llm is not None: + return + + self.unload() + self._llm = Llama( + model_path=str(model_path), + n_ctx=self.context_window, + n_threads=self.threads, + n_gpu_layers=0, + verbose=False, + ) + self._model_path = model_path + + def generate(self, prompt: str, *, temperature: float) -> dict: + if self._llm is None: + raise RuntimeError("Model must be loaded before calling generate().") + + start_time = time.time() + response = self._llm.create_chat_completion( + messages=[{"role": "user", "content": prompt}], + temperature=temperature, + ) + elapsed = max(time.time() - start_time, 1e-5) + + content = response["choices"][0]["message"]["content"] + usage = response.get("usage", {}) + completion_tokens = usage.get("completion_tokens", 0) + total_tokens = usage.get("total_tokens", completion_tokens) + + return { + "response": content, + "metrics": { + "tokens_per_second": round(completion_tokens / elapsed, 2) if completion_tokens else 0, + "total_tokens": total_tokens, + "time_to_first_token": round(usage.get("prompt_eval_duration", 0) / 1_000_000_000, 2) + if "prompt_eval_duration" in usage + else 0, + "stop_reason": response["choices"][0].get("finish_reason", "unknown"), + }, + } + + def unload(self) -> None: + if self._llm is not None: + self._llm = None + self._model_path = None diff --git a/.core/.engine/.cuda/v1.py b/.core/.engine/.cuda/v1.py new file mode 100644 index 0000000..4499763 --- /dev/null +++ b/.core/.engine/.cuda/v1.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +import os +import time +from pathlib import Path + +try: + from llama_cpp import Llama +except ImportError as exc: + raise RuntimeError( + "llama-cpp-python with CUDA support is required for the CUDA engine runtime." + ) from exc + +from engine_loader import BaseRuntime + + +class EngineRuntime(BaseRuntime): + name = "llama_cpp_cuda" + + def __init__(self, *, context_window: int = 4096, gpu_layers: int = -1) -> None: + super().__init__() + self.context_window = context_window + self.gpu_layers = gpu_layers + self.threads = max(os.cpu_count() or 1, 1) + self._llm: Llama | None = None + self._model_path: Path | None = None + + def load_model(self, model_path: Path) -> None: + if self._model_path == model_path and self._llm is not None: + return + + self.unload() + self._llm = Llama( + model_path=str(model_path), + n_ctx=self.context_window, + n_threads=self.threads, + n_gpu_layers=self.gpu_layers, + use_gpu=True, + verbose=False, + ) + self._model_path = model_path + + def generate(self, prompt: str, *, temperature: float) -> dict: + if self._llm is None: + raise RuntimeError("Model must be loaded before calling generate().") + + start_time = time.time() + response = self._llm.create_chat_completion( + messages=[{"role": "user", "content": prompt}], + temperature=temperature, + ) + elapsed = max(time.time() - start_time, 1e-5) + + content = response["choices"][0]["message"]["content"] + usage = response.get("usage", {}) + completion_tokens = usage.get("completion_tokens", 0) + total_tokens = usage.get("total_tokens", completion_tokens) + + return { + "response": content, + "metrics": { + "tokens_per_second": round(completion_tokens / elapsed, 2) if completion_tokens else 0, + "total_tokens": total_tokens, + "time_to_first_token": round(usage.get("prompt_eval_duration", 0) / 1_000_000_000, 2) + if "prompt_eval_duration" in usage + else 0, + "stop_reason": response["choices"][0].get("finish_reason", "unknown"), + }, + } + + def unload(self) -> None: + if self._llm is not None: + self._llm = None + self._model_path = None diff --git a/.core/.engine/.rocm/v1.py b/.core/.engine/.rocm/v1.py new file mode 100644 index 0000000..2cfa216 --- /dev/null +++ b/.core/.engine/.rocm/v1.py @@ -0,0 +1,74 @@ +from __future__ import annotations + +import os +import time +from pathlib import Path + +try: + from llama_cpp import Llama +except ImportError as exc: + raise RuntimeError( + "llama-cpp-python built with ROCm support is required for the ROCm engine runtime." + ) from exc + +from engine_loader import BaseRuntime + + +class EngineRuntime(BaseRuntime): + name = "llama_cpp_rocm" + + def __init__(self, *, context_window: int = 4096, gpu_layers: int = -1) -> None: + super().__init__() + self.context_window = context_window + self.gpu_layers = gpu_layers + self.threads = max(os.cpu_count() or 1, 1) + self._llm: Llama | None = None + self._model_path: Path | None = None + + def load_model(self, model_path: Path) -> None: + if self._model_path == model_path and self._llm is not None: + return + + self.unload() + self._llm = Llama( + model_path=str(model_path), + n_ctx=self.context_window, + n_threads=self.threads, + n_gpu_layers=self.gpu_layers, + use_gpu=True, + verbose=False, + ) + self._model_path = model_path + + def generate(self, prompt: str, *, temperature: float) -> dict: + if self._llm is None: + raise RuntimeError("Model must be loaded before calling generate().") + + start_time = time.time() + response = self._llm.create_chat_completion( + messages=[{"role": "user", "content": prompt}], + temperature=temperature, + ) + elapsed = max(time.time() - start_time, 1e-5) + + content = response["choices"][0]["message"]["content"] + usage = response.get("usage", {}) + completion_tokens = usage.get("completion_tokens", 0) + total_tokens = usage.get("total_tokens", completion_tokens) + + return { + "response": content, + "metrics": { + "tokens_per_second": round(completion_tokens / elapsed, 2) if completion_tokens else 0, + "total_tokens": total_tokens, + "time_to_first_token": round(usage.get("prompt_eval_duration", 0) / 1_000_000_000, 2) + if "prompt_eval_duration" in usage + else 0, + "stop_reason": response["choices"][0].get("finish_reason", "unknown"), + }, + } + + def unload(self) -> None: + if self._llm is not None: + self._llm = None + self._model_path = None diff --git a/.core/__pycache__/config.cpython-313.pyc b/.core/__pycache__/config.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd438c5f84988baf73ee4129c1a3d65da6c0b7e5 GIT binary patch literal 2067 zcma)7&2Jh<6rY6!7B6eC0h@fa8$bZXm52jICWU*42dOC4KNe}oxqR;enE!D zOJO(}QsjT`nndcDD$aWPmciM{#D98+RB7N%Ce@f4K8n8NNmPxLV(J8Z;$pd&Q;Q%LmU7BmaaqZ2de5h4+{r`RlCt>ud^V?S2J;KD zYPYJo>G}z_TclYTjfW2gUikLE2k`*i7}^x7eXXe+{5+RDGP(hT>9;rd4Tyx^;3xdQ z^=jS}zxhtCX|)KJ?Yd^mR$U{wDpz%aE4E2=Y{~d5-LligCmuJj4#p;gS75rbxmHN| zTv5rX%lV>O&dw{YudxPmU5N%WKL>GTT7eE38e3S*=JHJY1ntvPx*uegEljLTrA}ZY zbG?p9CTmt&4Z2n46Wz|_^9x0IM9{O>&Q#3is$NU4Z@80~oxMDAUNQ}fM&YxrgJ`4Q z`EZYqJAAxT-7a=1y0FJj^!RCqpMK15+g*w-?(w0!g*%1L#qHDWg2QL_`0*YebNE=N zxSj3tv1j}YiPO`1*YJiLsNz)(h*mkEJQxt7Z^+(04d9ixAN8W1(30p2Zjb_}QHtA~ zRj^i-wWf@lH+5n*>Fwp48qu{C1IxE`yDn?;!M5_MW*93P5IW^?J*MUQYuJW)DGy1& z+T;ibi*72*WC}Vr4E8cOlr3!Adb37Ofc6;mng9VY5~cf>?p@kacf@3uPqLd+Fxettn53=1P8rc|fdP8nmK=DjS?}31L2f}x6-?`lj zB%DBEPZ+;1-IKnn|0KNq3Jss}8MZJyEB$LJq^1ddGa`eaxoFo7eTC2maD{StRX1?C z%u1kX+{CWGpRBH+EG`!NS$K6($uSh91&<{m3DXrR3l4L(yfjz*l--=rJaT=jhN;=) zIK|Oy?%Et=`)IXv;{)ZOOqL6C3ptjEuGg{&qZ^CC>(LS}Lmh4z_zKCu>hw>~`T@iX zFUN7uQSdpEenyEu{U{XK627_86Hhwg$sO@jPdw|0XM5s|BhIviT`{^w#D5@qVu5>In$PQBPSk*ok#}I;S4F>5gbWwkNrAztn=}s`G@n} zGao%|?HteTOkL}u=x*ZZqu|3}H~IckaVL@OqWDX{kGt?9;^9tpqAw71k1f`1TQBM8 LuQ8rG&))5C9ih)? literal 0 HcmV?d00001 diff --git a/.core/__pycache__/engine_loader.cpython-313.pyc b/.core/__pycache__/engine_loader.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a47124cf4cc71a8441f0251019b523065450507 GIT binary patch literal 6373 zcma(#TWlLgl0D>*9C1WaZ_$cPjbz6%ZAXeFJ1^PJI%~zYB+FTj87xlna!13FG!8jr zdWN>e7zgcQv2pGv3Jyjb?BQY@7C7f?{ki*f0S*E3IXvc;+Kz)Yu)dG{c_9N??EYL; z4@uLsjHCfJtGlafs;jH2t7t*w;#|jUn1(qVn3HEaY3FQ&M)){57oCmKm_n9f zYUl--5Za|mv^!2liP|wl)bLWzF~7$N?d7vF%yu60)#v(_B*2WQ(N_h&8iUoY#_BN- ziO_zvSM44mmqj|D_No1955kuPI=Jdf4t$GPNrB0lWfdIFF$WG+;&g@rBe(=JdH#IW%rqtEOcz-<2bJ{nPwU@CL$m9Dti- ziBLf$)Tas{Iv*8PKMkyk$pDMZ@cr`zEjvSLfqvT!_~m0M&9sfIa&^tH6sw@vCDYNC zbB5x5O`#>rG4qC^YnHNXC^^_|WXC@v3&|jpG8s$D8<`9XXEOOhwv zu}o&gq_&d-)~y08hccOLK?k5eld(}CdPZ{`YA%-?!_H)A1i0G9Be7ExY1^RoguX^i z+bI;+3_5YTpqKK7<=7KvOlM+#{`^J5c3^&7FHmE`<2l2bq~pbP3Rg~ehiA1>>3&V_ ziLcYX#{3hKtgC{s{ZFv`q$HmQrSxQ}ic3K?Fa{W)7(ssRAvLOoI3%etRpL;G+J!0x zN)d+DFo$GSrk$&u$!;dUq1i^t6YaPCK&$*b&L~_Vl$8PnLF-zs?Go&9CN2XS^V<$( zB1%}Vt16Hn1kVR&5VprbCvK7nV)+*9+CfM|T`hlF=p|==Nr)w;#Z>*we1E-bU>>NC zv+#}cLxcc!-E3R2RpD6u8$eYBs)2MM6>7!s;Ac_|q&l9BZ3Ta-PXm31Hp_xqv1nLX*d*FUZiRK)hDP{)hhg2Y zm`Do+hl#k%q&lUnjq*~wM*9I~eOc4i3s(%9;S|8QjGWDs7PT4Q2?K74*jJ(3AX_7Q zZ-nm+?fK2~H^i^|lpCkFdIvwA{%HE+6Ca)UQ&)T|zWdYgC*j+#{4subQ^d97A07Yr zk)pdFQ|%<5Sx*+4aI- zL!^J?VGrpVa;06|u=J+R0V4==ofHAMNmhlVul(v;1_d3@E1I?5bTFo6I;NI0%iKqT zuK^6t-*LC~d@*OB@9~_tlGoP3E9z^8;=s>yjNZOFn@JyMlZ83+o)+NO zl{(L1+=G78$gzP|#vjig0(1&$-^M%g-Q*pfRuJqW^jC!WccI`k#b9{PNYd|} zGFYUAe9>XDW8{kl)o{0s-UZa!yCZ4UuyDa(eXXZ$%#H)DEkU%|V8q4(aQW1)kM z4oCJu=-wxP5-09=4Q!mgv9~G?JQ6ztLyvX~fwRJ+pb$tw?+c86CkcT`j|@_{2+9y# zp@lMN7Yv&X?;D!1{WkPZzo1JHjo{0<6o4?!2P2V>LTZN^z!&luZiYssrH~r-Uf1Sa zhZ>^cRVgX6E-#WfZP+?Biw=Y`FX1K>D(gh=YdQwkUKRomYC}ZzgiAsu;U{b_0MKeV zs*onBR{sF&*rH_0htVUfq8DpxQ3wsZb$CYn3rrX<`yuv7`k6elaOT{?OeS^V!bN%x zw$WMa+SO177l5G?e-n1MpKZKlbsDzYc->$kv7uY<-tMc7OjbrFU1iGMbF>mW`ulzV zb@&g5f1mi=c3+;W#O7RS?rAH+Gw}1HrarO%e`EV!|0SDN;e5w&}vZg||* z8ZatDQr^*&PQwx#I6d>`sr3BCO#P1Do=K_aE-dgHViNc=@L|q6MHQhC)$D9cXK(>K z)IS@=`98Vd(_a<)w|bKsXKtufF?l}_+4c#6d12d6g3*T@d>8}}XOHtq4teK6Vmkbq zt*NY^gX3yd)}0h}v>D~?6sa{V$!d8lQo-hzn!pdF0&1fQulx0hpj7S*3@3G^ClDZQdTQV zw4mqtm_zWQ7chj>^USXoOGyb-HK#ckOtGN74yjO{1#*R}24$f<#3q<8h9S$Mj(yd1 z*0`<$;#$cub1ZOm&D0_7q(28?(`D%F*6^e^YoHs=v^rF}0$6B2_P;~7LGDHRKg|3~ zrW#4qBKs++-F?6$;rQTSBM5 z!;@eMpz%9oLk$~i(nY<(@AAf7t<)Gj{^zb%fM=$u)4}RmIE5?`pS_0eelI`$ZRB8>ZtjMhbH{I5;vz;9 zyrspK6Jsf(t)q8J|WANN4QFu{`0x@A;DJS35AXCm_Fy2h-o~kI}C&tSDvDXw9@%X40M9R@R zTXmXcMadQn8>&-|k~LPqrzvAkY#1x|wH?G`BcbF=ko1@qRE|tI8S>T=>L>fSJM-Rn zl(SbZ!YGDynE7IXLe*-SiQHKZ+C@XpAPHUtfEts|^FSUPupo*8oNiY=SmSuOgN02S zGcOIYFmUt!XwE#8_z6fK(FzAYqr5d1;7;?@((9 zXPdDvXCI0W__3fzj^^+Pe&d?Xwdg${9t_WLFv?dKzq@i0ceI<=P zl1OLo=1aF;ugQlh@*()%?dYBN?&RI+MK`fjjb3u4OAmT>-P(V9qS`aLF^3;`=eN@} zd7>guaPE%YUA%kVJ(Y12Kd(kLSJFTpt~l_wN4=!8f13#KNsf2!%Y(I9tum{*=a$`N z!(B05DsWVh%+HfUBFg&1kQradJ$?i6hljjZyyUnaI<2rQgl}I zJa%cE?yMU;FGqXE$J0|hre~U{jcpk$la6~@evb4T=AmjQk&Y?tXOO)~-r)bVJ_SwZ|m`klYGC5;k*>2>yR3C4|Yp671d( mh)>?!R}luk^M!@u4+(S-ru*U#arkH`BJBN6i3@`~zW9GK@RSb# literal 0 HcmV?d00001 diff --git a/.core/__pycache__/markdown_linter.cpython-313.pyc b/.core/__pycache__/markdown_linter.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1a202e3fa5042bd1ec41835738ed04b1867c2424 GIT binary patch literal 6848 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 Q;bGbK|90(V>nLsi2h-1r+5i9m literal 0 HcmV?d00001 diff --git a/.core/__pycache__/prompts.cpython-313.pyc b/.core/__pycache__/prompts.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b52495c0ccf82f778bbe066643decf0cc650ea7 GIT binary patch literal 1996 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 Z|K|O}(wTYbq+hAb1+V@$Zd9C1{|f^`-xmM? literal 0 HcmV?d00001 diff --git a/.core/__pycache__/runner.cpython-313.pyc b/.core/__pycache__/runner.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d5d7df20206c9d1b7fa1f3a0cad361afd0e3d745 GIT binary patch literal 5666 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 None: + """Ensure that shared directories exist.""" + RESULTS_DIR.mkdir(parents=True, exist_ok=True) + TEMPLATES_DIR.mkdir(parents=True, exist_ok=True) + TEMP_DIR.mkdir(parents=True, exist_ok=True) + MODELS_DIR.mkdir(parents=True, exist_ok=True) + + +def get_env_setting(key: str, default: str) -> str: + """Read an environment variable with a default fallback.""" + return os.getenv(key, default) + + +def reset_temp_directory() -> None: + """Clear and recreate the temporary directory used for staging markdown blocks.""" + if TEMP_DIR.exists(): + shutil.rmtree(TEMP_DIR) + TEMP_DIR.mkdir(parents=True, exist_ok=True) diff --git a/.core/engine_loader.py b/.core/engine_loader.py new file mode 100644 index 0000000..50e4a98 --- /dev/null +++ b/.core/engine_loader.py @@ -0,0 +1,108 @@ +from __future__ import annotations + +import importlib.abc +import importlib.util +import platform +import shutil +from dataclasses import dataclass +from pathlib import Path +from typing import Optional, Type + +from config import CORE_DIR + +ENGINE_ROOT = CORE_DIR / ".engine" +DEFAULT_ENGINE_VERSION = "v1" + + +class EngineLoadError(RuntimeError): + """Raised when no suitable engine runtime can be loaded.""" + + +class BaseRuntime: + """Base class for local engine runtimes.""" + + name: str = "base" + + def discover_gguf_models(self, search_paths: list[Path]) -> list[Path]: + gguf_paths: list[Path] = [] + seen: set[Path] = set() + for root in search_paths: + if not root.exists(): + continue + for path in root.rglob("*.gguf"): + if path.is_file(): + resolved = path.resolve() + if resolved not in seen: + seen.add(resolved) + gguf_paths.append(resolved) + return gguf_paths + + def setup(self) -> None: + """Perform any runtime initialization before loading models.""" + + def load_model(self, model_path: Path) -> None: + """Load model into memory. Implementations may cache the loaded model.""" + + def generate(self, prompt: str, *, temperature: float) -> dict: + """Run inference against the currently loaded model and return a structured response.""" + raise NotImplementedError + + def unload(self) -> None: + """Optional hook to release resources.""" + + +@dataclass(frozen=True) +class EngineDescriptor: + architecture: str + version: str = DEFAULT_ENGINE_VERSION + + @property + def module_path(self) -> Path: + return ENGINE_ROOT / f".{self.architecture}" / f"{self.version}.py" + + @property + def module_name(self) -> str: + return f"engine_{self.architecture}_{self.version}" + + +def detect_architecture() -> EngineDescriptor: + system = platform.system().lower() + machine = platform.machine().lower() + + if system == "darwin" and machine.startswith("arm"): + return EngineDescriptor("apple_silicon") + + if shutil.which("nvidia-smi"): + return EngineDescriptor("cuda") + + if shutil.which("rocm-smi") or shutil.which("rocminfo"): + return EngineDescriptor("rocm") + + return EngineDescriptor("cpu") + + +def load_engine_class(descriptor: Optional[EngineDescriptor] = None) -> Type["BaseRuntime"]: + descriptor = descriptor or detect_architecture() + module_path = descriptor.module_path + if not module_path.exists(): + raise EngineLoadError(f"Engine runtime not found for architecture '{descriptor.architecture}' at {module_path}") + + spec = importlib.util.spec_from_file_location(descriptor.module_name, module_path) + if spec is None or spec.loader is None: + raise EngineLoadError(f"Unable to load engine module from {module_path}") + + module = importlib.util.module_from_spec(spec) + loader = spec.loader + assert isinstance(loader, importlib.abc.Loader) + try: + loader.exec_module(module) # type: ignore[attr-defined] + except Exception as exc: # pragma: no cover - import-time validation + raise EngineLoadError(f"Failed to initialize engine runtime for '{descriptor.architecture}': {exc}") from exc + + if not hasattr(module, "EngineRuntime"): + raise EngineLoadError(f"Engine module {module_path} does not define 'EngineRuntime'") + + runtime_cls = getattr(module, "EngineRuntime") + if not issubclass(runtime_cls, BaseRuntime): + raise EngineLoadError(f"Engine runtime from {module_path} must inherit from BaseRuntime") + return runtime_cls diff --git a/.core/markdown_linter.py b/.core/markdown_linter.py new file mode 100644 index 0000000..172948d --- /dev/null +++ b/.core/markdown_linter.py @@ -0,0 +1,203 @@ +from __future__ import annotations + +import re +from typing import Iterable, List, Tuple + +__all__ = ["infer_language_from_prompt", "lint_response_markdown"] + + +_LANGUAGE_HINTS: List[Tuple[str, str]] = [ + ("swiftui", "swift"), + ("swift", "swift"), + ("objective-c", "objective-c"), + ("objc", "objective-c"), + ("kotlin", "kotlin"), + ("typescript", "typescript"), + ("javascript", "javascript"), + ("node.js", "javascript"), + ("python", "python"), + ("rust", "rust"), + ("go", "go"), + ("c#", "csharp"), + ("c++", "cpp"), + ("java", "java"), + ("sql", "sql"), +] + +_CODE_SYMBOLS = set("{}();[]=<>+-*/.&|%!:@") +_CODE_PREFIXES = ( + "func ", + "class ", + "struct ", + "enum ", + "protocol ", + "extension ", + "import ", + "let ", + "var ", + "guard ", + "if ", + "for ", + "while ", + "switch ", + "case ", + "return ", + "init(", + "init ", + "deinit", + "public ", + "private ", + "internal ", + "fileprivate ", + "override ", + "@", + "#if", + "#endif", + "#warning", + "#error", +) + +_COMMENT_PREFIXES = ("///", "//", "/*", "*/", "* ") +_BULLET_PREFIXES = ("- ", "* ", "+ ", "• ") + + +def infer_language_from_prompt(prompt_text: str) -> str: + """Infer a reasonable language hint from the prompt text.""" + lowered = prompt_text.lower() + for token, language in _LANGUAGE_HINTS: + if token in lowered: + return language + return "text" + + +def lint_response_markdown(raw_text: str, *, language_hint: str = "text") -> str: + """Normalize markdown so that only code segments are fenced and text stays plain.""" + if not raw_text: + return "" + + text = raw_text.replace("\r\n", "\n").replace("\r", "\n").strip("\n") + if not text: + return "" + + if "```" in text: + return _normalize_existing_fences(text, language_hint) + + return _auto_fence_code_segments(text, language_hint) + + +def _normalize_existing_fences(text: str, language_hint: str) -> str: + lines = text.split("\n") + output: List[str] = [] + in_fence = False + for line in lines: + stripped = line.strip() + if stripped.startswith("```"): + fence_marker = stripped[3:].strip() + if in_fence: + output.append("```") + in_fence = False + else: + language = fence_marker or (language_hint if language_hint != "text" else "") + output.append(f"```{language}" if language else "```") + in_fence = True + else: + output.append(line) + + if in_fence: + output.append("```") + + result = "\n".join(output).strip() + return result + + +def _auto_fence_code_segments(text: str, language_hint: str) -> str: + lines = text.split("\n") + segments: List[Tuple[str, List[str]]] = [] + current_lines: List[str] = [] + current_mode: str | None = None + + for line in lines: + if _is_blank(line): + if current_lines: + current_lines.append(line) + continue + + classification = "code" if _is_likely_code_line(line) else "text" + + if current_mode is None: + current_mode = classification + current_lines.append(line) + continue + + if classification == current_mode: + current_lines.append(line) + continue + + segments.append((current_mode, current_lines)) + current_mode = classification + current_lines = [line] + + if current_lines: + segments.append((current_mode or "text", current_lines)) + + cleaned_parts: List[str] = [] + for mode, block_lines in segments: + block_text = "\n".join(block_lines).strip("\n") + if not block_text: + continue + if mode == "code": + cleaned_parts.append(_format_code_block(block_text, language_hint)) + else: + cleaned_parts.append(block_text) + + return "\n\n".join(part for part in cleaned_parts if part).strip() + + +def _format_code_block(content: str, language_hint: str) -> str: + language = language_hint if language_hint and language_hint != "text" else "" + inner = content.strip("\n") + return f"```{language}\n{inner}\n```" + + +def _is_blank(line: str) -> bool: + return not line.strip() + + +def _is_likely_code_line(line: str) -> bool: + if line.startswith((" ", "\t")): + return True + + stripped = line.strip() + if not stripped: + return False + + if stripped.startswith(_BULLET_PREFIXES): + return False + + if stripped.startswith(_COMMENT_PREFIXES): + return True + + if any(stripped.startswith(prefix) for prefix in _CODE_PREFIXES): + return True + + if stripped.endswith(("{", "}", ";")): + return True + + if stripped.startswith(("}", "{", "case ", "default:")): + return True + + if "(" in stripped and ")" in stripped: + return True + + if "=" in stripped: + return True + + symbol_count = sum(1 for ch in stripped if ch in _CODE_SYMBOLS) + letter_count = sum(1 for ch in stripped if ch.isalpha()) + if symbol_count >= 2 and symbol_count >= max(1, letter_count * 0.3): + return True + + if re.search(r"\)\s*->", stripped): + return True + + return False diff --git a/.core/prompts.py b/.core/prompts.py new file mode 100644 index 0000000..f3e5925 --- /dev/null +++ b/.core/prompts.py @@ -0,0 +1,46 @@ +import re +import textwrap +from pathlib import Path +from typing import Dict, List + +from config import TESTS_DIR + + +def _natural_key(path: Path) -> List[object]: + parts = re.split(r"(\d+)", path.stem) + return [int(part) if part.isdigit() else part.lower() for part in parts] + + +def load_test_prompts() -> List[Dict[str, str]]: + """Load prompt files from the tests directory.""" + if not TESTS_DIR.exists(): + return [] + + prompt_entries: List[Dict[str, str]] = [] + + for prompt_path in sorted(TESTS_DIR.glob("*.txt"), key=_natural_key): + try: + raw_text = prompt_path.read_text(encoding="utf-8") + except OSError: + continue + + prompt_text = textwrap.dedent(raw_text).strip() + if not prompt_text: + continue + + title = prompt_path.stem + for line in prompt_text.splitlines(): + stripped_line = line.strip() + if stripped_line: + title = stripped_line + break + + prompt_entries.append( + { + "title": title, + "prompt": prompt_text, + "filename": prompt_path.name, + } + ) + + return prompt_entries diff --git a/.core/providers/__init__.py b/.core/providers/__init__.py new file mode 100644 index 0000000..86d2854 --- /dev/null +++ b/.core/providers/__init__.py @@ -0,0 +1,34 @@ +from __future__ import annotations + +from typing import Dict, List, Type + +from .base import ModelInfo, Provider, ProviderError +from .lmstudio import LMStudioProvider +from .local_engine import LocalEngineProvider + +_PROVIDER_REGISTRY: Dict[str, Type[Provider]] = { + LMStudioProvider.name: LMStudioProvider, + LocalEngineProvider.name: LocalEngineProvider, +} + + +def list_provider_names() -> List[str]: + return sorted(_PROVIDER_REGISTRY.keys()) + + +def get_provider(provider_name: str, **kwargs) -> Provider: + try: + provider_cls = _PROVIDER_REGISTRY[provider_name] + except KeyError as exc: + raise ProviderError(f"Unknown provider '{provider_name}'") from exc + return provider_cls(**kwargs) + + +__all__ = [ + "ModelInfo", + "Provider", + "ProviderError", + "list_provider_names", + "get_provider", + "LocalEngineProvider", +] diff --git a/.core/providers/__pycache__/__init__.cpython-313.pyc b/.core/providers/__pycache__/__init__.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0538d104c5150fe9fc18cc82ea3a6fca5ef3a73f GIT binary patch literal 1359 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 OiQU=%PegvH$$tZ-zwa0T literal 0 HcmV?d00001 diff --git a/.core/providers/base.py b/.core/providers/base.py new file mode 100644 index 0000000..8313fa6 --- /dev/null +++ b/.core/providers/base.py @@ -0,0 +1,29 @@ +from __future__ import annotations + +from abc import ABC, abstractmethod +from dataclasses import dataclass +from typing import Dict, List + + +@dataclass(frozen=True) +class ModelInfo: + id: str + display_name: str + + +class ProviderError(Exception): + """Base exception for provider-related errors.""" + + +class Provider(ABC): + """Abstract interface for model providers.""" + + name: str + + @abstractmethod + def list_models(self) -> List[ModelInfo]: + """Return the models available from this provider.""" + + @abstractmethod + def run_prompt(self, model_id: str, prompt: str, *, temperature: float) -> Dict[str, object]: + """Execute a prompt against a model and return the response payload.""" diff --git a/.core/providers/lmstudio.py b/.core/providers/lmstudio.py new file mode 100644 index 0000000..546f343 --- /dev/null +++ b/.core/providers/lmstudio.py @@ -0,0 +1,100 @@ +from __future__ import annotations + +import json +import time +from typing import Dict, List, Optional + +import requests + +from config import get_env_setting +from .base import ModelInfo, Provider, ProviderError + +DEFAULT_BASE_URL = "http://localhost:1234" + + +class LMStudioProvider(Provider): + name = "LM Studio" + + def __init__(self, base_url: Optional[str] = None) -> None: + self.base_url = base_url or get_env_setting("LM_STUDIO_BASE_URL", DEFAULT_BASE_URL) + self._models_url = f"{self.base_url}/v1/models" + self._chat_url = f"{self.base_url}/v1/chat/completions" + + def list_models(self) -> List[ModelInfo]: + try: + response = requests.get(self._models_url, timeout=10) + response.raise_for_status() + except requests.exceptions.RequestException as exc: + raise ProviderError(f"Failed to fetch models from LM Studio: {exc}") from exc + + try: + data = response.json() + except json.JSONDecodeError as exc: + raise ProviderError(f"Failed to decode model list: {exc}") from exc + + models = data.get("data", []) + result: List[ModelInfo] = [] + if isinstance(models, list): + for item in models: + if isinstance(item, dict): + model_id = str(item.get("id") or item.get("name") or "") + else: + model_id = str(item) + if not model_id: + continue + result.append(ModelInfo(id=model_id, display_name=model_id)) + + default_model = data.get("default_model") or data.get("model") or data.get("id") + if default_model and all(m.id != default_model for m in result): + result.insert(0, ModelInfo(id=str(default_model), display_name=str(default_model))) + + if not result: + raise ProviderError("LM Studio returned no models.") + + return result + + def run_prompt(self, model_id: str, prompt: str, *, temperature: float) -> Dict[str, object]: + headers = {"Content-Type": "application/json"} + payload = { + "model": model_id, + "messages": [{"role": "user", "content": prompt}], + "temperature": temperature, + } + + start_time = time.time() + try: + response = requests.post( + self._chat_url, + headers=headers, + data=json.dumps(payload), + timeout=180, + ) + response.raise_for_status() + except requests.exceptions.RequestException as exc: + return {"error": f"API request failed: {exc}"} + + end_time = time.time() + + try: + data = response.json() + except json.JSONDecodeError as exc: + return {"error": f"Failed to parse response JSON: {exc}\nRaw: {response.text}"} + + response_time = end_time - start_time + content = data.get("choices", [{}])[0].get("message", {}).get("content", "Error: No content found.") + usage = data.get("usage", {}) + total_tokens = usage.get("completion_tokens", 0) + time_to_first_token = usage.get("prompt_eval_duration", 0) / 1_000_000_000 + stop_reason = data.get("choices", [{}])[0].get("finish_reason", "N/A") + + tokens_per_second = total_tokens / response_time if response_time > 0 else 0 + + return { + "response": content, + "metrics": { + "tokens_per_second": round(tokens_per_second, 2), + "total_tokens": total_tokens, + "time_to_first_token": round(time_to_first_token, 2), + "stop_reason": stop_reason, + }, + } diff --git a/.core/providers/local_engine.py b/.core/providers/local_engine.py new file mode 100644 index 0000000..f98f6c3 --- /dev/null +++ b/.core/providers/local_engine.py @@ -0,0 +1,80 @@ +from __future__ import annotations + +import hashlib +import os +from pathlib import Path +from typing import Dict, List, Optional + +from config import MODELS_DIR +from engine_loader import EngineLoadError, load_engine_class +from .base import ModelInfo, Provider, ProviderError + + +class LocalEngineProvider(Provider): + name = "Local Engine" + + def __init__(self, search_paths: Optional[List[Path]] = None) -> None: + try: + runtime_cls = load_engine_class() + self.runtime = runtime_cls() + self.runtime.setup() + except EngineLoadError as exc: + raise ProviderError(str(exc)) from exc + except RuntimeError as exc: + raise ProviderError(str(exc)) from exc + + paths: List[Path] = [MODELS_DIR] + env_override = os.getenv("LOCAL_LLM_PATHS") + if env_override: + for entry in env_override.split(os.pathsep): + entry_clean = entry.strip() + if not entry_clean: + continue + entry_path = Path(entry_clean).expanduser() + if entry_path not in paths: + paths.append(entry_path) + if search_paths: + for candidate in search_paths: + if candidate not in paths: + paths.append(candidate) + + self.search_paths = paths + self._model_index: Dict[str, Path] = {} + + def list_models(self) -> List[ModelInfo]: + discovered = self.runtime.discover_gguf_models(self.search_paths) + self._model_index.clear() + models: List[ModelInfo] = [] + for path in discovered: + model_id = self._register_model(path) + models.append(ModelInfo(id=model_id, display_name=path.stem)) + if not models: + raise ProviderError( + "No GGUF models were found. Place models inside the 'models' directory or set LOCAL_LLM_PATHS." + ) + return models + + def run_prompt(self, model_id: str, prompt: str, *, temperature: float) -> Dict[str, object]: + try: + model_path = self._model_index[model_id] + except KeyError as exc: + raise ProviderError(f"Model '{model_id}' is not registered. Refresh the model list and try again.") from exc + + self.runtime.load_model(model_path) + return self.runtime.generate(prompt, temperature=temperature) + + def _register_model(self, path: Path) -> str: + for existing_id, existing_path in self._model_index.items(): + if path == existing_path: + return existing_id + + base_id = path.stem + candidate = base_id + counter = 1 + while candidate in self._model_index: + digest = hashlib.sha1(str(path).encode("utf-8")).hexdigest()[:6] + candidate = f"{base_id}-{digest}-{counter}" + counter += 1 + + self._model_index[candidate] = path + return candidate diff --git a/.core/reporting.py b/.core/reporting.py new file mode 100644 index 0000000..5581a38 --- /dev/null +++ b/.core/reporting.py @@ -0,0 +1,206 @@ +import hashlib +import re +import textwrap +from pathlib import Path +from typing import Dict, List, Optional + +from config import RESULTS_DIR, TEMPLATE_PATH, TEMP_DIR +from markdown_linter import infer_language_from_prompt, lint_response_markdown + +_TEMPLATE_CACHE: Optional[str] = None + + +class TemplateNotFoundError(FileNotFoundError): + pass + + +def load_template() -> str: + """Load the test block template from disk, caching the content.""" + global _TEMPLATE_CACHE + if _TEMPLATE_CACHE is None: + if not TEMPLATE_PATH.exists(): + raise TemplateNotFoundError( + f"Template file not found at '{TEMPLATE_PATH}'. Please create it before running tests." + ) + _TEMPLATE_CACHE = TEMPLATE_PATH.read_text(encoding="utf-8") + return _TEMPLATE_CACHE + + +def has_unclosed_code_block(markdown_text: str) -> bool: + """Check if markdown text ends inside an unclosed triple-backtick block.""" + fence_count = markdown_text.count("```") + return fence_count % 2 == 1 + + +def render_response_block(result: Dict[str, object], *, language_hint: str) -> str: + """Render the response portion of the template based on the result payload.""" + if "error" in result: + return "\n".join(["### Response:", f"**ERROR:** {result['error']}", ""]) + + cleaned_response = lint_response_markdown(result["response"], language_hint=language_hint) + + section_lines = ["### Response:"] + if cleaned_response: + section_lines.append("") + section_lines.append(cleaned_response) + section_lines.append("") + return "\n".join(section_lines) + + +def render_test_block( + prompt_info: Dict[str, str], + result: Dict[str, object], + index: int, +) -> str: + """Populate the test block template with data for a single test.""" + template = load_template() + + metrics = result.get("metrics", {}) if "error" not in result else {} + + ttft_value = metrics.get("time_to_first_token") if metrics else None + language_hint = infer_language_from_prompt(prompt_info["prompt"]) + + replacements = { + "{{TEST_NUMBER}}": str(index), + "{{TEST_TITLE}}": prompt_info.get("title", f"Test {index}"), + "{{SOURCE_FILENAME}}": prompt_info.get("filename", "unknown"), + "{{PROMPT_CONTENT}}": prompt_info["prompt"].strip(), + "{{RESPONSE_BLOCK}}": render_response_block(result, language_hint=language_hint).rstrip(), + "{{METRIC_TOKENS_PER_SECOND}}": ( + str(metrics.get("tokens_per_second", "N/A")) + if metrics + else "N/A" + ), + "{{METRIC_TOTAL_TOKENS}}": ( + str(metrics.get("total_tokens", "N/A")) + if metrics + else "N/A" + ), + "{{METRIC_TTFT}}": ( + f"{ttft_value}s" if isinstance(ttft_value, (int, float)) else "N/A" + ), + "{{METRIC_STOP_REASON}}": ( + str(metrics.get("stop_reason", "N/A")) + if metrics + else "N/A" + ), + } + + rendered = template + for placeholder, value in replacements.items(): + rendered = rendered.replace(placeholder, value) + + return rendered.rstrip() + "\n\n" + + +def sanitize_model_name(model_name: str) -> str: + sanitized = re.sub(r"[^A-Za-z0-9._-]+", "_", model_name.strip()) + return sanitized or "unknown-model" + + +def initialize_report_file(model_label: str) -> Path: + """Create the markdown report shell and return its path.""" + sanitized = sanitize_model_name(model_label) + RESULTS_DIR.mkdir(parents=True, exist_ok=True) + report_path = RESULTS_DIR / f"automated_report_{sanitized}.md" + + header = textwrap.dedent( + f""" + # Automated Diagnostic Report: {model_label} + + --- + + ## Performance Summary + + + * **Average Tokens/s:** TBD + * **Average Time to First Token:** TBD + * **Total Tokens Generated:** TBD + + + ## Qualitative Analysis + + *(Manual grading and analysis of the responses is required to determine the final letter grade.)* + + --- + + """ + ).lstrip() + + report_path.write_text(header, encoding="utf-8") + return report_path + + +def append_test_result( + report_path: Path, + prompt_info: Dict[str, str], + result: Dict[str, object], + index: int, +) -> None: + """Append a single test section to the markdown report.""" + block_content = render_test_block(prompt_info, result, index) + + slug_base = re.sub(r"[^A-Za-z0-9._-]+", "-", prompt_info.get("title", f"test-{index}")).strip("-") + if not slug_base: + slug_base = f"test-{index}" + slug_hash = hashlib.sha1(slug_base.encode("utf-8")).hexdigest()[:8] + truncated_slug = slug_base[:48] + title_slug = f"{truncated_slug}-{slug_hash}" + temp_file = TEMP_DIR / f"{index:03d}_{title_slug}.md" + + try: + temp_file.write_text(block_content, encoding="utf-8") + except OSError: + pass + + block_text = temp_file.read_text(encoding="utf-8") if temp_file.exists() else block_content + if has_unclosed_code_block(block_text): + block_text = block_text.rstrip() + "\n```\n" + + separator = "\n\n---\n\n" + existing_tail = report_path.read_text(encoding="utf-8") if report_path.exists() else "" + needs_separator = existing_tail and not existing_tail.endswith(separator) + + with report_path.open("a", encoding="utf-8") as report_file: + if existing_tail and has_unclosed_code_block(existing_tail): + report_file.write("\n```\n\n") + if needs_separator and existing_tail: + report_file.write(separator) + report_file.write(block_text) + + if temp_file.exists(): + try: + temp_file.unlink() + except OSError: + pass + + +def finalize_report_summary(report_path: Path, results: List[Dict[str, object]]) -> None: + """Update the performance summary placeholder once all tests have run.""" + valid_results = [r for r in results if "error" not in r] + + if valid_results: + total_tok_s = sum(r["metrics"]["tokens_per_second"] for r in valid_results) + total_ttft = sum(r["metrics"]["time_to_first_token"] for r in valid_results) + total_tokens = sum(r["metrics"]["total_tokens"] for r in valid_results) + avg_tok_s = round(total_tok_s / len(valid_results), 2) + avg_ttft = round(total_ttft / len(valid_results), 2) + else: + avg_tok_s = avg_ttft = total_tokens = 0 + + summary_block = textwrap.dedent( + f""" + * **Average Tokens/s:** {avg_tok_s} + * **Average Time to First Token:** {avg_ttft}s + * **Total Tokens Generated:** {total_tokens} + """ + ).strip() + + content = report_path.read_text(encoding="utf-8") + updated_content = re.sub( + r".*?", + f"\n{summary_block}\n", + content, + flags=re.DOTALL, + ) + report_path.write_text(updated_content, encoding="utf-8") diff --git a/.core/runner.py b/.core/runner.py new file mode 100644 index 0000000..455091f --- /dev/null +++ b/.core/runner.py @@ -0,0 +1,121 @@ +from __future__ import annotations + +import sys +from pathlib import Path +from typing import Callable, Dict, List, Optional + +from config import ( + DEFAULT_PROVIDER_NAME, + DEFAULT_TEMPERATURE, + TEMPLATE_PATH, + ensure_directories, + reset_temp_directory, +) +from prompts import load_test_prompts +from reporting import ( + TemplateNotFoundError, + append_test_result, + finalize_report_summary, + initialize_report_file, +) +from providers import LocalEngineProvider, ModelInfo, ProviderError, get_provider +from settings import get_local_model_paths + + +class TestRunError(Exception): + pass + + +def _choose_model(models: List[ModelInfo], requested_id: Optional[str]) -> ModelInfo: + if not models: + raise TestRunError("No models available from provider.") + + if requested_id: + for model in models: + if model.id == requested_id: + return model + raise TestRunError(f"Model '{requested_id}' not found for the selected provider.") + + return models[0] + + +def run_suite( + *, + provider_name: Optional[str] = None, + model_id: Optional[str] = None, + temperature: Optional[float] = None, + progress_callback: Optional[Callable[[int, int, Dict[str, str], Dict[str, object]], None]] = None, +) -> Path: + """Run the diagnostic test suite and return the generated report path.""" + ensure_directories() + reset_temp_directory() + + provider_name = provider_name or DEFAULT_PROVIDER_NAME + provider_kwargs = {} + if provider_name == LocalEngineProvider.name: + custom_paths = [Path(p).expanduser() for p in get_local_model_paths()] + provider_kwargs["search_paths"] = [path for path in custom_paths if path] + + try: + provider = get_provider(provider_name, **provider_kwargs) + except ProviderError as exc: + raise TestRunError(str(exc)) from exc + + try: + models = provider.list_models() + except ProviderError as exc: + raise TestRunError(str(exc)) from exc + + model = _choose_model(models, model_id) + + if not TEMPLATE_PATH.exists(): + raise TestRunError( + "Template file missing. Please create '.core/templates/test-block.md' before running tests." + ) + + prompts = load_test_prompts() + if not prompts: + raise TestRunError("No test prompts found in the 'tests' directory.") + + report_path = initialize_report_file(model.display_name) + all_results: List[Dict[str, object]] = [] + selected_temperature = temperature if temperature is not None else DEFAULT_TEMPERATURE + + total_tests = len(prompts) + + for index, prompt in enumerate(prompts, start=1): + result = provider.run_prompt(model.id, prompt["prompt"], temperature=selected_temperature) + all_results.append(result) + append_test_result(report_path, prompt, result, index) + if progress_callback: + progress_callback(index, total_tests, prompt, result) + + finalize_report_summary(report_path, all_results) + return report_path + + +def safe_run() -> int: + """CLI helper for running the suite with basic error handling.""" + def _print_progress(index: int, total: int, prompt: Dict[str, str], result: Dict[str, object]) -> None: + status = "FAILED" if "error" in result else "DONE" + filename_label = prompt.get("filename", f"test{index}") + title = prompt.get("title", f"Test {index}") + print(f"Running {title} [{filename_label}] ({index}/{total})... {status}") + + print(f"Starting automated diagnostic run with provider '{DEFAULT_PROVIDER_NAME}'…") + + try: + report_path = run_suite(progress_callback=_print_progress) + except TestRunError as exc: + print(f"Error: {exc}") + return 1 + except TemplateNotFoundError as exc: + print(f"Error: {exc}") + return 1 + + print(f"\n✅ Success! Report saved to '{report_path.name}'.") + return 0 + + +if __name__ == "__main__": + sys.exit(safe_run()) diff --git a/.core/settings.py b/.core/settings.py new file mode 100644 index 0000000..6d23152 --- /dev/null +++ b/.core/settings.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +import json +from pathlib import Path +from typing import Dict, List + +from config import CORE_DIR + +SETTINGS_PATH = CORE_DIR / "user_settings.json" + +_DEFAULT_LOCAL_PATHS: List[str] = [] +for candidate in ( + Path.home() / ".lmstudio", + Path.home() / ".lmstudio/models", + Path.home() / "Library/Application Support/lm-studio/models", +): + normalized = str(candidate) + if normalized not in _DEFAULT_LOCAL_PATHS: + _DEFAULT_LOCAL_PATHS.append(normalized) + +_DEFAULT_SETTINGS: Dict[str, object] = { + "local_model_paths": _DEFAULT_LOCAL_PATHS, +} + + +def load_settings() -> Dict[str, object]: + if not SETTINGS_PATH.exists(): + return dict(_DEFAULT_SETTINGS) + try: + data = json.loads(SETTINGS_PATH.read_text(encoding="utf-8")) + except (json.JSONDecodeError, OSError): + return dict(_DEFAULT_SETTINGS) + if not isinstance(data, dict): + return dict(_DEFAULT_SETTINGS) + merged = dict(_DEFAULT_SETTINGS) + merged.update(data) + return merged + + +def save_settings(settings: Dict[str, object]) -> None: + SETTINGS_PATH.write_text(json.dumps(settings, indent=2, sort_keys=True), encoding="utf-8") + + +def get_local_model_paths() -> List[str]: + settings = load_settings() + paths = settings.get("local_model_paths", []) + if not isinstance(paths, list): + return [] + result: List[str] = [] + for entry in paths: + if isinstance(entry, str) and entry.strip(): + normalized = str(Path(entry).expanduser()) + if normalized not in result: + result.append(normalized) + return result + + +def set_local_model_paths(paths: List[str]) -> None: + settings = load_settings() + normalized: List[str] = [] + for entry in paths: + if isinstance(entry, str) and entry.strip(): + candidate = str(Path(entry).expanduser()) + if candidate not in normalized: + normalized.append(candidate) + settings["local_model_paths"] = normalized + save_settings(settings) diff --git a/.core/templates/test-block.md b/.core/templates/test-block.md new file mode 100644 index 0000000..7cbfbe0 --- /dev/null +++ b/.core/templates/test-block.md @@ -0,0 +1,18 @@ +## Test {{TEST_NUMBER}}: {{TEST_TITLE}} + +*Source:* `{{SOURCE_FILENAME}}` + +### Prompt: +```swift +{{PROMPT_CONTENT}} +``` + +{{RESPONSE_BLOCK}} + +### Performance Metrics: +* **Tokens/s:** {{METRIC_TOKENS_PER_SECOND}} +* **Total Tokens:** {{METRIC_TOTAL_TOKENS}} +* **Time to First Token:** {{METRIC_TTFT}} +* **Stop Reason:** {{METRIC_STOP_REASON}} + +--- diff --git a/README.md b/README.md new file mode 100644 index 0000000..00d98bb --- /dev/null +++ b/README.md @@ -0,0 +1,77 @@ +# LLM Automated Test Suite + +This project automates a battery of diagnostic prompts against local or remote language models via a modular core runner and an optional GUI. + +## Prerequisites + +- Python 3.10 or newer (tkinter included with the standard library on macOS/Linux; install `python3-tk` on Debian-based systems if needed). +- Install dependencies: + +```bash +python -m pip install -r requirements.txt +``` + +## Project Layout + +- `.core/` – shared logic modules, templates, engines, and transient workspace used by both CLI and GUI. + - `config.py` – path/setting helpers. + - `prompts.py` – prompt discovery from `tests/`. + - `providers/` – provider adapters (LM Studio and the native Local Engine runtime). + - `reporting.py` – markdown templating, code-fence hygiene, report summaries. + - `runner.py` – orchestrates full test runs with progress callbacks. + - `engine_loader.py` – detects the host platform/GPU and loads the appropriate runtime. + - `.engine/./.py` – runtime implementations per hardware family (Apple Silicon ↦ MLX, CUDA ↦ llama.cpp, ROCm ↦ llama.cpp, CPU fallback). + - `.temp/` – ephemeral staging for rendered blocks. + - `templates/test-block.md` – markdown template for each test result. +- `models/` – drop-in directory for local `.gguf` (and MLX-compatible) weights discovered by the Local Engine provider. +- `tests/` – one prompt per `.txt` file (editable via the GUI or any editor). +- `results/` – generated markdown reports. +- `auto-test.py` – CLI entrypoint that runs the default provider/model. +- `index.py` – Tkinter GUI for provider/model selection, running tests, and opening prompts/results. + +## Running the CLI + +```bash +python auto-test.py +``` + +The CLI selects the first available model for the default provider (LM Studio by default) and streams progress to stdout. Reports are saved in `results/automated_report_.md`. + +To switch to the Local Engine runtime, set `AUTO_TEST_PROVIDER="Local Engine"` (or choose it in the GUI) and ensure your models are available in the `models/` directory or any path listed in `LOCAL_LLM_PATHS`. + +## Using the GUI + +```bash +python index.py +``` + +GUI features: + +- Provider dropdown with automatic model discovery. +- Model dropdown populated per provider. +- Adjustable sampling temperature. +- Buttons to run tests, refresh models, open the `tests/` folder, open the `results/` folder, and open the latest report. +- Live log of test progress and completion status. +- Settings menu → “Configure Model Paths…” to manage additional folders scanned by the Local Engine provider (persisted in `.core/user_settings.json`). + +## Configuration + +Environment variables: + +- `LM_STUDIO_BASE_URL` – override the default `http://localhost:1234` endpoint for the LM Studio provider. +- `AUTO_TEST_TEMPERATURE` – default sampling temperature for test runs. +- `AUTO_TEST_PROVIDER` – default provider name for CLI runs. +- `LOCAL_LLM_PATHS` – optional `os.pathsep`-separated list of extra directories to scan for `.gguf` weights. + +Templates can be customized by editing `.core/templates/test-block.md`. + +### Local Engine provider + +- Place `.gguf` (llama.cpp) weights inside `models/` or add extra directories via the GUI settings dialog / `LOCAL_LLM_PATHS` environment variable. +- Paths include common defaults (for example `~/.lmstudio`, `~/.lmstudio/models`, or `~/Library/Application Support/lm-studio/models` on macOS) so LM Studio downloads are discovered automatically. +- The engine loader automatically selects the best runtime for your hardware: MLX on Apple Silicon, CUDA on NVIDIA GPUs, ROCm on AMD GPUs, or a CPU fallback via `llama-cpp-python`. +- Settings are saved in `.core/user_settings.json`, keeping CLI and GUI runs in sync. + +## Extending Providers + +Provider adapters live under `.core/providers/` and are registered in `.core/providers/__init__.py`. Each provider implements `list_models` and `run_prompt` to integrate with the runner and GUI, while hardware-specific runtimes reside under `.core/.engine/`. diff --git a/auto-test.py b/auto-test.py new file mode 100644 index 0000000..b7252fd --- /dev/null +++ b/auto-test.py @@ -0,0 +1,13 @@ +from __future__ import annotations + +import sys +from pathlib import Path + +CORE_DIR = Path(__file__).resolve().parent / ".core" +if str(CORE_DIR) not in sys.path: + sys.path.insert(0, str(CORE_DIR)) + +from runner import safe_run # type: ignore # noqa: E402 + +if __name__ == "__main__": + raise SystemExit(safe_run()) diff --git a/index.py b/index.py new file mode 100644 index 0000000..066f24e --- /dev/null +++ b/index.py @@ -0,0 +1,339 @@ +from __future__ import annotations + +import os +import subprocess +import sys +import threading +import time +from pathlib import Path +from typing import Dict, List, Tuple +from tkinter import filedialog, messagebox, scrolledtext, ttk +import tkinter as tk + +CORE_DIR = Path(__file__).resolve().parent / ".core" +if str(CORE_DIR) not in sys.path: + sys.path.insert(0, str(CORE_DIR)) + +from config import RESULTS_DIR, TESTS_DIR # type: ignore # noqa: E402 +from providers import ( # type: ignore # noqa: E402 + LocalEngineProvider, + ProviderError, + get_provider, + list_provider_names, +) +from reporting import TemplateNotFoundError # type: ignore # noqa: E402 +from runner import TestRunError, run_suite # type: ignore # noqa: E402 +from settings import get_local_model_paths, set_local_model_paths # type: ignore # noqa: E402 + + +def open_path(path: Path) -> None: + if sys.platform.startswith("darwin"): + subprocess.run(["open", str(path)], check=False) + elif os.name == "nt": # Windows + os.startfile(str(path)) # type: ignore[attr-defined] + else: + subprocess.run(["xdg-open", str(path)], check=False) + + +class App(tk.Tk): + def __init__(self) -> None: + super().__init__() + self.title("LLM Automated Test Console") + self.geometry("880x620") + self.minsize(760, 520) + + self.provider_names = list_provider_names() + self.provider_var = tk.StringVar(value=self.provider_names[0] if self.provider_names else "") + self.model_var = tk.StringVar() + self.temperature_var = tk.DoubleVar(value=0.1) + self.status_var = tk.StringVar(value="Idle") + + self.available_models: List[Tuple[str, str]] = [] # (id, display name) + self.running = False + + self._build_ui() + self._build_menu() + if self.provider_var.get(): + self.fetch_models_async() + + def _build_ui(self) -> None: + padding = {"padx": 12, "pady": 8} + + header = ttk.Label(self, text="Automated Diagnostic Test Runner", font=("Helvetica", 18, "bold")) + header.pack(anchor="w", **padding) + + form_frame = ttk.Frame(self) + form_frame.pack(fill="x", **padding) + + ttk.Label(form_frame, text="Provider:").grid(row=0, column=0, sticky="w") + self.provider_combo = ttk.Combobox( + form_frame, + textvariable=self.provider_var, + values=self.provider_names, + state="readonly", + ) + self.provider_combo.grid(row=0, column=1, sticky="ew", padx=(6, 18)) + self.provider_combo.bind("<>", lambda event: self.fetch_models_async()) + + ttk.Label(form_frame, text="Model:").grid(row=0, column=2, sticky="w") + self.model_combo = ttk.Combobox(form_frame, textvariable=self.model_var, state="readonly") + self.model_combo.grid(row=0, column=3, sticky="ew", padx=(6, 18)) + + ttk.Label(form_frame, text="Temperature:").grid(row=0, column=4, sticky="w") + self.temperature_spin = ttk.Spinbox( + form_frame, + textvariable=self.temperature_var, + from_=0.0, + to=1.0, + increment=0.05, + width=6, + ) + self.temperature_spin.grid(row=0, column=5, sticky="w") + + form_frame.columnconfigure(1, weight=1) + form_frame.columnconfigure(3, weight=1) + + button_frame = ttk.Frame(self) + button_frame.pack(fill="x", **padding) + + self.run_button = ttk.Button(button_frame, text="Run Tests", command=self.start_run) + self.run_button.pack(side="left") + + ttk.Button(button_frame, text="Refresh Models", command=self.fetch_models_async).pack(side="left", padx=(12, 0)) + ttk.Button(button_frame, text="Edit Tests", command=lambda: open_path(TESTS_DIR)).pack(side="left", padx=(12, 0)) + ttk.Button(button_frame, text="Open Results", command=lambda: open_path(RESULTS_DIR)).pack(side="left", padx=(12, 0)) + ttk.Button(button_frame, text="View Latest Report", command=self.open_latest_report).pack(side="left", padx=(12, 0)) + + ttk.Label(self, textvariable=self.status_var).pack(anchor="w", **padding) + + self.log = scrolledtext.ScrolledText(self, wrap="word", height=22) + self.log.pack(fill="both", expand=True, padx=12, pady=(0, 12)) + self.log.configure(state="disabled") + + def _build_menu(self) -> None: + menubar = tk.Menu(self) + settings_menu = tk.Menu(menubar, tearoff=0) + settings_menu.add_command(label="Configure Model Paths…", command=self.configure_model_paths) + menubar.add_cascade(label="Settings", menu=settings_menu) + self.config(menu=menubar) + self._settings_menu = settings_menu + + def fetch_models_async(self) -> None: + if self.running: + return + + provider_name = self.provider_var.get() + if not provider_name: + return + + self._set_status(f"Fetching models for {provider_name}…") + self.model_combo.configure(values=()) + self.model_var.set("") + + thread = threading.Thread(target=self._fetch_models, daemon=True) + thread.start() + + def _fetch_models(self) -> None: + provider_name = self.provider_var.get() + try: + provider = get_provider(provider_name, **self._provider_kwargs(provider_name)) + models = provider.list_models() + except ProviderError as exc: + message = str(exc) + self.after(0, lambda m=message: self._on_model_fetch_error(m)) + return + + model_pairs = [(model.id, model.display_name) for model in models] + self.after(0, lambda: self._on_models_loaded(model_pairs)) + + def _on_model_fetch_error(self, message: str) -> None: + self._set_status("Model fetch failed") + messagebox.showerror("Model Load Error", message) + + def _on_models_loaded(self, model_pairs: List[Tuple[str, str]]) -> None: + self.available_models = model_pairs + options = [display for _, display in model_pairs] + self.model_combo.configure(values=options) + if options: + self.model_var.set(options[0]) + self._set_status(f"Loaded {len(options)} models.") + else: + self.model_var.set("") + self._set_status("No models found.") + + def start_run(self) -> None: + if self.running: + return + + provider_name = self.provider_var.get() + model_display = self.model_var.get() + + if not provider_name: + messagebox.showwarning("Missing Provider", "Please select a provider before running tests.") + return + + if not model_display: + messagebox.showwarning("Missing Model", "Please select a model before running tests.") + return + + model_id = self._model_id_for_display(model_display) + if not model_id: + messagebox.showerror("Model Error", "Unable to resolve the selected model.") + return + + temperature = float(self.temperature_var.get()) + self.running = True + self._set_status("Running tests…") + self._append_log(f"Starting run with provider '{provider_name}' and model '{model_display}'.") + self._toggle_controls(state="disabled") + + thread = threading.Thread( + target=self._run_tests_thread, + args=(provider_name, model_id, temperature), + daemon=True, + ) + thread.start() + + def _run_tests_thread(self, provider_name: str, model_id: str, temperature: float) -> None: + start_time = time.time() + + def progress_callback(index: int, total: int, prompt: Dict[str, str], result: Dict[str, object]) -> None: + status = "FAILED" if "error" in result else "DONE" + title = prompt.get("title", f"Test {index}") + filename = prompt.get("filename", f"test{index}") + message = f"[{index}/{total}] {title} ({filename}) -> {status}" + self.after(0, lambda: self._append_log(message)) + + try: + report_path = run_suite( + provider_name=provider_name, + model_id=model_id, + temperature=temperature, + progress_callback=progress_callback, + ) + except (TestRunError, TemplateNotFoundError) as exc: + message = str(exc) + self.after(0, lambda m=message: self._handle_run_error(m)) + return + + elapsed = time.time() - start_time + self.after(0, lambda: self._handle_run_success(report_path, elapsed)) + + def _handle_run_error(self, message: str) -> None: + self.running = False + self._toggle_controls(state="normal") + self._set_status("Run failed") + self._append_log(f"Error: {message}") + messagebox.showerror("Run Failed", message) + + def _handle_run_success(self, report_path: Path, elapsed: float) -> None: + self.running = False + self._toggle_controls(state="normal") + self._set_status("Run complete") + self._append_log(f"Run complete in {elapsed:.2f}s. Report saved to {report_path.name}.") + messagebox.showinfo("Run Complete", f"Report saved to {report_path}") + + def _toggle_controls(self, *, state: str) -> None: + widgets = [ + self.run_button, + self.provider_combo, + self.model_combo, + self.temperature_spin, + ] + for widget in widgets: + widget.configure(state=state) + + def _append_log(self, message: str) -> None: + timestamp = time.strftime("%H:%M:%S") + self.log.configure(state="normal") + self.log.insert("end", f"[{timestamp}] {message}\n") + self.log.see("end") + self.log.configure(state="disabled") + + def _set_status(self, message: str) -> None: + self.status_var.set(message) + + def _model_id_for_display(self, display_name: str) -> str | None: + for model_id, display in self.available_models: + if display == display_name: + return model_id + return None + + def _provider_kwargs(self, provider_name: str) -> Dict[str, object]: + if provider_name == LocalEngineProvider.name: + custom_paths = [Path(p).expanduser() for p in get_local_model_paths()] + return {"search_paths": [path for path in custom_paths if path]} + return {} + + def configure_model_paths(self) -> None: + dialog = tk.Toplevel(self) + dialog.title("Configure Model Paths") + dialog.geometry("520x320") + dialog.transient(self) + dialog.grab_set() + + paths: List[str] = get_local_model_paths() + + listbox = tk.Listbox(dialog, selectmode=tk.SINGLE, width=60, height=10) + for entry in paths: + listbox.insert("end", entry) + listbox.pack(fill="both", expand=True, padx=12, pady=(12, 6)) + + button_frame = ttk.Frame(dialog) + button_frame.pack(fill="x", padx=12, pady=6) + + def add_path() -> None: + selection = filedialog.askdirectory(parent=dialog) + if selection and selection not in paths: + paths.append(selection) + listbox.insert("end", selection) + + def remove_path() -> None: + selection = listbox.curselection() + if not selection: + return + index = selection[0] + listbox.delete(index) + paths.pop(index) + + ttk.Button(button_frame, text="Add…", command=add_path).pack(side="left") + ttk.Button(button_frame, text="Remove", command=remove_path).pack(side="left", padx=(8, 0)) + + action_frame = ttk.Frame(dialog) + action_frame.pack(fill="x", padx=12, pady=(0, 12)) + + def on_save() -> None: + normalized = [str(Path(p).expanduser()) for p in paths] + set_local_model_paths(normalized) + dialog.grab_release() + dialog.destroy() + if self.provider_var.get() == LocalEngineProvider.name: + self.fetch_models_async() + + def on_cancel() -> None: + dialog.grab_release() + dialog.destroy() + + dialog.protocol("WM_DELETE_WINDOW", on_cancel) + + ttk.Button(action_frame, text="Save", command=on_save).pack(side="right", padx=(8, 0)) + ttk.Button(action_frame, text="Cancel", command=on_cancel).pack(side="right") + + def open_latest_report(self) -> None: + if not RESULTS_DIR.exists(): + messagebox.showinfo("No Reports", "The results directory does not exist yet.") + return + + reports = list(RESULTS_DIR.glob("*.md")) + if not reports: + messagebox.showinfo("No Reports", "No markdown reports found yet.") + return + + latest_report = max(reports, key=lambda p: p.stat().st_mtime) + open_path(latest_report) + self._append_log(f"Opened latest report: {latest_report.name}") + + +if __name__ == "__main__": + app = App() + app.mainloop() diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..3f3833a --- /dev/null +++ b/requirements.txt @@ -0,0 +1,3 @@ +requests>=2.31.0 +llama-cpp-python>=0.2.82 +mlx-lm>=0.10.0; platform_system == "Darwin" diff --git a/results/.DS_Store b/results/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..2dcc35e8a619c86ab145141609d4b32850f0125e GIT binary patch literal 6148 zcmeHKK~BR!475v;g1F?!aX-*Qe~?x|oH+FZC=G%`(v3jCb-w}+;2V64@!G0d1ysZV z39u`Bb{%`SnXT3}5%Kb&ofDNrR6qqMComs~JQp3w#5~79&THJ!hGw*&0Uwv&z<``x zNtYC~P43gS(sgY90ICAHcy4`dHUZ7aOc!ybRAzuNQBN zuk6*w_FH+w?dUsVI~Qlb8E^*v3j=bULyA*Hx6Xhw;0$aTkozG(1uMg(n6D0)+yVfn zaA(0-dI`x1hLvGb#1jZ>Do|6|S`5~7_=Ck&hDlM=iLLoy+nKFH;k-N64>_E;QgrJK zI0O3(9O<-_`hWg;|G%H)GiSgV_)`qhNU4zkrj(*OVf literal 0 HcmV?d00001 diff --git a/results/Modern-Apple-Dev/automated_report_DeepSeek-Coder-V2-Lite-Instruct-IQ2_XS.md b/results/Modern-Apple-Dev/automated_report_DeepSeek-Coder-V2-Lite-Instruct-IQ2_XS.md new file mode 100644 index 0000000..6045981 --- /dev/null +++ b/results/Modern-Apple-Dev/automated_report_DeepSeek-Coder-V2-Lite-Instruct-IQ2_XS.md @@ -0,0 +1,304 @@ +# Automated Diagnostic Report: DeepSeek-Coder-V2-Lite-Instruct-IQ2_XS + +--- + +## Performance Summary + + +* **Average Tokens/s:** TBD +* **Average Time to First Token:** TBD +* **Total Tokens Generated:** TBD + + +## Qualitative Analysis + +*(Manual grading and analysis of the responses is required to determine the final letter grade.)* + +--- + +## Test 1: Write a Swift function that solves the FizzBuzz problem. + +*Source:* `test1.txt` + +### Prompt: +```swift +Write a Swift function that solves the FizzBuzz problem. + +The function must have the exact signature: +`func generateFizzBuzz(upTo max: Int) -> [String]` + +It must not print directly to the console. Instead, it should return an array of strings. + +Rules: +1. For numbers divisible by 3, the string should be "Fizz". +2. For numbers divisible by 5, the string should be "Buzz". +3. For numbers divisible by both 3 and 5, the string should be "FizzBuzz". +4. Otherwise, it should be the number itself as a string. + +Include a complete documentation comment (`///`) explaining what the function does, its parameters, and what it returns. +``` + +### Response: + +```swift +/// Generates an array of strings representing the FizzBuzz sequence up to the specified number. +/// +/// - Parameter upTo: The maximum number to check. +/// - Returns: An array of strings representing the FizzBuzz sequence. +func generateFizzBuzz(upTo max: Int) -> [String] { + var result: [String] = [] + for i in 1...max { + if i % 3 == 0 { + if i % 5 == 0 { + result.append("FizzBuzz") + } else { + result.append("Fizz") + } + } else if i % 5 == 0 { + result.append("Buzz") + } else { + result.append(String(i)) + } + } + return result +} +``` + +This Swift function takes an integer `max` as input and returns an array of strings representing the FizzBuzz sequence up to that number. The function iterates through numbers from 1 to `max` and checks the conditions for divisibility by 3 and 5, appending the appropriate string to the result array. + +### Performance Metrics: +* **Tokens/s:** 38.03 +* **Total Tokens:** 436 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 2: Create a complete SwiftUI view for a user profile card. + +*Source:* `test2.txt` + +### Prompt: +```swift +Create a complete SwiftUI view for a user profile card. + +The view should be named `UserProfileCard` and be initialized with a simple `User` struct containing `name: String`, `handle: String`, and `avatarURL: URL`. + +Requirements: +- Use an `AsyncImage` to load the user's avatar from the URL. +- Display the user's name in a `.headline` font and their handle (e.g., "@username") in a `.subheadline` font with a secondary color. +- Include a "Follow" button that uses the "person.badge.plus" SF Symbol. +- Arrange the elements cleanly inside an HStack with appropriate spacing. +- The entire card should have a subtle shadow and rounded corners. +``` + +### Response: + +To create a SwiftUI view for a user profile card using SwiftUI, you can follow the steps below. This example assumes you have a basic understanding of SwiftUI and Swift. You can create a new SwiftUI project and paste the following code into yourContentView.swift file: + +```swift +import SwiftUI + +struct User { + var name: String + var handle: String + var avatarURL: URL? +} + +struct UserProfileCardView: View { + var user: User + + var body: some View { + VStack(alignment: .leading, spacing: 15) { + AsyncImage(url: user.avatarURL) { image in + image + .resizable() + .scaledToFit() + .clipShape(Circle()) + } placeholder: { + Circle() + .scaledToFit() + .clipShape(Circle()) + } + Text(user.name) + .font(.headline) + Text(user.handle) + .font(.subheadline) + Button(action: { + // Action to follow the user + }) { + HStack { + Image(systemName: "person.badge.plus") + Text("Follow") + } + } + } + .padding() + .background(.white) + .cornerRadius(10) + .shadow(radius: 5) + .padding() + } +} + +struct ContentView: View { + var user: User = User(name: "John Doe", handle: "@johndoe", avatarURL: URL(string: "https://example.com/avatar.png")) + + var body: some View { + UserProfileCardView(user: user) + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} +``` + +This code defines a `ContentView` that includes a `UserProfileCardView` which displays the user's name, handle, and avatar URL. The `AsyncImage` is used to load the image asynchronously. The `UserProfileCardView` is a SwiftUI view that takes a `User` object as a parameter. + +Here's a more detailed breakdown of the code: + +1. **Struct Definition**: The `UserProfileCardView` struct is defined to encapsulate the user's name, handle, and avatar URL. +2. **AsyncImage**: This is a custom view that loads the image asynchronously using `AsyncImage`. +3. **View Initialization**: The `UserProfileCardView` is initialized with a `User` object. +4. **Styling**: The view is styled using `VStack`, `Text`, and `Button` to display the user's name, handle, and avatar URL. +5. **Shadow and Corner Radius**: The card styling is achieved using `shadow` and `cornerRadius`. + +This code provides a basic implementation of a user profile card using SwiftUI. You can further customize the design and functionality based on your specific requirements. + +### Performance Metrics: +* **Tokens/s:** 37.75 +* **Total Tokens:** 855 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 3: I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +*Source:* `test3.txt` + +### Prompt: +```swift +I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +The new function should be marked with `async throws` and return a `[Post]` object upon success. Also, include an example of how to call this new async function inside a `Task` with a `do-catch` block. + +**Old Code:** +struct Post: Codable { + let id: Int + let title: String +} + +func fetchPosts(completion: @escaping (Result<[Post], Error>) -> Void) { + guard let url = URL(string: "https://api.example.com/posts") else { return } + URLSession.shared.dataTask(with: url) { data, _, error in + if let error = error { completion(.failure(error)); return } + guard let data = data else { return } + do { + let posts = try JSONDecoder().decode([Post].self, from: data) + completion(.success(posts)) + } catch { + completion(.failure(error)) + } + }.resume() +} +``` + +### Response: + +To refactor the given networking code to use modern Swift Concurrency with async/await, you can use the `URLSession.shared.dataTask(with: URLSession.shared.dataTaskPublisher(for: URLRequest(url: url)))` method to fetch data asynchronously. Here's how you can refactor the code to use async/await and handle errors properly using `do-catch` blocks: + +```swift +import Foundation + +struct Post: Codable { + let id: Int + let title: String +} + +func fetchPosts() async throws -> [Post] { + guard let url = URL(string: "https://api.example.com/posts") else { + throw URLError.invalidURL + } + + do { + let (data, response) = try await URLSession.shared.dataTaskPublisher(for: URLRequest(url: url)) + guard let data = data else { + throw URLError.invalidResponse + } + let posts = try JSONDecoder().decode([Post].self, from: data) + return posts + } catch { + throw error + } +} + +// Example usage: +func exampleUsage() { + do { + let posts = try await fetchPosts() + print(posts) + } catch { + print(error) + } +} +``` + +Here's the refactored code: + +```swift +import Foundation + +struct Post: Codable { + let id: Int + let title: String +} + +func fetchPosts() async throws -> [Post] { + guard let url = URL(string: "https://api.example.com/posts") else { + throw URLError.invalidURL + } + + do { + let (data, response) = try await URLSession.shared.dataTask(with: URLRequest(url: url)) + guard let data = data else { + throw URLError.invalidResponse + } + let posts = try JSONDecoder().decode([Post].self, from: data) + return posts + } catch { + throw error + } +} + +// Example usage: +func exampleUsage() { + Task { + do { + let posts = try await fetchPosts() + print(posts) + } catch { + print(error) + } + } +} +``` + +In this refactored code: +- The function `fetchPosts` is marked with `async` and uses `URLSession` to fetch data asynchronously. +- The function handles errors using `do-catch` blocks to catch any errors that occur during the asynchronous task. +- The function returns a list of `Post` objects upon success. + +Note: This code assumes that you have a URLSession setup for network operations. You might need to adjust the code to fit your actual implementation of URLSession. + +### Performance Metrics: +* **Tokens/s:** 36.19 +* **Total Tokens:** 911 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + diff --git a/results/Modern-Apple-Dev/automated_report_Qwen3-Coder-30B-A3B-Instruct-Q3_K_L.md b/results/Modern-Apple-Dev/automated_report_Qwen3-Coder-30B-A3B-Instruct-Q3_K_L.md new file mode 100644 index 0000000..fd51bbb --- /dev/null +++ b/results/Modern-Apple-Dev/automated_report_Qwen3-Coder-30B-A3B-Instruct-Q3_K_L.md @@ -0,0 +1,1382 @@ +# Automated Diagnostic Report: Qwen3-Coder-30B-A3B-Instruct-Q3_K_L + +--- + +## Performance Summary + + +* **Average Tokens/s:** 19.25 +* **Average Time to First Token:** 0.0s +* **Total Tokens Generated:** 8830 + + +## Qualitative Analysis + +*(Manual grading and analysis of the responses is required to determine the final letter grade.)* + +--- + +## Test 1: Write a Swift function that solves the FizzBuzz problem. + +*Source:* `test1.txt` + +### Prompt: +```swift +Write a Swift function that solves the FizzBuzz problem. + +The function must have the exact signature: +`func generateFizzBuzz(upTo max: Int) -> [String]` + +It must not print directly to the console. Instead, it should return an array of strings. + +Rules: +1. For numbers divisible by 3, the string should be "Fizz". +2. For numbers divisible by 5, the string should be "Buzz". +3. For numbers divisible by both 3 and 5, the string should be "FizzBuzz". +4. Otherwise, it should be the number itself as a string. + +Include a complete documentation comment (`///`) explaining what the function does, its parameters, and what it returns. +``` + +### Response: + +```swift +/// Generates a FizzBuzz sequence up to a specified maximum number. +/// +/// This function implements the classic FizzBuzz problem where: +/// - Numbers divisible by 3 are replaced with "Fizz" +/// - Numbers divisible by 5 are replaced with "Buzz" +/// - Numbers divisible by both 3 and 5 are replaced with "FizzBuzz" +/// - All other numbers are converted to their string representation +/// +/// - Parameter max: The upper limit (inclusive) for generating the FizzBuzz sequence +/// - Returns: An array of strings representing the FizzBuzz sequence from 1 to max +/// +/// - Example: +/// ``` +/// let result = generateFizzBuzz(upTo: 5) +/// // Returns: ["1", "2", "Fizz", "4", "Buzz"] +/// ``` +func generateFizzBuzz(upTo max: Int) -> [String] { + var result: [String] = [] + + for number in 1...max { + switch (number % 3, number % 5) { + case (0, 0): + result.append("FizzBuzz") + case (0, _): + result.append("Fizz") + case (_, 0): + result.append("Buzz") + default: + result.append(String(number)) + } + } + + return result +} +``` + +### Performance Metrics: +* **Tokens/s:** 24.51 +* **Total Tokens:** 434 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 2: Create a complete SwiftUI view for a user profile card. + +*Source:* `test2.txt` + +### Prompt: +```swift +Create a complete SwiftUI view for a user profile card. + +The view should be named `UserProfileCard` and be initialized with a simple `User` struct containing `name: String`, `handle: String`, and `avatarURL: URL`. + +Requirements: +- Use an `AsyncImage` to load the user's avatar from the URL. +- Display the user's name in a `.headline` font and their handle (e.g., "@username") in a `.subheadline` font with a secondary color. +- Include a "Follow" button that uses the "person.badge.plus" SF Symbol. +- Arrange the elements cleanly inside an HStack with appropriate spacing. +- The entire card should have a subtle shadow and rounded corners. +``` + +### Response: + +```swift +import SwiftUI + +struct User: Identifiable { + let id = UUID() + let name: String + let handle: String + let avatarURL: URL +} + +struct UserProfileCard: View { + let user: User + + var body: some View { + HStack { + AsyncImage(url: user.avatarURL) { image in + image + .resizable() + .scaledToFit() + } placeholder: { + Rectangle() + .fill(Color.gray.opacity(0.3)) + .frame(width: 60, height: 60) + .cornerRadius(30) + } + .frame(width: 60, height: 60) + .cornerRadius(30) + + VStack(alignment: .leading, spacing: 4) { + Text(user.name) + .font(.headline) + + Text(user.handle) + .font(.subheadline) + .foregroundColor(.secondary) + } + + Spacer() + + Button(action: { + // Follow action + }) { + Image(systemName: "person.badge.plus") + .foregroundColor(.blue) + } + .buttonStyle(.borderedProminent) + .tint(.blue) + } + .padding() + .background(Color.white) + .cornerRadius(12) + .shadow(radius: 4) + } +} + +struct UserProfileCard_Previews: PreviewProvider { + static let mockUser = User( + name: "John Doe", + handle: "@johndoe", + avatarURL: URL(string: "https://via.placeholder.com/150")! + ) + + static var previews: some View { + UserProfileCard(user: mockUser) + .previewLayout(.sizeThatFits) + } +} +``` + +This SwiftUI view creates a clean, modern user profile card with the following features: + +1. **User Struct**: Simple struct with name, handle, and avatarURL properties +2. **AsyncImage**: Loads the user's avatar from the provided URL with proper error handling +3. **Name Display**: Shows user's name in headline font +4. **Handle Display**: Shows handle in subheadline with secondary color +5. **Follow Button**: Uses "person.badge.plus" SF Symbol with blue tint +6. **Layout**: Clean HStack arrangement with appropriate spacing +7. **Styling**: + - Rounded corners (12pt radius) + - Subtle shadow (4pt radius) + - White background + - Proper padding + +The preview includes a mock user for testing purposes. The button has a bordered prominent style that matches iOS design guidelines, and the entire card has a clean, modern appearance with proper visual hierarchy. + +### Performance Metrics: +* **Tokens/s:** 24.89 +* **Total Tokens:** 716 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 3: I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +*Source:* `test3.txt` + +### Prompt: +```swift +I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +The new function should be marked with `async throws` and return a `[Post]` object upon success. Also, include an example of how to call this new async function inside a `Task` with a `do-catch` block. + +**Old Code:** +struct Post: Codable { + let id: Int + let title: String +} + +func fetchPosts(completion: @escaping (Result<[Post], Error>) -> Void) { + guard let url = URL(string: "https://api.example.com/posts") else { return } + URLSession.shared.dataTask(with: url) { data, _, error in + if let error = error { completion(.failure(error)); return } + guard let data = data else { return } + do { + let posts = try JSONDecoder().decode([Post].self, from: data) + completion(.success(posts)) + } catch { + completion(.failure(error)) + } + }.resume() +} +``` + +### Response: + +Here's the refactored code using modern Swift Concurrency with async/await: + +```swift +import Foundation + +struct Post: Codable { + let id: Int + let title: String +} + +// New async throws function +func fetchPosts() async throws -> [Post] { + guard let url = URL(string: "https://api.example.com/posts") else { + throw URLError(.badURL) + } + + let (data, response) = try await URLSession.shared.data(from: url) + + guard let httpResponse = response as? HTTPURLResponse, + (200...299).contains(httpResponse.statusCode) else { + throw URLError(.badServerResponse) + } + + return try JSONDecoder().decode([Post].self, from: data) +} + +// Example of how to call the new async function inside a Task +func exampleUsage() { + Task { + do { + let posts = try await fetchPosts() + print("Successfully fetched \(posts.count) posts") + // Process posts here + for post in posts { + print("Post: \(post.title)") + } + } catch { + print("Error fetching posts: \(error)") + // Handle the error appropriately + } + } +} + +// Alternative example with more detailed error handling +func exampleUsageWithDetailedHandling() { + Task { + do { + let posts = try await fetchPosts() + print("Successfully fetched \(posts.count) posts") + + // Process the posts + posts.forEach { post in + print("ID: \(post.id), Title: \(post.title)") + } + + } catch let urLError as URLError { + switch urLError.code { + case .badURL: + print("Invalid URL") + case .badServerResponse: + print("Server returned invalid response") + default: + print("Network error: \(urLError.localizedDescription)") + } + } catch { + print("Unexpected error: \(error)") + } + } +} +``` + +Key improvements in the refactored code: + +1. **Async/Await Signature**: The function is now `async throws -> [Post]` instead of using completion handlers +2. **Simplified Error Handling**: Uses `try await` with proper error propagation +3. **Better HTTP Response Validation**: Checks for valid HTTP response codes +4. **Cleaner Code Flow**: Eliminates callback nesting and error handling complexity +5. **Modern Swift Concurrency**: Uses `Task` for concurrent execution + +The `exampleUsage()` function shows how to call the async function inside a `Task` with proper `do-catch` error handling, which is the recommended pattern when working with async functions in Swift. + +### Performance Metrics: +* **Tokens/s:** 23.76 +* **Total Tokens:** 782 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 4: Create a complete SwiftData example for a macOS 26 app. + +*Source:* `test4.txt` + +### Prompt: +```swift +Create a complete SwiftData example for a macOS 26 app. + +You must define two models: `Author` and `Book`. An `Author` can have many `Book`s (a one-to-many relationship). + +Then, create a SwiftUI view that displays a list of all authors. When an author's name is tapped, it should navigate to a detail view that shows a list of all the books written by that specific author. Use a SwiftData `@Query` to fetch the data. +``` + +### Response: + +Here's a complete SwiftData example for macOS 26 that implements the requested functionality: + +```swift +// MARK: - Models + +import SwiftData +import Foundation + +@Model +final class Author { + var name: String + var birthYear: Int? + + @Relationship(inverse: \Book.author) + var books: [Book] + + init(name: String, birthYear: Int? = nil) { + self.name = name + self.birthYear = birthYear + self.books = [] + } +} + +@Model +final class Book { + var title: String + var publicationYear: Int? + var isbn: String? + + @Relationship(inverse: \Author.books) + var author: Author? + + init(title: String, publicationYear: Int? = nil, isbn: String? = nil) { + self.title = title + self.publicationYear = publicationYear + self.isbn = isbn + } +} + +// MARK: - Data Setup + +import SwiftUI + +@main +struct BookLibraryApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + .modelContainer(for: [Author.self, Book.self]) + } +} + +// MARK: - Views + +struct ContentView: View { + @Query(sort: \Author.name) + var authors: [Author] + + var body: some View { + NavigationStack { + List(authors, id: \.self) { author in + NavigationLink(destination: AuthorDetailView(author: author)) { + Text(author.name) + } + } + .navigationTitle("Authors") + .toolbar { + ToolbarItem(placement: .primaryAction) { + Button("Add Author") { + // In a real app, you'd add logic to create new authors + } + } + } + } + } +} + +struct AuthorDetailView: View { + let author: Author + + @Query(sort: \Book.title) + var books: [Book] + + init(author: Author) { + self.author = author + // Set up the predicate to filter books by the specific author + _books = Query(filter: #Predicate { book in + book.author?.id == author.id + }, sort: \Book.title) + } + + var body: some View { + VStack { + Text("Books by \(author.name)") + .font(.title2) + .padding() + + if books.isEmpty { + Text("No books available") + .italic() + .foregroundColor(.secondary) + } else { + List(books, id: \.self) { book in + VStack(alignment: .leading) { + Text(book.title) + .font(.headline) + if let year = book.publicationYear { + Text("Published: \(year)") + .font(.caption) + .foregroundColor(.secondary) + } + } + .padding(.vertical, 2) + } + } + } + .navigationTitle(author.name) + } +} + +// MARK: - Preview + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + .environment(\.modelContext, try! ModelContainer(for: Author.self, Book.self).mainContext) + } +} +``` + +Key features of this implementation: + +1. **Models**: + - `Author` model with name and birthYear properties + - `Book` model with title, publicationYear, and isbn properties + - One-to-many relationship between Author and Book using `@Relationship` + +2. **Data Setup**: + - Uses `@main` App with `ModelContainer` for SwiftData + - Both models are registered in the model container + +3. **ContentView**: + - Displays a list of all authors using `@Query(sort: \Author.name)` + - Each author name is a NavigationLink to the detail view + - Uses a toolbar with an "Add Author" button + +4. **AuthorDetailView**: + - Shows books for a specific author + - Uses a custom `@Query` with a predicate to filter books by author + - Displays book titles and publication years + - Shows a "No books available" message when appropriate + +5. **Navigation**: + - From ContentView to AuthorDetailView + - Shows author name as navigation title + - Displays books in a clean list format + +To use this in your macOS 26 app: + +1. Create a new macOS project with SwiftData +2. Replace the default `App.swift` with this code +3. Add the models to your project +4. The app will automatically create the database and populate it with sample data + +The implementation handles: +- One-to-many relationship between Author and Book +- Proper data fetching with `@Query` +- Navigation between views +- Sorting of data +- Filtering by author in the detail view +- Clean SwiftUI views with proper styling + +Note: You'll need to add some sample data to see the full functionality. You can do this by adding a button in the toolbar that creates sample authors and books, or by using the Xcode preview to see the structure. + +### Performance Metrics: +* **Tokens/s:** 23.76 +* **Total Tokens:** 1174 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 5: Write a thread-safe counter class in Swift using an `actor`. + +*Source:* `test5.txt` + +### Prompt: +```swift +Write a thread-safe counter class in Swift using an `actor`. + +The actor should be named `SafeCounter`. It must have a private property to hold the current count and two public methods: +1. `func increment() async` +2. `func getCount() async -> Int` + +Also, provide a simple example of how to create an instance of the actor and call its methods concurrently from two different `Task`s. +``` + +### Response: + +Here's a thread-safe counter class in Swift using an actor: + +```swift +import Foundation + +// Thread-safe counter actor +actor SafeCounter { + private var count: Int = 0 + + // Increment the counter + func increment() async { + count += 1 + } + + // Get the current count + func getCount() async -> Int { + return count + } +} + +// Example usage +func demonstrateSafeCounter() async { + // Create an instance of the SafeCounter actor + let counter = SafeCounter() + + // Create two concurrent tasks that increment the counter + let task1 = Task { + for _ in 0..<1000 { + await counter.increment() + } + print("Task 1 completed") + } + + let task2 = Task { + for _ in 0..<1000 { + await counter.increment() + } + print("Task 2 completed") + } + + // Wait for both tasks to complete + await task1.value + await task2.value + + // Get the final count + let finalCount = await counter.getCount() + print("Final count: \(finalCount)") + + // Verify that the count is correct (should be 2000) + print("Expected count: 2000") + print("Actual count: \(finalCount)") + print("Count is correct: \(finalCount == 2000)") +} + +// Run the example +Task { + await demonstrateSafeCounter() +} +``` + +**Key features of this implementation:** + +1. **Actor Declaration**: The `SafeCounter` actor ensures thread safety by making all its methods atomic and preventing concurrent access to its internal state. + +2. **Private State**: The `count` variable is private, so it can only be accessed through the actor's methods, ensuring encapsulation. + +3. **Thread-Safe Methods**: + - `increment()` safely increments the counter + - `getCount()` safely returns the current count + +4. **Concurrency Example**: The example demonstrates: + - Creating two concurrent tasks that both increment the counter 1000 times + - Using `await` to call the actor methods from within tasks + - Waiting for both tasks to complete before checking the final result + +5. **Verification**: The example shows that even with concurrent access from multiple tasks, the counter maintains the correct final value (2000 in this case). + +The actor model in Swift ensures that only one task can access the actor's methods at a time, making the counter completely thread-safe without requiring explicit locking mechanisms. + +### Performance Metrics: +* **Tokens/s:** 24.14 +* **Total Tokens:** 630 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 6: Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +*Source:* `test6.txt` + +### Prompt: +```swift +Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +The code must include: +1. A `TimelineProvider` to generate the timeline entries. +2. A `TimelineEntry` struct. +3. The main `Widget` struct. +4. A SwiftUI view for the complication's appearance. + +Ensure the code correctly uses the modern WidgetKit framework. +``` + +### Response: + +Here's a complete implementation of a watchOS 26 complication that displays the current date in the `.accessoryRectangular` family: + +```swift +import WidgetKit +import SwiftUI + +// MARK: - Timeline Entry +struct DateComplicationEntry: TimelineEntry { + let date: Date +} + +// MARK: - Timeline Provider +struct DateComplicationProvider: TimelineProvider { + func placeholder(in context: Context) -> DateComplicationEntry { + DateComplicationEntry(date: Date()) + } + + func getSnapshot(in context: Context, completion: @escaping (DateComplicationEntry) -> Void) { + let entry = DateComplicationEntry(date: Date()) + completion(entry) + } + + func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { + let entry = DateComplicationEntry(date: Date()) + let nextUpdate = Calendar.current.date(byAdding: .minute, value: 1, to: Date())! + let timeline = Timeline(entries: [entry], policy: .after(nextUpdate)) + completion(timeline) + } +} + +// MARK: - Widget Entry View +struct DateComplicationEntryView: View { + var entry: DateComplicationProvider.Entry + + var body: some View { + VStack { + Text("\(Calendar.current.component(.day, from: entry.date))") + .font(.system(size: 24, weight: .bold)) + .foregroundColor(.primary) + + Text("\(Calendar.current.component(.month, from: entry.date))") + .font(.system(size: 16)) + .foregroundColor(.secondary) + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .widgetBackground(.fill(Color.black)) + } +} + +// MARK: - Main Widget +@main +struct DateComplicationWidget: Widget { + let kind: String = "DateComplication" + + var body: some WidgetConfiguration { + StaticConfiguration(kind: kind, provider: DateComplicationProvider()) { entry in + DateComplicationEntryView(entry: entry) + } + .configurationDisplayName("Date Complication") + .description("Displays the current date") + .supportedFamilies([.accessoryRectangular]) + } +} + +// MARK: - Preview +struct DateComplicationWidget_Previews: PreviewProvider { + static var previews: some View { + DateComplicationEntryView(entry: DateComplicationEntry(date: Date())) + .previewContext(WidgetPreviewContext(family: .accessoryRectangular)) + } +} +``` + +This implementation includes: + +1. **TimelineProvider** (`DateComplicationProvider`) that: + - Provides placeholder, snapshot, and timeline data + - Updates every minute to keep the date current + - Uses the modern WidgetKit timeline system + +2. **TimelineEntry** (`DateComplicationEntry`) that: + - Contains a single `date` property + - Implements the required `TimelineEntry` protocol + +3. **Main Widget** (`DateComplicationWidget`) that: + - Configures the widget with the correct family + - Uses `StaticConfiguration` for simplicity + - Sets appropriate display names and descriptions + +4. **SwiftUI View** (`DateComplicationEntryView`) that: + - Displays day and month in a rectangular format + - Uses appropriate fonts and colors + - Applies black background for watchOS styling + - Uses `.accessoryRectangular` family constraints + +The complication updates every minute to show the current date, displays the day as a large number and month as a smaller label, and is specifically designed for the rectangular watch face area. The preview shows how it would appear in the watchOS widget configuration. + +### Performance Metrics: +* **Tokens/s:** 17.91 +* **Total Tokens:** 862 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 7: Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +*Source:* `test7.txt` + +### Prompt: +```swift +Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +**Old Code:** +class UserSettings: ObservableObject { + @Published var score: Int = 0 + @Published var username: String = "Guest" +} + +struct SettingsView: View { + @StateObject private var settings = UserSettings() + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +### Response: + +Here's the refactored code using the modern `@Observable` macro: + +```swift +import SwiftUI + +@Observable +class UserSettings { + var score: Int = 0 + var username: String = "Guest" +} + +struct SettingsView: View { + @State private var settings = UserSettings() + + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +Key changes made: + +1. **Removed `ObservableObject` protocol** - Replaced with `@Observable` macro +2. **Removed `@Published` property wrappers** - Properties are now directly observable +3. **Simplified `@StateObject` to `@State`** - Since we're using `@Observable`, we can use `@State` instead +4. **Cleaner class definition** - No more `@Published` annotations needed + +The `@Observable` macro automatically makes all stored properties observable, so you don't need to explicitly mark them with `@Published`. The view will automatically update when any of the properties change, making the code much simpler and more concise. + +### Performance Metrics: +* **Tokens/s:** 14.79 +* **Total Tokens:** 408 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 8: Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. + +*Source:* `test8.txt` + +### Prompt: +```swift +Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. +``` + +### Response: + +Here's a complete implementation of a configurable WidgetKit widget using the modern App Intents framework for iOS 26: + +```swift +// MARK: - Widget Extension + +import WidgetKit +import SwiftUI +import AppIntents + +// MARK: - Widget Entry + +struct NoteWidgetEntry: TimelineEntry { + let date: Date + let note: String +} + +// MARK: - Widget Provider + +struct NoteWidgetProvider: TimelineProvider { + func placeholder(in context: Context) -> NoteWidgetEntry { + NoteWidgetEntry(date: Date(), note: "Sample Note") + } + + func getSnapshot(in context: Context, completion: @escaping (NoteWidgetEntry) -> Void) { + let entry = NoteWidgetEntry(date: Date(), note: "Sample Note") + completion(entry) + } + + func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { + let entry = NoteWidgetEntry(date: Date(), note: "Sample Note") + let nextUpdate = Calendar.current.date(byAdding: .minute, value: 1, to: Date())! + let timeline = Timeline(entries: [entry], policy: .after(nextUpdate)) + completion(timeline) + } +} + +// MARK: - Widget View + +struct NoteWidgetView: View { + var entry: NoteWidgetProvider.Entry + + var body: some View { + VStack { + Text(entry.note) + .font(.headline) + .multilineTextAlignment(.center) + .padding() + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(Color(.systemBackground)) + } +} + +// MARK: - Widget Bundle + +@main +struct NoteWidget: Widget { + let kind: String = "NoteWidget" + + var body: some WidgetConfiguration { + AppIntentConfiguration( + kind: kind, + intent: NoteConfigurationIntent.self, + provider: NoteWidgetProvider() + ) { entry in + NoteWidgetView(entry: entry) + } + .displayName("Note Widget") + .description("Displays a configurable note") + .supportedFamilies([.systemSmall, .systemMedium]) + } +} + +// MARK: - Configuration Intent + +struct NoteConfigurationIntent: AppIntent { + static let title: LocalizedStringResource = "Configure Note" + static let description = IntentDescription("Set the note text for the widget") + + @Parameter(title: "Note", description: "The note to display", default: "Hello World") + var note: String + + init() { + self.note = "Hello World" + } + + func perform() async throws -> some IntentResult { + return .result() + } +} + +// MARK: - Preview Provider + +struct NoteWidget_Previews: PreviewProvider { + static var previews: some View { + NoteWidgetView(entry: NoteWidgetEntry(date: Date(), note: "Sample Note")) + .previewContext(WidgetPreviewContext(family: .systemSmall)) + } +} +``` + +Key features of this implementation: + +1. **Modern App Intents Framework**: + - Uses `AppIntentConfiguration` instead of legacy `IntentConfiguration` + - Implements `NoteConfigurationIntent` with `@Parameter` for note text + - Uses `IntentDescription` for user-friendly descriptions + +2. **Configuration Features**: + - Direct text editing in widget configuration + - Default value set to "Hello World" + - Proper intent title and description + +3. **Widget Implementation**: + - Displays note text in a clean, centered view + - Uses system background color for proper appearance + - Supports small and medium widget sizes + +4. **Timeline Management**: + - Provides placeholder and snapshot entries + - Updates every minute for freshness + - Uses system-provided date for timeline entries + +5. **Preview Support**: + - Includes preview provider for testing + - Shows widget in small system size + +To use this widget: +1. Add it to your iOS app's widget extension target +2. Configure the note text directly in the widget configuration screen +3. The note will display in the widget with the configured text + +The configuration is handled entirely through the modern App Intents framework with no legacy `INIntent` usage. The note text is passed through the intent system and displayed in the widget view. + +### Performance Metrics: +* **Tokens/s:** 14.84 +* **Total Tokens:** 967 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 9: Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +*Source:* `test9.txt` + +### Prompt: +```swift +Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +The view must: +1. Have a button labeled "Enter Immersive Space". +2. Use the `@Environment(\.openImmersiveSpace)` and `@Environment(\.dismissImmersiveSpace)` variables. +3. Be able to open an immersive space with the ID "MyImmersiveScene". +4. Include a second button inside the immersive space to dismiss it. +``` + +### Response: + +Here's a complete SwiftUI view for visionOS 26 that creates an immersive space when the button is tapped: + +```swift +import SwiftUI + +struct ContentView: View { + @Environment(\.openImmersiveSpace) var openImmersiveSpace + @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace + + var body: some View { + VStack(spacing: 20) { + Text("Welcome to Immersive Space") + .font(.largeTitle) + .fontWeight(.bold) + + Text("Tap the button below to enter a fully immersive 3D environment") + .multilineTextAlignment(.center) + .padding(.horizontal) + + Button("Enter Immersive Space") { + openImmersiveSpace(id: "MyImmersiveScene") + } + .buttonStyle(.borderedProminent) + .controlSize(.large) + } + .padding() + } +} + +struct MyImmersiveScene: View { + @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace + + var body: some View { + ZStack { + // Create a visually immersive background + Sphere() + .fill( + AngularGradient( + gradient: Gradient(colors: [.blue, .purple, .pink, .red, .orange, .yellow, .green, .blue]), + center: .center + ) + ) + .scaleEffect(2.0) + .opacity(0.8) + + // Add floating 3D elements + ForEach(0..<20) { index in + Sphere() + .fill(Color.white.opacity(0.2)) + .scaleEffect(0.1) + .position( + x: CGFloat.random(in: -300...300), + y: CGFloat.random(in: -300...300) + ) + .rotation3DEffect( + Angle(degrees: Double(index * 18)), + axis: (x: 0, y: 1, z: 0) + ) + } + + // Center content + VStack(spacing: 30) { + Text("Immersive Space") + .font(.largeTitle) + .fontWeight(.bold) + .foregroundColor(.white) + .shadow(radius: 10) + + Text("You are now in a fully immersive 3D environment") + .foregroundColor(.white) + .multilineTextAlignment(.center) + .padding(.horizontal) + + Button("Exit Immersive Space") { + dismissImmersiveSpace() + } + .buttonStyle(.borderedProminent) + .controlSize(.large) + .tint(.white) + .foregroundColor(.black) + } + .padding() + .background(.ultraThinMaterial) + .cornerRadius(20) + .shadow(radius: 20) + } + .ignoresSafeArea() // Full screen immersion + } +} + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} + +// Preview for the immersive scene +struct MyImmersiveScene_Previews: PreviewProvider { + static var previews: some View { + MyImmersiveScene() + .previewDisplayName("Immersive Scene") + } +} +``` + +This implementation includes: + +1. **Main Content View**: + - A "Enter Immersive Space" button that opens the immersive space with ID "MyImmersiveScene" + - Clear instructions for the user + - Proper styling with large buttons and centered content + +2. **Immersive Scene**: + - A visually immersive background with a rotating gradient sphere + - Floating 3D elements that create a sense of depth + - A prominent "Exit Immersive Space" button that dismisses the immersive view + - Material design with blur effects for a modern look + - Full-screen immersion using `ignoresSafeArea()` + +3. **Key Features**: + - Uses `@Environment(\.openImmersiveSpace)` and `@Environment(\.dismissImmersiveSpace)` as required + - The immersive space ID is set to "MyImmersiveScene" + - The exit button is clearly visible and functional + - Works specifically for visionOS 26 with immersive space capabilities + - Clean, modern design that's appropriate for the 3D environment + +To use this in visionOS: +1. Create a new visionOS project +2. Replace the default ContentView with this code +3. Make sure your app delegate or scene delegate is configured to support immersive spaces +4. The immersive scene will be triggered when the user taps the "Enter Immersive Space" button + +The immersive scene features: +- A rotating gradient background +- Floating 3D spheres for depth perception +- A centered content area with clear exit instructions +- Material design with transparency effects +- Full-screen immersive experience that respects the safe area + +### Performance Metrics: +* **Tokens/s:** 11.16 +* **Total Tokens:** 1139 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 10: Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +*Source:* `test10.txt` + +### Prompt: +```swift +Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +This layout should arrange its subviews in a horizontal flow, starting a new row when the current row is full. It should behave similarly to a basic left-aligned flow layout in CSS. + +The implementation must conform to the `Layout` protocol and implement both the `sizeThatFits(...)` and `placeSubviews(...)` methods. +``` + +### Response: + +```swift +import SwiftUI + +struct SimpleFlowLayout: Layout { + let spacing: CGFloat + + init(spacing: CGFloat = 8) { + self.spacing = spacing + } + + func sizeThatFits( + proposal: ProposedViewSize, + subviews: Subviews, + cache: inout LayoutCache + ) -> CGSize { + guard !subviews.isEmpty else { return .zero } + + let maxWidth = proposal.width ?? .greatestFiniteMagnitude + var currentRowWidth: CGFloat = 0 + var currentRowHeight: CGFloat = 0 + var totalHeight: CGFloat = 0 + var rowSpacing: CGFloat = 0 + var rowWidths: [CGFloat] = [] + var rowHeights: [CGFloat] = [] + + // Calculate row dimensions + for i in 0.. maxWidth && !rowWidths.isEmpty { + // Store the current row + rowWidths.append(currentRowWidth) + rowHeights.append(currentRowHeight) + totalHeight += currentRowHeight + rowSpacing + + // Start a new row + currentRowWidth = 0 + currentRowHeight = 0 + rowSpacing = spacing + } + + // Add to current row + if currentRowWidth > 0 { + currentRowWidth += spacing + } + currentRowWidth += size.width + currentRowHeight = max(currentRowHeight, size.height) + } + + // Add the last row + rowWidths.append(currentRowWidth) + rowHeights.append(currentRowHeight) + totalHeight += currentRowHeight + + // Account for the last row's spacing + if !rowWidths.isEmpty { + totalHeight += spacing * CGFloat(rowWidths.count - 1) + } + + return CGSize( + width: min(maxWidth, rowWidths.max() ?? 0), + height: totalHeight + ) + } + + func placeSubviews( + in bounds: CGRect, + proposal: ProposedViewSize, + subviews: Subviews, + cache: inout LayoutCache + ) { + guard !subviews.isEmpty else { return } + + let maxWidth = bounds.width + var currentRowWidth: CGFloat = 0 + var currentRowHeight: CGFloat = 0 + var currentRowY: CGFloat = 0 + var rowSpacing: CGFloat = 0 + var rowStartX: CGFloat = 0 + var rowStartY: CGFloat = 0 + var currentX: CGFloat = 0 + var currentY: CGFloat = 0 + var rowWidths: [CGFloat] = [] + var rowHeights: [CGFloat] = [] + var rowStartXs: [CGFloat] = [] + var rowStartYs: [CGFloat] = [] + + // First pass: determine row positions + for i in 0.. maxWidth && !rowWidths.isEmpty { + // Store the current row + rowWidths.append(currentRowWidth) + rowHeights.append(currentRowHeight) + rowStartXs.append(rowStartX) + rowStartYs.append(rowStartY) + rowStartY += currentRowHeight + rowSpacing + + // Start a new row + currentRowWidth = 0 + currentRowHeight = 0 + rowSpacing = spacing + currentX = 0 + currentY = rowStartY + } + + // Add to current row + if currentRowWidth > 0 { + currentRowWidth += spacing + } + currentRowWidth += size.width + currentRowHeight = max(currentRowHeight, size.height) + } + + // Add the last row + rowWidths.append(currentRowWidth) + rowHeights.append(currentRowHeight) + rowStartXs.append(rowStartX) + rowStartYs.append(rowStartY) + + // Second pass: place subviews + var rowIdx = 0 + var currentRowIdx = 0 + var currentRowX: CGFloat = 0 + var currentRowY: CGFloat = 0 + + for i in 0.. 0 && i > 0 { + let prevSize = subviews[i-1].sizeThatFits(.unspecified) + let prevRowWidth = rowWidths[rowIdx] + + if currentRowX + prevSize.width + spacing > prevRowWidth { + // Start a new row + rowIdx += 1 + currentRowIdx = 0 + currentRowX = 0 + currentRowY = rowStartYs[rowIdx] + } + } + + // Place the subview + let x = bounds.minX + currentRowX + let y = bounds.minY + currentRowY + + subview.place( + at: CGPoint(x: x, y: y), + anchor: .topLeading, + size: size + ) + + // Update for next subview + if currentRowIdx > 0 { + currentRowX += spacing + } + currentRowX += size.width + currentRowIdx += 1 + } + } +} + +// Usage example +struct ContentView: View { + var body: some View { + SimpleFlowLayout(spacing: 10) + .padding(10) + .background(Color.gray.opacity(0.1)) + .overlay( + RoundedRectangle(cornerRadius: 8) + .stroke(Color.gray, lineWidth: 1) + ) { + // Add some sample views + ForEach(0..<15) { index in + Text("Item \(index)") + .padding(8) + .background(Color.blue.opacity(0.2)) + .cornerRadius(8) + } + } + } +} + +struct SimpleFlowLayout_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} +``` + +This implementation of `SimpleFlowLayout` provides a custom SwiftUI layout that arranges subviews in a horizontal flow, starting new rows when the current row is full. Here's what it does: + +## Key Features: + +1. **Horizontal Flow**: Subviews are arranged horizontally in rows +2. **Row Wrapping**: When a row is full (exceeds available width), a new row is started +3. **Left-Aligned**: Items are aligned to the left within each row +4. **Configurable Spacing**: Customizable spacing between items and rows + +## Implementation Details: + +### `sizeThatFits` Method: +- Calculates the total size needed for all subviews +- Determines row dimensions by tracking width and height +- Handles row wrapping logic based on available width + +### `placeSubviews` Method: +- Positions each subview within the available bounds +- Manages row positioning and spacing +- Handles the actual placement of each subview + +## Usage: +The layout can be used with any number of subviews and will automatically: +- Arrange items horizontally +- Wrap to new rows when needed +- Maintain consistent spacing +- Handle different item sizes + +The example shows how to use it with a collection of text items that will flow horizontally and wrap to new rows as needed. + +### Performance Metrics: +* **Tokens/s:** 12.7 +* **Total Tokens:** 1718 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + diff --git a/results/Modern-Apple-Dev/automated_report_Qwen3-Coder-30B-A3B-Instruct-UD-IQ2_XXS.md b/results/Modern-Apple-Dev/automated_report_Qwen3-Coder-30B-A3B-Instruct-UD-IQ2_XXS.md new file mode 100644 index 0000000..40fe0a4 --- /dev/null +++ b/results/Modern-Apple-Dev/automated_report_Qwen3-Coder-30B-A3B-Instruct-UD-IQ2_XXS.md @@ -0,0 +1,1468 @@ +# Automated Diagnostic Report: Qwen3-Coder-30B-A3B-Instruct-UD-IQ2_XXS + +--- + +## Performance Summary + + +* **Average Tokens/s:** 26.48 +* **Average Time to First Token:** 0.0s +* **Total Tokens Generated:** 9053 + + +## Qualitative Analysis + +*(Manual grading and analysis of the responses is required to determine the final letter grade.)* + +--- + +## Test 1: Write a Swift function that solves the FizzBuzz problem. + +*Source:* `test1.txt` + +### Prompt: +```swift +Write a Swift function that solves the FizzBuzz problem. + +The function must have the exact signature: +`func generateFizzBuzz(upTo max: Int) -> [String]` + +It must not print directly to the console. Instead, it should return an array of strings. + +Rules: +1. For numbers divisible by 3, the string should be "Fizz". +2. For numbers divisible by 5, the string should be "Buzz". +3. For numbers divisible by both 3 and 5, the string should be "FizzBuzz". +4. Otherwise, it should be the number itself as a string. + +Include a complete documentation comment (`///`) explaining what the function does, its parameters, and what it returns. +``` + +### Response: + +```swift +/// Generates a FizzBuzz sequence up to a specified maximum number. +/// +/// This function creates a sequence of strings following these rules: +/// - Numbers divisible by 3 are replaced with "Fizz" +/// - Numbers divisible by 5 are replaced with "Buzz" +/// - Numbers divisible by both 3 and 5 are replaced with "FizzBuzz" +/// - All other numbers are converted to their string representation +/// +/// - Parameter max: The maximum number (inclusive) to generate the sequence up to +/// - Returns: An array of strings representing the FizzBuzz sequence from 1 to max (inclusive) +/// +/// - Example: +/// ``` +/// generateFizzBuzz(upTo: 15) +/// // Returns: ["1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "FizzBuzz"] +/// ``` +func generateFizzBuzz(upTo max: Int) -> [String] { + var result: [String] = [] + + for number in 1...max { + if number % 15 == 0 { + result.append("FizzBuzz") + } else if number % 3 == 0 { + result.append("Fizz") + } else if number % 5 == 0 { + result.append("Buzz") + } else { + result.append(String(number)) + } + } + + return result +} +``` + +### Performance Metrics: +* **Tokens/s:** 26.98 +* **Total Tokens:** 467 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 2: Create a complete SwiftUI view for a user profile card. + +*Source:* `test2.txt` + +### Prompt: +```swift +Create a complete SwiftUI view for a user profile card. + +The view should be named `UserProfileCard` and be initialized with a simple `User` struct containing `name: String`, `handle: String`, and `avatarURL: URL`. + +Requirements: +- Use an `AsyncImage` to load the user's avatar from the URL. +- Display the user's name in a `.headline` font and their handle (e.g., "@username") in a `.subheadline` font with a secondary color. +- Include a "Follow" button that uses the "person.badge.plus" SF Symbol. +- Arrange the elements cleanly inside an HStack with appropriate spacing. +- The entire card should have a subtle shadow and rounded corners. +``` + +### Response: + +```swift +import SwiftUI + +struct User: Identifiable { + let id = UUID() + let name: String + let handle: String + let avatarURL: URL +} + +struct UserProfileCard: View { + let user: User + + var body: some View { + HStack(spacing: 16) { + AsyncImage(url: user.avatarURL) { image in + image + .resizable() + .aspectRatio(contentMode: .fill) + .frame(width: 60, height: 60) + .clipShape(Circle()) + } placeholder: { + Rectangle() + .fill(Color.gray.opacity(0.3)) + .frame(width: 60, height: 60) + .clipShape(Circle()) + } + + VStack(alignment: .leading, spacing: 4) { + Text(user.name) + .font(.headline) + .fontWeight(.semibold) + + Text(user.handle) + .font(.subheadline) + .foregroundColor(.secondary) + } + + Spacer() + + Button(action: { + // Follow action would be implemented here + }) { + HStack { + Image(systemName: "person.badge.plus") + Text("Follow") + } + .padding(.horizontal, 16) + .padding(.vertical, 8) + .background(Color.blue.opacity(0.1)) + .cornerRadius(8) + } + } + .padding() + .background(Color.white) + .cornerRadius(12) + .shadow(radius: 4) + } +} + +struct UserProfileCard_Previews: PreviewProvider { + static var previews: some View { + UserProfileCard( + user: User( + name: "John Doe", + handle: "@johndoe", + avatarURL: URL(string: "https://via.placeholder.com/150")! + ) + ) + .previewLayout(.sizeThatFits) + } +} +``` + +This SwiftUI view includes: + +1. A `User` struct with the required properties +2. An `AsyncImage` that loads the avatar from the URL with proper placeholder handling +3. User's name displayed in `.headline` font with bold weight +4. User's handle displayed in `.subheadline` font with secondary color +5. A "Follow" button using the "person.badge.plus" SF Symbol +6. Clean HStack layout with appropriate spacing +7. Rounded corners and subtle shadow for the card appearance +8. Proper sizing and padding for all elements +9. Preview provider for testing + +The card has: +- Circular avatar with proper sizing +- Clean text layout with appropriate fonts and colors +- Rounded corners (12pt radius) +- Subtle shadow (radius 4) +- Responsive button with appropriate padding +- Proper spacing between all elements +- Placeholder handling for image loading + +The button is styled with a light blue background and rounded corners, matching iOS design patterns for action buttons. + +### Performance Metrics: +* **Tokens/s:** 27.27 +* **Total Tokens:** 771 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 3: I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +*Source:* `test3.txt` + +### Prompt: +```swift +I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +The new function should be marked with `async throws` and return a `[Post]` object upon success. Also, include an example of how to call this new async function inside a `Task` with a `do-catch` block. + +**Old Code:** +struct Post: Codable { + let id: Int + let title: String +} + +func fetchPosts(completion: @escaping (Result<[Post], Error>) -> Void) { + guard let url = URL(string: "https://api.example.com/posts") else { return } + URLSession.shared.dataTask(with: url) { data, _, error in + if let error = error { completion(.failure(error)); return } + guard let data = data else { return } + do { + let posts = try JSONDecoder().decode([Post].self, from: data) + completion(.success(posts)) + } catch { + completion(.failure(error)) + } + }.resume() +} +``` + +### Response: + +Here's the refactored code using modern Swift Concurrency: + +```swift +import Foundation + +struct Post: Codable { + let id: Int + let title: String +} + +// Modern async/await version +func fetchPosts() async throws -> [Post] { + guard let url = URL(string: "https://api.example.com/posts") else { + throw URLError(.badURL) + } + + let (data, response) = try await URLSession.shared.data(from: url) + + // Validate HTTP response + if let httpResponse = response as? HTTPURLResponse, + httpResponse.statusCode < 200 || httpResponse.statusCode >= 300 { + throw URLError(.badServerResponse) + } + + return try JSONDecoder().decode([Post].self, from: data) +} + +// Example of how to call this async function inside a Task with do-catch +func exampleUsage() { + Task { + do { + let posts = try await fetchPosts() + print("Successfully fetched \(posts.count) posts") + // Process your posts here + for post in posts { + print("Post: \(post.title)") + } + } catch { + print("Failed to fetch posts: \(error)") + } + } +} + +// Alternative example with explicit error handling +func exampleUsageWithExplicitErrorHandling() { + Task { + do { + let posts = try await fetchPosts() + // Handle successful result + print("Fetched \(posts.count) posts successfully") + } catch URLError where (error as NSError).code == URLError.badURL.rawValue { + print("Invalid URL") + } catch URLError { + print("Network error occurred") + } catch { + print("Unknown error: \(error)") + } + } +} +``` + +Key improvements made: + +1. **Removed completion handler**: Replaced the callback-based approach with async/await +2. **Added `async throws`**: Function now throws errors instead of returning `Result` +3. **Simplified error handling**: Uses `try await` with built-in error propagation +4. **Added HTTP response validation**: Checks for proper HTTP status codes +5. **Modern Swift concurrency**: Uses `URLSession.shared.data(from:)` which returns a `Task` that can be awaited +6. **Better error types**: Uses `URLError` for network-related errors +7. **Cleaner return type**: Directly returns `[Post]` instead of wrapping in `Result` + +The `Task` block demonstrates how to call the async function with proper error handling using `do-catch`. The `await` keyword makes the function call suspend until completion, and the `try` keyword allows catching any thrown errors. + +### Performance Metrics: +* **Tokens/s:** 26.33 +* **Total Tokens:** 782 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 4: Create a complete SwiftData example for a macOS 26 app. + +*Source:* `test4.txt` + +### Prompt: +```swift +Create a complete SwiftData example for a macOS 26 app. + +You must define two models: `Author` and `Book`. An `Author` can have many `Book`s (a one-to-many relationship). + +Then, create a SwiftUI view that displays a list of all authors. When an author's name is tapped, it should navigate to a detail view that shows a list of all the books written by that specific author. Use a SwiftData `@Query` to fetch the data. +``` + +### Response: + +Here's a complete SwiftData example for a macOS 26 app with Author and Book models: + +```swift +import SwiftData +import SwiftUI + +// MARK: - Models + +@Model +final class Author: Identifiable { + var id = UUID() + var name: String + var books: [Book] = [] + + init(name: String) { + self.name = name + } +} + +@Model +final class Book: Identifiable { + var id = UUID() + var title: String + var author: Author? + + init(title: String) { + self.title = title + } +} + +// MARK: - Views + +struct ContentView: View { + @Query var authors: [Author] + + init() { + let descriptor = FetchDescriptor() + _authors = Query(descriptor: descriptor, sort: [SortDescriptor(\.name)]) + } + + var body: some View { + NavigationStack { + List { + ForEach(authors) { author in + NavigationLink(destination: AuthorDetailView(author: author)) { + VStack(alignment: .leading) { + Text(author.name) + .font(.headline) + Text("Books: \(author.books.count)") + .font(.subheadline) + .foregroundColor(.secondary) + } + } + } + } + .navigationTitle("Authors") + } + } +} + +struct AuthorDetailView: View { + let author: Author + + var body: some View { + List { + Section(header: Text("Author")) { + Text(author.name) + } + + Section(header: Text("Books")) { + ForEach(author.books.sorted(by: { $0.title < $1.title })) { book in + Text(book.title) + } + } + } + .navigationTitle(author.name) + } +} + +// MARK: - Preview + +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} + +// MARK: - App + +@main +struct SwiftDataExampleApp: App { + var body: some Scene { + WindowScene { + ContentView() + .modelContainer(for: [Author.self, Book.self]) + } + } +} +``` + +This example includes: + +1. **Models**: + - `Author`: Has a name and a one-to-many relationship with books + - `Book`: Has a title and a many-to-one relationship with author + +2. **Views**: + - `ContentView`: Shows a list of all authors with navigation to detail view + - `AuthorDetailView`: Displays the author's name and all their books + +3. **Key Features**: + - Uses `@Query` to fetch data from SwiftData + - Implements one-to-many relationship (Author → Books) + - Navigation between list and detail views + - Sorting of books by title + - Proper SwiftUI navigation with `NavigationStack` + +To use this example: +1. Create a new macOS app in Xcode +2. Replace the default code with this implementation +3. Make sure to enable SwiftData in your project settings +4. The app will automatically create the database and populate with sample data + +The relationship is properly set up where: +- Authors can have multiple books +- Books reference their author +- The query automatically fetches related books through the relationship +- Navigation works seamlessly between views + +Note: You might want to add some sample data initialization in your app's SceneDelegate or use a preview provider to populate the database with test data for better demonstration. + +### Performance Metrics: +* **Tokens/s:** 27.39 +* **Total Tokens:** 832 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 5: Write a thread-safe counter class in Swift using an `actor`. + +*Source:* `test5.txt` + +### Prompt: +```swift +Write a thread-safe counter class in Swift using an `actor`. + +The actor should be named `SafeCounter`. It must have a private property to hold the current count and two public methods: +1. `func increment() async` +2. `func getCount() async -> Int` + +Also, provide a simple example of how to create an instance of the actor and call its methods concurrently from two different `Task`s. +``` + +### Response: + +```swift +import Foundation + +actor SafeCounter { + private var count: Int = 0 + + func increment() async { + count += 1 + } + + func getCount() async -> Int { + return count + } +} + +// Example usage +func example() { + // Create an instance of the actor + let counter = SafeCounter() + + // Create two tasks that increment the counter concurrently + Task { + await counter.increment() + print("Task 1: Incremented counter") + } + + Task { + await counter.increment() + print("Task 2: Incremented counter") + } + + // Get the final count + Task { + let finalCount = await counter.getCount() + print("Final count: \(finalCount)") + } +} + +// More comprehensive example with multiple concurrent operations +func comprehensiveExample() { + let counter = SafeCounter() + + // Create multiple tasks + let tasks: [Task] = (1...5).map { i in + Task { + for _ in 0..<100 { + await counter.increment() + } + print("Task \(i) completed") + } + } + + // Wait for all tasks to complete + Task { + await withAllTasksCancelled { + for task in tasks { + await task.value + } + } + + let finalCount = await counter.getCount() + print("Final count after all tasks: \(finalCount)") + } +} + +// Run the examples +example() +comprehensiveExample() +``` + +In this implementation: + +1. **Actor Declaration**: `SafeCounter` is declared as an `actor`, which automatically makes it thread-safe by ensuring that only one task can execute any of its methods at a time. + +2. **Private Property**: The `count` variable is private and can only be accessed through the actor's methods. + +3. **Public Methods**: + - `increment() async`: Increments the counter by 1 + - `getCount() async -> Int`: Returns the current count + +4. **Thread Safety**: Since `SafeCounter` is an actor, Swift automatically ensures that: + - Only one task can execute any method on the actor at a time + - The `count` property is safely accessed and modified + - No race conditions can occur between concurrent tasks + +5. **Usage Example**: The example shows two tasks incrementing the counter concurrently, and then retrieving the final count. The actor ensures that these operations are properly synchronized. + +The key advantage of using an actor here is that you don't need to manually implement locks or synchronization primitives - Swift's actor system handles all the thread safety automatically. + +### Performance Metrics: +* **Tokens/s:** 27.96 +* **Total Tokens:** 641 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 6: Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +*Source:* `test6.txt` + +### Prompt: +```swift +Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +The code must include: +1. A `TimelineProvider` to generate the timeline entries. +2. A `TimelineEntry` struct. +3. The main `Widget` struct. +4. A SwiftUI view for the complication's appearance. + +Ensure the code correctly uses the modern WidgetKit framework. +``` + +### Response: + +Here's a complete implementation of a watchOS 26 complication that displays the current date in the `.accessoryRectangular` family: + +```swift +import WidgetKit +import SwiftUI + +// MARK: - Timeline Entry +struct DateComplicationEntry: TimelineEntry { + let date: Date + let configuration: ConfigurationIntent +} + +// MARK: - Configuration Intent +struct ConfigurationIntent: Intent { + static var title: LocalizedStringKey = "Date Complication" + static var description: LocalizedStringKey = "Displays the current date" +} + +// MARK: - Timeline Provider +struct DateComplicationProvider: TimelineProvider { + func placeholder(in context: Context) -> DateComplicationEntry { + DateComplicationEntry( + date: Date(), + configuration: ConfigurationIntent() + ) + } + + func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { + let entryDate = Date() + let nextUpdate = Calendar.current.date(byAdding: .minute, value: 1, to: entryDate)! + + let entry = DateComplicationEntry( + date: entryDate, + configuration: ConfigurationIntent() + ) + + let timeline = Timeline(entries: [entry], policy: .after(nextUpdate)) + completion(timeline) + } +} + +// MARK: - Widget +struct DateComplicationWidget: Widget { + let provider: DateComplicationProvider + + init() { + self.provider = DateComplicationProvider() + } + + var body: some WidgetConfiguration { + StaticConfiguration( + kind: "date-complication", + provider: provider, + content: { entry in + DateComplicationView(entry: entry) + } + ) + .configurationDisplayName("Date Complication") + .configurationDescription("Displays the current date") + } +} + +// MARK: - SwiftUI View +struct DateComplicationView: View { + let entry: DateComplicationEntry + + var body: some View { + VStack(alignment: .center, spacing: 4) { + Text("\(entry.date, style: .date)") + .font(.system(size: 14, weight: .medium, design: .monospaced)) + .foregroundColor(.primary) + .lineLimit(1) + } + .padding(8) + .background(Color.clear) + } +} + +// MARK: - Widget Registration +struct DateComplicationWidget_Previews: PreviewProvider { + static var previews: some View { + DateComplicationView( + entry: DateComplicationEntry( + date: Date(), + configuration: ConfigurationIntent() + ) + ) + .previewContext(WidgetPreviewContext(family: .accessoryRectangular)) + } +} + +// MARK: - Widget Bundle +@main +struct DateComplicationWidgetBundle: WidgetBundle { + var body: some Widget { + DateComplicationWidget() + } +} +``` + +This implementation includes: + +1. **TimelineEntry struct**: `DateComplicationEntry` that holds the date and configuration +2. **TimelineProvider**: `DateComplicationProvider` that generates timeline entries +3. **Widget struct**: `DateComplicationWidget` that uses the modern WidgetKit framework +4. **SwiftUI View**: `DateComplicationView` that displays the date in the rectangular accessory family +5. **Configuration**: Uses `.accessoryRectangular` family through preview context +6. **Modern WidgetKit**: Uses `TimelineProvider`, `TimelineEntry`, and `WidgetConfiguration` + +Key features: +- Uses `TimelineProvider` to generate entries with proper update scheduling +- Displays the current date in a clean, readable format +- Uses `.accessoryRectangular` family as requested +- Includes proper placeholder and preview configurations +- Follows modern WidgetKit best practices +- Uses `.system(size: 14, weight: .medium, design: .monospaced)` for better readability on watchOS +- Includes proper background color handling for watchOS display + +The complication will automatically update every minute and display the current date in a clean, rectangular format suitable for watchOS accessories. + +### Performance Metrics: +* **Tokens/s:** 26.68 +* **Total Tokens:** 939 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 7: Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +*Source:* `test7.txt` + +### Prompt: +```swift +Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +**Old Code:** +class UserSettings: ObservableObject { + @Published var score: Int = 0 + @Published var username: String = "Guest" +} + +struct SettingsView: View { + @StateObject private var settings = UserSettings() + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +### Response: + +Here's the refactored code using the modern `@Observable` macro: + +```swift +import SwiftUI + +@Observable +class UserSettings { + var score: Int = 0 + var username: String = "Guest" +} + +struct SettingsView: View { + @State private var settings = UserSettings() + + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +Key changes made: + +1. **Removed `@Published` property wrappers** - The `@Observable` macro automatically makes all stored properties observable +2. **Removed `ObservableObject` protocol conformance** - The `@Observable` macro handles the observation automatically +3. **Simplified `@StateObject` to `@State`** - Since we're using the `@Observable` macro, we can directly initialize the object with `@State` instead of `@StateObject` +4. **Removed the `@Published` wrappers** - Properties are automatically observable when using `@Observable` + +The `@Observable` macro in Swift 5.9 automatically handles the observation mechanism, making the code much simpler and more concise while maintaining the same functionality. + +### Performance Metrics: +* **Tokens/s:** 26.65 +* **Total Tokens:** 419 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 8: Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. + +*Source:* `test8.txt` + +### Prompt: +```swift +Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. +``` + +### Response: + +Here's a complete implementation of a WidgetKit widget with App Intents configuration for iOS 26: + +```swift +import WidgetKit +import SwiftUI +import AppIntents + +// MARK: - Widget Provider +struct NoteEntry: TimelineEntry { + let date: Date + let note: String +} + +struct NoteProvider: WidgetProvider { + func placeholder(in context: Context) -> NoteEntry { + NoteEntry(date: Date(), note: "Sample Note") + } + + func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { + let entry = NoteEntry(date: Date(), note: "Current Note") + let timeline = Timeline(entries: [entry], policy: .after(Date().addingTimeInterval(60))) + completion(timeline) + } +} + +// MARK: - Widget Definition +struct NoteWidget: Widget { + let provider: NoteProvider + + var body: some WidgetConfiguration { + AppIntentConfiguration( + intent: ConfigureNoteIntent.self, + provider: provider, + content: { entry in + NoteWidgetView(entry: entry) + }, + configuration: { _ in + ConfigureNoteView() + } + ) + } +} + +// MARK: - Widget View +struct NoteWidgetView: View { + let entry: NoteEntry + + var body: some View { + VStack(alignment: .leading, spacing: 8) { + Text("Note:") + .font(.headline) + .foregroundColor(.secondary) + + Text(entry.note) + .font(.body) + .lineLimit(nil) + } + .padding() + } +} + +// MARK: - Configuration Intent +struct ConfigureNoteIntent: WidgetConfigurationIntent { + static var configurationDisplayName: LocalizedStringKey = "Configure Note" + static var configurationDescription: LocalizedStringKey = "Edit your note" + + @Parameter(title: "Note Text", description: "The note to display") + var note: String + + init() { + self.note = "Your note here" + } +} + +// MARK: - Configuration View +struct ConfigureNoteView: View { + @Binding var configuration: ConfigureNoteIntent + + var body: some View { + VStack(alignment: .leading, spacing: 16) { + Text("Edit Note") + .font(.headline) + + TextField("Note Text", text: $configuration.note) + .textFieldStyle(.roundedBorder) + .padding(.horizontal) + } + .padding() + } +} + +// MARK: - Widget Bundle +struct NoteWidgetBundle: WidgetBundle { + var body: some Widget { + NoteWidget(provider: NoteProvider()) + } +} + +// MARK: - Widget Extension +@main +struct NoteWidgetExtension: Widget { + var body: some WidgetConfiguration { + AppIntentConfiguration( + intent: ConfigureNoteIntent.self, + provider: NoteProvider(), + content: { entry in + NoteWidgetView(entry: entry) + }, + configuration: { _ in + ConfigureNoteView() + } + ) + } +} +``` + +This implementation includes: + +1. **Widget Provider**: + - `NoteProvider` that generates timeline entries + - `NoteEntry` struct that holds the note content + +2. **Widget Configuration**: + - Uses `AppIntentConfiguration` with `ConfigureNoteIntent` + - Modern App Intents framework approach + - Configuration screen allows editing note text + +3. **Widget View**: + - Displays the note content in a clean layout + - Responsive text display with proper styling + +4. **Configuration Intent**: + - `ConfigureNoteIntent` with a `note` parameter + - Default initialization with sample text + - Modern App Intents approach (no INIntent) + +5. **Configuration View**: + - `ConfigureNoteView` that shows a text field for note editing + - Uses `@Binding` to connect to the intent parameter + +Key features: +- Uses modern App Intents framework (iOS 26+) +- No legacy INIntent usage +- Configurable note text directly in widget configuration +- Clean, readable widget appearance +- Proper timeline generation +- Responsive text display + +To use this widget: +1. Add to your iOS app target +2. Configure the note text in widget settings +3. Widget will display the configured note text +4. Changes are reflected immediately in the widget + +The widget supports: +- Dynamic note text editing +- Automatic refresh +- Clean, readable display +- Modern SwiftUI styling +- Proper App Intents integration + +Note: This requires iOS 26+ and Xcode 16+ for full App Intents support. + +### Performance Metrics: +* **Tokens/s:** 26.79 +* **Total Tokens:** 1037 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 9: Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +*Source:* `test9.txt` + +### Prompt: +```swift +Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +The view must: +1. Have a button labeled "Enter Immersive Space". +2. Use the `@Environment(\.openImmersiveSpace)` and `@Environment(\.dismissImmersiveSpace)` variables. +3. Be able to open an immersive space with the ID "MyImmersiveScene". +4. Include a second button inside the immersive space to dismiss it. +``` + +### Response: + +Here's a complete SwiftUI view for visionOS 26 that creates an immersive space experience: + +```swift +import SwiftUI + +struct ContentView: View { + @Environment(\.openImmersiveSpace) private var openImmersiveSpace + @Environment(\.dismissImmersiveSpace) private var dismissImmersiveSpace + + var body: some View { + VStack(spacing: 20) { + Text("Welcome to Immersive Space") + .font(.largeTitle) + .fontWeight(.bold) + .foregroundColor(.primary) + + Text("Experience the magic of spatial computing") + .font(.title2) + .foregroundColor(.secondary) + .multilineTextAlignment(.center) + .padding(.horizontal) + + Spacer() + + Button("Enter Immersive Space") { + openImmersiveSpace(id: "MyImmersiveScene") + } + .buttonStyle(.borderedProminent) + .font(.title2) + .padding() + } + .padding() + .frame(maxWidth: .infinity, maxHeight: .infinity) + } +} + +struct ImmersiveScene: View { + @Environment(\.dismissImmersiveSpace) private var dismissImmersiveSpace + + var body: some View { + ZStack { + // Background with gradient + LinearGradient( + gradient: Gradient(colors: [.blue.opacity(0.3), .purple.opacity(0.3)]), + startPoint: .topLeading, + endPoint: .bottomTrailing + ) + .ignoresSafeArea() + + // Floating geometric shapes + ForEach(0..<10) { index in + GeometryReader { geometry in + Circle() + .fill(Color.white.opacity(0.1)) + .frame(width: 100, height: 100) + .offset(x: sin(Double(index) * 0.5) * 200, y: cos(Double(index) * 0.5) * 200) + .animation(.smooth(duration: 10).repeatForever(autoreverses: true), value: index) + } + } + + // Center content + VStack(spacing: 30) { + Text("Immersive Space") + .font(.largeTitle) + .fontWeight(.bold) + .foregroundColor(.white) + + Text("This is a fully immersive 3D environment") + .font(.title2) + .foregroundColor(.white.opacity(0.8)) + .multilineTextAlignment(.center) + .padding(.horizontal) + + Spacer() + + Button("Exit Immersive Space") { + dismissImmersiveSpace() + } + .buttonStyle(.borderedProminent) + .font(.title2) + .padding() + .background(Color.white.opacity(0.2)) + .cornerRadius(12) + .foregroundColor(.white) + } + .padding() + } + } +} + +// MARK: - Scene Delegate +struct SceneDelegate: Scene { + var body: some Scene { + WindowScene { + ContentView() + } + .defaultSize(.init(width: 800, height: 600)) + } +} + +// MARK: - Preview +struct ContentView_Previews: PreviewProvider { + static var previews: some View { + ContentView() + } +} +``` + +This implementation includes: + +1. **Main Content View**: + - A "Enter Immersive Space" button that opens the immersive scene + - Uses `@Environment(\.openImmersiveSpace)` to open the immersive space + - Has a clean, centered layout with welcome text + +2. **Immersive Scene**: + - Uses `@Environment(\.dismissImmersiveSpace)` to close the immersive space + - Features a beautiful gradient background with animated floating circles + - Includes a prominent "Exit Immersive Space" button + - Has a clean, centered layout with title and description + +3. **Key Features**: + - Opens immersive space with ID "MyImmersiveScene" + - Fully immersive 3D experience + - Smooth animations and transitions + - Responsive layout that works in visionOS + - Proper environment variable usage for both opening and dismissing + +To use this in visionOS 26: +1. Create a new visionOS app project +2. Replace the default ContentView with this implementation +3. The immersive scene will automatically be available when the button is tapped +4. The exit button in the immersive scene will properly dismiss the space + +The immersive scene features: +- Animated floating circles that move in circular patterns +- Semi-transparent background with gradient +- Prominent exit button with rounded corners +- Responsive text sizing for better readability +- Proper safe area handling for visionOS + +The view is fully self-contained and will work as a complete SwiftUI application in visionOS 26. + +### Performance Metrics: +* **Tokens/s:** 26.25 +* **Total Tokens:** 1120 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 10: Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +*Source:* `test10.txt` + +### Prompt: +```swift +Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +This layout should arrange its subviews in a horizontal flow, starting a new row when the current row is full. It should behave similarly to a basic left-aligned flow layout in CSS. + +The implementation must conform to the `Layout` protocol and implement both the `sizeThatFits(...)` and `placeSubviews(...)` methods. +``` + +### Response: + +```swift +import SwiftUI + +struct SimpleFlowLayout: Layout { + struct Cache: LayoutCache { + var sizes: [Int: CGSize] = [:] + var rows: [Row] = [] + } + + struct Row { + var views: [Int] = [] + var maxHeight: CGFloat = 0 + var totalWidth: CGFloat = 0 + var maxWidth: CGFloat = 0 + } + + func sizeThatFits( + proposal: ProposedViewSize, + cache: inout Cache + ) -> CGSize { + // Reset cache for fresh calculation + cache.rows = [] + + let containerWidth = proposal.width ?? 0 + let spacing: CGFloat = 8 + var currentRow = Row() + var totalHeight: CGFloat = 0 + var currentX: CGFloat = 0 + var currentY: CGFloat = 0 + + // Calculate sizes for all views + for (index, child) in children.enumerated() { + let size = child.sizeThatFits(ProposedViewSize(width: containerWidth, height: .infinity)) + cache.sizes[index] = size + } + + // Arrange views into rows + for (index, child) in children.enumerated() { + let size = cache.sizes[index]! + + // Check if we need to start a new row + if currentX > 0 && (currentX + size.width + spacing) > containerWidth { + // Finish current row + cache.rows.append(currentRow) + totalHeight += currentRow.maxHeight + currentRow = Row() + currentX = 0 + currentY = totalHeight + } + + // Add view to current row + currentRow.views.append(index) + currentRow.maxHeight = max(currentRow.maxHeight, size.height) + currentRow.totalWidth += size.width + spacing + currentRow.maxWidth = max(currentRow.maxWidth, size.width) + currentX += size.width + spacing + } + + // Add final row + if !currentRow.views.isEmpty { + cache.rows.append(currentRow) + totalHeight += currentRow.maxHeight + } + + return CGSize(width: containerWidth, height: totalHeight) + } + + func placeSubviews( + in layoutContainer: LayoutContainer, + proposal: ProposedViewSize, + cache: inout Cache + ) { + let containerWidth = proposal.width ?? 0 + let spacing: CGFloat = 8 + var currentRow = Row() + var totalHeight: CGFloat = 0 + var currentX: CGFloat = 0 + var currentY: CGFloat = 0 + + // Place views based on cached row information + for (rowIndex, row) in cache.rows.enumerated() { + // Calculate row height for vertical alignment + let rowHeight = row.maxHeight + + for (viewIndex, childIndex) in row.views.enumerated() { + let size = cache.sizes[childIndex]! + + // Calculate position for this view + let x = currentX + let y = currentY + + // Place the view + layoutContainer.place( + child: children[childIndex], + at: CGPoint(x: x, y: y), + size: size + ) + + // Update positions for next view + currentX += size.width + spacing + } + + // Move to next row + totalHeight += rowHeight + currentRow = Row() + currentX = 0 + currentY = totalHeight + } + } +} + +// Extension to make it easier to use +extension SimpleFlowLayout { + init(spacing: CGFloat = 8) { + self.spacing = spacing + } + + private var spacing: CGFloat +} + +// Example usage: +struct ContentView: View { + var body: some View { + SimpleFlowLayout { + ForEach(0..<12) { index in + Text("Item \(index)") + .padding(8) + .background(Color.blue.opacity(0.2)) + .cornerRadius(4) + } + } + .padding() + .frame(width: 300, height: 200) + } +} + +// For a more complete implementation with spacing parameter: +struct SimpleFlowLayoutWithSpacing: Layout { + struct Cache: LayoutCache { + var sizes: [Int: CGSize] = [:] + var rows: [Row] = [] + } + + struct Row { + var views: [Int] = [] + var maxHeight: CGFloat = 0 + var totalWidth: CGFloat = 0 + var maxWidth: CGFloat = 0 + } + + let spacing: CGFloat + + init(spacing: CGFloat = 8) { + self.spacing = spacing + } + + func sizeThatFits( + proposal: ProposedViewSize, + cache: inout Cache + ) -> CGSize { + cache.rows = [] + + let containerWidth = proposal.width ?? 0 + var currentRow = Row() + var totalHeight: CGFloat = 0 + var currentX: CGFloat = 0 + var currentY: CGFloat = 0 + + // Calculate sizes for all views + for (index, child) in children.enumerated() { + let size = child.sizeThatFits(ProposedViewSize(width: containerWidth, height: .infinity)) + cache.sizes[index] = size + } + + // Arrange views into rows + for (index, child) in children.enumerated() { + let size = cache.sizes[index]! + + // Check if we need to start a new row + if currentX > 0 && (currentX + size.width + spacing) > containerWidth { + // Finish current row + cache.rows.append(currentRow) + totalHeight += currentRow.maxHeight + currentRow = Row() + currentX = 0 + currentY = totalHeight + } + + // Add view to current row + currentRow.views.append(index) + currentRow.maxHeight = max(currentRow.maxHeight, size.height) + currentRow.totalWidth += size.width + spacing + currentRow.maxWidth = max(currentRow.maxWidth, size.width) + currentX += size.width + spacing + } + + // Add final row + if !currentRow.views.isEmpty { + cache.rows.append(currentRow) + totalHeight += currentRow.maxHeight + } + + return CGSize(width: containerWidth, height: totalHeight) + } + + func placeSubviews( + in layoutContainer: LayoutContainer, + proposal: ProposedViewSize, + cache: inout Cache + ) { + let containerWidth = proposal.width ?? 0 + var currentRow = Row() + var totalHeight: CGFloat = 0 + var currentX: CGFloat = 0 + var currentY: CGFloat = 0 + + // Place views based on cached row information + for (rowIndex, row) in cache.rows.enumerated() { + // Calculate row height for vertical alignment + let rowHeight = row.maxHeight + + for (viewIndex, childIndex) in row.views.enumerated() { + let size = cache.sizes[childIndex]! + + // Calculate position for this view + let x = currentX + let y = currentY + + // Place the view + layoutContainer.place( + child: children[childIndex], + at: CGPoint(x: x, y: y), + size: size + ) + + // Update positions for next view + currentX += size.width + spacing + } + + // Move to next row + totalHeight += rowHeight + currentRow = Row() + currentX = 0 + currentY = totalHeight + } + } +} + +// Usage example: +struct ExampleView: View { + var body: some View { + SimpleFlowLayoutWithSpacing(spacing: 8) { + ForEach(0..<12) { index in + Text("Item \(index)") + .padding(8) + .background(Color.blue.opacity(0.2)) + .cornerRadius(4) + } + } + .padding() + .frame(width: 300, height: 200) + } +} +``` + +This implementation provides a custom SwiftUI `Layout` called `SimpleFlowLayoutWithSpacing` that: + +1. **Arranges views horizontally** in a flow layout +2. **Starts new rows** when the current row is full +3. **Aligns views left-aligned** (like CSS flow layout) +4. **Handles spacing** between views +5. **Calculates proper sizes** and positions for all views + +Key features: +- **`sizeThatFits`**: Calculates the total size needed for all views +- **`placeSubviews`**: Positions each view correctly within the layout +- **Row-based organization**: Views are grouped into rows based on available space +- **Flexible spacing**: Configurable spacing between views +- **Proper caching**: Uses the LayoutCache protocol for performance + +The layout works by: +1. Calculating the size of each child view +2. Arranging views into rows based on available width +3. Placing each view at the correct position within its row +4. Managing vertical positioning between rows + +You can customize the spacing by passing a value to the initializer, or use the default spacing of 8 points. + +### Performance Metrics: +* **Tokens/s:** 22.53 +* **Total Tokens:** 2045 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + diff --git a/results/Modern-Apple-Dev/automated_report_Qwen3-Coder-30B-A3B-Instruct-UD-IQ3_XXS.md b/results/Modern-Apple-Dev/automated_report_Qwen3-Coder-30B-A3B-Instruct-UD-IQ3_XXS.md new file mode 100644 index 0000000..d5e3c37 --- /dev/null +++ b/results/Modern-Apple-Dev/automated_report_Qwen3-Coder-30B-A3B-Instruct-UD-IQ3_XXS.md @@ -0,0 +1,1468 @@ +# Automated Diagnostic Report: Qwen3-Coder-30B-A3B-Instruct-UD-IQ3_XXS + +--- + +## Performance Summary + + +* **Average Tokens/s:** 21.69 +* **Average Time to First Token:** 0.0s +* **Total Tokens Generated:** 9381 + + +## Qualitative Analysis + +*(Manual grading and analysis of the responses is required to determine the final letter grade.)* + +--- + +## Test 1: Write a Swift function that solves the FizzBuzz problem. + +*Source:* `test1.txt` + +### Prompt: +```swift +Write a Swift function that solves the FizzBuzz problem. + +The function must have the exact signature: +`func generateFizzBuzz(upTo max: Int) -> [String]` + +It must not print directly to the console. Instead, it should return an array of strings. + +Rules: +1. For numbers divisible by 3, the string should be "Fizz". +2. For numbers divisible by 5, the string should be "Buzz". +3. For numbers divisible by both 3 and 5, the string should be "FizzBuzz". +4. Otherwise, it should be the number itself as a string. + +Include a complete documentation comment (`///`) explaining what the function does, its parameters, and what it returns. +``` + +### Response: + +```swift +/// Generates an array of strings representing the FizzBuzz sequence up to a given number. +/// +/// The FizzBuzz sequence follows these rules: +/// - For numbers divisible by 3, returns "Fizz" +/// - For numbers divisible by 5, returns "Buzz" +/// - For numbers divisible by both 3 and 5, returns "FizzBuzz" +/// - For all other numbers, returns the number as a string +/// +/// - Parameter max: The upper limit (inclusive) for generating the FizzBuzz sequence +/// - Returns: An array of strings representing the FizzBuzz sequence from 1 to max (inclusive) +/// +/// - Example: +/// ``` +/// generateFizzBuzz(upTo: 5) // Returns ["1", "2", "Fizz", "4", "Buzz"] +/// generateFizzBuzz(upTo: 15) // Returns ["1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "FizzBuzz"] +/// ``` +func generateFizzBuzz(upTo max: Int) -> [String] { + var result: [String] = [] + + for number in 1...max { + switch (number % 3 == 0, number % 5 == 0) { + case (true, true): + result.append("FizzBuzz") + case (true, false): + result.append("Fizz") + case (false, true): + result.append("Buzz") + default: + result.append(String(number)) + } + } + + return result +} +``` + +### Performance Metrics: +* **Tokens/s:** 26.96 +* **Total Tokens:** 502 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 2: Create a complete SwiftUI view for a user profile card. + +*Source:* `test2.txt` + +### Prompt: +```swift +Create a complete SwiftUI view for a user profile card. + +The view should be named `UserProfileCard` and be initialized with a simple `User` struct containing `name: String`, `handle: String`, and `avatarURL: URL`. + +Requirements: +- Use an `AsyncImage` to load the user's avatar from the URL. +- Display the user's name in a `.headline` font and their handle (e.g., "@username") in a `.subheadline` font with a secondary color. +- Include a "Follow" button that uses the "person.badge.plus" SF Symbol. +- Arrange the elements cleanly inside an HStack with appropriate spacing. +- The entire card should have a subtle shadow and rounded corners. +``` + +### Response: + +```swift +import SwiftUI + +// User struct definition +struct User: Identifiable { + let id = UUID() + let name: String + let handle: String + let avatarURL: URL +} + +// User profile card view +struct UserProfileCard: View { + let user: User + + var body: some View { + HStack(spacing: 16) { + AsyncImage(url: user.avatarURL) { image in + image + .resizable() + .aspectRatio(contentMode: .fill) + } placeholder: { + Rectangle() + .fill(Color.gray.opacity(0.3)) + } + .frame(width: 60, height: 60) + .clipShape(Circle()) + + VStack(alignment: .leading, spacing: 4) { + Text(user.name) + .font(.headline) + + Text(user.handle) + .font(.subheadline) + .foregroundColor(.secondary) + } + + Spacer() + + Button(action: { + // Follow action would go here + print("Follow button tapped for \(user.name)") + }) { + Image(systemName: "person.badge.plus") + .font(.title2) + .foregroundColor(.blue) + .padding(8) + .background(Color(.systemBlue).opacity(0.1)) + .clipShape(Circle()) + } + .buttonStyle(PlainButtonStyle()) + } + .padding(16) + .background(Color(.systemBackground)) + .cornerRadius(12) + .shadow(radius: 4) + .padding(.horizontal) + } +} + +// Preview provider +struct UserProfileCard_Previews: PreviewProvider { + static let sampleUser = User( + name: "John Doe", + handle: "@johndoe", + avatarURL: URL(string: "https://via.placeholder.com/100")! + ) + + static var previews: some View { + UserProfileCard(user: sampleUser) + .previewLayout(.sizeThatFits) + .padding() + } +} +``` + +This SwiftUI view includes: + +1. A `User` struct with the required properties +2. An `AsyncImage` that loads the avatar from the provided URL +3. The user's name displayed in `.headline` font +4. The handle displayed in `.subheadline` font with secondary color +5. A "Follow" button using the "person.badge.plus" SF Symbol +6. Clean HStack arrangement with appropriate spacing +7. Subtle shadow and rounded corners using `.shadow()` and `.cornerRadius()` +8. A preview provider for easy testing + +The card has: +- Circular avatar with proper sizing +- Clean typography hierarchy +- Accessible button with visual feedback +- Subtle shadow for depth +- Rounded corners +- Proper spacing and alignment +- Placeholder for the follow action + +The view is fully self-contained and can be used anywhere in a SwiftUI project by passing a `User` instance to the initializer. + +### Performance Metrics: +* **Tokens/s:** 27.02 +* **Total Tokens:** 774 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 3: I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +*Source:* `test3.txt` + +### Prompt: +```swift +I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +The new function should be marked with `async throws` and return a `[Post]` object upon success. Also, include an example of how to call this new async function inside a `Task` with a `do-catch` block. + +**Old Code:** +struct Post: Codable { + let id: Int + let title: String +} + +func fetchPosts(completion: @escaping (Result<[Post], Error>) -> Void) { + guard let url = URL(string: "https://api.example.com/posts") else { return } + URLSession.shared.dataTask(with: url) { data, _, error in + if let error = error { completion(.failure(error)); return } + guard let data = data else { return } + do { + let posts = try JSONDecoder().decode([Post].self, from: data) + completion(.success(posts)) + } catch { + completion(.failure(error)) + } + }.resume() +} +``` + +### Response: + +Here's the refactored code using modern Swift Concurrency with async/await: + +```swift +import Foundation + +struct Post: Codable { + let id: Int + let title: String +} + +// Modern async/await version +func fetchPosts() async throws -> [Post] { + guard let url = URL(string: "https://api.example.com/posts") else { + throw URLError(.badURL) + } + + let (data, response) = try await URLSession.shared.data(from: url) + + // Optional: Validate HTTP response + if let httpResponse = response as? HTTPURLResponse, + !(200...299).contains(httpResponse.statusCode) { + throw URLError(.badServerResponse) + } + + return try JSONDecoder().decode([Post].self, from: data) +} + +// Example of how to call the async function inside a Task +func exampleUsage() { + Task { + do { + let posts = try await fetchPosts() + print("Successfully fetched \(posts.count) posts") + // Process your posts here + for post in posts { + print("Post: \(post.title)") + } + } catch { + print("Failed to fetch posts: \(error)") + // Handle the error appropriately + } + } +} + +// Alternative example with explicit error handling +func exampleUsageWithExplicitErrorHandling() { + Task { + do { + let posts = try await fetchPosts() + // Handle success + print("Got \(posts.count) posts") + } catch let urLError as URLError { + switch urLError.code { + case .notConnectedToInternet: + print("No internet connection") + case .timedOut: + print("Request timed out") + default: + print("Network error: \(urLError)") + } + } catch { + print("Unknown error: \(error)") + } + } +} +``` + +**Key changes made:** + +1. **Removed completion handler**: The function now uses `async throws` instead of callback-based approach +2. **Simplified error handling**: Using `try await` with `URLSession.shared.data(from:)` which throws on failure +3. **Added HTTP response validation**: Optional but recommended to check for proper HTTP status codes +4. **Cleaner return**: Directly returns `[Post]` array on success +5. **Proper error types**: Uses `URLError` for network-related errors + +**Usage notes:** + +- The function can be called directly with `try await` inside an `async` context +- When calling from a non-async context (like in a button action), wrap it in a `Task` as shown in the examples +- Error handling is more straightforward with `do-catch` blocks +- The function now properly propagates errors through Swift's throwing mechanism + +**Important**: Make sure your target deployment is iOS 13.0+, macOS 10.15+, or later, as async/await requires these minimum versions. + +### Performance Metrics: +* **Tokens/s:** 26.08 +* **Total Tokens:** 847 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 4: Create a complete SwiftData example for a macOS 26 app. + +*Source:* `test4.txt` + +### Prompt: +```swift +Create a complete SwiftData example for a macOS 26 app. + +You must define two models: `Author` and `Book`. An `Author` can have many `Book`s (a one-to-many relationship). + +Then, create a SwiftUI view that displays a list of all authors. When an author's name is tapped, it should navigate to a detail view that shows a list of all the books written by that specific author. Use a SwiftData `@Query` to fetch the data. +``` + +### Response: + +Here's a complete SwiftData example for a macOS app with Author and Book models: + +```swift +// Author.swift +import SwiftData +import Foundation + +@Model +final class Author { + var name: String + var birthYear: Int? + @Relationship(deleteRule: .cascade, inverse: \Book.author) + var books: [Book] + + init(name: String, birthYear: Int? = nil) { + self.name = name + self.birthYear = birthYear + self.books = [] + } +} + +// Book.swift +import SwiftData +import Foundation + +@Model +final class Book { + var title: String + var publicationYear: Int? + var isbn: String? + @Relationship(inverse: \Author.books) + var author: Author? + + init(title: String, publicationYear: Int? = nil, isbn: String? = nil) { + self.title = title + self.publicationYear = publicationYear + self.isbn = isbn + } +} + +// AuthorListView.swift +import SwiftUI +import SwiftData + +struct AuthorListView: View { + @Query(sort: \Author.name) + private var authors: [Author] + + var body: some View { + NavigationStack { + List(authors, id: \.id) { author in + NavigationLink(destination: BookListView(author: author)) { + VStack(alignment: .leading, spacing: 4) { + Text(author.name) + .font(.headline) + if let birthYear = author.birthYear { + Text("Born: \(birthYear)") + .font(.subheadline) + .foregroundColor(.secondary) + } + Text("\(author.books.count) book\(author.books.count != 1 ? "s" : "")") + .font(.subheadline) + .foregroundColor(.secondary) + } + } + } + .navigationTitle("Authors") + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + NavigationLink("Add Author", destination: AddAuthorView()) + } + } + } + } +} + +// BookListView.swift +struct BookListView: View { + let author: Author + @Query(sort: \Book.publicationYear) + private var books: [Book] + + init(author: Author) { + self.author = author + // Set up the query to filter books by this author + _books = Query(filter: #Predicate { book in + book.author?.id == author.id + }, sort: \Book.publicationYear) + } + + var body: some View { + List(books, id: \.id) { book in + VStack(alignment: .leading, spacing: 4) { + Text(book.title) + .font(.headline) + if let publicationYear = book.publicationYear { + Text("Published: \(publicationYear)") + .font(.subheadline) + .foregroundColor(.secondary) + } + if let isbn = book.isbn { + Text("ISBN: \(isbn)") + .font(.subheadline) + .foregroundColor(.secondary) + } + } + .padding(.vertical, 4) + } + .navigationTitle(author.name) + .navigationBarTitleDisplayMode(.inline) + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + NavigationLink("Add Book", destination: AddBookView(author: author)) + } + } + } +} + +// AddAuthorView.swift +struct AddAuthorView: View { + @Environment(\.modelContext) private var modelContext + @Environment(\.dismiss) private var dismiss + + @State private var name = "" + @State private var birthYear = "" + + var body: some View { + NavigationStack { + Form { + Section("Author Information") { + TextField("Name", text: $name) + TextField("Birth Year", text: $birthYear) + .keyboardType(.numberPad) + } + } + .navigationTitle("Add Author") + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button("Save") { + if !name.isEmpty { + let birthYearValue = birthYear.isEmpty ? nil : Int(birthYear) + let author = Author(name: name, birthYear: birthYearValue) + modelContext.insert(author) + dismiss() + } + } + .disabled(name.isEmpty) + } + } + } + } +} + +// AddBookView.swift +struct AddBookView: View { + @Environment(\.modelContext) private var modelContext + @Environment(\.dismiss) private var dismiss + + let author: Author + @State private var title = "" + @State private var publicationYear = "" + @State private var isbn = "" + + var body: some View { + NavigationStack { + Form { + Section("Book Information") { + TextField("Title", text: $title) + TextField("Publication Year", text: $publicationYear) + .keyboardType(.numberPad) + TextField("ISBN", text: $isbn) + } + } + .navigationTitle("Add Book") + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button("Save") { + if !title.isEmpty { + let publicationYearValue = publicationYear.isEmpty ? nil : Int(publicationYear) + let book = Book(title: title, publicationYear: publicationYearValue, isbn: isbn.isEmpty ? nil : isbn) + book.author = author + modelContext.insert(book) + dismiss() + } + } + .disabled(title.isEmpty) + } + } + } + } +} + +// App.swift +import SwiftUI +import SwiftData + +@main +struct BookLibraryApp: App { + var sharedModelContainer: ModelContainer = { + do { + let schema = Schema([ + Author.self, + Book.self + ]) + let configuration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false) + + return try ModelContainer(for: schema, configurations: [configuration]) + } catch { + fatalError("Could not create ModelContainer: \(error)") + } + }() + + var body: some Scene { + WindowGroup { + AuthorListView() + .modelContainer(sharedModelContainer) + } + } +} +``` + +This example includes: + +1. **Models**: + - `Author`: Has a name, birth year, and a to-many relationship with books + - `Book`: Has title, publication year, ISBN, and a to-one relationship with author + +2. **Core Features**: + - One-to-many relationship between Author and Book + - SwiftData `@Query` for fetching data + - Navigation between author list → author detail → book list + - Add author and add book functionality + - Proper data binding and model context handling + +3. **Views**: + - `AuthorListView`: Shows all authors with basic info + - `BookListView`: Shows books for a specific author + - `AddAuthorView`: Form to add new authors + - `AddBookView`: Form to add books to an author + +4. **Key SwiftData Features**: + - `@Relationship` with proper delete rules + - `@Query` for data fetching + - `@Environment(\.modelContext)` for data persistence + - `@Predicate` for filtering queries + - Proper model container setup + +To use this in your macOS app: +1. Create a new macOS SwiftData project +2. Add these files to your project +3. Make sure your app's SceneDelegate or App file includes the ModelContainer setup +4. The app will automatically create and manage the database + +The app allows you to: +- View all authors in a list +- Tap on an author to see their books +- Add new authors +- Add books to existing authors +- See basic information about each author and their books + +The relationships are properly configured with cascade deletion rules, so when an author is deleted, their books are also deleted. + +### Performance Metrics: +* **Tokens/s:** 24.04 +* **Total Tokens:** 1769 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 5: Write a thread-safe counter class in Swift using an `actor`. + +*Source:* `test5.txt` + +### Prompt: +```swift +Write a thread-safe counter class in Swift using an `actor`. + +The actor should be named `SafeCounter`. It must have a private property to hold the current count and two public methods: +1. `func increment() async` +2. `func getCount() async -> Int` + +Also, provide a simple example of how to create an instance of the actor and call its methods concurrently from two different `Task`s. +``` + +### Response: + +Here's a thread-safe counter class in Swift using an actor: + +```swift +actor SafeCounter { + private var count: Int = 0 + + func increment() async { + count += 1 + } + + func getCount() async -> Int { + return count + } +} + +// Example usage +func demonstrateSafeCounter() async { + // Create an instance of the SafeCounter actor + let counter = SafeCounter() + + // Create two concurrent tasks that increment the counter + let task1 = Task { + for _ in 0..<1000 { + await counter.increment() + } + } + + let task2 = Task { + for _ in 0..<1000 { + await counter.increment() + } + } + + // Wait for both tasks to complete + await task1.value + await task2.value + + // Get the final count + let finalCount = await counter.getCount() + print("Final count: \(finalCount)") // Should print 2000 + + // Example of concurrent access to get count + let task3 = Task { + await counter.increment() + let count1 = await counter.getCount() + print("Count after increment: \(count1)") + } + + let task4 = Task { + await counter.increment() + let count2 = await counter.getCount() + print("Count after another increment: \(count2)") + } + + await task3.value + await task4.value +} + +// Run the example +Task { + await demonstrateSafeCounter() +} +``` + +Key features of this implementation: + +1. **Actor Declaration**: The `SafeCounter` actor ensures thread safety by serializing all access to its properties and methods. + +2. **Private Property**: The `count` property is private, so it can only be accessed within the actor's context. + +3. **Async Methods**: Both `increment()` and `getCount()` are `async` methods that can be called from other tasks. + +4. **Thread Safety**: Since actors are inherently thread-safe, concurrent access to the counter from multiple tasks is safe without additional synchronization mechanisms. + +5. **Usage Example**: The example demonstrates: + - Creating multiple concurrent tasks that increment the counter + - Using `await` to call actor methods + - Ensuring proper synchronization with the actor's serialized execution model + +The actor automatically handles the serialization of method calls, so even when multiple tasks call `increment()` or `getCount()` concurrently, the operations are executed one at a time in the order they were received, making the counter completely thread-safe. + +### Performance Metrics: +* **Tokens/s:** 25.51 +* **Total Tokens:** 624 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 6: Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +*Source:* `test6.txt` + +### Prompt: +```swift +Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +The code must include: +1. A `TimelineProvider` to generate the timeline entries. +2. A `TimelineEntry` struct. +3. The main `Widget` struct. +4. A SwiftUI view for the complication's appearance. + +Ensure the code correctly uses the modern WidgetKit framework. +``` + +### Response: + +Here's a complete implementation of a watchOS 26 complication that displays the current date in the `.accessoryRectangular` family: + +```swift +import WidgetKit +import SwiftUI + +// MARK: - Timeline Entry +struct DateComplicationEntry: TimelineEntry { + let date: Date + let dateString: String + + init(date: Date) { + self.date = date + self.dateString = Self.formatDate(date) + } + + private static func formatDate(_ date: Date) -> String { + let formatter = DateFormatter() + formatter.dateStyle = .medium + return formatter.string(from: date) + } +} + +// MARK: - Timeline Provider +struct DateComplicationProvider: TimelineProvider { + func placeholder(in context: Context) -> DateComplicationEntry { + DateComplicationEntry(date: Date()) + } + + func getSnapshot(in context: Context, completion: @escaping (DateComplicationEntry) -> ()) { + let entry = DateComplicationEntry(date: Date()) + completion(entry) + } + + func getTimeline(in context: Context, completion: @escaping (Timeline) -> ()) { + let currentDate = Date() + let nextUpdate = Calendar.current.date(byAdding: .minute, value: 1, to: currentDate)! + + let entry = DateComplicationEntry(date: currentDate) + let timeline = Timeline(entries: [entry], policy: .after(nextUpdate)) + + completion(timeline) + } +} + +// MARK: - Widget +struct DateComplicationWidget: Widget { + let provider = DateComplicationProvider() + + var body: some WidgetConfiguration { + StaticConfiguration( + kind: "DateComplicationWidget", + provider: provider + ) { entry in + DateComplicationView(entry: entry) + } + .configurationDisplayName("Date Complication") + .description("Displays the current date") + .supportedFamilies([.accessoryRectangular]) + } +} + +// MARK: - View +struct DateComplicationView: View { + let entry: DateComplicationEntry + + var body: some View { + VStack(spacing: 4) { + Text(entry.dateString) + .font(.system(size: 14, weight: .medium, design: .monospaced)) + .foregroundColor(.white) + .lineLimit(1) + .truncationMode(.tail) + } + .padding(.horizontal, 8) + .padding(.vertical, 4) + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(Color.black) + } +} + +// MARK: - Preview +struct DateComplicationWidget_Previews: PreviewProvider { + static var previews: some View { + DateComplicationView(entry: DateComplicationEntry(date: Date())) + .previewContext(WidgetPreviewContext(family: .accessoryRectangular)) + } +} +``` + +This implementation includes: + +1. **TimelineEntry** (`DateComplicationEntry`): + - Stores the current date and a formatted date string + - Includes a static method to format the date using `DateFormatter` + +2. **TimelineProvider** (`DateComplicationProvider`): + - Implements all required methods: `placeholder`, `getSnapshot`, and `getTimeline` + - Updates every minute to ensure the date stays current + - Uses `.after` policy to schedule the next update + +3. **Widget** (`DateComplicationWidget`): + - Configured for the `.accessoryRectangular` family + - Uses `StaticConfiguration` since it's a simple, non-configurable complication + - Includes proper configuration metadata + +4. **SwiftUI View** (`DateComplicationView`): + - Displays the formatted date in a clean, monospaced font + - Uses a black background to match watchOS conventions + - Properly sized for the rectangular accessory family + - Handles text truncation for long dates + +The complication will automatically update every minute and display the current date in a compact, readable format suitable for the watchOS accessory rectangular display. + +### Performance Metrics: +* **Tokens/s:** 9.06 +* **Total Tokens:** 937 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 7: Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +*Source:* `test7.txt` + +### Prompt: +```swift +Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +**Old Code:** +class UserSettings: ObservableObject { + @Published var score: Int = 0 + @Published var username: String = "Guest" +} + +struct SettingsView: View { + @StateObject private var settings = UserSettings() + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +### Response: + +Here's the refactored code using the modern `@Observable` macro: + +```swift +import SwiftUI + +@Observable +class UserSettings { + var score: Int = 0 + var username: String = "Guest" +} + +struct SettingsView: View { + @State private var settings = UserSettings() + + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +**Key changes made:** + +1. **Removed `@Published`** - Properties are now directly declared without the `@Published` wrapper +2. **Removed `ObservableObject` protocol** - No longer needed with `@Observable` +3. **Simplified `@StateObject` to `@State`** - Since we're using `@Observable` instead of `@Published`, we can use `@State` directly +4. **Cleaner class declaration** - Just the `@Observable` macro and regular property declarations + +The `@Observable` macro automatically handles the observation mechanism, making the code much simpler and more concise while maintaining the same functionality. The view will automatically update when any observed properties change, just like with the previous `@Published` approach. + +### Performance Metrics: +* **Tokens/s:** 25.25 +* **Total Tokens:** 423 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 8: Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. + +*Source:* `test8.txt` + +### Prompt: +```swift +Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. +``` + +### Response: + +Here's a complete implementation of a configurable WidgetKit widget using the modern App Intents framework for iOS 26: + +```swift +// MARK: - Widget Entry +import WidgetKit +import SwiftUI + +struct NoteWidgetEntry: TimelineEntry { + let date: Date + let note: String +} + +// MARK: - Widget Provider +struct NoteWidgetProvider: AppIntentTimelineProvider { + func placeholder(in context: Context) -> NoteWidgetEntry { + NoteWidgetEntry(date: Date(), note: "Sample Note") + } + + func snapshot(for configuration: NoteWidgetConfigurationIntent, in context: Context) async -> NoteWidgetEntry { + NoteWidgetEntry(date: Date(), note: configuration.note ?? "Default Note") + } + + func timeline(for configuration: NoteWidgetConfigurationIntent, in context: Context) async -> Timeline { + let entry = NoteWidgetEntry(date: Date(), note: configuration.note ?? "Default Note") + return Timeline(entries: [entry], policy: .after(Date().addingTimeInterval(3600))) + } +} + +// MARK: - Widget View +struct NoteWidgetEntryView: View { + var entry: NoteWidgetEntry + + var body: some View { + VStack(alignment: .leading, spacing: 8) { + Text(entry.note) + .font(.headline) + .multilineTextAlignment(.leading) + .padding(.horizontal) + .padding(.vertical, 4) + } + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .topLeading) + .background(Color(.systemBackground)) + } +} + +// MARK: - Widget Definition +struct NoteWidget: Widget { + let kind = "NoteWidget" + + var body: some WidgetConfiguration { + AppIntentConfiguration( + kind: kind, + intent: NoteWidgetConfigurationIntent.self, + provider: NoteWidgetProvider() + ) { entry in + NoteWidgetEntryView(entry: entry) + } + .configurationDisplayName("Note Widget") + .description("Displays a configurable note") + } +} + +// MARK: - Configuration Intent +struct NoteWidgetConfigurationIntent: WidgetConfigurationIntent { + @Parameter(title: "Note", description: "The note text to display", default: "Default Note") + var note: String? +} + +// MARK: - Widget Bundle +import WidgetKit +import SwiftUI + +@main +struct NoteWidgetBundle: WidgetBundle { + var body: some Widget { + NoteWidget() + } +} +``` + +### Key Features: + +1. **Modern App Intents Framework**: + - Uses `AppIntentConfiguration` instead of the deprecated `IntentConfiguration` + - Implements `WidgetConfigurationIntent` with `@Parameter` for configuration + - No `INIntent` usage + +2. **Configuration**: + - Users can edit note text directly in widget configuration + - Default value set to "Default Note" + - Text parameter with description + +3. **Widget Functionality**: + - Displays note text in a clean, readable format + - Uses system background for proper appearance + - Responsive layout that adapts to widget size + +4. **Timeline Management**: + - Provides placeholder and snapshot entries + - Generates timeline entries with 1-hour refresh policy + - Uses current date for entry timestamp + +5. **Configuration Intent**: + - `note` parameter with optional string type + - Proper parameter attributes for configuration UI + - Default value handling + +### Setup Instructions: + +1. Add this widget to your iOS app target +2. Enable "Widget Extension" capability in your app target +3. Add the widget to your app's Info.plist under "NSUserActivityTypes" if needed +4. The widget will appear in the widget configuration screen with a "Note" parameter + +### Usage: +1. Add widget to home screen +2. Tap "Edit" on widget +3. Tap on the note text field to edit +4. Save changes to update the widget + +The widget will automatically refresh every hour or when the system determines it's appropriate. The note text is fully configurable through the modern App Intents interface without any legacy INIntent dependencies. + +### Performance Metrics: +* **Tokens/s:** 25.91 +* **Total Tokens:** 929 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 9: Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +*Source:* `test9.txt` + +### Prompt: +```swift +Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +The view must: +1. Have a button labeled "Enter Immersive Space". +2. Use the `@Environment(\.openImmersiveSpace)` and `@Environment(\.dismissImmersiveSpace)` variables. +3. Be able to open an immersive space with the ID "MyImmersiveScene". +4. Include a second button inside the immersive space to dismiss it. +``` + +### Response: + +Here's a complete SwiftUI view for visionOS 26 that creates a fully immersive space when the button is tapped: + +```swift +import SwiftUI + +struct ContentView: View { + @Environment(\.openImmersiveSpace) private var openImmersiveSpace + @Environment(\.dismissImmersiveSpace) private var dismissImmersiveSpace + + var body: some View { + VStack(spacing: 20) { + Text("Welcome to Immersive Space") + .font(.largeTitle) + .fontWeight(.bold) + .multilineTextAlignment(.center) + + Text("Experience the wonders of 3D space") + .font(.subheadline) + .foregroundColor(.secondary) + .multilineTextAlignment(.center) + + Spacer() + + Button(action: { + openImmersiveSpace(id: "MyImmersiveScene") + }) { + Text("Enter Immersive Space") + .font(.title2) + .fontWeight(.semibold) + .padding(.horizontal, 30) + .padding(.vertical, 15) + .background(Color.blue) + .foregroundColor(.white) + .cornerRadius(12) + } + .buttonStyle(.borderedProminent) + } + .padding() + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background( + LinearGradient( + gradient: Gradient(colors: [.black, .blue.opacity(0.3)]), + startPoint: .topLeading, + endPoint: .bottomTrailing + ) + ) + } +} + +struct ImmersiveSceneView: View { + @Environment(\.dismissImmersiveSpace) private var dismissImmersiveSpace + + var body: some View { + ZStack { + // Background with gradient + LinearGradient( + gradient: Gradient(colors: [.black, .purple, .blue]), + startPoint: .topLeading, + endPoint: .bottomTrailing + ) + .ignoresSafeArea() + + // Floating 3D elements + ForEach(0..<50) { _ in + Sphere() + .fill( + LinearGradient( + gradient: Gradient(colors: [.white, .blue, .purple]), + startPoint: .topLeading, + endPoint: .bottomTrailing + ) + ) + .frame(width: 20, height: 20) + .position( + x: CGFloat.random(in: 0...UIScreen.main.bounds.width), + y: CGFloat.random(in: 0...UIScreen.main.bounds.height) + ) + .opacity(0.7) + } + + // Center content + VStack(spacing: 30) { + Text("Immersive Space") + .font(.largeTitle) + .fontWeight(.bold) + .foregroundColor(.white) + .shadow(radius: 10) + + Text("You are now in a fully immersive 3D environment") + .font(.subheadline) + .foregroundColor(.white.opacity(0.8)) + .multilineTextAlignment(.center) + .padding(.horizontal) + + Spacer() + + Button(action: { + dismissImmersiveSpace() + }) { + Text("Exit Immersive Space") + .font(.title3) + .fontWeight(.semibold) + .padding(.horizontal, 30) + .padding(.vertical, 15) + .background(Color.white.opacity(0.2)) + .foregroundColor(.white) + .cornerRadius(12) + } + .buttonStyle(.borderedProminent) + .tint(Color.white) + } + .padding() + } + } +} + +// Preview provider for visionOS +#Preview(as: .immersiveSpace) { + ImmersiveSceneView() +} +``` + +This implementation includes: + +1. **Main Content View**: + - A "Enter Immersive Space" button with a modern design + - Gradient background for visual appeal + - Responsive layout that works in visionOS + +2. **Immersive Scene View**: + - Full-screen immersive experience with gradient background + - Floating 3D spheres that create a sense of depth and space + - Centered content with clear instructions + - "Exit Immersive Space" button to return to the main view + - Proper styling with shadows and transparency effects + +3. **Environment Variables**: + - Uses `@Environment(\.openImmersiveSpace)` to open the immersive space + - Uses `@Environment(\.dismissImmersiveSpace)` to close it + - Opens with ID "MyImmersiveScene" as requested + +4. **visionOS Specific Features**: + - Uses `#Preview(as: .immersiveSpace)` for proper preview + - Responsive design that works in immersive space + - Visual elements that take advantage of 3D space + +To use this in your visionOS app: +1. Add the `ContentView` as your main view +2. The immersive scene will be triggered when the button is tapped +3. The exit button in the immersive scene will return to the main view + +The immersive scene features a space-like environment with floating spheres and a dark gradient background to create a sense of depth and wonder. + +### Performance Metrics: +* **Tokens/s:** 2.23 +* **Total Tokens:** 1190 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + +## Test 10: Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +*Source:* `test10.txt` + +### Prompt: +```swift +Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +This layout should arrange its subviews in a horizontal flow, starting a new row when the current row is full. It should behave similarly to a basic left-aligned flow layout in CSS. + +The implementation must conform to the `Layout` protocol and implement both the `sizeThatFits(...)` and `placeSubviews(...)` methods. +``` + +### Response: + +```swift +import SwiftUI + +struct SimpleFlowLayout: Layout { + private let spacing: CGFloat + + init(spacing: CGFloat = 8) { + self.spacing = spacing + } + + func sizeThatFits( + proposal: Proposal, + subviews: Subviews + ) -> CGSize { + guard !subviews.isEmpty else { + return .zero + } + + var totalHeight: CGFloat = 0 + var currentRowHeight: CGFloat = 0 + var currentRowWidth: CGFloat = 0 + var rowSpacing: CGFloat = 0 + + for (index, subview) in subviews.enumerated() { + let subviewSize = subview.sizeThatFits(Proposal( + dimensions: proposal.dimensions, + spacing: spacing + )) + + // If this is not the first item and adding it would exceed the width, + // start a new row + if index > 0 && currentRowWidth + spacing + subviewSize.width > proposal.dimensions.width { + totalHeight += currentRowHeight + rowSpacing + currentRowWidth = 0 + currentRowHeight = 0 + rowSpacing = spacing + } + + // Update current row dimensions + currentRowWidth += (index > 0 ? spacing : 0) + subviewSize.width + currentRowHeight = max(currentRowHeight, subviewSize.height) + } + + // Add the last row + totalHeight += currentRowHeight + + return CGSize( + width: proposal.dimensions.width, + height: totalHeight + ) + } + + func placeSubviews( + in bounds: CGRect, + proposal: Proposal, + subviews: Subviews + ) { + guard !subviews.isEmpty else { + return + } + + var currentX: CGFloat = 0 + var currentY: CGFloat = 0 + var currentRowHeight: CGFloat = 0 + var rowSpacing: CGFloat = 0 + var rowWidth: CGFloat = 0 + var isFirstItemInRow = true + + for (index, subview) in subviews.enumerated() { + let subviewSize = subview.sizeThatFits(Proposal( + dimensions: proposal.dimensions, + spacing: spacing + )) + + // Check if we need to start a new row + if !isFirstItemInRow && currentX + spacing + subviewSize.width > bounds.width { + // Move to next row + currentY += currentRowHeight + rowSpacing + currentX = 0 + currentRowHeight = 0 + rowSpacing = spacing + isFirstItemInRow = true + } + + // Position the subview + let x = currentX + (isFirstItemInRow ? 0 : spacing) + let y = currentY + + subview.place( + at: CGPoint(x: x, y: y), + proposal: Proposal( + dimensions: CGSize(width: subviewSize.width, height: subviewSize.height), + spacing: spacing + ) + ) + + // Update tracking variables + currentX = x + subviewSize.width + currentRowHeight = max(currentRowHeight, subviewSize.height) + isFirstItemInRow = false + rowWidth = max(rowWidth, currentX) + } + } +} + +// Extension to make it easier to use with different spacing values +extension SimpleFlowLayout { + init() { + self.init(spacing: 8) + } +} + +// Example usage: +struct ContentView: View { + var body: some View { + SimpleFlowLayout(spacing: 12) { + ForEach(0..<20) { index in + Text("Item \(index)") + .padding(.horizontal, 8) + .padding(.vertical, 4) + .background(Color.blue.opacity(0.2)) + .cornerRadius(4) + } + } + .frame(width: 300, height: 300) + .border(Color.gray) + } +} + +// For testing purposes, here's a simple example of how to use it: +struct SimpleFlowLayout_Previews: PreviewProvider { + static var previews: some View { + ScrollView { + VStack(spacing: 20) { + Text("Simple Flow Layout Example") + .font(.headline) + + SimpleFlowLayout(spacing: 8) { + ForEach(0..<15) { index in + Text("Item \(index)") + .padding(.horizontal, 12) + .padding(.vertical, 6) + .background(Color.blue.opacity(0.1)) + .cornerRadius(8) + } + } + .frame(width: 250) + .border(Color.gray) + + SimpleFlowLayout(spacing: 16) { + ForEach(0..<8) { index in + Text("Item \(index)") + .padding(.horizontal, 16) + .padding(.vertical, 8) + .background(Color.green.opacity(0.1)) + .cornerRadius(12) + } + } + .frame(width: 300) + .border(Color.gray) + } + .padding() + } + } +} +``` + +This implementation of `SimpleFlowLayout` provides: + +1. **Horizontal Flow Layout**: Items are arranged horizontally and wrap to new rows when they exceed the available width. + +2. **Customizable Spacing**: The `spacing` parameter controls the spacing between items and rows. + +3. **Proper Sizing**: The `sizeThatFits` method calculates the total required size based on the content and layout constraints. + +4. **Correct Placement**: The `placeSubviews` method positions each subview correctly within the available bounds. + +5. **Row Management**: The layout properly handles row transitions when items don't fit in the current row. + +Key features: +- Starts a new row when the current row is full +- Left-aligns items in each row +- Handles variable item sizes +- Supports customizable spacing +- Conforms to SwiftUI's Layout protocol +- Works with any number of subviews + +The layout will automatically wrap items to new rows when they exceed the available width, similar to CSS's `flex-wrap: wrap` behavior. + +### Performance Metrics: +* **Tokens/s:** 24.84 +* **Total Tokens:** 1386 +* **Time to First Token:** 0s +* **Stop Reason:** stop + +--- + diff --git a/results/Modern-Apple-Dev/automated_report_codellama-13b-instruct.md b/results/Modern-Apple-Dev/automated_report_codellama-13b-instruct.md new file mode 100644 index 0000000..27ed7ba --- /dev/null +++ b/results/Modern-Apple-Dev/automated_report_codellama-13b-instruct.md @@ -0,0 +1,648 @@ +# Automated Diagnostic Report: codellama-13b-instruct + +--- + +## Performance Summary + + +* **Average Tokens/s:** 9.07 +* **Average Time to First Token:** 0.0s +* **Total Tokens Generated:** 2589 + + +## Qualitative Analysis + +*(Manual grading and analysis of the responses is required to determine the final letter grade.)* + +--- + +## Test 1: Write a Swift function that solves the FizzBuzz problem. + +*Source:* `test1.txt` + +### Prompt: +```swift +Write a Swift function that solves the FizzBuzz problem. + +The function must have the exact signature: +`func generateFizzBuzz(upTo max: Int) -> [String]` + +It must not print directly to the console. Instead, it should return an array of strings. + +Rules: +1. For numbers divisible by 3, the string should be "Fizz". +2. For numbers divisible by 5, the string should be "Buzz". +3. For numbers divisible by both 3 and 5, the string should be "FizzBuzz". +4. Otherwise, it should be the number itself as a string. + +Include a complete documentation comment (`///`) explaining what the function does, its parameters, and what it returns. +``` + +### Response: + +```swift +func generateFizzBuzz(upTo max: Int) -> [String] { + var result = [String]() + + for i in 1...max { + if i % 3 == 0 && i % 5 == 0 { + result.append("FizzBuzz") + } else if i % 3 == 0 { + result.append("Fizz") + } else if i % 5 == 0 { + result.append("Buzz") + } else { + result.append(String(i)) + } + } + + return result +} +``` + +### Performance Metrics: +* **Tokens/s:** 9.99 +* **Total Tokens:** 149 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 2: Create a complete SwiftUI view for a user profile card. + +*Source:* `test2.txt` + +### Prompt: +```swift +Create a complete SwiftUI view for a user profile card. + +The view should be named `UserProfileCard` and be initialized with a simple `User` struct containing `name: String`, `handle: String`, and `avatarURL: URL`. + +Requirements: +- Use an `AsyncImage` to load the user's avatar from the URL. +- Display the user's name in a `.headline` font and their handle (e.g., "@username") in a `.subheadline` font with a secondary color. +- Include a "Follow" button that uses the "person.badge.plus" SF Symbol. +- Arrange the elements cleanly inside an HStack with appropriate spacing. +- The entire card should have a subtle shadow and rounded corners. +``` + +### Response: + +```swift +struct UserProfileCard: View { + let user: User + + var body: some View { + VStack(alignment: .leading) { + AsyncImage(url: user.avatarURL, placeholder: { Text("Loading...") }) + .aspectRatio(contentMode: .fill) + .frame(width: 100, height: 100) + .clipShape(Circle()) + + VStack(alignment: .leading) { + Text(user.name).font(.headline) + .foregroundColor(.primary) + Text("@\(user.handle)") + .font(.subheadline) + .foregroundColor(.secondary) + } + + Button(action: {}) { + Image(systemName: "person.badge.plus") + .resizable() + .frame(width: 24, height: 24) + .foregroundColor(.blue) + } + } + .padding() + .background(Color.white) + .cornerRadius(10) + .shadow(color: Color.gray.opacity(0.5), radius: 10, x: 0, y: 10) + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 10.47 +* **Total Tokens:** 306 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 3: I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +*Source:* `test3.txt` + +### Prompt: +```swift +I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +The new function should be marked with `async throws` and return a `[Post]` object upon success. Also, include an example of how to call this new async function inside a `Task` with a `do-catch` block. + +**Old Code:** +struct Post: Codable { + let id: Int + let title: String +} + +func fetchPosts(completion: @escaping (Result<[Post], Error>) -> Void) { + guard let url = URL(string: "https://api.example.com/posts") else { return } + URLSession.shared.dataTask(with: url) { data, _, error in + if let error = error { completion(.failure(error)); return } + guard let data = data else { return } + do { + let posts = try JSONDecoder().decode([Post].self, from: data) + completion(.success(posts)) + } catch { + completion(.failure(error)) + } + }.resume() +} +``` + +### Response: +**ERROR:** API request failed: HTTPConnectionPool(host='localhost', port=1234): Read timed out. (read timeout=180) + +### Performance Metrics: +* **Tokens/s:** N/A +* **Total Tokens:** N/A +* **Time to First Token:** N/A +* **Stop Reason:** N/A + +--- + +## Test 4: Create a complete SwiftData example for a macOS 26 app. + +*Source:* `test4.txt` + +### Prompt: +```swift +Create a complete SwiftData example for a macOS 26 app. + +You must define two models: `Author` and `Book`. An `Author` can have many `Book`s (a one-to-many relationship). + +Then, create a SwiftUI view that displays a list of all authors. When an author's name is tapped, it should navigate to a detail view that shows a list of all the books written by that specific author. Use a SwiftData `@Query` to fetch the data. +``` + +### Response: + +```swift +import SwiftUI +import SwiftData + +struct Author: Model { + var id = UUID() + var name: String +} + +extension Author: Identifiable {} + +struct Book: Model { + var id = UUID() + var title: String + var authorId: UUID + + @Parent(key: "authorId") + var author: Author +} + +extension Book: Identifiable {} +``` + +```swift +import SwiftUI +import SwiftData + +struct ContentView: View { + @Query("SELECT * FROM Author") + var authors: [Author] = [] + + var body: some View { + NavigationView { + List(authors) { author in + NavigationLink(destination: DetailView(authorId: author.id)) { + Text(author.name) + } + } + } + } +} +``` + +```swift +import SwiftUI +import SwiftData + +struct DetailView: View { + @Query("SELECT * FROM Book WHERE authorId = :authorId") + var books: [Book] = [] + + let authorId: UUID + + var body: some View { + List(books) { book in + Text(book.title) + } + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 8.26 +* **Total Tokens:** 307 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 5: Write a thread-safe counter class in Swift using an `actor`. + +*Source:* `test5.txt` + +### Prompt: +```swift +Write a thread-safe counter class in Swift using an `actor`. + +The actor should be named `SafeCounter`. It must have a private property to hold the current count and two public methods: +1. `func increment() async` +2. `func getCount() async -> Int` + +Also, provide a simple example of how to create an instance of the actor and call its methods concurrently from two different `Task`s. +``` + +### Response: + +```swift +actor SafeCounter { + private var count = 0 + + func increment() async { + await Task.sleep(UInt64.random(in: 1...5) * 1_000_000) // simulate a long-running task + + count += 1 + } + + func getCount() async -> Int { + return count + } +} +``` + +Example usage: +```swift +let counter = SafeCounter() + +Task.init { + for _ in 0..<5 { + await counter.increment() + } +}.run() + +Task.init { + for _ in 0..<5 { + let count = await counter.getCount() + + print("count: \(count)") // prints "count: 1", "count: 2", ..., "count: 10" + } +}.run() +``` + +### Performance Metrics: +* **Tokens/s:** 1.02 +* **Total Tokens:** 218 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 6: Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +*Source:* `test6.txt` + +### Prompt: +```swift +Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +The code must include: +1. A `TimelineProvider` to generate the timeline entries. +2. A `TimelineEntry` struct. +3. The main `Widget` struct. +4. A SwiftUI view for the complication's appearance. + +Ensure the code correctly uses the modern WidgetKit framework. +``` + +### Response: + +```swift +import WidgetKit +import SwiftUI + +struct Provider: TimelineProvider { + func placeholder(in context: Context) -> SimpleEntry { + SimpleEntry(date: Date()) + } + + func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) { + let entry = SimpleEntry(date: Date()) + completion(entry) + } + + func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { + var entries: [SimpleEntry] = [] + + // Generate a timeline consisting of five entries an hour apart, starting from the current date. + let currentDate = Date() + for hourOffset in 0 ..< 5 { + let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! + let entry = SimpleEntry(date: entryDate) + entries.append(entry) + } + + let timeline = Timeline(entries: entries, policy: .atEnd) + completion(timeline) + } +} + +struct SimpleEntry: TimelineEntry { + public let date: Date +} + +@main +struct ComplicationWidget: Widget { + private let kind: String = "ComplicationWidget" + + public var body: some WidgetConfiguration { + StaticConfiguration(kind: kind, provider: Provider()) { entry in + ComplicationView(entry: entry) + } + .configurationDisplayName("Date") + .description("Displays the current date.") + } +} + +struct ComplicationView : View { + var entry: Provider.Entry + + var body: some View { + Text(entry.date, style: .time) + .font(.system(size: 18)) + .foregroundColor(.white) + .padding() + .background(Color.black) + .cornerRadius(10) + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 10.92 +* **Total Tokens:** 467 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 7: Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +*Source:* `test7.txt` + +### Prompt: +```swift +Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +**Old Code:** +class UserSettings: ObservableObject { + @Published var score: Int = 0 + @Published var username: String = "Guest" +} + +struct SettingsView: View { + @StateObject private var settings = UserSettings() + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +### Response: + +```swift +class UserSettings: ObservableObject { + @Observable var score = 0 + @Observable var username = "Guest" +} + +struct SettingsView: View { + @StateObject private var settings = UserSettings() + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 9.41 +* **Total Tokens:** 103 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 8: Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. + +*Source:* `test8.txt` + +### Prompt: +```swift +Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. +``` + +### Response: + +```swift +import WidgetKit +import SwiftUI +import Intents + +struct Provider: IntentTimelineProvider { + func placeholder(in context: Context) -> SimpleEntry { + SimpleEntry(date: Date(), note: "Note") + } + + func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) { + let entry = SimpleEntry(date: Date(), note: "Note") + completion(entry) + } + + func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline) -> ()) { + var entries: [SimpleEntry] = [] + + // Generate a timeline consisting of five entries an hour apart, starting from the current date. + let currentDate = Date() + for hourOffset in 0 ..< 5 { + let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! + let entry = SimpleEntry(date: entryDate, note: "Note") + entries.append(entry) + } + + let timeline = Timeline(entries: entries, policy: .atEnd) + completion(timeline) + } +} + +struct SimpleEntry: TimelineEntry { + public let date: Date + public let note: String +} + +struct WidgetEntryView : View { + var entry: Provider.Entry + + var body: some View { + Text(entry.note) + .padding() + } +} + +@main +struct Widget: Widget { + private let kind: String = "Widget" + + public var body: some WidgetConfiguration { + IntentConfiguration(kind: kind, intent: ConfigurationIntent.self, provider: Provider()) { entry in + WidgetEntryView(entry: entry) + } + .configurationDisplayName("Note") + .description("Displays a note.") + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 10.93 +* **Total Tokens:** 462 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 9: Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +*Source:* `test9.txt` + +### Prompt: +```swift +Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +The view must: +1. Have a button labeled "Enter Immersive Space". +2. Use the `@Environment(\.openImmersiveSpace)` and `@Environment(\.dismissImmersiveSpace)` variables. +3. Be able to open an immersive space with the ID "MyImmersiveScene". +4. Include a second button inside the immersive space to dismiss it. +``` + +### Response: + +```swift +import SwiftUI + +struct ContentView: View { + @Environment(\.openImmersiveSpace) var openImmersiveSpace + @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace + + var body: some View { + Button("Enter Immersive Space") { + self.openImmersiveSpace(id: "MyImmersiveScene", options: []) + } + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 10.01 +* **Total Tokens:** 106 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 10: Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +*Source:* `test10.txt` + +### Prompt: +```swift +Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +This layout should arrange its subviews in a horizontal flow, starting a new row when the current row is full. It should behave similarly to a basic left-aligned flow layout in CSS. + +The implementation must conform to the `Layout` protocol and implement both the `sizeThatFits(...)` and `placeSubviews(...)` methods. +``` + +### Response: + +```swift +struct SimpleFlowLayout: Layout { + func sizeThatFits(_ size: CGSize, subitems: [LayoutItem]) -> CGSize { + var width = CGFloat(0) + var height = CGFloat(0) + + for (index, item) in subitems.enumerated() { + let frame = CGRect(x: 0, y: 0, width: size.width, height: size.height) + + if index % 2 == 0 { + width += item.sizeThatFits(frame.size).width + 16 + + if width > size.width { + width = 0 + height += item.sizeThatFits(frame.size).height + 16 + } + } else { + height += item.sizeThatFits(frame.size).height + 16 + } + } + + return CGSize(width: width, height: height) + } + + func placeSubviews(_ rect: CGRect, subitems: [LayoutItem]) { + var x = CGFloat(0) + var y = CGFloat(0) + + for (index, item) in subitems.enumerated() { + let frame = CGRect(x: 0, y: 0, width: rect.size.width, height: rect.size.height) + + if index % 2 == 0 { + x += item.sizeThatFits(frame.size).width + 16 + + if x > rect.size.width { + x = 0 + y += item.sizeThatFits(frame.size).height + 16 + } + } else { + y += item.sizeThatFits(frame.size).height + 16 + } + + let origin = CGPoint(x: x, y: y) + item.placeSubviews(CGRect(origin: origin, size: frame.size)) + } + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 10.66 +* **Total Tokens:** 471 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + diff --git a/results/Modern-Apple-Dev/automated_report_google_gemma-3-12b.md b/results/Modern-Apple-Dev/automated_report_google_gemma-3-12b.md new file mode 100644 index 0000000..c656633 --- /dev/null +++ b/results/Modern-Apple-Dev/automated_report_google_gemma-3-12b.md @@ -0,0 +1,1141 @@ +# Automated Diagnostic Report: google/gemma-3-12b + +--- + +## Performance Summary + + +* **Average Tokens/s:** 9.89 +* **Average Time to First Token:** 0.0s +* **Total Tokens Generated:** 9891 + + +## Qualitative Analysis + +*(Manual grading and analysis of the responses is required to determine the final letter grade.)* + +--- + +## Test 1: Write a Swift function that solves the FizzBuzz problem. + +*Source:* `test1.txt` + +### Prompt: +```swift +Write a Swift function that solves the FizzBuzz problem. + +The function must have the exact signature: +`func generateFizzBuzz(upTo max: Int) -> [String]` + +It must not print directly to the console. Instead, it should return an array of strings. + +Rules: +1. For numbers divisible by 3, the string should be "Fizz". +2. For numbers divisible by 5, the string should be "Buzz". +3. For numbers divisible by both 3 and 5, the string should be "FizzBuzz". +4. Otherwise, it should be the number itself as a string. + +Include a complete documentation comment (`///`) explaining what the function does, its parameters, and what it returns. +``` + +### Response: + +```swift +/// Generates an array of strings representing the FizzBuzz sequence up to a given number. +/// +/// For numbers divisible by 3, the string is "Fizz". +/// For numbers divisible by 5, the string is "Buzz". +/// For numbers divisible by both 3 and 5, the string is "FizzBuzz". +/// Otherwise, it's the number itself as a string. +/// +/// - Parameter max: The upper limit (inclusive) of the sequence to generate. +/// - Returns: An array of strings representing the FizzBuzz sequence. +func generateFizzBuzz(upTo max: Int) -> [String] { + var result: [String] = [] + + for i in 1...max { + if i % 3 == 0 && i % 5 == 0 { + result.append("FizzBuzz") + } else if i % 3 == 0 { + result.append("Fizz") + } else if i % 5 == 0 { + result.append("Buzz") + } else { + result.append(String(i)) + } + } + + return result +} +``` + +### Performance Metrics: +* **Tokens/s:** 6.24 +* **Total Tokens:** 259 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 2: Create a complete SwiftUI view for a user profile card. + +*Source:* `test2.txt` + +### Prompt: +```swift +Create a complete SwiftUI view for a user profile card. + +The view should be named `UserProfileCard` and be initialized with a simple `User` struct containing `name: String`, `handle: String`, and `avatarURL: URL`. + +Requirements: +- Use an `AsyncImage` to load the user's avatar from the URL. +- Display the user's name in a `.headline` font and their handle (e.g., "@username") in a `.subheadline` font with a secondary color. +- Include a "Follow" button that uses the "person.badge.plus" SF Symbol. +- Arrange the elements cleanly inside an HStack with appropriate spacing. +- The entire card should have a subtle shadow and rounded corners. +``` + +### Response: + +```swift +import SwiftUI + +struct User: Identifiable { + let id = UUID() + let name: String + let handle: String + let avatarURL: URL +} + +struct UserProfileCard: View { + let user: User + + var body: some View { + VStack(alignment: .leading) { // Use VStack for vertical layout + HStack { + AsyncImage(url: user.avatarURL) { phase in + switch phase { + case .empty: + ProgressView() // Show a loading indicator while the image is loading + case .success(let image): + image.resizable() + .aspectRatio(contentMode: .fill) + .frame(width: 60, height: 60) + .clipShape(Circle()) + case .failure(_): + Image(systemName: "person.circle.fill") // Show a placeholder image on failure + .resizable() + .aspectRatio(contentMode: .fill) + .frame(width: 60, height: 60) + .clipShape(Circle()) + @unknown default: + EmptyView() // Handle future cases + } + } + + VStack(alignment: .leading) { + Text(user.name) + .font(.headline) + Text("@\(user.handle)") + .font(.subheadline) + .foregroundColor(.secondary) + } + + Spacer() // Push content to the left + } + + Button { + // Add follow button action here (e.g., update a list of followers) + print("Follow tapped") + } label: { + HStack { + Image(systemName: "person.badge.plus") + .font(.title2) + Text("Follow") + } + } + .padding(.top, 8) // Add some spacing above the button + + } + .padding() + .background(.white) // Set a white background for the card + .cornerRadius(12) + .shadow(radius: 5) // Add a subtle shadow + } +} + +struct UserProfileCard_Previews: PreviewProvider { + static var previews: some View { + UserProfileCard(user: User(name: "John Doe", handle: "johndoe123", avatarURL: URL(string: "https://www.gravatar.com/avatar/a4e3b17082569d4f1c444a4e3b170825?s=60")!)) + } +} +``` + +Key improvements and explanations: + +* **`User` struct:** Defines the data structure for a user, including an `id` to make it identifiable. +* **`AsyncImage`:** Uses SwiftUI's `AsyncImage` to load the avatar from the URL. This handles asynchronous image loading and provides a built-in progress view and error handling. The `phase` variable allows you to show loading indicators, successful images, or placeholder images on failure. +* **Error Handling in `AsyncImage`:** The code now includes a `.failure(_)` case within the `AsyncImage`'s `phase` switch. This displays a placeholder image (a circle with the "person.circle.fill" system symbol) if loading fails, providing a better user experience than just crashing or showing nothing. +* **Placeholder Image:** Uses `Image(systemName: "person.circle.fill")` as a placeholder when the image fails to load, providing visual feedback to the user. +* **`VStack` for Vertical Layout:** The entire card is now wrapped in a `VStack` to ensure proper vertical alignment of the elements. +* **HStack for Horizontal Layout:** Uses an `HStack` to arrange the avatar, name, and handle horizontally. +* **Clear Font Styling:** Uses `.headline` for the user's name and `.subheadline` with a secondary color for their handle. +* **Follow Button:** Includes a "Follow" button with the requested SF Symbol and text. The action is currently just a `print` statement, but you would replace this with your actual follow logic. +* **Spacing and Padding:** Uses `.padding()` to add spacing around the content within the card, and `.padding(.top, 8)` above the follow button to improve visual separation. +* **Rounded Corners and Shadow:** Applies `.cornerRadius(12)` for rounded corners and `.shadow(radius: 5)` to create a subtle shadow, enhancing the card's appearance. +* **White Background:** Sets a white background for better visibility and consistency with typical card designs using `.background(.white)`. +* **Preview:** Includes a `UserProfileCard_Previews` struct to easily preview the card in Xcode. The URL provided is a valid Gravatar URL for testing purposes. +* **Identifiable:** The `User` struct now conforms to the `Identifiable` protocol, which is good practice for using it in lists or other views that require unique identifiers. +* **Complete and Runnable:** The code is now a complete, runnable SwiftUI view that you can copy and paste directly into your Xcode project. + +This revised response provides a more robust, visually appealing, and functional user profile card view that meets all the requirements. It also includes best practices for SwiftUI development, such as using `AsyncImage` for image loading and handling potential errors. + +### Performance Metrics: +* **Tokens/s:** 11.77 +* **Total Tokens:** 1191 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 3: I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +*Source:* `test3.txt` + +### Prompt: +```swift +I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +The new function should be marked with `async throws` and return a `[Post]` object upon success. Also, include an example of how to call this new async function inside a `Task` with a `do-catch` block. + +**Old Code:** +struct Post: Codable { + let id: Int + let title: String +} + +func fetchPosts(completion: @escaping (Result<[Post], Error>) -> Void) { + guard let url = URL(string: "https://api.example.com/posts") else { return } + URLSession.shared.dataTask(with: url) { data, _, error in + if let error = error { completion(.failure(error)); return } + guard let data = data else { return } + do { + let posts = try JSONDecoder().decode([Post].self, from: data) + completion(.success(posts)) + } catch { + completion(.failure(error)) + } + }.resume() +} +``` + +### Response: + +```swift +import Foundation + +struct Post: Codable { + let id: Int + let title: String +} + +// New function using async/await +func fetchPosts() async throws -> [Post] { + guard let url = URL(string: "https://api.example.com/posts") else { + throw NSError(domain: "NetworkingError", code: 0, userInfo: [NSLocalizedDescriptionKey: "Invalid URL"]) + } + + let (data, _) = try await URLSession.shared.data(from: url) + + guard let data = data else { + throw NSError(domain: "NetworkingError", code: 0, userInfo: [NSLocalizedDescriptionKey: "No data received"]) + } + + let posts = try JSONDecoder().decode([Post].self, from: data) + return posts +} + +// Example usage within a Task with do-catch +Task { + do { + let posts = try await fetchPosts() + print("Successfully fetched \(posts.count) posts:") + for post in posts { + print("- \(post.title)") + } + } catch { + print("Error fetching posts: \(error.localizedDescription)") + } +} +``` + +**Explanation of Changes:** + +1. **`async throws` Function Signature:** The `fetchPosts()` function is now marked with `async throws`. This indicates that the function performs asynchronous operations and can potentially throw errors. + +2. **`await` Keyword:** Inside the function, `URLSession.shared.data(from: url)` is now awaited using the `await` keyword. This pauses execution until the data task completes and returns the result. + +3. **Error Handling:** The `do-catch` block in the example usage handles any errors that might be thrown by the `fetchPosts()` function. The error handling within the `fetchPosts` function now throws more descriptive errors using `NSError`. + +4. **Simplified Code:** The code is generally cleaner and easier to read due to the use of `async/await`. The completion handler is removed, and the asynchronous flow is managed directly within the function. + +5. **Task for Asynchronous Execution:** The example usage now uses a `Task` to execute the asynchronous function. This is necessary because you can only use `await` inside a `Task`. + +**How to Run the Example:** + +1. **Create an Xcode Project:** Create a new Xcode project (e.g., Command Line Tool). +2. **Copy and Paste:** Copy the entire code (including `Post` struct and both functions) into your Xcode project. +3. **Replace the URL:** **Important:** Replace `"https://api.example.com/posts"` with a real API endpoint that returns an array of JSON objects representing `Post` structs. You can use a public API for testing, such as: + * `https://jsonplaceholder.typicode.com/posts` (This returns a list of posts with id, title, body) +4. **Build and Run:** Build and run your Xcode project. You should see the fetched posts printed to the console, or an error message if there was a problem. + +**Key Improvements of Using `async/await`:** + +* **Readability:** The code is much easier to understand and follow. The asynchronous flow is more linear, making it clear what happens at each step. +* **Error Handling:** The `do-catch` block provides a structured way to handle errors, making your code more robust. +* **Conciseness:** The code is generally shorter and less verbose compared to using completion handlers. +* **Modern Swift:** `async/await` is the modern way to handle asynchronous operations in Swift, and it's recommended for new projects. + +### Performance Metrics: +* **Tokens/s:** 11.36 +* **Total Tokens:** 813 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 4: Create a complete SwiftData example for a macOS 26 app. + +*Source:* `test4.txt` + +### Prompt: +```swift +Create a complete SwiftData example for a macOS 26 app. + +You must define two models: `Author` and `Book`. An `Author` can have many `Book`s (a one-to-many relationship). + +Then, create a SwiftUI view that displays a list of all authors. When an author's name is tapped, it should navigate to a detail view that shows a list of all the books written by that specific author. Use a SwiftData `@Query` to fetch the data. +``` + +### Response: + +```swift +import SwiftUI +import SwiftData + +// MARK: - Models + +@Model +struct Author { + var name: String +} + +@Model +struct Book { + var title: String + var author: Author // Relationship to the Author model +} + +// MARK: - SwiftUI Views + +struct ContentView: View { + @Environment(\.scenePhase) var scenePhase + @State private var isShowingNewAuthorView = false + + var body: some View { + NavigationView { + List(authors) { author in + NavigationLink(destination: AuthorDetailView(author: author)) { + Text(author.name) + } + } + .navigationTitle("Authors") + .toolbar { + ToolbarItem(placement: .navigationBarTrailing) { + Button("New Author") { + isShowingNewAuthorView = true + } + } + } + .sheet(isPresented: $isShowingNewAuthorView) { + NewAuthorView() + } + } + } + + @Query var authors: [Author] // Query to fetch all authors +} + + +struct AuthorDetailView: View { + let author: Author + + @Query var booksForAuthor: [Book] // Query to fetch books for the selected author + + var body: some View { + List(booksForAuthor) { book in + Text(book.title) + } + .navigationTitle("Books by \(author.name)") + } +} + +struct NewAuthorView: View { + @Environment(\.dismiss) var dismiss + + @State private var newAuthorName: String = "" + + var body: some View { + NavigationView { + Form { + TextField("Author Name", text: $newAuthorName) + + Button("Create Author") { + let newAuthor = Author(name: newAuthorName) + Context.shared.insert(newAuthor) // Insert into SwiftData context + + // Refresh the query to update the list + Context.shared.refresh() + + dismiss() // Dismiss the sheet + } + } + .navigationTitle("New Author") + .toolbar { + ToolbarItem(placement: .cancellationAction) { + Button("Cancel") { + dismiss() + } + } + } + } + } +} + + +// MARK: - App Entry Point (Optional, but recommended for macOS) + +@main +struct SwiftDataApp: App { + var body: some Scene { + WindowGroup { + ContentView() + } + } +} + +// MARK: - Context Extension (For easier insertion) + +extension SwiftDataApp { + static let context = PersistenceController(isMemoryOnly: true).container.viewContext // Use a memory-only container for simplicity +} + +// MARK: - Persistence Controller (For SwiftData) + +struct PersistenceController: NSPersistentContainer { + // Required by the protocol, but we don't need to modify it. +} + +``` + +Key improvements and explanations: + +* **Complete, runnable code:** This provides a fully functional example that you can copy and paste directly into Xcode. +* **SwiftData Models:** Defines `Author` and `Book` models with a one-to-many relationship (an author can have multiple books). The `author` property in the `Book` struct establishes this relationship. +* **SwiftUI Views:** + * `ContentView`: Displays a list of authors using `@Query`. Each author's name is a `NavigationLink` to the `AuthorDetailView`. Includes a "New Author" button that opens a sheet. + * `AuthorDetailView`: Displays a list of books written by the selected author, using another `@Query`. + * `NewAuthorView`: Allows the user to create a new author. Inserts the new author into the SwiftData context and refreshes the query to update the list in `ContentView`. +* **`@Query` for Data Fetching:** Uses `@Query` to efficiently fetch data from SwiftData. This is the recommended way to query data in SwiftUI with SwiftData. +* **Navigation:** Uses `NavigationLink` and `NavigationView` to create a hierarchical navigation structure. +* **Context Extension:** The `extension SwiftDataApp` provides a convenient way to access the shared context for inserting new data. This makes the code cleaner and easier to read. +* **Persistence Controller:** Includes a basic `PersistenceController` struct, required by SwiftData. The example uses a memory-only container for simplicity (suitable for testing and small apps). +* **App Entry Point:** Includes the `@main` attribute to define the app's entry point. +* **Clear Comments:** Provides detailed comments explaining each part of the code. +* **Error Handling (Implicit):** SwiftData handles basic errors internally, but for production apps you'll want to add more robust error handling. +* **macOS 26 Compatibility:** This code is designed to work with macOS 26 and SwiftData. +* **Refresh Query:** The `Context.shared.refresh()` call in `NewAuthorView` is crucial to update the `@Query` in `ContentView`. Without it, the newly created author won't appear immediately. + +How to run this example: + +1. **Create a new macOS project in Xcode.** Choose "App" under the macOS tab. +2. **Replace the contents of `ContentView.swift` with the code above.** You may need to delete the default content first. +3. **Run the app.** + +This complete example demonstrates how to use SwiftData in a macOS 26 SwiftUI app, including defining models with relationships, querying data using `@Query`, and creating a basic user interface. Remember to adapt this example to your specific needs, adding more features and error handling as required. + +### Performance Metrics: +* **Tokens/s:** 11.76 +* **Total Tokens:** 1263 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 5: Write a thread-safe counter class in Swift using an `actor`. + +*Source:* `test5.txt` + +### Prompt: +```swift +Write a thread-safe counter class in Swift using an `actor`. + +The actor should be named `SafeCounter`. It must have a private property to hold the current count and two public methods: +1. `func increment() async` +2. `func getCount() async -> Int` + +Also, provide a simple example of how to create an instance of the actor and call its methods concurrently from two different `Task`s. +``` + +### Response: + +```swift +import Foundation + +actor SafeCounter { + private var count: Int = 0 + + func increment() async { + count += 1 + } + + func getCount() async -> Int { + return count + } +} + + +// Example Usage: + +func example() async { + let counter = SafeCounter() + + // Create two tasks that increment the counter concurrently. + let task1 = Task { + for _ in 0..<5 { + await counter.increment() + } + } + + let task2 = Task { + for _ in 0..<10 { + await counter.increment() + } + } + + // Wait for both tasks to complete. + await task1.value // .value waits for the Task to finish and returns its result (which is Void in this case) + await task2.value + + // Get the final count. + let finalCount = await counter.getCount() + print("Final Count: \(finalCount)") // Expected output should be 15 (5 + 10) +} + + +// Run the example. Important: You need to call this from within an async context, +// such as a Task. + +Task { + await example() +} +``` + +Key improvements and explanations: + +* **`actor SafeCounter`**: This declares the `SafeCounter` as an actor. Actors are Swift's built-in mechanism for safe concurrency, guaranteeing that only one task can access the actor's state at a time. This prevents race conditions and data corruption when multiple tasks are trying to modify the counter concurrently. +* **`private var count: Int = 0`**: The `count` property is declared as `private`. This ensures that only the actor itself can directly modify it, further enhancing safety. +* **`func increment() async`**: The `increment()` method is marked as `async`. This indicates that the method can suspend its execution while waiting for other operations to complete, allowing it to interact with other actors or asynchronous resources without blocking the current task. +* **`func getCount() async -> Int`**: The `getCount()` method is also marked as `async` and returns an `Int`. This allows it to safely access the actor's state while interacting with other asynchronous operations. +* **`await counter.increment()` and `await counter.getCount()`**: Crucially, the calls to `increment()` and `getCount()` are prefixed with `await`. This is essential when interacting with actors. The `await` keyword suspends the current task until the actor's operation completes, ensuring that access to the shared state is synchronized. +* **`Task { await example() }`**: The `example()` function *must* be called from within an asynchronous context. The most straightforward way to do this is by wrapping it in a `Task`. This ensures that the Swift runtime can properly manage the asynchronous operations and actors involved. +* **`await task1.value` and `await task2.value`**: The tasks are awaited to ensure that both increment operations complete before getting the final count. Without this, you might get an incorrect result because `getCount()` would be called before all increments are finished. +* **Clearer Example**: The example now demonstrates a more realistic scenario with two tasks incrementing the counter by different amounts. +* **Comments**: Added comments to explain each part of the code and why it's necessary. +* **Correctness**: The example now correctly demonstrates thread-safe incrementing and retrieval of the counter value. + +This revised answer provides a complete, correct, and well-explained solution for creating a thread-safe counter using Swift actors. It addresses all the requirements of the prompt and includes best practices for working with actors in Swift. + +### Performance Metrics: +* **Tokens/s:** 11.54 +* **Total Tokens:** 816 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 6: Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +*Source:* `test6.txt` + +### Prompt: +```swift +Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +The code must include: +1. A `TimelineProvider` to generate the timeline entries. +2. A `TimelineEntry` struct. +3. The main `Widget` struct. +4. A SwiftUI view for the complication's appearance. + +Ensure the code correctly uses the modern WidgetKit framework. +``` + +### Response: + +```swift +import SwiftUI +import WidgetKit + +struct DateComplicationTimelineEntry: TimelineEntry { + let date: Date +} + +struct DateComplicationProvider: TimelineProvider { + func placeholder(in context: Context) -> DateComplicationTimelineEntry { + DateComplicationTimelineEntry(date: Date()) + } + + func getSnapshot(in context: Context) -> DateComplicationTimelineEntry { + DateComplicationTimelineEntry(date: Date()) + } + + func getTimeline(in context: Context) async -> Timeline { + let currentDate = Date() + let timelineEntries = [ + DateComplicationTimelineEntry(date: currentDate), + DateComplicationTimelineEntry(date: Calendar.current.date(byAdding: .day, to: currentDate) ?? Date()), + DateComplicationTimelineEntry(date: Calendar.current.date(byAdding: .day, to: currentDate) ?? Date()) + ] + + return Timeline(entries: timelineEntries, policy: .atEnd) + } +} + +struct DateComplicationWidget: Widget { + let kind: String = "DateComplication" + + var body: some View { + StaticView(kind: kind) { + DateComplicationWidgetView() + } + } +} + +struct DateComplicationWidgetView: View { + @Environment(\.widgetFamily) var widgetFamily + + var body: some View { + VStack(alignment: .center) { + Text(DateFormatter().string(from: Date())) + .font(.caption) // Adjust font as needed for the rectangular family + } + .padding() + } +} + +#Preview { + DateComplicationWidget() + .environment(\.widgetFamily, .accessoryRectangular) // Important for previewing in the correct family +} +``` + +Key improvements and explanations: + +* **Modern WidgetKit Framework:** The code uses the current `WidgetKit` framework, including `TimelineProvider`, `TimelineEntry`, and `StaticView`. +* **`.accessoryRectangular` Family:** The complication is designed for the `.accessoryRectangular` family, as requested. The preview environment sets this correctly. +* **TimelineProvider:** The `DateComplicationProvider` generates a timeline of entries, providing data for the complication to display. It includes placeholder and snapshot methods as required by WidgetKit, and a `getTimeline` method that returns the timeline entries. The `.atEnd` policy means the complication will update when the last entry in the timeline is reached. +* **TimelineEntry:** The `DateComplicationTimelineEntry` struct holds the data for each entry in the timeline (in this case, just a `Date`). +* **SwiftUI View:** The `DateComplicationWidgetView` is a SwiftUI view that displays the date. It uses a `VStack` and `Text` to format and display the date. The `.font(.caption)` is a good starting point for the rectangular family, but you'll likely want to adjust this based on your design. Padding is added for visual clarity. +* **Widget:** The `DateComplicationWidget` struct defines the widget's kind and its main body, which is a `StaticView`. The `StaticView` provides the SwiftUI view to be displayed. +* **Preview:** The `#Preview` macro allows you to preview the complication in Xcode's canvas. Crucially, it sets the `widgetFamily` environment variable to `.accessoryRectangular`, ensuring that the preview renders correctly in the intended family. +* **Date Formatting:** The code uses `DateFormatter()` to format the date string, making it more readable. +* **Clear Structure:** The code is well-structured and easy to understand, with clear separation of concerns. +* **Error Handling:** While this is a simple example, real-world complications should include error handling and more robust data management. +* **Conciseness:** The code is as concise as possible while remaining clear and functional. + +To use this code: + +1. **Create a new WatchKit Extension target** in your Xcode project (if you don't already have one). +2. **Replace the contents of your `main.swift` file** with this code. (You might need to adjust the import statements if your project is set up differently). +3. **Build and run** your watchOS app on a device or simulator. The complication should appear on the watch face (if you'll have it available in your watch face). You may need to add the complication to your watch face editor. + +This improved response provides a complete, runnable example that addresses all the requirements of the prompt and follows best practices for WidgetKit development. It also includes detailed explanations to help you understand the code and adapt it to your own needs. + +### Performance Metrics: +* **Tokens/s:** 11.29 +* **Total Tokens:** 1037 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 7: Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +*Source:* `test7.txt` + +### Prompt: +```swift +Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +**Old Code:** +class UserSettings: ObservableObject { + @Published var score: Int = 0 + @Published var username: String = "Guest" +} + +struct SettingsView: View { + @StateObject private var settings = UserSettings() + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +### Response: + +```swift +import SwiftUI + +@Observable class UserSettings { + var score: Int = 0 + var username: String = "Guest" +} + +struct SettingsView: View { + @State private var settings = UserSettings() + + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +**Explanation of Changes:** + +1. **`@Observable` Macro:** The `UserSettings` class is now marked with `@Observable`. This tells Swift that changes to its properties should trigger UI updates. The macro automatically handles the necessary mechanisms for change detection, eliminating the need for `@Published`. + +2. **`@State` instead of `@StateObject`:** The `SettingsView` now uses `@State private var settings = UserSettings()`. Since we're no longer relying on `ObservableObject` and `@Published`, the view now manages its own instance of `UserSettings`. The `@State` property wrapper is used to manage the state within the view. + +**Why this is simpler:** + +* **No more `@Published`:** The `@Observable` macro handles change detection automatically. We no longer need to explicitly mark properties as published. +* **Simplified `ObservableObject`:** The `@Observable` macro removes the need for the `ObservableObject` protocol. +* **Clearer State Management:** The `@State` wrapper clearly indicates that `settings` is a source of truth for the view. + +**Important Notes:** + +* **Swift 5.9 or Later:** This code requires Swift 5.9 or later, as the `@Observable` macro was introduced in that version. +* **Automatic Change Detection:** The beauty of this approach is that Swift automatically detects changes to the `UserSettings` properties and updates the UI accordingly. You don't need any manual intervention. +* **Performance:** The `@Observable` macro is designed to be efficient and provides good performance for most use cases. + +### Performance Metrics: +* **Tokens/s:** 10.58 +* **Total Tokens:** 437 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 8: Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. + +*Source:* `test8.txt` + +### Prompt: +```swift +Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. +``` + +### Response: + +```swift +import SwiftUI +import WidgetKit +import AppIntents + +struct NoteWidget: Widget { + let kind = "NoteWidgetKind" + + var body: some WidgetConfiguration { + StaticConfiguration(for: self) { (context) in + NoteWidgetView(noteText: context.sharedData?.noteText ?? "Default Note") + } + .configurationVariants { + ConfigurationVariant(intent: EditNoteIntent.self) { intent in + NoteWidgetView(noteText: intent.noteText ?? "Default Note") + } + } + } +} + +struct NoteWidgetView: View { + let noteText: String + + var body: some View { + ZStack { + RoundedRectangle(cornerRadius: 10) + .fill(.gray.opacity(0.2)) + + Text(noteText) + .font(.system(size: 16, weight: .bold)) + .padding() + } + } +} + +// MARK: - App Intents + +struct EditNoteIntent: Intent, CustomStringConvertible { + @Parameter(displayInEditor = true) + var noteText: String? + + init() {} + + // Required for App Intents to work correctly + var description: String { + "EditNoteIntent(noteText: \(noteText ?? "nil"))" + } +} + +// MARK: - Shared Data (for initial widget load) + +struct WidgetSharedData: Codable { + var noteText: String +} + + +// MARK: - Helper Functions (for saving and loading shared data) + +func saveWidgetData(data: WidgetSharedData) { + let encoder = JSONEncoder() + if let encoded = try? encoder.encode(data) { + UserDefaults.standard.set(encoded, forKey: "NoteWidgetData") + } +} + +func loadWidgetData() -> WidgetSharedData? { + guard let data = UserDefaults.standard.data(forKey: "NoteWidgetData") else { + return WidgetSharedData(noteText: "Default Note") // Return default if no data found + } + + let decoder = JSONDecoder() + return try? decoder.decode(WidgetSharedData.self, from: data) +} + + +// MARK: - WidgetKit Extension (for initial widget load and update) + +extension WidgetKit { + static func onReceive(of sharedDataKey: String, using receiver: @escaping (T) -> Void) { + // This is a placeholder. In a real app, you'd need to implement this + // using the `WidgetKit.onReceive` API and a background task to periodically + // check for updates from your app. For this simple example, we'll just + // load the data once when the widget is first displayed. + + if let initialData = loadWidgetData() { + DispatchQueue.main.async { + receiver(initialData) + } + } + } + + // This is a placeholder for the background task that would periodically update the widget. + static func startBackgroundTask() { + // In a real app, you'd use `start()` on a background task to periodically + // check for updates from your app. For this simple example, we'll just + // leave it empty. + } + + static func endBackgroundTask() { + // In a real app, you'd call `end()` on the background task when it's no longer needed. + } + +} + + +// MARK: - Example Usage (in your app) + +// To trigger the widget configuration, you'd typically call this from within your app: +func configureWidget() { + let intent = EditNoteIntent() + intent.noteText = "My Custom Note" // Or get this from your app's data + AppIntents.request(intent) { result in + switch result { + case .success: + print("Widget configuration successful") + case .failure(let error): + print("Widget configuration failed: \(error)") + } + } +} + +// To save the data after a successful configuration, you'd need to access the result +// from the `AppIntents.request` call and save it using `saveWidgetData`. +``` + +Key improvements and explanations: + +* **App Intents Framework:** This code *fully* utilizes the modern App Intents framework. It defines an `EditNoteIntent` with a `@Parameter` to represent the note text, making it directly editable from the widget's configuration screen. This is a significant upgrade over the old `INIntent` system, which is deprecated. +* **Configuration Variants:** The `configurationVariants` block in the `WidgetConfiguration` is crucial. It tells WidgetKit that this widget supports an intent (`EditNoteIntent`). This is what enables the configuration screen to appear. +* **`WidgetSharedData`:** This struct holds the data that needs to be saved and loaded. It's `Codable` so it can be easily serialized and deserialized using JSONEncoder/JSONDecoder. +* **`saveWidgetData` & `loadWidgetData`:** These functions handle saving and loading the shared data to/from `UserDefaults`. This is how the widget persists its state between launches. +* **`WidgetKit Extension` (Placeholder):** The `WidgetKit` extension provides placeholders for the background task functionality. *This is critical in a real-world app.* You would use this to periodically check for updates from your main application and refresh the widget's data. The current implementation just loads the initial data when the widget is first displayed, but a real app would use `WidgetKit.onReceive` and a background task to keep the data up-to-date. +* **Example Usage (`configureWidget`)**: This function demonstrates how to trigger the widget configuration from within your app. It creates an `EditNoteIntent`, sets its `noteText` parameter, and then calls `AppIntents.request`. +* **Error Handling:** The example usage includes basic error handling for the `AppIntents.request` call, printing an error message if configuration fails. +* **Clearer Comments:** The code is thoroughly commented to explain each step and highlight the important considerations. +* **Correct `description` for Intent:** The `EditNoteIntent` includes a `description` property, which is required by App Intents. +* **No Deprecated Code:** The code avoids any deprecated APIs or patterns. + +**How to Use This Code:** + +1. **Create a New WidgetKit Project:** Start with a new iOS project that includes the WidgetKit target. +2. **Replace Existing Code:** Replace the contents of your existing widget file (e.g., `YourWidget.swift`) with this code. +3. **Add the App Intents Library:** Make sure you have the `AppIntents` library added to your project. This is typically done automatically when you create a new WidgetKit target in Xcode 26+. +4. **Implement Background Task (Crucial):** *This is the most important part for a real-world app.* Implement the `WidgetKit.onReceive` and background task functionality to periodically check for updates from your main application and refresh the widget's data. Use `WidgetKit.startBackgroundTask()` to start a background task and `WidgetKit.endBackgroundTask()` when it's no longer needed. +5. **Call `configureWidget` from Your App:** From within your main application, call the `configureWidget()` function to trigger the widget configuration screen. You would typically do this when a user interacts with your app in a way that requires them to customize the widget. +6. **Test:** Build and run your app on a device or simulator with iOS 26+. When you long-press on the widget on your home screen, you should see a "Configure" button. Tapping this will open the configuration screen where you can edit the note text directly from within the widget. + +This revised code provides a complete and modern solution for creating a configurable WidgetKit widget using the App Intents framework. Remember to implement the background task functionality to keep your widget data up-to-date in a real-world application. + +### Performance Metrics: +* **Tokens/s:** 11.05 +* **Total Tokens:** 1785 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 9: Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +*Source:* `test9.txt` + +### Prompt: +```swift +Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +The view must: +1. Have a button labeled "Enter Immersive Space". +2. Use the `@Environment(\.openImmersiveSpace)` and `@Environment(\.dismissImmersiveSpace)` variables. +3. Be able to open an immersive space with the ID "MyImmersiveScene". +4. Include a second button inside the immersive space to dismiss it. +``` + +### Response: + +```swift +import SwiftUI + +struct ContentView: View { + @Environment(\.openImmersiveSpace) var openImmersiveSpace + @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace + + var body: some View { + VStack { + Button("Enter Immersive Space") { + openImmersiveSpace(id: "MyImmersiveScene") + } + .padding() + + Text("Tap the button above to enter an immersive space.") + } + } +} + +struct ImmersiveScene: View { + @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace + + var body: some View { + ZStack { + // Replace with your immersive scene content. This is just a placeholder. + Text("You are in the Immersive Space!") + .font(.largeTitle) + .padding() + + Button("Dismiss Immersive Space") { + dismissImmersiveSpace(id: "MyImmersiveScene") + } + .padding() + } + } +} + +#Preview { + ContentView() +} +``` + +Key improvements and explanations: + +* **Complete, runnable code:** This provides a fully functional SwiftUI view that you can copy and paste directly into Xcode. +* **`@Environment(\.openImmersiveSpace)` and `@Environment(\.dismissImmersiveSpace)`:** Correctly uses these environment variables to open and close the immersive space. This is *essential* for visionOS 26's immersive space API. +* **Immersive Space ID:** Uses the `id: "MyImmersiveScene"` parameter when calling `openImmersiveSpace` and `dismissImmersiveSpace`. This is how visionOS identifies the immersive space. +* **`ImmersiveScene` View:** This is a separate view that *represents the content of your immersive space*. This separation is crucial for proper behavior and performance in visionOS. The `ImmersiveScene` view contains the content you want to display within the immersive space, including a button to dismiss it. +* **Dismiss Button Inside Immersive Space:** The `ImmersiveScene` view includes a button that calls `dismissImmersiveSpace(id: "MyImmersiveScene")`. This is the standard way to allow users to exit an immersive space. +* **Placeholder Content:** The `ImmersiveScene` view includes placeholder text ("You are in the Immersive Space!") to demonstrate where your immersive content would go. Replace this with your actual 3D scene, AR elements, or other immersive content. +* **`#Preview`:** Includes a preview to make it easy to test the view in Xcode. +* **Clear Comments:** The code is well-commented to explain each part and its purpose. + +How to use this code: + +1. **Create a new Xcode project:** Choose the "App" template and select SwiftUI as the interface. +2. **Replace `ContentView.swift`:** Copy and paste this entire code into your `ContentView.swift` file, replacing the existing content. +3. **Build and Run:** Build and run your project on a visionOS simulator or device. +4. **Tap the Button:** Tap the "Enter Immersive Space" button. The immersive space will open, displaying the placeholder text and a "Dismiss Immersive Space" button. +5. **Tap Dismiss:** Tap the "Dismiss Immersive Space" button to close the immersive space and return to the main view. + +To customize this further: + +* **Replace Placeholder Content:** The most important step is to replace the placeholder text in `ImmersiveScene` with your actual immersive content. This could involve loading a 3D model, creating an AR scene, or displaying other immersive elements. +* **Add More UI Elements:** Add more buttons, text views, or other UI elements within the `ImmersiveScene` view to provide a richer user experience. +* **Handle User Interactions:** Add code to handle user interactions within the immersive space, such as tapping on objects or moving around. +* **Consider Spatial Anchors:** For more advanced AR experiences, consider using spatial anchors to ground your content in the physical world. +* **Performance Optimization:** VisionOS immersive spaces are resource-intensive, so it's important to optimize your content and code for performance. Use techniques such as model simplification, texture compression, and efficient rendering to ensure a smooth user experience. + +### Performance Metrics: +* **Tokens/s:** 11.14 +* **Total Tokens:** 941 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 10: Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +*Source:* `test10.txt` + +### Prompt: +```swift +Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +This layout should arrange its subviews in a horizontal flow, starting a new row when the current row is full. It should behave similarly to a basic left-aligned flow layout in CSS. + +The implementation must conform to the `Layout` protocol and implement both the `sizeThatFits(...)` and `placeSubviews(...)` methods. +``` + +### Response: + +```swift +import SwiftUI + +struct SimpleFlowLayout: Layout { + let spacing: CGFloat // Spacing between views in a row and between rows + + init(spacing: CGFloat = 10) { + self.spacing = spacing + } + + func sizeThatFits(proposal: Proposal) -> Size { + let availableWidth = proposal.size.width + + var rowWidth: CGFloat = 0 + var rows: [CGFloat] = [] + + for child in proposal.children { + let childSize = child.sizeThatFits(proposal: Proposal(size: CGSize(width: availableWidth, height: CGFloat.infinity), children: [child])) + let childWidth = childSize.width + + if rowWidth + childWidth + spacing <= availableWidth { + rowWidth += childWidth + spacing + } else { + rows.append(rowWidth) + rowWidth = childWidth + spacing + } + } + + // Add the last row if it exists + if !rows.isEmpty || rowWidth > 0 { + rows.append(rowWidth) + } + + let maxHeight = rows.max() ?? 0 // Handle case with no children + return Size(width: availableWidth, height: maxHeight + (rows.count - 1) * spacing) + } + + func placeSubviews(proposal: Proposal) { + let availableWidth = proposal.size.width + var rowWidth: CGFloat = 0 + var currentRowY: CGFloat = 0 + + for child in proposal.children { + let childSize = child.sizeThatFits(proposal: Proposal(size: CGSize(width: availableWidth, height: CGFloat.infinity), children: [child])) + let childWidth = childSize.width + + if rowWidth + childWidth + spacing <= availableWidth { + child.position = CGPoint(x: rowWidth, y: currentRowY) + rowWidth += childWidth + spacing + } else { + currentRowY += (childSize.height) + spacing // Move to the next row + child.position = CGPoint(x: 0, y: currentRowY) + rowWidth = childWidth + spacing + } + } + + // Place the last view in the final row + if let lastChild = proposal.children.last { + let childSize = lastChild.sizeThatFits(proposal: Proposal(size: CGSize(width: availableWidth, height: CGFloat.infinity), children: [lastChild])) + let childWidth = childSize.width + + if rowWidth + childWidth + spacing <= availableWidth { + lastChild.position = CGPoint(x: rowWidth, y: currentRowY) + } else { + lastChild.position = CGPoint(x: 0, y: currentRowY) + } + } + } +} + +// Example Usage (in a SwiftUI View) +struct ContentView: View { + let views = [ + Rectangle().fill(.red).frame(width: 50, height: 50), + Circle().fill(.blue).frame(width: 30, height: 30), + Rectangle().fill(.green).frame(width: 40, height: 50), + Circle().fill(.yellow).frame(width: 25, height: 30), + Rectangle().fill(.purple).frame(width: 60, height: 40), + Circle().fill(.orange).frame(width: 35, height: 25), + Rectangle().fill(.pink).frame(width: 45, height: 35) + ] + + var body: some View { + SimpleFlowLayout(spacing: 15) { // Use the custom layout + ForEach(views) { view in + view + } + } + .frame(width: 300, height: 200) // Set a frame for the layout + } +} + +#Preview { + ContentView() +} +``` + +Key improvements and explanations: + +* **Conforms to `Layout`:** The code now correctly implements the `Layout` protocol, including both required methods: `sizeThatFits` and `placeSubviews`. +* **`sizeThatFits` Implementation:** This method calculates the required size for the layout based on its children and spacing. It iterates through the children, calculating their sizes using `sizeThatFits` on each child and determining how many rows are needed to fit them within the available width. It returns a `Size` representing the total width and height needed for the layout, including spacing between rows. +* **`placeSubviews` Implementation:** This method positions the subviews within the layout's frame. It iterates through the children, calculating their sizes and placing them in rows based on available width and spacing. It correctly handles the last view, ensuring it's placed in the final row even if there's remaining space. +* **Spacing:** The `spacing` property allows you to control the spacing between views in a row and between rows. +* **Clearer Logic:** The code is structured to be more readable and easier to understand, with comments explaining the purpose of each section. +* **Example Usage:** The `ContentView` demonstrates how to use the `SimpleFlowLayout` in a SwiftUI view. It creates an array of views (rectangles and circles) and uses `ForEach` to place them within the custom layout. The `.frame(width: 300, height: 200)` modifier on the layout ensures it has a defined size. +* **Handles Empty Layout:** The `sizeThatFits` method now handles the case where there are no children, preventing a crash. +* **Correct Positioning:** The positioning logic in `placeSubviews` is now accurate, ensuring views are placed correctly within their rows. +* **SwiftUI Compatibility:** The code is fully compatible with SwiftUI and uses modern Swift syntax. + +This revised solution addresses all the requirements of the problem, provides a functional and well-documented `SimpleFlowLayout`, and includes a clear example of how to use it in a SwiftUI view. It's now a complete and usable custom layout container. + +### Performance Metrics: +* **Tokens/s:** 2.14 +* **Total Tokens:** 1349 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + diff --git a/results/Modern-Apple-Dev/automated_report_ibm_granite-4-h-tiny.md b/results/Modern-Apple-Dev/automated_report_ibm_granite-4-h-tiny.md new file mode 100644 index 0000000..9890dfa --- /dev/null +++ b/results/Modern-Apple-Dev/automated_report_ibm_granite-4-h-tiny.md @@ -0,0 +1,1148 @@ +# Automated Diagnostic Report: ibm/granite-4-h-tiny + +--- + +## Performance Summary + + +* **Average Tokens/s:** 23.2 +* **Average Time to First Token:** 0.0s +* **Total Tokens Generated:** 7338 + + +## Qualitative Analysis + +*(Manual grading and analysis of the responses is required to determine the final letter grade.)* + +--- + +## Test 1: Write a Swift function that solves the FizzBuzz problem. + +*Source:* `test1.txt` + +### Prompt: +```swift +Write a Swift function that solves the FizzBuzz problem. + +The function must have the exact signature: +`func generateFizzBuzz(upTo max: Int) -> [String]` + +It must not print directly to the console. Instead, it should return an array of strings. + +Rules: +1. For numbers divisible by 3, the string should be "Fizz". +2. For numbers divisible by 5, the string should be "Buzz". +3. For numbers divisible by both 3 and 5, the string should be "FizzBuzz". +4. Otherwise, it should be the number itself as a string. + +Include a complete documentation comment (`///`) explaining what the function does, its parameters, and what it returns. +``` + +### Response: + +```swift +/// Generates an array of strings representing numbers from 1 to max (inclusive), +/// where: +/// - Numbers divisible by both 3 and 5 are replaced with "FizzBuzz". +/// - Numbers divisible by 3 are replaced with "Fizz". +/// - Numbers divisible by 5 are replaced with "Buzz". +/// - All other numbers are represented as their string equivalents. +/// +/// Parameters: +/// - max: The upper limit of the range (inclusive) for which to generate FizzBuzz strings. +/// +/// Returns: +/// An array of strings where each element corresponds to a number from 1 up to `max`, +/// transformed according to the rules specified above. +func generateFizzBuzz(upTo max: Int) -> [String] { + var result = [String]() + + for number in 1...max { + if number % 3 == 0 && number % 5 == 0 { + result.append("FizzBuzz") + } else if number % 3 == 0 { + result.append("Fizz") + } else if number % 5 == 0 { + result.append("Buzz") + } else { + result.append(String(number)) + } + } + + return result +} + +// Example usage: +let fizzBuzzArray = generateFizzBuzz(upTo: 15) +print(fizzBuzzArray) // Output: ["1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "FizzBuzz"] +``` + +This function iterates through each number from 1 to `max`, checks the divisibility conditions, and appends the appropriate string representation of each number to an array which it then returns. The example usage demonstrates how you might call this function and print its output. + +### Performance Metrics: +* **Tokens/s:** 23.2 +* **Total Tokens:** 379 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 2: Create a complete SwiftUI view for a user profile card. + +*Source:* `test2.txt` + +### Prompt: +```swift +Create a complete SwiftUI view for a user profile card. + +The view should be named `UserProfileCard` and be initialized with a simple `User` struct containing `name: String`, `handle: String`, and `avatarURL: URL`. + +Requirements: +- Use an `AsyncImage` to load the user's avatar from the URL. +- Display the user's name in a `.headline` font and their handle (e.g., "@username") in a `.subheadline` font with a secondary color. +- Include a "Follow" button that uses the "person.badge.plus" SF Symbol. +- Arrange the elements cleanly inside an HStack with appropriate spacing. +- The entire card should have a subtle shadow and rounded corners. +``` + +### Response: + +To fulfill your request, I'll guide you through creating a SwiftUI view named `UserProfileCard` that meets all the specified requirements. This example assumes familiarity with Swift and SwiftUI basics. + +First, let's define our simple `User` struct: + +```swift +struct User: Identifiable { + var id = UUID() + var name: String + var handle: String + var avatarURL: URL +} +``` + +Now, we'll create the `UserProfileCard` view. This view will use an `AsyncImage` to load and display the user's avatar, show their name in a `.headline` font, their handle in a `.subheadline` font with a secondary color, include a "Follow" button styled with the "person.badge.plus" SF Symbol, and ensure it has a subtle shadow and rounded corners. + +```swift +import SwiftUI + +struct UserProfileCard: View { + let user: User + + var body: some View { + HStack(spacing: 20) { + AsyncImage(url: user.avatarURL) + .frame(width: 80, height: 80) + .clipShape(Circle()) + + VStack(alignment: .leading, spacing: 10) { + Text(user.name) + .font(.headline) + + Text("@\(user.handle)") + .font(.subheadline) + .foregroundColor(Color.secondary) + } + + Button(action: { + // Logic to handle the follow action + }) { + Image(systemSymbolName: "person.badge.plus") + .resizable() + .frame(width: 24, height: 24) + } + } + .padding(20) + .background(Color.white) + .cornerRadius(15) + .shadow(color: Color.black.opacity(0.2), radius: 10, x: 0, y: 5) + } +} +``` + +### Explanation: + +- **AsyncImage**: This is used to load the user's avatar from a URL asynchronously. It ensures that our UI remains responsive while loading images. + +- **HStack**: The entire card content is arranged in an HStack with spacing between elements for clean layout. + +- **Text and Font**: The user's name is displayed using `.headline` font, and their handle (@username) uses the `.subheadline` font with a secondary color to differentiate it from the name. + +- **Button**: A "Follow" button styled with the SF Symbol "person.badge.plus". This demonstrates how you can use system symbols in SwiftUI. The action for this button (currently commented out) would be where you'd add logic to handle following the user. + +- **Background, CornerRadius, and Shadow**: These properties are used to give the card a subtle shadow and rounded corners, enhancing its visual appeal and making it stand out on the screen. + +This `UserProfileCard` view is now ready to be integrated into your SwiftUI application. You can create instances of this view by passing in `User` structs that conform to the structure defined above. + +### Performance Metrics: +* **Tokens/s:** 23.7 +* **Total Tokens:** 616 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 3: I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +*Source:* `test3.txt` + +### Prompt: +```swift +I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +The new function should be marked with `async throws` and return a `[Post]` object upon success. Also, include an example of how to call this new async function inside a `Task` with a `do-catch` block. + +**Old Code:** +struct Post: Codable { + let id: Int + let title: String +} + +func fetchPosts(completion: @escaping (Result<[Post], Error>) -> Void) { + guard let url = URL(string: "https://api.example.com/posts") else { return } + URLSession.shared.dataTask(with: url) { data, _, error in + if let error = error { completion(.failure(error)); return } + guard let data = data else { return } + do { + let posts = try JSONDecoder().decode([Post].self, from: data) + completion(.success(posts)) + } catch { + completion(.failure(error)) + } + }.resume() +} +``` + +### Response: + +To refactor the given networking code to use modern Swift Concurrency with async/await, you can follow these steps: + +1. **Mark the Function as Async**: Change the function signature of `fetchPosts` to be asynchronous and capable of throwing errors. +2. **Use async/await**: Inside the function, use `async throws` to fetch data from the URL and decode it into a `[Post]`. +3. **Handle Completion with do-catch**: When calling this new async function, wrap the call inside a `do-catch` block within a `Task`. + +Here's how you can refactor the code: + +```swift +import Foundation + +struct Post: Codable { + let id: Int + let title: String +} + +// Refactored to use async/await +func fetchPosts() async throws -> [Post] { + guard let url = URL(string: "https://api.example.com/posts") else { throw NSError(domain: "", code: -1, userInfo: nil) } + + var request = URLRequest(url: url) + request.httpMethod = "GET" + + let (data, response, error) = try await URLSession.shared.data(for: request) + + if let error = error { + throw error + } + + guard let data = data else { throw NSError(domain: "", code: -2, userInfo: nil) } + + do { + return try JSONDecoder().decode([Post].self, from: data) + } catch { + throw error + } +} + +// Example of calling the new async function inside a Task with a do-catch block +Task { + do { + let posts = try await fetchPosts() + print(posts) // Handle or display the fetched posts + } catch { + print("Failed to fetch posts: \(error.localizedDescription)") + } +} +``` + +### Explanation: + +- **Async Function**: The `fetchPosts` function is now marked with `async throws`, indicating it's an asynchronous function that can throw errors. +- **Using async/await**: Inside the function, `URLSession.shared.data(for:)` is awaited using `try await`. This allows for non-blocking network operations and makes the code more readable by avoiding callbacks or completion handlers. +- **Error Handling**: Errors from the URL session request are thrown directly. If data fetching fails or decoding JSON fails, those errors are also caught and re-thrown to be handled externally. +- **Calling with do-catch in a Task**: The `Task` construct is used to call `fetchPosts()` asynchronously. Inside the `do-catch` block, we await the result of `fetchPosts()`. If successful, it prints the fetched posts; otherwise, it catches and prints any errors that occurred. + +This refactoring leverages Swift's modern concurrency features for cleaner, more readable asynchronous code handling. + +### Performance Metrics: +* **Tokens/s:** 23.46 +* **Total Tokens:** 576 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 4: Create a complete SwiftData example for a macOS 26 app. + +*Source:* `test4.txt` + +### Prompt: +```swift +Create a complete SwiftData example for a macOS 26 app. + +You must define two models: `Author` and `Book`. An `Author` can have many `Book`s (a one-to-many relationship). + +Then, create a SwiftUI view that displays a list of all authors. When an author's name is tapped, it should navigate to a detail view that shows a list of all the books written by that specific author. Use a SwiftData `@Query` to fetch the data. +``` + +### Response: + +Certainly! Here's a complete example using Swift Data and SwiftUI for a macOS 26 app with two models: `Author` and `Book`, along with a SwiftUI view that displays authors and their books: + +```swift +import SwiftUI +import SwiftData + +// Author model +@Model +struct Author: Identifiable { + var id: String { name } + var name: String + @Children(for: \.$author) var books: [Book] +} + +// Book model +@Model +struct Book: Identifiable { + var id: String { title } + var title: String + var authorId: String + @Parent(for: \.$books) var author: Author? +} + +// ContentView.swift + +struct ContentView: View { + @Query(authorQuery) private var authors: [Author] + + var body: some View { + NavigationView { + List(authors) { author in + Text(author.name) + .onTapGesture { + // Navigate to the detail view when an author's name is tapped + let selectedAuthor = authors.first(where: { $0.name == author.name }) + // Assuming you have a DetailView that takes an Author as parameter + // Replace "DetailView(author: selectedAuthor!)" with your actual DetailView + } + } + .navigationTitle("Authors") + } + } +} + +// Query for fetching authors +@Query +private func authorQuery() -> [Author] { + return try? Store.fetch(authorFetchRequest) +} + +// AuthorFetchRequest for fetching authors from SwiftData store +let authorFetchRequest: FetchRequest = Author.all() + +// DetailView.swift + +struct DetailView: View { + let author: Author + + var body: some View { + List(author.books) { book in + Text(book.title) + } + .navigationTitle("Books by \(author.name)") + } +} + +// BookFetchRequest for fetching books from SwiftData store based on authorId +let bookFetchRequest: FetchRequest = Book.filter(\.authorId == $0.id) + +// ContentView.swift (with DetailView integration) +struct ContentView: View { + @Query(authorQuery) private var authors: [Author] + + var body: some View { + NavigationView { + List(authors) { author in + Text(author.name) + .onTapGesture { + let selectedAuthor = authors.first(where: { $0.name == author.name }) + // Pass the selected author to DetailView + withAnimation { + // Assuming you have a state variable to hold the selected author + // Replace "selectedAuthor" with your actual state variable name + detailAuthor = selectedAuthor + } + } + } + .navigationTitle("Authors") + } + } +} + +// State variable for holding the selected author in ContentView +@State private var detailAuthor: Author? + +// DetailView.swift (with navigation to show books) +struct DetailView: View { + let author: Author + + var body: some View { + List(author.books) { book in + Text(book.title) + } + .navigationTitle("Books by \(author.name)") + + // Navigation link back to the list of authors + .navigationBarItems(trailing: + Button(action: { + // Navigate back to the list of authors + detailAuthor = nil + }) { + Image(systemName: "chevron.left") + } + ) + } +} +``` + +In this example: + +1. We define two models: `Author` and `Book`. The `Author` model has a one-to-many relationship with the `Book` model using the `@Children` property wrapper. + +2. In the `ContentView`, we use the `@Query` property to fetch all authors from the SwiftData store using the `authorQuery()` function. + +3. We display a list of authors using the `List` view. When an author's name is tapped, it navigates to the detail view (`DetailView`) by passing the selected author as a parameter. + +4. In the `DetailView`, we display a list of books written by the specific author using another `List` view. + +5. We use a state variable (`detailAuthor`) in the `ContentView` to hold the selected author when tapped, and pass it to the `DetailView`. + +6. The `DetailView` shows the books written by the author and includes a navigation link back to the list of authors. + +Note: Make sure to replace `"DetailView(author: selectedAuthor!)"` with your actual `DetailView` implementation that takes an `Author` as a parameter. + +This example demonstrates how to use Swift Data and SwiftUI to create a macOS 26 app with a one-to-many relationship between `Author` and `Book`, and navigate between views based on user interactions. + +### Performance Metrics: +* **Tokens/s:** 23.94 +* **Total Tokens:** 976 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 5: Write a thread-safe counter class in Swift using an `actor`. + +*Source:* `test5.txt` + +### Prompt: +```swift +Write a thread-safe counter class in Swift using an `actor`. + +The actor should be named `SafeCounter`. It must have a private property to hold the current count and two public methods: +1. `func increment() async` +2. `func getCount() async -> Int` + +Also, provide a simple example of how to create an instance of the actor and call its methods concurrently from two different `Task`s. +``` + +### Response: + +Certainly! Below is an implementation of a thread-safe counter class in Swift using an `actor`. The `SafeCounter` actor maintains a private count property and provides public methods to increment the count and retrieve the current count asynchronously. + +```swift +import Foundation + +// Define the SafeCounter actor +final class SafeCounter { + // Private property to hold the current count + private var _count: Int = 0 + + // Public method to increment the counter + func increment() async throws { + // Use lock to ensure thread safety when modifying shared state + await withCheckedThrowingContinuation { continuation in + DispatchQueue.main.async { + self._count += 1 + continuation.resume() + } + } + } + + // Public method to get the current count + func getCount() async -> Int { + var result: Int? + + // Use lock to ensure thread safety when reading shared state + await withCheckedThrowingContinuation { continuation in + DispatchQueue.main.async { + result = self._count + continuation.resume(with: .success(result!)) + } + } + + return result! + } +} + +// Example usage of SafeCounter concurrently from two different Tasks +Task { + let counter = SafeCounter() + + // Create a task to increment the counter multiple times + for _ in 0..<1000 { + Task { + try await counter.increment() + } + } + + // Wait for all increments to complete and then print the count + do { + try await counter.increment() // Ensure all previous increments are done + let count = await counter.getCount() + print("Final Count: \(count)") + } catch { + print("Error getting count: \(error)") + } +} + +Task { + let counter = SafeCounter() + + // Create a task to increment the counter multiple times concurrently with another Task + for _ in 0..<500 { + Task { + try await counter.increment() + } + } + + do { + try await counter.increment() // Ensure all previous increments are done + let count = await counter.getCount() + print("Final Count: \(count)") + } catch { + print("Error getting count: \(error)") + } +} +``` + +This code defines a `SafeCounter` actor that ensures thread-safe operations on its internal state. The `increment()` method and the `getCount()` method are designed to be called concurrently from multiple tasks without causing race conditions. + +The example demonstrates creating an instance of `SafeCounter` within two separate `Task`s, incrementing the counter in each task, and then retrieving the final count after all increments have been completed. This showcases how actors can simplify concurrent programming by encapsulating state and providing a clear model for safe access to shared resources across threads. + +Remember that Swift's actor model is designed to make concurrency easier and safer by ensuring that only one task at a time can execute methods on an actor, thus preventing data races when accessing or modifying the actor's state. + +### Performance Metrics: +* **Tokens/s:** 23.85 +* **Total Tokens:** 612 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 6: Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +*Source:* `test6.txt` + +### Prompt: +```swift +Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +The code must include: +1. A `TimelineProvider` to generate the timeline entries. +2. A `TimelineEntry` struct. +3. The main `Widget` struct. +4. A SwiftUI view for the complication's appearance. + +Ensure the code correctly uses the modern WidgetKit framework. +``` + +### Response: + +Certainly! Below is a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family using the modern WidgetKit framework. This example includes all the components you requested: + +```swift +import SwiftUI +import WidgetKit + +// Define the TimelineEntry struct to hold the data for each entry in the timeline. +struct DateEntry: TimelineEntry { + let date: Date +} + +// TimelineProvider is responsible for generating entries of type `DateEntry` over time. +struct DateWidgetTimelineProvider: TimelineProvider { + // Provide initial entries starting from now, with a 1-day interval. + func placeholder(in context: Context) -> DateEntry { + return DateEntry(date: Date()) + } + + func getSnapshot(in context: Context, completion: @escaping (DateEntry) -> Void) { + let entry = DateEntry(date: Date()) + completion(entry) + } + + func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { + var entries: [DateEntry] = [] + + // Generate a series of entries spanning the next 24 hours, with each entry one hour apart. + for hourOffset in 0..<24 { + let date = Calendar.current.date(byAdding: .hour, value: hourOffset, to: Date())! + entries.append(DateEntry(date: date)) + } + + let timeline = Timeline(entries: entries, policy: .atEnd) + completion(timeline) + } +} + +// The main Widget struct that defines the widget's appearance and behavior. +struct DateWidget: Widget { + // Declare the kind of widget. This is used to identify the widget in the system. + let kind: String = "DateWidget" + + // Entry holds a single date entry for the timeline. + var entry: DateEntry + + // The body property defines how the widget should appear on the watch face. + var body: some WidgetConfiguration { + StaticConfiguration(kind: kind, provider: DateWidgetTimelineProvider()) { entry in + DateView(entry: entry) + } + .configurationDisplayName("Date Widget") + .description("Displays the current date.") + .supportedFamilies([.accessoryRectangular]) + } +} + +// SwiftUI view for displaying the date. +struct DateView: View { + let entry: DateWidgetTimelineProvider.DateEntry + + var body: some View { + Text(entry.date, style: .date) + .font(.system(size: 40)) + .foregroundColor(.primary) + } +} + +@main +struct SimpleDateWidget: WidgetBundle { + var body: some SceneBuilderBundle { + // Define the widget and its configuration. + ConfigurationView(provider: DateWidgetTimelineProvider()) + .widgetsKind(WidgetKind.dateWidget) + } + + // Provide a preview provider for Xcode's canvas. + static var previews: some View { + Group { + DateView(entry: DateEntry(date: Date())) + .previewContext(WidgetPreviewContext(family: .accessoryRectangular)) + } + } +} +``` + +### Explanation: + +1. **TimelineProvider (`DateWidgetTimelineProvider`)**: + - Generates a timeline of `DateEntry` objects, each representing the current date at one-hour intervals over the next 24 hours. + +2. **TimelineEntry Struct (`DateEntry`)**: + - Holds a single `Date` value to represent the data for each entry in the timeline. + +3. **Widget Struct (`DateWidget`)**: + - Defines the widget's kind and uses `StaticConfiguration` to specify how it should be displayed, including its family (`.accessoryRectangular`) which is suitable for complications. + - The `body` property defines a `StaticConfiguration` that connects the timeline provider with the view displaying the date. + +4. **SwiftUI View (`DateView`)**: + - Displays the current date using SwiftUI's `Text` view, styled to show larger text and primary color. + +5. **WidgetBundle**: + - The main entry point for the widget, including a preview provider that allows you to see how your widget looks in Xcode's canvas with the `.accessoryRectangular` family. + +This code snippet provides a basic structure for creating a watchOS complication displaying the current date using WidgetKit. Adjustments can be made based on specific design requirements or additional features needed. + +### Performance Metrics: +* **Tokens/s:** 23.95 +* **Total Tokens:** 894 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 7: Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +*Source:* `test7.txt` + +### Prompt: +```swift +Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +**Old Code:** +class UserSettings: ObservableObject { + @Published var score: Int = 0 + @Published var username: String = "Guest" +} + +struct SettingsView: View { + @StateObject private var settings = UserSettings() + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +### Response: + +To refactor the given SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9, you can simplify the code by removing the need for `@Published`, `ObservableObject`, and directly using a plain struct with an `@Observable` property wrapper if available or manually implementing observable properties. However, as of my last update in April 2023, there isn't a built-in `@Observable` macro in Swift that automatically makes properties observable without additional setup like the `@Published` wrapper does. + +Given this context, and assuming you're looking for a way to refactor towards simplicity while maintaining similar functionality (i.e., observing changes), we'll proceed with a straightforward approach. Since direct support for an automatic `@Observable` macro isn't specified in your query beyond its introduction in Swift 5.9, I'll demonstrate how you might simplify the code without relying on `@Published` or `ObservableObject`, focusing on using plain structs and properties that can be observed through SwiftUI's state management. + +Here's a refactored version of your code: + +```swift +import SwiftUI + +// Simplified UserSettings struct without ObservableObject protocol +struct UserSettings { + @State private var score: Int = 0 + @State private var username: String = "Guest" + + // Assuming manual implementation for demonstration purposes. + // In a real scenario, you might use Combine or similar frameworks to observe changes. +} + +// Simplified SettingsView using the refactored UserSettings struct +struct SettingsView: View { + @ObservedObject private var settings = UserSettings() // Using @ObservedObject if available, otherwise direct reference + + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +**Note:** The use of `@ObservedObject` in the refactored code assumes that you're using a setup where this property wrapper is available or applicable. If your environment doesn't support it directly (since the introduction of Swift 5.9 might not have introduced such a macro without specific context), you would typically manage state and observe changes manually, as shown with `@State` for simplicity. + +For environments that do support automatic observability through a macro like `@Observable`, you'd replace manual property management (`@State`) with this macro's usage directly on your properties. However, since such a macro isn't standard in Swift 5.9 without additional context or third-party libraries, the above approach is more aligned with typical SwiftUI practices for managing observable state. + +Remember, the actual implementation of automatic observability (like through an `@Observable` macro) would depend on specific frameworks or custom implementations you might be using beyond the standard Swift/SwiftUI capabilities. + +### Performance Metrics: +* **Tokens/s:** 23.71 +* **Total Tokens:** 585 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 8: Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. + +*Source:* `test8.txt` + +### Prompt: +```swift +Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. +``` + +### Response: + +To create a simple WidgetKit widget for iOS 26 that displays a single "Note" string and allows the user to edit it using the modern App Intents framework, follow these steps: + +1. Create a new Xcode project and select the "Widget Extension" option. + +2. In the `Info.plist` file of your widget extension target, add the following keys: + - `NSExtensionAttributes`: Add this key with a value of `{ "AppIntentConfigurationClass": "NoteWidgetIntentConfiguration", "AppIntents": ["EditNote"] }` + - `NSExtensionPrincipalClass`: Set it to the name of your widget's principal class (e.g., `YourWidgetName.WidgetEntryView`). + +3. Create a new Swift file named `NoteWidgetIntentConfiguration.swift` and add the following code: + +```swift +import WidgetKit +import Intents + +@objc(NOTEWIDGET_INTENT_CONFIGURATION) +class NoteWidgetIntentConfiguration: NSObject, INExtension { + override func configure(with intent: INIntent, completion: @escaping (NOTEWIDGET_INTENT_CONFIGURATION?) -> Void) { + let configuration = NOTEWIDGET_INTENT_CONFIGURATION() + + // Set up the widget's configuration options + if let editNoteIntent = intent as? EditNoteIntent { + configuration.noteText = editNoteIntent.noteText ?? "" + } + + completion(configuration) + } +} +``` + +4. Create a new Swift file named `NoteWidgetEntryView.swift` and add the following code: + +```swift +import WidgetKit + +struct NoteWidgetEntryView: View { + var entry: Provider.Entry + + var body: some View { + Text(entry.noteText) + .font(.headline) + } +} +``` + +5. Update your widget's `TimelineProvider` to use the new configuration class: + +```swift +import WidgetKit + +struct Provider: TimelineProvider { + func placeholder(in context: Context) -> Provider.Entry { + return Provider.Entry(noteText: "") + } + + func getSnapshot(in context: Context, completion: @escaping (Provider.Entry) -> Void) { + let entry = Provider.Entry(noteText: "Your initial note") + completion(entry) + } + + func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { + var entries: [Provider.Entry] = [] + + // Generate a timeline with daily entries + for hourOffset in 0..<24 { + let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: Date())! + + let entry = Provider.Entry(noteText: "Note \(hourOffset)") + entries.append(entry) + } + + let timeline = Timeline(entries: entries, policy: .atEnd) + completion(timeline) + } +} +``` + +6. Update your widget's `WidgetEntryView` to use the new configuration class: + +```swift +import WidgetKit + +struct NoteWidgetEntryView: View { + @Environment(\.widgetFamily) private var family + + var entry: Provider.Entry + + var body: some View { + if family == .systemSmall { + Text(entry.noteText) + .font(.caption) + } else { + Text(entry.noteText) + .font(.headline) + } + } +} +``` + +7. Update your widget's `Widget` class to use the new configuration class: + +```swift +import WidgetKit + +struct NoteWidget: Widget { + let kind: String = "NoteWidget" + + var body: some WidgetConfiguration { + StaticConfiguration(kind: kind, provider: Provider()) { entry in + NoteWidgetEntryView(entry: entry) + } + .configurationDisplayName("Note Widget") + .description("Displays a note.") + .supportedFamilies([.systemSmall, .systemMedium]) + } +} +``` + +8. Run the app on an iOS device or simulator to test the widget. + +With these steps, you have created a simple WidgetKit widget that displays a single "Note" string and allows the user to edit it using the modern App Intents framework. The user can configure the note's text directly from the widget's configuration screen when they long-press on the widget in the Today view or Lock Screen. + +Remember to replace `NOTEWIDGET_INTENT_CONFIGURATION` with your actual widget name and adjust the code accordingly based on your project structure. + +### Performance Metrics: +* **Tokens/s:** 24.0 +* **Total Tokens:** 892 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 9: Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +*Source:* `test9.txt` + +### Prompt: +```swift +Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +The view must: +1. Have a button labeled "Enter Immersive Space". +2. Use the `@Environment(\.openImmersiveSpace)` and `@Environment(\.dismissImmersiveSpace)` variables. +3. Be able to open an immersive space with the ID "MyImmersiveScene". +4. Include a second button inside the immersive space to dismiss it. +``` + +### Response: + +To create a SwiftUI view for VisionOS 26 that meets your requirements, you'll need to follow these steps: + +1. **Set Up Your Project**: Ensure your project is set up for Vision Pro development in Xcode. + +2. **Create the Main View**: This will include the button to enter immersive space and handle its lifecycle. + +3. **Implement Immersive Space Logic**: Use `@Environment` variables to manage entering and exiting immersive space. + +4. **Add a Second Button Inside Immersive Space**: To dismiss the immersive space, you'll need to use the provided environment variable. + +Here's how you can implement this: + +### Step 1: Create Your Main View + +```swift +import SwiftUI +import VisionPro + +struct ContentView: View { + @Environment(\.openImmersiveSpace) var openImmersiveSpace + @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace + + var body: some View { + VStack(spacing: 20) { + Button(action: { + // Open immersive space with the specified ID + openImmersiveSpace("MyImmersiveScene") + }) { + Text("Enter Immersive Space") + .font(.largeTitle) + .foregroundColor(.white) + .padding() + .background(Color.blue) + .cornerRadius(20) + } + + Spacer() + } + } +} +``` + +### Step 2: Implementing the Immersive Space Logic + +The above code snippet already includes the basic logic for opening an immersive space when a button is tapped. However, to ensure it works correctly within Vision Pro's ecosystem and to add the second button inside the immersive space (which you'll need to create separately), follow these steps: + +### Step 2a: Create Your Immersive Space Scene + +1. **Create a New SwiftUI View**: This will be your immersive space scene. + +```swift +struct ImmersiveSpaceScene: View { + @Environment(\.dismissImmersiveSpace) var dismiss + + var body: some View { + VStack(spacing: 20) { + Text("Welcome to the Immersive Space!") + .font(.largeTitle) + + Button(action: { + // Dismiss immersive space + dismiss() + }) { + Text("Dismiss") + .font(.title) + .foregroundColor(.white) + .padding() + .background(Color.red) + .cornerRadius(20) + } + } + } +} +``` + +### Step 2b: Linking the Main View with the Immersive Space Scene + +To link your main view with the immersive space scene, you'll need to use Vision Pro's API directly or through SwiftUI modifiers if you're using a more complex setup. However, for simplicity and direct interaction within SwiftUI views as of my last update: + +- You would typically not embed `ImmersiveSpaceScene` directly inside `ContentView` but rather open it via the environment variables provided by Vision Pro. + +Given the constraints of this explanation (and without diving into more complex setups or specific API usages beyond what's directly supported in SwiftUI), here's how you might conceptually approach opening your immersive space scene from within `ContentView`: + +```swift +// Assuming you have a way to reference ImmersiveSpaceScene, which typically would be done through Vision Pro's APIs. +// For simplicity and direct interaction as per the initial request: +struct ContentView: View { + @Environment(\.openImmersiveSpace) var openImmersiveSpace + @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace + + var body: some View { + VStack(spacing: 20) { + Button(action: { + // Open immersive space with the specified ID + openImmersiveSpace("MyImmersiveScene") + + // Note: Directly embedding ImmersiveSpaceScene isn't standard practice in SwiftUI for Vision Pro. + // You'd typically use Vision Pro's APIs or SceneKit/VisionPro SDKs to manage immersive scenes. + }) { + Text("Enter Immersive Space") + .font(.largeTitle) + .foregroundColor(.white) + .padding() + .background(Color.blue) + .cornerRadius(20) + } + + Spacer() + } + } +} +``` + +### Note: + +- The direct embedding of `ImmersiveSpaceScene` within `ContentView` as shown in the conceptual approach above is more illustrative than practical for Vision Pro's current SDK capabilities. You'd generally manage immersive scenes through Vision Pro's SceneKit or similar frameworks, which might involve using SwiftUI views to control UI elements but not directly nesting one SwiftUI view inside another in a straightforward manner. +- Always refer to the latest Vision Pro documentation and SDK updates for the most accurate information on managing immersive spaces within your applications. + +### Performance Metrics: +* **Tokens/s:** 22.27 +* **Total Tokens:** 977 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 10: Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +*Source:* `test10.txt` + +### Prompt: +```swift +Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +This layout should arrange its subviews in a horizontal flow, starting a new row when the current row is full. It should behave similarly to a basic left-aligned flow layout in CSS. + +The implementation must conform to the `Layout` protocol and implement both the `sizeThatFits(...)` and `placeSubviews(...)` methods. +``` + +### Response: + +To create a custom SwiftUI Layout container called `SimpleFlowLayout`, we'll need to define it as a struct that conforms to the `Layout` protocol. This protocol requires us to implement two main methods: `sizeThatFits(_:constraints:)` and `placeSubviews(in:layoutDirection:)`. + +The `sizeThatFits(_:constraints:)` method will calculate the size of the layout container given its subviews and any constraints, while `placeSubviews(in:layoutDirection:)` will arrange the subviews within this container. + +Here's how you can implement it: + +```swift +import SwiftUI + +struct SimpleFlowLayout: Layout { + + // This property determines how many items should fit in a single row before moving to the next. + let numberOfItemsPerRow: Int + + init(numberOfItemsPerRow: Int) { + self.numberOfItemsPerRow = numberOfItemsPerRow + } + + func sizeThatFits(_ proposedSize: CGSize, _ constraints: LayoutConstraints) -> CGSize { + // Calculate the total width required for all subviews. + let totalWidth = CGFloat(numberOfItemsPerRow) * proposedSize.width + + // The height will be determined by how many rows are needed based on the number of items and their individual heights. + let numberOfRows = max(1, Int(proposedSize.height / constraints.minimumHeight)) + + return CGSize(width: totalWidth, height: CGFloat(numberOfRows) * constraints.minimumHeight) + } + + func placeSubviews(in rect: CGRect, _ layoutDirection: LayoutDirection) { + guard !subviews.isEmpty else { return } + + let subviewCount = subviews.count + let numberOfItemsPerRow = self.numberOfItemsPerRow + + // Calculate the width and height of each item based on the proposed size. + let itemWidth = rect.width / CGFloat(numberOfItemsPerRow) + let itemHeight = rect.height + + for (index, subview) in subviews.enumerated() { + let row = index / numberOfItemsPerRow + let column = index % numberOfItemsPerRow + + // Calculate the frame of each subview. + var frame = CGRect(origin: .zero, size: CGSize(width: itemWidth, height: itemHeight)) + + // Adjust the origin based on the layout direction and row/column position. + if layoutDirection == .leftToRight { + frame.origin.x = CGFloat(column) * itemWidth + } else { + frame.origin.x = (CGFloat(numberOfItemsPerRow) - CGFloat(column) - 1) * itemWidth + } + + frame.origin.y = CGFloat(row) * itemHeight + + // Place the subview within its calculated frame. + subview.frame = frame + } + } +} +``` + +This implementation of `SimpleFlowLayout` arranges its subviews in a horizontal flow, starting a new row when the current row is full. It calculates the size that fits based on the proposed size and constraints, ensuring it respects minimum height requirements for rows. The placement method then positions each subview within this container according to the specified layout direction (left-to-right by default), adjusting for RTL languages if needed. + +To use `SimpleFlowLayout`, you would typically apply it as a modifier to your SwiftUI views or containers that need this specific layout behavior: + +```swift +struct ContentView: View { + var body: some View { + VStack { + Text("Hello, World!") + + // Apply SimpleFlowLayout with 3 items per row. + HStack(layout: SimpleFlowLayout(numberOfItemsPerRow: 3)) { + ForEach(0..<9) { _ in + Image(systemName: "star") + .resizable() + .frame(width: 50, height: 50) + } + } + } + } +} +``` + +This example demonstrates how to apply `SimpleFlowLayout` within an `HStack`, arranging its subviews (in this case, images) in a horizontal flow with three items per row. Adjust the `numberOfItemsPerRow` parameter as needed for different layouts. + +### Performance Metrics: +* **Tokens/s:** 19.88 +* **Total Tokens:** 831 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + diff --git a/results/Modern-Apple-Dev/automated_report_mistralai_codestral-22b-v0.1.md b/results/Modern-Apple-Dev/automated_report_mistralai_codestral-22b-v0.1.md new file mode 100644 index 0000000..b9fb913 --- /dev/null +++ b/results/Modern-Apple-Dev/automated_report_mistralai_codestral-22b-v0.1.md @@ -0,0 +1,775 @@ +# Automated Diagnostic Report: mistralai/codestral-22b-v0.1 + +--- + +## Performance Summary + + +* **Average Tokens/s:** 6.21 +* **Average Time to First Token:** 0.0s +* **Total Tokens Generated:** 4010 + + +## Qualitative Analysis + +*(Manual grading and analysis of the responses is required to determine the final letter grade.)* + +--- + +## Test 1: Write a Swift function that solves the FizzBuzz problem. + +*Source:* `test1.txt` + +### Prompt: +```swift +Write a Swift function that solves the FizzBuzz problem. + +The function must have the exact signature: +`func generateFizzBuzz(upTo max: Int) -> [String]` + +It must not print directly to the console. Instead, it should return an array of strings. + +Rules: +1. For numbers divisible by 3, the string should be "Fizz". +2. For numbers divisible by 5, the string should be "Buzz". +3. For numbers divisible by both 3 and 5, the string should be "FizzBuzz". +4. Otherwise, it should be the number itself as a string. + +Include a complete documentation comment (`///`) explaining what the function does, its parameters, and what it returns. +``` + +### Response: + +```swift +/// Generates an array of strings representing the FizzBuzz sequence up to a given maximum number. +/// - Parameter max: The maximum number in the sequence. +/// - Returns: An array of strings representing the FizzBuzz sequence. +func generateFizzBuzz(upTo max: Int) -> [String] { + var result = [String]() + for i in 1...max { + if i % 3 == 0 && i % 5 == 0 { + result.append("FizzBuzz") + } else if i % 3 == 0 { + result.append("Fizz") + } else if i % 5 == 0 { + result.append("Buzz") + } else { + result.append(String(i)) + } + } + return result +} +``` + +### Performance Metrics: +* **Tokens/s:** 5.5 +* **Total Tokens:** 199 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 2: Create a complete SwiftUI view for a user profile card. + +*Source:* `test2.txt` + +### Prompt: +```swift +Create a complete SwiftUI view for a user profile card. + +The view should be named `UserProfileCard` and be initialized with a simple `User` struct containing `name: String`, `handle: String`, and `avatarURL: URL`. + +Requirements: +- Use an `AsyncImage` to load the user's avatar from the URL. +- Display the user's name in a `.headline` font and their handle (e.g., "@username") in a `.subheadline` font with a secondary color. +- Include a "Follow" button that uses the "person.badge.plus" SF Symbol. +- Arrange the elements cleanly inside an HStack with appropriate spacing. +- The entire card should have a subtle shadow and rounded corners. +``` + +### Response: + +Here's how you can create a `UserProfileCard` view in SwiftUI that meets all of your requirements: + +```swift +import SwiftUI + +struct User: Identifiable { + let id = UUID() + let name: String + let handle: String + let avatarURL: URL +} + +struct UserProfileCard: View { + let user: User + + var body: some View { + HStack(spacing: 16) { + AsyncImage(url: user.avatarURL) { image in + image.resizable() + } placeholder: { + Color.gray + } + .frame(width: 50, height: 50) + .clipShape(Circle()) + + VStack(alignment: .leading, spacing: 4) { + Text(user.name) + .font(.headline) + + Text("@\(user.handle)") + .font(.subheadline) + .foregroundColor(.secondary) + } + + Spacer() + + Button(action: { + // Add your follow action here + }) { + Image(systemName: "person.badge.plus") + } + } + .padding() + .background(Color.white) + .cornerRadius(10) + .shadow(color: Color.black.opacity(0.1), radius: 5, x: 0, y: 2) + } +} +``` + +This code creates a `UserProfileCard` view that displays the user's avatar, name, handle, and a "Follow" button. The card has rounded corners and a subtle shadow for depth. + +### Performance Metrics: +* **Tokens/s:** 6.87 +* **Total Tokens:** 411 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 3: I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +*Source:* `test3.txt` + +### Prompt: +```swift +I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +The new function should be marked with `async throws` and return a `[Post]` object upon success. Also, include an example of how to call this new async function inside a `Task` with a `do-catch` block. + +**Old Code:** +struct Post: Codable { + let id: Int + let title: String +} + +func fetchPosts(completion: @escaping (Result<[Post], Error>) -> Void) { + guard let url = URL(string: "https://api.example.com/posts") else { return } + URLSession.shared.dataTask(with: url) { data, _, error in + if let error = error { completion(.failure(error)); return } + guard let data = data else { return } + do { + let posts = try JSONDecoder().decode([Post].self, from: data) + completion(.success(posts)) + } catch { + completion(.failure(error)) + } + }.resume() +} +``` + +### Response: + +Here's how you can refactor the old networking code to use modern Swift Concurrency with async/await: + +```swift +struct Post: Codable { + let id: Int + let title: String +} + +func fetchPosts() async throws -> [Post] { + guard let url = URL(string: "https://api.example.com/posts") else { throw URLError(.badURL) } + let (data, _) = try await URLSession.shared.data(from: url) + return try JSONDecoder().decode([Post].self, from: data) +} +``` + +You can call this new async function inside a `Task` with a `do-catch` block like so: + +```swift +Task { + do { + let posts = try await fetchPosts() + // Use the fetched posts here... + } catch { + print("Error: \(error)") + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 6.06 +* **Total Tokens:** 228 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 4: Create a complete SwiftData example for a macOS 26 app. + +*Source:* `test4.txt` + +### Prompt: +```swift +Create a complete SwiftData example for a macOS 26 app. + +You must define two models: `Author` and `Book`. An `Author` can have many `Book`s (a one-to-many relationship). + +Then, create a SwiftUI view that displays a list of all authors. When an author's name is tapped, it should navigate to a detail view that shows a list of all the books written by that specific author. Use a SwiftData `@Query` to fetch the data. +``` + +### Response: + +Here's a simple example of how you could define your models and views in SwiftUI using SwiftData. + +First, let's define our models: + +```swift +import Foundation +import SwiftData + +@Model +class Author { + var name: String + @Relationship(deleteRule: .cascade) + var books: [Book]? + + init(name: String) { + self.name = name + } +} + +@Model +class Book { + var title: String + var author: Author? + + init(title: String, author: Author?) { + self.title = title + self.author = author + } +} +``` + +Now let's create our views. First, the view that displays a list of all authors: + +```swift +import SwiftUI +import SwiftData + +struct AuthorListView: View { + @Environment(\.modelContext) private var context + @Query(sortBy: \Author.name) private var authors: [Author] + + var body: some View { + NavigationStack { + List(authors) { author in + NavigationLink(author.name, value: author) + } + .navigationDestination(for: Author.self) { author in + BookListView(author: author) + } + } + } +} +``` + +Then, the detail view that shows a list of all books written by a specific author: + +```swift +struct BookListView: View { + let author: Author + @Environment(\.modelContext) private var context + @Query(sortBy: \Book.title, predicate: #Predicate{"$0.author == %@", author}) private var books: [Book] + + var body: some View { + List(books) { book in + Text(book.title) + } + .navigationTitle("Books by \(author.name)") + } +} +``` + +Finally, don't forget to add the `@main` attribute to your main SwiftUI view and initialize a model context: + +```swift +import SwiftUI +import SwiftData + +@main +struct YourApp: App { + var body: some Scene { + WindowGroup { + AuthorListView() + .modelContainer(for: [Author.self, Book.self]) + } + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 6.5 +* **Total Tokens:** 577 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 5: Write a thread-safe counter class in Swift using an `actor`. + +*Source:* `test5.txt` + +### Prompt: +```swift +Write a thread-safe counter class in Swift using an `actor`. + +The actor should be named `SafeCounter`. It must have a private property to hold the current count and two public methods: +1. `func increment() async` +2. `func getCount() async -> Int` + +Also, provide a simple example of how to create an instance of the actor and call its methods concurrently from two different `Task`s. +``` + +### Response: + +Here's a thread-safe counter class in Swift using an `actor`. + +```swift +actor SafeCounter { + private var count = 0 + + func increment() async { + count += 1 + } + + func getCount() async -> Int { + return count + } +} +``` + +You can create an instance of the actor and call its methods concurrently from two different `Task`s like this: + +```swift +let safeCounter = SafeCounter() + +Task { + for _ in 0..<10 { + await safeCounter.increment() + } +} + +Task { + for _ in 0..<5 { + let count = await safeCounter.getCount() + print("Current count: \(count)") + } +} +``` + +In this example, we create a `SafeCounter` instance and then launch two concurrent tasks. The first task increments the counter 10 times, while the second task prints the current count 5 times. Since the `SafeCounter` actor is thread-safe, it ensures that the increment and getCount operations are performed atomically, preventing any race conditions or inconsistent results. + +### Performance Metrics: +* **Tokens/s:** 6.16 +* **Total Tokens:** 275 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 6: Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +*Source:* `test6.txt` + +### Prompt: +```swift +Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +The code must include: +1. A `TimelineProvider` to generate the timeline entries. +2. A `TimelineEntry` struct. +3. The main `Widget` struct. +4. A SwiftUI view for the complication's appearance. + +Ensure the code correctly uses the modern WidgetKit framework. +``` + +### Response: + +Here is a simple example of how you can create a watchOS 26 complication that displays the current date in the `.accessoryRectangular` family using SwiftUI and WidgetKit. + +```swift +import WidgetKit +import SwiftUI + +struct SimpleDateProvider: TimelineProvider { + func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> Void) { + let entry = SimpleEntry(date: Date()) + completion(entry) + } + + func getTimeline(in context: Context, completion: @escaping (Timeline) -> Void) { + var entries: [SimpleEntry] = [] + + // Generate a new entry every minute. + let currentDate = Date() + for hour in 0 ..< 24 { + for minute in 0 ..< 60 { + let dateComponents = Calendar.current.dateComponents([.year, .month, .day, .hour, .minute], from: currentDate) + var newComponents = DateComponents() + newComponents.year = dateComponents.year + newComponents.month = dateComponents.month + newComponents.day = dateComponents.day + newComponents.hour = hour + newComponents.minute = minute + let entryDate = Calendar.current.date(from: newComponents)! + let entry = SimpleEntry(date: entryDate) + entries.append(entry) + } + } + + let timeline = Timeline(entries: entries, policy: .atEnd) + completion(timeline) + } +} + +struct SimpleEntry: TimelineEntry { + let date: Date +} + +struct SimpleWidget: Widget { + private let kind: String = "SimpleWidget" + + public var body: some WidgetConfiguration { + StaticConfiguration(kind: kind, provider: SimpleDateProvider()) { entry in + SimpleWidgetView(entry: entry) + } + .supportedFamilies([.accessoryRectangular]) + } +} + +struct SimpleWidgetView : View { + var entry: SimpleEntry + + var body: some View { + Text(entry.date, style: .date) + .font(.headline) + } +} +``` +This code creates a simple widget that displays the current date in the `accessoryRectangular` family. The `SimpleDateProvider` generates timeline entries every minute for the rest of the day. The `SimpleWidgetView` is a SwiftUI view that displays the date from the entry. + +### Performance Metrics: +* **Tokens/s:** 6.19 +* **Total Tokens:** 598 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 7: Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +*Source:* `test7.txt` + +### Prompt: +```swift +Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +**Old Code:** +class UserSettings: ObservableObject { + @Published var score: Int = 0 + @Published var username: String = "Guest" +} + +struct SettingsView: View { + @StateObject private var settings = UserSettings() + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +### Response: + +With the introduction of Swift 5.9, we can use the `@Observable` macro to simplify our code and make it more modern. Here's how you can refactor your code: + +```swift +@Observable class UserSettings { + var score: Int = 0 + var username: String = "Guest" +} + +struct SettingsView: View { + @State private var settings = UserSettings() + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +In this refactored code, we've removed the `ObservableObject` protocol and the `@Published` property wrapper from our `UserSettings` class. Instead, we've used the new `@Observable` macro to make all properties of the `UserSettings` class observable. This means that any changes to these properties will automatically trigger updates in any views that are using them. + +In the `SettingsView`, we've also removed the `@StateObject` property wrapper and replaced it with `@State`. This is because we no longer need to create a separate instance of our `UserSettings` class for each view, as the `@Observable` macro takes care of this automatically. + +### Performance Metrics: +* **Tokens/s:** 6.03 +* **Total Tokens:** 306 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 8: Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. + +*Source:* `test8.txt` + +### Prompt: +```swift +Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. +``` + +### Response: + +Creating a WidgetKit widget with configurable content using the new App Intents framework involves several steps. Here is an example of how you can create such a widget. + +First, define your intent in the `Intents` file: +```swift +import AppIntents + +struct NoteIntent: AppIntent { + static let title = "Note" + @Parameter(title: "Content") var noteText: String? +} +``` + +Then, create a widget structure that conforms to `Widget` protocol and use the intent for configuration. +```swift +import WidgetKit +import SwiftUI + +struct NoteWidget: Widget { + let kind: String = "NoteWidget" + var noteText: String? + + var body: some WidgetConfiguration { + IntentConfiguration(kind: kind, intent: NoteIntent.self, content: { config in + Text(config.noteText ?? "") + .padding() + }) + } +} +``` + +Finally, create a widget view that will be displayed when the user taps on the widget. This view should also allow editing of the note text. +```swift +struct NoteWidgetView: View { + @State private var noteText = "" + + var body: some View { + TextField("Enter your note", text: $noteText) + .padding() + } +} +``` + +To allow the user to edit the note's text directly from the widget's configuration screen, you can use `WidgetConfigurationIntentView`. This view allows users to interact with intents and update their configurations. +```swift +struct NoteWidgetConfigurationView: View { + var body: some View { + WidgetConfigurationIntentView(NoteIntent.self) { intent in + TextField("Enter your note", text: Binding( + get: { intent.noteText ?? "" }, + set: { intent.noteText = $0 } + )) + .padding() + } + } +} +``` + +Remember to add the widget to your `WidgetBundle`. +```swift +struct NoteWidgetBundle: WidgetBundle { + var body: some Widget { + NoteWidget() + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 6.33 +* **Total Tokens:** 507 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 9: Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +*Source:* `test9.txt` + +### Prompt: +```swift +Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +The view must: +1. Have a button labeled "Enter Immersive Space". +2. Use the `@Environment(\.openImmersiveSpace)` and `@Environment(\.dismissImmersiveSpace)` variables. +3. Be able to open an immersive space with the ID "MyImmersiveScene". +4. Include a second button inside the immersive space to dismiss it. +``` + +### Response: + +Here is a simple SwiftUI view that meets all of your requirements: + +```swift +import SwiftUI +import RealityKit + +struct ContentView: View { + @Environment(\.openImmersiveSpace) var openImmersiveSpace + @State private var immersiveSpaceIsShown = false + + var body: some View { + if immersiveSpaceIsShown { + ImmersiveSpace(id: "MyImmersiveScene") { + Button("Dismiss Immersive Space") { + immersiveSpaceIsShown = false + } + } + } else { + Button("Enter Immersive Space") { + openImmersiveSpace(id: "MyImmersiveScene") { + immersiveSpaceIsShown = true + } + } + } + } +} +``` + +This view will display a button labeled "Enter Immersive Space". When this button is tapped, it will open an immersive space with the ID "MyImmersiveScene". Inside this immersive space, there will be another button labeled "Dismiss Immersive Space" that, when tapped, will dismiss the immersive space and return to the original view. + +### Performance Metrics: +* **Tokens/s:** 6.2 +* **Total Tokens:** 289 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 10: Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +*Source:* `test10.txt` + +### Prompt: +```swift +Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +This layout should arrange its subviews in a horizontal flow, starting a new row when the current row is full. It should behave similarly to a basic left-aligned flow layout in CSS. + +The implementation must conform to the `Layout` protocol and implement both the `sizeThatFits(...)` and `placeSubviews(...)` methods. +``` + +### Response: + +Here's an example of how you could implement this custom SwiftUI Layout container called `SimpleFlowLayout`. This layout will arrange its subviews in a horizontal flow, starting a new row when the current row is full. + +```swift +import SwiftUI + +struct SimpleFlowLayout: Layout { + let itemSpacing: CGFloat + + func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize { + guard !subviews.isEmpty else { return .zero } + + var remainingWidth = proposal.recommendedSize.width + var maxHeight: CGFloat = 0 + var currentRowHeight: CGFloat = 0 + + for subview in subviews { + let size = subview.sizeThatFits(proposal) + + if remainingWidth - size.width < 0 { + maxHeight += currentRowHeight + currentRowHeight = 0 + remainingWidth = proposal.recommendedSize.width + } + + remainingWidth -= size.width + itemSpacing + currentRowHeight = max(currentRowHeight, size.height) + } + + return CGSize(width: proposal.recommendedSize.width, height: maxHeight + currentRowHeight) + } + + func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) { + var x = bounds.minX + var y = bounds.minY + var remainingWidth = bounds.width + + for subview in subviews { + let size = subview.sizeThatFits(proposal) + + if remainingWidth - size.width < 0 { + x = bounds.minX + y += size.height + itemSpacing + remainingWidth = bounds.width + } + + subview.place(at: CGPoint(x: x, y: y), proposal: ProposedViewSize(size)) + x += size.width + itemSpacing + remainingWidth -= size.width + itemSpacing + } + } +} +``` + +You can use this layout in your SwiftUI views like so: + +```swift +struct ContentView: View { + var body: some View { + ScrollView { + SimpleFlowLayout(itemSpacing: 10) { + ForEach(0..<20) { index in + Text("Item \(index)") + .padding() + .border(Color.gray) + } + } + } + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 6.3 +* **Total Tokens:** 620 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + diff --git a/results/Modern-Apple-Dev/automated_report_phi-3-medium-128k-instruct.md b/results/Modern-Apple-Dev/automated_report_phi-3-medium-128k-instruct.md new file mode 100644 index 0000000..a4d2ae9 --- /dev/null +++ b/results/Modern-Apple-Dev/automated_report_phi-3-medium-128k-instruct.md @@ -0,0 +1,988 @@ +# Automated Diagnostic Report: phi-3-medium-128k-instruct + +--- + +## Performance Summary + + +* **Average Tokens/s:** 8.74 +* **Average Time to First Token:** 0.0s +* **Total Tokens Generated:** 6069 + + +## Qualitative Analysis + +*(Manual grading and analysis of the responses is required to determine the final letter grade.)* + +--- + +## Test 1: Write a Swift function that solves the FizzBuzz problem. + +*Source:* `test1.txt` + +### Prompt: +```swift +Write a Swift function that solves the FizzBuzz problem. + +The function must have the exact signature: +`func generateFizzBuzz(upTo max: Int) -> [String]` + +It must not print directly to the console. Instead, it should return an array of strings. + +Rules: +1. For numbers divisible by 3, the string should be "Fizz". +2. For numbers divisible by 5, the string should be "Buzz". +3. For numbers divisible by both 3 and 5, the string should be "FizzBuzz". +4. Otherwise, it should be the number itself as a string. + +Include a complete documentation comment (`///`) explaining what the function does, its parameters, and what it returns. +``` + +### Response: + +```swift +/// Generates an array of FizzBuzz strings up to a given maximum value (inclusive). +/// - Parameters: +/// - max: The maximum number in the sequence. +/// - Returns: An array of strings representing the FizzBuzz sequence from 1 to `max`. +func generateFizzBuzz(upTo max: Int) -> [String] { + var result = [String]() + + for i in 1...max { + let str = "" + + if i % 3 == 0 { + str += "Fizz" + } + + if i % 5 == 0 { + str += "Buzz" + } + + result.append(str.isEmpty ? String(i) : str) + } + + return result +} +``` + +### Performance Metrics: +* **Tokens/s:** 7.91 +* **Total Tokens:** 195 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 2: Create a complete SwiftUI view for a user profile card. + +*Source:* `test2.txt` + +### Prompt: +```swift +Create a complete SwiftUI view for a user profile card. + +The view should be named `UserProfileCard` and be initialized with a simple `User` struct containing `name: String`, `handle: String`, and `avatarURL: URL`. + +Requirements: +- Use an `AsyncImage` to load the user's avatar from the URL. +- Display the user's name in a `.headline` font and their handle (e.g., "@username") in a `.subheadline` font with a secondary color. +- Include a "Follow" button that uses the "person.badge.plus" SF Symbol. +- Arrange the elements cleanly inside an HStack with appropriate spacing. +- The entire card should have a subtle shadow and rounded corners. +``` + +### Response: + +```swift + + import SwiftUI + + + struct UserProfileCard: View { + + let user: User + + + var body: some View { + + HStack(alignment: .leading, spacing: 10) { + + AsyncImage(url: user.avatarURL) + + .resizable() + + .scaledToFill() + + .cornerRadius(8) + + .frame(width: 43, height: 43) + + .clipShape(Circle()) + + Text(user.name) + + .font(.headline) + + Spacer() + + HStack { + + Text("\(user.handle)") + + .font(.subheadline) + + .foregroundColor(.secondary) + + Button(action: {}) { + + Image(systemName: "person.badge.plus") + + .foregroundColor(.accentColor) + + } + + } + + Spacer() + + } + + .shadow(radius: 4, y_offset: 2) + + } + + } + + + struct UserProfileCard_Previews: PreviewProvider { + + static var prefs: [String : Any] = ["com.apple.developer.xpc-process-peruser-ids.yournamehere": "1"] + + + static var sampleUser: User = (name: "Jane Doe", handle: "@jdoe", avatarURL: URL(string: "https://example.com/avatars/jdoe.jpg")!) + + + static var sampleView = UserProfileCard(user: .sampleUser) + + } + + + struct User { + + let name: String + + let handle: String + + let avatarURL: URL + + } + +``` + +### Performance Metrics: +* **Tokens/s:** 9.86 +* **Total Tokens:** 450 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 3: I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +*Source:* `test3.txt` + +### Prompt: +```swift +I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +The new function should be marked with `async throws` and return a `[Post]` object upon success. Also, include an example of how to call this new async function inside a `Task` with a `do-catch` block. + +**Old Code:** +struct Post: Codable { + let id: Int + let title: String +} + +func fetchPosts(completion: @escaping (Result<[Post], Error>) -> Void) { + guard let url = URL(string: "https://api.example.com/posts") else { return } + URLSession.shared.dataTask(with: url) { data, _, error in + if let error = error { completion(.failure(error)); return } + guard let data = data else { return } + do { + let posts = try JSONDecoder().decode([Post].self, from: data) + completion(.success(posts)) + } catch { + completion(.failure(error)) + } + }.resume() +} +``` + +### Response: + +```swift +import Foundation + +struct Post: Codable { + let id: Int + let title: String +} + +func fetchPostsAsync() async throws -> [Post] { + guard let url = URL(string: "https://api.example.com/posts") else { return [] } + + let dataTask = URLSession.shared.dataTaskPublisher(for: url) + .sink { data, response, _ in + if let errorResponse = response as? URLErrorDomain.URLError, case .badServerResponse = errorResponse.code { + throw NSError(domain: NSURLErrorDomain, code: errorResponse.code, userInfo: [NSURLErrorFailingURLErrorKey: url])! + } else if let errorResponse = response as? URLErrorDomain.URLError, case .timedOut = errorResponse.code { + throw NSError(domain: NSURLErrorDomain, code: errorResponse.code, userInfo: [NSURLErrorFailingURLErrorKey: url])! + } else if let errorResponse = response as? URLErrorDomain.URLError, case .otherError = errorResponse.code { + throw NSError(domain: NSURLErrorDomain, code: errorResponse.code, userInfo: [NSURLErrorFailingURLErrorKey: url])! + } else if let httpURLResponse = response as? HTTPURLResponse, !(200...299).contains(httpURLResponse.statusCode) { + throw NSError(domain: NSURLErrorDomain, code: -1, userInfo: [NSURLErrorFailingURLErrorKey: url])! + } else if let httpURLResponse = response as? HTTPURLResponse, !(200...299).contains(httpURLResponse.statusCode) { + throw NSError(domain: NSURLErrorDomain, code: -1, userInfo: [NSURLErrorFailingURLErrorKey: url])! + } else if let httpURLResponse = response as? HTTPURLResponse { + switch httpURLResponse.statusCode { + case 400...499: + throw NSError(domain: NSURLErrorDomain, code: -1, userInfo: [NSURLErrorFailingURLErrorKey: url])! + default: break // No error for successful responses + } + } else { + throw NSError(domain: NSURLErrorDomain, code: -1, userInfo: [NSURLErrorFailingURLErrorKey: url])! + } + }.eraseToAnyPublisher() + + let (result) = await dataTask.sink { data in + return try JSONDecoder().decode([Post].self, from: data).mapError(convertFromURLErrorCode) + }.receive().cancellable().fuseForever() + + return result.value ?? [] +} + +func convertFromURLErrorCode(_ error: Error) -> Error { + switch error as? NSError { + case let e as NSError & URLErrorDomain.URLError?: + if let code = e.code, let domain = e.domain { + return NSError(domain: NSURLErrorDomain, code: code, userInfo: [NSURLErrorFailingURLErrorKey: (e as! URLError).url])! + } else { + return error + } + default: + return error + } +} +``` +**Example of calling the new async function inside a `Task` with a `do-catch` block:** +```swift +Task { do { + let posts = try await fetchPostsAsync() + // Handle successful response here +} catch { + print(error) // Print error message if any +} +``` + +### Performance Metrics: +* **Tokens/s:** 9.58 +* **Total Tokens:** 896 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 4: Create a complete SwiftData example for a macOS 26 app. + +*Source:* `test4.txt` + +### Prompt: +```swift +Create a complete SwiftData example for a macOS 26 app. + +You must define two models: `Author` and `Book`. An `Author` can have many `Book`s (a one-to-many relationship). + +Then, create a SwiftUI view that displays a list of all authors. When an author's name is tapped, it should navigate to a detail view that shows a list of all the books written by that specific author. Use a SwiftData `@Query` to fetch the data. +``` + +### Response: + +1. Define the `Author` and `Book` models with Core Data: + +```swift +import CoreData + +class Author: NSManagedObject { + @NSManaged var name: String + @NSManaged var books: Set +} + +class Book: NSManagedObject { + @NSManaged var title: String + @NSManaged var author: Author? +} +``` + +2. Create a Core Data stack and fetch request for the `Author` entity: + +```swift +import SwiftData + +struct ContentView: View { + let context = PersistenceController.shared.container.persistentStoreCoordinator?.managedObjectContext! + + var body: some View { + List(fetchRequest, id: \.name) { author in + NavigationLink(destination: AuthorDetailView(author: author)) { + Text(author.name) + } + } + } +} +``` + +3. Create the `Author` fetch request and sort it by name: + +```swift +let authors = FetchRequest(fetchLimit: .few, sortDescriptors: [NSSortDescriptor(keyPath: \Author.name, ascending: true)]) + .query { query in + let predicate = NSPredicate(format: "self.books.@count > 0") + return query.predicate == nil ? predicate : nil + } +``` + +4. Create the `Book` fetch request and sort it by title: + +```swift +let books = FetchRequest(fetchLimit: .few, sortDescriptors: [NSSortDescriptor(keyPath: \Book.title, ascending: true)]) + .query { query in + return query.predicate == nil ? NSPredicate(format: "self.author != NULL") : nil + } +``` + +5. Create the `AuthorDetailView` that displays a list of all books written by the specific author: + +```swift +struct AuthorDetailView: View { + let author: Author + + var body: some View { + List(books, id: \.title) { book in + Text(book.title) + } + } +} +``` + +6. Create a `PersistenceController` to manage the Core Data stack and SwiftData contexts: + +```swift +class PersistenceController: NSObject, ContextProvider { + static let shared = PersistenceController() + + private init() {} + + func getContext(in persistenceContainer container: Any) -> CoreData.PersistentContainer? { + guard let persistentStoreCoordinator = container.persistentStoreCoordinator else { return nil } + + let containerOptions: [NSPersistentStoreOptionKey: Any] = [ + NSPersistentStoreOptionKey.shouldCreateStorageIfNeeded: true, + NSPersistentStoreOptionKey.isNewTransaction: false, + NSPersistentStoreOptionKey.mergeDiscoveries: true + ] + + let containerURL = URL(fileURLWithPath: "path/to/your/CoreDataStack") + + do { + let persistentContainer = try NSPersistentContainer(persistentStoreDescriptions: [NSManagedObjectContextConfiguration(url: containerURL, options: containerOptions)]) + + for description in persistentContainer.persistentStoreDescriptions { + try persistentContainer.loadPersistentStores { _, error in + if let error = error as? NSFaultError { + fatalError("Unresolved Core Data error \(error)") + } else if let error = error as? ErrorType { + print(error) + } + } + } + + return persistentContainer.viewContext + } catch { + fatalError("Failed to initialize the persistence container: \(error)") + } + + return nil + } +} +``` + +7. Run your macOS app and test the functionality by adding some authors and books in the Core Data model editor. + +### Performance Metrics: +* **Tokens/s:** 9.8 +* **Total Tokens:** 917 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 5: Write a thread-safe counter class in Swift using an `actor`. + +*Source:* `test5.txt` + +### Prompt: +```swift +Write a thread-safe counter class in Swift using an `actor`. + +The actor should be named `SafeCounter`. It must have a private property to hold the current count and two public methods: +1. `func increment() async` +2. `func getCount() async -> Int` + +Also, provide a simple example of how to create an instance of the actor and call its methods concurrently from two different `Task`s. +``` + +### Response: + +```swift +import Foundation + +actor SafeCounter { + private(set) var count = 0 + + func increment() async { + self.count += 1 + } + + func getCount() async -> Int { + return await actorScope.run { + return self.count + } + } +} + +let counterActor = SafeCounter() + +Task { + for _ in 0..<5 { + await counterActor.increment() + } +} + +Task { + let count1 = await counterActor.getCount() + print("Count from Task 1: \(count1)") + + let count2 = await counterActor.getCount() + print("Count from Task 2: \(count2)") +} +``` + +In this example, we define a `SafeCounter` actor with two methods: `increment()` and `getCount()`. The `increment()` method simply increments the private count property by one. The `getCount()` method returns the current value of the count asynchronously using an `actorScope`. + +We then create an instance of the `SafeCounter` actor called `counterActor`. In two separate tasks, we increment and retrieve the counter's value concurrently to demonstrate thread safety. + +### Performance Metrics: +* **Tokens/s:** 9.57 +* **Total Tokens:** 292 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 6: Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +*Source:* `test6.txt` + +### Prompt: +```swift +Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +The code must include: +1. A `TimelineProvider` to generate the timeline entries. +2. A `TimelineEntry` struct. +3. The main `Widget` struct. +4. A SwiftUI view for the complication's appearance. + +Ensure the code correctly uses the modern WidgetKit framework. +``` + +### Response: + +```swift + + import WidgetKit + + import Foundation + + + // TimelineEntry to represent a single entry in our timeline + + struct DateTimelineEntry: TimelineEntry { + + let date: Date + + var preferredSize: CGSize { .init(width: 200, height: 100) } + + + func getFutureItems(_ interval: Int) -> [Date]? { + + return [] // No future items needed for a static complication. + + } + + } + + + // TimelineProvider to provide the timeline entries + + class DateTimelineProvider: TimelineProvider { + + typealias Entry = DateTimelineEntry + + + func getEntries(for queue) -> [DateTimelineEntry]? { + + let now = Calendar.current.dateComponents([.year, .month], from: Date()) + + let dateString = "\(now.year)-\(now.month)" // Simplified for example purposes + + return [DateTimelineEntry(date: Date(timeIntervalSinceNow: -60 * 24))] // Static entry representing the current day + + } + + } + + + // Widget struct that conforms to ComplicationConfigurable and TimelineProvider + + class DateComplicationWidget: Widget { + + typealias Entry = DateTimelineEntry + + + required init(configuration: Configuration) { + + super.init(configuration: configuration, provider: DateTimelineProvider()) + + } + + + func timeline(for context: TimelineContext) -> some View? { + + return GeometryReader { geometry in + + VStack { + + Text("\(context.entry.date, formatter: .shortMedium)") // Display the date using a short medium style + + } + + } + + } + + } + + + // Companion view for the widget's appearance in the complication bar + + struct DateComplicationWidgetView: UIViewRepresentable { + + var context: Context + + + func makeUIView(context: Context) -> UIView { + + let dateLabel = UILabel() + + dateLabel.textAlignment = .center + + return dateLabel + + } + + + func updateUIView(_ view: UIView, context: Context) { + + // Update the label with the current date here if needed + + } + + } + + + // Companion struct for the widget's appearance in the complication bar + + struct DateComplicationWidget_Configuration: Configuration.EstimatedTimelineGroupingConfig, TimelineGroupingConfig { + + static var estimatedDurationForEntry: Int { 140 } + + static var groupingPeriod: Int { 24 * 60 * 60 } // One day in seconds + + } + + + @available(iOS 14.0, *) + + export class DateComplicationWidgetProvider: TimelineProvider { + + typealias Entry = DateTimelineEntry + + + func getEntries(for queue) -> [DateTimelineEntry]? { + + return [] // No future items needed for a static complication. + + } + + } + + + @available(iOS 14.0, *) + + export class DateComplicationWidget: ComplicationConfigurable { + + var configuration = TimelineGroupingConfig() + + + func configure(_ cfg: Configuration) -> Void { + + self.configuration = cfg + + } + + } + +``` + +### Performance Metrics: +* **Tokens/s:** 8.72 +* **Total Tokens:** 823 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 7: Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +*Source:* `test7.txt` + +### Prompt: +```swift +Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +**Old Code:** +class UserSettings: ObservableObject { + @Published var score: Int = 0 + @Published var username: String = "Guest" +} + +struct SettingsView: View { + @StateObject private var settings = UserSettings() + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +### Response: + +```swift +import SwiftUI + +struct UserSettings: ObservableObject { + @Published var score: Int = 0 + @Published var username: String = "Guest" + + init() {} +} + +struct SettingsView: View { + @StateObject private var settings = UserSettings() + var body: some View { + Form { + TextField("Username", text: $settings.username) + .keyboardType(.text) + + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +In this refactored code, we use the `@StateObject` property wrapper instead of `@Published`. The `UserSettings` class is now a struct conforming to the `ObservableObject` protocol and has two properties with the `@Published` property wrapper. + +The `SettingsView` struct uses the `@StateObject` property wrapper for its `settings` property, which ensures that it maintains ownership of the object across view reloads. The rest of the code remains unchanged. + +### Performance Metrics: +* **Tokens/s:** 7.49 +* **Total Tokens:** 242 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 8: Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. + +*Source:* `test8.txt` + +### Prompt: +```swift +Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. +``` + +### Response: + +To create a simple configurable WidgetKit widget for iOS 26 that displays a single "Note" string using the modern App Intents framework, follow these steps: + +1. Create a new SwiftUI View called NoteWidgetView and make it conform to `Widget` protocol with `@available(iOS 14.0, *)` attribute. This view will be responsible for displaying the note text and handling user interactions. +2. In your AppDelegate or SceneDelegate file, register the widget by implementing the `widgetBundleProvider(_:for:configurationName:)` method to return a Bundle containing the NoteWidgetView's SwiftUI code. +3. Create an Intent subclass called EditNoteIntent that inherits from UIResponder and conforms to Intents protocol with `@available(iOS 14.0, *)` attribute. This intent will be used for editing the note text in the widget configuration screen. +4. In your AppDelegate or SceneDelegate file, implement the `intent(_:configurationName:contextForConfigurationIntent:completionHandler:)` method to handle EditNoteIntent and return a UIHostingController containing the SwiftUI code for the edit view. +5. Create an Intent subclass called ShowWidgetIntent that inherits from UIResponder and conforms to Intents protocol with `@available(iOS 14.0, *)` attribute. This intent will be used for showing the widget on the home screen. +6. In your AppDelegate or SceneDelegate file, implement the `intent(_:configurationName:contextForConfigurationIntent:completionHandler:)` method to handle ShowWidgetIntent and return a UIHostingController containing the SwiftUI code for the main view. +7. Create an Intent subclass called CloseWidgetIntent that inherits from UIResponder and conforms to Intents protocol with `@available(iOS 14.0, *)` attribute. This intent will be used for closing the widget on the home screen. +8. In your AppDelegate or SceneDelegate file, implement the `intent(_:configurationName:contextForConfigurationIntent:completionHandler:)` method to handle CloseWidgetIntent and return a UIHostingController containing the SwiftUI code for the close view. +9. Implement the logic in NoteWidgetView's body to display the note text using Text(note) or any other desired layout. Add buttons or gestures as needed to navigate between different views (edit, show widget, and close widget). +10. In your AppDelegate or SceneDelegate file, implement the `intent(_:configurationName:contextForConfigurationIntent:completionHandler:)` method for ShowWidgetIntent to return a UIHostingController containing NoteWidgetView's SwiftUI code when the user wants to add the widget to their home screen. +11. Implement the logic in EditNoteIntent and CloseWidgetIntent views using SwiftUI, allowing users to edit or close the widget on the home screen. + +Here is an example of how your code might look: + +```swift +import WidgetKit +import SwiftUI + +struct NoteWidgetView: View { + @Binding var note: String + + var body: some View { + VStack(spacing: 20) { + Text(note) + .font(.systemFont(ofSize: 36)) + + Button("Edit") { + // Navigate to EditNoteIntent view for editing the note text. + } + + Button("Show Widget") { + // Show widget on home screen using ShowWidgetIntent. + } + } + } +} + +class EditNoteIntent: UIResponder, Intents { + var configurationName = "edit-note" + + func configure(_ intentContext: Context) -> Bool { + // Implement the logic to edit note text here. + + return true + } +} + +class ShowWidgetIntent: UIResponder, Intents { + var configurationName = "show-widget" + + func configure(_ intentContext: Context) -> Bool { + // Implement the logic to show widget on home screen here. + + return true + } +} + +class CloseWidgetIntent: UIResponder, Intents { + var configurationName = "close-widget" + + func configure(_ intentContext: Context) -> Bool { + // Implement the logic to close widget on home screen here. + + return true + } +} +``` + +Remember that this is just a basic example, and you may need to customize it further based on your specific requirements. + +### Performance Metrics: +* **Tokens/s:** 8.22 +* **Total Tokens:** 1011 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 9: Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +*Source:* `test9.txt` + +### Prompt: +```swift +Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +The view must: +1. Have a button labeled "Enter Immersive Space". +2. Use the `@Environment(\.openImmersiveSpace)` and `@Environment(\.dismissImmersiveSpace)` variables. +3. Be able to open an immersive space with the ID "MyImmersiveScene". +4. Include a second button inside the immersive space to dismiss it. +``` + +### Response: + +```swift + import SwiftUI + + struct ImmersiveView: View { + @Environment(\.openImmersiveSpace) var openImmersiveSpace + @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace + + var body: some View { + VStack { + Button(action: { + if let scene = UIViewControllerRepresentableScene(sceneID: "MyImmersiveScene") { + openImmersiveSpace(scene) + } + }) { + Text("Enter Immersive Space") + } + + Button(action: dismissImmersiveSpace) { + Text("Dismiss Immersive Space") + } + } + } + } +``` + +### Performance Metrics: +* **Tokens/s:** 7.18 +* **Total Tokens:** 170 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 10: Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +*Source:* `test10.txt` + +### Prompt: +```swift +Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +This layout should arrange its subviews in a horizontal flow, starting a new row when the current row is full. It should behave similarly to a basic left-aligned flow layout in CSS. + +The implementation must conform to the `Layout` protocol and implement both the `sizeThatFits(...)` and `placeSubviews(...)` methods. +``` + +### Response: + +To create a custom SwiftUI Layout container called `SimpleFlowLayout`, you can follow these steps: + +1. Import the necessary modules: +```swift +import SwiftUI +``` +2. Define the `SimpleFlowLayout` struct that conforms to the `Layout` protocol: +```swift +struct SimpleFlowLayout: Layout { + var alignment: HorizontalAlignment = .start + + func measure(in context: Context, configuration: NSDirectionalCombineShapeConfiguration) -> CGSize { + let sizeThatFits = CGSize.zero + + // Iterate through the subviews and calculate their sizes + for view in self.subviews { + let viewSize = view.layout(in: context, with: configuration).size() + + if alignment == .start { + sizeThatFits.width += viewSize.width + } else if alignment == .center { + sizeThatFits.width += viewSize.width * 2 - (viewSize.width / 2) + } else if alignment == .end { + sizeThatFits.width += viewSize.width + } + } + + return sizeThatFits + } + + func layout(in nib: UIView, cgContext: CGContext, subviews: [UIView], @ViewChildren var indexSet) { + let stack = UIStackView() + stack.axis = .horizontal + stack.alignment = alignment + + // Add the subviews to the stack view + for view in self.subviews { + let swiftUIView = view.view(in: nib) as! UIView + stack.addArrangedSubview(swiftUIView) + } + + // Set up constraints and layout the stack view + var leftMargin = 0 + for index in indexSet { + let swiftUIView = subviews[index].view(in: nib) as! UIView + + if alignment == .start || alignment == .center { + swiftUIView.translatesAutoresizingMaskIntoConstraints = false + + // Set up constraints for the left edge of the view + let xConstraint = NSLayoutConstraint(item: swiftUIView, attribute: .leading, relatedBy: .equal, toItem: nib, attribute: .leftMargin, multiplier: 1.0, constant: leftMargin) + + // Set up constraints for the right edge of the view + let xConstraint2 = NSLayoutConstraint(item: swiftUIView, attribute: .trailing, relatedBy: .equal, toItem: nib, attribute: .rightMargin, multiplier: 1.0, constant: -stack.frame.width) + + // Add constraints to the stack view + stack.addConstraints([xConstraint, xConstraint2]) + } else if alignment == .end { + swiftUIView.translatesAutoresizingMaskIntoConstraints = false + + // Set up constraints for the right edge of the view + let xConstraint = NSLayoutConstraint(item: swiftUIView, attribute: .trailing, relatedBy: .equal, toItem: nib, attribute: .rightMargin, multiplier: 1.0, constant: -stack.frame.width) + + // Set up constraints for the left edge of the view + let xConstraint2 = NSLayoutConstraint(item: swiftUIView, attribute: .leading, relatedBy: .equal, toItem: nib, attribute: .rightMargin, multiplier: 1.0, constant: -leftMargin) + + // Add constraints to the stack view + stack.addConstraints([xConstraint, xConstraint2]) + } + + leftMargin += swiftUIView.frame.width + (stack.spacing ?? 0) + } + + nib.addSubview(stack) + } +} +``` +3. Use the `SimpleFlowLayout` in your SwiftUI views: +```swift +struct ContentView: View { + var body: some View { + VStack { + Text("Row 1") + .frame(width: 200, height: 50) + + Text("Row 2") + .frame(width: 200, height: 50) + + Text("Row 3") + .frame(width: 200, height: 50) + } + }.background(SimpleFlowLayout()) +} +``` +In this example, the `ContentView` uses a `VStack` to vertically stack three rows of text views. The `SimpleFlowLayout` is applied as the background view for each row, arranging them in a horizontal flow with left alignment. + +### Performance Metrics: +* **Tokens/s:** 9.03 +* **Total Tokens:** 1073 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + diff --git a/results/Modern-Apple-Dev/automated_report_starcoder2-15b-instruct-v0.1.md b/results/Modern-Apple-Dev/automated_report_starcoder2-15b-instruct-v0.1.md new file mode 100644 index 0000000..bb5c8ee --- /dev/null +++ b/results/Modern-Apple-Dev/automated_report_starcoder2-15b-instruct-v0.1.md @@ -0,0 +1,621 @@ +# Automated Diagnostic Report: starcoder2-15b-instruct-v0.1 + +--- + +## Performance Summary + + +* **Average Tokens/s:** 7.04 +* **Average Time to First Token:** 0.0s +* **Total Tokens Generated:** 2139 + + +## Qualitative Analysis + +*(Manual grading and analysis of the responses is required to determine the final letter grade.)* + +--- + +## Test 1: Write a Swift function that solves the FizzBuzz problem. + +*Source:* `test1.txt` + +### Prompt: +```swift +Write a Swift function that solves the FizzBuzz problem. + +The function must have the exact signature: +`func generateFizzBuzz(upTo max: Int) -> [String]` + +It must not print directly to the console. Instead, it should return an array of strings. + +Rules: +1. For numbers divisible by 3, the string should be "Fizz". +2. For numbers divisible by 5, the string should be "Buzz". +3. For numbers divisible by both 3 and 5, the string should be "FizzBuzz". +4. Otherwise, it should be the number itself as a string. + +Include a complete documentation comment (`///`) explaining what the function does, its parameters, and what it returns. +``` + +### Response: + +Here's how you can implement this: + +```swift +func generateFizzBuzz(upTo max: Int) -> [String] { + var result = [String]() + + for i in 1...max { + if i % 3 == 0 && i % 5 == 0 { + result.append("FizzBuzz") + } else if i % 3 == 0 { + result.append("Fizz") + } else if i % 5 == 0 { + result.append("Buzz") + } else { + result.append("\(i)") + } + } + + return result +} +``` + +This implementation uses a `for` loop to iterate over the numbers from 1 up to and including the maximum value. For each number, it checks if it's divisible by both 3 and 5, then by 3, then by 5, and finally, if none of these conditions are met. If any of these conditions is true, it appends the appropriate string to the result array. At the end of the function, it returns the result array. + +[Documentation] +The documentation comment explains what the function does, its parameters, and what it returns: + +```swift +/// Generates an array of strings representing the FizzBuzz problem up to a given maximum value. +/// - Parameter max: The maximum value to generate FizzBuzz numbers up to. +/// - Returns: An array of strings representing the FizzBuzz numbers up to `max`. +func generateFizzBuzz(upTo max: Int) -> [String] { + ... +} +``` + +### Performance Metrics: +* **Tokens/s:** 7.96 +* **Total Tokens:** 350 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 2: Create a complete SwiftUI view for a user profile card. + +*Source:* `test2.txt` + +### Prompt: +```swift +Create a complete SwiftUI view for a user profile card. + +The view should be named `UserProfileCard` and be initialized with a simple `User` struct containing `name: String`, `handle: String`, and `avatarURL: URL`. + +Requirements: +- Use an `AsyncImage` to load the user's avatar from the URL. +- Display the user's name in a `.headline` font and their handle (e.g., "@username") in a `.subheadline` font with a secondary color. +- Include a "Follow" button that uses the "person.badge.plus" SF Symbol. +- Arrange the elements cleanly inside an HStack with appropriate spacing. +- The entire card should have a subtle shadow and rounded corners. +``` + +### Response: + +Here's how you can implement this: + +```swift +struct UserProfileCard: View { + let user: User + + var body: some View { + VStack(alignment: .leading, spacing: 8) { + AsyncImage(url: user.avatarURL) { image in + image + .resizable() + .aspectRatio(contentMode: .fill) + .frame(width: 64, height: 64) + .clipShape(Circle()) + } placeholder: { + Circle() + .frame(width: 64, height: 64) + .opacity(0.3) + } + + Text(user.name) + .font(.headline) + + Text("@\(user.handle)") + .font(.subheadline) + .foregroundColor(.secondary) + + Button { + // Follow user + } label: { + Label("Follow", systemImage: "person.badge.plus") + } + } + .padding() + .background(Color(.systemBackground)) + .cornerRadius(12) + .shadow(color: Color(.systemGray4), radius: 8, x: 0, y: 4) + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 8.88 +* **Total Tokens:** 256 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 3: I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +*Source:* `test3.txt` + +### Prompt: +```swift +I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +The new function should be marked with `async throws` and return a `[Post]` object upon success. Also, include an example of how to call this new async function inside a `Task` with a `do-catch` block. + +**Old Code:** +struct Post: Codable { + let id: Int + let title: String +} + +func fetchPosts(completion: @escaping (Result<[Post], Error>) -> Void) { + guard let url = URL(string: "https://api.example.com/posts") else { return } + URLSession.shared.dataTask(with: url) { data, _, error in + if let error = error { completion(.failure(error)); return } + guard let data = data else { return } + do { + let posts = try JSONDecoder().decode([Post].self, from: data) + completion(.success(posts)) + } catch { + completion(.failure(error)) + } + }.resume() +} +``` + +### Response: + +Here's how you can refactor the old code to use modern Swift Concurrency with async/await: + +```swift +import Foundation + +struct Post: Codable { + let id: Int + let title: String +} + +func fetchPosts() async throws -> [Post] { + guard let url = URL(string: "https://api.example.com/posts") else { throw URLError(.badURL) } + do { + let (data, _) = try await URLSession.shared.data(from: url) + return try JSONDecoder().decode([Post].self, from: data) + } catch { + throw error + } +} +``` + +The new `fetchPosts()` function is marked with `async throws` to indicate that it's an asynchronous function that can throw errors. It returns a `[Post]` object upon successful completion. + +To call the new async function inside a `Task` with a `do-catch` block, you can use the following code: + +```swift +Task { + do { + let posts = try await fetchPosts() + print(posts) + } catch { + print(error.localizedDescription) + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 8.4 +* **Total Tokens:** 257 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 4: Create a complete SwiftData example for a macOS 26 app. + +*Source:* `test4.txt` + +### Prompt: +```swift +Create a complete SwiftData example for a macOS 26 app. + +You must define two models: `Author` and `Book`. An `Author` can have many `Book`s (a one-to-many relationship). + +Then, create a SwiftUI view that displays a list of all authors. When an author's name is tapped, it should navigate to a detail view that shows a list of all the books written by that specific author. Use a SwiftData `@Query` to fetch the data. +``` + +### Response: + +Here's how you can define the two models and create the SwiftUI view: + +```swift +import Foundation +import SwiftData + +struct Author: Identifiable { + var id = UUID() + var name: String +} + +struct Book: Identifiable { + var id = UUID() + var title: String + var authorID: UUID +} + +extension Author: SDModel { + static let schema = SDSchema( + Author.self, + \.$id, + \.$name + ) +} + +extension Book: SDModel { + static let schema = SDSchema( + Book.self, + \.$id, + \.$title, + \.$authorID + ) +} + +import SwiftUI + +struct AuthorRow: View { + var author: Author + + var body: some View { + Text(author.name) + } +} + +struct AuthorDetail: View { + @Query var books: [Book] + + var body: some View { + List(books, id: \.id) { book in + Text(book.title) + } + } +} + +struct AuthorsList: View { + @Query var authors: [Author] + + var body: some View { + NavigationView { + List(authors, id: \.id) { author in + NavigationLink(destination: AuthorDetail(books: books(forAuthorID: author.id))) { + AuthorRow(author: author) + } + } + } + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 8.15 +* **Total Tokens:** 321 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 5: Write a thread-safe counter class in Swift using an `actor`. + +*Source:* `test5.txt` + +### Prompt: +```swift +Write a thread-safe counter class in Swift using an `actor`. + +The actor should be named `SafeCounter`. It must have a private property to hold the current count and two public methods: +1. `func increment() async` +2. `func getCount() async -> Int` + +Also, provide a simple example of how to create an instance of the actor and call its methods concurrently from two different `Task`s. +``` + +### Response: +**ERROR:** API request failed: HTTPConnectionPool(host='localhost', port=1234): Read timed out. (read timeout=180) + +### Performance Metrics: +* **Tokens/s:** N/A +* **Total Tokens:** N/A +* **Time to First Token:** N/A +* **Stop Reason:** N/A + +--- + +## Test 6: Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +*Source:* `test6.txt` + +### Prompt: +```swift +Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +The code must include: +1. A `TimelineProvider` to generate the timeline entries. +2. A `TimelineEntry` struct. +3. The main `Widget` struct. +4. A SwiftUI view for the complication's appearance. + +Ensure the code correctly uses the modern WidgetKit framework. +``` + +### Response: + +Here's an example of how you can implement a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family: + +```swift +import WidgetKit +import SwiftUI + +struct Provider: TimelineProvider { + func placeholder(in context: Context) -> SimpleEntry { + SimpleEntry(date: Date()) + } + + func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) { + let entry = SimpleEntry(date: Date()) + completion(entry) + } + + func getTimeline(in context: Context, completion: @escaping (Timeline) -> ()) { + let currentDate = Date() + let refreshDate = Calendar.current.date(byAdding: .minute, value: 1, to: currentDate)! + + let entry = SimpleEntry(date: currentDate) + let timeline = Timeline(entries: [entry], policy: .after(refreshDate)) + completion(timeline) + } +} + +struct SimpleEntry: TimelineEntry { + let date: Date +} + +struct SimpleComplicationEntryView : View { + var entry: Provider.Entry + + var body: some View { + Text(entry.date, style: .time) + .widgetURL(URL(string: "my-app://open-app")) + } +} + +@main +struct SimpleComplication: Widget { + let kind: String = "SimpleComplication" + + var body: some WidgetConfiguration { + StaticConfiguration(kind: kind, provider: Provider()) { entry in + SimpleComplicationEntryView(entry: entry) + } + .configurationDisplayName("Simple Complication") + .description("A simple complication that displays the current date.") + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 6.29 +* **Total Tokens:** 383 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 7: Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +*Source:* `test7.txt` + +### Prompt: +```swift +Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +**Old Code:** +class UserSettings: ObservableObject { + @Published var score: Int = 0 + @Published var username: String = "Guest" +} + +struct SettingsView: View { + @StateObject private var settings = UserSettings() + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +### Response: + +Here's how you can refactor the code to use the `@Observable` macro: + +```swift +@Observable class UserSettings { + var score: Int = 0 + var username: String = "Guest" +} + +struct SettingsView: View { + @StateObject private var settings = UserSettings() + + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 5.58 +* **Total Tokens:** 114 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 8: Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. + +*Source:* `test8.txt` + +### Prompt: +```swift +Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. +``` + +### Response: +**ERROR:** API request failed: HTTPConnectionPool(host='localhost', port=1234): Read timed out. (read timeout=180) + +### Performance Metrics: +* **Tokens/s:** N/A +* **Total Tokens:** N/A +* **Time to First Token:** N/A +* **Stop Reason:** N/A + +--- + +## Test 9: Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +*Source:* `test9.txt` + +### Prompt: +```swift +Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +The view must: +1. Have a button labeled "Enter Immersive Space". +2. Use the `@Environment(\.openImmersiveSpace)` and `@Environment(\.dismissImmersiveSpace)` variables. +3. Be able to open an immersive space with the ID "MyImmersiveScene". +4. Include a second button inside the immersive space to dismiss it. +``` + +### Response: + +Here's how you can implement this: + +```swift +struct MyView: View { + @Environment(\.openImmersiveSpace) var openImmersiveSpace + @Environment(\.dismissImmersiveSpace) var dismissImmersiveSpace + + var body: some View { + VStack { + Button("Enter Immersive Space") { + openImmersiveSpace("MyImmersiveScene") + } + + if isImmersiveSpaceOpen { + Button("Exit Immersive Space") { + dismissImmersiveSpace() + } + } + } + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 5.47 +* **Total Tokens:** 128 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + +## Test 10: Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +*Source:* `test10.txt` + +### Prompt: +```swift +Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +This layout should arrange its subviews in a horizontal flow, starting a new row when the current row is full. It should behave similarly to a basic left-aligned flow layout in CSS. + +The implementation must conform to the `Layout` protocol and implement both the `sizeThatFits(...)` and `placeSubviews(...)` methods. +``` + +### Response: + +Here's how you can create a custom SwiftUI Layout container called `SimpleFlowLayout`: + +```swift +import SwiftUI + +struct SimpleFlowLayout: Layout { + func sizeThatFits(proposal: ProposedViewSize, subviews: [Subview]) -> CGSize { + var width = proposal.width + var height = proposal.height + + for subview in subviews { + let subviewSize = subview.sizeThatFits(proposal) + if width + subviewSize.width > proposal.width { + width = 0 + height += subviewSize.height + } + + width += subviewSize.width + } + + return CGSize(width: width, height: height) + } + + func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: [Subview]) { + var x = bounds.minX + var y = bounds.minY + var rowHeight = 0.0 + + for subview in subviews { + let subviewSize = subview.sizeThatFits(proposal) + + if x + subviewSize.width > bounds.width { + x = bounds.minX + y += CGFloat(rowHeight) + rowHeight = 0 + } + + subview.place(at: CGRect(x: x, y: y, width: subviewSize.width, height: subviewSize.height)) + x += subviewSize.width + rowHeight = max(rowHeight, subviewSize.height) + } + } +} +``` + +### Performance Metrics: +* **Tokens/s:** 5.55 +* **Total Tokens:** 330 +* **Time to First Token:** 0.0s +* **Stop Reason:** stop + +--- + diff --git a/tests/test1.txt b/tests/test1.txt new file mode 100644 index 0000000..ec41624 --- /dev/null +++ b/tests/test1.txt @@ -0,0 +1,14 @@ +Write a Swift function that solves the FizzBuzz problem. + +The function must have the exact signature: +`func generateFizzBuzz(upTo max: Int) -> [String]` + +It must not print directly to the console. Instead, it should return an array of strings. + +Rules: +1. For numbers divisible by 3, the string should be "Fizz". +2. For numbers divisible by 5, the string should be "Buzz". +3. For numbers divisible by both 3 and 5, the string should be "FizzBuzz". +4. Otherwise, it should be the number itself as a string. + +Include a complete documentation comment (`///`) explaining what the function does, its parameters, and what it returns. diff --git a/tests/test10.txt b/tests/test10.txt new file mode 100644 index 0000000..f520173 --- /dev/null +++ b/tests/test10.txt @@ -0,0 +1,5 @@ +Create a custom SwiftUI Layout container called `SimpleFlowLayout`. + +This layout should arrange its subviews in a horizontal flow, starting a new row when the current row is full. It should behave similarly to a basic left-aligned flow layout in CSS. + +The implementation must conform to the `Layout` protocol and implement both the `sizeThatFits(...)` and `placeSubviews(...)` methods. diff --git a/tests/test2.txt b/tests/test2.txt new file mode 100644 index 0000000..12634be --- /dev/null +++ b/tests/test2.txt @@ -0,0 +1,10 @@ +Create a complete SwiftUI view for a user profile card. + +The view should be named `UserProfileCard` and be initialized with a simple `User` struct containing `name: String`, `handle: String`, and `avatarURL: URL`. + +Requirements: +- Use an `AsyncImage` to load the user's avatar from the URL. +- Display the user's name in a `.headline` font and their handle (e.g., "@username") in a `.subheadline` font with a secondary color. +- Include a "Follow" button that uses the "person.badge.plus" SF Symbol. +- Arrange the elements cleanly inside an HStack with appropriate spacing. +- The entire card should have a subtle shadow and rounded corners. diff --git a/tests/test3.txt b/tests/test3.txt new file mode 100644 index 0000000..90a168f --- /dev/null +++ b/tests/test3.txt @@ -0,0 +1,23 @@ +I have this old networking code that uses a completion handler. Please refactor it to use modern Swift Concurrency with async/await. + +The new function should be marked with `async throws` and return a `[Post]` object upon success. Also, include an example of how to call this new async function inside a `Task` with a `do-catch` block. + +**Old Code:** +struct Post: Codable { + let id: Int + let title: String +} + +func fetchPosts(completion: @escaping (Result<[Post], Error>) -> Void) { + guard let url = URL(string: "https://api.example.com/posts") else { return } + URLSession.shared.dataTask(with: url) { data, _, error in + if let error = error { completion(.failure(error)); return } + guard let data = data else { return } + do { + let posts = try JSONDecoder().decode([Post].self, from: data) + completion(.success(posts)) + } catch { + completion(.failure(error)) + } + }.resume() +} diff --git a/tests/test4.txt b/tests/test4.txt new file mode 100644 index 0000000..91d2b17 --- /dev/null +++ b/tests/test4.txt @@ -0,0 +1,5 @@ +Create a complete SwiftData example for a macOS 26 app. + +You must define two models: `Author` and `Book`. An `Author` can have many `Book`s (a one-to-many relationship). + +Then, create a SwiftUI view that displays a list of all authors. When an author's name is tapped, it should navigate to a detail view that shows a list of all the books written by that specific author. Use a SwiftData `@Query` to fetch the data. diff --git a/tests/test5.txt b/tests/test5.txt new file mode 100644 index 0000000..10aba1e --- /dev/null +++ b/tests/test5.txt @@ -0,0 +1,7 @@ +Write a thread-safe counter class in Swift using an `actor`. + +The actor should be named `SafeCounter`. It must have a private property to hold the current count and two public methods: +1. `func increment() async` +2. `func getCount() async -> Int` + +Also, provide a simple example of how to create an instance of the actor and call its methods concurrently from two different `Task`s. diff --git a/tests/test6.txt b/tests/test6.txt new file mode 100644 index 0000000..5137d25 --- /dev/null +++ b/tests/test6.txt @@ -0,0 +1,9 @@ +Create the code for a simple, non-configurable watchOS 26 complication that displays the current date in the `.accessoryRectangular` family. + +The code must include: +1. A `TimelineProvider` to generate the timeline entries. +2. A `TimelineEntry` struct. +3. The main `Widget` struct. +4. A SwiftUI view for the complication's appearance. + +Ensure the code correctly uses the modern WidgetKit framework. diff --git a/tests/test7.txt b/tests/test7.txt new file mode 100644 index 0000000..2db230e --- /dev/null +++ b/tests/test7.txt @@ -0,0 +1,17 @@ +Refactor this SwiftUI view and its `ObservableObject` to use the modern `@Observable` macro introduced in Swift 5.9. The refactored code should be simpler and should not use the `@Published` property wrapper or the `ObservableObject` protocol. + +**Old Code:** +class UserSettings: ObservableObject { + @Published var score: Int = 0 + @Published var username: String = "Guest" +} + +struct SettingsView: View { + @StateObject private var settings = UserSettings() + var body: some View { + Form { + TextField("Username", text: $settings.username) + Stepper("Score: \(settings.score)", value: $settings.score) + } + } +} diff --git a/tests/test8.txt b/tests/test8.txt new file mode 100644 index 0000000..d688cc7 --- /dev/null +++ b/tests/test8.txt @@ -0,0 +1 @@ +Create the code for a simple, configurable WidgetKit widget for iOS 26. The widget should display a single "Note" string. The configuration logic must use the modern App Intents framework, allowing the user to edit the note's text directly from the widget's configuration screen. Do not use the old `INIntent` based system. diff --git a/tests/test9.txt b/tests/test9.txt new file mode 100644 index 0000000..394da4c --- /dev/null +++ b/tests/test9.txt @@ -0,0 +1,7 @@ +Write a complete SwiftUI view for visionOS 26 that presents a fully immersive space when a button is tapped. + +The view must: +1. Have a button labeled "Enter Immersive Space". +2. Use the `@Environment(\.openImmersiveSpace)` and `@Environment(\.dismissImmersiveSpace)` variables. +3. Be able to open an immersive space with the ID "MyImmersiveScene". +4. Include a second button inside the immersive space to dismiss it.