@bogyie/opencode-kiro-plugin 0.2.9 → 0.2.10

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.
@@ -36,6 +36,15 @@ export function toKiroRestPayload(request, profileArn) {
36
36
  ? {
37
37
  assistantResponseMessage: {
38
38
  content: turn.content,
39
+ ...(turn.toolUses && turn.toolUses.length > 0
40
+ ? {
41
+ toolUses: turn.toolUses.map((toolUse) => ({
42
+ toolUseId: toolUse.toolUseId,
43
+ name: toolUse.name,
44
+ input: toolUse.input,
45
+ })),
46
+ }
47
+ : {}),
39
48
  },
40
49
  }
41
50
  : {
@@ -70,6 +70,15 @@ export function toGenerateAssistantResponseInput(request, options = {}) {
70
70
  ? {
71
71
  assistantResponseMessage: {
72
72
  content: turn.content,
73
+ ...(turn.toolUses && turn.toolUses.length > 0
74
+ ? {
75
+ toolUses: turn.toolUses.map((toolUse) => ({
76
+ toolUseId: toolUse.toolUseId,
77
+ name: toolUse.name,
78
+ input: toolUse.input,
79
+ })),
80
+ }
81
+ : {}),
73
82
  },
74
83
  }
75
84
  : {
@@ -78,6 +78,12 @@ export interface KiroDocumentBlock {
78
78
  export interface KiroConversationTurn {
79
79
  readonly role: "user" | "assistant" | "tool";
80
80
  readonly content: string;
81
+ readonly toolUses?: ReadonlyArray<KiroConversationToolUse>;
82
+ }
83
+ export interface KiroConversationToolUse {
84
+ readonly toolUseId: string;
85
+ readonly name: string;
86
+ readonly input: unknown;
81
87
  }
82
88
  export interface KiroToolSpec {
83
89
  readonly name: string;
@@ -108,18 +108,6 @@ function toolSpecs(tools) {
108
108
  inputSchema: tool.function.parameters ?? { type: "object", properties: {} },
109
109
  }));
110
110
  }
111
- function requestedToolCallIds(messages) {
112
- const ids = new Set();
113
- for (const message of messages) {
114
- if (message.role !== "assistant")
115
- continue;
116
- for (const toolCall of message.tool_calls ?? []) {
117
- if (toolCall.id)
118
- ids.add(toolCall.id);
119
- }
120
- }
121
- return ids;
122
- }
123
111
  function toolNameById(messages) {
124
112
  const names = new Map();
125
113
  for (const message of messages) {
@@ -133,13 +121,27 @@ function toolNameById(messages) {
133
121
  return names;
134
122
  }
135
123
  function toolResults(messages) {
136
- const requested = requestedToolCallIds(messages);
137
124
  const names = toolNameById(messages);
125
+ const nonSystemMessages = messages.filter((message) => message.role !== "system");
126
+ const trailingTools = [];
127
+ let index = nonSystemMessages.length - 1;
128
+ while (index >= 0 && nonSystemMessages[index]?.role === "tool") {
129
+ const message = nonSystemMessages[index];
130
+ if (message)
131
+ trailingTools.unshift(message);
132
+ index -= 1;
133
+ }
134
+ if (trailingTools.length === 0)
135
+ return [];
136
+ const previous = nonSystemMessages[index];
137
+ if (!previous || previous.role !== "assistant")
138
+ return [];
139
+ const activeToolIds = new Set((previous.tool_calls ?? []).map((toolCall) => toolCall.id).filter((id) => Boolean(id)));
140
+ if (activeToolIds.size === 0)
141
+ return [];
138
142
  const results = new Map();
139
- for (const message of messages) {
140
- if (message.role !== "tool" || !message.tool_call_id)
141
- continue;
142
- if (requested.size > 0 && !requested.has(message.tool_call_id))
143
+ for (const message of trailingTools) {
144
+ if (!message.tool_call_id || !activeToolIds.has(message.tool_call_id))
143
145
  continue;
144
146
  const toolName = message.name ?? names.get(message.tool_call_id);
145
147
  results.set(message.tool_call_id, {
@@ -150,6 +152,40 @@ function toolResults(messages) {
150
152
  }
151
153
  return [...results.values()];
152
154
  }
155
+ function trailingToolMessageIndexes(messages) {
156
+ const indexes = new Set();
157
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
158
+ const message = messages[index];
159
+ if (!message || message.role === "system")
160
+ continue;
161
+ if (message.role !== "tool")
162
+ break;
163
+ indexes.add(index);
164
+ }
165
+ return indexes;
166
+ }
167
+ function toolUses(message) {
168
+ return (message.tool_calls ?? [])
169
+ .map((toolCall) => {
170
+ if (!toolCall.id || !toolCall.function?.name)
171
+ return undefined;
172
+ let input = {};
173
+ if (toolCall.function.arguments) {
174
+ try {
175
+ input = JSON.parse(toolCall.function.arguments);
176
+ }
177
+ catch {
178
+ input = toolCall.function.arguments;
179
+ }
180
+ }
181
+ return {
182
+ toolUseId: toolCall.id,
183
+ name: toolCall.function.name,
184
+ input,
185
+ };
186
+ })
187
+ .filter((item) => item !== undefined);
188
+ }
153
189
  function finiteNumber(value) {
154
190
  return typeof value === "number" && Number.isFinite(value) ? value : undefined;
155
191
  }
@@ -184,28 +220,41 @@ export async function readOpenAIRequest(input, init) {
184
220
  }
185
221
  export function toKiroGenerateRequest(request, resolver) {
186
222
  const resolved = resolver.resolve(request.model);
223
+ const activeToolResults = toolResults(request.messages);
224
+ const activeTrailingToolIndexes = activeToolResults.length > 0 ? trailingToolMessageIndexes(request.messages) : new Set();
187
225
  const system = request.messages
188
226
  .filter((message) => message.role === "system")
189
227
  .map((message) => textFromContent(message.content))
190
228
  .filter(Boolean)
191
229
  .join("\n\n");
192
- const turns = request.messages
193
- .filter((message) => message.role !== "system")
194
- .map((message) => {
230
+ const turns = [];
231
+ for (const [index, message] of request.messages.entries()) {
232
+ if (message.role === "system" || activeTrailingToolIndexes.has(index))
233
+ continue;
195
234
  const content = textFromContent(message.content);
196
- return content ? { role: message.role, content } : undefined;
197
- })
198
- .filter((item) => item !== undefined);
199
- const current = turns.at(-1);
200
- const history = turns.slice(0, -1);
201
- const currentMessage = request.messages.filter((message) => message.role !== "system").at(-1);
235
+ const assistantToolUses = message.role === "assistant" ? toolUses(message) : [];
236
+ if (!content && assistantToolUses.length === 0)
237
+ continue;
238
+ turns.push({
239
+ role: message.role,
240
+ content,
241
+ ...(assistantToolUses.length > 0 ? { toolUses: assistantToolUses } : {}),
242
+ });
243
+ }
244
+ const current = activeToolResults.length > 0 ? undefined : turns.at(-1);
245
+ const history = activeToolResults.length > 0 ? turns : turns.slice(0, -1);
246
+ const currentMessage = request.messages
247
+ .map((message, index) => ({ message, index }))
248
+ .filter(({ message, index }) => message.role !== "system" && !activeTrailingToolIndexes.has(index))
249
+ .map(({ message }) => message)
250
+ .at(-1);
202
251
  const media = mediaFromContent(currentMessage?.content);
203
252
  return {
204
253
  modelId: resolved.internalID,
205
254
  prompt: current?.content ?? "",
206
255
  history,
207
256
  tools: toolSpecs(request.tools),
208
- toolResults: toolResults(request.messages),
257
+ toolResults: activeToolResults,
209
258
  images: media.images,
210
259
  documents: media.documents,
211
260
  modelOptions: modelOptions(request),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bogyie/opencode-kiro-plugin",
3
- "version": "0.2.9",
3
+ "version": "0.2.10",
4
4
  "description": "OpenCode plugin for using Kiro as a provider adapter",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",