{"record":{"id":"12ad0e03df1d85d6","repo":"can1357/oh-my-pi","slug":"no-session-output-artifacts-unavailable","errorCode":null,"errorMessage":"No session - output artifacts unavailable","messagePattern":"No session - output artifacts unavailable","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"packages/coding-agent/src/eval/py/prelude.py","lineNumber":181,"sourceCode":"            Single ID: str (format='raw'/'stripped') or dict (format='json')\n            Multiple IDs: list of dict with 'id' and 'content'/'data' keys\n\n        Examples:\n            output('scout_0')  # Read as raw text\n            output('reviewer_0', format='json')  # Read with metadata\n            output('scout_0', query='.files[0]')  # Extract JSON field\n            output('scout_0', offset=10, limit=20)  # Lines 10-29\n            output('scout_0', 'reviewer_1')  # Read multiple outputs\n        \"\"\"\n        # Prefer PI_ARTIFACTS_DIR so subagents resolve through the parent's\n        # shared artifacts dir; fall back to deriving from PI_SESSION_FILE\n        # for legacy callers / top-level sessions where the two coincide.\n        artifacts_dir = os.environ.get(\"PI_ARTIFACTS_DIR\")\n        if not artifacts_dir:\n            session_file = os.environ.get(\"PI_SESSION_FILE\")\n            if not session_file:\n                _emit_status(\"output\", error=\"No session file available\")\n                raise RuntimeError(\"No session - output artifacts unavailable\")\n            artifacts_dir = session_file.rsplit(\".\", 1)[0]  # Strip .jsonl extension\n        if not Path(artifacts_dir).exists():\n            _emit_status(\n                \"output\", error=\"Artifacts directory not found\", path=artifacts_dir\n            )\n            raise RuntimeError(f\"No artifacts directory found: {artifacts_dir}\")\n\n        if not ids:\n            _emit_status(\"output\", error=\"No IDs provided\")\n            raise ValueError(\"At least one output ID is required\")\n\n        if query and (offset is not None or limit is not None):\n            _emit_status(\"output\", error=\"query cannot be combined with offset/limit\")\n            raise ValueError(\"query cannot be combined with offset/limit\")\n\n        results: list[dict] = []\n        not_found: list[str] = []\n","sourceCodeStart":163,"sourceCodeEnd":199,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/coding-agent/src/eval/py/prelude.py#L163-L199","documentation":"The prelude's output() writes result artifacts to an artifacts directory taken from PI_ARTIFACTS_DIR, falling back to deriving it from PI_SESSION_FILE (session file minus .jsonl extension). When neither env var is set there is no session context, so it emits an error status and raises RuntimeError 'No session - output artifacts unavailable'. The prelude is designed to run inside an eval session and refuses to guess where artifacts should go.","triggerScenarios":"Calling output(ids=...) in a Python process where the eval harness didn't inject PI_ARTIFACTS_DIR or PI_SESSION_FILE — e.g. running the script standalone, spawning a subprocess that doesn't inherit the env, or invoking output() from a non-session REPL.","commonSituations":"Executing prelude code directly with `python script.py` outside the agent; launching a subprocess with a scrubbed environment (env={}); running the same code locally during development without the harness.","solutions":["Set PI_ARTIFACTS_DIR (or PI_SESSION_FILE) in the environment before running the code.","Run the script through the eval harness so it injects the session env vars.","When spawning subprocesses, pass the parent environment through instead of a fresh env.","For local development, skip output() and write files to a known directory directly."],"exampleFix":"# before\noutput(ids=[\"result\"])\n# after\nimport os\nos.environ.setdefault(\"PI_ARTIFACTS_DIR\", \"/tmp/eval-artifacts\")\noutput(ids=[\"result\"])","handlingStrategy":"validation","validationCode":"import os\nif not (os.environ.get('PI_ARTIFACTS_DIR') or os.environ.get('PI_SESSION_FILE')):\n    raise RuntimeError('output() requires PI_ARTIFACTS_DIR or PI_SESSION_FILE in the environment')","typeGuard":"def has_session_env(): return bool(os.environ.get('PI_ARTIFACTS_DIR') or os.environ.get('PI_SESSION_FILE'))","tryCatchPattern":"try:\n    output(ids=['result'])\nexcept RuntimeError as e:\n    if 'No session' in str(e):\n        # not running under the eval harness — persist locally instead\n        write_local_artifact()\n    else:\n        raise","preventionTips":["Run prelude scripts through the eval harness so session env vars are injected.","Never spawn subprocesses with a scrubbed env={}; inherit the parent environment.","Check PI_ARTIFACTS_DIR/PI_SESSION_FILE at script start and fail fast with a clear message.","Gate output() calls behind has_session_env() in locally-run code."],"tags":["python","environment","session","artifacts"],"backgroundTag":"missing-env-var","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}