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(
|
|
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.
|
|
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",
|