feat: update schema & bump deps (#15455)

#### PR Dependency Tree


* **PR #15455** 👈

This tree was auto-generated by
[Charcoal](https://github.com/danerwilliams/charcoal)

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Added workspace artifact management, artifact details, and removal
support.
- Added workspace BYOK configuration insights, model capabilities,
connection checks, and validation status.
  - Added profile reordering and credential revision safeguards.
- **Improvements**
- Improved Copilot session creation with server-provided history and
metadata.
- Streamlined context handling with document scope selections and
selected-source synchronization.
- **Bug Fixes**
- Improved compatibility and reliability across web, Android, and iOS
Copilot workflows.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
DarkSky
2026-08-10 18:16:13 +08:00
committed by GitHub
parent 7bc349c4de
commit 386e92acb6
86 changed files with 1311 additions and 2211 deletions

View File

@@ -16,7 +16,7 @@ let package = Package(
dependencies: [
.package(path: "../AffineGraphQL"),
.package(path: "../AffineResources"),
.package(url: "https://github.com/apollographql/apollo-ios.git", from: "1.25.4"),
.package(url: "https://github.com/apollographql/apollo-ios.git", from: "1.25.7"),
.package(url: "https://github.com/apple/swift-collections.git", from: "1.6.0"),
.package(url: "https://github.com/SnapKit/SnapKit.git", from: "5.7.1"),
.package(url: "https://github.com/SwifterSwift/SwifterSwift.git", from: "6.2.0"),

View File

@@ -55,10 +55,10 @@ public extension ChatManager {
}
DispatchQueue.global().async {
self.prepareContext(
self.startCopilotResponse(
workspaceId: workspaceId,
sessionId: sessionId,
editorData: editorData,
sessionId: sessionId,
viewModelId: viewModelId
)
}
@@ -66,108 +66,15 @@ public extension ChatManager {
}
private extension ChatManager {
func prepareContext(
workspaceId: String,
sessionId: String,
editorData: InputBoxData,
viewModelId: UUID
) {
assert(!Thread.isMainThread)
let createContext = CreateCopilotContextMutation(
workspaceId: workspaceId,
sessionId: sessionId
)
QLService.shared.client.perform(mutation: createContext) { result in
DispatchQueue.main.async {
switch result {
case let .success(graphQLResult):
guard let contextId = graphQLResult.data?.createCopilotContext else {
self.report(sessionId, ChatError.invalidResponse)
return
}
print("[+] copilot context created: \(contextId)")
DispatchQueue.global().async {
let docAttachGroup = DispatchGroup()
for docAttach in editorData.documentAttachments {
let addDoc = AddContextDocMutation(
options: .init(
contextId: contextId,
docId: docAttach.documentID
)
)
docAttachGroup.enter()
QLService.shared.client.perform(mutation: addDoc) { result in
switch result {
case .success:
print("[+] doc \(docAttach.documentID) added to context")
case let .failure(error):
print("[-] addContextDoc failed: \(error)")
}
docAttachGroup.leave()
}
}
docAttachGroup.notify(queue: .global()) {
var contextSnippet = ""
if !editorData.documentAttachments.isEmpty {
let sem = DispatchSemaphore(value: 0)
let matchQuery = MatchContextQuery(
contextId: .some(contextId),
workspaceId: .some(workspaceId),
content: editorData.text,
limit: .none,
scopedThreshold: .none,
threshold: .none
)
QLService.shared.client.fetch(query: matchQuery) { result in
switch result {
case let .success(queryResult):
let matches = queryResult.data?.currentUser?.copilot.contexts ?? []
let matchDocs = matches.compactMap(\.matchWorkspaceDocs).flatMap(\.self)
for context in matchDocs {
contextSnippet += "<file docId=\"\(context.docId)\" chunk=\"\(context.chunk)\">\(context.content)</file>\n"
}
case let .failure(error):
print("[-] matchContext failed: \(error)")
// self.report(sessionId, error)
}
sem.signal()
}
sem.wait()
}
print("[+] context snippet prepared: \(contextSnippet)")
self.startCopilotResponse(
editorData: editorData,
contextSnippet: contextSnippet,
sessionId: sessionId,
viewModelId: viewModelId
)
}
}
case let .failure(error):
self.report(sessionId, error)
return
}
}
}
}
func startCopilotResponse(
workspaceId: String,
editorData: InputBoxData,
contextSnippet: String,
sessionId: String,
viewModelId: UUID
) {
assert(!Thread.isMainThread)
print("[+] starting copilot response for session: \(sessionId)")
let messageParameters: AffineGraphQL.JSON = [
// packages/frontend/core/src/blocksuite/ai/provider/setup-provider.tsx
"docs": editorData.documentAttachments.map(\.documentID), // affine doc
"files": [String](), // attachment in context, keep nil for now
"searchMode": editorData.isSearchEnabled ? "MUST" : "AUTO",
]
let uploadableAttachments: [CopilotAttachmentUpload] = [
editorData.fileAttachments.map { file -> CopilotAttachmentUpload in
.init(
@@ -185,13 +92,28 @@ private extension ChatManager {
},
].flatMap(\.self)
assert(uploadableAttachments.allSatisfy { !$0.data.isEmpty })
let messageContent = contextSnippet.isEmpty ? editorData.text : "\(contextSnippet)\n\(editorData.text)"
Task {
do {
let selectedDocumentIds = editorData.documentAttachments.map(\.documentID)
if !selectedDocumentIds.isEmpty {
try await IntelligentContext.shared.waitForSelectedSources(selectedDocumentIds)
}
let messageParameters: AffineGraphQL.JSON = [
// packages/frontend/core/src/blocksuite/ai/provider/setup-provider.tsx
"scopeSelectors": editorData.documentAttachments.map { attachment in
[
"kind": "document",
"id": attachment.documentID,
"name": attachment.title,
"source": "draft",
]
},
"searchMode": editorData.isSearchEnabled ? "MUST" : "AUTO",
]
let messageIdentifier = try await QLService.shared.createCopilotMessage(
workspaceId: IntelligentContext.shared.currentWorkspaceId ?? "",
workspaceId: workspaceId,
sessionId: sessionId,
content: messageContent,
content: editorData.text,
params: messageParameters,
attachments: uploadableAttachments
)

View File

@@ -20,10 +20,13 @@ enum BridgedWindowScript: String {
case getAiButtonFeatureFlag = "window.getAiButtonFeatureFlag();"
case getCurrentI18nLocale = "window.getCurrentI18nLocale();"
case createNewDocByMarkdownInCurrentWorkspace = "return await window.createNewDocByMarkdownInCurrentWorkspace(markdown, title);"
case waitForSelectedSources = "return await window.waitForSelectedSources(documentIds);"
var requiresAsyncContext: Bool {
switch self {
case .getCurrentDocContentInMarkdown, .createNewDocByMarkdownInCurrentWorkspace: true
case .getCurrentDocContentInMarkdown,
.createNewDocByMarkdownInCurrentWorkspace,
.waitForSelectedSources: true
default: false
}
}

View File

@@ -25,27 +25,27 @@ public extension IntelligentContext {
workspaceId: workspaceId
)
let mutation = CreateCopilotSessionMutation(options: input)
let mutation = CreateCopilotSessionWithHistoryMutation(options: input)
QLService.shared.client.perform(mutation: mutation) { result in
switch result {
case let .success(graphQLResult):
guard let sessionId = graphQLResult.data?.createCopilotSession else {
guard let history = graphQLResult.data?.createCopilotSessionWithHistory else {
completion(.failure(IntelligentError.sessionCreationFailed("No session ID returned.")))
return
}
let session = ChatSessionObject(
id: sessionId,
workspaceId: workspaceId,
docId: docId,
promptName: promptName.rawValue,
id: history.sessionId,
workspaceId: history.workspaceId,
docId: history.docId,
promptName: history.promptName,
model: nil,
pinned: pinned,
pinned: history.pinned,
tokens: 0,
createdAt: DateTime(date: Date()),
updatedAt: DateTime(date: Date()),
parentSessionId: nil
createdAt: history.createdAt,
updatedAt: history.updatedAt,
parentSessionId: history.parentSessionId
)
completion(.success(session))

View File

@@ -9,6 +9,16 @@ import UIKit
import WebKit
extension IntelligentContext {
@MainActor
func waitForSelectedSources(_ documentIds: [String]) async throws {
_ = try await webView.callAsyncJavaScript(
BridgedWindowScript.waitForSelectedSources.rawValue,
arguments: ["documentIds": documentIds],
in: nil,
contentWorld: .page
)
}
func prepareMetadataFrom(webView: WKWebView, completion: @escaping ([WebViewMetadataKey: Any]) -> Void) {
var newMetadata: [WebViewMetadataKey: Any] = [:]
let dispatchGroup = DispatchGroup()