René's URL Explorer Experiment


Title: How to capture root message of a thread in a Space? · Issue #265 · WebexCommunity/WebexPythonSDK · GitHub

Open Graph Title: How to capture root message of a thread in a Space? · Issue #265 · WebexCommunity/WebexPythonSDK

X Title: How to capture root message of a thread in a Space? · Issue #265 · WebexCommunity/WebexPythonSDK

Description: By root message I mean the first original message from which a thread starts. In an attempt to capture the root message of a thread (both 1:1 and Space) from which the webhook was called, starter = api.messages.get( parent_id ) works for...

Open Graph Description: By root message I mean the first original message from which a thread starts. In an attempt to capture the root message of a thread (both 1:1 and Space) from which the webhook was called, starter =...

X Description: By root message I mean the first original message from which a thread starts. In an attempt to capture the root message of a thread (both 1:1 and Space) from which the webhook was called, starter =...

Opengraph URL: https://github.com/WebexCommunity/WebexPythonSDK/issues/265

X: @github

direct link

Domain: patch-diff.githubusercontent.com


Hey, it has json ld scripts:
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"How to capture root message of a thread in a Space?","articleBody":"By root message I mean the first original message from which a thread starts.\n\n\u003cimg width=\"955\" height=\"177\" alt=\"Image\" src=\"https://github.com/user-attachments/assets/90abf083-b2c1-4226-bedc-ff7e49391c20\" /\u003e\n\nIn an attempt to capture the root message of a thread (both 1:1 and Space) from which the webhook was called,\n\n`starter = api.messages.get( parent_id )` works for 1:1 not in a Space, throws error:\n```\nTraceback (most recent call last):\nFile \"/app/webex-bot/app.py\", line 174, in collect_thread_text_and_attachments\nstarter = api.messages.get(parent_id)\nFile \"/app/webex-bot/pyvenv/lib/python3.10/site-packages/webexpythonsdk/api/messages.py\", line 339, in get\njson_data = self._session.get(API_ENDPOINT + \"/\" + messageId)\nFile \"/app/webex-bot/pyvenv/lib/python3.10/site-packages/webexpythonsdk/restsession.py\", line 428, in get\nresponse = self.request(\"GET\", url, erc, params=params, **kwargs)\nFile \"/app/webex-bot/pyvenv/lib/python3.10/site-packages/webexpythonsdk/restsession.py\", line 393, in request\ncheck_response_code(response, erc)\nFile \"/app/webex-bot/pyvenv/lib/python3.10/site-packages/webexpythonsdk/utils.py\", line 207, in check_response_code\nraise ApiError(response)\nwebexpythonsdk.exceptions.ApiError: [404] Not Found - Unable to get message. [Tracking ID: ROUTERGW_add856f9-8590-471d-a355-3b4b2405fdb9]  \n```\n\nAlso, `starter_candidates = list( api.messages.list( roomId = room_id, max = 5, beforeMessage = parent_id ) )` works 1:1 but not in Space, throws error:\n```\nTraceback (most recent call last):\nFile \"/app/webex-bot/app.py\", line 179, in collect_thread_text_and_attachments\nstarter_candidates = list( api.messages.list( roomId = room_id, max = 5, beforeMessage = parent_id ) )\nFile \"/app/webex-bot/pyvenv/lib/python3.10/site-packages/webexpythonsdk/api/messages.py\", line 138, in list\nfor item in items:\nFile \"/app/webex-bot/pyvenv/lib/python3.10/site-packages/webexpythonsdk/restsession.py\", line 502, in get_items\nfor json_page in pages:\nFile \"/app/webex-bot/pyvenv/lib/python3.10/site-packages/webexpythonsdk/restsession.py\", line 455, in get_pages\nresponse = self.request(\"GET\", url, erc, params=params, **kwargs)\nFile \"/app/webex-bot/pyvenv/lib/python3.10/site-packages/webexpythonsdk/restsession.py\", line 393, in request\ncheck_response_code(response, erc)\nFile \"/app/webex-bot/pyvenv/lib/python3.10/site-packages/webexpythonsdk/utils.py\", line 207, in check_response_code\nraise ApiError(response)\nwebexpythonsdk.exceptions.ApiError: [403] Forbidden - Failed to get activity. [Tracking ID: ROUTERGW_48f845fd-b077-4dab-8ec8-57291972479f] \n```\n\nThis piece works fine to capture the root message of a 1:1 thread but fails to capture the root message of a thread in a Space.\n```\ndef collect_thread_text_and_attachments(msg) -\u003e tuple[str, list[str]]:\n    \"\"\"\n    Robustly collect thread text + attachments. Works in 1:1 but not in spaces.\n    Strategy:\n      1) Try api.messages.get(parent_id)\n      2) If that fails, scan recent messages in the room up to MAX_SCAN to find the parent\n      3) If still not found, try beforeMessage(parent_id) as a fallback\n      4) Always include replies (list parentId=...) ordered oldest-\u003enewest\n      5) Ensure the incoming message 'msg' is present\n      6) If starter can't be found, add a placeholder notice\n    Returns (thread_text, [attachment_text]) where attachment_text is list with single big string\n    \"\"\"\n    author_cache = {}\n    thread_text_lines = []\n    attachment_blocks = []\n\n    def process_single_message(m):\n        author = get_display_name(getattr(m, \"personId\", \"unknown\"), author_cache)\n        mtext = (getattr(m, \"text\", \"\") or \"\").strip()\n        if mtext:\n            thread_text_lines.append(f\"[{author}]: {mtext}\")\n\n        if getattr(m, \"files\", None):\n            for f_url in m.files:\n                try:\n                    content, fname, ctype = download_webex_file(f_url)\n                    extracted = extract_text_from_file(content, fname, ctype)\n                    attachment_blocks.append(f\"[Attachment {fname}]:\\n{extracted}\")\n                except Exception as e:\n                    # keep going; record the error in attachments so user sees it\n                    attachment_blocks.append(f\"[Attachment error for {fname}]: {e}\")\n\n    parent_id = getattr(msg, \"parentId\", None)\n    room_id = getattr(msg, \"roomId\", None)\n\n    messages_to_process = []\n    found_starter = None\n    starter_unavailable = False\n\n    if parent_id and room_id:\n        # 1) Try to fetch starter directly (works in many cases)\n        try:\n            starter = api.messages.get(parent_id)\n            found_starter = starter\n        except Exception as ex_get:\n            # failed to get the parent message (common in spaces)\n            # 2) Try scanning recent messages in the room to find that id (paginated)\n            MAX_SCAN = 500  # \u003c= number of messages to scan; adjust as needed\n            scanned = 0\n            try:\n                for m in api.messages.list(roomId=room_id, max=100):\n                    scanned += 1\n                    if getattr(m, \"id\", None) == parent_id:\n                        found_starter = m\n                        break\n                    if scanned \u003e= MAX_SCAN:\n                        break\n            except Exception:\n                # scanning may also fail due to permissions; ignore and fallback\n                pass\n\n            # 3) fallback: try beforeMessage (sometimes works)\n            if not found_starter:\n                try:\n                    candidates = list(api.messages.list(roomId=room_id, max=1, beforeMessage=parent_id))\n                    if candidates:\n                        found_starter = candidates[0]\n                except Exception:\n                    pass\n\n            if not found_starter:\n                starter_unavailable = True  # note that we couldn't retrieve the starter\n\n        # If we found a starter, add it first\n        if found_starter:\n            messages_to_process.append(found_starter)\n\n        # Collect replies (newest-first), reverse to oldest-\u003enewest\n        try:\n            replies = list(api.messages.list(roomId=room_id, parentId=parent_id, max=100))\n            replies.reverse()            \n            messages_to_process.extend(replies)\n            messages_to_process.pop()\n        except Exception:\n            # if replies cannot be fetched, continue - we'll at least include incoming message\n            pass\n\n        # Ensure incoming 'msg' is present (sometimes it's not in replies list)\n        if not any(getattr(m, \"id\", None) == getattr(msg, \"id\", None) for m in messages_to_process):\n            messages_to_process.append(msg)\n\n        # If we couldn't find the starter, insert a placeholder at the top (so LLM sees lack of context)\n        if starter_unavailable:\n            thread_text_lines.append(\"[Starter message unavailable — bot may have joined after the thread started or lacks permission to read the original message.]\")\n\n    else:\n        # Not a thread or missing metadata: just process the single message\n        messages_to_process = [msg]\n\n    # Now process messages in order, avoid duplicates\n    seen_ids = set()\n    for m in messages_to_process:\n        mid = getattr(m, \"id\", None)\n        if mid and mid in seen_ids:\n            continue\n        if mid:\n            seen_ids.add(mid)\n        process_single_message(m)\n\n    # Combine, guardrail sizes\n    thread_text = \"\\n\".join(thread_text_lines)\n    MAX_CHARS = 60_000\n    if len(thread_text) \u003e MAX_CHARS:\n        thread_text = thread_text[:MAX_CHARS] + \"\\n...[truncated]\"\n\n    att_text = \"\\n\\n\".join(attachment_blocks)\n    if len(att_text) \u003e MAX_CHARS:\n        att_text = att_text[:MAX_CHARS] + \"\\n...[attachments truncated]\"\n\n    return thread_text, [att_text] if att_text else []  \n```","author":{"url":"https://github.com/ddebta","@type":"Person","name":"ddebta"},"datePublished":"2025-09-02T21:47:38.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":0},"url":"https://github.com/265/WebexPythonSDK/issues/265"}

route-pattern/_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format)
route-controllervoltron_issues_fragments
route-actionissue_layout
fetch-noncev2:8a8d7b48-1571-8ad9-9dab-5efcc6ba3d91
current-catalog-service-hash81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114
request-id9CC2:358866:3725D5:4C195E:696E55BE
html-safe-nonce9a71c9fe250a6fc45857e7f1e70bff22034117654b944c870c0e94c0c973c515
visitor-payloadeyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiI5Q0MyOjM1ODg2NjozNzI1RDU6NEMxOTVFOjY5NkU1NUJFIiwidmlzaXRvcl9pZCI6IjgxMjA5NTY2NzM2NTMxMDIwMTQiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ==
visitor-hmacf09950eb950eb0936808e1f1a68756a4841930e1f84eab5e3c38933ca3aa79cf
hovercard-subject-tagissue:3377580788
github-keyboard-shortcutsrepository,issues,copilot
google-site-verificationApib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I
octolytics-urlhttps://collector.github.com/github/collect
analytics-location///voltron/issues_fragments/issue_layout
fb:app_id1401488693436528
apple-itunes-appapp-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/WebexCommunity/WebexPythonSDK/265/issue_layout
twitter:imagehttps://opengraph.githubassets.com/944e5bf3d32048b104056d326714d090bd16a58d902f3018a19a4b4488cbe755/WebexCommunity/WebexPythonSDK/issues/265
twitter:cardsummary_large_image
og:imagehttps://opengraph.githubassets.com/944e5bf3d32048b104056d326714d090bd16a58d902f3018a19a4b4488cbe755/WebexCommunity/WebexPythonSDK/issues/265
og:image:altBy root message I mean the first original message from which a thread starts. In an attempt to capture the root message of a thread (both 1:1 and Space) from which the webhook was called, starter =...
og:image:width1200
og:image:height600
og:site_nameGitHub
og:typeobject
og:author:usernameddebta
hostnamegithub.com
expected-hostnamegithub.com
Nonef68b42d371252b0f236260d6234f4304a806fe5ac43d59faa21fb59d80df103b
turbo-cache-controlno-preview
go-importgithub.com/WebexCommunity/WebexPythonSDK git https://github.com/WebexCommunity/WebexPythonSDK.git
octolytics-dimension-user_id112501140
octolytics-dimension-user_loginWebexCommunity
octolytics-dimension-repository_id63186293
octolytics-dimension-repository_nwoWebexCommunity/WebexPythonSDK
octolytics-dimension-repository_publictrue
octolytics-dimension-repository_is_forkfalse
octolytics-dimension-repository_network_root_id63186293
octolytics-dimension-repository_network_root_nwoWebexCommunity/WebexPythonSDK
turbo-body-classeslogged-out env-production page-responsive
disable-turbofalse
browser-stats-urlhttps://api.github.com/_private/browser/stats
browser-errors-urlhttps://api.github.com/_private/browser/errors
release6b74bc8dbcd10b5d69fd9ee9d2cfdc8b35e18a4c
ui-targetfull
theme-color#1e2327
color-schemelight dark

Links:

Skip to contenthttps://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/issues/265#start-of-content
https://patch-diff.githubusercontent.com/
Sign in https://patch-diff.githubusercontent.com/login?return_to=https%3A%2F%2Fgithub.com%2FWebexCommunity%2FWebexPythonSDK%2Fissues%2F265
GitHub CopilotWrite better code with AIhttps://github.com/features/copilot
GitHub SparkBuild and deploy intelligent appshttps://github.com/features/spark
GitHub ModelsManage and compare promptshttps://github.com/features/models
MCP RegistryNewIntegrate external toolshttps://github.com/mcp
ActionsAutomate any workflowhttps://github.com/features/actions
CodespacesInstant dev environmentshttps://github.com/features/codespaces
IssuesPlan and track workhttps://github.com/features/issues
Code ReviewManage code changeshttps://github.com/features/code-review
GitHub Advanced SecurityFind and fix vulnerabilitieshttps://github.com/security/advanced-security
Code securitySecure your code as you buildhttps://github.com/security/advanced-security/code-security
Secret protectionStop leaks before they starthttps://github.com/security/advanced-security/secret-protection
Why GitHubhttps://github.com/why-github
Documentationhttps://docs.github.com
Bloghttps://github.blog
Changeloghttps://github.blog/changelog
Marketplacehttps://github.com/marketplace
View all featureshttps://github.com/features
Enterpriseshttps://github.com/enterprise
Small and medium teamshttps://github.com/team
Startupshttps://github.com/enterprise/startups
Nonprofitshttps://github.com/solutions/industry/nonprofits
App Modernizationhttps://github.com/solutions/use-case/app-modernization
DevSecOpshttps://github.com/solutions/use-case/devsecops
DevOpshttps://github.com/solutions/use-case/devops
CI/CDhttps://github.com/solutions/use-case/ci-cd
View all use caseshttps://github.com/solutions/use-case
Healthcarehttps://github.com/solutions/industry/healthcare
Financial serviceshttps://github.com/solutions/industry/financial-services
Manufacturinghttps://github.com/solutions/industry/manufacturing
Governmenthttps://github.com/solutions/industry/government
View all industrieshttps://github.com/solutions/industry
View all solutionshttps://github.com/solutions
AIhttps://github.com/resources/articles?topic=ai
Software Developmenthttps://github.com/resources/articles?topic=software-development
DevOpshttps://github.com/resources/articles?topic=devops
Securityhttps://github.com/resources/articles?topic=security
View all topicshttps://github.com/resources/articles
Customer storieshttps://github.com/customer-stories
Events & webinarshttps://github.com/resources/events
Ebooks & reportshttps://github.com/resources/whitepapers
Business insightshttps://github.com/solutions/executive-insights
GitHub Skillshttps://skills.github.com
Documentationhttps://docs.github.com
Customer supporthttps://support.github.com
Community forumhttps://github.com/orgs/community/discussions
Trust centerhttps://github.com/trust-center
Partnershttps://github.com/partners
GitHub SponsorsFund open source developershttps://github.com/sponsors
Security Labhttps://securitylab.github.com
Maintainer Communityhttps://maintainers.github.com
Acceleratorhttps://github.com/accelerator
Archive Programhttps://archiveprogram.github.com
Topicshttps://github.com/topics
Trendinghttps://github.com/trending
Collectionshttps://github.com/collections
Enterprise platformAI-powered developer platformhttps://github.com/enterprise
GitHub Advanced SecurityEnterprise-grade security featureshttps://github.com/security/advanced-security
Copilot for BusinessEnterprise-grade AI featureshttps://github.com/features/copilot/copilot-business
Premium SupportEnterprise-grade 24/7 supporthttps://github.com/premium-support
Pricinghttps://github.com/pricing
Search syntax tipshttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
documentationhttps://docs.github.com/search-github/github-code-search/understanding-github-code-search-syntax
Sign in https://patch-diff.githubusercontent.com/login?return_to=https%3A%2F%2Fgithub.com%2FWebexCommunity%2FWebexPythonSDK%2Fissues%2F265
Sign up https://patch-diff.githubusercontent.com/signup?ref_cta=Sign+up&ref_loc=header+logged+out&ref_page=%2F%3Cuser-name%3E%2F%3Crepo-name%3E%2Fvoltron%2Fissues_fragments%2Fissue_layout&source=header-repo&source_repo=WebexCommunity%2FWebexPythonSDK
Reloadhttps://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/issues/265
Reloadhttps://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/issues/265
Reloadhttps://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/issues/265
WebexCommunity https://patch-diff.githubusercontent.com/WebexCommunity
WebexPythonSDKhttps://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK
Notifications https://patch-diff.githubusercontent.com/login?return_to=%2FWebexCommunity%2FWebexPythonSDK
Fork 154 https://patch-diff.githubusercontent.com/login?return_to=%2FWebexCommunity%2FWebexPythonSDK
Star 256 https://patch-diff.githubusercontent.com/login?return_to=%2FWebexCommunity%2FWebexPythonSDK
Code https://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK
Issues 6 https://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/issues
Pull requests 3 https://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/pulls
Actions https://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/actions
Wiki https://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/wiki
Security Uh oh! There was an error while loading. Please reload this page. https://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/security
Please reload this pagehttps://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/issues/265
Insights https://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/pulse
Code https://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK
Issues https://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/issues
Pull requests https://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/pulls
Actions https://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/actions
Wiki https://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/wiki
Security https://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/security
Insights https://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/pulse
New issuehttps://patch-diff.githubusercontent.com/login?return_to=https://github.com/WebexCommunity/WebexPythonSDK/issues/265
New issuehttps://patch-diff.githubusercontent.com/login?return_to=https://github.com/WebexCommunity/WebexPythonSDK/issues/265
How to capture root message of a thread in a Space?https://patch-diff.githubusercontent.com/WebexCommunity/WebexPythonSDK/issues/265#top
https://patch-diff.githubusercontent.com/Joezanini
https://github.com/ddebta
https://github.com/ddebta
ddebtahttps://github.com/ddebta
on Sep 2, 2025https://github.com/WebexCommunity/WebexPythonSDK/issues/265#issue-3377580788
https://private-user-images.githubusercontent.com/79559125/484777082-90abf083-b2c1-4226-bedc-ff7e49391c20.png?jwt=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Njg4Mzg4OTAsIm5iZiI6MTc2ODgzODU5MCwicGF0aCI6Ii83OTU1OTEyNS80ODQ3NzcwODItOTBhYmYwODMtYjJjMS00MjI2LWJlZGMtZmY3ZTQ5MzkxYzIwLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNjAxMTklMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjYwMTE5VDE2MDMxMFomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWU1ZWQwYmRhMTgyZDI0MTZiOTRmNjQzMWZmNjJhOWM4ZTc1ZjJiMjY2YjRjNmVmNTE5ZGQ3YWY2YzQ0OWM0NjEmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.U3BPft2tDm_-Bdi_P5TUnxl01Ns9F6iT2mePDoQFqHY
Joezaninihttps://patch-diff.githubusercontent.com/Joezanini
https://github.com
Termshttps://docs.github.com/site-policy/github-terms/github-terms-of-service
Privacyhttps://docs.github.com/site-policy/privacy-policies/github-privacy-statement
Securityhttps://github.com/security
Statushttps://www.githubstatus.com/
Communityhttps://github.community/
Docshttps://docs.github.com/
Contacthttps://support.github.com?tags=dotcom-footer

Viewport: width=device-width


URLs of crawlers that visited me.