{"id":8908,"date":"2026-11-02T10:29:09","date_gmt":"2026-11-02T04:59:09","guid":{"rendered":"https:\/\/blogs.infosys.com\/digital-experience\/?p=8908"},"modified":"2026-11-02T10:29:09","modified_gmt":"2026-11-02T04:59:09","slug":"swift-ai-engineering-three-files-one-task-building-a-document-agent-with-swiftui","status":"publish","type":"post","link":"https:\/\/blogs.infosys.com\/digital-experience\/mobility\/swift-ai-engineering-three-files-one-task-building-a-document-agent-with-swiftui.html","title":{"rendered":"SWIFT \/ AI ENGINEERING &#8212;&#8212;&#8212;&#8212;&#8211; Three Files, One Task: Building a Document Agent with SwiftUI"},"content":{"rendered":"<article lang=\"en\" style=\"width: 100%;max-width: 688px;margin: 0 auto;padding: 16px;background-color: #ffffff;color: #142438;font-family: Georgia,&#039;Times New Roman&#039;,serif\"><!-- Upload thumbnail.png to your blog media library and replace this src with its URL. --><\/p>\n<figure style=\"margin: 16px 0\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8924\" src=\"https:\/\/blogs.infosys.com\/digital-experience\/wp-content\/uploads\/2026\/10\/thumbnail-300x169.png\" alt=\"\" width=\"691\" height=\"389\" srcset=\"https:\/\/blogs.infosys.com\/digital-experience\/wp-content\/uploads\/2026\/10\/thumbnail-300x169.png 300w, https:\/\/blogs.infosys.com\/digital-experience\/wp-content\/uploads\/2026\/10\/thumbnail-1024x576.png 1024w, https:\/\/blogs.infosys.com\/digital-experience\/wp-content\/uploads\/2026\/10\/thumbnail-768x432.png 768w, https:\/\/blogs.infosys.com\/digital-experience\/wp-content\/uploads\/2026\/10\/thumbnail-1536x864.png 1536w, https:\/\/blogs.infosys.com\/digital-experience\/wp-content\/uploads\/2026\/10\/thumbnail.png 1672w\" sizes=\"auto, (max-width: 691px) 100vw, 691px\" \/><\/figure>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 12pt;line-height: 1.3;color: #586675;margin: 9px 0;text-align: justify\"><em>A practical design for iPhone and iPad apps that turn selected documents into useful answers.<\/em><\/p>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">A consultant opens three proposals on an iPad and asks an assistant to compare delivery dates, exclusions, and payment terms. The useful result is a concise brief with supporting passages. Getting there requires more than connecting a chat interface to a model: the app must manage document access, extraction, task state, and user control.<\/p>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">For a mobility team working in Swift, this is an opportunity to build intelligence directly into a familiar document workflow. <strong style=\"font-weight: bold;color: #833b1d;padding: 0 2px\">Let the user choose the files, keep processing visible, and make every action accountable to the current task.<\/strong><\/p>\n<section aria-labelledby=\"section-1\">\n<h2 id=\"section-1\" style=\"font-family: &#039;Segoe UI&#039;,Arial,sans-serif;font-size: 13pt;font-weight: 650;line-height: 1.25;letter-spacing: -0.6px;color: #142438;margin: 14px 0 7px\">Start with the mobile permission model<\/h2>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">Full Disk Access belongs to macOS. An iPhone or iPad document assistant should be designed around its app sandbox and user-selected documents, rather than a desktop permission setting.<\/p>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">SwiftUI&#8217;s <code style=\"font-family: Consolas,monospace;font-size: 0.83em;background-color: #ece9e2;border-radius: 4px;padding: 2px 5px\">fileImporter<\/code> presents the system document picker. Restrict supported content types with <code style=\"font-family: Consolas,monospace;font-size: 0.83em;background-color: #ece9e2;border-radius: 4px;padding: 2px 5px\">UTType<\/code>, enable multiple selection when appropriate, and show the selected files before processing. Documents may come from local storage, iCloud Drive, or another file provider, so selection does not guarantee immediate availability.<\/p>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">For security-scoped URLs returned by the importer, call <code style=\"font-family: Consolas,monospace;font-size: 0.83em;background-color: #ece9e2;border-radius: 4px;padding: 2px 5px\">startAccessingSecurityScopedResource()<\/code> before access and balance each successful call with <code style=\"font-family: Consolas,monospace;font-size: 0.83em;background-color: #ece9e2;border-radius: 4px;padding: 2px 5px\">stopAccessingSecurityScopedResource()<\/code> when finished. Handle failures without silently broadening the task.<\/p>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\"><strong style=\"font-weight: bold;color: #833b1d;padding: 0 2px\">Selecting a document authorizes a file workflow; uploading its contents requires a separate, clearly explained processing decision.<\/strong><\/p>\n<\/section>\n<section aria-labelledby=\"section-2\">\n<h2 id=\"section-2\" style=\"font-family: &#039;Segoe UI&#039;,Arial,sans-serif;font-size: 13pt;font-weight: 650;line-height: 1.25;letter-spacing: -0.6px;color: #142438;margin: 14px 0 7px\">Give the SwiftUI screen a clear state<\/h2>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">Model the workflow explicitly: selecting, loading, extracting, generating, completed, cancelled, or failed. Keep UI-facing state on <code style=\"font-family: Consolas,monospace;font-size: 0.83em;background-color: #ece9e2;border-radius: 4px;padding: 2px 5px\">MainActor<\/code> and move expensive document processing off the main actor. Creating a <code style=\"font-family: Consolas,monospace;font-size: 0.83em;background-color: #ece9e2;border-radius: 4px;padding: 2px 5px\">Task<\/code> alone does not guarantee background execution.<\/p>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">Show progress, preserve the user&#8217;s question during recoverable errors, and make cancellation available. Swift cancellation is cooperative: check it between processing stages and stop further work where supported.<\/p>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">Use stable document identifiers in the app&#8217;s workspace. A filename is useful for display, but it should not be the sole key for authorization or retrieval.<\/p>\n<\/section>\n<section aria-labelledby=\"section-3\">\n<h2 id=\"section-3\" style=\"font-family: &#039;Segoe UI&#039;,Arial,sans-serif;font-size: 13pt;font-weight: 650;line-height: 1.25;letter-spacing: -0.6px;color: #142438;margin: 14px 0 7px\">Extract useful context before generation<\/h2>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">For text-bearing PDFs, PDFKit&#8217;s <code style=\"font-family: Consolas,monospace;font-size: 0.83em;background-color: #ece9e2;border-radius: 4px;padding: 2px 5px\">PDFDocument<\/code> exposes extracted text. Work page by page when answers need page references. A scanned PDF may require an OCR pipeline, and an encrypted or malformed document needs an understandable error.<\/p>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">Divide extracted text into manageable passages and retain their document and page identifiers. Retrieve the material relevant to the question instead of placing every document into every prompt.<\/p>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">This makes the answer easier to verify and helps manage context limits. <strong style=\"font-weight: bold;color: #833b1d;padding: 0 2px\">A comparison should show where its material claims came from.<\/strong><\/p>\n<\/section>\n<p><!-- Upload workflow.png to your blog media library and replace this src with its URL. --><\/p>\n<figure style=\"margin: 16px 0\"><figcaption style=\"font-family: &#039;Segoe UI&#039;,Arial,sans-serif;font-size: 9pt;line-height: 1.4;color: #586675;margin-top: 6px\"><img loading=\"lazy\" decoding=\"async\" class=\"alignnone wp-image-8926\" src=\"https:\/\/blogs.infosys.com\/digital-experience\/wp-content\/uploads\/2026\/10\/workflow-300x143.png\" alt=\"\" width=\"682\" height=\"325\" srcset=\"https:\/\/blogs.infosys.com\/digital-experience\/wp-content\/uploads\/2026\/10\/workflow-300x143.png 300w, https:\/\/blogs.infosys.com\/digital-experience\/wp-content\/uploads\/2026\/10\/workflow-1024x486.png 1024w, https:\/\/blogs.infosys.com\/digital-experience\/wp-content\/uploads\/2026\/10\/workflow-768x365.png 768w, https:\/\/blogs.infosys.com\/digital-experience\/wp-content\/uploads\/2026\/10\/workflow-1536x730.png 1536w, https:\/\/blogs.infosys.com\/digital-experience\/wp-content\/uploads\/2026\/10\/workflow.png 1600w\" sizes=\"auto, (max-width: 682px) 100vw, 682px\" \/>The app checks each operation against the user&#8217;s approved workspace.<\/figcaption><\/figure>\n<section aria-labelledby=\"section-4\">\n<h2 id=\"section-4\" style=\"font-family: &#039;Segoe UI&#039;,Arial,sans-serif;font-size: 13pt;font-weight: 650;line-height: 1.25;letter-spacing: -0.6px;color: #142438;margin: 14px 0 7px\">Connect the model through a controlled Swift layer<\/h2>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">For supported devices and configurations, the Foundation Models framework offers on-device generation through <code style=\"font-family: Consolas,monospace;font-size: 0.83em;background-color: #ece9e2;border-radius: 4px;padding: 2px 5px\">LanguageModelSession<\/code>. Check <code style=\"font-family: Consolas,monospace;font-size: 0.83em;background-color: #ece9e2;border-radius: 4px;padding: 2px 5px\">SystemLanguageModel.default.availability<\/code> before offering that path. Provide a clear unavailable state; never silently switch sensitive document processing to a cloud service.<\/p>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">A summarizer follows a fixed pipeline. An agent can choose additional steps, such as requesting another passage. Expose narrowly defined tools for approved document search and retrieval, with application-side validation on every call.<\/p>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">Treat retrieved text as untrusted input. Instructions embedded in a proposal cannot authorize another file, a network upload, or a write operation. Removing a document must block subsequent retrieval, including during an ongoing task.<\/p>\n<\/section>\n<section aria-labelledby=\"section-5\">\n<h2 id=\"section-5\" style=\"font-family: &#039;Segoe UI&#039;,Arial,sans-serif;font-size: 13pt;font-weight: 650;line-height: 1.25;letter-spacing: -0.6px;color: #142438;margin: 14px 0 7px\">Finish the mobile experience responsibly<\/h2>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">Use SwiftUI&#8217;s <code style=\"font-family: Consolas,monospace;font-size: 0.83em;background-color: #ece9e2;border-radius: 4px;padding: 2px 5px\">fileExporter<\/code> for user-directed exports and <code style=\"font-family: Consolas,monospace;font-size: 0.83em;background-color: #ece9e2;border-radius: 4px;padding: 2px 5px\">ShareLink<\/code> where an explicit sharing workflow fits. Keep original documents unchanged unless editing is a deliberate feature with appropriate confirmation.<\/p>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">Before release, test on physical devices:<\/p>\n<ul style=\"margin: 7px 0;padding-left: 18px\">\n<li style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 4px 0;padding-left: 6px;text-align: justify\"><strong style=\"font-weight: bold;color: #833b1d;padding: 0 2px\">Availability:<\/strong> unsupported model configurations and offline file providers.<\/li>\n<li style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 4px 0;padding-left: 6px;text-align: justify\"><strong style=\"font-weight: bold;color: #833b1d;padding: 0 2px\">Responsiveness:<\/strong> large PDFs, memory pressure, and cancellation.<\/li>\n<li style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 4px 0;padding-left: 6px;text-align: justify\"><strong style=\"font-weight: bold;color: #833b1d;padding: 0 2px\">Boundaries:<\/strong> unselected files and instructions embedded in documents.<\/li>\n<li style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 4px 0;padding-left: 6px;text-align: justify\"><strong style=\"font-weight: bold;color: #833b1d;padding: 0 2px\">Retention:<\/strong> extracted text, temporary copies, indexes, and conversation history.<\/li>\n<\/ul>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">Stopping file access does not delete information already copied into app storage. Explain what a workspace removal action clears and any limits on deletion.<\/p>\n<\/section>\n<section aria-labelledby=\"section-6\">\n<h2 id=\"section-6\" style=\"font-family: &#039;Segoe UI&#039;,Arial,sans-serif;font-size: 13pt;font-weight: 650;line-height: 1.25;letter-spacing: -0.6px;color: #142438;margin: 14px 0 7px\">Conclusion<\/h2>\n<p style=\"font-family: Georgia,&#039;Times New Roman&#039;,serif;font-size: 10.5pt;line-height: 1.32;color: #142438;margin: 9px 0;text-align: justify\">A useful SwiftUI document agent combines native file selection, deliberate Swift concurrency, grounded retrieval, and controlled model access. Start with a focused iPhone or iPad task, make failures understandable, and preserve the user&#8217;s authority from import to export. The quality of the mobile experience depends as much on those decisions as on the generated answer.<\/p>\n<\/section>\n<\/article>\n","protected":false},"excerpt":{"rendered":"<p>A practical design for iPhone and iPad apps that turn selected documents into useful [&hellip;]<\/p>\n","protected":false},"author":929,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"inline_featured_image":false,"footnotes":""},"categories":[1],"tags":[],"coauthors":[781],"class_list":["post-8908","post","type-post","status-publish","format-standard","hentry","category-mobility"],"acf":[],"_links":{"self":[{"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/posts\/8908","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/users\/929"}],"replies":[{"embeddable":true,"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/comments?post=8908"}],"version-history":[{"count":10,"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/posts\/8908\/revisions"}],"predecessor-version":[{"id":8949,"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/posts\/8908\/revisions\/8949"}],"wp:attachment":[{"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/media?parent=8908"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/categories?post=8908"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/tags?post=8908"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/blogs.infosys.com\/digital-experience\/wp-json\/wp\/v2\/coauthors?post=8908"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}