@adonis-agora/agent 0.94.0 → 0.96.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/CHANGELOG.md +16 -0
- package/dist/assets/spa/assets/{index-DUq09Q_k.js → index-DBu17cDY.js} +1 -1
- package/dist/assets/spa/index.html +1 -1
- package/dist/providers/poppy_connections_provider.d.ts +1 -1
- package/dist/providers/poppy_connections_provider.js +1 -1
- package/dist/providers/poppy_provider.d.ts +1 -1
- package/dist/providers/poppy_provider.d.ts.map +1 -1
- package/dist/providers/poppy_provider.js +6 -6
- package/dist/providers/poppy_provider.js.map +1 -1
- package/dist/src/index.d.ts +1 -1
- package/dist/src/index.js +1 -1
- package/dist/src/mcp/auth.d.ts +3 -3
- package/dist/src/mcp/auth.d.ts.map +1 -1
- package/dist/src/mcp/auth.js +2 -29
- package/dist/src/mcp/auth.js.map +1 -1
- package/dist/src/mcp/discovery.d.ts +3 -3
- package/dist/src/mcp/discovery.d.ts.map +1 -1
- package/dist/src/mcp/discovery.js +2 -2
- package/dist/src/poppy/auth.d.ts +20 -16
- package/dist/src/poppy/auth.d.ts.map +1 -1
- package/dist/src/poppy/auth.js.map +1 -1
- package/dist/src/poppy/conversations.d.ts +25 -25
- package/dist/src/poppy/conversations.d.ts.map +1 -1
- package/dist/src/poppy/conversations.js +37 -37
- package/dist/src/poppy/conversations.js.map +1 -1
- package/dist/src/poppy/define_config.d.ts +7 -7
- package/dist/src/poppy/define_config.d.ts.map +1 -1
- package/dist/src/poppy/define_config.js +1 -1
- package/dist/src/poppy/endpoints.d.ts +2 -2
- package/dist/src/poppy/endpoints.js +1 -1
- package/dist/src/poppy/handler.d.ts +5 -5
- package/dist/src/poppy/handler.d.ts.map +1 -1
- package/dist/src/poppy/handler.js +23 -21
- package/dist/src/poppy/handler.js.map +1 -1
- package/dist/src/poppy/index.d.ts +2 -2
- package/dist/src/poppy/index.d.ts.map +1 -1
- package/dist/src/poppy/index.js +1 -1
- package/dist/src/poppy/index.js.map +1 -1
- package/dist/src/poppy/protocol.d.ts +30 -23
- package/dist/src/poppy/protocol.d.ts.map +1 -1
- package/dist/src/poppy/protocol.js +16 -17
- package/dist/src/poppy/protocol.js.map +1 -1
- package/dist/src/poppy/redis-store.d.ts +1 -1
- package/dist/src/poppy/redis-store.js +1 -1
- package/dist/src/poppy/store.d.ts +7 -7
- package/dist/src/poppy/store.js +1 -1
- package/dist/src/poppy-client/api.d.ts +5 -4
- package/dist/src/poppy-client/api.d.ts.map +1 -1
- package/dist/src/poppy-client/api.js +14 -9
- package/dist/src/poppy-client/api.js.map +1 -1
- package/dist/src/poppy-client/browser.d.ts +12 -18
- package/dist/src/poppy-client/browser.d.ts.map +1 -1
- package/dist/src/poppy-client/browser.js +33 -73
- package/dist/src/poppy-client/browser.js.map +1 -1
- package/dist/src/poppy-client/cli/main.d.ts.map +1 -1
- package/dist/src/poppy-client/cli/main.js +48 -56
- package/dist/src/poppy-client/cli/main.js.map +1 -1
- package/dist/src/poppy-client/company.d.ts +43 -28
- package/dist/src/poppy-client/company.d.ts.map +1 -1
- package/dist/src/poppy-client/company.js +216 -160
- package/dist/src/poppy-client/company.js.map +1 -1
- package/dist/src/poppy-client/conversations.d.ts +12 -13
- package/dist/src/poppy-client/conversations.d.ts.map +1 -1
- package/dist/src/poppy-client/conversations.js +24 -22
- package/dist/src/poppy-client/conversations.js.map +1 -1
- package/dist/src/poppy-client/discovery.d.ts +32 -10
- package/dist/src/poppy-client/discovery.d.ts.map +1 -1
- package/dist/src/poppy-client/discovery.js +134 -68
- package/dist/src/poppy-client/discovery.js.map +1 -1
- package/dist/src/poppy-client/dpop.d.ts +2 -1
- package/dist/src/poppy-client/dpop.d.ts.map +1 -1
- package/dist/src/poppy-client/dpop.js +2 -1
- package/dist/src/poppy-client/dpop.js.map +1 -1
- package/dist/src/poppy-client/errors.d.ts +5 -4
- package/dist/src/poppy-client/errors.d.ts.map +1 -1
- package/dist/src/poppy-client/errors.js +5 -4
- package/dist/src/poppy-client/errors.js.map +1 -1
- package/dist/src/poppy-client/http.d.ts +4 -2
- package/dist/src/poppy-client/http.d.ts.map +1 -1
- package/dist/src/poppy-client/http.js +9 -5
- package/dist/src/poppy-client/http.js.map +1 -1
- package/dist/src/poppy-client/identity.d.ts +15 -15
- package/dist/src/poppy-client/identity.d.ts.map +1 -1
- package/dist/src/poppy-client/identity.js +17 -33
- package/dist/src/poppy-client/identity.js.map +1 -1
- package/dist/src/poppy-client/index.d.ts +6 -3
- package/dist/src/poppy-client/index.d.ts.map +1 -1
- package/dist/src/poppy-client/index.js +6 -3
- package/dist/src/poppy-client/index.js.map +1 -1
- package/dist/src/poppy-client/llm.js +4 -4
- package/dist/src/poppy-client/llm.js.map +1 -1
- package/dist/src/poppy-client/mcp.d.ts +3 -4
- package/dist/src/poppy-client/mcp.d.ts.map +1 -1
- package/dist/src/poppy-client/mcp.js +26 -38
- package/dist/src/poppy-client/mcp.js.map +1 -1
- package/dist/src/poppy-client/safe_fetch.d.ts +30 -0
- package/dist/src/poppy-client/safe_fetch.d.ts.map +1 -0
- package/dist/src/poppy-client/safe_fetch.js +210 -0
- package/dist/src/poppy-client/safe_fetch.js.map +1 -0
- package/dist/src/poppy-client/session_jwt.d.ts +20 -0
- package/dist/src/poppy-client/session_jwt.d.ts.map +1 -0
- package/dist/src/poppy-client/session_jwt.js +37 -0
- package/dist/src/poppy-client/session_jwt.js.map +1 -0
- package/dist/src/poppy-client/signin.d.ts +34 -11
- package/dist/src/poppy-client/signin.d.ts.map +1 -1
- package/dist/src/poppy-client/signin.js +134 -80
- package/dist/src/poppy-client/signin.js.map +1 -1
- package/dist/src/poppy-client/store.d.ts +23 -11
- package/dist/src/poppy-client/store.d.ts.map +1 -1
- package/dist/src/poppy-client/store.js +1 -1
- package/dist/src/poppy-client/store.js.map +1 -1
- package/dist/src/poppy-client/task_coverage.d.ts +13 -0
- package/dist/src/poppy-client/task_coverage.d.ts.map +1 -0
- package/dist/src/poppy-client/task_coverage.js +66 -0
- package/dist/src/poppy-client/task_coverage.js.map +1 -0
- package/dist/src/poppy-client/token_client.d.ts +36 -33
- package/dist/src/poppy-client/token_client.d.ts.map +1 -1
- package/dist/src/poppy-client/token_client.js +47 -47
- package/dist/src/poppy-client/token_client.js.map +1 -1
- package/dist/src/poppy-client/types.d.ts +81 -42
- package/dist/src/poppy-client/types.d.ts.map +1 -1
- package/dist/src/poppy-client/types.js +1 -1
- package/dist/src/poppy-client/util.d.ts +12 -3
- package/dist/src/poppy-client/util.d.ts.map +1 -1
- package/dist/src/poppy-client/util.js +29 -9
- package/dist/src/poppy-client/util.js.map +1 -1
- package/dist/src/poppy-connections/config.d.ts +2 -2
- package/dist/src/poppy-connections/config.js +1 -1
- package/dist/src/poppy-connections/config.js.map +1 -1
- package/dist/src/poppy-connections/crypto.d.ts +2 -2
- package/dist/src/poppy-connections/crypto.js +2 -2
- package/dist/src/poppy-connections/index.d.ts +1 -1
- package/dist/src/poppy-connections/index.js +1 -1
- package/dist/src/poppy-connections/service.d.ts +11 -10
- package/dist/src/poppy-connections/service.d.ts.map +1 -1
- package/dist/src/poppy-connections/service.js +33 -21
- package/dist/src/poppy-connections/service.js.map +1 -1
- package/dist/src/poppy-connections/store.d.ts +2 -2
- package/dist/src/poppy-connections/tools.d.ts.map +1 -1
- package/dist/src/poppy-connections/tools.js +5 -4
- package/dist/src/poppy-connections/tools.js.map +1 -1
- package/dist/src/rag/index.d.ts +1 -0
- package/dist/src/rag/index.d.ts.map +1 -1
- package/dist/src/rag/index.js +1 -0
- package/dist/src/rag/index.js.map +1 -1
- package/dist/src/rag/pg-vector-store.d.ts +8 -0
- package/dist/src/rag/pg-vector-store.d.ts.map +1 -1
- package/dist/src/rag/pg-vector-store.js +14 -5
- package/dist/src/rag/pg-vector-store.js.map +1 -1
- package/dist/src/rag/with-rag.d.ts +75 -0
- package/dist/src/rag/with-rag.d.ts.map +1 -0
- package/dist/src/rag/with-rag.js +132 -0
- package/dist/src/rag/with-rag.js.map +1 -0
- package/package.json +9 -9
- package/skills/agent-governance/SKILL.md +3 -3
- package/skills/agent-tools/SKILL.md +3 -3
package/dist/src/poppy/store.js
CHANGED
|
@@ -112,7 +112,7 @@ export const POPPY_TABLES = {
|
|
|
112
112
|
* `CREATE TABLE IF NOT EXISTS` DDL for the Poppy tables — the agent tables' portable dialect
|
|
113
113
|
* (quoted identifiers, epoch-ms `BIGINT`, `TEXT` JSON; `forDialect` adapts it to MySQL). An event's
|
|
114
114
|
* primary key is its position, so two appends racing for one position cannot both win; a message's
|
|
115
|
-
* is its (owner, id), the idempotency lock of §
|
|
115
|
+
* is its (owner, id), the idempotency lock of §8.3.
|
|
116
116
|
*/
|
|
117
117
|
export function poppyTableStatements() {
|
|
118
118
|
const t = POPPY_TABLES;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { CompanyClient } from './company.js';
|
|
2
2
|
import type { PoppyApiEntry } from './types.js';
|
|
3
|
-
/** API types this client understands (section
|
|
3
|
+
/** API types this client understands (section 7). Others are skipped. */
|
|
4
4
|
export declare const KNOWN_API_TYPES: string[];
|
|
5
5
|
export declare function listApis(company: CompanyClient): PoppyApiEntry[];
|
|
6
6
|
export declare function pickApi(company: CompanyClient, type: 'openapi' | 'mcp', index?: number | undefined): PoppyApiEntry;
|
|
@@ -14,13 +14,14 @@ export interface OpenApiDoc {
|
|
|
14
14
|
}>>;
|
|
15
15
|
[k: string]: unknown;
|
|
16
16
|
}
|
|
17
|
-
/** Loads an OpenAPI description. Tried
|
|
17
|
+
/** Loads an OpenAPI description. Tried as a public document first; through the Session if that's refused. */
|
|
18
18
|
export declare function loadOpenApi(company: CompanyClient, api: PoppyApiEntry): Promise<OpenApiDoc>;
|
|
19
19
|
/** The API's base URL: `servers[0].url` resolved against the description's URL. */
|
|
20
20
|
export declare function apiBaseUrl(doc: OpenApiDoc, api: PoppyApiEntry): string;
|
|
21
21
|
/**
|
|
22
|
-
* Calls an endpoint of a listed OpenAPI API
|
|
23
|
-
* absolute URLs outside the API's own origin, so
|
|
22
|
+
* Calls an endpoint of a listed OpenAPI API (section 7), through the Session and, when signed in,
|
|
23
|
+
* with an access token. Refuses absolute URLs outside the API's own origin, so nothing goes to a
|
|
24
|
+
* third party.
|
|
24
25
|
*/
|
|
25
26
|
export declare function callOpenApi(company: CompanyClient, input: {
|
|
26
27
|
method: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/poppy-client/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAIlD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,yEAAyE;AACzE,eAAO,MAAM,eAAe,UAAqB,CAAC;AAElD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,aAAa,GAAG,aAAa,EAAE,CAIhE;AAED,wBAAgB,OAAO,CACrB,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,SAAS,GAAG,KAAK,EACvB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,GACzB,aAAa,CAOf;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,SAAS,CAAC;IACxC,KAAK,CAAC,EAAE,MAAM,CACZ,MAAM,EACN,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC,CACnF,CAAC;IACF,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED,
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../src/poppy-client/api.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAIlD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAGhD,yEAAyE;AACzE,eAAO,MAAM,eAAe,UAAqB,CAAC;AAElD,wBAAgB,QAAQ,CAAC,OAAO,EAAE,aAAa,GAAG,aAAa,EAAE,CAIhE;AAED,wBAAgB,OAAO,CACrB,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,SAAS,GAAG,KAAK,EACvB,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,GACzB,aAAa,CAOf;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,EAAE,GAAG,SAAS,CAAC;IACxC,KAAK,CAAC,EAAE,MAAM,CACZ,MAAM,EACN,MAAM,CAAC,MAAM,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAAE,CAAC,CACnF,CAAC;IACF,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACtB;AAED,6GAA6G;AAC7G,wBAAsB,WAAW,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,EAAE,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,CAWjG;AAED,mFAAmF;AACnF,wBAAgB,UAAU,CAAC,GAAG,EAAE,UAAU,EAAE,GAAG,EAAE,aAAa,GAAG,MAAM,CAGtE;AAED;;;;GAIG;AACH,wBAAsB,WAAW,CAC/B,OAAO,EAAE,aAAa,EACtB,KAAK,EAAE;IACL,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B,GACA,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAqC9D"}
|
|
@@ -2,7 +2,7 @@ import { throwForResponse } from './company.js';
|
|
|
2
2
|
import { PoppyError } from './errors.js';
|
|
3
3
|
import { readJson } from './http.js';
|
|
4
4
|
import { requireSecureUrl } from './util.js';
|
|
5
|
-
/** API types this client understands (section
|
|
5
|
+
/** API types this client understands (section 7). Others are skipped. */
|
|
6
6
|
export const KNOWN_API_TYPES = ['openapi', 'mcp'];
|
|
7
7
|
export function listApis(company) {
|
|
8
8
|
return (company.document.apis ?? []).filter((a) => a && KNOWN_API_TYPES.includes(a.type) && typeof a.url === 'string');
|
|
@@ -17,7 +17,7 @@ export function pickApi(company, type, index) {
|
|
|
17
17
|
requireSecureUrl(api.url, `${type} url`, company.security);
|
|
18
18
|
return api;
|
|
19
19
|
}
|
|
20
|
-
/** Loads an OpenAPI description. Tried
|
|
20
|
+
/** Loads an OpenAPI description. Tried as a public document first; through the Session if that's refused. */
|
|
21
21
|
export async function loadOpenApi(company, api) {
|
|
22
22
|
const res = await company.http.request(api.url, { headers: { accept: 'application/json' } });
|
|
23
23
|
if (res.ok)
|
|
@@ -25,7 +25,7 @@ export async function loadOpenApi(company, api) {
|
|
|
25
25
|
if (res.status === 401 || res.status === 403) {
|
|
26
26
|
const { body } = await company.json(api.url, {
|
|
27
27
|
headers: { accept: 'application/json' },
|
|
28
|
-
|
|
28
|
+
service: api.url,
|
|
29
29
|
});
|
|
30
30
|
return body ?? {};
|
|
31
31
|
}
|
|
@@ -37,8 +37,9 @@ export function apiBaseUrl(doc, api) {
|
|
|
37
37
|
return new URL(server ?? '/', api.url).toString().replace(/\/+$/, '');
|
|
38
38
|
}
|
|
39
39
|
/**
|
|
40
|
-
* Calls an endpoint of a listed OpenAPI API
|
|
41
|
-
* absolute URLs outside the API's own origin, so
|
|
40
|
+
* Calls an endpoint of a listed OpenAPI API (section 7), through the Session and, when signed in,
|
|
41
|
+
* with an access token. Refuses absolute URLs outside the API's own origin, so nothing goes to a
|
|
42
|
+
* third party.
|
|
42
43
|
*/
|
|
43
44
|
export async function callOpenApi(company, input) {
|
|
44
45
|
const api = pickApi(company, 'openapi', input.apiIndex);
|
|
@@ -49,7 +50,7 @@ export async function callOpenApi(company, input) {
|
|
|
49
50
|
: new URL(base + (input.path.startsWith('/') ? input.path : `/${input.path}`));
|
|
50
51
|
const allowed = new Set([new URL(base).origin, new URL(api.url).origin]);
|
|
51
52
|
if (!allowed.has(url.origin)) {
|
|
52
|
-
throw new PoppyError('foreign_origin', `${url.origin} is not this API's origin; refusing to send
|
|
53
|
+
throw new PoppyError('foreign_origin', `${url.origin} is not this API's origin; refusing to send credentials`);
|
|
53
54
|
}
|
|
54
55
|
requireSecureUrl(url.toString(), 'API URL', company.security);
|
|
55
56
|
const headers = { accept: 'application/json' };
|
|
@@ -59,11 +60,15 @@ export async function callOpenApi(company, input) {
|
|
|
59
60
|
method: input.method.toUpperCase(),
|
|
60
61
|
headers,
|
|
61
62
|
body: input.body === undefined ? undefined : JSON.stringify(input.body),
|
|
62
|
-
|
|
63
|
+
service: base,
|
|
63
64
|
scope: input.scope,
|
|
64
65
|
});
|
|
65
|
-
if (res.status === 401 || res.status === 403) {
|
|
66
|
-
|
|
66
|
+
if ((res.status === 401 || res.status === 403) && res.headers.get('www-authenticate')) {
|
|
67
|
+
await throwForResponse(res);
|
|
68
|
+
}
|
|
69
|
+
if (res.status === 400) {
|
|
70
|
+
const refused = await readJson(res.clone());
|
|
71
|
+
if (refused?.error === 'invalid_session')
|
|
67
72
|
await throwForResponse(res);
|
|
68
73
|
}
|
|
69
74
|
const text = await res.text();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/poppy-client/api.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAErC,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,yEAAyE;AACzE,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,SAAS,EAAE,KAAK,CAAC,CAAC;AAElD,MAAM,UAAU,QAAQ,CAAC,OAAsB;IAC7C,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,MAAM,CACzC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,CAC1E,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,OAAO,CACrB,OAAsB,EACtB,IAAuB,EACvB,KAA0B;IAE1B,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC9D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,MAAM,IAAI,UAAU,CAAC,QAAQ,EAAE,oBAAoB,IAAI,MAAM,CAAC,CAAC;IACtF,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC;IAC7B,IAAI,CAAC,GAAG;QAAE,MAAM,IAAI,UAAU,CAAC,QAAQ,EAAE,MAAM,IAAI,iBAAiB,KAAK,EAAE,CAAC,CAAC;IAC7E,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,MAAM,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC;IAC3D,OAAO,GAAG,CAAC;AACb,CAAC;AAWD,
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../../../src/poppy-client/api.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,24 +1,18 @@
|
|
|
1
1
|
import type { CompanyClient } from './company.js';
|
|
2
|
+
/** Where the Personal Agent's browser joins a Session (section 6), or an error without one. */
|
|
3
|
+
export declare function browserSessionEndpoint(company: CompanyClient): string;
|
|
2
4
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
+
* Step 2: reads the one-time code from the HTML of the page the agent's OWN browser loaded in step
|
|
6
|
+
* 1 (section 6). Pass it nothing else: a code from anywhere else may come from someone else's
|
|
7
|
+
* browser, which would then join the User's Session (10.6). Keep the code out of model context.
|
|
5
8
|
*/
|
|
6
|
-
export declare function
|
|
7
|
-
endpoint: string;
|
|
8
|
-
assertion: string;
|
|
9
|
-
sessionId: string;
|
|
10
|
-
}>;
|
|
11
|
-
/** A page whose form POSTs the assertion as a top-level navigation. Never in the URL (5). */
|
|
12
|
-
export declare function autoSubmitFormHtml(endpoint: string, assertion: string): string;
|
|
9
|
+
export declare function browserJoinCode(html: string): string;
|
|
13
10
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
11
|
+
* Step 2: authorizes the code with the Session header and, if signed in, the access token, which
|
|
12
|
+
* never reaches the browser. The agent's browser then submits the form (step 3); after a failure,
|
|
13
|
+
* start again at step 1.
|
|
16
14
|
*/
|
|
17
|
-
export declare function
|
|
18
|
-
|
|
19
|
-
}): Promise<
|
|
20
|
-
url: string;
|
|
21
|
-
served: Promise<void>;
|
|
22
|
-
close: () => void;
|
|
23
|
-
}>;
|
|
15
|
+
export declare function authorizeBrowserJoin(company: CompanyClient, code: string, opts?: {
|
|
16
|
+
signedOut?: boolean | undefined;
|
|
17
|
+
}): Promise<void>;
|
|
24
18
|
//# sourceMappingURL=browser.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../src/poppy-client/browser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../../src/poppy-client/browser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAKlD,+FAA+F;AAC/F,wBAAgB,sBAAsB,CAAC,OAAO,EAAE,aAAa,GAAG,MAAM,CASrE;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAQpD;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CACxC,OAAO,EAAE,aAAa,EACtB,IAAI,EAAE,MAAM,EACZ,IAAI,GAAE;IAAE,SAAS,CAAC,EAAE,OAAO,GAAG,SAAS,CAAA;CAAO,GAC7C,OAAO,CAAC,IAAI,CAAC,CAWf"}
|
|
@@ -1,83 +1,43 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { throwForResponse } from './company.js';
|
|
2
2
|
import { PoppyError } from './errors.js';
|
|
3
|
-
import {
|
|
4
|
-
/**
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
export async function createBrowserAssertion(company, returnTo) {
|
|
9
|
-
const ep = company.document.web?.browser_session_endpoint;
|
|
10
|
-
if (!ep) {
|
|
3
|
+
import { requireSecureUrl } from './util.js';
|
|
4
|
+
/** Where the Personal Agent's browser joins a Session (section 6), or an error without one. */
|
|
5
|
+
export function browserSessionEndpoint(company) {
|
|
6
|
+
const endpoint = company.document.web?.browser_session_endpoint;
|
|
7
|
+
if (!endpoint) {
|
|
11
8
|
throw new PoppyError('no_browser_session_endpoint', 'Company has no web.browser_session_endpoint: browse as an ordinary signed-out visitor');
|
|
12
9
|
}
|
|
13
|
-
|
|
14
|
-
const target = requireSecureUrl(returnTo, 'return_to', company.security);
|
|
15
|
-
const org = normalizeDomain(company.document.organization.domain.replace(/:\d+$/, ''));
|
|
16
|
-
const host = target.hostname.toLowerCase();
|
|
17
|
-
if (normalizeDomain(host) !== org && !host.endsWith(`.${org}`)) {
|
|
18
|
-
throw new PoppyError('invalid_return_to', `return_to must be on ${org} or a subdomain (section 5)`);
|
|
19
|
-
}
|
|
20
|
-
const { sessionId } = await company.token();
|
|
21
|
-
const assertion = await company.agent.identity.browserAssertion({
|
|
22
|
-
userId: company.userId,
|
|
23
|
-
endpoint,
|
|
24
|
-
sessionId,
|
|
25
|
-
returnTo: target.toString(),
|
|
26
|
-
});
|
|
27
|
-
return { endpoint, assertion, sessionId };
|
|
28
|
-
}
|
|
29
|
-
function escapeHtml(s) {
|
|
30
|
-
return s.replace(/[&<>"']/g, (c) => `&#${c.charCodeAt(0)};`);
|
|
10
|
+
return requireSecureUrl(endpoint, 'web.browser_session_endpoint', company.security).toString();
|
|
31
11
|
}
|
|
32
|
-
/**
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
12
|
+
/**
|
|
13
|
+
* Step 2: reads the one-time code from the HTML of the page the agent's OWN browser loaded in step
|
|
14
|
+
* 1 (section 6). Pass it nothing else: a code from anywhere else may come from someone else's
|
|
15
|
+
* browser, which would then join the User's Session (10.6). Keep the code out of model context.
|
|
16
|
+
*/
|
|
17
|
+
export function browserJoinCode(html) {
|
|
18
|
+
for (const tag of html.match(/<input\b[^>]*>/gi) ?? []) {
|
|
19
|
+
if (!/\bname\s*=\s*["']?code["']?(?:\s|\/|>)/i.test(tag))
|
|
20
|
+
continue;
|
|
21
|
+
const value = /\bvalue\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+))/i.exec(tag);
|
|
22
|
+
const code = value?.[1] ?? value?.[2] ?? value?.[3];
|
|
23
|
+
if (code)
|
|
24
|
+
return code;
|
|
25
|
+
}
|
|
26
|
+
throw new PoppyError('invalid_browser_page', 'the browser-session page has no code field');
|
|
43
27
|
}
|
|
44
28
|
/**
|
|
45
|
-
*
|
|
46
|
-
*
|
|
29
|
+
* Step 2: authorizes the code with the Session header and, if signed in, the access token, which
|
|
30
|
+
* never reaches the browser. The agent's browser then submits the form (step 3); after a failure,
|
|
31
|
+
* start again at step 1.
|
|
47
32
|
*/
|
|
48
|
-
export async function
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
let used = false;
|
|
55
|
-
const server = createServer((req, res) => {
|
|
56
|
-
if (req.url !== path || used) {
|
|
57
|
-
res.writeHead(404).end();
|
|
58
|
-
return;
|
|
59
|
-
}
|
|
60
|
-
used = true;
|
|
61
|
-
res.writeHead(200, {
|
|
62
|
-
'content-type': 'text/html; charset=utf-8',
|
|
63
|
-
'cache-control': 'no-store',
|
|
64
|
-
'referrer-policy': 'no-referrer',
|
|
65
|
-
});
|
|
66
|
-
res.end(html);
|
|
67
|
-
resolveServed();
|
|
68
|
-
setTimeout(() => server.close(), 1000).unref();
|
|
33
|
+
export async function authorizeBrowserJoin(company, code, opts = {}) {
|
|
34
|
+
const res = await company.fetch(`${browserSessionEndpoint(company).replace(/\/+$/, '')}/authorize`, {
|
|
35
|
+
method: 'POST',
|
|
36
|
+
headers: { 'content-type': 'application/json' },
|
|
37
|
+
body: JSON.stringify({ code }),
|
|
38
|
+
...(opts.signedOut ? { signedOut: true } : {}),
|
|
69
39
|
});
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
timer.unref();
|
|
73
|
-
const { port } = server.address();
|
|
74
|
-
return {
|
|
75
|
-
url: `http://127.0.0.1:${port}${path}`,
|
|
76
|
-
served,
|
|
77
|
-
close: () => {
|
|
78
|
-
clearTimeout(timer);
|
|
79
|
-
server.close();
|
|
80
|
-
},
|
|
81
|
-
};
|
|
40
|
+
if (res.status !== 204)
|
|
41
|
+
await throwForResponse(res);
|
|
82
42
|
}
|
|
83
43
|
//# sourceMappingURL=browser.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../../src/poppy-client/browser.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../../../src/poppy-client/browser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAE7C,+FAA+F;AAC/F,MAAM,UAAU,sBAAsB,CAAC,OAAsB;IAC3D,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,wBAAwB,CAAC;IAChE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,UAAU,CAClB,6BAA6B,EAC7B,uFAAuF,CACxF,CAAC;IACJ,CAAC;IACD,OAAO,gBAAgB,CAAC,QAAQ,EAAE,8BAA8B,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAC,QAAQ,EAAE,CAAC;AACjG,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,IAAY;IAC1C,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,IAAI,EAAE,EAAE,CAAC;QACvD,IAAI,CAAC,yCAAyC,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,SAAS;QACnE,MAAM,KAAK,GAAG,kDAAkD,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAC3E,MAAM,IAAI,GAAG,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC;QACpD,IAAI,IAAI;YAAE,OAAO,IAAI,CAAC;IACxB,CAAC;IACD,MAAM,IAAI,UAAU,CAAC,sBAAsB,EAAE,4CAA4C,CAAC,CAAC;AAC7F,CAAC;AAED;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,OAAsB,EACtB,IAAY,EACZ,IAAI,GAAwC,EAAE;IAE9C,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,KAAK,CAC7B,GAAG,sBAAsB,CAAC,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,EAClE;QACE,MAAM,EAAE,MAAM;QACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;QAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC;QAC9B,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/C,CACF,CAAC;IACF,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG;QAAE,MAAM,gBAAgB,CAAC,GAAG,CAAC,CAAC;AACtD,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../src/poppy-client/cli/main.ts"],"names":[],"mappings":"AAuHA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../../../src/poppy-client/cli/main.ts"],"names":[],"mappings":"AAuHA,wBAAsB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CA6D5D"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
1
2
|
import { parseArgs } from 'node:util';
|
|
2
3
|
import { callOpenApi, listApis, loadOpenApi } from '../api.js';
|
|
3
|
-
import {
|
|
4
|
+
import { authorizeBrowserJoin, browserJoinCode, browserSessionEndpoint } from '../browser.js';
|
|
4
5
|
import { PoppyAgent } from '../company.js';
|
|
5
6
|
import { ConversationClient, newMessageId, poppyProtocol } from '../conversations.js';
|
|
6
7
|
import { discover } from '../discovery.js';
|
|
@@ -11,13 +12,13 @@ import { generateEs256Key } from '../keys.js';
|
|
|
11
12
|
import { ask, DEFAULT_MODEL } from '../llm.js';
|
|
12
13
|
import { connectMcp } from '../mcp.js';
|
|
13
14
|
import { openInBrowser } from '../open_url.js';
|
|
14
|
-
import { completeDirectSignIn, deviceSignIn, eligibleSignInTypes, mediatedSignIn, startDirectSignIn, submitMediatedCode, } from '../signin.js';
|
|
15
|
+
import { completeDirectSignIn, deviceSignIn, eligibleSignInTypes, mediatedExtension, mediatedSignIn, offeredSignInTypes, startDirectSignIn, submitMediatedCode, } from '../signin.js';
|
|
15
16
|
import { StateStore } from '../store.js';
|
|
16
17
|
import { isLoopbackHost, requireSecureUrl } from '../util.js';
|
|
17
18
|
import { Prompter } from './prompt.js';
|
|
18
19
|
const HELP = `poppy-agent — reference Personal Agent for the Personal Agent Protocol (Poppy)
|
|
19
20
|
|
|
20
|
-
EXPERIMENTAL. Implements spec Draft 0.
|
|
21
|
+
EXPERIMENTAL. Implements spec Draft 0.3 (https://personalagentprotocol.org/docs/spec).
|
|
21
22
|
The spec is still in development; this client tracks it and WILL change, possibly in
|
|
22
23
|
breaking ways, as the spec evolves.
|
|
23
24
|
|
|
@@ -34,7 +35,7 @@ Sessions & sign-in (4)
|
|
|
34
35
|
session <domain> [--new] [--scope <s>] [--resource <url>]
|
|
35
36
|
signin <domain> [--method direct|device|mediated] [--scope "<scopes>"] [--no-open]
|
|
36
37
|
status [domain]
|
|
37
|
-
disconnect <domain> revoke the
|
|
38
|
+
disconnect <domain> revoke the refresh token (RFC 7009)
|
|
38
39
|
APIs (6)
|
|
39
40
|
apis <domain> list APIs (and OpenAPI operations)
|
|
40
41
|
api <domain> <METHOD> <path> [--data <json>] [--api <n>] [--scope <s>]
|
|
@@ -43,7 +44,7 @@ APIs (6)
|
|
|
43
44
|
Conversations (7)
|
|
44
45
|
chat <domain> [--conversation <id>] [--as agent|human] [--no-stream]
|
|
45
46
|
Web browsing (5)
|
|
46
|
-
open <domain> <
|
|
47
|
+
open <domain> [--page <file>] authorize a browser join: code from that browser's page
|
|
47
48
|
LLM mode
|
|
48
49
|
ask <domain> "<task>" [--model <id>] [--max-steps <n>] [--yes]
|
|
49
50
|
needs OPENROUTER_API_KEY (default model ${DEFAULT_MODEL})
|
|
@@ -51,7 +52,6 @@ LLM mode
|
|
|
51
52
|
Global options
|
|
52
53
|
--state <file> state file (default $POPPY_AGENT_STATE or ~/.config/poppy-agent/state.json), mode 0600
|
|
53
54
|
--profile <name> local user to act for (default "default"); each gets its own User IDs
|
|
54
|
-
--client-assertion-aud token_endpoint|issuer aud of private_key_jwt (default token_endpoint)
|
|
55
55
|
--insecure-dev NON-SPEC: allow http:// URLs (client_id, discovery, endpoints). Local testing only.
|
|
56
56
|
Also: POPPY_AGENT_INSECURE_DEV=1
|
|
57
57
|
`;
|
|
@@ -72,14 +72,12 @@ function loadIdentity(ctx) {
|
|
|
72
72
|
return new AgentIdentity(id, { insecureDev: ctx.insecureDev });
|
|
73
73
|
}
|
|
74
74
|
function makeAgent(ctx) {
|
|
75
|
-
const aud = ctx.values['client-assertion-aud'];
|
|
76
75
|
return new PoppyAgent({
|
|
77
76
|
store: ctx.store,
|
|
78
77
|
identity: loadIdentity(ctx),
|
|
79
78
|
profile: ctx.profile,
|
|
80
79
|
insecureDev: ctx.insecureDev,
|
|
81
80
|
log: (l) => err(dim(`· ${l}`)),
|
|
82
|
-
tokenClient: { clientAssertionAudience: aud === 'issuer' ? 'issuer' : 'token_endpoint' },
|
|
83
81
|
});
|
|
84
82
|
}
|
|
85
83
|
async function company(ctx, domain) {
|
|
@@ -116,11 +114,10 @@ export async function runCli(argv) {
|
|
|
116
114
|
conversation: { type: 'string' },
|
|
117
115
|
as: { type: 'string' },
|
|
118
116
|
'no-stream': { type: 'boolean' },
|
|
119
|
-
|
|
117
|
+
page: { type: 'string' },
|
|
120
118
|
model: { type: 'string' },
|
|
121
119
|
'max-steps': { type: 'string' },
|
|
122
120
|
yes: { type: 'boolean' },
|
|
123
|
-
'client-assertion-aud': { type: 'string' },
|
|
124
121
|
},
|
|
125
122
|
});
|
|
126
123
|
const [command, ...args] = positionals;
|
|
@@ -145,9 +142,6 @@ export async function runCli(argv) {
|
|
|
145
142
|
if (e instanceof ResourceAuthError && e.code === 'insufficient_scope') {
|
|
146
143
|
err(`error: insufficient_scope — the Company needs "${e.scope ?? '?'}". Run: poppy-agent signin <domain> --scope "${e.scope ?? ''}"`);
|
|
147
144
|
}
|
|
148
|
-
else if (e instanceof ResourceAuthError && e.code === 'sign_in_required') {
|
|
149
|
-
err('error: sign_in_required — run: poppy-agent signin <domain>');
|
|
150
|
-
}
|
|
151
145
|
else {
|
|
152
146
|
err(`error: ${e.message}`);
|
|
153
147
|
}
|
|
@@ -183,12 +177,12 @@ async function dispatch(ctx, command, args) {
|
|
|
183
177
|
const t = await c.token({ scope: str(v.scope), resource: str(v.resource) });
|
|
184
178
|
out(JSON.stringify({
|
|
185
179
|
user_id: c.userId,
|
|
186
|
-
session_id:
|
|
187
|
-
signed_in: t
|
|
188
|
-
scope: t
|
|
189
|
-
token_type: t
|
|
190
|
-
expires_at: new Date(t.expiresAt).toISOString(),
|
|
191
|
-
|
|
180
|
+
session_id: c.sessionId,
|
|
181
|
+
signed_in: t !== null,
|
|
182
|
+
scope: t?.scope ?? '',
|
|
183
|
+
token_type: t?.tokenType ?? null,
|
|
184
|
+
expires_at: t ? new Date(t.expiresAt).toISOString() : null,
|
|
185
|
+
refresh_token: c.accountToken
|
|
192
186
|
? { scope: c.accountToken.scope, via: c.accountToken.via }
|
|
193
187
|
: null,
|
|
194
188
|
}, null, 2));
|
|
@@ -205,14 +199,14 @@ async function dispatch(ctx, command, args) {
|
|
|
205
199
|
const c = await company(ctx, args[0]);
|
|
206
200
|
const revoked = await c.signOut();
|
|
207
201
|
out(revoked
|
|
208
|
-
? '
|
|
209
|
-
: 'No
|
|
202
|
+
? 'Refresh token revoked; Sessions continue signed out.'
|
|
203
|
+
: 'No refresh token for this Company.');
|
|
210
204
|
return 0;
|
|
211
205
|
}
|
|
212
206
|
case 'apis': {
|
|
213
207
|
const c = await company(ctx, args[0]);
|
|
214
208
|
for (const a of listApis(c)) {
|
|
215
|
-
out(`${bold(`[${a.type}]`)} ${a.url}
|
|
209
|
+
out(`${bold(`[${a.type}]`)} ${a.url} — ${a.description ?? ''}`);
|
|
216
210
|
if (a.type === 'openapi') {
|
|
217
211
|
try {
|
|
218
212
|
const doc = await loadOpenApi(c, a);
|
|
@@ -252,7 +246,7 @@ async function dispatch(ctx, command, args) {
|
|
|
252
246
|
case 'chat':
|
|
253
247
|
return cmdChat(ctx, args[0]);
|
|
254
248
|
case 'open':
|
|
255
|
-
return cmdOpen(ctx, args[0]
|
|
249
|
+
return cmdOpen(ctx, args[0]);
|
|
256
250
|
case 'ask':
|
|
257
251
|
return cmdAsk(ctx, args[0], args.slice(1).join(' '));
|
|
258
252
|
default:
|
|
@@ -320,14 +314,12 @@ async function cmdServeIdentity(ctx) {
|
|
|
320
314
|
}
|
|
321
315
|
/* --------------------------------------------------------------------------- sign-in */
|
|
322
316
|
function defaultScope(c, method) {
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
return (
|
|
317
|
+
if (method === 'mediated')
|
|
318
|
+
return (mediatedExtension(c)?.scopes ?? []).join(' ');
|
|
319
|
+
return (c.metadata.scopes_supported ?? Object.keys(c.document.auth?.scopes ?? {})).join(' ');
|
|
326
320
|
}
|
|
327
321
|
async function signIn(ctx, c, method, scope) {
|
|
328
|
-
const eligible = scope
|
|
329
|
-
? eligibleSignInTypes(c, scope)
|
|
330
|
-
: ['direct', 'device', 'mediated'].filter((t) => c.document.auth?.[t]);
|
|
322
|
+
const eligible = scope ? eligibleSignInTypes(c, scope) : offeredSignInTypes(c);
|
|
331
323
|
const chosen = method ?? eligible[0];
|
|
332
324
|
if (!chosen) {
|
|
333
325
|
err(scope
|
|
@@ -343,7 +335,7 @@ async function signIn(ctx, c, method, scope) {
|
|
|
343
335
|
else if (chosen === 'device') {
|
|
344
336
|
result = await deviceSignIn(c, wanted, {
|
|
345
337
|
display: (i) => {
|
|
346
|
-
out(
|
|
338
|
+
out(`${bold(i.organization.name)} (${i.organization.domain}): open ${bold(i.verificationUriComplete ?? i.verificationUri)} and enter the code ${bold(i.userCode)}`);
|
|
347
339
|
out(dim(`(expires in ${i.expiresIn}s; waiting…)`));
|
|
348
340
|
},
|
|
349
341
|
onPoll: (s, n) => s === 'slow_down' && err(dim(`slow_down: polling every ${n}s`)),
|
|
@@ -352,7 +344,7 @@ async function signIn(ctx, c, method, scope) {
|
|
|
352
344
|
else
|
|
353
345
|
result = await mediatedFlow(ctx, c, wanted);
|
|
354
346
|
if (result) {
|
|
355
|
-
out(`Signed in. Granted scope: "${result.grantedScope}"
|
|
347
|
+
out(`Signed in. Granted scope: "${result.grantedScope}" `);
|
|
356
348
|
if (result.missingScopes.length)
|
|
357
349
|
out(`Note: the User did not grant ${result.missingScopes.join(', ')}`);
|
|
358
350
|
}
|
|
@@ -411,7 +403,7 @@ async function directFlow(ctx, c, scope) {
|
|
|
411
403
|
}
|
|
412
404
|
}
|
|
413
405
|
async function mediatedFlow(ctx, c, scope) {
|
|
414
|
-
const mediated = c
|
|
406
|
+
const mediated = mediatedExtension(c);
|
|
415
407
|
const credentials = {};
|
|
416
408
|
for (const f of mediated.fields) {
|
|
417
409
|
credentials[f.name] = f.secret
|
|
@@ -422,7 +414,7 @@ async function mediatedFlow(ctx, c, scope) {
|
|
|
422
414
|
for (const k of Object.keys(credentials))
|
|
423
415
|
credentials[k] = '';
|
|
424
416
|
while (outcome.status === 'code_required') {
|
|
425
|
-
const code = await ctx.prompter.ask(`One-time code${outcome.sentTo ? ` (${outcome.sentTo})` : ''}${outcome.
|
|
417
|
+
const code = await ctx.prompter.ask(`One-time code${outcome.sentTo ? ` (${outcome.sentTo})` : ''}${outcome.expiresIn ? `, within ${outcome.expiresIn}s` : ''}: `);
|
|
426
418
|
outcome = await submitMediatedCode(c, scope, outcome.signInId, code.trim());
|
|
427
419
|
}
|
|
428
420
|
if (outcome.status === 'complete')
|
|
@@ -436,12 +428,12 @@ async function cmdStatus(ctx, domain) {
|
|
|
436
428
|
const id = ctx.store.data.identity;
|
|
437
429
|
out(`identity: ${id ? `${id.baseUrl}/agent.json` : '(none: run init)'} profile: ${ctx.profile}`);
|
|
438
430
|
for (const s of Object.values(companies)) {
|
|
439
|
-
if (domain && !s.domains.includes(domain.toLowerCase()
|
|
431
|
+
if (domain && !s.domains.includes(domain.toLowerCase()))
|
|
440
432
|
continue;
|
|
441
|
-
const t = s.tokens.
|
|
433
|
+
const t = s.tokens.default;
|
|
442
434
|
out(`${bold(s.issuer)} (${s.domains.join(', ')})`);
|
|
443
|
-
out(` user_id ${s.userId} session ${s.sessionId ?? '-'} ${
|
|
444
|
-
out(`
|
|
435
|
+
out(` user_id ${s.userId} session ${s.sessionId ?? '-'} ${s.accountToken ? 'signed in' : 'signed out'}${t ? ` scope="${t.scope}" expires ${new Date(t.expiresAt).toISOString()}` : ''}`);
|
|
436
|
+
out(` refresh token: ${s.accountToken ? `yes (scope "${s.accountToken.scope}", via ${s.accountToken.via})` : 'no'}`);
|
|
445
437
|
const convs = Object.entries(s.conversations).filter(([, c]) => !c.closed);
|
|
446
438
|
if (convs.length)
|
|
447
439
|
out(` open conversations: ${convs.map(([k]) => k).join(', ')}`);
|
|
@@ -474,19 +466,19 @@ async function cmdMcp(ctx, args) {
|
|
|
474
466
|
}
|
|
475
467
|
}
|
|
476
468
|
/* --------------------------------------------------------------------------- open */
|
|
477
|
-
async function cmdOpen(ctx, domain
|
|
478
|
-
if (!domain
|
|
479
|
-
throw new PoppyError('usage', 'open <domain> <
|
|
469
|
+
async function cmdOpen(ctx, domain) {
|
|
470
|
+
if (!domain)
|
|
471
|
+
throw new PoppyError('usage', 'open <domain> [--page <file>]');
|
|
480
472
|
const c = await company(ctx, domain);
|
|
481
|
-
const
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
await
|
|
489
|
-
|
|
473
|
+
const endpoint = browserSessionEndpoint(c);
|
|
474
|
+
err(dim("Section 6: join only a browser this agent controls, never the User's own, and take the code only from the page it loaded."));
|
|
475
|
+
out(`In the agent-controlled browser, load:\n ${endpoint}`);
|
|
476
|
+
const page = str(ctx.values.page);
|
|
477
|
+
const code = page
|
|
478
|
+
? browserJoinCode(await readFile(page, 'utf8'))
|
|
479
|
+
: (await ctx.prompter.askSecret('Code from that page (the form field `code`): ')).trim();
|
|
480
|
+
await authorizeBrowserJoin(c, code);
|
|
481
|
+
out('Authorized. Now submit the form in that browser, within its 60 seconds.');
|
|
490
482
|
return 0;
|
|
491
483
|
}
|
|
492
484
|
/* --------------------------------------------------------------------------- ask */
|
|
@@ -565,7 +557,7 @@ async function cmdChat(ctx, domain) {
|
|
|
565
557
|
provisional.delete(m.id);
|
|
566
558
|
if (m.role === 'user')
|
|
567
559
|
return; // our own message, echoed back
|
|
568
|
-
let line = `${tag}${bold(`company[${m.
|
|
560
|
+
let line = `${tag}${bold(`company[${m.author?.name ?? m.author?.type}]`)}: ${m.text ?? ''}`;
|
|
569
561
|
if (m.data)
|
|
570
562
|
line += `\n${dim(JSON.stringify(m.data, null, 2))}`;
|
|
571
563
|
print(line);
|
|
@@ -658,7 +650,7 @@ async function cmdChat(ctx, domain) {
|
|
|
658
650
|
continue;
|
|
659
651
|
try {
|
|
660
652
|
if (!line.startsWith('/')) {
|
|
661
|
-
await send({
|
|
653
|
+
await send({ author: { type: directId ? 'human' : sender }, text: line });
|
|
662
654
|
continue;
|
|
663
655
|
}
|
|
664
656
|
const [cmd, ...rest] = line.split(' ');
|
|
@@ -672,7 +664,7 @@ async function cmdChat(ctx, domain) {
|
|
|
672
664
|
out(dim(`now sending as ${sender}`));
|
|
673
665
|
}
|
|
674
666
|
else if (cmd === '/data') {
|
|
675
|
-
await send({
|
|
667
|
+
await send({ author: { type: directId ? 'human' : sender }, data: JSON.parse(restText) });
|
|
676
668
|
}
|
|
677
669
|
else if (cmd === '/context') {
|
|
678
670
|
const context = {};
|
|
@@ -682,7 +674,7 @@ async function cmdChat(ctx, domain) {
|
|
|
682
674
|
continue;
|
|
683
675
|
context[k] = val === 'true' ? true : val === 'false' ? false : val;
|
|
684
676
|
}
|
|
685
|
-
await send({
|
|
677
|
+
await send({ author: { type: 'agent' }, context });
|
|
686
678
|
}
|
|
687
679
|
else if (cmd === '/status') {
|
|
688
680
|
if (!mainId)
|
|
@@ -709,7 +701,7 @@ async function cmdChat(ctx, domain) {
|
|
|
709
701
|
const r = await signIn(ctx, c, m, m ? scope : [method, ...scopeParts].filter(Boolean).join(' ') || scope);
|
|
710
702
|
if (r) {
|
|
711
703
|
pendingAuth = undefined;
|
|
712
|
-
out(dim('Continue the conversation; the new
|
|
704
|
+
out(dim('Continue the conversation; the new access token is used from now on.'));
|
|
713
705
|
}
|
|
714
706
|
}
|
|
715
707
|
else if (cmd === '/direct') {
|
|
@@ -718,7 +710,7 @@ async function cmdChat(ctx, domain) {
|
|
|
718
710
|
else {
|
|
719
711
|
const message = {
|
|
720
712
|
id: newMessageId(),
|
|
721
|
-
|
|
713
|
+
author: { type: 'human' },
|
|
722
714
|
text: restText || 'Hi, I am here.',
|
|
723
715
|
context: { user_available: true },
|
|
724
716
|
};
|
|
@@ -735,7 +727,7 @@ async function cmdChat(ctx, domain) {
|
|
|
735
727
|
else {
|
|
736
728
|
await conv.send(mainId, {
|
|
737
729
|
id: newMessageId(),
|
|
738
|
-
|
|
730
|
+
author: { type: 'agent' },
|
|
739
731
|
text: pendingUserRequest
|
|
740
732
|
? 'The user declined to talk directly right now.'
|
|
741
733
|
: 'The user is not available.',
|