Flower Intelligence

Flower Intelligence is a cross-platform inference library that let’s user seamlessly interact with Large-Language Models both locally and remotely in a secure and private way. The library was created by the Flower Labs team that also created Flower: A Friendly Federated AI Framework.

We currently provide SDKs for TypeScript/JavaScript and Swift.

Install

npm i "@flwr/flwr"
npm i "@flwr/flwr"
# You can add package dependency to your Xcode project via its UI.
# Please refer to https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app.
#
# To add dependency to your Swift package, you can run the following command:
swift package add-dependency "https://github.com/adap/flower.git"

Hello, Flower Intelligence!

Flower Intelligence is built around the Singleton design pattern, meaning you only need to configure a single instance that can be reused throughout your project. This simple setup helps you integrate powerful AI capabilities with minimal overhead.

import { ChatResponseResult, FlowerIntelligence } from '@flwr/flwr';

// Access the singleton instance
const fi: FlowerIntelligence = FlowerIntelligence.instance;

async function main() {
  // Perform the inference
  const response: ChatResponseResult = await fi.chat("Why is the sky blue?");

  if (response.ok) {
    console.log(response.message.content);
  }
}

await main().then().catch();
import { FlowerIntelligence } from '@flwr/flwr';

// Access the singleton instance
const fi = FlowerIntelligence.instance;

async function main() {
  // Perform the inference
  const response = await fi.chat("Why is the sky blue?");

  console.log(response.message.content);
}

await main().then().catch();
import FlowerIntelligence

let fi = FlowerIntelligence.instance

let result = await fi.chat("Why is the sky blue?")
switch result {
case .success(let message):
  print(message.content)
case .failure(let error):
  print(error.localizedDescription)
}

Specify the model

By specifying a model in the chat options, you can easily switch between different AI models available in the ecosystem. For a full list of supported models, please refer to the available models list.

import { ChatResponseResult, FlowerIntelligence } from '@flwr/flwr';

// Access the singleton instance
const fi: FlowerIntelligence = FlowerIntelligence.instance;

async function main() {
  // Perform the inference
  const response: ChatResponseResult = await fi.chat('Why is the sky blue?', {
    model: 'meta/llama3.2-1b/instruct-fp16',
  });

  if (response.ok) {
    console.log(response.message.content);
  }
}

await main().then().catch();
import { FlowerIntelligence } from '@flwr/flwr';

// Access the singleton instance
const fi = FlowerIntelligence.instance;

async function main() {
  // Perform the inference
  const response = await fi.chat('Why is the sky blue?', {
    model: 'meta/llama3.2-1b/instruct-fp16',
  });

  console.log(response.message.content);
}

await main().then().catch();
import FlowerIntelligence

let fi = FlowerIntelligence.instance

let options = ChatOptions(model: "meta/llama3.2-1b/instruct-fp16")
let result = await fi.chat("Why is the sky blue?", maybeOptions: options)

switch result {
case .success(let message):
    print(message.content)
case .failure(let error):
    print(error.localizedDescription)
}

Check for errors

Instead of throwing exceptions that might crash your application, Flower Intelligence returns a response object that includes a dedicated Failure property, enabling graceful error handling and improved application stability.

import { ChatResponseResult, FlowerIntelligence } from '@flwr/flwr';

// Access the singleton instance
const fi: FlowerIntelligence = FlowerIntelligence.instance;

async function main() {
  // Perform the inference
  const response: ChatResponseResult = await fi.chat('Why is the sky blue?', {
    model: 'meta/llama3.2-1b/instruct-fp16',
  });

  if (!response.ok) {
    console.error(`${response.failure.code}: ${response.failure.description}`);
  } else {
    console.log(response.message.content);
  }
}

await main().then().catch();
import { FlowerIntelligence } from '@flwr/flwr';

// Access the singleton instance
const fi = FlowerIntelligence.instance;

async function main() {
  // Perform the inference
  const response = await fi.chat('Why is the sky blue?', {
    model: 'meta/llama3.2-1b/instruct-fp16',
  });

  if (!response.ok) {
    console.error(`${response.failure.code}: ${response.failure.description}`);
  } else {
    console.log(response.message.content);
  }
}

await main().then().catch();
import FlowerIntelligence

let fi = FlowerIntelligence.instance

let options = ChatOptions(model: "meta/llama3.2-1b/instruct-fp16")
let result = await fi.chat("Why is the sky blue?", maybeOptions: options)

switch result {
case .success(let message):
    print(message.content)
case .failure(let error):
    print(error.localizedDescription)
}

Stream Responses

By enabling the stream option and providing a callback function, you can watch the AI’s response as it is being generated. This approach is ideal for interactive applications, as it lets you process partial responses immediately before the full answer is available. The callback function must accept an argument of type StreamEvent.

import { ChatResponseResult, FlowerIntelligence, type StreamEvent } from '@flwr/flwr';

// Access the singleton instance
const fi: FlowerIntelligence = FlowerIntelligence.instance;

async function main() {
  // Perform the inference
  const response: ChatResponseResult = await fi.chat('Why is the sky blue?', {
    model: 'meta/llama3.2-1b/instruct-fp16',
    stream: true,
    onStreamEvent: (event: StreamEvent) => console.log(event.chunk)
  });

  if (!response.ok) {
    console.error(`${response.failure.code}: ${response.failure.description}`);
  } else {
    console.log('Full response:', response.message.content);
  }
}

await main().then().catch();
import { FlowerIntelligence } from '@flwr/flwr';

// Access the singleton instance
const fi = FlowerIntelligence.instance;

async function main() {
  // Perform the inference
  const response = await fi.chat('Why is the sky blue?', {
    model: 'meta/llama3.2-1b/instruct-fp16',
    stream: true,
    onStreamEvent: (event) => console.log(event.chunk)
  });

  if (!response.ok) {
    console.error(`${response.failure.code}: ${response.failure.description}`);
  } else {
    console.log(response.message.content);
  }
}

await main().then().catch();
import FlowerIntelligence

let fi = FlowerIntelligence.instance

let options = ChatOptions(
  model: "meta/llama3.2-1b/instruct-fp16",
  stream: true,
  onStreamEvent: { event in
      print(event.chunk)
  }
)

let result = await fi.chat("Why is the sky blue?", maybeOptions: options)

if case .failure(let error) = result {
    print(error.localizedDescription)
}

Use Roles

Instead of simply sending a single string, you can provide an array of messages with designated roles such as system and user. This allows you to define the behavior and context of the conversation more clearly, ensuring that the assistant responds in a way that’s tailored to the scenario.

import { ChatResponseResult, FlowerIntelligence, type StreamEvent } from '@flwr/flwr';

// Access the singleton instance
const fi: FlowerIntelligence = FlowerIntelligence.instance;

async function main() {
  // Perform the inference
  const response: ChatResponseResult = await fi.chat({
    messages: [
      { role: "system", content: "You are a friendly assistant that loves using emojies." }
      { role: "user", content: "Why is the sky blue?" }
    ],
    model: 'meta/llama3.2-1b/instruct-fp16',
    stream: true,
    onStreamEvent: (event: StreamEvent) => console.log(event.chunk)
  });

  if (!response.ok) {
    console.error(`${response.failure.code}: ${response.failure.description}`);
  } else {
    console.log('Full response:', response.message.content);
  }
}

await main().then().catch();
import { FlowerIntelligence } from '@flwr/flwr';

// Access the singleton instance
const fi = FlowerIntelligence.instance;

async function main() {
  // Perform the inference
  const response = await fi.chat({
    messages: [
      { role: "system", content: "You are a friendly assistant that loves using emojies." }
      { role: "user", content: "Why is the sky blue?" }
    ],
    model: 'meta/llama3.2-1b/instruct-fp16',
    stream: true,
    onStreamEvent: (event) => console.log(event.chunk)
  });

  if (!response.ok) {
    console.error(`${response.failure.code}: ${response.failure.description}`);
  } else {
    console.log(response.message.content);
  }
}

await main().then().catch();
import FlowerIntelligence

let fi = FlowerIntelligence.instance

let messages = [
  Message(role: "system", content: "You are a helpful assistant."),
  Message(role: "user", content: "Why is the sky blue?")
]

let options = ChatOptions(model: "meta/llama3.2-1b/instruct-fp16")
let result = await fi.chat(options: (messages, options))
switch result {
case .success(let message):
  print(message.content)
case .failure(let error):
  print(error.localizedDescription)
}

Handle history

In this example, the conversation history is maintained in an array that includes both system and user messages. Each time a new message is sent, it is appended to the history, ensuring that the assistant has access to the full dialogue context. This method allows Flower Intelligence to generate responses that are informed by previous interactions, resulting in a more coherent and dynamic conversation.

import { ChatResponseResult, FlowerIntelligence, type StreamEvent } from '@flwr/flwr';

// Access the singleton instance
const fi: FlowerIntelligence = FlowerIntelligence.instance;

// Initialize history with a system message.
const history: Message[] = [
  { role: "system", content: "You are a friendly assistant that loves using emojis." }
];

// Function to chat while preserving conversation history.
async function chatWithHistory(userInput: string): Promise<void> {
  // Append user input to the history.
  history.push({ role: "user", content: userInput });

  // Send the entire history to the chat method.
  const response: ChatResponseResult = await fi.chat({
    messages: history,
    model: 'meta/llama3.2-1b/instruct-fp16',
    stream: true,
    onStreamEvent: (event: StreamEvent) => console.log(event.chunk)
  });

  if (response.ok) {
    // Append the assistant's response to the history.
    history.push(response.message);
    console.log("Assistant's full response:", response.message.content);
  } else {
    console.error("Chat error:", response.failure.description);
  }
}

async function main() {
  chatWithHistory("Why is the sky blue?");
}

await main().then().catch();
import { FlowerIntelligence } from '@flwr/flwr';

// Access the singleton instance
const fi = FlowerIntelligence.instance;

// Initialize history with a system message.
const history = [
  { role: "system", content: "You are a friendly assistant that loves using emojis." }
];

// Function to chat while preserving conversation history.
async function chatWithHistory(userInput) {
  // Append user input to the history.
  history.push({ role: "user", content: userInput });

  // Send the entire history to the chat method.
  const response = await fi.chat({
    messages: history,
    model: 'meta/llama3.2-1b/instruct-fp16',
    stream: true,
    onStreamEvent: (event) => console.log(event.chunk)
  });

  if (response.ok) {
    // Append the assistant's response to the history.
    history.push(response.message);
    console.log("Assistant's full response:", response.message.content);
  } else {
    console.error("Chat error:", response.failure.description);
  }
}

async function main() {
  chatWithHistory("Why is the sky blue?");
}

await main().then().catch();
import FlowerIntelligence

let fi = FlowerIntelligence.instance

// Initialize history with a system message
var history: [Message] = [
    Message(role: "system", content: "You are a friendly assistant that loves using emojis.")
]

// Function to chat while preserving conversation history
func chatWithHistory(userInput: String) async {
    // Append user input to the history
    history.append(Message(role: "user", content: userInput))

    // Define chat options with streaming
    let options = ChatOptions(
        model: "meta/llama3.2-1b/instruct-fp16",
        stream: true,
        onStreamEvent: { event in
            print(event.chunk)
        }
    )

    // Perform chat with full history
    let result = await fi.chat(options: (history, options))

    switch result {
    case .success(let response):
        // Append assistant's response to history
        history.append(response)
        print("Assistant's full response:", response.content)
    case .failure(let error):
        print(error.localizedDescription)
    }
}

// Start the conversation
await chatWithHistory("Why is the sky blue?")

Pre-loading the model

You might have noticed that the first time you run inference on a given model, you’ll have to wait longer for it to complete compared to the second time you call the model. This is because the model first needs to be downloaded. This might be undesirable if you have an app where users can click a button and expect a quick response from the model. In this case, you might want to first let the user download the model (or download it on the first start-up), so once they click on the inference button, the results are consistently fast. This can be done using the fetchModel method.

import { ChatResponseResult, FlowerIntelligence, type StreamEvent } from '@flwr/flwr';

// Access the singleton instance
const fi: FlowerIntelligence = FlowerIntelligence.instance;

// Initialize history with a system message.
const history: Message[] = [
  { role: "system", content: "You are a friendly assistant that loves using emojis." }
];

// Function to chat while preserving conversation history.
async function chatWithHistory(userInput: string): Promise<void> {
  // Append user input to the history.
  history.push({ role: "user", content: userInput });

  // Send the entire history to the chat method.
  const response: ChatResponseResult = await fi.chat({
    messages: history,
    model: 'meta/llama3.2-1b/instruct-fp16',
    stream: true,
    onStreamEvent: (event: StreamEvent) => console.log(event.chunk)
  });

  if (response.ok) {
    // Append the assistant's response to the history.
    history.push(response.message);
    console.log("Assistant's full response:", response.message.content);
  } else {
    console.error("Chat error:", response.failure.description);
  }
}

async function main() {
  // Download the model first
  await fi.fetchModel('meta/llama3.2-1b/instruct-fp16');
  chatWithHistory("Why is the sky blue?");
}

await main().then().catch();
import { FlowerIntelligence } from '@flwr/flwr';

// Access the singleton instance
const fi = FlowerIntelligence.instance;

// Initialize history with a system message.
const history = [
  { role: "system", content: "You are a friendly assistant that loves using emojis." }
];

// Function to chat while preserving conversation history.
async function chatWithHistory(userInput) {
  // Append user input to the history.
  history.push({ role: "user", content: userInput });

  // Send the entire history to the chat method.
  const response = await fi.chat({
    messages: history,
    model: 'meta/llama3.2-1b/instruct-fp16',
    stream: true,
    onStreamEvent: (event) => console.log(event.chunk)
  });

  if (response.ok) {
    // Append the assistant's response to the history.
    history.push(response.message);
    console.log("Assistant's full response:", response.message.content);
  } else {
    console.error("Chat error:", response.failure.description);
  }
}

async function main() {
  await fi.fetchModel('meta/llama3.2-1b/instruct-fp16');
  chatWithHistory("Why is the sky blue?");
}

await main().then().catch();

If you want to follow the progress of the download, you can pass a callback function that takes a Progress object as input:

import { FlowerIntelligence, Progress } from '@flwr/flwr';

await fi.fetchModel('meta/llama3.2-1b/instruct-fp16', (progress: Progress) =>
  console.log(progress.percentage ?? '')
);
import { FlowerIntelligence } from '@flwr/flwr';

await fi.fetchModel('meta/llama3.2-1b/instruct-fp16', (progress) =>
  console.log(progress.percentage ?? '')
);

Note

Checkout out full examples over on GitHub for more information!

Flower Confidential Remote Compute

Warning

Flower Confidential Remote Compute is available in private beta. If you are interested in using Confidential Remote Compute, please apply for Early Access via the Flower Intelligence Pilot Program.

Flower Intelligence prioritizes local inference, but also allows to privately handoff the compute to the Flower Confidential Remote Compute service when local resources are scarce. You can find more information on flower.ai/intelligence.

This feature is turned off by default, and can be enabled by using the remoteHandoff attribute of the FlowerIntelligence object.

You will also need to provide a valid API key via the apiKey attribute.

import { ChatResponseResult, FlowerIntelligence, type StreamEvent } from '@flwr/flwr';

// Access the singleton instance
const fi: FlowerIntelligence = FlowerIntelligence.instance;

// Enable remote processing and provide your API key
fi.remoteHandoff = true;
fi.apiKey = "YOUR_API_KEY";

async function main() {
  const response: ChatResponseResult = await fi.chat({
    messages: [
      { role: "system", content: "You are a friendly assistant that loves using emojies." }
      { role: "user", content: "Why is the sky blue?" }
    ],
    model: 'meta/llama3.2-1b/instruct-fp16',
    stream: true,
    onStreamEvent: (event: StreamEvent) => console.log(event.chunk)
  });

  if (!response.ok) {
    console.error(`${response.failure.code}: ${response.failure.description}`);
  } else {
    console.log('Full response:', response.message.content);
  }
}

await main().then().catch();
import { FlowerIntelligence } from '@flwr/flwr';

// Access the singleton instance
const fi = FlowerIntelligence.instance;

// Enable remote processing and provide your API key
fi.remoteHandoff = true;
fi.apiKey = "YOUR_API_KEY";

async function main() {
  const response = await fi.chat({
    messages: [
      { role: "system", content: "You are a friendly assistant that loves using emojies." }
      { role: "user", content: "Why is the sky blue?" }
    ],
    model: 'meta/llama3.2-1b/instruct-fp16',
    stream: true,
    onStreamEvent: (event) => console.log(event.chunk)
  });

  if (!response.ok) {
    console.error(`${response.failure.code}: ${response.failure.description}`);
  } else {
    console.log(response.message.content);
  }
}

await main().then().catch();
import FlowerIntelligence

let fi = FlowerIntelligence.instance
fi.remoteHandoff = true
fi.apiKey = "YOUR_API_KEY"

let messages = [
  Message(role: "system", content: "You are a helpful assistant."),
  Message(role: "user", content: "Why is the sky blue?")
]

let options = ChatOptions(
  model: "meta/llama3.2-1b/instruct-fp16",
  stream: true,
  onStreamEvent: { event in
      print(event.chunk)
  }
)

let result = await fi.chat(options: (messages, options))

if case .failure(let error) = result {
  print(error.localizedDescription)
}

References

Information-oriented API reference and other reference material.

Contributor guides

If you are interested in contributing or playing around with the source code.

Contributor docs

Join the Flower Community

The Flower Community is growing quickly - we’re a friendly group of researchers, engineers, students, professionals, academics, and other enthusiasts.

Join us on Slack