感謝所有套件作者、貢獻者和早期存取計畫參與者,特別是 Jon Holtan、Rody Davis、Dominik Roszkowski、Alexander Thiele 和 Morgan McKenzie。這些社群成員測試了早期版本、審查了文件並幫助塑造了這些 API。請持續關注有關直接原生互通的專門文章。
在 Windows 和 Linux 上,桌面渲染獲得了關鍵的保真度和效能升級。Windows 引擎現在預設請求 OpenGL ES 3,同時保留自動 OpenGL ES 2 回退支援,解鎖了現代圖形功能,而不會丟棄舊的 PC。Windows 應用程式現在可以從包含非 ASCII 字元的路徑(例如國際使用者名稱或資料夾名稱)載入資產和檔案。Windows 還以改進的對比度渲染更清晰的文字,並跳過每個畫面額外的全螢幕複製以減少 GPU 開銷。在 Windows 和 Linux 上,改進的抗鋸齒平滑了分層 UI 元素和自訂形狀上的鋸齒邊緣。
@Schema() abstractclass $TripRequest{ Stringget destination; intget days; } // ...plus an Itinerary schema for the result. final ai = Genkit(plugins: [googleAI()]);
final planTrip = ai.defineFlow( name: 'planTrip', inputSchema: TripRequest.$schema, outputSchema: Itinerary.$schema, fn: (request, _) async { final response = await ai.generate( model: googleAI.gemini('gemini-flash-latest'), prompt: 'Plan a ${request.days}-day trip to ${request.destination}.', outputSchema: Itinerary.$schema, ); return response.output!; }, );
await (GenkitRouter()..addAction(planTrip)).serve(port: 8080); // POST /planTrip
// shared/lib/models.dart (used by both server and app) @Schema() abstractclass $TripRequest{ Stringget destination; intget days; } // ...plus an Itinerary schema for the result.
// server/bin/server.dart final planTrip = ai.defineFlow( name: 'planTrip', inputSchema: TripRequest.$schema, outputSchema: Itinerary.$schema, fn: (request, _) async { final response = await ai.generate( model: googleAI.gemini('gemini-flash-latest'), prompt: 'Plan a ${request.days}-day trip to ${request.destination}.', outputSchema: Itinerary.$schema, ); return response.output!; }, ); await (GenkitRouter()..addAction(planTrip)).serve(port: 8080); // POST /planTrip
// app/lib/main.dart final planTrip = defineRemoteAction( url: 'https://api.example.com/planTrip', // Your Genkit endpoint inputSchema: TripRequest.$schema, outputSchema: Itinerary.$schema, ); final itinerary = await planTrip( input: TripRequest(destination: 'Kyoto', days: 5), );
Dart 執行到哪裡,程式碼就執行到哪裡
因為您的 AI 邏輯是用標準 Dart 撰寫的,所以您可以透過熱重載快速疊代,並靈活地在適合您架構的任何地方執行程式碼:
直接在 Flutter 中:直接從您的應用程式呼叫模型,進行快速原型開發或自帶金鑰體驗(切勿在已發佈的用戶端應用程式中嵌入私有 API 金鑰)。
// server/bin/server.dart final genkit = GenkitRouter() ..addAction( googleAI().model('gemini-flash-latest'), path: '/gemini', // Runs before the model; throw a GenkitException to reject the request. contextProvider: (request) async => {'user': await verifyUser(request.headers['authorization'])}, ); await genkit.serve(port: 8080);
// app/lib/main.dart final ai = Genkit(); final gemini = ai.defineRemoteModel( name: 'gemini', url: 'https://api.example.com/gemini', headers: (context) async => {'Authorization': 'Bearer ${await getIdToken()}'}, ); final response = await ai.generate( model: gemini, prompt: 'Suggest a packing list for Kyoto in April.', );
final bookHotel = ai.defineTool( name: 'bookHotel', description: 'Books a hotel room for the user.', inputSchema: HotelBooking.$schema, fn: (input, ctx) async { // Ask the user to confirm before charging their card. if (ctx.resumed == null) { return .interrupt({'hotel': input.hotelName, 'total': input.totalPrice}); } final confirmation = await hotels.book(input); return .response(confirmation.id); }, );
--- model: googleai/gemini-flash-latest input: schema: destination: string --- Write a friendly, two-sentence introduction to {{destination}} for a first-time visitor.
1 2
final introPrompt = await ai.prompt('destinationIntro'); final response = await introPrompt({'destination': 'Kyoto'});
final travelAgent = ai.defineAgent( name: 'travelAgent', model: googleAI.gemini('gemini-flash-latest'), system: 'You help users plan and book trips.', tools: [searchFlights, bookHotel], store: FirestoreSessionStore(collection: 'sessions'), );
final chat = travelAgent.chat(sessionId: 'user-123'); final response = await chat.send(text: 'Find me a weekend in Lisbon.');
@freezed sealedclassMessageParameterswith_$MessageParameters{ /// Creates a new latte order. @Implements.fromString('BackendMessage<SaveOrderResponse>') constfactory MessageParameters.saveOrder({ @LatteOrderConverter() required LatteOrder order, }) = SaveOrderParameters;
/// Marks a latte order as completed. @Implements.fromString('BackendMessage<EmptyResponse>') constfactory MessageParameters.completeOrder({ requiredString orderId, requiredString baristaId, }) = CompleteOrderParameters;
// Many more message types... }
MessageResponse
這關閉了迴圈,宣告了每個方法呼叫預期的回應類別。它為需要即時回饋的方法提供了單獨的回應類型,並提供了空回應以表示 202 Accepted 或 204 No Content HTTP 回應。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
@freezed sealedclassMessageResponsewith_$MessageResponse{ /// Return data for [SaveOrderParameters]. constfactory MessageResponse.saveOrder({required LatteOrder? latteOrder}) = SaveOrderResponse;
// Many more response types...
/// Placeholder for method calls which require no return value. /// /// This is typically because the client will pick up any state changes via /// watched Firestore collections. constfactory MessageResponse.empty() = EmptyResponse; }
本專案的主要目標是擴展 package:ffigen 以自動生成 C++ API 的 Dart FFI 綁定。Dart 可以透過 FFI 套件與 C 和 C 相容的 API 通信,而 FFIgen 可以自動生成這些 API 的 Dart 綁定。然而,C++ 引入了 Dart FFI 無法直接表示的概念,例如類別、建構子和解構子、繼承和原生物件所有權。因此,從 Dart 使用 C++ 函式庫需要額外的膠水程式碼並仔細處理 Dart 物件及其底層 C++ 物件之間的關係。
FFIgen 中的實驗性 C++ 支援透過為 C++ 類別生成 Dart 綁定以及所需的 C++ 膠水程式碼來解決這些挑戰。生成的綁定支援 C++ 類別指標和原生物件生命週期管理,允許 Dart 物件與其底層 C++ 物件互動,同時保留原生所有權語義。這使得從 Dart 使用 C++ 類別成為可能,而無需使用者手動編寫綁定和記憶體管理層。
// Instantiate the C++ class through the generated constructor wrapper. final animal = Animal(10); expect(animal.getAge(), 10); animal.speak(); // Invoke a static C++ method. expect(Animal.getCount(), 42); // Deterministically release the native object. animal.dispose();
這種方法在 C++ 物件導向 API 和 Dart 的 FFI 模型之間提供了橋樑,同時使生成的綁定盡可能接近原始 C++ API 的語義。
現在,pkg:material_ui 和 pkg:cupertino_ui 分別獨立成套件,可以按照自己的每週排程發布。這簡化了 CI 工作流程,並且更容易貢獻,特別是對於那些不熟悉 Flutter 內部結構的人來說。
基於這些原因,我們預計 Material 和 Cupertino 將加速開發進程,並更好地與 Google 和 Apple 的設計語言更新保持同步。例如,Liquid Glass 和 Material 3 Expressive 的官方實作已經在進行中。我們正在與我們的套件作者社群合作,以確保 Flutter 對這些函式庫的實作具有最佳的品質和相容性。
--- name: networking-error-handling description: >- Use when the user is making network requests using the networking APIs to ensure safe patterns. ---
# Networking Error Handling
## Guidelines
- Operations must always be wrapped in a try/catch block. - You must catch `NetworkException` specifically to handle retries and log diagnostics. - Provide fallback UI state in the event of a timeout.
## Examples
```dart try { final response = await NetworkingClient.fetchData(); } on NetworkException catch (e) { Logger.log(e.context); return FallbackData(); }
/// 一個客戶端函數,使用本地 Dart 邏輯直接在設備上計算食材成本。classCalculateCostFunctionextendsSynchronousClientFunction{constCalculateCostFunction();// 1. LLM 在 A2UI 負載中引用的識別碼。@overrideStringgetname=>'calculateCost';// 2. 提供給 LLM 的清晰描述,以便它知道何時以及為何使用該函數。@overrideStringgetdescription=>'Calculates the cost for a certain quantity of an ingredient. ''Returns a formatted dollar string (for example, \$4.50).';// 3. 綁定的預期回傳類型。@overrideClientFunctionReturnTypegetreturnType=>ClientFunctionReturnType.string;// 4. 定義所需輸入參數的 JSON Schema。@overrideSchemagetargumentSchema=>S.object(properties:{'ingredient_id':S.string(description:'The ID of the ingredient.'),'quantity':S.number(description:'The quantity of the ingredient.'),},required:['ingredient_id','quantity'],);// 5. 客戶端上的同步 Dart 執行邏輯@overrideObject?executeSync(JsonMapargs,ExecutionContextcontext){finalingredientId=args['ingredient_id'].toString();finalquantity=num.tryParse(args['quantity'].toString())?.toDouble();if(quantity==null||quantity<1){return'\$0.00';}// 呼叫本地成本服務來獲取價格並格式化為貨幣finalcost=CostService().fetchPrice(ingredientId,quantity);return'\$${cost.toStringAsFixed(2)}';}}