@@ -367,7 +367,7 @@ async def create_progress_message(
367367 return progress
368368
369369
370- # --- Slack File Upload API (files.getUploadURLExternal + completeUploadExternal ) ---
370+ # --- Slack Snippet Upload (files.upload with content parameter ) ---
371371
372372
373373async def upload_snippet (
@@ -378,12 +378,14 @@ async def upload_snippet(
378378 title : str | None = None ,
379379 filetype : str | None = None ,
380380) -> dict [str , Any ]:
381- """Upload a code snippet as a Slack file using the new external upload API .
381+ """Upload a code snippet using files.upload with content parameter .
382382
383- Uses the three-step process:
384- 1. files.getUploadURLExternal - get upload URL and file ID
385- 2. POST content to that URL
386- 3. files.completeUploadExternal - finalize and share in channel
383+ This creates an actual Slack snippet (with line numbers and collapsible UI),
384+ not just a file attachment. Uses the `content` parameter which creates
385+ editable snippets.
386+
387+ Note: files.upload is deprecated but still works. The new external upload API
388+ (files.getUploadURLExternal) doesn't create proper snippets with line numbers.
387389
388390 Args:
389391 content: The snippet content to upload
@@ -396,70 +398,35 @@ async def upload_snippet(
396398 Returns:
397399 dict with file info from Slack API
398400 """
399- content_bytes = content .encode ("utf-8" )
400- length = len (content_bytes )
401+ # Build form data for multipart upload
402+ # Using `content` parameter (not `file`) creates an editable snippet
403+ form_data : dict [str , Any ] = {
404+ "content" : content ,
405+ "filename" : filename ,
406+ "channels" : channel_id ,
407+ }
408+ if title :
409+ form_data ["title" ] = title
410+ if filetype :
411+ form_data ["filetype" ] = filetype
412+ if thread_ts :
413+ form_data ["thread_ts" ] = thread_ts
401414
402415 async with httpx .AsyncClient () as client :
403- # Step 1: Get upload URL
404- get_url_params : dict [str , Any ] = {
405- "filename" : filename ,
406- "length" : length ,
407- }
408- if filetype :
409- get_url_params ["snippet_type" ] = filetype
410-
411- response = await client .get (
412- "https://slack.com/api/files.getUploadURLExternal" ,
416+ response = await client .post (
417+ "https://slack.com/api/files.upload" ,
413418 headers = {"Authorization" : f"Bearer { settings .slack_api_token } " },
414- params = get_url_params ,
419+ data = form_data ,
415420 )
416421 response .raise_for_status ()
417- url_data = response .json ()
418-
419- if not url_data .get ("ok" ):
420- raise ValueError (
421- f"Failed to get upload URL: { url_data .get ('error' , 'unknown error' )} "
422- )
423-
424- upload_url = url_data ["upload_url" ]
425- file_id = url_data ["file_id" ]
426-
427- # Step 2: Upload content to the provided URL
428- upload_response = await client .post (
429- upload_url ,
430- content = content_bytes ,
431- headers = {"Content-Type" : "application/octet-stream" },
432- )
433- if upload_response .status_code != 200 :
434- raise ValueError (
435- f"Failed to upload file content: { upload_response .status_code } "
436- )
437-
438- # Step 3: Complete the upload and share in channel
439- complete_payload : dict [str , Any ] = {
440- "files" : [{"id" : file_id , "title" : title or filename }],
441- "channel_id" : channel_id ,
442- }
443- if thread_ts :
444- complete_payload ["thread_ts" ] = thread_ts
445-
446- complete_response = await client .post (
447- "https://slack.com/api/files.completeUploadExternal" ,
448- headers = {
449- "Authorization" : f"Bearer { settings .slack_api_token } " ,
450- "Content-Type" : "application/json" ,
451- },
452- json = complete_payload ,
453- )
454- complete_response .raise_for_status ()
455- complete_data = complete_response .json ()
422+ result = response .json ()
456423
457- if not complete_data .get ("ok" ):
424+ if not result .get ("ok" ):
458425 raise ValueError (
459- f"Failed to complete upload: { complete_data .get ('error' , 'unknown error' )} "
426+ f"Failed to upload snippet : { result .get ('error' , 'unknown error' )} "
460427 )
461428
462- return complete_data
429+ return result
463430
464431
465432# Language to file extension mapping for snippet filenames
0 commit comments