@ai-ecoverse/slicc-agent 6.15.2 → 6.17.0
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 +3 -1
- package/dist/codex.js +50 -0
- package/dist/codex.js.map +7 -0
- package/dist/device.js +145 -0
- package/dist/device.js.map +7 -0
- package/dist/guests/guard.js +28 -1
- package/dist/guests/guard.js.map +2 -2
- package/dist/main.js +10 -6
- package/dist/main.js.map +2 -2
- package/dist/preferred.js +1 -0
- package/dist/preferred.js.map +2 -2
- package/dist/providers.js +16 -4
- package/dist/providers.js.map +2 -2
- package/dist/secrets/credentials.js +10 -2
- package/dist/secrets/credentials.js.map +2 -2
- package/dist/secrets/vault.js +4 -0
- package/dist/secrets/vault.js.map +2 -2
- package/dist/services.js.map +2 -2
- package/dist/settings.js +31 -5
- package/dist/settings.js.map +2 -2
- package/dist/sign-ins.js +25 -0
- package/dist/sign-ins.js.map +7 -0
- package/dist/spectrum/approvals-port.js +26 -2
- package/dist/spectrum/approvals-port.js.map +2 -2
- package/dist/spectrum/mcp-login.js +2 -1
- package/dist/spectrum/mcp-login.js.map +2 -2
- package/dist/spectrum/settings-port.js +65 -11
- package/dist/spectrum/settings-port.js.map +2 -2
- package/dist/types/codex.d.ts +4 -0
- package/dist/types/device.d.ts +24 -0
- package/dist/types/guests/guard.d.ts +1 -0
- package/dist/types/providers.d.ts +1 -0
- package/dist/types/secrets/vault.d.ts +6 -0
- package/dist/types/services.d.ts +2 -1
- package/dist/types/settings.d.ts +4 -0
- package/dist/types/sign-ins.d.ts +17 -0
- package/dist/types/spectrum/approvals-port.d.ts +1 -0
- package/dist/types/spectrum/mcp-login.d.ts +1 -0
- package/dist/types/spectrum/settings-port.d.ts +5 -2
- package/package.json +4 -4
|
@@ -1,8 +1,13 @@
|
|
|
1
|
-
import { BACKGROUND_CONTEXT } from "@earendil-works/chord/context";
|
|
1
|
+
import { BACKGROUND_CONTEXT, withAbortSignal } from "@earendil-works/chord/context";
|
|
2
2
|
import { preferredModel } from "../preferred.js";
|
|
3
|
+
import {
|
|
4
|
+
DEVICE_SIGN_INS,
|
|
5
|
+
httpsUrl,
|
|
6
|
+
SIGN_IN_UNFINISHED
|
|
7
|
+
} from "../sign-ins.js";
|
|
3
8
|
import { attempt } from "./attempt.js";
|
|
4
9
|
import { Emitter } from "./emitter.js";
|
|
5
|
-
import { mcpLogin } from "./mcp-login.js";
|
|
10
|
+
import { mcpLogin, untilAborted } from "./mcp-login.js";
|
|
6
11
|
const SETTINGS_KEY = "slicc-agent.settings";
|
|
7
12
|
const defaults = {
|
|
8
13
|
color: "system",
|
|
@@ -13,7 +18,8 @@ const defaults = {
|
|
|
13
18
|
diffStyle: "unified"
|
|
14
19
|
};
|
|
15
20
|
const SIGN_IN_NEEDS_VAULT = "Adobe sign-in needs seven's vault: update seven";
|
|
16
|
-
const UNFINISHED =
|
|
21
|
+
const UNFINISHED = SIGN_IN_UNFINISHED;
|
|
22
|
+
const openPopup = () => globalThis.open?.("about:blank", "slicc-sign-in", "popup,width=520,height=720") ?? null;
|
|
17
23
|
function readable(error) {
|
|
18
24
|
if (error instanceof DOMException && error.name === "AbortError") return error;
|
|
19
25
|
const text = (error instanceof Error ? error.message : String(error ?? "")).trim();
|
|
@@ -28,12 +34,15 @@ class SettingsAdapter extends Emitter {
|
|
|
28
34
|
#login;
|
|
29
35
|
#mcpLogin;
|
|
30
36
|
#signing = /* @__PURE__ */ new Map();
|
|
37
|
+
#prompts = /* @__PURE__ */ new Map();
|
|
38
|
+
#open;
|
|
31
39
|
#local;
|
|
32
40
|
#offered = "";
|
|
33
41
|
#urls = /* @__PURE__ */ new Map();
|
|
34
|
-
constructor(settings, agent, storage, login = null, mcp = mcpLogin()) {
|
|
42
|
+
constructor(settings, agent, storage, login = null, mcp = mcpLogin(), open = openPopup) {
|
|
35
43
|
super();
|
|
36
44
|
this.#mcpLogin = mcp;
|
|
45
|
+
this.#open = open;
|
|
37
46
|
this.#settings = settings;
|
|
38
47
|
this.#agent = agent;
|
|
39
48
|
this.#storage = storage;
|
|
@@ -126,20 +135,29 @@ class SettingsAdapter extends Emitter {
|
|
|
126
135
|
return this.#state().accounts.map(({ needs, ...account }) => {
|
|
127
136
|
const url = this.#urls.get(account.id);
|
|
128
137
|
const located = url ? { ...account, url } : account;
|
|
129
|
-
const
|
|
138
|
+
const prompt = this.#prompts.get(account.id);
|
|
139
|
+
const shown = this.#signing.has(account.id) ? {
|
|
140
|
+
...located,
|
|
141
|
+
status: "signing-in",
|
|
142
|
+
...prompt ? { signIn: { ...prompt } } : {}
|
|
143
|
+
} : located;
|
|
130
144
|
return needs ? { ...shown, needs } : shown;
|
|
131
145
|
});
|
|
132
146
|
}
|
|
133
|
-
async connect(id, secret, fields) {
|
|
147
|
+
async connect(id, secret, fields, options) {
|
|
134
148
|
const account = this.#state().accounts.find((candidate) => candidate.id === id) ?? this.#offer(id);
|
|
135
149
|
const mcp = account?.group === "mcp";
|
|
136
|
-
const login = account?.auth !== "oauth" ? null : mcp ? this.#mcpLogin : this.#login;
|
|
137
150
|
const given = fields ? { ...fields } : null;
|
|
151
|
+
const keyed = options?.method === "key";
|
|
152
|
+
if (account?.auth === "oauth" && DEVICE_SIGN_INS.has(id) && secret === void 0 && !keyed)
|
|
153
|
+
return this.#device(id, given);
|
|
154
|
+
const login = account?.auth !== "oauth" || keyed ? null : mcp ? this.#mcpLogin : this.#login;
|
|
155
|
+
if (keyed) this.cancel(id);
|
|
138
156
|
if (secret !== void 0) {
|
|
139
157
|
await this.#settings.connect(id, secret, given, BACKGROUND_CONTEXT);
|
|
140
158
|
return;
|
|
141
159
|
}
|
|
142
|
-
if (account?.auth === "oauth" && !login) throw new Error(`${id} needs a sign-in`);
|
|
160
|
+
if (account?.auth === "oauth" && !login && !keyed) throw new Error(`${id} needs a sign-in`);
|
|
143
161
|
if (!login) {
|
|
144
162
|
if (account?.store !== "vault") throw new Error(`${id} needs an API key`);
|
|
145
163
|
await this.#settings.connect(id, null, given, BACKGROUND_CONTEXT);
|
|
@@ -154,11 +172,47 @@ class SettingsAdapter extends Emitter {
|
|
|
154
172
|
if (answer?.sealed !== true) throw new Error(UNFINISHED);
|
|
155
173
|
await this.#settings.connect(id, null, given, BACKGROUND_CONTEXT);
|
|
156
174
|
}
|
|
157
|
-
|
|
175
|
+
#begin(id) {
|
|
158
176
|
const controller = new AbortController();
|
|
159
177
|
this.#signing.get(id)?.abort(new DOMException("A newer sign-in replaced this one.", "AbortError"));
|
|
160
178
|
this.#signing.set(id, controller);
|
|
179
|
+
this.#prompts.delete(id);
|
|
180
|
+
this.emit("accounts", this.accounts());
|
|
181
|
+
return controller;
|
|
182
|
+
}
|
|
183
|
+
#end(id, controller) {
|
|
184
|
+
if (this.#signing.get(id) === controller) {
|
|
185
|
+
this.#signing.delete(id);
|
|
186
|
+
this.#prompts.delete(id);
|
|
187
|
+
}
|
|
161
188
|
this.emit("accounts", this.accounts());
|
|
189
|
+
}
|
|
190
|
+
async #device(id, given) {
|
|
191
|
+
const popup = this.#open();
|
|
192
|
+
const controller = this.#begin(id);
|
|
193
|
+
const { signal } = controller;
|
|
194
|
+
const context = withAbortSignal(signal, BACKGROUND_CONTEXT);
|
|
195
|
+
try {
|
|
196
|
+
const started = await untilAborted(
|
|
197
|
+
this.#settings.signIn(id, context),
|
|
198
|
+
signal
|
|
199
|
+
);
|
|
200
|
+
if (!started || !httpsUrl(started.url)) throw new Error(UNFINISHED);
|
|
201
|
+
const code = typeof started.code === "string" && started.code ? started.code : void 0;
|
|
202
|
+
this.#prompts.set(id, { url: started.url, ...code ? { code } : {} });
|
|
203
|
+
this.emit("accounts", this.accounts());
|
|
204
|
+
if (popup) popup.location.href = started.url;
|
|
205
|
+
await untilAborted(this.#settings.connect(id, null, given, context), signal);
|
|
206
|
+
} catch (error) {
|
|
207
|
+
signal.throwIfAborted();
|
|
208
|
+
throw readable(error);
|
|
209
|
+
} finally {
|
|
210
|
+
popup?.close();
|
|
211
|
+
this.#end(id, controller);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
async #signIn(id, login) {
|
|
215
|
+
const controller = this.#begin(id);
|
|
162
216
|
try {
|
|
163
217
|
const key = await login(
|
|
164
218
|
id,
|
|
@@ -173,14 +227,14 @@ class SettingsAdapter extends Emitter {
|
|
|
173
227
|
controller.signal.throwIfAborted();
|
|
174
228
|
return key;
|
|
175
229
|
} finally {
|
|
176
|
-
|
|
177
|
-
this.emit("accounts", this.accounts());
|
|
230
|
+
this.#end(id, controller);
|
|
178
231
|
}
|
|
179
232
|
}
|
|
180
233
|
cancel(id) {
|
|
181
234
|
const controller = this.#signing.get(id);
|
|
182
235
|
if (!controller) return;
|
|
183
236
|
this.#signing.delete(id);
|
|
237
|
+
this.#prompts.delete(id);
|
|
184
238
|
controller.abort(new DOMException("The sign-in was cancelled.", "AbortError"));
|
|
185
239
|
this.emit("accounts", this.accounts());
|
|
186
240
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/spectrum/settings-port.ts"],
|
|
4
|
-
"sourcesContent": ["import type {\n Account,\n ModelOption,\n Settings,\n SettingsEvents,\n SettingsPort,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport { BACKGROUND_CONTEXT } from '@earendil-works/chord/context';\nimport { preferredModel } from '../preferred.ts';\nimport type { AgentSettings, ProviderOption, SettingsState, SignIn } from '../services.ts';\nimport type { AgentAdapter } from './agent-port.ts';\nimport { attempt } from './attempt.ts';\nimport { Emitter } from './emitter.ts';\nimport { mcpLogin } from './mcp-login.ts';\n\nexport const SETTINGS_KEY = 'slicc-agent.settings';\n\nconst defaults: Settings = {\n color: 'system',\n model: '',\n thinking: 'off',\n sendOnEnter: true,\n showThinking: false,\n diffStyle: 'unified',\n};\n\ntype Local = Omit<Settings, 'model' | 'thinking'>;\n\nexport type Sealed = { sealed: true };\n\nexport type Login = (\n providerId: string,\n signIn: () => Promise<SignIn | null>,\n options: { signal: AbortSignal }\n) => Promise<string | Sealed>;\n\nexport const SIGN_IN_NEEDS_VAULT = \"Adobe sign-in needs seven's vault: update seven\";\nexport const UNFINISHED = \"The sign-in didn't finish. Try again.\";\n\nexport function readable(error: unknown): Error {\n if (error instanceof DOMException && error.name === 'AbortError') return error;\n const text = (error instanceof Error ? error.message : String(error ?? '')).trim();\n if (!text) return new Error(UNFINISHED);\n const lead = /^[a-z]+\\b(?![-.@/])/.test(text) ? text[0].toUpperCase() + text.slice(1) : text;\n return new Error(/[.!?]$/.test(lead) ? lead : `${lead}.`);\n}\n\ntype Events = SettingsEvents & { providers: readonly ProviderOption[] };\n\nexport class SettingsAdapter extends Emitter<Events> implements SettingsPort {\n readonly #settings: AgentSettings;\n readonly #agent: AgentAdapter;\n readonly #storage: Pick<Storage, 'getItem' | 'setItem'> | null;\n readonly #login: Login | null;\n readonly #mcpLogin: Login;\n readonly #signing = new Map<string, AbortController>();\n #local: Local;\n #offered = '';\n readonly #urls = new Map<string, string>();\n\n constructor(\n settings: AgentSettings,\n agent: AgentAdapter,\n storage: Pick<Storage, 'getItem' | 'setItem'> | null,\n login: Login | null = null,\n mcp: Login = mcpLogin() as Login\n ) {\n super();\n this.#mcpLogin = mcp;\n this.#settings = settings;\n this.#agent = agent;\n this.#storage = storage;\n this.#login = login;\n const saved = JSON.parse(storage?.getItem(SETTINGS_KEY) ?? '{}') as Partial<Local>;\n const { model: _model, thinking: _thinking, ...local } = { ...defaults, ...saved };\n this.#local = local;\n this.#offered = JSON.stringify(this.providers());\n this.#locate();\n settings.state.subscribe(() => {\n this.#locate();\n this.emit('accounts', this.accounts());\n this.emit('settings', this.get());\n const offered = JSON.stringify(this.providers());\n if (offered === this.#offered) return;\n this.#offered = offered;\n this.emit('providers', this.providers());\n });\n agent.on('agents', () => this.emit('settings', this.get()));\n }\n\n #locate(): void {\n const servers = this.#state()\n .accounts.filter(({ group }) => group === 'mcp')\n .map(({ id }) => id);\n for (const id of this.#urls.keys()) if (!servers.includes(id)) this.#urls.delete(id);\n for (const id of servers) {\n void this.#settings\n .serverUrl?.(id, BACKGROUND_CONTEXT)\n .then((url) => {\n if ((url ?? undefined) === this.#urls.get(id)) return;\n if (url) this.#urls.set(id, url);\n else this.#urls.delete(id);\n this.emit('accounts', this.accounts());\n })\n .catch(() => undefined);\n }\n }\n\n #state(): SettingsState {\n return this.#settings.state.value ?? { models: [], accounts: [] };\n }\n\n get(): Settings {\n const cone = this.#agent.list()[0];\n return { ...this.#local, model: cone?.model ?? '', thinking: cone?.thinking ?? 'off' };\n }\n\n update(patch: Partial<Settings>): void {\n const { model, thinking, ...local } = patch;\n const id = this.#agent.active();\n if (model !== undefined) this.#agent.setModel(id, model);\n if (thinking !== undefined) this.#agent.setThinking(id, thinking);\n this.#local = { ...this.#local, ...local };\n this.#storage?.setItem(SETTINGS_KEY, JSON.stringify(this.#local));\n this.emit('settings', this.get());\n }\n\n models(): readonly ModelOption[] {\n const choices = this.#state().models;\n const groups = Map.groupBy(choices, ({ id }) => id.slice(0, id.indexOf('/')));\n const chosen = new Set(\n [...groups].map(\n ([providerId, group]) =>\n preferredModel(\n providerId,\n group.map((choice) => ({ id: choice.id.slice(providerId.length + 1), choice }))\n )?.choice\n )\n );\n return choices.map((choice) => {\n const { id, label, provider, kind, reasoning, images } = choice;\n return {\n id,\n label,\n provider,\n kind,\n reasoning,\n ...(images === undefined ? {} : { images }),\n ...(chosen.has(choice) ? { default: true } : {}),\n };\n });\n }\n\n #offer(id: string) {\n const option = this.providers().find((candidate) => candidate.id === id);\n if (!option) return undefined;\n return {\n auth: option.auth === 'oauth' ? ('oauth' as const) : ('api-key' as const),\n store: 'vault' as const,\n group: 'providers' as const,\n };\n }\n\n providers(): readonly ProviderOption[] {\n return this.#state().providers ?? [];\n }\n\n async remove(id: string): Promise<void> {\n this.cancel(id);\n await this.#settings.remove(id, BACKGROUND_CONTEXT);\n }\n\n accounts(): readonly Account[] {\n return this.#state().accounts.map(({ needs, ...account }) => {\n const url = this.#urls.get(account.id);\n const located = url ? { ...account, url } : account;\n const shown = this.#signing.has(account.id)\n ? { ...located, status: 'signing-in' as const }\n : located;\n return needs ? { ...shown, needs } : shown;\n });\n }\n\n async connect(id: string, secret?: string, fields?: Record<string, string>): Promise<void> {\n const account =\n this.#state().accounts.find((candidate) => candidate.id === id) ?? this.#offer(id);\n const mcp = account?.group === 'mcp';\n const login = account?.auth !== 'oauth' ? null : mcp ? this.#mcpLogin : this.#login;\n const given = fields ? { ...fields } : null;\n if (secret !== undefined) {\n await this.#settings.connect(id, secret, given, BACKGROUND_CONTEXT);\n return;\n }\n if (account?.auth === 'oauth' && !login) throw new Error(`${id} needs a sign-in`);\n if (!login) {\n if (account?.store !== 'vault') throw new Error(`${id} needs an API key`);\n await this.#settings.connect(id, null, given, BACKGROUND_CONTEXT);\n return;\n }\n const answer = await this.#signIn(id, login);\n if (typeof answer === 'string') {\n if (!mcp) throw new Error(SIGN_IN_NEEDS_VAULT);\n await this.#settings.connect(id, answer, given, BACKGROUND_CONTEXT);\n return;\n }\n if (answer?.sealed !== true) throw new Error(UNFINISHED);\n await this.#settings.connect(id, null, given, BACKGROUND_CONTEXT);\n }\n\n async #signIn(id: string, login: Login): Promise<string | Sealed> {\n const controller = new AbortController();\n this.#signing\n .get(id)\n ?.abort(new DOMException('A newer sign-in replaced this one.', 'AbortError'));\n this.#signing.set(id, controller);\n this.emit('accounts', this.accounts());\n try {\n const key = await login(\n id,\n () => this.#settings.signIn(id, BACKGROUND_CONTEXT) as Promise<SignIn | null>,\n {\n signal: controller.signal,\n }\n ).catch((error: unknown) => {\n controller.signal.throwIfAborted();\n throw readable(error);\n });\n controller.signal.throwIfAborted();\n return key;\n } finally {\n if (this.#signing.get(id) === controller) this.#signing.delete(id);\n this.emit('accounts', this.accounts());\n }\n }\n\n cancel(id: string): void {\n const controller = this.#signing.get(id);\n if (!controller) return;\n this.#signing.delete(id);\n controller.abort(new DOMException('The sign-in was cancelled.', 'AbortError'));\n this.emit('accounts', this.accounts());\n }\n\n disconnect(id: string): void {\n attempt(this.#settings.disconnect(id, BACKGROUND_CONTEXT), 'disconnect accounts', (text) =>\n this.#agent.notify(text)\n );\n }\n}\n"],
|
|
5
|
-
"mappings": "AAOA,SAAS,
|
|
4
|
+
"sourcesContent": ["import type {\n Account,\n ModelOption,\n Settings,\n SettingsEvents,\n SettingsPort,\n} from '@ai-ecoverse/slicc-spectrum/ui';\nimport { BACKGROUND_CONTEXT, withAbortSignal } from '@earendil-works/chord/context';\nimport { preferredModel } from '../preferred.ts';\nimport type { AgentSettings, ProviderOption, SettingsState, SignIn } from '../services.ts';\nimport {\n type ConnectOptions,\n DEVICE_SIGN_INS,\n type DeviceSignIn,\n httpsUrl,\n SIGN_IN_UNFINISHED,\n} from '../sign-ins.ts';\nimport type { AgentAdapter } from './agent-port.ts';\nimport { attempt } from './attempt.ts';\nimport { Emitter } from './emitter.ts';\nimport { mcpLogin, type Popup, untilAborted } from './mcp-login.ts';\n\nexport const SETTINGS_KEY = 'slicc-agent.settings';\n\nconst defaults: Settings = {\n color: 'system',\n model: '',\n thinking: 'off',\n sendOnEnter: true,\n showThinking: false,\n diffStyle: 'unified',\n};\n\ntype Local = Omit<Settings, 'model' | 'thinking'>;\n\nexport type Sealed = { sealed: true };\n\nexport type Login = (\n providerId: string,\n signIn: () => Promise<SignIn | null>,\n options: { signal: AbortSignal }\n) => Promise<string | Sealed>;\n\nexport const SIGN_IN_NEEDS_VAULT = \"Adobe sign-in needs seven's vault: update seven\";\nexport const UNFINISHED = SIGN_IN_UNFINISHED;\n\nexport type OpenPopup = () => Popup | null;\n\nconst openPopup: OpenPopup = () =>\n globalThis.open?.('about:blank', 'slicc-sign-in', 'popup,width=520,height=720') ?? null;\n\nexport function readable(error: unknown): Error {\n if (error instanceof DOMException && error.name === 'AbortError') return error;\n const text = (error instanceof Error ? error.message : String(error ?? '')).trim();\n if (!text) return new Error(UNFINISHED);\n const lead = /^[a-z]+\\b(?![-.@/])/.test(text) ? text[0].toUpperCase() + text.slice(1) : text;\n return new Error(/[.!?]$/.test(lead) ? lead : `${lead}.`);\n}\n\ntype Events = SettingsEvents & { providers: readonly ProviderOption[] };\n\nexport class SettingsAdapter extends Emitter<Events> implements SettingsPort {\n readonly #settings: AgentSettings;\n readonly #agent: AgentAdapter;\n readonly #storage: Pick<Storage, 'getItem' | 'setItem'> | null;\n readonly #login: Login | null;\n readonly #mcpLogin: Login;\n readonly #signing = new Map<string, AbortController>();\n readonly #prompts = new Map<string, DeviceSignIn>();\n readonly #open: OpenPopup;\n #local: Local;\n #offered = '';\n readonly #urls = new Map<string, string>();\n\n constructor(\n settings: AgentSettings,\n agent: AgentAdapter,\n storage: Pick<Storage, 'getItem' | 'setItem'> | null,\n login: Login | null = null,\n mcp: Login = mcpLogin() as Login,\n open: OpenPopup = openPopup\n ) {\n super();\n this.#mcpLogin = mcp;\n this.#open = open;\n this.#settings = settings;\n this.#agent = agent;\n this.#storage = storage;\n this.#login = login;\n const saved = JSON.parse(storage?.getItem(SETTINGS_KEY) ?? '{}') as Partial<Local>;\n const { model: _model, thinking: _thinking, ...local } = { ...defaults, ...saved };\n this.#local = local;\n this.#offered = JSON.stringify(this.providers());\n this.#locate();\n settings.state.subscribe(() => {\n this.#locate();\n this.emit('accounts', this.accounts());\n this.emit('settings', this.get());\n const offered = JSON.stringify(this.providers());\n if (offered === this.#offered) return;\n this.#offered = offered;\n this.emit('providers', this.providers());\n });\n agent.on('agents', () => this.emit('settings', this.get()));\n }\n\n #locate(): void {\n const servers = this.#state()\n .accounts.filter(({ group }) => group === 'mcp')\n .map(({ id }) => id);\n for (const id of this.#urls.keys()) if (!servers.includes(id)) this.#urls.delete(id);\n for (const id of servers) {\n void this.#settings\n .serverUrl?.(id, BACKGROUND_CONTEXT)\n .then((url) => {\n if ((url ?? undefined) === this.#urls.get(id)) return;\n if (url) this.#urls.set(id, url);\n else this.#urls.delete(id);\n this.emit('accounts', this.accounts());\n })\n .catch(() => undefined);\n }\n }\n\n #state(): SettingsState {\n return this.#settings.state.value ?? { models: [], accounts: [] };\n }\n\n get(): Settings {\n const cone = this.#agent.list()[0];\n return { ...this.#local, model: cone?.model ?? '', thinking: cone?.thinking ?? 'off' };\n }\n\n update(patch: Partial<Settings>): void {\n const { model, thinking, ...local } = patch;\n const id = this.#agent.active();\n if (model !== undefined) this.#agent.setModel(id, model);\n if (thinking !== undefined) this.#agent.setThinking(id, thinking);\n this.#local = { ...this.#local, ...local };\n this.#storage?.setItem(SETTINGS_KEY, JSON.stringify(this.#local));\n this.emit('settings', this.get());\n }\n\n models(): readonly ModelOption[] {\n const choices = this.#state().models;\n const groups = Map.groupBy(choices, ({ id }) => id.slice(0, id.indexOf('/')));\n const chosen = new Set(\n [...groups].map(\n ([providerId, group]) =>\n preferredModel(\n providerId,\n group.map((choice) => ({ id: choice.id.slice(providerId.length + 1), choice }))\n )?.choice\n )\n );\n return choices.map((choice) => {\n const { id, label, provider, kind, reasoning, images } = choice;\n return {\n id,\n label,\n provider,\n kind,\n reasoning,\n ...(images === undefined ? {} : { images }),\n ...(chosen.has(choice) ? { default: true } : {}),\n };\n });\n }\n\n #offer(id: string) {\n const option = this.providers().find((candidate) => candidate.id === id);\n if (!option) return undefined;\n return {\n auth: option.auth === 'oauth' ? ('oauth' as const) : ('api-key' as const),\n store: 'vault' as const,\n group: 'providers' as const,\n };\n }\n\n providers(): readonly ProviderOption[] {\n return this.#state().providers ?? [];\n }\n\n async remove(id: string): Promise<void> {\n this.cancel(id);\n await this.#settings.remove(id, BACKGROUND_CONTEXT);\n }\n\n accounts(): readonly Account[] {\n return this.#state().accounts.map(({ needs, ...account }) => {\n const url = this.#urls.get(account.id);\n const located = url ? { ...account, url } : account;\n const prompt = this.#prompts.get(account.id);\n const shown = this.#signing.has(account.id)\n ? {\n ...located,\n status: 'signing-in' as const,\n ...(prompt ? { signIn: { ...prompt } } : {}),\n }\n : located;\n return needs ? { ...shown, needs } : shown;\n });\n }\n\n async connect(\n id: string,\n secret?: string,\n fields?: Record<string, string>,\n options?: ConnectOptions\n ): Promise<void> {\n const account =\n this.#state().accounts.find((candidate) => candidate.id === id) ?? this.#offer(id);\n const mcp = account?.group === 'mcp';\n const given = fields ? { ...fields } : null;\n const keyed = options?.method === 'key';\n if (account?.auth === 'oauth' && DEVICE_SIGN_INS.has(id) && secret === undefined && !keyed)\n return this.#device(id, given);\n const login = account?.auth !== 'oauth' || keyed ? null : mcp ? this.#mcpLogin : this.#login;\n if (keyed) this.cancel(id);\n if (secret !== undefined) {\n await this.#settings.connect(id, secret, given, BACKGROUND_CONTEXT);\n return;\n }\n if (account?.auth === 'oauth' && !login && !keyed) throw new Error(`${id} needs a sign-in`);\n if (!login) {\n if (account?.store !== 'vault') throw new Error(`${id} needs an API key`);\n await this.#settings.connect(id, null, given, BACKGROUND_CONTEXT);\n return;\n }\n const answer = await this.#signIn(id, login);\n if (typeof answer === 'string') {\n if (!mcp) throw new Error(SIGN_IN_NEEDS_VAULT);\n await this.#settings.connect(id, answer, given, BACKGROUND_CONTEXT);\n return;\n }\n if (answer?.sealed !== true) throw new Error(UNFINISHED);\n await this.#settings.connect(id, null, given, BACKGROUND_CONTEXT);\n }\n\n #begin(id: string): AbortController {\n const controller = new AbortController();\n this.#signing\n .get(id)\n ?.abort(new DOMException('A newer sign-in replaced this one.', 'AbortError'));\n this.#signing.set(id, controller);\n this.#prompts.delete(id);\n this.emit('accounts', this.accounts());\n return controller;\n }\n\n #end(id: string, controller: AbortController): void {\n if (this.#signing.get(id) === controller) {\n this.#signing.delete(id);\n this.#prompts.delete(id);\n }\n this.emit('accounts', this.accounts());\n }\n\n async #device(id: string, given: Record<string, string> | null): Promise<void> {\n const popup = this.#open();\n const controller = this.#begin(id);\n const { signal } = controller;\n const context = withAbortSignal(signal, BACKGROUND_CONTEXT);\n try {\n const started = (await untilAborted(\n this.#settings.signIn(id, context),\n signal\n )) as DeviceSignIn | null;\n if (!started || !httpsUrl(started.url)) throw new Error(UNFINISHED);\n const code = typeof started.code === 'string' && started.code ? started.code : undefined;\n this.#prompts.set(id, { url: started.url, ...(code ? { code } : {}) });\n this.emit('accounts', this.accounts());\n if (popup) popup.location.href = started.url;\n await untilAborted(this.#settings.connect(id, null, given, context), signal);\n } catch (error) {\n signal.throwIfAborted();\n throw readable(error);\n } finally {\n popup?.close();\n this.#end(id, controller);\n }\n }\n\n async #signIn(id: string, login: Login): Promise<string | Sealed> {\n const controller = this.#begin(id);\n try {\n const key = await login(\n id,\n () => this.#settings.signIn(id, BACKGROUND_CONTEXT) as Promise<SignIn | null>,\n {\n signal: controller.signal,\n }\n ).catch((error: unknown) => {\n controller.signal.throwIfAborted();\n throw readable(error);\n });\n controller.signal.throwIfAborted();\n return key;\n } finally {\n this.#end(id, controller);\n }\n }\n\n cancel(id: string): void {\n const controller = this.#signing.get(id);\n if (!controller) return;\n this.#signing.delete(id);\n this.#prompts.delete(id);\n controller.abort(new DOMException('The sign-in was cancelled.', 'AbortError'));\n this.emit('accounts', this.accounts());\n }\n\n disconnect(id: string): void {\n attempt(this.#settings.disconnect(id, BACKGROUND_CONTEXT), 'disconnect accounts', (text) =>\n this.#agent.notify(text)\n );\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import type { Context } from '@earendil-works/chord';
|
|
2
|
+
import type { OAuthCredential, Provider } from '@earendil-works/pi-ai';
|
|
3
|
+
import { type DeviceSignIn } from './sign-ins.ts';
|
|
4
|
+
export declare const ATTACH_MS = 60000;
|
|
5
|
+
export interface ProviderGrant {
|
|
6
|
+
provider: string;
|
|
7
|
+
name: string;
|
|
8
|
+
response: Uint8Array;
|
|
9
|
+
settings?: Record<string, string>;
|
|
10
|
+
}
|
|
11
|
+
export type Grant = (grant: ProviderGrant) => Promise<unknown>;
|
|
12
|
+
export interface DeviceFlows {
|
|
13
|
+
has(providerId: string): boolean;
|
|
14
|
+
start(provider: Provider, name: string, context: Context): Promise<DeviceSignIn>;
|
|
15
|
+
finish(providerId: string, context: Context): Promise<void>;
|
|
16
|
+
stop(providerId: string): void;
|
|
17
|
+
}
|
|
18
|
+
export declare function keptError(error: unknown): Error;
|
|
19
|
+
export declare function flowError(error: unknown): Error;
|
|
20
|
+
export declare function tokenResponse(credential: OAuthCredential, now: number): Uint8Array;
|
|
21
|
+
export declare function deviceFlows(grant: Grant, options?: {
|
|
22
|
+
attachMs?: number;
|
|
23
|
+
now?: () => number;
|
|
24
|
+
}): DeviceFlows;
|
|
@@ -31,6 +31,7 @@ type Taint = {
|
|
|
31
31
|
tier: string;
|
|
32
32
|
};
|
|
33
33
|
export declare function canonical(value: unknown): string;
|
|
34
|
+
export declare function scrubbedArguments(args: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
34
35
|
export declare function summaryOf(args: Record<string, unknown>): string;
|
|
35
36
|
export declare function reasonOf(item: Approval): string;
|
|
36
37
|
export declare function taintsOf(inputs: readonly SubmissionId[], seats: Readonly<Record<string, SeatRecord>>, harness: Pick<Harness, 'submission'>, context: Context): Promise<Taint[]>;
|
|
@@ -49,6 +49,12 @@ export declare class Vault implements Scrub {
|
|
|
49
49
|
mcp(server: string, request: OutgoingRequest): Promise<OutgoingRequest>;
|
|
50
50
|
records(): Promise<AgentRecord[]>;
|
|
51
51
|
grant(server: string, response: string | Uint8Array, oauth: OAuthConfig, name?: string): Promise<Granted>;
|
|
52
|
+
grantProvider(grant: {
|
|
53
|
+
provider: string;
|
|
54
|
+
name: string;
|
|
55
|
+
response: Uint8Array;
|
|
56
|
+
settings?: Record<string, string>;
|
|
57
|
+
}): Promise<Omit<Granted, 'response'>>;
|
|
52
58
|
refresh(target: RefreshTarget, name?: string): Promise<string>;
|
|
53
59
|
endpoints(set: EndpointSet): Promise<void>;
|
|
54
60
|
stream(): ScrubStream;
|
package/dist/types/services.d.ts
CHANGED
|
@@ -11,6 +11,7 @@ import type { GuestDraft, GuestGates, GuestSeat } from './guests/seats.ts';
|
|
|
11
11
|
import type { MemoryEntry, MemoryScope, MemoryTag } from './memory/format.ts';
|
|
12
12
|
import type { AgentRemote } from './remote/host.ts';
|
|
13
13
|
import type { VaultState } from './secrets/vault.ts';
|
|
14
|
+
import type { DeviceSignIn } from './sign-ins.ts';
|
|
14
15
|
import type { SkillPackage, SkillSource } from './skills/skills.ts';
|
|
15
16
|
import type { Sprinkle } from './sprinkles/kind.ts';
|
|
16
17
|
export type SendMode = 'steer' | 'followUp' | 'reject';
|
|
@@ -409,7 +410,7 @@ export interface AgentSettings {
|
|
|
409
410
|
disconnect(providerId: string, context: Context): Promise<void>;
|
|
410
411
|
remove(providerId: string, context: Context): Promise<void>;
|
|
411
412
|
serverUrl(providerId: string, context: Context): Promise<string | null>;
|
|
412
|
-
signIn(providerId: string, context: Context): Promise<SignIn | McpSignIn | null>;
|
|
413
|
+
signIn(providerId: string, context: Context): Promise<SignIn | McpSignIn | DeviceSignIn | null>;
|
|
413
414
|
dismissMoved(context: Context): Promise<void>;
|
|
414
415
|
}
|
|
415
416
|
export declare const SETTINGS_METHODS: ("connect" | "disconnect" | "dismissMoved" | "remove" | "serverUrl" | "signIn")[];
|
package/dist/types/settings.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import type { CredentialStore, ModelsStore, Provider } from '@earendil-works/pi-ai';
|
|
2
2
|
import { type MutableModels } from '@earendil-works/pi-ai/models';
|
|
3
3
|
import { type Budget } from './adobe.ts';
|
|
4
|
+
import { type DeviceFlows } from './device.ts';
|
|
4
5
|
import type { McpAccounts } from './mcp/index.ts';
|
|
5
6
|
import type { Reach } from './net.ts';
|
|
6
7
|
import type { KeysMoved } from './secrets/legacy.ts';
|
|
7
8
|
import type { VaultRecords } from './secrets/records.ts';
|
|
8
9
|
import type { PlainStore } from './secrets/store.ts';
|
|
10
|
+
import type { Vault } from './secrets/vault.ts';
|
|
9
11
|
import type { AccountField, AgentSettings } from './services.ts';
|
|
10
12
|
export { BEDROCK, PREFERRED_MODELS, preferredModel } from './preferred.ts';
|
|
11
13
|
export declare const DEFAULT_MODEL: {
|
|
@@ -45,4 +47,6 @@ export declare function createAgentSettings(models: MutableModels, sources: Sett
|
|
|
45
47
|
mcp?: McpAccounts;
|
|
46
48
|
moved?: KeysMoved;
|
|
47
49
|
reach?: Reach;
|
|
50
|
+
vault?: Pick<Vault, 'connected' | 'needed' | 'grantProvider'>;
|
|
51
|
+
flows?: DeviceFlows;
|
|
48
52
|
}): Promise<AgentSettings>;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export declare const CODEX = "openai-codex";
|
|
2
|
+
export declare const CODEX_ACCOUNT = "CHATGPT_ACCOUNT_ID";
|
|
3
|
+
export declare const DEVICE_SIGN_INS: ReadonlySet<string>;
|
|
4
|
+
export declare const SIGN_IN_REFUSED = "The sign-in was refused.";
|
|
5
|
+
export declare const SIGN_IN_UNFINISHED = "The sign-in didn't finish. Try again.";
|
|
6
|
+
export declare const NAME_TAKEN = "This name holds another provider's key.";
|
|
7
|
+
export declare const SIGN_IN_LOCKED = "Unlock the vault to sign in.";
|
|
8
|
+
export declare const SIGN_IN_UNKEPT = "The vault didn't keep the sign-in. Try again.";
|
|
9
|
+
export declare const DEVICE_NEEDS_VAULT = "Signing in needs seven's vault: update seven";
|
|
10
|
+
export interface DeviceSignIn {
|
|
11
|
+
url: string;
|
|
12
|
+
code?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ConnectOptions {
|
|
15
|
+
method?: 'sign-in' | 'key';
|
|
16
|
+
}
|
|
17
|
+
export declare function httpsUrl(value: unknown): value is string;
|
|
@@ -2,6 +2,7 @@ import type { Approval, ApprovalDecision, ApprovalsEvents, ApprovalsPort } from
|
|
|
2
2
|
import type { Approval as Item } from '../approvals/record.ts';
|
|
3
3
|
import type { AgentConnection } from '../client.ts';
|
|
4
4
|
import { Emitter } from './emitter.ts';
|
|
5
|
+
export declare const ARGS_LENGTH = 65536;
|
|
5
6
|
export declare function shown(item: Item, agentName: string | undefined): Approval;
|
|
6
7
|
export type HostApprovals = ApprovalsPort;
|
|
7
8
|
export declare const NOT_HERE = "This request can't be answered in this tab.";
|
|
@@ -21,6 +21,7 @@ export interface McpLoginHost {
|
|
|
21
21
|
timeoutMs?: number;
|
|
22
22
|
}
|
|
23
23
|
export declare function safeAuthorizationUrl(value: string): boolean;
|
|
24
|
+
export declare function untilAborted<T>(promise: Promise<T>, signal: AbortSignal): Promise<T>;
|
|
24
25
|
export declare function mcpLogin(host?: McpLoginHost): (providerId: string, signIn: () => Promise<SignIn | McpSignIn | null>, options: {
|
|
25
26
|
signal: AbortSignal;
|
|
26
27
|
}) => Promise<string>;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { Account, ModelOption, Settings, SettingsEvents, SettingsPort } from '@ai-ecoverse/slicc-spectrum/ui';
|
|
2
2
|
import type { AgentSettings, ProviderOption, SignIn } from '../services.ts';
|
|
3
|
+
import { type ConnectOptions } from '../sign-ins.ts';
|
|
3
4
|
import type { AgentAdapter } from './agent-port.ts';
|
|
4
5
|
import { Emitter } from './emitter.ts';
|
|
6
|
+
import { type Popup } from './mcp-login.ts';
|
|
5
7
|
export declare const SETTINGS_KEY = "slicc-agent.settings";
|
|
6
8
|
export type Sealed = {
|
|
7
9
|
sealed: true;
|
|
@@ -11,20 +13,21 @@ export type Login = (providerId: string, signIn: () => Promise<SignIn | null>, o
|
|
|
11
13
|
}) => Promise<string | Sealed>;
|
|
12
14
|
export declare const SIGN_IN_NEEDS_VAULT = "Adobe sign-in needs seven's vault: update seven";
|
|
13
15
|
export declare const UNFINISHED = "The sign-in didn't finish. Try again.";
|
|
16
|
+
export type OpenPopup = () => Popup | null;
|
|
14
17
|
export declare function readable(error: unknown): Error;
|
|
15
18
|
type Events = SettingsEvents & {
|
|
16
19
|
providers: readonly ProviderOption[];
|
|
17
20
|
};
|
|
18
21
|
export declare class SettingsAdapter extends Emitter<Events> implements SettingsPort {
|
|
19
22
|
#private;
|
|
20
|
-
constructor(settings: AgentSettings, agent: AgentAdapter, storage: Pick<Storage, 'getItem' | 'setItem'> | null, login?: Login | null, mcp?: Login);
|
|
23
|
+
constructor(settings: AgentSettings, agent: AgentAdapter, storage: Pick<Storage, 'getItem' | 'setItem'> | null, login?: Login | null, mcp?: Login, open?: OpenPopup);
|
|
21
24
|
get(): Settings;
|
|
22
25
|
update(patch: Partial<Settings>): void;
|
|
23
26
|
models(): readonly ModelOption[];
|
|
24
27
|
providers(): readonly ProviderOption[];
|
|
25
28
|
remove(id: string): Promise<void>;
|
|
26
29
|
accounts(): readonly Account[];
|
|
27
|
-
connect(id: string, secret?: string, fields?: Record<string, string
|
|
30
|
+
connect(id: string, secret?: string, fields?: Record<string, string>, options?: ConnectOptions): Promise<void>;
|
|
28
31
|
cancel(id: string): void;
|
|
29
32
|
disconnect(id: string): void;
|
|
30
33
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-ecoverse/slicc-agent",
|
|
3
|
-
"version": "6.
|
|
3
|
+
"version": "6.17.0",
|
|
4
4
|
"description": "SLICC's agent core on pi durable: an agent worker, session storage, remoting and pi extensions",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -65,10 +65,10 @@
|
|
|
65
65
|
"release": "semantic-release"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
|
-
"@ai-ecoverse/slicc-kernel": "1.134.
|
|
68
|
+
"@ai-ecoverse/slicc-kernel": "1.134.3",
|
|
69
69
|
"@ai-ecoverse/slicc-scrub": "1.0.0",
|
|
70
|
-
"@ai-ecoverse/slicc-shared-web": "1.
|
|
71
|
-
"@ai-ecoverse/slicc-spectrum": "1.101.
|
|
70
|
+
"@ai-ecoverse/slicc-shared-web": "1.27.0",
|
|
71
|
+
"@ai-ecoverse/slicc-spectrum": "1.101.2",
|
|
72
72
|
"@ai-ecoverse/wasi-fnox": "1.39.0-5",
|
|
73
73
|
"@ai-ecoverse/wasm-bash": "5.3.0-21",
|
|
74
74
|
"@ai-ecoverse/wasm-coreutils": "9.12.0-10",
|