* Copyright (c) 2026 Huawei Technologies Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import test from "node:test"
import assert from "node:assert/strict"
import { extractSkillsWithVersionsFromOpencodeSession, normalizeInteractions } from "../src/lib/shared/interaction-utils"
test("opencode: normalizeInteractions groups into a single turn and preserves assistant request tool calls", () => {
const messages = [
{ role: "user", content: "Diagnose" },
{
role: "assistant",
content: "Launching subagents",
tool_calls: [
{
id: "call_task_1",
type: "function",
function: {
name: "task",
arguments: JSON.stringify({
subagent_type: "kuafu",
load_skills: ["offline-file-system-fault-diagnosis", { name: "disk-diagnosis-by-log", version: 3 }],
description: "T1+T2",
}),
},
},
],
},
{
role: "assistant",
content: "Final answer",
tool_calls: [
{
id: "call_skill_1",
type: "function",
function: { name: "skill", arguments: JSON.stringify({ name: "some-skill", version: 2 }) },
},
],
},
]
const normalized = normalizeInteractions(messages as any[])
assert.equal(normalized.length, 1)
assert.equal(normalized[0].requestMessages.length, 2)
assert.equal(normalized[0].responseMessage?.role, "assistant")
assert.equal(normalized[0].responseMessage?.content, "Final answer")
})
test("opencode: extractSkillsWithVersionsFromOpencodeSession supports skill/load_skill and task.load_skills", () => {
const messages = [
{ role: "user", content: "Diagnose" },
{
role: "assistant",
content: "Launching subagents",
tool_calls: [
{
id: "call_task_1",
type: "function",
function: {
name: "task",
arguments: JSON.stringify({
subagent_type: "kuafu",
load_skills: ["offline-file-system-fault-diagnosis", { name: "disk-diagnosis-by-log", version: 3 }],
}),
},
},
{
id: "call_task_bad_json",
type: "function",
function: {
name: "task",
arguments: "{not-json}",
},
},
],
},
{
role: "assistant",
content: "Final answer",
tool_calls: [
{
id: "call_skill_1",
type: "function",
function: { name: "skill", arguments: JSON.stringify({ name: "some-skill", version: 2 }) },
},
{
id: "call_load_skill_1",
type: "function",
function: { name: "load_skill", arguments: JSON.stringify({ skill: "another-skill" }) },
},
],
},
]
const normalized = normalizeInteractions(messages as any[])
const skills = extractSkillsWithVersionsFromOpencodeSession(normalized)
assert.deepEqual(skills, [
{ name: "some-skill", version: 2 },
{ name: "another-skill", version: null },
{ name: "offline-file-system-fault-diagnosis", version: null },
{ name: "disk-diagnosis-by-log", version: 3 },
])
})
test("opencode: extractSkillsWithVersionsFromOpencodeSession dedupes repeated skill declarations", () => {
const messages = [
{ role: "user", content: "x" },
{
role: "assistant",
content: "y",
tool_calls: [
{
id: "c1",
type: "function",
function: { name: "skill", arguments: JSON.stringify({ name: "dup-skill", version: 1 }) },
},
{
id: "c2",
type: "function",
function: { name: "skill", arguments: JSON.stringify({ name: "dup-skill", version: 2 }) },
},
{
id: "c3",
type: "function",
function: {
name: "task",
arguments: JSON.stringify({ load_skills: ["dup-skill", "unique-skill"] }),
},
},
],
},
]
const normalized = normalizeInteractions(messages as any[])
const skills = extractSkillsWithVersionsFromOpencodeSession(normalized)
assert.deepEqual(skills, [
{ name: "dup-skill", version: 1 },
{ name: "unique-skill", version: null },
])
})
test("opencode: normalizeInteractions treats opencode role as a user boundary", () => {
const messages = [
{ role: "user", content: "Top-level user" },
{ role: "assistant", content: "Top-level assistant" },
{ role: "opencode", content: "Child user message (from subagent session)" },
{ role: "subagent", content: "Child assistant message (from subagent session)" },
]
const normalized = normalizeInteractions(messages as any[])
assert.equal(normalized.length, 2)
assert.equal(normalized[0].requestMessages.length, 1)
assert.equal(normalized[0].responseMessage?.content, "Top-level assistant")
assert.equal(normalized[1].requestMessages.length, 1)
assert.equal(normalized[1].responseMessage?.content, "Child assistant message (from subagent session)")
})
test("opencode: extractSkillsWithVersionsFromOpencodeSession extracts from subagent role tool calls", () => {
const messages = [
{ role: "user", content: "x" },
{ role: "assistant", content: "y" },
{
role: "opencode",
content: "child user",
},
{
role: "subagent",
content: "child assistant",
tool_calls: [
{
id: "call_skill_subagent",
type: "function",
function: { name: "skill", arguments: JSON.stringify({ name: "deep-skill", version: 7 }) },
},
],
},
]
const normalized = normalizeInteractions(messages as any[])
const skills = extractSkillsWithVersionsFromOpencodeSession(normalized)
assert.deepEqual(skills, [{ name: "deep-skill", version: 7 }])
})