@x-otto/plugin-otto-wire-protocols 0.1.0-alpha.15 → 0.1.0-alpha.18
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/package.json +5 -5
- package/plugin-dist/meta.json +1 -1
- package/plugin-dist/plugin.cjs +17 -7
- package/src/anthropic-messages.ts +14 -0
- package/src/openai-responses.ts +15 -0
package/package.json
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@x-otto/plugin-otto-wire-protocols",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.18",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Three standard wire protocol implementations (anthropic-messages/openai-responses/openai-completions) — runtime support for provider plugins. Publishable standalone so non-CLI hosts (e.g. desktop apps depending only on @x-otto/coding) can install it without the full @x-otto/cli dependency tree.",
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@anthropic-ai/sdk": "0.88.0",
|
|
8
|
-
"@x-otto/provider": "0.1.0-alpha.
|
|
9
|
-
"@x-otto/
|
|
10
|
-
"@x-otto/plugin": "0.1.0-alpha.
|
|
11
|
-
"@x-otto/
|
|
8
|
+
"@x-otto/provider": "0.1.0-alpha.18",
|
|
9
|
+
"@x-otto/shared": "0.1.0-alpha.18",
|
|
10
|
+
"@x-otto/plugin": "0.1.0-alpha.18",
|
|
11
|
+
"@x-otto/interchange": "0.1.0-alpha.18"
|
|
12
12
|
},
|
|
13
13
|
"type": "module",
|
|
14
14
|
"files": [
|
package/plugin-dist/meta.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"apiVersion":1,"compilerVersion":"0.1.0-alpha.
|
|
1
|
+
{"apiVersion":1,"compilerVersion":"0.1.0-alpha.18","sourceHash":"351f1300a8c8f67cbe2bb9d9bfb16787f280ed3147fad3eda349aa1d5822450a"}
|
package/plugin-dist/plugin.cjs
CHANGED
|
@@ -16615,11 +16615,11 @@ function B2(e8) {
|
|
|
16615
16615
|
}
|
|
16616
16616
|
}
|
|
16617
16617
|
async function* me(e8) {
|
|
16618
|
-
let { url: t6, headers: r4, body: i3, identity: a3, signal: o3, timeout: s3, idleTimeout: c3, onResponse: l2, registeredToolNames: u } = e8, d = L2(), p = (e9 = false) => z2(a3, R3(d, e9), d, d.stopReason), m = false, h = false, g = false, _3, v3 = bt({ url: t6, body: i3, headers: r4, signal: o3, timeout: s3, idleTimeout: c3, onResponse: (e9) => {
|
|
16619
|
-
|
|
16618
|
+
let { url: t6, headers: r4, body: i3, identity: a3, signal: o3, timeout: s3, idleTimeout: c3, onResponse: l2, registeredToolNames: u } = e8, d = L2(), p = (e9 = false) => z2(a3, R3(d, e9), d, d.stopReason), m = false, h = false, g = false, _3 = false, v3, y3 = bt({ url: t6, body: i3, headers: r4, signal: o3, timeout: s3, idleTimeout: c3, onResponse: (e9) => {
|
|
16619
|
+
v3 = e9, l2?.(e9);
|
|
16620
16620
|
} });
|
|
16621
16621
|
try {
|
|
16622
|
-
for await (let e9 of
|
|
16622
|
+
for await (let e9 of y3) {
|
|
16623
16623
|
if (e9.data === `[DONE]`) break;
|
|
16624
16624
|
let t7;
|
|
16625
16625
|
try {
|
|
@@ -16638,7 +16638,7 @@ async function* me(e8) {
|
|
|
16638
16638
|
let r5 = t7.choices?.[0];
|
|
16639
16639
|
if (!r5) continue;
|
|
16640
16640
|
let i4 = r5.delta;
|
|
16641
|
-
if (m || (m = true, yield { type: `start`, partial: p() }), r5.finish_reason && (d.stopReason = B2(r5.finish_reason)), !i4) continue;
|
|
16641
|
+
if (m || (m = true, yield { type: `start`, partial: p() }), r5.finish_reason && (_3 = true, d.stopReason = B2(r5.finish_reason)), !i4) continue;
|
|
16642
16642
|
if (i4.content) {
|
|
16643
16643
|
let e10 = i4.content;
|
|
16644
16644
|
h || (h = true, yield { type: `text_start`, index: 0, partial: p() }), d.textContent += e10, yield { type: `text_delta`, index: 0, delta: e10, partial: p() };
|
|
@@ -16656,7 +16656,7 @@ async function* me(e8) {
|
|
|
16656
16656
|
}
|
|
16657
16657
|
g && (yield { type: `thinking_end`, index: 0, content: d.thinkingText, partial: p() }), h && (yield { type: `text_end`, index: 0, content: d.textContent, partial: p() });
|
|
16658
16658
|
for (let [e9, t7] of d.toolCalls) yield { type: `tool_call_end`, index: e9, toolCall: N2(t7.id, t7.name, t7.argumentsJson), partial: p() };
|
|
16659
|
-
yield { type: `done`, reason: d.stopReason, message: P2(p(true), u ?? /* @__PURE__ */ new Set()), providerUsage: A3(
|
|
16659
|
+
_3 || (d.stopReason = `incomplete`), yield { type: `done`, reason: d.stopReason, message: P2(p(true), u ?? /* @__PURE__ */ new Set()), providerUsage: A3(v3) };
|
|
16660
16660
|
} catch (e9) {
|
|
16661
16661
|
yield { type: `error`, error: e9 instanceof Error ? e9 : new Ce(`Unknown Chat Completions stream error`, { code: `PROVIDER_STREAM_ERROR` }) };
|
|
16662
16662
|
}
|
|
@@ -17021,7 +17021,8 @@ function initStreamState(modelId) {
|
|
|
17021
17021
|
...j3(),
|
|
17022
17022
|
model: modelId,
|
|
17023
17023
|
blocks: /* @__PURE__ */ new Map(),
|
|
17024
|
-
stopReason: "end_turn"
|
|
17024
|
+
stopReason: "end_turn",
|
|
17025
|
+
sawStopReason: false
|
|
17025
17026
|
};
|
|
17026
17027
|
}
|
|
17027
17028
|
function buildAssistantMessage(state, final = false) {
|
|
@@ -17138,6 +17139,7 @@ function dispatchStreamEvent(event, state) {
|
|
|
17138
17139
|
if (event.usage.cache_read_input_tokens != null) {
|
|
17139
17140
|
state.cacheReadTokens = event.usage.cache_read_input_tokens;
|
|
17140
17141
|
}
|
|
17142
|
+
state.sawStopReason = true;
|
|
17141
17143
|
state.stopReason = mapStopReason(event.delta.stop_reason);
|
|
17142
17144
|
return [];
|
|
17143
17145
|
}
|
|
@@ -17291,6 +17293,9 @@ var AnthropicStream = class {
|
|
|
17291
17293
|
if (signal.aborted) {
|
|
17292
17294
|
throw new Anthropic.APIUserAbortError();
|
|
17293
17295
|
}
|
|
17296
|
+
if (!state.sawStopReason) {
|
|
17297
|
+
state.stopReason = "incomplete";
|
|
17298
|
+
}
|
|
17294
17299
|
const providerUsage = extractProviderUsageFromHeaders(response?.headers);
|
|
17295
17300
|
const doneMessage = buildAssistantMessage(state, true);
|
|
17296
17301
|
yield {
|
|
@@ -17483,7 +17488,8 @@ function initStreamState2(model) {
|
|
|
17483
17488
|
...j3(),
|
|
17484
17489
|
model,
|
|
17485
17490
|
blocks: /* @__PURE__ */ new Map(),
|
|
17486
|
-
stopReason: "end_turn"
|
|
17491
|
+
stopReason: "end_turn",
|
|
17492
|
+
sawStopReason: false
|
|
17487
17493
|
};
|
|
17488
17494
|
}
|
|
17489
17495
|
function buildAssistantMessage2(state, final = false) {
|
|
@@ -17549,6 +17555,7 @@ function dispatchResponsesSSEEvent(type, data, state) {
|
|
|
17549
17555
|
}
|
|
17550
17556
|
case "response.completed":
|
|
17551
17557
|
case "response.incomplete": {
|
|
17558
|
+
state.sawStopReason = true;
|
|
17552
17559
|
const response = data.response;
|
|
17553
17560
|
const usage = response?.usage;
|
|
17554
17561
|
if (usage) {
|
|
@@ -17722,6 +17729,9 @@ var OpenAIResponsesStream = class {
|
|
|
17722
17729
|
};
|
|
17723
17730
|
}
|
|
17724
17731
|
}
|
|
17732
|
+
if (!state.sawStopReason) {
|
|
17733
|
+
state.stopReason = "incomplete";
|
|
17734
|
+
}
|
|
17725
17735
|
yield {
|
|
17726
17736
|
type: "done",
|
|
17727
17737
|
reason: state.stopReason,
|
|
@@ -445,6 +445,13 @@ interface AnthropicStreamState extends StreamUsage {
|
|
|
445
445
|
model: string
|
|
446
446
|
blocks: Map<number, StreamBlock>
|
|
447
447
|
stopReason: StopReason
|
|
448
|
+
/**
|
|
449
|
+
* RFC-421(新发现,会话 fe6bc77e 事故复盘):是否收到过 `message_delta`(唯一携带
|
|
450
|
+
* `stop_reason` 的事件)。流因 `message_stop` 或对端正常关闭而结束、但从未见过
|
|
451
|
+
* `message_delta` 时,`stopReason` 会悄悄停在默认值 'end_turn'——见
|
|
452
|
+
* chat-completions-stream.ts 同名字段注释,判据与根因完全一致(provider-agnostic)。
|
|
453
|
+
*/
|
|
454
|
+
sawStopReason: boolean
|
|
448
455
|
}
|
|
449
456
|
|
|
450
457
|
function initStreamState(modelId: string): AnthropicStreamState {
|
|
@@ -453,6 +460,7 @@ function initStreamState(modelId: string): AnthropicStreamState {
|
|
|
453
460
|
model: modelId,
|
|
454
461
|
blocks: new Map(),
|
|
455
462
|
stopReason: 'end_turn',
|
|
463
|
+
sawStopReason: false,
|
|
456
464
|
}
|
|
457
465
|
}
|
|
458
466
|
|
|
@@ -589,6 +597,7 @@ function dispatchStreamEvent(
|
|
|
589
597
|
if (event.usage.cache_read_input_tokens != null) {
|
|
590
598
|
state.cacheReadTokens = event.usage.cache_read_input_tokens
|
|
591
599
|
}
|
|
600
|
+
state.sawStopReason = true
|
|
592
601
|
state.stopReason = mapStopReason(event.delta.stop_reason)
|
|
593
602
|
return []
|
|
594
603
|
}
|
|
@@ -910,6 +919,11 @@ class AnthropicStream implements ProviderStream {
|
|
|
910
919
|
// 成功路径 usage 快照:仅 Anthropic OAuth 订阅计划的响应带 anthropic-ratelimit-unified-*
|
|
911
920
|
// 头族(API key 走标准 RPM/TPM,headers 里没有该头族 → extractProviderUsageFromHeaders
|
|
912
921
|
// 返回 null,天然实现"API key 不显示")。
|
|
922
|
+
// RFC-421:流正常结束(无 SSE/网络异常)但从未见过 message_delta 的 stop_reason——
|
|
923
|
+
// 诚实标注为 'incomplete' 而非让默认值 'end_turn' 冒充"模型正常说完"。
|
|
924
|
+
if (!state.sawStopReason) {
|
|
925
|
+
state.stopReason = 'incomplete'
|
|
926
|
+
}
|
|
913
927
|
const providerUsage = extractProviderUsageFromHeaders(response?.headers)
|
|
914
928
|
const doneMessage = buildAssistantMessage(state, true)
|
|
915
929
|
yield {
|
package/src/openai-responses.ts
CHANGED
|
@@ -230,6 +230,13 @@ interface ResponsesStreamState extends StreamUsage {
|
|
|
230
230
|
model: Model
|
|
231
231
|
blocks: Map<number, StreamBlock>
|
|
232
232
|
stopReason: StopReason
|
|
233
|
+
/**
|
|
234
|
+
* RFC-421(新发现,会话 fe6bc77e 事故复盘):是否收到过 `response.completed` /
|
|
235
|
+
* `response.incomplete`(唯二携带终态 stopReason 的事件)。流因 `[DONE]` 或对端正常
|
|
236
|
+
* 关闭而结束、但从未见过这两类事件时,`stopReason` 会悄悄停在默认值 'end_turn'——见
|
|
237
|
+
* chat-completions-stream.ts 同名字段注释,判据与根因完全一致(provider-agnostic)。
|
|
238
|
+
*/
|
|
239
|
+
sawStopReason: boolean
|
|
233
240
|
}
|
|
234
241
|
|
|
235
242
|
function ensureBlock(
|
|
@@ -251,6 +258,7 @@ function initStreamState(model: Model): ResponsesStreamState {
|
|
|
251
258
|
model,
|
|
252
259
|
blocks: new Map(),
|
|
253
260
|
stopReason: 'end_turn',
|
|
261
|
+
sawStopReason: false,
|
|
254
262
|
}
|
|
255
263
|
}
|
|
256
264
|
|
|
@@ -333,6 +341,7 @@ function dispatchResponsesSSEEvent(
|
|
|
333
341
|
|
|
334
342
|
case 'response.completed':
|
|
335
343
|
case 'response.incomplete': {
|
|
344
|
+
state.sawStopReason = true
|
|
336
345
|
const response = data.response as Record<string, unknown> | undefined
|
|
337
346
|
const usage = response?.usage as Record<string, unknown> | undefined
|
|
338
347
|
if (usage) {
|
|
@@ -548,6 +557,12 @@ class OpenAIResponsesStream implements ProviderStream {
|
|
|
548
557
|
}
|
|
549
558
|
}
|
|
550
559
|
|
|
560
|
+
// RFC-421:流正常结束(无 SSE/网络异常)但从未见过 response.completed/incomplete——
|
|
561
|
+
// 诚实标注为 'incomplete' 而非让默认值 'end_turn' 冒充"模型正常说完"。
|
|
562
|
+
if (!state.sawStopReason) {
|
|
563
|
+
state.stopReason = 'incomplete'
|
|
564
|
+
}
|
|
565
|
+
|
|
551
566
|
yield {
|
|
552
567
|
type: 'done',
|
|
553
568
|
reason: state.stopReason,
|