@magpie-community/opencode-kiro-auth 0.1.21 → 0.1.22
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 +9 -0
- package/index.mjs +64 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -108,6 +108,10 @@ request:
|
|
|
108
108
|
profile ARN names.
|
|
109
109
|
- It turns the request into a Kiro conversation:
|
|
110
110
|
- The system prompt goes at the head of the first message.
|
|
111
|
+
- System messages that end the conversation (Claude Code's environment
|
|
112
|
+
context) are sent as a turn before the question, answered by Kiro IDE's
|
|
113
|
+
"Understood.", so the question is the message answered (#538). After
|
|
114
|
+
tool results they stay with them.
|
|
111
115
|
- Tool calls and results are paired: an unanswered call gets an error
|
|
112
116
|
result, and a result longer than 250,000 characters is cut.
|
|
113
117
|
- Tool ids Kiro wouldn't take are rewritten. A tool name over 64
|
|
@@ -136,6 +140,11 @@ request:
|
|
|
136
140
|
the prompt, with a budget: low 10k, medium 20k, high 30k, xhigh and max
|
|
137
141
|
50k (as magpie's built-in Kiro: #120). The
|
|
138
142
|
`<thinking>` block of the reply comes back as thinking.
|
|
143
|
+
A model whose Kiro catalog lists effort levels with adaptive thinking
|
|
144
|
+
(`additionalModelRequestFieldsSchema`) is sent the level instead, as Kiro
|
|
145
|
+
IDE sends it: `additionalModelRequestFields` with `thinking.type:
|
|
146
|
+
"adaptive"` and `output_config.effort` (or `reasoning.effort`), and no
|
|
147
|
+
budget. So xhigh and max stay apart there (#538).
|
|
139
148
|
- Anthropic's hosted web search is answered with Kiro's own web search
|
|
140
149
|
(see [Web search](#web-search)).
|
|
141
150
|
- Kiro's failures keep their meaning:
|
package/index.mjs
CHANGED
|
@@ -574,6 +574,24 @@ function account(client) {
|
|
|
574
574
|
// ---- models ----------------------------------------------------------------------
|
|
575
575
|
|
|
576
576
|
const windows = new Map() // a model's context, as Kiro last listed it
|
|
577
|
+
const natives = new Map() // a model's effort levels sent as fields, as Kiro last listed them (nativeOf)
|
|
578
|
+
|
|
579
|
+
// nativeOf is what a model's additionalModelRequestFieldsSchema in Kiro's
|
|
580
|
+
// list offers, read as Kiro IDE reads it: the effort levels in the enum of
|
|
581
|
+
// output_config's (or reasoning's) effort, and whether thinking.type may be
|
|
582
|
+
// "adaptive". A model offering both is sent the caller's effort in
|
|
583
|
+
// additionalModelRequestFields, as the IDE sends it; any other keeps the
|
|
584
|
+
// <max_thinking_length> budget (#538).
|
|
585
|
+
function nativeOf(s) {
|
|
586
|
+
if (!s || typeof s !== "object" || Array.isArray(s)) return undefined
|
|
587
|
+
const types = s.properties?.thinking?.properties?.type?.enum
|
|
588
|
+
if (!Array.isArray(types) || !types.includes("adaptive")) return undefined
|
|
589
|
+
for (const path of ["output_config", "reasoning"]) {
|
|
590
|
+
const levels = s.properties?.[path]?.properties?.effort?.enum
|
|
591
|
+
if (Array.isArray(levels) && levels.length) return { path, levels }
|
|
592
|
+
}
|
|
593
|
+
return undefined
|
|
594
|
+
}
|
|
577
595
|
|
|
578
596
|
const thinks = (id) => /claude/i.test(id) || id === "auto"
|
|
579
597
|
// the levels a thinking model offers, as the built-in thinks them (xhigh as
|
|
@@ -653,6 +671,7 @@ async function listModels(a) {
|
|
|
653
671
|
}
|
|
654
672
|
if (!list.length) throw new Error("Kiro listed no models")
|
|
655
673
|
for (const m of list) windows.set(m.id, m.context)
|
|
674
|
+
for (const m of out?.models ?? []) if (m?.modelId) natives.set(m.modelId, nativeOf(m.additionalModelRequestFieldsSchema))
|
|
656
675
|
return list
|
|
657
676
|
}
|
|
658
677
|
|
|
@@ -834,6 +853,17 @@ function thinking(req, model) {
|
|
|
834
853
|
return 20000
|
|
835
854
|
}
|
|
836
855
|
|
|
856
|
+
// nativeFields is the additionalModelRequestFields a thinking request is
|
|
857
|
+
// sent with when Kiro's list says the model takes its effort as a field:
|
|
858
|
+
// adaptive thinking at the caller's level, so xhigh and max reach the model
|
|
859
|
+
// as two levels rather than one 50000 budget (#538). undefined otherwise.
|
|
860
|
+
function nativeFields(req, model) {
|
|
861
|
+
const n = natives.get(model)
|
|
862
|
+
const effort = req.output_config?.effort
|
|
863
|
+
if (!n || typeof effort !== "string" || !n.levels.includes(effort) || !thinking(req, model)) return undefined
|
|
864
|
+
return { thinking: { type: "adaptive" }, [n.path]: { effort } }
|
|
865
|
+
}
|
|
866
|
+
|
|
837
867
|
// formatText is the structured output a request asks for, said in words:
|
|
838
868
|
// Anthropic's output_config.format (or the AI SDK's output_format) with a
|
|
839
869
|
// JSON schema, "" when it asks for none. A JSON object with no schema
|
|
@@ -872,6 +902,34 @@ async function kiroBody(req, model, profile, budget) {
|
|
|
872
902
|
return JSON.stringify(await fitImages(kiroRequest(req, model, profile, budget)))
|
|
873
903
|
}
|
|
874
904
|
|
|
905
|
+
// UNDERSTOOD is the reply Kiro IDE puts in its history where a turn has
|
|
906
|
+
// none of its own, before the message being answered
|
|
907
|
+
const UNDERSTOOD = "Understood."
|
|
908
|
+
|
|
909
|
+
// contextFirst is a conversation that ends in system messages (Claude
|
|
910
|
+
// Code's environment context, sent after the user's question) with that
|
|
911
|
+
// context said first: a turn of its own, answered by Kiro IDE's
|
|
912
|
+
// placeholder, before the question, which stays the message being
|
|
913
|
+
// answered rather than the head of "question, then context" (#538). The
|
|
914
|
+
// instructions' own field isn't used: Kiro refuses it ("systemPrompt field
|
|
915
|
+
// is not enabled for this user"). A question carrying tool results, or
|
|
916
|
+
// following tool calls, keeps the context in it as before, so no call is
|
|
917
|
+
// parted from its result.
|
|
918
|
+
function contextFirst(messages) {
|
|
919
|
+
let end = messages.length
|
|
920
|
+
while (end > 0 && messages[end - 1]?.role === "system") end--
|
|
921
|
+
if (end === messages.length) return messages
|
|
922
|
+
let start = end
|
|
923
|
+
while (start > 0 && messages[start - 1]?.role === "user") start--
|
|
924
|
+
const parts = (m) => (typeof m?.content === "string" ? [{ type: "text", text: m.content }] : Array.isArray(m?.content) ? m.content : [])
|
|
925
|
+
const context = messages.slice(end)
|
|
926
|
+
if (start === end || !context.some((m) => parts(m).some((p) => p?.type !== "text" || p.text))) return messages
|
|
927
|
+
const turn = messages.slice(start, end)
|
|
928
|
+
if (turn.some((m) => parts(m).some((p) => p?.type === "tool_result"))) return messages
|
|
929
|
+
if (parts(messages[start - 1]).some((p) => p?.type === "tool_use" || p?.type === "server_tool_use" || p?.type === "web_search_tool_result")) return messages
|
|
930
|
+
return [...messages.slice(0, start), ...context.map((m) => ({ ...m, role: "user" })), { role: "assistant", content: UNDERSTOOD }, ...turn]
|
|
931
|
+
}
|
|
932
|
+
|
|
875
933
|
function kiroRequest(req, model, profile, budget) {
|
|
876
934
|
const entries = []
|
|
877
935
|
// the messages the caller marked for its prompt cache (cache_control),
|
|
@@ -882,7 +940,7 @@ function kiroRequest(req, model, profile, budget) {
|
|
|
882
940
|
}
|
|
883
941
|
const user = () => ({ content: "", modelId: model, origin: "KIRO_CLI" })
|
|
884
942
|
const resultsOnly = new WeakSet() // the messages made to carry a reply's web search results
|
|
885
|
-
for (const m of req.messages ?? []) {
|
|
943
|
+
for (const m of contextFirst(req.messages ?? [])) {
|
|
886
944
|
const parts = typeof m.content === "string" ? [{ type: "text", text: m.content }] : m.content ?? []
|
|
887
945
|
const texts = []
|
|
888
946
|
if (m.role === "assistant") {
|
|
@@ -1013,7 +1071,9 @@ function kiroRequest(req, model, profile, budget) {
|
|
|
1013
1071
|
// end of the instructions, as magpie's built-in tells it (inSystem)
|
|
1014
1072
|
const format = formatText(req)
|
|
1015
1073
|
if (format) system = system ? system + "\n\n" + format : format
|
|
1016
|
-
|
|
1074
|
+
// a level Kiro takes as a field is sent as one, not also as a budget
|
|
1075
|
+
const native = budget ? nativeFields(req, model) : undefined
|
|
1076
|
+
if (budget && !native) system = `<thinking_mode>enabled</thinking_mode><max_thinking_length>${budget}</max_thinking_length>` + (system ? "\n" + system : "")
|
|
1017
1077
|
if (system) entries[0].userInputMessage.content = system + "\n\n" + entries[0].userInputMessage.content
|
|
1018
1078
|
if (Array.isArray(req.system)) mark(entries[0].userInputMessage, req.system)
|
|
1019
1079
|
|
|
@@ -1063,6 +1123,7 @@ function kiroRequest(req, model, profile, budget) {
|
|
|
1063
1123
|
if (entries.length > 1) state.history = entries.slice(0, -1)
|
|
1064
1124
|
const out = { conversationState: state, agentMode: "vibe" }
|
|
1065
1125
|
if (profile) out.profileArn = profile
|
|
1126
|
+
if (native) out.additionalModelRequestFields = native
|
|
1066
1127
|
return out
|
|
1067
1128
|
}
|
|
1068
1129
|
|
|
@@ -2309,4 +2370,4 @@ export async function KiroAuthPlugin({ client } = {}) {
|
|
|
2309
2370
|
}
|
|
2310
2371
|
|
|
2311
2372
|
// for tests
|
|
2312
|
-
export const _internal = { generate, refresh, usageOf, buildKiro, kiroBody, IMAGE_LIMIT, events, reply, failure, toolID, toolName, toolNames, thinking, configModel, runtimeModel, readCLI, readIDE, regionOf, planName, frames }
|
|
2373
|
+
export const _internal = { generate, refresh, usageOf, buildKiro, kiroBody, IMAGE_LIMIT, events, reply, failure, toolID, toolName, toolNames, thinking, nativeFields, listModels, contextFirst, configModel, runtimeModel, readCLI, readIDE, regionOf, planName, frames }
|