Skip to content

Commit fffd19a

Browse files
committed
feat(protocol): add typed session and prompt result models
1 parent a4e7e00 commit fffd19a

5 files changed

Lines changed: 185 additions & 0 deletions

File tree

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Copyright (c) 2018-present, easy-4-java.
3+
* Licensed under the Apache License, Version 2.0.
4+
*/
5+
package io.github.easy4j.kimi.model;
6+
7+
import java.util.Map;
8+
9+
import tools.jackson.databind.JsonNode;
10+
11+
public final class KimiPromptResult {
12+
private final String sessionId;
13+
private final KimiStopReason stopReason;
14+
private final String content;
15+
private final KimiUsage usage;
16+
private final Map<String, JsonNode> extensions;
17+
18+
KimiPromptResult(String sessionId, KimiStopReason stopReason, String content,
19+
KimiUsage usage, Map<String, JsonNode> extensions) {
20+
this.sessionId = sessionId;
21+
this.stopReason = stopReason;
22+
this.content = content;
23+
this.usage = usage;
24+
this.extensions = KimiSession.immutableExtensions(extensions);
25+
}
26+
27+
public String getSessionId() { return sessionId; }
28+
public KimiStopReason getStopReason() { return stopReason; }
29+
public String getContent() { return content; }
30+
public KimiUsage getUsage() { return usage; }
31+
public Map<String, JsonNode> getExtensions() { return extensions; }
32+
}

‎src/main/java/io/github/easy4j/kimi/model/KimiProtocolMapper.java‎

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,74 @@ public KimiMessage readMessage(String json) {
6464
}
6565
}
6666

67+
public KimiSession readSession(String json) {
68+
JsonNode root = readObject(json, "Kimi session");
69+
Map<String, JsonNode> extensions = extensions(root, "sessionId", "session_id", "model", "mode");
70+
return new KimiSession(firstText(root, "sessionId", "session_id"),
71+
root.path("model").asText(null),
72+
root.path("mode").asText(null),
73+
extensions);
74+
}
75+
76+
public KimiPromptResult readPromptResult(String json) {
77+
JsonNode root = readObject(json, "Kimi prompt result");
78+
JsonNode usageNode = root.path("usage");
79+
KimiUsage usage = usageNode.isObject()
80+
? new KimiUsage(usageNode.path("inputTokens").asLong(0L),
81+
usageNode.path("outputTokens").asLong(0L),
82+
usageNode.path("totalTokens").asLong(0L))
83+
: null;
84+
Map<String, JsonNode> extensions = extensions(root,
85+
"sessionId", "session_id", "stopReason", "stop_reason", "content", "usage");
86+
return new KimiPromptResult(firstText(root, "sessionId", "session_id"),
87+
KimiStopReason.of(firstText(root, "stopReason", "stop_reason")),
88+
root.path("content").asText(null),
89+
usage,
90+
extensions);
91+
}
92+
93+
private JsonNode readObject(String json, String what) {
94+
if (json == null) {
95+
throw new NullPointerException("json");
96+
}
97+
try {
98+
JsonNode root = mapper.readTree(json);
99+
if (root == null || !root.isObject()) {
100+
throw new KimiException(what + " must be a JSON object");
101+
}
102+
return root;
103+
} catch (KimiException e) {
104+
throw e;
105+
} catch (Exception e) {
106+
throw new KimiException("Failed to parse " + what, e);
107+
}
108+
}
109+
110+
private Map<String, JsonNode> extensions(JsonNode root, String... known) {
111+
Map<String, Boolean> knownNames = new LinkedHashMap<String, Boolean>();
112+
for (String name : known) {
113+
knownNames.put(name, Boolean.TRUE);
114+
}
115+
Map<String, JsonNode> result = new LinkedHashMap<String, JsonNode>();
116+
for (Map.Entry<String, JsonNode> entry : root.properties()) {
117+
if (!knownNames.containsKey(entry.getKey())) {
118+
JsonNode value = entry.getValue();
119+
result.put(entry.getKey(), value == null ? null : value.deepCopy());
120+
}
121+
}
122+
return result;
123+
}
124+
125+
private String firstText(JsonNode node, String... names) {
126+
for (String name : names) {
127+
String value = node.path(name).asText(null);
128+
if (value != null && !value.isEmpty()) {
129+
return value;
130+
}
131+
}
132+
return null;
133+
}
134+
67135
private KimiContentBlock readContentBlock(JsonNode node) {
68136
if (node == null || !node.isObject()) {
69137
return new KimiUnknownContentBlock(null, node == null ? mapper.nullNode() : node);
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright (c) 2018-present, easy-4-java.
3+
* Licensed under the Apache License, Version 2.0.
4+
*/
5+
package io.github.easy4j.kimi.model;
6+
7+
import java.util.Collections;
8+
import java.util.LinkedHashMap;
9+
import java.util.Map;
10+
11+
import tools.jackson.databind.JsonNode;
12+
13+
public final class KimiSession {
14+
private final String id;
15+
private final String model;
16+
private final String mode;
17+
private final Map<String, JsonNode> extensions;
18+
19+
KimiSession(String id, String model, String mode, Map<String, JsonNode> extensions) {
20+
this.id = id;
21+
this.model = model;
22+
this.mode = mode;
23+
this.extensions = immutableExtensions(extensions);
24+
}
25+
26+
public String getId() { return id; }
27+
public String getModel() { return model; }
28+
public String getMode() { return mode; }
29+
public Map<String, JsonNode> getExtensions() { return extensions; }
30+
31+
static Map<String, JsonNode> immutableExtensions(Map<String, JsonNode> source) {
32+
Map<String, JsonNode> copy = new LinkedHashMap<String, JsonNode>();
33+
for (Map.Entry<String, JsonNode> entry : source.entrySet()) {
34+
copy.put(entry.getKey(), entry.getValue() == null ? null : entry.getValue().deepCopy());
35+
}
36+
return Collections.unmodifiableMap(copy);
37+
}
38+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright (c) 2018-present, easy-4-java.
3+
* Licensed under the Apache License, Version 2.0.
4+
*/
5+
package io.github.easy4j.kimi.model;
6+
7+
public final class KimiStopReason {
8+
private final String value;
9+
10+
private KimiStopReason(String value) {
11+
this.value = value;
12+
}
13+
14+
public static KimiStopReason of(String value) {
15+
return new KimiStopReason(value);
16+
}
17+
18+
public String getValue() {
19+
return value;
20+
}
21+
22+
@Override
23+
public String toString() {
24+
return value;
25+
}
26+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Copyright (c) 2018-present, easy-4-java.
3+
* Licensed under the Apache License, Version 2.0.
4+
*/
5+
package io.github.easy4j.kimi.model;
6+
7+
public final class KimiUsage {
8+
private final long inputTokens;
9+
private final long outputTokens;
10+
private final long totalTokens;
11+
12+
KimiUsage(long inputTokens, long outputTokens, long totalTokens) {
13+
this.inputTokens = inputTokens;
14+
this.outputTokens = outputTokens;
15+
this.totalTokens = totalTokens;
16+
}
17+
18+
public long getInputTokens() { return inputTokens; }
19+
public long getOutputTokens() { return outputTokens; }
20+
public long getTotalTokens() { return totalTokens; }
21+
}

0 commit comments

Comments
 (0)