@magpie-community/opencode-kiro-auth 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -1
- package/index.mjs +52 -12
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -73,7 +73,11 @@ request:
|
|
|
73
73
|
- The system prompt goes at the head of the first message.
|
|
74
74
|
- Tool calls and results are paired: an unanswered call gets an error
|
|
75
75
|
result, and a result longer than 250,000 characters is cut.
|
|
76
|
-
- Tool ids Kiro wouldn't take are rewritten.
|
|
76
|
+
- Tool ids Kiro wouldn't take are rewritten. A tool name over 64
|
|
77
|
+
characters (an MCP plugin's, in Claude Code) is sent shortened with a
|
|
78
|
+
hash and its calls come back under the full name.
|
|
79
|
+
- A tool's images (a screenshot, Codex's view_image) go with the
|
|
80
|
+
message that answers the call, as Kiro's tool results hold text alone.
|
|
77
81
|
- Only the latest images are sent.
|
|
78
82
|
- Tools the history used but the request doesn't offer are declared.
|
|
79
83
|
- It turns the AWS event stream Kiro answers with back into Messages'
|
package/index.mjs
CHANGED
|
@@ -576,6 +576,36 @@ const TOOL_ID = /^[a-zA-Z0-9_.:-]{1,64}$/
|
|
|
576
576
|
// one of Kiro's own, the same each time.
|
|
577
577
|
const toolID = (id) => (TOOL_ID.test(id ?? "") ? id : "t_" + createHash("sha256").update(String(id ?? "")).digest("base64url").slice(0, 32))
|
|
578
578
|
|
|
579
|
+
// Kiro answers a tool named past 64 characters, or outside these, "Invalid
|
|
580
|
+
// tool use format." and won't raise the limit (kirodotdev/Kiro#7684), while
|
|
581
|
+
// MCP tools in Claude Code are named mcp__plugin_<plugin>_<server>__<tool>
|
|
582
|
+
// (yetone/magpie#1393).
|
|
583
|
+
const TOOL_NAME = /^[a-zA-Z0-9_-]{1,64}$/
|
|
584
|
+
|
|
585
|
+
// toolName is a tool's name as Kiro takes one: another is its head with a
|
|
586
|
+
// hash of the whole name, the same each time, so the conversation's later
|
|
587
|
+
// turns name it the same way. toolNames maps each such name back.
|
|
588
|
+
const toolName = (name) => {
|
|
589
|
+
const n = String(name ?? "")
|
|
590
|
+
if (TOOL_NAME.test(n)) return n
|
|
591
|
+
const hash = createHash("sha256").update(n).digest("hex").slice(0, 12)
|
|
592
|
+
return n.replace(/[^a-zA-Z0-9_-]/g, "_").slice(0, 64 - 1 - hash.length) + "_" + hash
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
// toolNames is the name the caller knows for each tool a request names
|
|
596
|
+
// that Kiro is sent under another name.
|
|
597
|
+
function toolNames(req) {
|
|
598
|
+
const names = new Map()
|
|
599
|
+
const add = (n) => {
|
|
600
|
+
if (typeof n !== "string" || !n) return
|
|
601
|
+
const k = toolName(n)
|
|
602
|
+
if (k !== n) names.set(k, n)
|
|
603
|
+
}
|
|
604
|
+
for (const t of req.tools ?? []) add(t?.name)
|
|
605
|
+
for (const m of req.messages ?? []) if (Array.isArray(m.content)) for (const p of m.content) if (p?.type === "tool_use") add(p.name)
|
|
606
|
+
return names
|
|
607
|
+
}
|
|
608
|
+
|
|
579
609
|
function imageFormat(mediaType) {
|
|
580
610
|
const t = String(mediaType ?? "").toLowerCase()
|
|
581
611
|
const f = t.replace(/^image\//, "")
|
|
@@ -584,6 +614,12 @@ function imageFormat(mediaType) {
|
|
|
584
614
|
return f
|
|
585
615
|
}
|
|
586
616
|
|
|
617
|
+
// addImage puts an Anthropic image block in images as Kiro takes it: the
|
|
618
|
+
// bytes inline. One named only by a URL has no bytes to send and is left out.
|
|
619
|
+
function addImage(images, p) {
|
|
620
|
+
if (p.source?.type === "base64" && p.source.data) images.push({ format: imageFormat(p.source.media_type), source: { bytes: p.source.data } })
|
|
621
|
+
}
|
|
622
|
+
|
|
587
623
|
const textOf = (c) =>
|
|
588
624
|
typeof c === "string" ? c : Array.isArray(c) ? c.filter((p) => p?.type === "text").map((p) => p.text ?? "").join("\n\n") : ""
|
|
589
625
|
const joinNonEmpty = (a, b) => (a && b ? a + "\n\n" + b : a + b)
|
|
@@ -620,7 +656,7 @@ function buildKiro(req, model, profile, budget) {
|
|
|
620
656
|
if (p?.type === "text" && p.text) texts.push(p.text)
|
|
621
657
|
else if (p?.type === "tool_use") {
|
|
622
658
|
const input = p.input && typeof p.input === "object" && !Array.isArray(p.input) ? p.input : {}
|
|
623
|
-
a.toolUses.push({ name: p.name, toolUseId: toolID(p.id), input })
|
|
659
|
+
a.toolUses.push({ name: toolName(p.name), toolUseId: toolID(p.id), input })
|
|
624
660
|
}
|
|
625
661
|
}
|
|
626
662
|
a.content = texts.join("\n\n")
|
|
@@ -639,12 +675,14 @@ function buildKiro(req, model, profile, budget) {
|
|
|
639
675
|
if (p?.type === "text") {
|
|
640
676
|
if (p.text) texts.push(p.text)
|
|
641
677
|
} else if (p?.type === "document") texts.push(documentText(p))
|
|
642
|
-
else if (p?.type === "image")
|
|
643
|
-
|
|
644
|
-
} else if (p?.type === "tool_result") {
|
|
678
|
+
else if (p?.type === "image") addImage(u.images, p)
|
|
679
|
+
else if (p?.type === "tool_result") {
|
|
645
680
|
let out = textOf(p.content)
|
|
646
681
|
if (out.length > RESULT_LIMIT) out = out.slice(0, RESULT_LIMIT) + "\n… (cut)"
|
|
647
682
|
results.push({ toolUseId: toolID(p.tool_use_id), status: p.is_error ? "error" : "success", content: [{ text: out || "(no output)" }] })
|
|
683
|
+
// a tool's images (a screenshot, Codex's view_image) go with the
|
|
684
|
+
// message, as Kiro's tool results carry text alone (magpie #369, #1861)
|
|
685
|
+
if (Array.isArray(p.content)) for (const c of p.content) if (c?.type === "image") addImage(u.images, c)
|
|
648
686
|
}
|
|
649
687
|
}
|
|
650
688
|
u.content = texts.join("\n\n")
|
|
@@ -719,8 +757,9 @@ function buildKiro(req, model, profile, budget) {
|
|
|
719
757
|
const EMPTY = { type: "object", properties: {} }
|
|
720
758
|
for (const t of req.tools ?? []) {
|
|
721
759
|
if (!t?.name || (t.type && t.type !== "custom" && !t.input_schema)) continue // server tools Kiro hasn't
|
|
722
|
-
|
|
723
|
-
|
|
760
|
+
const name = toolName(t.name)
|
|
761
|
+
offered.add(name)
|
|
762
|
+
tools.push({ toolSpecification: { name, description: t.description || t.name, inputSchema: { json: t.input_schema ?? EMPTY } } })
|
|
724
763
|
}
|
|
725
764
|
for (const e of entries)
|
|
726
765
|
for (const c of e.assistantResponseMessage?.toolUses ?? [])
|
|
@@ -1047,8 +1086,9 @@ const QUOTA_WORDS = /quota|insufficient|balance|credit|billing|exceeded|rate.?li
|
|
|
1047
1086
|
const failedBefore = (text) => errorResponse(QUOTA_WORDS.test(text) ? 429 : 502, text)
|
|
1048
1087
|
|
|
1049
1088
|
// reply answers the Messages request from Kiro's events: a stream of
|
|
1050
|
-
// Messages' events, or one message.
|
|
1051
|
-
|
|
1089
|
+
// Messages' events, or one message. names gives back the caller's name of
|
|
1090
|
+
// a tool Kiro was sent under another (toolNames).
|
|
1091
|
+
async function reply(it, model, stream, names = new Map()) {
|
|
1052
1092
|
const id = "msg_" + randomBytes(12).toString("hex")
|
|
1053
1093
|
if (!stream) {
|
|
1054
1094
|
const content = []
|
|
@@ -1066,7 +1106,7 @@ async function reply(it, model, stream) {
|
|
|
1066
1106
|
else add({ type: "thinking", thinking: e.text, signature: "" })
|
|
1067
1107
|
} else if (e.kind === "sig") {
|
|
1068
1108
|
if (last?.type === "thinking") last.signature += e.text
|
|
1069
|
-
} else if (e.kind === "toolStart") add({ type: "tool_use", id: e.id, name: e.name, input: "" })
|
|
1109
|
+
} else if (e.kind === "toolStart") add({ type: "tool_use", id: e.id, name: names.get(e.name) ?? e.name, input: "" })
|
|
1070
1110
|
else if (e.kind === "toolArgs") {
|
|
1071
1111
|
if (last?.type === "tool_use") last.input += e.text
|
|
1072
1112
|
} else if (e.kind === "error") {
|
|
@@ -1127,7 +1167,7 @@ async function reply(it, model, stream) {
|
|
|
1127
1167
|
if (open === "thinking") ctl.enqueue(sse("content_block_delta", { index, delta: { type: "signature_delta", signature: e.text } }))
|
|
1128
1168
|
break
|
|
1129
1169
|
case "toolStart":
|
|
1130
|
-
begin("tool", { type: "tool_use", id: e.id, name: e.name, input: {} })
|
|
1170
|
+
begin("tool", { type: "tool_use", id: e.id, name: names.get(e.name) ?? e.name, input: {} })
|
|
1131
1171
|
break
|
|
1132
1172
|
case "toolArgs":
|
|
1133
1173
|
if (open === "tool") ctl.enqueue(sse("content_block_delta", { index, delta: { type: "input_json_delta", partial_json: e.text } }))
|
|
@@ -1189,7 +1229,7 @@ async function generate(creds, auth, req, signal) {
|
|
|
1189
1229
|
const f = failure(res.status, (await res.text()).slice(0, 1 << 20))
|
|
1190
1230
|
return errorResponse(f.status, f.message)
|
|
1191
1231
|
}
|
|
1192
|
-
return kept(await reply(events(res.body, model, budget), model, req.stream === true))
|
|
1232
|
+
return kept(await reply(events(res.body, model, budget), model, req.stream === true, toolNames(req)))
|
|
1193
1233
|
}
|
|
1194
1234
|
|
|
1195
1235
|
// ---- signing in ----------------------------------------------------------------------
|
|
@@ -1453,4 +1493,4 @@ export async function KiroAuthPlugin({ client } = {}) {
|
|
|
1453
1493
|
}
|
|
1454
1494
|
|
|
1455
1495
|
// for tests
|
|
1456
|
-
export const _internal = { generate, refresh, usageOf, buildKiro, events, reply, failure, toolID, thinking, readCLI, readIDE, regionOf, planName, frames }
|
|
1496
|
+
export const _internal = { generate, refresh, usageOf, buildKiro, events, reply, failure, toolID, toolName, toolNames, thinking, readCLI, readIDE, regionOf, planName, frames }
|