dsh-plugin-subscription-oauth 0.12.5 → 0.12.6

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.
@@ -63,6 +63,8 @@ export declare class WorkBuddyAdapter extends LlmAdapter {
63
63
  /** The stored session's fields as the token the request signs with. */
64
64
  private tokenOf;
65
65
  private requestBody;
66
+ /** The system prompt: the caller's, else WorkBuddy's default. */
67
+ private systemPrompt;
66
68
  private toChatMessage;
67
69
  /** Turn a non-2xx into an LlmError, naming WorkBuddy's specific refusals. */
68
70
  private errorOf;
@@ -51,6 +51,40 @@ export const WORKBUDDY_CATALOG = CN_MODELS.map((entry) => {
51
51
  ...efforts === undefined ? {} : { reasoningEfforts: efforts },
52
52
  };
53
53
  });
54
+ /**
55
+ * Words WorkBuddy refuses a chat for ("Illegal API invocation from an unapproved
56
+ * channel"), each with words that say the same and pass. WorkBuddy reads every message,
57
+ * not only the system prompt, and pays no mind to case. Adapted from magpie's workbuddy.
58
+ */
59
+ const FLAGGED = [
60
+ [/x-anthropic-billing-header:[^\n]*\n?/gi, ''],
61
+ [/You are Claude Code, Anthropic['']s official CLI for Claude/gi, "You are Claude Code, Anthropic's CLI for Claude"],
62
+ [/Main branch \(you will usually use this for PRs\)/gi, 'Main branch (usually the base for PRs)'],
63
+ [/(?<!the )Codex CLI is an open source project led by OpenAI\./gi, 'The Codex CLI is an open source project led by OpenAI.'],
64
+ ];
65
+ /** Put FLAGGED's words in place in one message's content. */
66
+ function unflagText(text) {
67
+ let out = text;
68
+ for (const [pattern, replacement] of FLAGGED)
69
+ out = out.replace(pattern, replacement);
70
+ return out;
71
+ }
72
+ /** Apply the FLAGGED filter to every message's content, in place. */
73
+ function unflagMessages(messages) {
74
+ for (let index = messages.length - 1; index >= 0; index--) {
75
+ const message = messages[index];
76
+ if (typeof message.content === 'string') {
77
+ message.content = unflagText(message.content);
78
+ }
79
+ }
80
+ return messages;
81
+ }
82
+ /** 32 hex digits, for the chat ids WorkBuddy's own client makes. */
83
+ function randomHex() {
84
+ const bytes = new Uint8Array(16);
85
+ crypto.getRandomValues(bytes);
86
+ return [...bytes].map((byte) => byte.toString(16).padStart(2, '0')).join('');
87
+ }
54
88
  /** The WorkBuddy China wire adapter serving the `workbuddy` route. */
55
89
  export class WorkBuddyAdapter extends LlmAdapter {
56
90
  options;
@@ -126,16 +160,23 @@ export class WorkBuddyAdapter extends LlmAdapter {
126
160
  const token = this.tokenOf(held.session);
127
161
  const watchdog = idleWatchdog(options.signal, this.options.streamIdleTimeoutMs);
128
162
  try {
163
+ const body = this.requestBody(options);
129
164
  const response = await this.fetchFn(WORKBUDDY_API, {
130
165
  method: 'POST',
131
166
  headers: {
132
167
  'Content-Type': 'application/json',
133
168
  'Accept': 'text/event-stream',
134
169
  ...workbuddyHeaders(token),
170
+ // Name the chat the way WorkBuddy's own client does: without these the gateway
171
+ // counts the request under no client and can cut the stream.
172
+ 'X-Conversation-Message-ID': randomHex(),
173
+ 'X-Request-ID': randomHex(),
135
174
  },
136
- body: JSON.stringify(this.requestBody(options)),
175
+ body: JSON.stringify(body),
137
176
  signal: watchdog.signal,
138
177
  });
178
+ // WorkBuddy refuses a chat mid-stream when the request carries words it filters; a
179
+ // 403/400 here names why, so surface it instead of dying on an empty stream.
139
180
  if (!response.ok || response.body === null) {
140
181
  throw await this.errorOf(response);
141
182
  }
@@ -163,19 +204,34 @@ export class WorkBuddyAdapter extends LlmAdapter {
163
204
  }
164
205
  requestBody(options) {
165
206
  const messages = [];
166
- if (options.system !== undefined && options.system.trim() !== '') {
167
- messages.push({ role: 'system', content: options.system });
168
- }
169
207
  for (const message of options.messages) {
170
208
  messages.push(this.toChatMessage(message));
171
209
  }
210
+ // A chat that doesn't open with a system message is refused: give it WorkBuddy's
211
+ // default one, as its own app does, and take the words WorkBuddy filters (Codex and
212
+ // Claude Code's own) out of every message — WorkBuddy reads them all, whatever role.
213
+ const system = this.systemPrompt(options);
214
+ messages.unshift({ role: 'system', content: system });
172
215
  return {
173
216
  model: options.model,
174
- messages,
217
+ messages: unflagMessages(messages),
175
218
  ...options.maxTokens === undefined ? {} : { max_tokens: options.maxTokens },
176
219
  stream: true,
177
220
  };
178
221
  }
222
+ /** The system prompt: the caller's, else WorkBuddy's default. */
223
+ systemPrompt(options) {
224
+ if (options.system !== undefined && options.system.trim() !== '')
225
+ return options.system;
226
+ for (const message of options.messages) {
227
+ if (message.role === 'system') {
228
+ const text = message.content.filter((block) => block.type === 'text').map((block) => block.text).join('\n');
229
+ if (text.trim() !== '')
230
+ return text;
231
+ }
232
+ }
233
+ return 'You are a helpful assistant.';
234
+ }
179
235
  toChatMessage(message) {
180
236
  const role = message.role === 'assistant' ? 'assistant' : 'user';
181
237
  const textParts = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-plugin-subscription-oauth",
3
- "version": "0.12.5",
3
+ "version": "0.12.6",
4
4
  "description": "Use subscription accounts as DeepSeek Harness LLM providers — Kimi Code (OAuth device flow), Grok / X Premium (OIDC + PKCE), Google Antigravity (Google OAuth + Cloud Code Assist) and GLM / BigModel (ZCode's browser sign-in) — with per-model visibility, drag-to-reorder Auto fallback and plan quotas from the web Settings page",
5
5
  "license": "MIT",
6
6
  "author": "EricFL1998",