@sunerpy/opencode-kiro-auth 0.4.2 → 0.4.3

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 CHANGED
@@ -192,6 +192,12 @@ Details and the full JSON example: [docs/MODELS.md](docs/MODELS.md).
192
192
  > `kiro.json` instead. See
193
193
  > [Reasoning effort](docs/CONFIGURATION.md#reasoning-effort) for details.
194
194
 
195
+ > **Note:** Reasoning-capable Kiro models (Claude Opus 4.x and other
196
+ > reasoning-capable models) stream their chain-of-thought as a separate
197
+ > event, which the plugin surfaces as OpenCode's own reasoning block — shown
198
+ > as "Thought: `<duration>`" above the final reply. No config needed. See
199
+ > [Reasoning display](docs/CONFIGURATION.md#reasoning-display) for details.
200
+
195
201
  ## Troubleshooting
196
202
 
197
203
  Common issues — 403/AccessDeniedException with IAM Identity Center, "No
@@ -84,12 +84,16 @@ export class ResponseHandler {
84
84
  async handleSdkNonStreaming(sdkResponse, model, conversationId) {
85
85
  // For non-streaming SDK responses, collect all events
86
86
  let content = '';
87
+ let reasoningContent = '';
87
88
  const toolCalls = [];
88
89
  let inputTokens = 0;
89
90
  let outputTokens = 0;
90
91
  const eventStream = sdkResponse.generateAssistantResponseResponse;
91
92
  if (eventStream) {
92
93
  for await (const event of eventStream) {
94
+ if (event.reasoningContentEvent?.text) {
95
+ reasoningContent += event.reasoningContentEvent.text;
96
+ }
93
97
  if (event.assistantResponseEvent?.content) {
94
98
  content += event.assistantResponseEvent.content;
95
99
  }
@@ -102,6 +106,10 @@ export class ResponseHandler {
102
106
  }
103
107
  }
104
108
  }
109
+ const message = { role: 'assistant', content };
110
+ if (reasoningContent) {
111
+ message.reasoning_content = reasoningContent;
112
+ }
105
113
  const oai = {
106
114
  id: conversationId,
107
115
  object: 'chat.completion',
@@ -110,7 +118,7 @@ export class ResponseHandler {
110
118
  choices: [
111
119
  {
112
120
  index: 0,
113
- message: { role: 'assistant', content },
121
+ message,
114
122
  finish_reason: toolCalls.length > 0 ? 'tool_calls' : 'stop'
115
123
  }
116
124
  ],
@@ -24,16 +24,53 @@ export async function* transformSdkStream(sdkResponse, model, conversationId) {
24
24
  let contextUsagePercentage = null;
25
25
  const toolCalls = [];
26
26
  let currentToolCall = null;
27
+ // Probe (opus-4.8): reasoning streams via `reasoningContentEvent{text,signature}` as a
28
+ // contiguous run BEFORE `assistantResponseEvent.content`; no `<thinking>` tags emitted.
29
+ // signature is metadata and ignored for rendering.
30
+ let reasoningStarted = false;
31
+ let reasoningClosed = false;
27
32
  const eventStream = sdkResponse.generateAssistantResponseResponse;
28
33
  if (!eventStream) {
29
34
  throw new Error('SDK response has no event stream');
30
35
  }
31
36
  try {
32
37
  for await (const event of eventStream) {
38
+ if (event.reasoningContentEvent?.text) {
39
+ const reasoningText = event.reasoningContentEvent.text;
40
+ if (reasoningClosed) {
41
+ // Defensive, normally unreached (probe: reasoning is contiguous-before-text).
42
+ // The stopped thinking index cannot be reused, so open a fresh one.
43
+ streamState.thinkingBlockIndex = null;
44
+ reasoningClosed = false;
45
+ }
46
+ reasoningStarted = true;
47
+ for (const ev of createThinkingDeltaEvents(reasoningText, streamState)) {
48
+ const _c = convertToOpenAI(ev, conversationId, model);
49
+ if (_c !== null)
50
+ yield _c;
51
+ }
52
+ continue;
53
+ }
33
54
  if (event.assistantResponseEvent?.content) {
34
55
  const text = event.assistantResponseEvent.content;
35
56
  totalContent += text;
36
57
  textOnlyContent += text;
58
+ if (reasoningStarted && !reasoningClosed) {
59
+ for (const ev of stopBlock(streamState.thinkingBlockIndex, streamState)) {
60
+ const _c = convertToOpenAI(ev, conversationId, model);
61
+ if (_c !== null)
62
+ yield _c;
63
+ }
64
+ reasoningClosed = true;
65
+ }
66
+ if (reasoningStarted) {
67
+ for (const ev of createTextDeltaEvents(text, streamState)) {
68
+ const _c = convertToOpenAI(ev, conversationId, model);
69
+ if (_c !== null)
70
+ yield _c;
71
+ }
72
+ continue;
73
+ }
37
74
  if (!thinkingRequested) {
38
75
  for (const ev of createTextDeltaEvents(text, streamState)) {
39
76
  {
@@ -151,6 +188,15 @@ export async function* transformSdkStream(sdkResponse, model, conversationId) {
151
188
  toolCalls.push(currentToolCall);
152
189
  currentToolCall = null;
153
190
  }
191
+ // Reasoning-only responses (reasoning but no reply text): close the thinking block.
192
+ if (reasoningStarted && !reasoningClosed) {
193
+ for (const ev of stopBlock(streamState.thinkingBlockIndex, streamState)) {
194
+ const _c = convertToOpenAI(ev, conversationId, model);
195
+ if (_c !== null)
196
+ yield _c;
197
+ }
198
+ reasoningClosed = true;
199
+ }
154
200
  if (thinkingRequested && streamState.buffer) {
155
201
  if (streamState.inThinking) {
156
202
  for (const ev of createThinkingDeltaEvents(streamState.buffer, streamState)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sunerpy/opencode-kiro-auth",
3
- "version": "0.4.2",
3
+ "version": "0.4.3",
4
4
  "description": "OpenCode plugin for AWS Kiro (CodeWhisperer) providing access to Claude models",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",