@bogyie/opencode-kiro-plugin 0.2.9 → 0.2.11

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.
@@ -15,6 +15,12 @@ function conversationId(request) {
15
15
  return `opencode-${hash.toString(16)}-${Date.now().toString(36)}`;
16
16
  }
17
17
  export function toKiroRestPayload(request, profileArn) {
18
+ const toolResults = request.toolResults.map((item) => ({
19
+ toolUseId: item.toolUseId,
20
+ content: [{ text: item.content }],
21
+ status: "success",
22
+ ...(item.toolName ? { toolName: item.toolName } : {}),
23
+ }));
18
24
  const history = [
19
25
  ...(request.system
20
26
  ? [
@@ -36,6 +42,15 @@ export function toKiroRestPayload(request, profileArn) {
36
42
  ? {
37
43
  assistantResponseMessage: {
38
44
  content: turn.content,
45
+ ...(turn.toolUses && turn.toolUses.length > 0
46
+ ? {
47
+ toolUses: turn.toolUses.map((toolUse) => ({
48
+ toolUseId: toolUse.toolUseId,
49
+ name: toolUse.name,
50
+ input: toolUse.input,
51
+ })),
52
+ }
53
+ : {}),
39
54
  },
40
55
  }
41
56
  : {
@@ -45,6 +60,20 @@ export function toKiroRestPayload(request, profileArn) {
45
60
  origin: "AI_EDITOR",
46
61
  },
47
62
  }),
63
+ ...(toolResults.length > 0
64
+ ? [
65
+ {
66
+ userInputMessage: {
67
+ content: "",
68
+ modelId: request.modelId,
69
+ origin: "AI_EDITOR",
70
+ userInputMessageContext: {
71
+ toolResults,
72
+ },
73
+ },
74
+ },
75
+ ]
76
+ : []),
48
77
  ];
49
78
  const tools = request.tools.map((item) => ({
50
79
  toolSpecification: {
@@ -53,16 +82,9 @@ export function toKiroRestPayload(request, profileArn) {
53
82
  inputSchema: { json: item.inputSchema },
54
83
  },
55
84
  }));
56
- const toolResults = request.toolResults.map((item) => ({
57
- toolUseId: item.toolUseId,
58
- content: [{ text: item.content }],
59
- status: "success",
60
- ...(item.toolName ? { toolName: item.toolName } : {}),
61
- }));
62
- const userInputMessageContext = tools.length > 0 || toolResults.length > 0
85
+ const userInputMessageContext = tools.length > 0
63
86
  ? {
64
87
  ...(tools.length > 0 ? { tools } : {}),
65
- ...(toolResults.length > 0 ? { toolResults } : {}),
66
88
  }
67
89
  : undefined;
68
90
  const inferenceConfig = request.modelOptions.maxTokens !== undefined || request.modelOptions.temperature !== undefined
@@ -49,6 +49,12 @@ export function createCodeWhispererClient(options) {
49
49
  export function toGenerateAssistantResponseInput(request, options = {}) {
50
50
  const content = request.prompt;
51
51
  const modelFields = additionalModelRequestFields(request);
52
+ const toolResults = request.toolResults.map((item) => ({
53
+ toolUseId: item.toolUseId,
54
+ content: [{ text: item.content }],
55
+ status: "SUCCESS",
56
+ ...(item.toolName ? { toolName: item.toolName } : {}),
57
+ }));
52
58
  return {
53
59
  ...(options.profileArn ? { profileArn: options.profileArn } : {}),
54
60
  agentMode: options.agentMode ?? DEFAULT_AGENT_MODE,
@@ -70,6 +76,15 @@ export function toGenerateAssistantResponseInput(request, options = {}) {
70
76
  ? {
71
77
  assistantResponseMessage: {
72
78
  content: turn.content,
79
+ ...(turn.toolUses && turn.toolUses.length > 0
80
+ ? {
81
+ toolUses: turn.toolUses.map((toolUse) => ({
82
+ toolUseId: toolUse.toolUseId,
83
+ name: toolUse.name,
84
+ input: toolUse.input,
85
+ })),
86
+ }
87
+ : {}),
73
88
  },
74
89
  }
75
90
  : {
@@ -78,6 +93,19 @@ export function toGenerateAssistantResponseInput(request, options = {}) {
78
93
  origin: "AI_EDITOR",
79
94
  },
80
95
  }),
96
+ ...(toolResults.length > 0
97
+ ? [
98
+ {
99
+ userInputMessage: {
100
+ content: "",
101
+ origin: "AI_EDITOR",
102
+ userInputMessageContext: {
103
+ toolResults,
104
+ },
105
+ },
106
+ },
107
+ ]
108
+ : []),
81
109
  ],
82
110
  currentMessage: {
83
111
  userInputMessage: {
@@ -101,7 +129,7 @@ export function toGenerateAssistantResponseInput(request, options = {}) {
101
129
  })),
102
130
  }
103
131
  : {}),
104
- userInputMessageContext: request.tools.length > 0 || request.toolResults.length > 0
132
+ userInputMessageContext: request.tools.length > 0
105
133
  ? {
106
134
  ...(request.tools.length > 0
107
135
  ? {
@@ -114,16 +142,6 @@ export function toGenerateAssistantResponseInput(request, options = {}) {
114
142
  })),
115
143
  }
116
144
  : {}),
117
- ...(request.toolResults.length > 0
118
- ? {
119
- toolResults: request.toolResults.map((item) => ({
120
- toolUseId: item.toolUseId,
121
- content: [{ text: item.content }],
122
- status: "SUCCESS",
123
- ...(item.toolName ? { toolName: item.toolName } : {}),
124
- })),
125
- }
126
- : {}),
127
145
  }
128
146
  : undefined,
129
147
  },
@@ -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,51 @@ 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 previousAssistantIndexForTrailingTools(messages, trailingIndexes) {
168
+ if (trailingIndexes.size === 0)
169
+ return undefined;
170
+ for (let index = messages.length - 1; index >= 0; index -= 1) {
171
+ const message = messages[index];
172
+ if (!message || message.role === "system" || trailingIndexes.has(index))
173
+ continue;
174
+ return message.role === "assistant" ? index : undefined;
175
+ }
176
+ return undefined;
177
+ }
178
+ function toolUses(message) {
179
+ return (message.tool_calls ?? [])
180
+ .map((toolCall) => {
181
+ if (!toolCall.id || !toolCall.function?.name)
182
+ return undefined;
183
+ let input = {};
184
+ if (toolCall.function.arguments) {
185
+ try {
186
+ input = JSON.parse(toolCall.function.arguments);
187
+ }
188
+ catch {
189
+ input = toolCall.function.arguments;
190
+ }
191
+ }
192
+ return {
193
+ toolUseId: toolCall.id,
194
+ name: toolCall.function.name,
195
+ input,
196
+ };
197
+ })
198
+ .filter((item) => item !== undefined);
199
+ }
153
200
  function finiteNumber(value) {
154
201
  return typeof value === "number" && Number.isFinite(value) ? value : undefined;
155
202
  }
@@ -184,28 +231,42 @@ export async function readOpenAIRequest(input, init) {
184
231
  }
185
232
  export function toKiroGenerateRequest(request, resolver) {
186
233
  const resolved = resolver.resolve(request.model);
234
+ const activeToolResults = toolResults(request.messages);
235
+ const activeTrailingToolIndexes = activeToolResults.length > 0 ? trailingToolMessageIndexes(request.messages) : new Set();
236
+ const activeToolUseAssistantIndex = previousAssistantIndexForTrailingTools(request.messages, activeTrailingToolIndexes);
187
237
  const system = request.messages
188
238
  .filter((message) => message.role === "system")
189
239
  .map((message) => textFromContent(message.content))
190
240
  .filter(Boolean)
191
241
  .join("\n\n");
192
- const turns = request.messages
193
- .filter((message) => message.role !== "system")
194
- .map((message) => {
242
+ const turns = [];
243
+ for (const [index, message] of request.messages.entries()) {
244
+ if (message.role === "system" || activeTrailingToolIndexes.has(index))
245
+ continue;
195
246
  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);
247
+ const assistantToolUses = message.role === "assistant" && index === activeToolUseAssistantIndex ? toolUses(message) : [];
248
+ if (!content && assistantToolUses.length === 0)
249
+ continue;
250
+ turns.push({
251
+ role: message.role,
252
+ content,
253
+ ...(assistantToolUses.length > 0 ? { toolUses: assistantToolUses } : {}),
254
+ });
255
+ }
256
+ const current = activeToolResults.length > 0 ? undefined : turns.at(-1);
257
+ const history = activeToolResults.length > 0 ? turns : turns.slice(0, -1);
258
+ const currentMessage = request.messages
259
+ .map((message, index) => ({ message, index }))
260
+ .filter(({ message, index }) => message.role !== "system" && !activeTrailingToolIndexes.has(index))
261
+ .map(({ message }) => message)
262
+ .at(-1);
202
263
  const media = mediaFromContent(currentMessage?.content);
203
264
  return {
204
265
  modelId: resolved.internalID,
205
266
  prompt: current?.content ?? "",
206
267
  history,
207
268
  tools: toolSpecs(request.tools),
208
- toolResults: toolResults(request.messages),
269
+ toolResults: activeToolResults,
209
270
  images: media.images,
210
271
  documents: media.documents,
211
272
  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.11",
4
4
  "description": "OpenCode plugin for using Kiro as a provider adapter",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",