@parlor/client 0.2.0 → 0.3.1

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.
Files changed (37) hide show
  1. package/dist/action-client.d.ts +7 -1
  2. package/dist/action-client.d.ts.map +1 -1
  3. package/dist/action-client.js +10 -2
  4. package/dist/action-client.js.map +1 -1
  5. package/dist/index.d.ts +1 -1
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js.map +1 -1
  8. package/dist/react/chat/chat-ask.d.ts +3 -2
  9. package/dist/react/chat/chat-ask.d.ts.map +1 -1
  10. package/dist/react/chat/chat-ask.js +3 -2
  11. package/dist/react/chat/chat-ask.js.map +1 -1
  12. package/dist/react/chat/runtime.d.ts +17 -3
  13. package/dist/react/chat/runtime.d.ts.map +1 -1
  14. package/dist/react/chat/runtime.js +117 -16
  15. package/dist/react/chat/runtime.js.map +1 -1
  16. package/dist/react/chat/use-chat.d.ts.map +1 -1
  17. package/dist/react/chat/use-chat.js +2 -0
  18. package/dist/react/chat/use-chat.js.map +1 -1
  19. package/dist/react/chat/use-streaming-text.d.ts +7 -0
  20. package/dist/react/chat/use-streaming-text.d.ts.map +1 -0
  21. package/dist/react/chat/use-streaming-text.js +59 -0
  22. package/dist/react/chat/use-streaming-text.js.map +1 -0
  23. package/dist/react/hooks.d.ts.map +1 -1
  24. package/dist/react/hooks.js +3 -6
  25. package/dist/react/hooks.js.map +1 -1
  26. package/dist/react/index.d.ts +3 -1
  27. package/dist/react/index.d.ts.map +1 -1
  28. package/dist/react/index.js +2 -0
  29. package/dist/react/index.js.map +1 -1
  30. package/dist/react/write-refresh.d.ts +27 -0
  31. package/dist/react/write-refresh.d.ts.map +1 -0
  32. package/dist/react/write-refresh.js +80 -0
  33. package/dist/react/write-refresh.js.map +1 -0
  34. package/dist/session.d.ts +7 -1
  35. package/dist/session.d.ts.map +1 -1
  36. package/dist/session.js.map +1 -1
  37. package/package.json +6 -6
@@ -1,4 +1,4 @@
1
- import { ActionError, type ActionInput, type ActionMap, type ActionOutput, type Tag } from "@parlor/core";
1
+ import { ActionError, type ActionInput, type ActionMap, type ActionOutput, type ReadRequest, type RefreshedRead, type Tag } from "@parlor/core";
2
2
  export declare function generateClientId(): string;
3
3
  export type HeadersProvider = HeadersInit | (() => HeadersInit | Promise<HeadersInit>);
4
4
  export interface ActionClientOptions {
@@ -10,12 +10,18 @@ export interface ActionClientOptions {
10
10
  }
11
11
  export interface CallOptions {
12
12
  readonly signal?: AbortSignal | undefined;
13
+ /** For a write: the reads the page shows, to answer with fresh the ones it changed. */
14
+ readonly refresh?: readonly ReadRequest[] | undefined;
13
15
  }
14
16
  export interface ActionEnvelope<T> {
15
17
  readonly data: T;
16
18
  readonly tags: readonly Tag[];
17
19
  /** The sync cursor a read's data reflects, when the server tracks it. */
18
20
  readonly cursor?: string | undefined;
21
+ /** For a call with `refresh`, when the server knows it: what the write changed. */
22
+ readonly writes?: readonly Tag[] | undefined;
23
+ /** For a call with `refresh`, when the server knows it: each read named, in order. */
24
+ readonly refreshed?: readonly RefreshedRead[] | undefined;
19
25
  }
20
26
  export interface ActionClient<T extends ActionMap> {
21
27
  readonly clientId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"action-client.d.ts","sourceRoot":"","sources":["../src/action-client.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"action-client.d.ts","sourceRoot":"","sources":["../src/action-client.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { ActionError, SHELL_ORIGINS, } from "@parlor/core";
1
+ import { ActionError, encodeReadRequests, REFRESH_HEADER, SHELL_ORIGINS, } from "@parlor/core";
2
2
  const DEFAULT_BASE_PATH = "/_parlor";
3
3
  const SOURCE_HEADER = "x-parlor-source";
4
4
  const CLIENT_HEADER = "x-parlor-client";
@@ -26,7 +26,12 @@ export async function toActionError(response, options = {}) {
26
26
  export async function invokeAt(request, path, input, options = {}) {
27
27
  const response = await request(path, {
28
28
  method: "POST",
29
- headers: { "content-type": "application/json" },
29
+ headers: {
30
+ "content-type": "application/json",
31
+ ...(options.refresh?.length
32
+ ? { [REFRESH_HEADER]: encodeReadRequests(options.refresh) }
33
+ : {}),
34
+ },
30
35
  body: JSON.stringify(input ?? {}),
31
36
  signal: options.signal ?? null,
32
37
  });
@@ -38,6 +43,9 @@ export async function invokeAt(request, path, input, options = {}) {
38
43
  data: body.data,
39
44
  tags: body.tags ?? [],
40
45
  ...(typeof body.cursor === "string" ? { cursor: body.cursor } : {}),
46
+ ...(Array.isArray(body.writes) && Array.isArray(body.refreshed)
47
+ ? { writes: body.writes, refreshed: body.refreshed }
48
+ : {}),
41
49
  };
42
50
  }
43
51
  export function resolveServerOrigin() {
@@ -1 +1 @@
1
- {"version":3,"file":"action-client.js","sourceRoot":"","sources":["../src/action-client.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ActionError,\n type ActionInput,\n type ActionMap,\n type ActionOutput,\n SHELL_ORIGINS,\n type Tag,\n} from \"@parlor/core\";\n\nconst DEFAULT_BASE_PATH = \"/_parlor\";\nconst SOURCE_HEADER = \"x-parlor-source\";\nconst CLIENT_HEADER = \"x-parlor-client\";\n\nfunction injectedServerUrl(): string {\n const env = (import.meta as { env?: { PARLOR_SERVER_URL?: string } }).env;\n return env?.PARLOR_SERVER_URL ?? \"\";\n}\n\nexport function generateClientId(): string {\n return globalThis.crypto?.randomUUID?.() ?? Math.random().toString(36).slice(2);\n}\n\nexport type HeadersProvider = HeadersInit | (() => HeadersInit | Promise<HeadersInit>);\n\nexport interface ActionClientOptions {\n readonly baseUrl?: string | undefined;\n readonly basePath?: string | undefined;\n readonly fetch?: typeof fetch | undefined;\n readonly headers?: HeadersProvider | undefined;\n readonly clientId?: string | undefined;\n}\n\nexport interface CallOptions {\n readonly signal?: AbortSignal | undefined;\n}\n\nexport interface ActionEnvelope<T> {\n readonly data: T;\n readonly tags: readonly Tag[];\n /** The sync cursor a read's data reflects, when the server tracks it. */\n readonly cursor?: string | undefined;\n}\n\nexport interface ActionClient<T extends ActionMap> {\n readonly clientId: string;\n readonly basePath: string;\n call<K extends keyof T & string>(\n name: K,\n input: ActionInput<T[K]>,\n options?: CallOptions,\n ): Promise<ActionOutput<T[K]>>;\n invoke<K extends keyof T & string>(\n name: K,\n input: ActionInput<T[K]>,\n options?: CallOptions,\n ): Promise<ActionEnvelope<ActionOutput<T[K]>>>;\n request(path: string, init?: RequestInit): Promise<Response>;\n}\n\nasync function resolveHeaders(\n provider: HeadersProvider | undefined,\n clientId: string,\n extra?: HeadersInit,\n): Promise<Headers> {\n const headers = new Headers(\n typeof provider === \"function\" ? await provider() : provider,\n );\n new Headers(extra).forEach((value, key) => headers.set(key, value));\n headers.set(SOURCE_HEADER, \"ui\");\n headers.set(CLIENT_HEADER, clientId);\n return headers;\n}\n\nexport async function toActionError(\n response: Response,\n options: { readonly missingIsNotFound?: boolean } = {},\n): Promise<ActionError> {\n const body: unknown = await response.json().catch(() => undefined);\n if (ActionError.isBody(body)) return ActionError.fromBody(body);\n const code =\n options.missingIsNotFound && response.status === 404 ? \"not_found\" : \"internal\";\n return new ActionError(code, `Action request failed with HTTP ${response.status}`);\n}\n\nexport async function invokeAt<T extends ActionMap, K extends keyof T & string>(\n request: ActionClient<ActionMap>[\"request\"],\n path: string,\n input: ActionInput<T[K]>,\n options: CallOptions & { readonly missingIsNotFound?: boolean } = {},\n): Promise<ActionEnvelope<ActionOutput<T[K]>>> {\n const response = await request(path, {\n method: \"POST\",\n headers: { \"content-type\": \"application/json\" },\n body: JSON.stringify(input ?? {}),\n signal: options.signal ?? null,\n });\n if (!response.ok) {\n throw await toActionError(\n response,\n options.missingIsNotFound ? { missingIsNotFound: true } : {},\n );\n }\n const body = (await response.json()) as {\n data: ActionOutput<T[K]>;\n tags?: Tag[];\n cursor?: string;\n };\n return {\n data: body.data,\n tags: body.tags ?? [],\n ...(typeof body.cursor === \"string\" ? { cursor: body.cursor } : {}),\n };\n}\n\nexport function resolveServerOrigin(): string {\n return injectedServerUrl() || globalThis.location?.origin || \"\";\n}\n\nfunction injectedAppOrigin(): string {\n const env = (import.meta as { env?: { PARLOR_APP_ORIGIN?: string } }).env;\n return env?.PARLOR_APP_ORIGIN ?? \"\";\n}\n\n/**\n * The one name of this app's backend on every surface: the page's own origin when it is\n * served over http(s) and is not a shell's webview origin, else the shell's `server.url`.\n * `parlor dev` running several targets names the web target's origin for all of them.\n * Statements are signed for it and the host is paired with it.\n */\nexport function appOrigin(\n serverUrl: string = resolveServerOrigin(),\n injected: string = injectedAppOrigin(),\n): string {\n if (injected) return new URL(injected).origin;\n const page = globalThis.location?.origin ?? \"\";\n if (/^https?:\\/\\//.test(page) && !SHELL_ORIGINS.includes(page)) return page;\n try {\n return new URL(serverUrl).origin;\n } catch {\n return serverUrl;\n }\n}\n\nexport function createActionClient<T extends ActionMap>(\n options: ActionClientOptions = {},\n): ActionClient<T> {\n const {\n baseUrl = injectedServerUrl(),\n basePath = DEFAULT_BASE_PATH,\n headers,\n } = options;\n // Drawn on first use: workerd allows no random values while a module loads.\n let clientId = options.clientId;\n const ownId = () => (clientId ??= generateClientId());\n const fetchImpl = options.fetch ?? globalThis.fetch;\n\n const request = async (path: string, init: RequestInit = {}) =>\n fetchImpl(`${baseUrl}${path}`, {\n ...init,\n headers: await resolveHeaders(headers, ownId(), init.headers),\n });\n\n const invoke = async <K extends keyof T & string>(\n name: K,\n input: ActionInput<T[K]>,\n callOptions: CallOptions = {},\n ): Promise<ActionEnvelope<ActionOutput<T[K]>>> => {\n return invokeAt<T, K>(request, `${basePath}/actions/${name}`, input, callOptions);\n };\n\n return {\n get clientId() {\n return ownId();\n },\n basePath,\n request,\n invoke,\n call: async (name, input, callOptions) =>\n (await invoke(name, input, callOptions)).data,\n };\n}\n"]}
1
+ {"version":3,"file":"action-client.js","sourceRoot":"","sources":["../src/action-client.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n ActionError,\n type ActionInput,\n type ActionMap,\n type ActionOutput,\n encodeReadRequests,\n type ReadRequest,\n REFRESH_HEADER,\n type RefreshedRead,\n SHELL_ORIGINS,\n type Tag,\n} from \"@parlor/core\";\n\nconst DEFAULT_BASE_PATH = \"/_parlor\";\nconst SOURCE_HEADER = \"x-parlor-source\";\nconst CLIENT_HEADER = \"x-parlor-client\";\n\nfunction injectedServerUrl(): string {\n const env = (import.meta as { env?: { PARLOR_SERVER_URL?: string } }).env;\n return env?.PARLOR_SERVER_URL ?? \"\";\n}\n\nexport function generateClientId(): string {\n return globalThis.crypto?.randomUUID?.() ?? Math.random().toString(36).slice(2);\n}\n\nexport type HeadersProvider = HeadersInit | (() => HeadersInit | Promise<HeadersInit>);\n\nexport interface ActionClientOptions {\n readonly baseUrl?: string | undefined;\n readonly basePath?: string | undefined;\n readonly fetch?: typeof fetch | undefined;\n readonly headers?: HeadersProvider | undefined;\n readonly clientId?: string | undefined;\n}\n\nexport interface CallOptions {\n readonly signal?: AbortSignal | undefined;\n /** For a write: the reads the page shows, to answer with fresh the ones it changed. */\n readonly refresh?: readonly ReadRequest[] | undefined;\n}\n\nexport interface ActionEnvelope<T> {\n readonly data: T;\n readonly tags: readonly Tag[];\n /** The sync cursor a read's data reflects, when the server tracks it. */\n readonly cursor?: string | undefined;\n /** For a call with `refresh`, when the server knows it: what the write changed. */\n readonly writes?: readonly Tag[] | undefined;\n /** For a call with `refresh`, when the server knows it: each read named, in order. */\n readonly refreshed?: readonly RefreshedRead[] | undefined;\n}\n\nexport interface ActionClient<T extends ActionMap> {\n readonly clientId: string;\n readonly basePath: string;\n call<K extends keyof T & string>(\n name: K,\n input: ActionInput<T[K]>,\n options?: CallOptions,\n ): Promise<ActionOutput<T[K]>>;\n invoke<K extends keyof T & string>(\n name: K,\n input: ActionInput<T[K]>,\n options?: CallOptions,\n ): Promise<ActionEnvelope<ActionOutput<T[K]>>>;\n request(path: string, init?: RequestInit): Promise<Response>;\n}\n\nasync function resolveHeaders(\n provider: HeadersProvider | undefined,\n clientId: string,\n extra?: HeadersInit,\n): Promise<Headers> {\n const headers = new Headers(\n typeof provider === \"function\" ? await provider() : provider,\n );\n new Headers(extra).forEach((value, key) => headers.set(key, value));\n headers.set(SOURCE_HEADER, \"ui\");\n headers.set(CLIENT_HEADER, clientId);\n return headers;\n}\n\nexport async function toActionError(\n response: Response,\n options: { readonly missingIsNotFound?: boolean } = {},\n): Promise<ActionError> {\n const body: unknown = await response.json().catch(() => undefined);\n if (ActionError.isBody(body)) return ActionError.fromBody(body);\n const code =\n options.missingIsNotFound && response.status === 404 ? \"not_found\" : \"internal\";\n return new ActionError(code, `Action request failed with HTTP ${response.status}`);\n}\n\nexport async function invokeAt<T extends ActionMap, K extends keyof T & string>(\n request: ActionClient<ActionMap>[\"request\"],\n path: string,\n input: ActionInput<T[K]>,\n options: CallOptions & { readonly missingIsNotFound?: boolean } = {},\n): Promise<ActionEnvelope<ActionOutput<T[K]>>> {\n const response = await request(path, {\n method: \"POST\",\n headers: {\n \"content-type\": \"application/json\",\n ...(options.refresh?.length\n ? { [REFRESH_HEADER]: encodeReadRequests(options.refresh) }\n : {}),\n },\n body: JSON.stringify(input ?? {}),\n signal: options.signal ?? null,\n });\n if (!response.ok) {\n throw await toActionError(\n response,\n options.missingIsNotFound ? { missingIsNotFound: true } : {},\n );\n }\n const body = (await response.json()) as {\n data: ActionOutput<T[K]>;\n tags?: Tag[];\n cursor?: string;\n writes?: Tag[];\n refreshed?: RefreshedRead[];\n };\n return {\n data: body.data,\n tags: body.tags ?? [],\n ...(typeof body.cursor === \"string\" ? { cursor: body.cursor } : {}),\n ...(Array.isArray(body.writes) && Array.isArray(body.refreshed)\n ? { writes: body.writes, refreshed: body.refreshed }\n : {}),\n };\n}\n\nexport function resolveServerOrigin(): string {\n return injectedServerUrl() || globalThis.location?.origin || \"\";\n}\n\nfunction injectedAppOrigin(): string {\n const env = (import.meta as { env?: { PARLOR_APP_ORIGIN?: string } }).env;\n return env?.PARLOR_APP_ORIGIN ?? \"\";\n}\n\n/**\n * The one name of this app's backend on every surface: the page's own origin when it is\n * served over http(s) and is not a shell's webview origin, else the shell's `server.url`.\n * `parlor dev` running several targets names the web target's origin for all of them.\n * Statements are signed for it and the host is paired with it.\n */\nexport function appOrigin(\n serverUrl: string = resolveServerOrigin(),\n injected: string = injectedAppOrigin(),\n): string {\n if (injected) return new URL(injected).origin;\n const page = globalThis.location?.origin ?? \"\";\n if (/^https?:\\/\\//.test(page) && !SHELL_ORIGINS.includes(page)) return page;\n try {\n return new URL(serverUrl).origin;\n } catch {\n return serverUrl;\n }\n}\n\nexport function createActionClient<T extends ActionMap>(\n options: ActionClientOptions = {},\n): ActionClient<T> {\n const {\n baseUrl = injectedServerUrl(),\n basePath = DEFAULT_BASE_PATH,\n headers,\n } = options;\n // Drawn on first use: workerd allows no random values while a module loads.\n let clientId = options.clientId;\n const ownId = () => (clientId ??= generateClientId());\n const fetchImpl = options.fetch ?? globalThis.fetch;\n\n const request = async (path: string, init: RequestInit = {}) =>\n fetchImpl(`${baseUrl}${path}`, {\n ...init,\n headers: await resolveHeaders(headers, ownId(), init.headers),\n });\n\n const invoke = async <K extends keyof T & string>(\n name: K,\n input: ActionInput<T[K]>,\n callOptions: CallOptions = {},\n ): Promise<ActionEnvelope<ActionOutput<T[K]>>> => {\n return invokeAt<T, K>(request, `${basePath}/actions/${name}`, input, callOptions);\n };\n\n return {\n get clientId() {\n return ownId();\n },\n basePath,\n request,\n invoke,\n call: async (name, input, callOptions) =>\n (await invoke(name, input, callOptions)).data,\n };\n}\n"]}
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ export { type ActionClient, appOrigin, type ActionClientOptions, type ActionEnve
2
2
  export { type AgentViewBinding, type AgentViewDefinition, type AnyAgentView, defineAgentView, type WritableField, } from "@parlor/agent-ui";
3
3
  export { ACTION_QUERY_PREFIX, actionQueryKey } from "./query-keys.js";
4
4
  export { createPluginClient, type PluginClient } from "./plugin-client.js";
5
- export type { AccountDevice, DeviceLinker, DeviceSource, FrameworkAuth, HostAuthorizer, PendingLink, SessionDevice, SessionSnapshot, SessionSource, SessionUser, } from "./session.js";
5
+ export type { AccountDevice, ComputerDisconnector, DeviceLinker, DeviceSource, FrameworkAuth, HostAuthorizer, PendingLink, SessionDevice, SessionSnapshot, SessionSource, SessionUser, } from "./session.js";
6
6
  export { LinkOnComputer } from "./session.js";
7
7
  export type { Register, RegisteredActions } from "./register.js";
8
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,SAAS,EACT,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,KAAK,eAAe,GACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,eAAe,EACf,KAAK,aAAa,GACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC3E,YAAY,EACV,aAAa,EACb,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,cAAc,EACd,WAAW,EACX,aAAa,EACb,eAAe,EACf,aAAa,EACb,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,YAAY,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,YAAY,EACjB,SAAS,EACT,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,kBAAkB,EAClB,gBAAgB,EAChB,KAAK,eAAe,GACrB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EACL,KAAK,gBAAgB,EACrB,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,eAAe,EACf,KAAK,aAAa,GACnB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC3E,YAAY,EACV,aAAa,EACb,oBAAoB,EACpB,YAAY,EACZ,YAAY,EACZ,aAAa,EACb,cAAc,EACd,WAAW,EACX,aAAa,EACb,eAAe,EACf,aAAa,EACb,WAAW,GACZ,MAAM,cAAc,CAAC;AACtB,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,YAAY,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC"}
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,SAAS,EAIT,kBAAkB,EAClB,gBAAgB,GAEjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAIL,eAAe,GAEhB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAqB,MAAM,oBAAoB,CAAC;AAa3E,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC","sourcesContent":["export {\n type ActionClient,\n appOrigin,\n type ActionClientOptions,\n type ActionEnvelope,\n type CallOptions,\n createActionClient,\n generateClientId,\n type HeadersProvider,\n} from \"./action-client.js\";\nexport {\n type AgentViewBinding,\n type AgentViewDefinition,\n type AnyAgentView,\n defineAgentView,\n type WritableField,\n} from \"@parlor/agent-ui\";\nexport { ACTION_QUERY_PREFIX, actionQueryKey } from \"./query-keys.js\";\nexport { createPluginClient, type PluginClient } from \"./plugin-client.js\";\nexport type {\n AccountDevice,\n DeviceLinker,\n DeviceSource,\n FrameworkAuth,\n HostAuthorizer,\n PendingLink,\n SessionDevice,\n SessionSnapshot,\n SessionSource,\n SessionUser,\n} from \"./session.js\";\nexport { LinkOnComputer } from \"./session.js\";\nexport type { Register, RegisteredActions } from \"./register.js\";\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,SAAS,EAIT,kBAAkB,EAClB,gBAAgB,GAEjB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAIL,eAAe,GAEhB,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,mBAAmB,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtE,OAAO,EAAE,kBAAkB,EAAqB,MAAM,oBAAoB,CAAC;AAc3E,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC","sourcesContent":["export {\n type ActionClient,\n appOrigin,\n type ActionClientOptions,\n type ActionEnvelope,\n type CallOptions,\n createActionClient,\n generateClientId,\n type HeadersProvider,\n} from \"./action-client.js\";\nexport {\n type AgentViewBinding,\n type AgentViewDefinition,\n type AnyAgentView,\n defineAgentView,\n type WritableField,\n} from \"@parlor/agent-ui\";\nexport { ACTION_QUERY_PREFIX, actionQueryKey } from \"./query-keys.js\";\nexport { createPluginClient, type PluginClient } from \"./plugin-client.js\";\nexport type {\n AccountDevice,\n ComputerDisconnector,\n DeviceLinker,\n DeviceSource,\n FrameworkAuth,\n HostAuthorizer,\n PendingLink,\n SessionDevice,\n SessionSnapshot,\n SessionSource,\n SessionUser,\n} from \"./session.js\";\nexport { LinkOnComputer } from \"./session.js\";\nexport type { Register, RegisteredActions } from \"./register.js\";\n"]}
@@ -9,8 +9,9 @@ export interface ChatAskProps extends ComponentProps<"div"> {
9
9
  }
10
10
  /**
11
11
  * The agent's own permission prompt or question: `role="group"` named by its question.
12
- * `data-approval` is `presence` (answering triggers the OS prompt) or `computer` (answered
13
- * on the computer; choices disabled). `data-state` is `open`, `answered` or `closed`.
12
+ * `data-approval` is `presence` (answering triggers the OS prompt), `device` (answered by
13
+ * the device that sent the prompt) or `computer` (answered on the computer; choices
14
+ * disabled). `data-state` is `open`, `answered` or `closed`.
14
15
  * Escape declines.
15
16
  */
16
17
  export declare function Ask({ item, onKeyDown, ...props }: ChatAskProps): ReactNode;
@@ -1 +1 @@
1
- {"version":3,"file":"chat-ask.d.ts","sourceRoot":"","sources":["../../../src/react/chat/chat-ask.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EACL,KAAK,cAAc,EAGnB,KAAK,SAAS,EAGf,MAAM,OAAO,CAAC;AAKf,KAAK,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC;AAOrE,MAAM,WAAW,YAAa,SAAQ,cAAc,CAAC,KAAK,CAAC;IACzD,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED;;;;;GAKG;AACH,wBAAgB,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,YAAY,GAAG,SAAS,CAyB1E;AAED,MAAM,WAAW,kBAAmB,SAAQ,cAAc,CAAC,QAAQ,CAAC;IAClE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;CAC7C;AAED,mEAAmE;AACnE,wBAAgB,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,kBAAkB,GAAG,SAAS,CAmBtF;AAID,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;AAEtD;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,gBAAgB,GAAG,SAAS,CA2BrF"}
1
+ {"version":3,"file":"chat-ask.d.ts","sourceRoot":"","sources":["../../../src/react/chat/chat-ask.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EACL,KAAK,cAAc,EAGnB,KAAK,SAAS,EAGf,MAAM,OAAO,CAAC;AAKf,KAAK,OAAO,GAAG,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,EAAE;IAAE,IAAI,EAAE,KAAK,CAAA;CAAE,CAAC,CAAC;AAOrE,MAAM,WAAW,YAAa,SAAQ,cAAc,CAAC,KAAK,CAAC;IACzD,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;CACxB;AAED;;;;;;GAMG;AACH,wBAAgB,GAAG,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,KAAK,EAAE,EAAE,YAAY,GAAG,SAAS,CAyB1E;AAED,MAAM,WAAW,kBAAmB,SAAQ,cAAc,CAAC,QAAQ,CAAC;IAClE,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;CAC7C;AAED,mEAAmE;AACnE,wBAAgB,SAAS,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,EAAE,kBAAkB,GAAG,SAAS,CAmBtF;AAID,MAAM,MAAM,gBAAgB,GAAG,cAAc,CAAC,MAAM,CAAC,CAAC;AAEtD;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,EAAE,QAAQ,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,gBAAgB,GAAG,SAAS,CA2BrF"}
@@ -6,8 +6,9 @@ const AskScope = createContext(undefined);
6
6
  const report = (error) => console.error("[parlor] The chat could not answer:", error);
7
7
  /**
8
8
  * The agent's own permission prompt or question: `role="group"` named by its question.
9
- * `data-approval` is `presence` (answering triggers the OS prompt) or `computer` (answered
10
- * on the computer; choices disabled). `data-state` is `open`, `answered` or `closed`.
9
+ * `data-approval` is `presence` (answering triggers the OS prompt), `device` (answered by
10
+ * the device that sent the prompt) or `computer` (answered on the computer; choices
11
+ * disabled). `data-state` is `open`, `answered` or `closed`.
11
12
  * Escape declines.
12
13
  */
13
14
  export function Ask({ item, onKeyDown, ...props }) {
@@ -1 +1 @@
1
- {"version":3,"file":"chat-ask.js","sourceRoot":"","sources":["../../../src/react/chat/chat-ask.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { AgentConfirmation } from \"@parlor/agent-ui/client\";\nimport type { ChatItem } from \"@parlor/chat\";\nimport {\n type ComponentProps,\n createContext,\n type KeyboardEvent,\n type ReactNode,\n use,\n useMemo,\n} from \"react\";\n\nimport { type AskField, askFields, askValues } from \"./ask-fields.js\";\nimport { useChatRuntime } from \"./context.js\";\n\ntype AskItem = Extract<ChatItem<AgentConfirmation>, { kind: \"ask\" }>;\n\nconst AskScope = createContext<AskItem | undefined>(undefined);\n\nconst report = (error: unknown) =>\n console.error(\"[parlor] The chat could not answer:\", error);\n\nexport interface ChatAskProps extends ComponentProps<\"div\"> {\n readonly item: AskItem;\n}\n\n/**\n * The agent's own permission prompt or question: `role=\"group\"` named by its question.\n * `data-approval` is `presence` (answering triggers the OS prompt) or `computer` (answered\n * on the computer; choices disabled). `data-state` is `open`, `answered` or `closed`.\n * Escape declines.\n */\nexport function Ask({ item, onKeyDown, ...props }: ChatAskProps): ReactNode {\n const runtime = useChatRuntime(\"Chat.Ask\");\n const decline = (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n if (event.defaultPrevented || event.key !== \"Escape\") return;\n const rejection = item.choices.find((choice) => choice.effect.startsWith(\"reject\"));\n if (!rejection || item.answer.state !== \"open\" || item.approval === \"computer\")\n return;\n event.preventDefault();\n event.stopPropagation();\n runtime.answer(item.id, rejection.id).catch(report);\n };\n return (\n <AskScope value={item}>\n <div\n role=\"group\"\n aria-label={item.question}\n tabIndex={-1}\n {...props}\n data-approval={item.approval}\n data-state={item.answer.state}\n onKeyDown={decline}\n />\n </AskScope>\n );\n}\n\nexport interface ChatAskChoiceProps extends ComponentProps<\"button\"> {\n readonly choice: AskItem[\"choices\"][number];\n}\n\n/** `type=\"button\"`; answers the enclosing ask with this choice. */\nexport function AskChoice({ choice, onClick, ...props }: ChatAskChoiceProps): ReactNode {\n const runtime = useChatRuntime(\"Chat.AskChoice\");\n const ask = use(AskScope);\n if (!ask) throw new Error(\"Chat.AskChoice must be rendered inside Chat.Ask.\");\n return (\n <button\n type=\"button\"\n disabled={ask.approval === \"computer\" || ask.answer.state !== \"open\"}\n data-effect={choice.effect}\n aria-pressed={\n ask.answer.state === \"answered\" ? ask.answer.choice === choice.id : undefined\n }\n {...props}\n onClick={(event) => {\n onClick?.(event);\n if (!event.defaultPrevented) runtime.answer(ask.id, choice.id).catch(report);\n }}\n />\n );\n}\n\nconst isAllow = (choice: AskItem[\"choices\"][number]) => choice.effect.startsWith(\"allow\");\n\nexport type ChatAskFormProps = ComponentProps<\"form\">;\n\n/**\n * A form ask's `<form>`: one `<input name=\"{property}\">` per property of its schema (`number`\n * for numbers and integers, `checkbox` for booleans, text otherwise). Submitting answers the\n * ask with its allow choice and the values typed per the schema. Its children, a submit\n * button for one, go after the inputs. Everything is disabled once the ask is not open or\n * is answered on the computer. Renders nothing for an ask without a form.\n */\nexport function AskForm({ onSubmit, children, ...props }: ChatAskFormProps): ReactNode {\n const runtime = useChatRuntime(\"Chat.AskForm\");\n const ask = use(AskScope);\n if (!ask) throw new Error(\"Chat.AskForm must be rendered inside Chat.Ask.\");\n const { form } = ask;\n const fields = useMemo(() => (form ? askFields(form) : []), [form]);\n const accept = ask.choices.find(isAllow);\n if (!form || !accept) return null;\n return (\n <form\n {...props}\n onSubmit={(event) => {\n onSubmit?.(event);\n event.preventDefault();\n runtime\n .answer(ask.id, accept.id, askValues(fields, event.currentTarget))\n .catch(report);\n }}\n >\n <fieldset disabled={ask.approval === \"computer\" || ask.answer.state !== \"open\"}>\n {fields.map((field) => (\n <AskInput key={field.name} field={field} />\n ))}\n {children}\n </fieldset>\n </form>\n );\n}\n\nfunction AskInput({ field }: { readonly field: AskField }): ReactNode {\n return (\n <label data-type={field.type}>\n <span>{field.label}</span>\n <input\n name={field.name}\n type={field.type}\n required={field.required && field.type !== \"checkbox\"}\n step={field.type === \"number\" ? (field.integer ? 1 : \"any\") : undefined}\n />\n </label>\n );\n}\n"]}
1
+ {"version":3,"file":"chat-ask.js","sourceRoot":"","sources":["../../../src/react/chat/chat-ask.tsx"],"names":[],"mappings":"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","sourcesContent":["import type { AgentConfirmation } from \"@parlor/agent-ui/client\";\nimport type { ChatItem } from \"@parlor/chat\";\nimport {\n type ComponentProps,\n createContext,\n type KeyboardEvent,\n type ReactNode,\n use,\n useMemo,\n} from \"react\";\n\nimport { type AskField, askFields, askValues } from \"./ask-fields.js\";\nimport { useChatRuntime } from \"./context.js\";\n\ntype AskItem = Extract<ChatItem<AgentConfirmation>, { kind: \"ask\" }>;\n\nconst AskScope = createContext<AskItem | undefined>(undefined);\n\nconst report = (error: unknown) =>\n console.error(\"[parlor] The chat could not answer:\", error);\n\nexport interface ChatAskProps extends ComponentProps<\"div\"> {\n readonly item: AskItem;\n}\n\n/**\n * The agent's own permission prompt or question: `role=\"group\"` named by its question.\n * `data-approval` is `presence` (answering triggers the OS prompt), `device` (answered by\n * the device that sent the prompt) or `computer` (answered on the computer; choices\n * disabled). `data-state` is `open`, `answered` or `closed`.\n * Escape declines.\n */\nexport function Ask({ item, onKeyDown, ...props }: ChatAskProps): ReactNode {\n const runtime = useChatRuntime(\"Chat.Ask\");\n const decline = (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown?.(event);\n if (event.defaultPrevented || event.key !== \"Escape\") return;\n const rejection = item.choices.find((choice) => choice.effect.startsWith(\"reject\"));\n if (!rejection || item.answer.state !== \"open\" || item.approval === \"computer\")\n return;\n event.preventDefault();\n event.stopPropagation();\n runtime.answer(item.id, rejection.id).catch(report);\n };\n return (\n <AskScope value={item}>\n <div\n role=\"group\"\n aria-label={item.question}\n tabIndex={-1}\n {...props}\n data-approval={item.approval}\n data-state={item.answer.state}\n onKeyDown={decline}\n />\n </AskScope>\n );\n}\n\nexport interface ChatAskChoiceProps extends ComponentProps<\"button\"> {\n readonly choice: AskItem[\"choices\"][number];\n}\n\n/** `type=\"button\"`; answers the enclosing ask with this choice. */\nexport function AskChoice({ choice, onClick, ...props }: ChatAskChoiceProps): ReactNode {\n const runtime = useChatRuntime(\"Chat.AskChoice\");\n const ask = use(AskScope);\n if (!ask) throw new Error(\"Chat.AskChoice must be rendered inside Chat.Ask.\");\n return (\n <button\n type=\"button\"\n disabled={ask.approval === \"computer\" || ask.answer.state !== \"open\"}\n data-effect={choice.effect}\n aria-pressed={\n ask.answer.state === \"answered\" ? ask.answer.choice === choice.id : undefined\n }\n {...props}\n onClick={(event) => {\n onClick?.(event);\n if (!event.defaultPrevented) runtime.answer(ask.id, choice.id).catch(report);\n }}\n />\n );\n}\n\nconst isAllow = (choice: AskItem[\"choices\"][number]) => choice.effect.startsWith(\"allow\");\n\nexport type ChatAskFormProps = ComponentProps<\"form\">;\n\n/**\n * A form ask's `<form>`: one `<input name=\"{property}\">` per property of its schema (`number`\n * for numbers and integers, `checkbox` for booleans, text otherwise). Submitting answers the\n * ask with its allow choice and the values typed per the schema. Its children, a submit\n * button for one, go after the inputs. Everything is disabled once the ask is not open or\n * is answered on the computer. Renders nothing for an ask without a form.\n */\nexport function AskForm({ onSubmit, children, ...props }: ChatAskFormProps): ReactNode {\n const runtime = useChatRuntime(\"Chat.AskForm\");\n const ask = use(AskScope);\n if (!ask) throw new Error(\"Chat.AskForm must be rendered inside Chat.Ask.\");\n const { form } = ask;\n const fields = useMemo(() => (form ? askFields(form) : []), [form]);\n const accept = ask.choices.find(isAllow);\n if (!form || !accept) return null;\n return (\n <form\n {...props}\n onSubmit={(event) => {\n onSubmit?.(event);\n event.preventDefault();\n runtime\n .answer(ask.id, accept.id, askValues(fields, event.currentTarget))\n .catch(report);\n }}\n >\n <fieldset disabled={ask.approval === \"computer\" || ask.answer.state !== \"open\"}>\n {fields.map((field) => (\n <AskInput key={field.name} field={field} />\n ))}\n {children}\n </fieldset>\n </form>\n );\n}\n\nfunction AskInput({ field }: { readonly field: AskField }): ReactNode {\n return (\n <label data-type={field.type}>\n <span>{field.label}</span>\n <input\n name={field.name}\n type={field.type}\n required={field.required && field.type !== \"checkbox\"}\n step={field.type === \"number\" ? (field.integer ? 1 : \"any\") : undefined}\n />\n </label>\n );\n}\n"]}
@@ -1,11 +1,11 @@
1
1
  import type { AgentConfirmation, AgentUiClient } from "@parlor/agent-ui/client";
2
2
  import type { CapabilityHandle, LocalAgentHost } from "@parlor/capabilities";
3
- import { type ChatItem, type HostSummary, type ThreadSummary } from "@parlor/chat";
3
+ import { type AgentOption, type AgentUsage, type ChatItem, type HostSummary, type ThreadSummary } from "@parlor/chat";
4
4
  import type { ChatUserActionMap } from "@parlor/chat/server";
5
5
  import { type Tag } from "@parlor/core";
6
6
  import type { ClientChannel } from "@parlor/sync";
7
7
  import type { PluginClient } from "../../plugin-client.js";
8
- import type { DeviceLinker, DeviceSource, HostAuthorizer } from "../../session.js";
8
+ import type { ComputerDisconnector, DeviceLinker, DeviceSource, HostAuthorizer } from "../../session.js";
9
9
  /** One agent the user can talk to; `key` is `<hostId>/<agentId>`. */
10
10
  export interface AgentChoice {
11
11
  readonly key: string;
@@ -14,6 +14,16 @@ export interface AgentChoice {
14
14
  readonly online: boolean;
15
15
  readonly ready: boolean;
16
16
  readonly problem: string | undefined;
17
+ /** What a prompt to this agent may choose, such as its model; empty until it has said. */
18
+ readonly options: readonly AgentChoiceOption[];
19
+ /** The account's allowance, as the agent last reported it. */
20
+ readonly usage: AgentUsage | undefined;
21
+ /** The name this agent knows the app by outside the sidebar, when the user let it use the app there. */
22
+ readonly outsideName: string | undefined;
23
+ }
24
+ export interface AgentChoiceOption extends AgentOption {
25
+ /** The value the next prompt runs with: this device's choice, or the agent's own. */
26
+ readonly selected: string;
17
27
  }
18
28
  /** How this client adds a computer, decided by the `localAgentHost` capability. */
19
29
  export type ConnectOption = {
@@ -118,6 +128,10 @@ export interface ChatCommands {
118
128
  /** A `presence` ask triggers the OS prompt first; a `computer` ask refuses. */
119
129
  answer(askId: string, choice: string, values?: Readonly<Record<string, string | number | boolean>>): Promise<void>;
120
130
  choose(agentKey: string): void;
131
+ /** Chooses a value of the chosen agent's option for this device's next prompts to it. */
132
+ setOption(optionId: string, value: string): void;
133
+ /** Disconnects a computer: its agents leave the sidebar and stop using the app outside it. */
134
+ disconnect(hostId: string): Promise<void>;
121
135
  /** `undefined` opens the most recent thread, if there is one. */
122
136
  openThread(threadId: string | undefined): void;
123
137
  /** Starts a blank thread; it exists on the server once the first prompt is sent. */
@@ -157,7 +171,7 @@ export interface ChatRuntimeDeps {
157
171
  readonly transport: () => "sse" | "poll" | undefined;
158
172
  readonly onNegotiated: (listener: (transport: "sse" | "poll") => void) => () => void;
159
173
  readonly isHidden?: (() => boolean) | undefined;
160
- readonly auth: Partial<DeviceSource & HostAuthorizer & DeviceLinker> | undefined;
174
+ readonly auth: Partial<DeviceSource & HostAuthorizer & DeviceLinker & ComputerDisconnector> | undefined;
161
175
  readonly localHost: Promise<CapabilityHandle<LocalAgentHost>>;
162
176
  readonly threadId: string | undefined;
163
177
  }
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/react/chat/runtime.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/react/chat/runtime.ts"],"names":[],"mappings":"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"}
@@ -64,8 +64,11 @@ export function createChatRuntime(deps) {
64
64
  let draft = "";
65
65
  let failure;
66
66
  let chosen;
67
+ let optionChoices = readOptionChoices();
67
68
  let sending = false;
68
69
  let pendingSend;
70
+ /** The prompt in flight, shown in its thread until the server's copy arrives. */
71
+ let shownSend;
69
72
  let startedNew = false;
70
73
  let connect = {
71
74
  kind: "command",
@@ -121,14 +124,27 @@ export function createChatRuntime(deps) {
121
124
  return undefined;
122
125
  return refusedLast(hostId, deviceId) ? 0 : due - PRESENCE_MARGIN_MS;
123
126
  };
124
- const choices = () => hosts.flatMap((host) => host.agents.map((agent) => ({
125
- key: `${host.id}/${agent.id}`,
126
- name: agent.name,
127
- hostName: host.name,
128
- online: host.online,
129
- ready: agent.ready,
130
- problem: agent.problem,
131
- })));
127
+ /** This device's choices for `agentKey` that its agent still offers. */
128
+ const chosenOptions = (agentKey, options) => Object.fromEntries(Object.entries(optionChoices[agentKey] ?? {}).filter(([id, value]) => options.some((option) => option.id === id && option.values.some((candidate) => candidate.id === value))));
129
+ const choices = () => hosts.flatMap((host) => host.agents.map((agent) => {
130
+ const key = `${host.id}/${agent.id}`;
131
+ const offered = agent.options ?? [];
132
+ const picked = chosenOptions(key, offered);
133
+ return {
134
+ key,
135
+ name: agent.name,
136
+ hostName: host.name,
137
+ online: host.online,
138
+ ready: agent.ready,
139
+ problem: agent.problem,
140
+ options: offered.map((option) => ({
141
+ ...option,
142
+ selected: picked[option.id] ?? option.current,
143
+ })),
144
+ usage: agent.usage,
145
+ outsideName: agent.outsideName,
146
+ };
147
+ }));
132
148
  const waitOn = (reason, hostId) => ({
133
149
  reason,
134
150
  hostId,
@@ -171,6 +187,27 @@ export function createChatRuntime(deps) {
171
187
  hosts.some((host) => host.id === turn.agent.hostId && !host.online));
172
188
  return offline && waitOn("offline", offline.agent.hostId);
173
189
  };
190
+ const withShownSend = (folded) => {
191
+ if (shownSend && items.has(shownSend.itemId))
192
+ shownSend = undefined;
193
+ const shown = shownSend;
194
+ if (!shown || (threadId !== shown.openedIn && threadId !== shown.threadId)) {
195
+ return folded;
196
+ }
197
+ const [hostId, agentId] = shown.agent.split("/");
198
+ const row = {
199
+ kind: "prompt",
200
+ id: shown.itemId,
201
+ turnId: shown.turnId,
202
+ text: shown.text,
203
+ agent: { hostId: asId("host", hostId), agentId },
204
+ state: "queued",
205
+ failure: undefined,
206
+ mine: true,
207
+ sending: true,
208
+ };
209
+ return [...folded, row];
210
+ };
174
211
  const compute = () => {
175
212
  const agents = choices();
176
213
  const wanted = chosen ??
@@ -203,13 +240,15 @@ export function createChatRuntime(deps) {
203
240
  moreThreads,
204
241
  hasOlder,
205
242
  loadingOlder,
206
- items: foldThread({
243
+ items: withShownSend(foldThread({
207
244
  items: [...items.values()].sort(bySeq),
208
245
  open: [...open.turns.values()],
209
246
  turns,
210
- confirmations: agentUi.confirmations.get().filter((c) => c.threadId === threadId),
247
+ confirmations: agentUi.confirmations
248
+ .get()
249
+ .filter((c) => c.threadId === threadId),
211
250
  deviceId: device?.id,
212
- }),
251
+ })),
213
252
  hosts,
214
253
  agents,
215
254
  agent,
@@ -477,6 +516,10 @@ export function createChatRuntime(deps) {
477
516
  try {
478
517
  await reporting(async () => {
479
518
  const agent = { hostId: asId("host", hostId), agentId };
519
+ const offered = hosts
520
+ .find((host) => host.id === hostId)
521
+ ?.agents.find((candidate) => candidate.id === agentId)?.options;
522
+ const options = chosenOptions(agentKey, offered ?? []);
480
523
  const signed = deps.auth?.device
481
524
  ? await signPrompt({
482
525
  threadId: attempt.threadId,
@@ -490,7 +533,12 @@ export function createChatRuntime(deps) {
490
533
  turnId: attempt.turnId,
491
534
  itemId: attempt.itemId,
492
535
  clientId: deps.clientId,
493
- prompt: { text: attempt.text, agent, ...(signed ? { signed } : {}) },
536
+ prompt: {
537
+ text: attempt.text,
538
+ agent,
539
+ ...(signed ? { signed } : {}),
540
+ ...(Object.keys(options).length > 0 ? { options } : {}),
541
+ },
494
542
  });
495
543
  settle();
496
544
  if (epoch !== generation)
@@ -518,6 +566,7 @@ export function createChatRuntime(deps) {
518
566
  open = NO_OPEN_TURNS;
519
567
  beforeLoad = [];
520
568
  pendingSend = undefined;
569
+ shownSend = undefined;
521
570
  stopIds.clear();
522
571
  answerIds.clear();
523
572
  dirty = false;
@@ -563,11 +612,26 @@ export function createChatRuntime(deps) {
563
612
  turnId: mint("turn"),
564
613
  itemId: mint("item"),
565
614
  });
566
- await whenSetUp(() => submit(attempt, target.key, () => {
567
- pendingSend = undefined;
615
+ await whenSetUp(async () => {
616
+ let delivered = false;
617
+ shownSend = attempt;
568
618
  if (draft.trim() === prompt)
569
619
  draft = "";
570
- }));
620
+ emit();
621
+ try {
622
+ await submit(attempt, target.key, () => {
623
+ delivered = true;
624
+ pendingSend = undefined;
625
+ });
626
+ }
627
+ finally {
628
+ if (!delivered && shownSend === attempt) {
629
+ shownSend = undefined;
630
+ draft = draft.trim() === "" ? attempt.text : `${attempt.text}\n\n${draft}`;
631
+ emit();
632
+ }
633
+ }
634
+ });
571
635
  },
572
636
  async loadOlder() {
573
637
  const target = threadId;
@@ -663,7 +727,7 @@ export function createChatRuntime(deps) {
663
727
  };
664
728
  await whenSetUp(() => reporting(async () => {
665
729
  const found = deps.auth?.device ? await deviceOf() : undefined;
666
- if (ask.approval === "presence" && !found) {
730
+ if ((ask.approval === "presence" || ask.approval === "device") && !found) {
667
731
  throw new NeedsDevice("This question needs a device that can confirm it is you.");
668
732
  }
669
733
  const signed = await found?.signAnswer(toSign, {
@@ -766,6 +830,25 @@ export function createChatRuntime(deps) {
766
830
  chosen = agentKey;
767
831
  emit();
768
832
  },
833
+ async disconnect(hostId) {
834
+ if (!deps.auth?.disconnectComputer) {
835
+ throw new Error("This app cannot disconnect computers.");
836
+ }
837
+ await deps.auth.disconnectComputer(hostId);
838
+ await refreshHosts();
839
+ emit();
840
+ },
841
+ setOption(optionId, value) {
842
+ const agentKey = state.agent?.key;
843
+ if (agentKey === undefined)
844
+ return;
845
+ optionChoices = {
846
+ ...optionChoices,
847
+ [agentKey]: { ...optionChoices[agentKey], [optionId]: value },
848
+ };
849
+ writeOptionChoices(optionChoices);
850
+ emit();
851
+ },
769
852
  openThread(target) {
770
853
  switchTo(target === undefined ? undefined : asId("thread", target), false);
771
854
  },
@@ -837,6 +920,7 @@ export function createChatRuntime(deps) {
837
920
  announceActivity();
838
921
  });
839
922
  const offConfirmations = agentUi.confirmations.subscribe(emit);
923
+ const offLink = deps.auth?.subscribeLink?.(() => void refreshLink());
840
924
  emit();
841
925
  announceActivity();
842
926
  void initial();
@@ -854,6 +938,7 @@ export function createChatRuntime(deps) {
854
938
  offResume();
855
939
  offNegotiated();
856
940
  offConfirmations();
941
+ offLink?.();
857
942
  stopWatching?.();
858
943
  stopWatching = undefined;
859
944
  watched = undefined;
@@ -936,4 +1021,20 @@ export function createChatRuntime(deps) {
936
1021
  }
937
1022
  return runtime;
938
1023
  }
1024
+ const OPTION_CHOICES_KEY = "parlor:agent-options";
1025
+ function readOptionChoices() {
1026
+ try {
1027
+ const stored = JSON.parse(globalThis.localStorage?.getItem(OPTION_CHOICES_KEY) ?? "{}");
1028
+ return stored && typeof stored === "object" ? stored : {};
1029
+ }
1030
+ catch {
1031
+ return {};
1032
+ }
1033
+ }
1034
+ function writeOptionChoices(choices) {
1035
+ try {
1036
+ globalThis.localStorage?.setItem(OPTION_CHOICES_KEY, JSON.stringify(choices));
1037
+ }
1038
+ catch { }
1039
+ }
939
1040
  //# sourceMappingURL=runtime.js.map