@elizaos/agent 2.0.0-alpha.413 → 2.0.0-alpha.415
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/apps/app-lifeops/src/lifeops/service-mixin-whatsapp.js +1 -90
- package/package.json +4 -4
- package/packages/agent/src/actions/index.d.ts +0 -1
- package/packages/agent/src/actions/index.d.ts.map +1 -1
- package/packages/agent/src/actions/index.js +0 -1
- package/packages/agent/src/api/accounts-routes.d.ts +31 -0
- package/packages/agent/src/api/accounts-routes.d.ts.map +1 -0
- package/packages/agent/src/api/accounts-routes.js +745 -0
- package/packages/agent/src/api/index.d.ts +1 -0
- package/packages/agent/src/api/index.d.ts.map +1 -1
- package/packages/agent/src/api/index.js +1 -0
- package/packages/agent/src/api/model-provider-helpers.js +10 -10
- package/packages/agent/src/api/provider-switch-config.js +2 -2
- package/packages/agent/src/api/server.d.ts.map +1 -1
- package/packages/agent/src/api/server.js +14 -0
- package/packages/agent/src/api/subscription-routes.d.ts.map +1 -1
- package/packages/agent/src/api/subscription-routes.js +48 -1
- package/packages/agent/src/auth/credentials.d.ts.map +1 -1
- package/packages/agent/src/auth/credentials.js +14 -3
- package/packages/agent/src/auth/index.d.ts +2 -0
- package/packages/agent/src/auth/index.d.ts.map +1 -1
- package/packages/agent/src/auth/index.js +2 -0
- package/packages/agent/src/auth/oauth-flow.d.ts +106 -0
- package/packages/agent/src/auth/oauth-flow.d.ts.map +1 -0
- package/packages/agent/src/auth/oauth-flow.js +349 -0
- package/packages/agent/src/auth/vendor/pi-oauth/anthropic-login.d.ts +32 -0
- package/packages/agent/src/auth/vendor/pi-oauth/anthropic-login.d.ts.map +1 -1
- package/packages/agent/src/auth/vendor/pi-oauth/anthropic-login.js +63 -28
- package/packages/agent/src/config/schema.js +1 -1
- package/packages/agent/src/config/types.messages.d.ts +1 -1
- package/packages/agent/src/config/types.tools.d.ts +1 -1
- package/packages/agent/src/providers/page-scoped-context.js +1 -1
- package/packages/agent/src/runtime/eliza-plugin.d.ts.map +1 -1
- package/packages/agent/src/runtime/eliza-plugin.js +0 -3
- package/packages/agent/src/runtime/eliza.js +3 -3
- package/packages/agent/src/runtime/plugin-collector.js +3 -4
- package/packages/app-core/src/components/conversations/conversation-utils.js +4 -4
- package/packages/app-core/src/components/pages/page-scoped-conversations.js +1 -1
- package/packages/app-core/src/components/settings/ProviderSwitcher.js +1 -1
- package/packages/app-core/src/services/auth-store.js +1 -1
- package/packages/app-core/src/state/useOnboardingState.js +1 -1
- package/packages/shared/src/contracts/lifeops.d.ts +5 -4
- package/packages/shared/src/contracts/lifeops.d.ts.map +1 -1
- package/packages/typescript/src/utils/context-catalog.d.ts.map +1 -1
- package/packages/typescript/src/utils/context-catalog.js +2 -3
- package/packages/agent/src/actions/app-control.d.ts +0 -23
- package/packages/agent/src/actions/app-control.d.ts.map +0 -1
- package/packages/agent/src/actions/app-control.js +0 -775
|
@@ -0,0 +1,349 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OAuth flow orchestration registry.
|
|
3
|
+
*
|
|
4
|
+
* Wraps the provider-specific programmatic OAuth helpers
|
|
5
|
+
* (`startAnthropicOAuthFlowRaw` from
|
|
6
|
+
* `vendor/pi-oauth/anthropic-login.ts` and the loopback-listener flow
|
|
7
|
+
* in `openai-codex.ts`) with:
|
|
8
|
+
*
|
|
9
|
+
* - a 5-minute timeout per flow,
|
|
10
|
+
* - automatic `saveAccount(...)` after token exchange,
|
|
11
|
+
* - an in-memory registry keyed by `sessionId` so the HTTP API can
|
|
12
|
+
* stream progress over SSE and the CLI can `await` completion,
|
|
13
|
+
* - garbage collection 10 minutes after a flow reaches a terminal
|
|
14
|
+
* state.
|
|
15
|
+
*
|
|
16
|
+
* Both the CLI and the new accounts-routes HTTP endpoints drive flows
|
|
17
|
+
* through this module — there is no direct caller of the vendor-level
|
|
18
|
+
* OAuth helpers anymore.
|
|
19
|
+
*/
|
|
20
|
+
import crypto from "node:crypto";
|
|
21
|
+
import { logger } from "@elizaos/core";
|
|
22
|
+
import { saveAccount, } from "./account-storage.js";
|
|
23
|
+
import { startCodexLogin } from "./openai-codex.js";
|
|
24
|
+
import { startAnthropicOAuthFlowRaw, } from "./vendor/pi-oauth/anthropic-login.js";
|
|
25
|
+
const FLOW_TIMEOUT_MS = 5 * 60 * 1000;
|
|
26
|
+
const FLOW_GC_MS = 10 * 60 * 1000;
|
|
27
|
+
const flows = new Map();
|
|
28
|
+
function newSessionId() {
|
|
29
|
+
return crypto.randomUUID();
|
|
30
|
+
}
|
|
31
|
+
function emit(entry) {
|
|
32
|
+
for (const listener of entry.listeners) {
|
|
33
|
+
listener(entry.state);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function scheduleGc(sessionId) {
|
|
37
|
+
const entry = flows.get(sessionId);
|
|
38
|
+
if (!entry)
|
|
39
|
+
return;
|
|
40
|
+
if (entry.gcTimer)
|
|
41
|
+
clearTimeout(entry.gcTimer);
|
|
42
|
+
entry.gcTimer = setTimeout(() => {
|
|
43
|
+
flows.delete(sessionId);
|
|
44
|
+
}, FLOW_GC_MS);
|
|
45
|
+
}
|
|
46
|
+
function resolveAccountId(opts) {
|
|
47
|
+
return opts.accountId?.trim() || crypto.randomUUID();
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Build an `AccountCredentialRecord` and persist it via `saveAccount`.
|
|
51
|
+
* Returns the canonical record (with `createdAt`/`updatedAt` filled).
|
|
52
|
+
*/
|
|
53
|
+
function persistAccount(args) {
|
|
54
|
+
const now = Date.now();
|
|
55
|
+
const record = {
|
|
56
|
+
id: args.accountId,
|
|
57
|
+
providerId: args.providerId,
|
|
58
|
+
label: args.label,
|
|
59
|
+
source: "oauth",
|
|
60
|
+
credentials: {
|
|
61
|
+
access: args.access,
|
|
62
|
+
refresh: args.refresh,
|
|
63
|
+
expires: args.expires,
|
|
64
|
+
},
|
|
65
|
+
createdAt: now,
|
|
66
|
+
updatedAt: now,
|
|
67
|
+
...(args.organizationId ? { organizationId: args.organizationId } : {}),
|
|
68
|
+
...(args.email ? { email: args.email } : {}),
|
|
69
|
+
};
|
|
70
|
+
saveAccount(record);
|
|
71
|
+
return record;
|
|
72
|
+
}
|
|
73
|
+
// Anthropic.
|
|
74
|
+
/**
|
|
75
|
+
* Start a programmatic Anthropic OAuth flow. Anthropic's redirect URI
|
|
76
|
+
* is hardcoded to `console.anthropic.com/oauth/code/callback` — the
|
|
77
|
+
* UI must surface the auth URL, prompt the user to copy the
|
|
78
|
+
* `code#state` blob, and call `submitCode()` with it. Once the code is
|
|
79
|
+
* submitted, the token exchange runs and the account is persisted.
|
|
80
|
+
*/
|
|
81
|
+
export function startAnthropicOAuthFlow(opts) {
|
|
82
|
+
return startGenericFlow({
|
|
83
|
+
providerId: "anthropic-subscription",
|
|
84
|
+
opts,
|
|
85
|
+
needsCodeSubmission: true,
|
|
86
|
+
begin: async () => {
|
|
87
|
+
const raw = await startAnthropicOAuthFlowRaw();
|
|
88
|
+
const completion = (async () => {
|
|
89
|
+
const creds = await raw.completion;
|
|
90
|
+
return { creds };
|
|
91
|
+
})();
|
|
92
|
+
return {
|
|
93
|
+
authUrl: raw.authUrl,
|
|
94
|
+
completion,
|
|
95
|
+
submitCode: raw.submitCode,
|
|
96
|
+
cancel: raw.cancel,
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
// Codex (OpenAI ChatGPT subscription).
|
|
102
|
+
/**
|
|
103
|
+
* Start a programmatic Codex OAuth flow. Codex has a loopback listener
|
|
104
|
+
* on :1455, so the user just signs in in the browser and the listener
|
|
105
|
+
* picks up the redirect — `submitCode()` is a no-op. The accountId
|
|
106
|
+
* baked into the JWT is preserved on `LinkedAccountConfig.organizationId`
|
|
107
|
+
* (used by the Codex usage probe via the `ChatGPT-Account-Id` header).
|
|
108
|
+
*/
|
|
109
|
+
export function startCodexOAuthFlow(opts) {
|
|
110
|
+
return startGenericFlow({
|
|
111
|
+
providerId: "openai-codex",
|
|
112
|
+
opts,
|
|
113
|
+
needsCodeSubmission: false,
|
|
114
|
+
begin: async () => {
|
|
115
|
+
const flow = await startCodexLogin();
|
|
116
|
+
const completion = (async () => {
|
|
117
|
+
const creds = await flow.credentials;
|
|
118
|
+
return { creds, codexFlow: flow };
|
|
119
|
+
})();
|
|
120
|
+
return {
|
|
121
|
+
authUrl: flow.authUrl,
|
|
122
|
+
completion,
|
|
123
|
+
submitCode: (code) => flow.submitCode(code),
|
|
124
|
+
cancel: () => flow.close(),
|
|
125
|
+
};
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
async function startGenericFlow(args) {
|
|
130
|
+
const { providerId, opts, needsCodeSubmission, begin } = args;
|
|
131
|
+
const sessionId = newSessionId();
|
|
132
|
+
const accountId = resolveAccountId(opts);
|
|
133
|
+
const vendor = await begin();
|
|
134
|
+
const startedAt = Date.now();
|
|
135
|
+
const initialState = {
|
|
136
|
+
sessionId,
|
|
137
|
+
providerId,
|
|
138
|
+
status: "pending",
|
|
139
|
+
authUrl: vendor.authUrl,
|
|
140
|
+
needsCodeSubmission,
|
|
141
|
+
startedAt,
|
|
142
|
+
};
|
|
143
|
+
let resolveCompletion;
|
|
144
|
+
let rejectCompletion;
|
|
145
|
+
const completion = new Promise((resolve, reject) => {
|
|
146
|
+
resolveCompletion = resolve;
|
|
147
|
+
rejectCompletion = reject;
|
|
148
|
+
});
|
|
149
|
+
const entry = {
|
|
150
|
+
state: initialState,
|
|
151
|
+
handle: {}, // filled below
|
|
152
|
+
listeners: new Set(),
|
|
153
|
+
};
|
|
154
|
+
flows.set(sessionId, entry);
|
|
155
|
+
const setTerminal = (next) => {
|
|
156
|
+
if (entry.state.status !== "pending")
|
|
157
|
+
return;
|
|
158
|
+
entry.state = {
|
|
159
|
+
...entry.state,
|
|
160
|
+
...next,
|
|
161
|
+
endedAt: Date.now(),
|
|
162
|
+
};
|
|
163
|
+
emit(entry);
|
|
164
|
+
scheduleGc(sessionId);
|
|
165
|
+
};
|
|
166
|
+
const timer = setTimeout(() => {
|
|
167
|
+
const err = new Error("OAuth flow timed out after 5 minutes");
|
|
168
|
+
try {
|
|
169
|
+
vendor.cancel("timeout");
|
|
170
|
+
}
|
|
171
|
+
catch (cancelErr) {
|
|
172
|
+
logger.debug(`[oauth-flow] cancel during timeout failed: ${String(cancelErr)}`);
|
|
173
|
+
}
|
|
174
|
+
setTerminal({ status: "timeout", error: err.message });
|
|
175
|
+
rejectCompletion(err);
|
|
176
|
+
}, FLOW_TIMEOUT_MS);
|
|
177
|
+
// Drive the vendor completion through to account-save and listener emit.
|
|
178
|
+
void (async () => {
|
|
179
|
+
try {
|
|
180
|
+
const { creds } = await vendor.completion;
|
|
181
|
+
clearTimeout(timer);
|
|
182
|
+
let organizationId;
|
|
183
|
+
// Codex bakes the account_id into the JWT — pull it back out for
|
|
184
|
+
// the usage probe header.
|
|
185
|
+
if (providerId === "openai-codex") {
|
|
186
|
+
const codexAccountId = extractCodexAccountId(creds.access);
|
|
187
|
+
if (codexAccountId)
|
|
188
|
+
organizationId = codexAccountId;
|
|
189
|
+
}
|
|
190
|
+
const record = persistAccount({
|
|
191
|
+
providerId,
|
|
192
|
+
accountId,
|
|
193
|
+
label: opts.label,
|
|
194
|
+
access: creds.access,
|
|
195
|
+
refresh: creds.refresh,
|
|
196
|
+
expires: creds.expires,
|
|
197
|
+
...(organizationId ? { organizationId } : {}),
|
|
198
|
+
});
|
|
199
|
+
if (opts.onAccountSaved) {
|
|
200
|
+
await opts.onAccountSaved(record);
|
|
201
|
+
}
|
|
202
|
+
setTerminal({ status: "success", account: record });
|
|
203
|
+
resolveCompletion({ account: record });
|
|
204
|
+
}
|
|
205
|
+
catch (err) {
|
|
206
|
+
clearTimeout(timer);
|
|
207
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
208
|
+
setTerminal({ status: "error", error: message });
|
|
209
|
+
rejectCompletion(err instanceof Error ? err : new Error(message));
|
|
210
|
+
}
|
|
211
|
+
})();
|
|
212
|
+
const handle = {
|
|
213
|
+
sessionId,
|
|
214
|
+
authUrl: vendor.authUrl,
|
|
215
|
+
needsCodeSubmission,
|
|
216
|
+
completion,
|
|
217
|
+
submitCode: (code) => {
|
|
218
|
+
vendor.submitCode(code);
|
|
219
|
+
},
|
|
220
|
+
cancel: (reason = "Cancelled") => {
|
|
221
|
+
if (entry.state.status !== "pending")
|
|
222
|
+
return;
|
|
223
|
+
try {
|
|
224
|
+
vendor.cancel(reason);
|
|
225
|
+
}
|
|
226
|
+
catch (err) {
|
|
227
|
+
logger.debug(`[oauth-flow] vendor cancel failed: ${String(err)}`);
|
|
228
|
+
}
|
|
229
|
+
clearTimeout(timer);
|
|
230
|
+
const error = new Error(reason);
|
|
231
|
+
setTerminal({ status: "cancelled", error: reason });
|
|
232
|
+
rejectCompletion(error);
|
|
233
|
+
},
|
|
234
|
+
};
|
|
235
|
+
entry.handle = handle;
|
|
236
|
+
emit(entry);
|
|
237
|
+
return handle;
|
|
238
|
+
}
|
|
239
|
+
// Registry surface used by the SSE / cancel routes.
|
|
240
|
+
export function getFlowState(sessionId) {
|
|
241
|
+
const entry = flows.get(sessionId);
|
|
242
|
+
return entry ? entry.state : null;
|
|
243
|
+
}
|
|
244
|
+
export function getFlowHandle(sessionId) {
|
|
245
|
+
const entry = flows.get(sessionId);
|
|
246
|
+
return entry ? entry.handle : null;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Subscribe to status updates for a flow. Replays the current state
|
|
250
|
+
* synchronously so SSE consumers always receive an immediate frame.
|
|
251
|
+
* Returns an unsubscribe function.
|
|
252
|
+
*/
|
|
253
|
+
export function subscribeFlow(sessionId, listener) {
|
|
254
|
+
const entry = flows.get(sessionId);
|
|
255
|
+
if (!entry)
|
|
256
|
+
return () => { };
|
|
257
|
+
entry.listeners.add(listener);
|
|
258
|
+
// Replay current state.
|
|
259
|
+
listener(entry.state);
|
|
260
|
+
return () => {
|
|
261
|
+
entry.listeners.delete(listener);
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
export function cancelFlow(sessionId, reason) {
|
|
265
|
+
const entry = flows.get(sessionId);
|
|
266
|
+
if (!entry)
|
|
267
|
+
return false;
|
|
268
|
+
if (entry.state.status !== "pending")
|
|
269
|
+
return false;
|
|
270
|
+
entry.handle.cancel(reason);
|
|
271
|
+
return true;
|
|
272
|
+
}
|
|
273
|
+
export function submitFlowCode(sessionId, code) {
|
|
274
|
+
const entry = flows.get(sessionId);
|
|
275
|
+
if (!entry)
|
|
276
|
+
return false;
|
|
277
|
+
if (entry.state.status !== "pending")
|
|
278
|
+
return false;
|
|
279
|
+
if (!entry.state.needsCodeSubmission)
|
|
280
|
+
return false;
|
|
281
|
+
entry.handle.submitCode(code);
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Remove every flow from the registry. Tests use this to reset
|
|
286
|
+
* between cases without resetting the whole module.
|
|
287
|
+
*/
|
|
288
|
+
export function _resetFlowRegistry() {
|
|
289
|
+
for (const entry of flows.values()) {
|
|
290
|
+
if (entry.gcTimer)
|
|
291
|
+
clearTimeout(entry.gcTimer);
|
|
292
|
+
}
|
|
293
|
+
flows.clear();
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Test-only helper to seed a synthetic flow without going through the
|
|
297
|
+
* vendor layer. Used by `accounts-routes.test.ts` to assert the SSE
|
|
298
|
+
* surface streams `success` / `error` payloads correctly.
|
|
299
|
+
*/
|
|
300
|
+
export function _registerSyntheticFlow(args) {
|
|
301
|
+
const sessionId = args.sessionId ?? newSessionId();
|
|
302
|
+
const state = {
|
|
303
|
+
sessionId,
|
|
304
|
+
providerId: args.providerId,
|
|
305
|
+
status: "pending",
|
|
306
|
+
authUrl: args.authUrl,
|
|
307
|
+
needsCodeSubmission: Boolean(args.needsCodeSubmission),
|
|
308
|
+
startedAt: Date.now(),
|
|
309
|
+
};
|
|
310
|
+
const entry = {
|
|
311
|
+
state,
|
|
312
|
+
handle: {
|
|
313
|
+
sessionId,
|
|
314
|
+
authUrl: args.authUrl,
|
|
315
|
+
needsCodeSubmission: Boolean(args.needsCodeSubmission),
|
|
316
|
+
completion: new Promise(() => undefined),
|
|
317
|
+
submitCode: () => undefined,
|
|
318
|
+
cancel: () => undefined,
|
|
319
|
+
},
|
|
320
|
+
listeners: new Set(),
|
|
321
|
+
};
|
|
322
|
+
flows.set(sessionId, entry);
|
|
323
|
+
const complete = (next) => {
|
|
324
|
+
entry.state = { ...next, endedAt: next.endedAt ?? Date.now() };
|
|
325
|
+
emit(entry);
|
|
326
|
+
scheduleGc(sessionId);
|
|
327
|
+
};
|
|
328
|
+
return { sessionId, complete };
|
|
329
|
+
}
|
|
330
|
+
/** OpenAI Codex JWT carries `chatgpt_account_id` under a vendor claim. */
|
|
331
|
+
function extractCodexAccountId(accessToken) {
|
|
332
|
+
try {
|
|
333
|
+
const parts = accessToken.split(".");
|
|
334
|
+
if (parts.length !== 3)
|
|
335
|
+
return null;
|
|
336
|
+
const payload = parts[1];
|
|
337
|
+
const decoded = JSON.parse(Buffer.from(payload, "base64").toString("utf-8"));
|
|
338
|
+
const claim = decoded["https://api.openai.com/auth"];
|
|
339
|
+
if (!claim || typeof claim !== "object")
|
|
340
|
+
return null;
|
|
341
|
+
const accountId = claim.chatgpt_account_id;
|
|
342
|
+
return typeof accountId === "string" && accountId.length > 0
|
|
343
|
+
? accountId
|
|
344
|
+
: null;
|
|
345
|
+
}
|
|
346
|
+
catch {
|
|
347
|
+
return null;
|
|
348
|
+
}
|
|
349
|
+
}
|
|
@@ -1,15 +1,47 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Anthropic OAuth (Claude Pro/Max) — authorization code + PKCE.
|
|
3
3
|
* Inlined OAuth flow (MIT) — vendored to avoid a runtime dependency.
|
|
4
|
+
*
|
|
5
|
+
* Anthropic's OAuth uses a fixed redirect URI on `console.anthropic.com`
|
|
6
|
+
* that displays the auth code on completion — there's no loopback
|
|
7
|
+
* listener. The flow surfaces an `authUrl` plus a `submitCode()` hook
|
|
8
|
+
* the UI / CLI calls once the user has copied the code.
|
|
4
9
|
*/
|
|
5
10
|
export interface AnthropicOAuthCredentials {
|
|
6
11
|
refresh: string;
|
|
7
12
|
access: string;
|
|
8
13
|
expires: number;
|
|
9
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Programmatic Anthropic OAuth flow.
|
|
17
|
+
*
|
|
18
|
+
* `authUrl` is ready immediately. The caller MUST eventually call
|
|
19
|
+
* either `submitCode(code)` (after the user has pasted the
|
|
20
|
+
* `code#state` blob from the redirect page) or `cancel()`. The
|
|
21
|
+
* `completion` promise rejects if the flow is cancelled.
|
|
22
|
+
*/
|
|
23
|
+
export interface AnthropicOAuthFlowHandle {
|
|
24
|
+
authUrl: string;
|
|
25
|
+
/** Pass `code#state` from the redirect page. */
|
|
26
|
+
submitCode: (code: string) => void;
|
|
27
|
+
/** Resolves with credentials once `submitCode` lands and the token exchange succeeds. */
|
|
28
|
+
completion: Promise<AnthropicOAuthCredentials>;
|
|
29
|
+
cancel: (reason?: string) => void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Start an Anthropic OAuth flow. Returns immediately with the auth
|
|
33
|
+
* URL and a `submitCode` hook. The token exchange happens inside
|
|
34
|
+
* `completion` once the caller submits the code.
|
|
35
|
+
*/
|
|
36
|
+
export declare function startAnthropicOAuthFlowRaw(): Promise<AnthropicOAuthFlowHandle>;
|
|
10
37
|
/**
|
|
11
38
|
* @param onAuthUrl - Receives the browser authorization URL
|
|
12
39
|
* @param onPromptCode - Resolves with pasted code (format: code#state)
|
|
40
|
+
*
|
|
41
|
+
* Thin compatibility wrapper around `startAnthropicOAuthFlowRaw` for
|
|
42
|
+
* the CLI entrypoint and any older callers. New code should use
|
|
43
|
+
* `startAnthropicOAuthFlowRaw` (or the higher-level
|
|
44
|
+
* `startAnthropicOAuthFlow` in `auth/oauth-flow.ts`) directly.
|
|
13
45
|
*/
|
|
14
46
|
export declare function loginAnthropic(onAuthUrl: (url: string) => void, onPromptCode: () => Promise<string>): Promise<AnthropicOAuthCredentials>;
|
|
15
47
|
export declare function refreshAnthropicToken(refreshToken: string): Promise<AnthropicOAuthCredentials>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"anthropic-login.d.ts","sourceRoot":"","sources":["../../../../../../../src/auth/vendor/pi-oauth/anthropic-login.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"anthropic-login.d.ts","sourceRoot":"","sources":["../../../../../../../src/auth/vendor/pi-oauth/anthropic-login.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAWH,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,gDAAgD;IAChD,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,yFAAyF;IACzF,UAAU,EAAE,OAAO,CAAC,yBAAyB,CAAC,CAAC;IAC/C,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAED;;;;GAIG;AACH,wBAAsB,0BAA0B,IAAI,OAAO,CAAC,wBAAwB,CAAC,CA6DpF;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,EAChC,YAAY,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,GAClC,OAAO,CAAC,yBAAyB,CAAC,CAMpC;AAED,wBAAsB,qBAAqB,CACzC,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,yBAAyB,CAAC,CAwBpC"}
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Anthropic OAuth (Claude Pro/Max) — authorization code + PKCE.
|
|
3
3
|
* Inlined OAuth flow (MIT) — vendored to avoid a runtime dependency.
|
|
4
|
+
*
|
|
5
|
+
* Anthropic's OAuth uses a fixed redirect URI on `console.anthropic.com`
|
|
6
|
+
* that displays the auth code on completion — there's no loopback
|
|
7
|
+
* listener. The flow surfaces an `authUrl` plus a `submitCode()` hook
|
|
8
|
+
* the UI / CLI calls once the user has copied the code.
|
|
4
9
|
*/
|
|
5
10
|
import { generatePKCE } from "./pkce.js";
|
|
6
11
|
const decode = (s) => atob(s);
|
|
@@ -10,10 +15,11 @@ const TOKEN_URL = "https://console.anthropic.com/v1/oauth/token";
|
|
|
10
15
|
const REDIRECT_URI = "https://console.anthropic.com/oauth/code/callback";
|
|
11
16
|
const SCOPES = "org:create_api_key user:profile user:inference";
|
|
12
17
|
/**
|
|
13
|
-
*
|
|
14
|
-
*
|
|
18
|
+
* Start an Anthropic OAuth flow. Returns immediately with the auth
|
|
19
|
+
* URL and a `submitCode` hook. The token exchange happens inside
|
|
20
|
+
* `completion` once the caller submits the code.
|
|
15
21
|
*/
|
|
16
|
-
export async function
|
|
22
|
+
export async function startAnthropicOAuthFlowRaw() {
|
|
17
23
|
const { verifier, challenge } = await generatePKCE();
|
|
18
24
|
const authParams = new URLSearchParams({
|
|
19
25
|
code: "true",
|
|
@@ -26,35 +32,64 @@ export async function loginAnthropic(onAuthUrl, onPromptCode) {
|
|
|
26
32
|
state: verifier,
|
|
27
33
|
});
|
|
28
34
|
const authUrl = `${AUTHORIZE_URL}?${authParams.toString()}`;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
const tokenResponse = await fetch(TOKEN_URL, {
|
|
35
|
-
method: "POST",
|
|
36
|
-
headers: { "Content-Type": "application/json" },
|
|
37
|
-
body: JSON.stringify({
|
|
38
|
-
grant_type: "authorization_code",
|
|
39
|
-
client_id: CLIENT_ID,
|
|
40
|
-
code,
|
|
41
|
-
state,
|
|
42
|
-
redirect_uri: REDIRECT_URI,
|
|
43
|
-
code_verifier: verifier,
|
|
44
|
-
}),
|
|
35
|
+
let resolveCode = null;
|
|
36
|
+
let rejectCode = null;
|
|
37
|
+
const codePromise = new Promise((resolve, reject) => {
|
|
38
|
+
resolveCode = resolve;
|
|
39
|
+
rejectCode = reject;
|
|
45
40
|
});
|
|
46
|
-
|
|
47
|
-
const
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
41
|
+
const completion = (async () => {
|
|
42
|
+
const authCode = await codePromise;
|
|
43
|
+
const splits = authCode.split("#");
|
|
44
|
+
const code = splits[0];
|
|
45
|
+
const state = splits[1];
|
|
46
|
+
const tokenResponse = await fetch(TOKEN_URL, {
|
|
47
|
+
method: "POST",
|
|
48
|
+
headers: { "Content-Type": "application/json" },
|
|
49
|
+
body: JSON.stringify({
|
|
50
|
+
grant_type: "authorization_code",
|
|
51
|
+
client_id: CLIENT_ID,
|
|
52
|
+
code,
|
|
53
|
+
state,
|
|
54
|
+
redirect_uri: REDIRECT_URI,
|
|
55
|
+
code_verifier: verifier,
|
|
56
|
+
}),
|
|
57
|
+
});
|
|
58
|
+
if (!tokenResponse.ok) {
|
|
59
|
+
const errText = await tokenResponse.text();
|
|
60
|
+
throw new Error(`Token exchange failed: ${errText}`);
|
|
61
|
+
}
|
|
62
|
+
const tokenData = (await tokenResponse.json());
|
|
63
|
+
const expiresAt = Date.now() + tokenData.expires_in * 1000 - 5 * 60 * 1000;
|
|
64
|
+
return {
|
|
65
|
+
refresh: tokenData.refresh_token,
|
|
66
|
+
access: tokenData.access_token,
|
|
67
|
+
expires: expiresAt,
|
|
68
|
+
};
|
|
69
|
+
})();
|
|
52
70
|
return {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
71
|
+
authUrl,
|
|
72
|
+
submitCode: (code) => resolveCode?.(code),
|
|
73
|
+
completion,
|
|
74
|
+
cancel: (reason = "Cancelled") => rejectCode?.(new Error(reason)),
|
|
56
75
|
};
|
|
57
76
|
}
|
|
77
|
+
/**
|
|
78
|
+
* @param onAuthUrl - Receives the browser authorization URL
|
|
79
|
+
* @param onPromptCode - Resolves with pasted code (format: code#state)
|
|
80
|
+
*
|
|
81
|
+
* Thin compatibility wrapper around `startAnthropicOAuthFlowRaw` for
|
|
82
|
+
* the CLI entrypoint and any older callers. New code should use
|
|
83
|
+
* `startAnthropicOAuthFlowRaw` (or the higher-level
|
|
84
|
+
* `startAnthropicOAuthFlow` in `auth/oauth-flow.ts`) directly.
|
|
85
|
+
*/
|
|
86
|
+
export async function loginAnthropic(onAuthUrl, onPromptCode) {
|
|
87
|
+
const handle = await startAnthropicOAuthFlowRaw();
|
|
88
|
+
onAuthUrl(handle.authUrl);
|
|
89
|
+
const code = await onPromptCode();
|
|
90
|
+
handle.submitCode(code);
|
|
91
|
+
return handle.completion;
|
|
92
|
+
}
|
|
58
93
|
export async function refreshAnthropicToken(refreshToken) {
|
|
59
94
|
const response = await fetch(TOKEN_URL, {
|
|
60
95
|
method: "POST",
|
|
@@ -413,7 +413,7 @@ const FIELD_HELP = {
|
|
|
413
413
|
"diagnostics.cacheTrace.includePrompt": "Include prompt text in trace output (default: true).",
|
|
414
414
|
"diagnostics.cacheTrace.includeSystem": "Include system prompt in trace output (default: true).",
|
|
415
415
|
"tools.exec.applyPatch.enabled": "Experimental. Enables apply_patch for OpenAI models when allowed by tool policy.",
|
|
416
|
-
"tools.exec.applyPatch.allowModels": 'Optional allowlist of model ids (e.g. "gpt-5.
|
|
416
|
+
"tools.exec.applyPatch.allowModels": 'Optional allowlist of model ids (e.g. "gpt-5.5" or "openai/gpt-5.5").',
|
|
417
417
|
"tools.exec.notifyOnExit": "When true (default), backgrounded exec sessions enqueue a system event and request a heartbeat on exit.",
|
|
418
418
|
"tools.exec.pathPrepend": "Directories to prepend to PATH for exec runs (gateway/sandbox).",
|
|
419
419
|
"tools.exec.safeBins": "Allow stdin-only safe binaries to run without explicit allowlist entries.",
|
|
@@ -123,7 +123,7 @@ export type MessagesConfig = {
|
|
|
123
123
|
* - special value: `"auto"` derives `[{agents.list[].identity.name}]` for the routed agent (when set)
|
|
124
124
|
*
|
|
125
125
|
* Supported template variables (case-insensitive):
|
|
126
|
-
* - `{model}` - short model name (e.g., `claude-opus-4-7`, `gpt-5.
|
|
126
|
+
* - `{model}` - short model name (e.g., `claude-opus-4-7`, `gpt-5.5`)
|
|
127
127
|
* - `{modelFull}` - full model identifier (e.g., `anthropic/claude-opus-4.7`)
|
|
128
128
|
* - `{provider}` - provider name (e.g., `anthropic`, `openai`)
|
|
129
129
|
* - `{thinkingLevel}` or `{think}` - current thinking level (`high`, `low`, `off`)
|
|
@@ -141,7 +141,7 @@ export type ExecToolConfig = {
|
|
|
141
141
|
enabled?: boolean;
|
|
142
142
|
/**
|
|
143
143
|
* Optional allowlist of model ids that can use apply_patch.
|
|
144
|
-
* Accepts either raw ids (e.g. "gpt-5.
|
|
144
|
+
* Accepts either raw ids (e.g. "gpt-5.5") or full ids (e.g. "openai/gpt-5.5").
|
|
145
145
|
*/
|
|
146
146
|
allowModels?: string[];
|
|
147
147
|
};
|
|
@@ -9,7 +9,7 @@ const PAGE_SCOPE_BRIEF = {
|
|
|
9
9
|
"page-browser": "The user is in the Browser view. Tabs are grouped into User Tabs, Agent Tabs, and App Tabs. User Tabs are writable: the user can open them, navigate URLs, refresh pages, capture snapshots, show or hide tabs, and close tabs there. Agent Tabs and App Tabs are read-only context: inspect and explain them, but do not navigate, click, type into, refresh, close, or otherwise mutate them. Action vocabulary the agent can rely on includes openBrowserWorkspaceTab, navigateBrowserWorkspaceTab, snapshotBrowserWorkspaceTab, showBrowserWorkspaceTab, hideBrowserWorkspaceTab, closeBrowserWorkspaceTab. When the user asks what to do, explain the available browser actions, recommend the next action from live tab and bridge state, and offer to answer questions about tabs, forms, current pages, or setup. Do not invent tabs or URLs.",
|
|
10
10
|
"page-character": "The user is in the Character view. The Character hub is organized into Overview, Personality, Knowledge, Experience, and Relationships. Name, voice, and system prompt live in Settings > Identity; Personality focuses on bio, style rules, message examples, and evolution history; Knowledge holds uploaded and learned knowledge; Experience surfaces durable learnings the agent recorded; Relationships shows the full relationship graph, facts, memories, and user-scoped personality preferences. When the user asks what to do, explain the relevant hub section, recommend the next improvement from live state, and offer to draft exact copy. Guide the user to the relevant section rather than fabricate a generic setter action.",
|
|
11
11
|
"page-automations": "The user is in the Automations view. They can create coordinator-text triggers, one-off tasks, recurring tasks, and n8n workflows; set cron or interval schedules; configure wake mode (inject_now / schedule_at / interval), max-runs, and enabled state; browse templates; inspect existing automations; and troubleshoot failed runs. Action vocabulary: createTriggerTaskAction, updateTriggerTaskAction, deleteTriggerTaskAction, runTriggerNowAction, createWorkflowAction, deleteWorkflowAction, toggleWorkflowActiveAction, promoteTaskToWorkflowAction, manageTasksAction. When the user asks what to do, recommend trigger vs task vs workflow based on the event, schedule, and desired result. Triggers and workflows already in the system are listed in live state below; reference them by display name when answering.",
|
|
12
|
-
"page-apps": "The user is in the Apps view. They can browse and compare catalog apps, launch apps, stop running apps, open attached live viewers, inspect run health and summaries, and manage favorites or recent apps. Action vocabulary:
|
|
12
|
+
"page-apps": "The user is in the Apps view. They can browse and compare catalog apps, launch apps, stop running apps, open attached live viewers, inspect run health and summaries, and manage favorites or recent apps. Action vocabulary: APP with mode launch, relaunch, list, load_from_directory, or create. When the user asks what to do, recommend an app or run-management action from the live catalog and running app state. Refer to apps by display name and never invent app names.",
|
|
13
13
|
"page-connectors": "The user is in the Connectors view. They can inspect connector availability, authentication state, setup requirements, webhook readiness, and integration health. When the user asks what to do, recommend the smallest connector setup or troubleshooting action that fits the visible state. Never invent connected accounts, permissions, webhook state, or delivery results.",
|
|
14
14
|
"page-plugins": "The user is in the Plugins view. They can inspect installed plugins, registry plugins, configuration readiness, plugin health, and runtime capability gaps. When the user asks what to do, recommend the smallest plugin setup or troubleshooting action that fits the visible state. Never invent installed plugins, credentials, or enabled capabilities.",
|
|
15
15
|
"page-lifeops": "The user is in the LifeOps view. They can inspect the overview, goals, reminders, calendar, messages, mail, sleep, screen time, social context, connector setup, capability readiness, and LifeOps settings. The LifeOps app provider and actions are the authoritative execution path for creating or changing personal workflows, reminders, goals, schedules, inbox drafts, connector setup, and executive-assistant follow-through. When the user asks what to do, recommend capability readiness and overview review first, then suggest the smallest concrete LifeOps action. Reference only live LifeOps state below; never invent reminders, messages, calendar events, goals, or connector status.",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eliza-plugin.d.ts","sourceRoot":"","sources":["../../../../../src/runtime/eliza-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAiB,MAAM,EAAgB,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"eliza-plugin.d.ts","sourceRoot":"","sources":["../../../../../src/runtime/eliza-plugin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAiB,MAAM,EAAgB,MAAM,eAAe,CAAC;AA0GzE,MAAM,MAAM,iBAAiB,GAAG;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,MAAM,CAAC,EAAE,iBAAiB,GAAG,MAAM,CAoMpE"}
|
|
@@ -6,7 +6,6 @@
|
|
|
6
6
|
* Memory search/get actions are superseded by plugin-clipboard.
|
|
7
7
|
*/
|
|
8
8
|
import { AgentEventService } from "@elizaos/core";
|
|
9
|
-
import { launchAppAction, stopAppAction } from "../actions/app-control.js";
|
|
10
9
|
import { browserSessionAction } from "../actions/browser-session.js";
|
|
11
10
|
import { executeDatabaseQueryAction, getTableDataAction, listDatabaseTablesAction, searchVectorsAction, } from "../actions/database.js";
|
|
12
11
|
import { getRelationshipActivityAction, linkEntityAction, readEntityAction, resolveMergeCandidateAction, searchEntityAction, } from "../actions/entity-actions.js";
|
|
@@ -167,8 +166,6 @@ export function createElizaPlugin(config) {
|
|
|
167
166
|
evaluators: [lateJoinWhitelistEvaluator],
|
|
168
167
|
actions: [
|
|
169
168
|
restartAction,
|
|
170
|
-
launchAppAction,
|
|
171
|
-
stopAppAction,
|
|
172
169
|
sendAdminMessageAction,
|
|
173
170
|
terminalAction,
|
|
174
171
|
createTriggerTaskAction,
|
|
@@ -464,8 +464,8 @@ function isLikelyOpenAiTextModel(value) {
|
|
|
464
464
|
* Normalize known-bad provider compatibility shims before plugin resolution.
|
|
465
465
|
*
|
|
466
466
|
* A common failure mode is routing the OpenAI plugin through Groq's
|
|
467
|
-
* OpenAI-compatible base URL while leaving OpenAI defaults (`gpt-5.
|
|
468
|
-
* `gpt-5.
|
|
467
|
+
* OpenAI-compatible base URL while leaving OpenAI defaults (`gpt-5.5`,
|
|
468
|
+
* `gpt-5.5-mini`) in place. Structured XML/object generation then fails during
|
|
469
469
|
* message handling because Groq does not serve those model IDs.
|
|
470
470
|
*
|
|
471
471
|
* When we can confidently detect that state, rewrite the effective runtime
|
|
@@ -1036,7 +1036,7 @@ export function applyCloudConfigToEnv(config) {
|
|
|
1036
1036
|
const llmText = resolveServiceRoutingInConfig(config)?.llmText;
|
|
1037
1037
|
const models = config.models;
|
|
1038
1038
|
if (effectivelyEnabled) {
|
|
1039
|
-
const nano = llmText?.nanoModel || models?.nano || "openai/gpt-5.
|
|
1039
|
+
const nano = llmText?.nanoModel || models?.nano || "openai/gpt-5.5-nano";
|
|
1040
1040
|
const small = llmText?.smallModel || models?.small || "minimax/minimax-m2.7";
|
|
1041
1041
|
const medium = llmText?.mediumModel || models?.medium || small;
|
|
1042
1042
|
const large = llmText?.largeModel || models?.large || "anthropic/claude-opus-4-7";
|
|
@@ -391,10 +391,9 @@ export function collectPluginNames(config, reasons) {
|
|
|
391
391
|
if (shellPluginDisabled) {
|
|
392
392
|
pluginsToLoad.delete("@elizaos/plugin-shell");
|
|
393
393
|
}
|
|
394
|
-
for (const
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
pluginsToLoad.delete(resolved);
|
|
394
|
+
for (const pluginName of Array.from(pluginsToLoad)) {
|
|
395
|
+
if (isPluginExplicitlyDisabled(pluginName)) {
|
|
396
|
+
pluginsToLoad.delete(pluginName);
|
|
398
397
|
}
|
|
399
398
|
}
|
|
400
399
|
return pluginsToLoad;
|
|
@@ -104,10 +104,10 @@ export function isNonChatModelLabel(model) {
|
|
|
104
104
|
export function estimateTokenCost(promptTokens, completionTokens, model) {
|
|
105
105
|
const normalizedModel = (model ?? "").toLowerCase();
|
|
106
106
|
const pricingByMillion = {
|
|
107
|
-
"gpt-5.
|
|
108
|
-
"gpt-5.
|
|
109
|
-
"gpt-5.
|
|
110
|
-
"gpt-5.
|
|
107
|
+
"gpt-5.5-pro": [30.0, 180.0],
|
|
108
|
+
"gpt-5.5-mini": [0.75, 4.5],
|
|
109
|
+
"gpt-5.5-nano": [0.2, 1.25],
|
|
110
|
+
"gpt-5.5": [2.5, 15.0],
|
|
111
111
|
"gpt-4.1": [2.0, 8.0],
|
|
112
112
|
"gpt-4o": [2.5, 10.0],
|
|
113
113
|
"gpt-4": [30.0, 60.0],
|
|
@@ -37,7 +37,7 @@ export const PAGE_SCOPE_COPY = {
|
|
|
37
37
|
"page-apps": {
|
|
38
38
|
title: "Apps chat",
|
|
39
39
|
body: "Use me to browse the catalog, compare apps, launch an app, stop a running app, open a live viewer, inspect run health, and manage favorites or recent apps. Recommended: describe the outcome you want, and I'll suggest the right app or launch it. Ask me about any catalog item or running app.",
|
|
40
|
-
systemAddendum: "You are answering inside the Apps view. The user can browse the catalog, compare apps by category and capability, launch apps, stop running apps, open attached live viewers, inspect run health and summaries, and manage favorites or recent apps. Recommend the best app or next run-management action based on live catalog and run state. Use
|
|
40
|
+
systemAddendum: "You are answering inside the Apps view. The user can browse the catalog, compare apps by category and capability, launch apps, stop running apps, open attached live viewers, inspect run health and summaries, and manage favorites or recent apps. Recommend the best app or next run-management action based on live catalog and run state. Use APP with mode launch, relaunch, list, load_from_directory, or create when the request is concrete. Refer to apps by display name and never invent app names.",
|
|
41
41
|
},
|
|
42
42
|
"page-connectors": {
|
|
43
43
|
title: "Connectors chat",
|
|
@@ -168,7 +168,7 @@ export function ProviderSwitcher(props = {}) {
|
|
|
168
168
|
const providerId = getOnboardingProviderOption(llmText?.backend)?.id;
|
|
169
169
|
const elizaCloudEnabledCfg = llmText?.transport === "cloud-proxy" && providerId === "elizacloud";
|
|
170
170
|
const defaults = {
|
|
171
|
-
nano: "openai/gpt-5.
|
|
171
|
+
nano: "openai/gpt-5.5-nano",
|
|
172
172
|
small: "minimax/minimax-m2.7",
|
|
173
173
|
medium: "anthropic/claude-sonnet-4.6",
|
|
174
174
|
large: "moonshotai/kimi-k2.5",
|