{"record":{"id":"ddea1c0dc7b4bfdf","repo":"HKUDS/Vibe-Trading","slug":"origin-delivery-requires-the-originating-session","errorCode":null,"errorMessage":"origin delivery requires the originating session","messagePattern":"origin delivery requires the originating session","errorType":"validation","errorClass":"ValueError","httpStatus":400,"severity":"error","filePath":"agent/src/scheduled_research/service.py","lineNumber":97,"sourceCode":"        return None\n    if isinstance(value, bool):\n        raise ValueError(\"end_at must be RFC3339 text or epoch milliseconds\")\n    if isinstance(value, int):\n        return value\n    if not isinstance(value, str):\n        raise ValueError(\"end_at must be RFC3339 text or epoch milliseconds\")\n    try:\n        parsed = datetime.fromisoformat(value.strip().replace(\"Z\", \"+00:00\"))\n    except ValueError as exc:\n        raise ValueError(\"end_at must be a valid RFC3339 timestamp\") from exc\n    if parsed.tzinfo is None:\n        raise ValueError(\"end_at must include an explicit timezone offset\")\n    return int(parsed.timestamp() * 1000)\n\n\ndef _origin_target(session_id: str | None) -> tuple[str, str, str | None, str]:\n    if not session_id:\n        raise ValueError(\"origin delivery requires the originating session\")\n    host = sys.modules.get(\"api_server\") or sys.modules.get(\"agent.api_server\")\n    service = (\n        host._get_session_service()\n        if host and hasattr(host, \"_get_session_service\")\n        else None\n    )\n    session = service.get_session(session_id) if service else None\n    config = getattr(session, \"config\", None) or {}\n    channel = config.get(\"channel\")\n    target = config.get(\"channel_chat_id\")\n    if not isinstance(channel, str) or not isinstance(target, str):\n        raise ValueError(\"the originating session is not an IM conversation\")\n    return channel, target, None, \"当前会话\"\n\n\ndef build_job_from_draft(\n    draft: Mapping[str, Any],\n    *,","sourceCodeStart":79,"sourceCodeEnd":115,"githubUrl":"https://github.com/HKUDS/Vibe-Trading/blob/80ffdda44c5c4db0dd84d70e051cca591cea67df/agent/src/scheduled_research/service.py#L79-L115","documentation":"_origin_target requires a session_id because 'origin' delivery sends results back to the IM conversation that created the job. The build_job_from_draft call was made without an originating session (e.g. server-side or CLI context).","triggerScenarios":"Creating a scheduled research draft with delivery.mode='origin' but session_id=None — e.g. calling build_job_from_draft/propose_create from a background task, API key context, or test without a session.","commonSituations":"Programmatic job creation outside a chat session; refactoring a caller to drop session context; tests that don't stub a session.","solutions":["Pass the originating session_id when proposing the draft","Or switch delivery.mode to 'in_app' or 'configured' for headless creation","If creating on behalf of a user, resolve their IM session first and forward its id"],"exampleFix":"# before\nbuild_job_from_draft(draft)  # draft.delivery.mode == 'origin'\n# after\nbuild_job_from_draft(draft, session_id=current_session_id)","handlingStrategy":"validation","validationCode":"if draft.get(\"delivery\", {}).get(\"mode\") == \"origin\":\n    assert session_id, \"origin delivery requires session_id\"","typeGuard":"def can_use_origin_delivery(draft: dict, session_id: str | None) -> bool:\n    return draft.get(\"delivery\", {}).get(\"mode\") != \"origin\" or bool(session_id)","tryCatchPattern":"try:\n    build_job_from_draft(draft, session_id=session_id)\nexcept ValueError as e:\n    if \"originating session\" in str(e):\n        draft[\"delivery\"] = {\"mode\": \"in_app\"}  # fallback","preventionTips":["Thread session context through job-creation call paths","Default headless callers to in_app/configured delivery"],"tags":["scheduled-research","delivery","session","validation"],"backgroundTag":"missing-required-context","analyzedSha":"80ffdda44c5c4db0dd84d70e051cca591cea67df","analyzedAt":"2026-08-28T12:46:38.989Z","schemaVersion":2},"datasetVersion":"2026-08-28T16:17:29.566Z"}