Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions CodenameOne/src/com/codename1/ai/AnthropicClient.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
/*
* Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/
package com.codename1.ai;

import com.codename1.util.AsyncResource;

/// Anthropic /v1/messages client. Wire format differs from OpenAI in
/// three important ways: system messages live in a top-level `system`
/// string rather than a role; image parts use `{type:"image", source:
/// {type:"base64", media_type, data}}`; tool calls stream argument
/// JSON via `input_json_delta` events.
///
/// This is currently a scaffold -- the full request/response mapping
/// is tracked as a follow-up. The class compiles and registers under
/// `LlmClient.anthropic(...)` so app code using the API can be built;
/// runtime calls throw a clear `UnsupportedOperationException`.
class AnthropicClient extends LlmClient {
private final String apiKey;

AnthropicClient(String apiKey, String baseUrl) {
super(baseUrl);
this.apiKey = apiKey;
}

public String getProvider() {
return "anthropic";
}

public AsyncResource<ChatResponse> chat(ChatRequest req) {
AsyncResource<ChatResponse> r = new AsyncResource<ChatResponse>();
r.error(new UnsupportedOperationException(
"AnthropicClient is not yet implemented in this release. "
+ "Use LlmClient.openai(...) or run the model behind an OpenAI-compatible proxy."));
return r;
}

public AsyncResource<ChatResponse> chatStream(ChatRequest req, StreamingListener listener) {
return chat(req);
}

public AsyncResource<EmbeddingResponse> embed(EmbeddingRequest req) {
AsyncResource<EmbeddingResponse> r = new AsyncResource<EmbeddingResponse>();
r.error(new UnsupportedOperationException(
"Anthropic does not publish a first-party embeddings endpoint. "
+ "Use a Voyage AI key via LlmClient.localOpenAiCompatible(\"https://api.voyageai.com/v1\", key, model)."));
return r;
}

String getApiKey() {
return apiKey;
}
}
132 changes: 132 additions & 0 deletions CodenameOne/src/com/codename1/ai/ChatMessage.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* Copyright (c) 2012, Codename One and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Codename One designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Codename One through http://www.codenameone.com/ if you
* need additional information or have any questions.
*/
package com.codename1.ai;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;

/// A single turn in a chat conversation. Holds a [Role], one or more
/// [MessagePart]s, and (for assistant turns) any [ToolCall]s the model
/// produced. Construct via the static helpers ([#user(String)],
/// [#system(String)], etc.) for the common case, or pass parts
/// directly for multi-modal messages.
public final class ChatMessage {
private final Role role;
private final List<MessagePart> parts;
private final List<ToolCall> toolCalls;
private final String name;
private final String toolCallId;

public ChatMessage(Role role, List<MessagePart> parts) {
this(role, parts, null, null, null);
}

public ChatMessage(Role role, List<MessagePart> parts, List<ToolCall> toolCalls,
String name, String toolCallId) {
if (role == null) {
throw new IllegalArgumentException("role is required");
}
this.role = role;
this.parts = parts == null ? Collections.<MessagePart>emptyList()
: Collections.unmodifiableList(new ArrayList<MessagePart>(parts));
this.toolCalls = toolCalls == null ? Collections.<ToolCall>emptyList()
: Collections.unmodifiableList(new ArrayList<ToolCall>(toolCalls));
this.name = name;
this.toolCallId = toolCallId;
}

public static ChatMessage system(String text) {
return single(Role.SYSTEM, new TextPart(text));
}

public static ChatMessage user(String text) {
return single(Role.USER, new TextPart(text));
}

public static ChatMessage assistant(String text) {
return single(Role.ASSISTANT, new TextPart(text));
}

/// Builds a USER message containing both a text and image part --
/// the common multi-modal pattern.
public static ChatMessage userWithImage(String text, ImagePart image) {
List<MessagePart> parts = new ArrayList<MessagePart>(2);
if (text != null && text.length() > 0) {
parts.add(new TextPart(text));
}
parts.add(image);
return new ChatMessage(Role.USER, parts);
}

/// Builds a TOOL message wrapping the result of a previous tool call.
public static ChatMessage toolResult(String toolCallId, String resultJson) {
return new ChatMessage(Role.TOOL,
Arrays.<MessagePart>asList(new ToolResultPart(toolCallId, resultJson)),
null, null, toolCallId);
}

private static ChatMessage single(Role r, MessagePart p) {
List<MessagePart> parts = new ArrayList<MessagePart>(1);
parts.add(p);
return new ChatMessage(r, parts);
}

public Role getRole() {
return role;
}

public List<MessagePart> getParts() {
return parts;
}

public List<ToolCall> getToolCalls() {
return toolCalls;
}

public String getName() {
return name;
}

public String getToolCallId() {
return toolCallId;
}

/// Convenience: concatenates the text of every [TextPart]. Image
/// and tool-result parts are skipped. Useful for `ChatView`
/// rendering when you don't care about multi-modal content.
public String getText() {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < parts.size(); i++) {
MessagePart p = parts.get(i);
if (p instanceof TextPart) {
if (sb.length() > 0) {
sb.append('\n');
}
sb.append(((TextPart) p).getText());
}
}
return sb.toString();
}
}
Loading