@blade-hq/agent-client 2612.0.0-beta.13 → 2612.0.0-beta.15
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 +61 -0
- package/dist/blade-client.d.ts +12 -1
- package/dist/{chunk-KPS6X6QX.js → chunk-7LEZA2WA.js} +338 -59
- package/dist/chunk-7LEZA2WA.js.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.js +3 -1
- package/dist/internal.js +3 -1
- package/dist/internal.js.map +1 -1
- package/dist/resources/sessions.d.ts +11 -0
- package/dist/schemas/message.d.ts +1 -0
- package/dist/schemas/session.d.ts +1 -0
- package/dist/session/agent-session.d.ts +27 -0
- package/dist/tool-provider.d.ts +51 -0
- package/dist/types/socket-events.d.ts +56 -0
- package/package.json +1 -1
- package/public-api.md +78 -2
- package/dist/chunk-KPS6X6QX.js.map +0 -1
package/dist/index.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ export { BladeApiError } from "./rest";
|
|
|
4
4
|
export type { LoginOptions, LoginResult, TokenStorageMode } from "./auth-login";
|
|
5
5
|
export { SDK_NAME, SDK_VERSION } from "./version";
|
|
6
6
|
export { AgentSession } from "./session/agent-session";
|
|
7
|
-
export type { AttachAppOptions, SendOptions } from "./session/agent-session";
|
|
7
|
+
export type { AttachAppOptions, SendOptions, PreparedSend, PreparedSendOptions, DeliveryReceipt } from "./session/agent-session";
|
|
8
8
|
export { AgentSessionError } from "./session/errors";
|
|
9
9
|
export type { AgentSessionEvents, AgentSessionEventName } from "./session/events";
|
|
10
10
|
export type { WorkflowRunEntry, WorkflowRunState } from "./session/workflow";
|
|
@@ -33,3 +33,5 @@ export type { ChatGroup, ChatGroupRole, ChatGroupMember, ChatGroupTask, CreateCh
|
|
|
33
33
|
export { normalizePluginRefs } from "./schemas/plugin-refs";
|
|
34
34
|
export type { PluginRef } from "./schemas/plugin-refs";
|
|
35
35
|
export type { ToolEvidence } from "./schemas/projection";
|
|
36
|
+
export { ToolProvider } from "./tool-provider";
|
|
37
|
+
export type { ToolProviderOptions, ProviderTool, ProviderToolResult } from "./tool-provider";
|
package/dist/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
SessionInfo,
|
|
10
10
|
SessionSetupError,
|
|
11
11
|
SessionStatus,
|
|
12
|
+
ToolProvider,
|
|
12
13
|
chatErrorForDisplay,
|
|
13
14
|
contentPreview,
|
|
14
15
|
getFileParts,
|
|
@@ -19,7 +20,7 @@ import {
|
|
|
19
20
|
normalizeTopicAssetRefs,
|
|
20
21
|
transformSlashCommand,
|
|
21
22
|
userFacingErrorText
|
|
22
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-7LEZA2WA.js";
|
|
23
24
|
export {
|
|
24
25
|
AgentSession,
|
|
25
26
|
AgentSessionError,
|
|
@@ -31,6 +32,7 @@ export {
|
|
|
31
32
|
SessionInfo,
|
|
32
33
|
SessionSetupError,
|
|
33
34
|
SessionStatus,
|
|
35
|
+
ToolProvider,
|
|
34
36
|
chatErrorForDisplay,
|
|
35
37
|
contentPreview,
|
|
36
38
|
getFileParts,
|
package/dist/internal.js
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
SessionInfo,
|
|
19
19
|
SessionSetupError,
|
|
20
20
|
SessionStatus,
|
|
21
|
+
ToolProvider,
|
|
21
22
|
acceptedPostChatFollowupCompletesLatestRun,
|
|
22
23
|
acknowledgeTurnEvents,
|
|
23
24
|
applyTurnPatch,
|
|
@@ -82,7 +83,7 @@ import {
|
|
|
82
83
|
withTurns,
|
|
83
84
|
workflowEntriesFromOutput,
|
|
84
85
|
workflowNameFromArguments
|
|
85
|
-
} from "./chunk-
|
|
86
|
+
} from "./chunk-7LEZA2WA.js";
|
|
86
87
|
|
|
87
88
|
// src/polling-backoff.ts
|
|
88
89
|
var MAX_BACKOFF_MS = 6e4;
|
|
@@ -272,6 +273,7 @@ export {
|
|
|
272
273
|
SessionStatus,
|
|
273
274
|
Task,
|
|
274
275
|
TaskStatus,
|
|
276
|
+
ToolProvider,
|
|
275
277
|
acceptedPostChatFollowupCompletesLatestRun,
|
|
276
278
|
acknowledgeTurnEvents,
|
|
277
279
|
applyTurnPatch,
|
package/dist/internal.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/polling-backoff.ts","../src/platform-endpoints.ts","../src/commands/protocol.ts","../src/schemas/projection-utils.ts","../src/schemas/solution.ts","../src/schemas/task.ts"],"sourcesContent":["import { BladeApiError } from \"./rest\"\n\nconst MAX_BACKOFF_MS = 60_000\nconst MAX_TIMER_MS = 2_147_483_647\n\n/** Scheduling policy for read-only polling; never sends or replays a request. */\nexport class PollingBackoff {\n private failures = 0\n private nextAt: number | false = 0\n\n constructor(private readonly intervalMs: number) {\n if (!Number.isFinite(intervalMs) || intervalMs <= 0 || intervalMs > MAX_BACKOFF_MS) {\n throw new RangeError(\"Polling interval must be between 0 and 60000 ms\")\n }\n }\n\n reset(): void {\n this.failures = 0\n this.nextAt = 0\n }\n\n failed(error: unknown): void {\n if (\n (error instanceof Error && error.name === \"AbortError\") ||\n (error instanceof BladeApiError && error.status < 500 &&\n error.status !== 408 && error.status !== 429)\n ) {\n this.nextAt = false\n return\n }\n this.failures = Math.min(this.failures + 1, 10)\n const ceiling = Math.min(MAX_BACKOFF_MS, this.intervalMs * 2 ** this.failures)\n const backoff = Math.max(this.intervalMs, ceiling * (0.5 + Math.random() * 0.5))\n const header = error instanceof BladeApiError\n ? error.response.headers.get(\"Retry-After\")?.trim()\n : undefined\n const retryAfter = header\n ? /^\\d+$/.test(header) ? Number(header) * 1000 : Date.parse(header) - Date.now()\n : 0\n const delay = Math.max(backoff, Number.isNaN(retryAfter) ? 0 : retryAfter)\n // Oversized server delays must not overflow browser timers into a hot loop.\n this.nextAt = delay > MAX_TIMER_MS ? false : Date.now() + delay\n }\n\n /** Zero means ready, false means stop, otherwise wait at least this many ms. */\n waitMs(): number | false {\n return this.nextAt === false ? false : Math.max(0, this.nextAt - Date.now())\n }\n}\n","import { isRecord } from \"./shared/type-guards\"\n\nexport const PLATFORM_SERVICE_NAMES = [\n \"os\",\n \"hub\",\n \"agent\",\n \"oauth\",\n \"llmGateway\",\n \"gitea\",\n \"tile\",\n] as const\n\nexport type PlatformServiceName = (typeof PLATFORM_SERVICE_NAMES)[number]\n\nexport interface PlatformEndpoints {\n services: Partial<Record<PlatformServiceName, string>>\n}\n\nexport const EMPTY_PLATFORM_ENDPOINTS: PlatformEndpoints = Object.freeze({\n services: Object.freeze({}),\n})\n\nexport interface LoadPlatformEndpointsOptions {\n baseUrl?: string\n fetchImpl?: typeof fetch\n timeoutMs?: number\n}\n\nfunction defaultDocumentBaseUrl(): string | undefined {\n if (typeof document === \"undefined\") return undefined\n if (document.querySelector(\"base[href]\")) return document.baseURI\n if (typeof location !== \"undefined\" && location.origin) return `${location.origin}/`\n return document.baseURI\n}\n\nfunction normalizeServiceUrl(value: unknown): string | null {\n if (typeof value !== \"string\" || !value.trim()) return null\n if (value.includes(\"?\") || value.includes(\"#\")) return null\n try {\n const url = new URL(value.trim())\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return null\n if (url.username || url.password || url.search || url.hash) return null\n return url.toString().replace(/\\/$/, \"\")\n } catch {\n return null\n }\n}\n\nexport function parsePlatformEndpoints(value: unknown): PlatformEndpoints | null {\n if (!isRecord(value) || !isRecord(value.services)) return null\n\n const services: Partial<Record<PlatformServiceName, string>> = {}\n for (const name of PLATFORM_SERVICE_NAMES) {\n if (!(name in value.services)) continue\n const url = normalizeServiceUrl(value.services[name])\n if (!url) return null\n if (name === \"agent\" && new URL(url).pathname !== \"/\") return null\n services[name] = url\n }\n\n return { services }\n}\n\nexport async function loadPlatformEndpoints(\n options: LoadPlatformEndpointsOptions = {},\n): Promise<PlatformEndpoints> {\n const fetchImpl = options.fetchImpl ?? globalThis.fetch\n const baseUrl = options.baseUrl ?? defaultDocumentBaseUrl()\n if (!fetchImpl || !baseUrl) return EMPTY_PLATFORM_ENDPOINTS\n\n const controller = new AbortController()\n const timeout = globalThis.setTimeout(() => controller.abort(), options.timeoutMs ?? 3_000)\n try {\n const response = await fetchImpl(new URL(\"config.json\", baseUrl), {\n cache: \"no-store\",\n credentials: \"same-origin\",\n headers: { Accept: \"application/json\" },\n signal: controller.signal,\n })\n if (!response.ok) return EMPTY_PLATFORM_ENDPOINTS\n return parsePlatformEndpoints(await response.json()) ?? EMPTY_PLATFORM_ENDPOINTS\n } catch {\n return EMPTY_PLATFORM_ENDPOINTS\n } finally {\n globalThis.clearTimeout(timeout)\n }\n}\n\nexport function resolveServiceUrl(\n endpoints: PlatformEndpoints,\n name: PlatformServiceName,\n path = \"\",\n): string | null {\n const baseUrl = endpoints.services[name]\n if (!baseUrl) return null\n if (!path) return baseUrl\n const pathReference = path.trimStart()\n if (\n path.includes(\"\\\\\") ||\n pathReference.startsWith(\"//\") ||\n /^[a-z][a-z0-9+.-]*:/i.test(pathReference)\n ) {\n return null\n }\n const base = new URL(`${baseUrl}/`)\n const target = new URL(path.replace(/^\\/+/, \"\"), base)\n if (target.origin !== base.origin || !target.pathname.startsWith(base.pathname)) {\n return null\n }\n return target.toString()\n}\n","/**\n * 页面协作协议(对应后端 `_meta.bridge` 通道,见 docs/specs/260417-embed-bridge)。\n *\n * ## action 从哪里来\n *\n * 智能体 → 宿主方向的每一条指令,都源自**技能作者写的工具代码**:工具返回值\n * JSON 里带 `_meta.bridge: { action, payload }`,后端在持久化前把它剥离成独立\n * 事件送达前端(LLM 的对话历史里读不到它)。因此:\n *\n * - action 字符串(如 \"map.highlight\")是**技能作者与宿主页面开发者之间的业务\n * 契约**,LLM 不参与协议、SDK 不做枚举校验;\n * - 宿主页面用 `session.onCommand(\"map.highlight\", fn)` 消费;\n * - 未注册 handler 的 action 会进入有限缓冲等待注册,超限后丢弃并 console 告警。\n *\n * 宿主 → 智能体方向只有三个白名单动作:attach(附件入输入框)/ insertText\n * (追加输入文本)/ send(直接发消息),对应协议层的 addContext / appendInput /\n * sendMessage。\n */\n\nexport interface CommandEnvelope {\n __bladeBridge: true\n direction: \"agent-to-host\"\n action: string\n payload: unknown\n meta: {\n sessionId: string\n toolCallId?: string\n timestamp: number\n }\n}\n\nexport type InboundAction = \"addContext\" | \"appendInput\" | \"sendMessage\"\n\nexport interface InboundEnvelope {\n __bladeBridge: true\n direction: \"host-to-agent\"\n action: InboundAction\n payload: unknown\n}\n\nexport function isCommandEnvelope(value: unknown): value is CommandEnvelope {\n if (typeof value !== \"object\" || value === null) return false\n const record = value as Record<string, unknown>\n return (\n record.__bladeBridge === true &&\n record.direction === \"agent-to-host\" &&\n typeof record.action === \"string\"\n )\n}\n\nexport function isInboundEnvelope(value: unknown): value is InboundEnvelope {\n if (typeof value !== \"object\" || value === null) return false\n const record = value as Record<string, unknown>\n return (\n record.__bladeBridge === true &&\n record.direction === \"host-to-agent\" &&\n (record.action === \"addContext\" || record.action === \"appendInput\" || record.action === \"sendMessage\")\n )\n}\n","import type { PostChatFollowup, TurnProjection } from \"./projection\"\n\n/** 返回最新根会话轮次的小结;新用户消息到达后旧小结立即失效。 */\nexport function latestPostChatFollowup(turns: TurnProjection[]): PostChatFollowup | null {\n for (let index = turns.length - 1; index >= 0; index -= 1) {\n const turn = turns[index]\n if (\n turn.loop_id === \"root\" &&\n (turn.role === \"user\" || turn.role === \"assistant\") &&\n (turn.kind ?? \"message\") === \"message\" &&\n !turn.blocks.some((block) =>\n [\"mode_change\", \"plan_status\", \"ask_user_answer\"].includes(block.type),\n )\n ) {\n return turn.role === \"assistant\" ? (turn.post_chat_followup ?? null) : null\n }\n }\n return null\n}\n","export enum LayoutType {\n Default = \"default\",\n SkillEditor = \"skill-editor\",\n SolutionEditor = \"solution-editor\",\n SolutionApp = \"solution-app\",\n Custom = \"custom\",\n}\n\nexport interface Solution {\n id: string\n name: string\n version: string\n description?: string | null\n source?: \"builtin\" | \"personal\" | string | null\n layout_type: LayoutType | string\n initial_mode?: \"planning\" | \"executing\" | string | null\n initial_message?: string | null\n preview?: { url: string; title?: string | null } | null\n layout?: {\n available?: boolean\n source_dir?: string\n entry?: string\n export?: string\n } | null\n roles?: BizRole[] | null\n data?: Record<string, unknown> | null\n ui_config?: SolutionAppUiConfig | null\n}\n\nexport interface SolutionAppUiConfig {\n branding: {\n name: string\n subtitle?: string\n icon_text: string\n icon_gradient?: string\n }\n list: {\n title: string\n create_button: string\n card?: {\n subtitle?: string\n stats?: Array<{\n label: string\n value: string\n color?: string\n }>\n }\n }\n create: {\n title: string\n description?: string\n submit_button: string\n sections: Array<{\n id: string\n title: string\n description?: string\n fields: Array<SolutionAppField>\n }>\n }\n}\n\nexport type SolutionAppField =\n | {\n id: string\n kind: \"textarea\"\n label: string\n placeholder?: string\n }\n | {\n id: string\n kind: \"file-upload\"\n accept?: string[]\n categories?: Array<{\n label: string\n description: string\n color: string\n }>\n }\n\nexport interface SolutionAppState {\n pipeline: Array<{\n id: string\n label: string\n status: \"done\" | \"active\" | \"pending\" | \"error\"\n }>\n meta: Record<\n string,\n {\n label: string\n value: string\n color?: string\n }\n >\n}\n\nexport interface BizRole {\n id: string\n name: string\n description?: string | null\n preview?: { url: string; title?: string | null } | null\n}\n","import { type } from \"arktype\"\n\nexport const TaskStatus = type(\"'pending' | 'in_progress' | 'done' | 'failed' | 'skipped'\")\nexport type TaskStatus = typeof TaskStatus.infer\n\nexport const Task = type({\n id: \"string\",\n goal: \"string\",\n skills: \"string[]\",\n depends_on: \"string[]\",\n status: TaskStatus,\n result_summary: \"string\",\n number: \"string\",\n})\nexport type Task = typeof Task.infer\n"],"mappings":"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","names":["LayoutType"]}
|
|
1
|
+
{"version":3,"sources":["../src/polling-backoff.ts","../src/platform-endpoints.ts","../src/commands/protocol.ts","../src/schemas/projection-utils.ts","../src/schemas/solution.ts","../src/schemas/task.ts"],"sourcesContent":["import { BladeApiError } from \"./rest\"\n\nconst MAX_BACKOFF_MS = 60_000\nconst MAX_TIMER_MS = 2_147_483_647\n\n/** Scheduling policy for read-only polling; never sends or replays a request. */\nexport class PollingBackoff {\n private failures = 0\n private nextAt: number | false = 0\n\n constructor(private readonly intervalMs: number) {\n if (!Number.isFinite(intervalMs) || intervalMs <= 0 || intervalMs > MAX_BACKOFF_MS) {\n throw new RangeError(\"Polling interval must be between 0 and 60000 ms\")\n }\n }\n\n reset(): void {\n this.failures = 0\n this.nextAt = 0\n }\n\n failed(error: unknown): void {\n if (\n (error instanceof Error && error.name === \"AbortError\") ||\n (error instanceof BladeApiError && error.status < 500 &&\n error.status !== 408 && error.status !== 429)\n ) {\n this.nextAt = false\n return\n }\n this.failures = Math.min(this.failures + 1, 10)\n const ceiling = Math.min(MAX_BACKOFF_MS, this.intervalMs * 2 ** this.failures)\n const backoff = Math.max(this.intervalMs, ceiling * (0.5 + Math.random() * 0.5))\n const header = error instanceof BladeApiError\n ? error.response.headers.get(\"Retry-After\")?.trim()\n : undefined\n const retryAfter = header\n ? /^\\d+$/.test(header) ? Number(header) * 1000 : Date.parse(header) - Date.now()\n : 0\n const delay = Math.max(backoff, Number.isNaN(retryAfter) ? 0 : retryAfter)\n // Oversized server delays must not overflow browser timers into a hot loop.\n this.nextAt = delay > MAX_TIMER_MS ? false : Date.now() + delay\n }\n\n /** Zero means ready, false means stop, otherwise wait at least this many ms. */\n waitMs(): number | false {\n return this.nextAt === false ? false : Math.max(0, this.nextAt - Date.now())\n }\n}\n","import { isRecord } from \"./shared/type-guards\"\n\nexport const PLATFORM_SERVICE_NAMES = [\n \"os\",\n \"hub\",\n \"agent\",\n \"oauth\",\n \"llmGateway\",\n \"gitea\",\n \"tile\",\n] as const\n\nexport type PlatformServiceName = (typeof PLATFORM_SERVICE_NAMES)[number]\n\nexport interface PlatformEndpoints {\n services: Partial<Record<PlatformServiceName, string>>\n}\n\nexport const EMPTY_PLATFORM_ENDPOINTS: PlatformEndpoints = Object.freeze({\n services: Object.freeze({}),\n})\n\nexport interface LoadPlatformEndpointsOptions {\n baseUrl?: string\n fetchImpl?: typeof fetch\n timeoutMs?: number\n}\n\nfunction defaultDocumentBaseUrl(): string | undefined {\n if (typeof document === \"undefined\") return undefined\n if (document.querySelector(\"base[href]\")) return document.baseURI\n if (typeof location !== \"undefined\" && location.origin) return `${location.origin}/`\n return document.baseURI\n}\n\nfunction normalizeServiceUrl(value: unknown): string | null {\n if (typeof value !== \"string\" || !value.trim()) return null\n if (value.includes(\"?\") || value.includes(\"#\")) return null\n try {\n const url = new URL(value.trim())\n if (url.protocol !== \"http:\" && url.protocol !== \"https:\") return null\n if (url.username || url.password || url.search || url.hash) return null\n return url.toString().replace(/\\/$/, \"\")\n } catch {\n return null\n }\n}\n\nexport function parsePlatformEndpoints(value: unknown): PlatformEndpoints | null {\n if (!isRecord(value) || !isRecord(value.services)) return null\n\n const services: Partial<Record<PlatformServiceName, string>> = {}\n for (const name of PLATFORM_SERVICE_NAMES) {\n if (!(name in value.services)) continue\n const url = normalizeServiceUrl(value.services[name])\n if (!url) return null\n if (name === \"agent\" && new URL(url).pathname !== \"/\") return null\n services[name] = url\n }\n\n return { services }\n}\n\nexport async function loadPlatformEndpoints(\n options: LoadPlatformEndpointsOptions = {},\n): Promise<PlatformEndpoints> {\n const fetchImpl = options.fetchImpl ?? globalThis.fetch\n const baseUrl = options.baseUrl ?? defaultDocumentBaseUrl()\n if (!fetchImpl || !baseUrl) return EMPTY_PLATFORM_ENDPOINTS\n\n const controller = new AbortController()\n const timeout = globalThis.setTimeout(() => controller.abort(), options.timeoutMs ?? 3_000)\n try {\n const response = await fetchImpl(new URL(\"config.json\", baseUrl), {\n cache: \"no-store\",\n credentials: \"same-origin\",\n headers: { Accept: \"application/json\" },\n signal: controller.signal,\n })\n if (!response.ok) return EMPTY_PLATFORM_ENDPOINTS\n return parsePlatformEndpoints(await response.json()) ?? EMPTY_PLATFORM_ENDPOINTS\n } catch {\n return EMPTY_PLATFORM_ENDPOINTS\n } finally {\n globalThis.clearTimeout(timeout)\n }\n}\n\nexport function resolveServiceUrl(\n endpoints: PlatformEndpoints,\n name: PlatformServiceName,\n path = \"\",\n): string | null {\n const baseUrl = endpoints.services[name]\n if (!baseUrl) return null\n if (!path) return baseUrl\n const pathReference = path.trimStart()\n if (\n path.includes(\"\\\\\") ||\n pathReference.startsWith(\"//\") ||\n /^[a-z][a-z0-9+.-]*:/i.test(pathReference)\n ) {\n return null\n }\n const base = new URL(`${baseUrl}/`)\n const target = new URL(path.replace(/^\\/+/, \"\"), base)\n if (target.origin !== base.origin || !target.pathname.startsWith(base.pathname)) {\n return null\n }\n return target.toString()\n}\n","/**\n * 页面协作协议(对应后端 `_meta.bridge` 通道,见 docs/specs/260417-embed-bridge)。\n *\n * ## action 从哪里来\n *\n * 智能体 → 宿主方向的每一条指令,都源自**技能作者写的工具代码**:工具返回值\n * JSON 里带 `_meta.bridge: { action, payload }`,后端在持久化前把它剥离成独立\n * 事件送达前端(LLM 的对话历史里读不到它)。因此:\n *\n * - action 字符串(如 \"map.highlight\")是**技能作者与宿主页面开发者之间的业务\n * 契约**,LLM 不参与协议、SDK 不做枚举校验;\n * - 宿主页面用 `session.onCommand(\"map.highlight\", fn)` 消费;\n * - 未注册 handler 的 action 会进入有限缓冲等待注册,超限后丢弃并 console 告警。\n *\n * 宿主 → 智能体方向只有三个白名单动作:attach(附件入输入框)/ insertText\n * (追加输入文本)/ send(直接发消息),对应协议层的 addContext / appendInput /\n * sendMessage。\n */\n\nexport interface CommandEnvelope {\n __bladeBridge: true\n direction: \"agent-to-host\"\n action: string\n payload: unknown\n meta: {\n sessionId: string\n toolCallId?: string\n timestamp: number\n }\n}\n\nexport type InboundAction = \"addContext\" | \"appendInput\" | \"sendMessage\"\n\nexport interface InboundEnvelope {\n __bladeBridge: true\n direction: \"host-to-agent\"\n action: InboundAction\n payload: unknown\n}\n\nexport function isCommandEnvelope(value: unknown): value is CommandEnvelope {\n if (typeof value !== \"object\" || value === null) return false\n const record = value as Record<string, unknown>\n return (\n record.__bladeBridge === true &&\n record.direction === \"agent-to-host\" &&\n typeof record.action === \"string\"\n )\n}\n\nexport function isInboundEnvelope(value: unknown): value is InboundEnvelope {\n if (typeof value !== \"object\" || value === null) return false\n const record = value as Record<string, unknown>\n return (\n record.__bladeBridge === true &&\n record.direction === \"host-to-agent\" &&\n (record.action === \"addContext\" || record.action === \"appendInput\" || record.action === \"sendMessage\")\n )\n}\n","import type { PostChatFollowup, TurnProjection } from \"./projection\"\n\n/** 返回最新根会话轮次的小结;新用户消息到达后旧小结立即失效。 */\nexport function latestPostChatFollowup(turns: TurnProjection[]): PostChatFollowup | null {\n for (let index = turns.length - 1; index >= 0; index -= 1) {\n const turn = turns[index]\n if (\n turn.loop_id === \"root\" &&\n (turn.role === \"user\" || turn.role === \"assistant\") &&\n (turn.kind ?? \"message\") === \"message\" &&\n !turn.blocks.some((block) =>\n [\"mode_change\", \"plan_status\", \"ask_user_answer\"].includes(block.type),\n )\n ) {\n return turn.role === \"assistant\" ? (turn.post_chat_followup ?? null) : null\n }\n }\n return null\n}\n","export enum LayoutType {\n Default = \"default\",\n SkillEditor = \"skill-editor\",\n SolutionEditor = \"solution-editor\",\n SolutionApp = \"solution-app\",\n Custom = \"custom\",\n}\n\nexport interface Solution {\n id: string\n name: string\n version: string\n description?: string | null\n source?: \"builtin\" | \"personal\" | string | null\n layout_type: LayoutType | string\n initial_mode?: \"planning\" | \"executing\" | string | null\n initial_message?: string | null\n preview?: { url: string; title?: string | null } | null\n layout?: {\n available?: boolean\n source_dir?: string\n entry?: string\n export?: string\n } | null\n roles?: BizRole[] | null\n data?: Record<string, unknown> | null\n ui_config?: SolutionAppUiConfig | null\n}\n\nexport interface SolutionAppUiConfig {\n branding: {\n name: string\n subtitle?: string\n icon_text: string\n icon_gradient?: string\n }\n list: {\n title: string\n create_button: string\n card?: {\n subtitle?: string\n stats?: Array<{\n label: string\n value: string\n color?: string\n }>\n }\n }\n create: {\n title: string\n description?: string\n submit_button: string\n sections: Array<{\n id: string\n title: string\n description?: string\n fields: Array<SolutionAppField>\n }>\n }\n}\n\nexport type SolutionAppField =\n | {\n id: string\n kind: \"textarea\"\n label: string\n placeholder?: string\n }\n | {\n id: string\n kind: \"file-upload\"\n accept?: string[]\n categories?: Array<{\n label: string\n description: string\n color: string\n }>\n }\n\nexport interface SolutionAppState {\n pipeline: Array<{\n id: string\n label: string\n status: \"done\" | \"active\" | \"pending\" | \"error\"\n }>\n meta: Record<\n string,\n {\n label: string\n value: string\n color?: string\n }\n >\n}\n\nexport interface BizRole {\n id: string\n name: string\n description?: string | null\n preview?: { url: string; title?: string | null } | null\n}\n","import { type } from \"arktype\"\n\nexport const TaskStatus = type(\"'pending' | 'in_progress' | 'done' | 'failed' | 'skipped'\")\nexport type TaskStatus = typeof TaskStatus.infer\n\nexport const Task = type({\n id: \"string\",\n goal: \"string\",\n skills: \"string[]\",\n depends_on: \"string[]\",\n status: TaskStatus,\n result_summary: \"string\",\n number: \"string\",\n})\nexport type Task = typeof Task.infer\n"],"mappings":"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","names":["LayoutType"]}
|
|
@@ -87,6 +87,8 @@ export interface SessionPluginConfigUpdate {
|
|
|
87
87
|
remove?: string[];
|
|
88
88
|
}
|
|
89
89
|
export interface CreateSessionRequest {
|
|
90
|
+
/** 认证创建独立匿名沙盒;链接持有者可继续聊天,不继承个人资源。 */
|
|
91
|
+
anonymous?: boolean;
|
|
90
92
|
intent?: string;
|
|
91
93
|
/** 正式 Solution 来源。Hub 使用 { source: "hub", org, name }。 */
|
|
92
94
|
solution_ref?: PublishedSolutionRef;
|
|
@@ -557,6 +559,15 @@ export declare class SessionsResource {
|
|
|
557
559
|
id: string;
|
|
558
560
|
leaf_id: string;
|
|
559
561
|
}>;
|
|
562
|
+
listAnonymousSessions(): Promise<Array<{
|
|
563
|
+
id: string;
|
|
564
|
+
intent: string;
|
|
565
|
+
created_at: string;
|
|
566
|
+
status: string;
|
|
567
|
+
}>>;
|
|
568
|
+
deleteAnonymousSession(sessionId: string): Promise<{
|
|
569
|
+
deleted: boolean;
|
|
570
|
+
}>;
|
|
560
571
|
deleteSession(sessionId: string, options?: {
|
|
561
572
|
deleteWorkspace?: boolean;
|
|
562
573
|
}): Promise<{
|
|
@@ -87,6 +87,7 @@ export interface ChatMessage {
|
|
|
87
87
|
duration_ms?: number;
|
|
88
88
|
timestamp?: string;
|
|
89
89
|
entry_id?: string;
|
|
90
|
+
client_request_id?: string;
|
|
90
91
|
/** Stable React key retained when an optimistic user message is confirmed. */
|
|
91
92
|
render_id?: string;
|
|
92
93
|
parent_id?: string | null;
|
|
@@ -58,6 +58,7 @@ export declare const SessionInfo: import("arktype/internal/variants/object.ts").
|
|
|
58
58
|
created_at: string;
|
|
59
59
|
updated_at: string;
|
|
60
60
|
shared?: boolean | undefined;
|
|
61
|
+
anonymous?: boolean | undefined;
|
|
61
62
|
memory_enabled?: boolean | undefined;
|
|
62
63
|
is_persistent?: boolean | undefined;
|
|
63
64
|
initiator?: "sdk" | "ui" | "unknown" | null | undefined;
|
|
@@ -84,6 +84,27 @@ export interface SendOptions {
|
|
|
84
84
|
*/
|
|
85
85
|
queueWhenRunning?: boolean;
|
|
86
86
|
}
|
|
87
|
+
/** Durable plain-text input. Persist this JSON value before calling sendPrepared. */
|
|
88
|
+
export interface PreparedSend {
|
|
89
|
+
sessionId: string;
|
|
90
|
+
requestId: string;
|
|
91
|
+
content: string;
|
|
92
|
+
options: PreparedSendOptions;
|
|
93
|
+
}
|
|
94
|
+
export interface PreparedSendOptions {
|
|
95
|
+
mode?: "planning" | "executing";
|
|
96
|
+
model?: string;
|
|
97
|
+
thinkingOverride?: boolean;
|
|
98
|
+
reasoningLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
|
|
99
|
+
}
|
|
100
|
+
export interface DeliveryReceipt {
|
|
101
|
+
requestId: string;
|
|
102
|
+
status: "accepted" | "not_found" | "rejected" | "unknown";
|
|
103
|
+
itemId?: string;
|
|
104
|
+
queueStatus?: string;
|
|
105
|
+
executionId?: string | null;
|
|
106
|
+
message?: string;
|
|
107
|
+
}
|
|
87
108
|
export declare function sessionStatusFromChatEnd(status: string | undefined): SessionStatus;
|
|
88
109
|
/**
|
|
89
110
|
* 一个会话的实时状态机:封装 Socket.IO 订阅、历史 + 流式合流、断线补数,
|
|
@@ -265,6 +286,12 @@ export declare class AgentSession {
|
|
|
265
286
|
* CLI 安装成功后才保存 getContext;之后每次 send 前恰好读取一次。
|
|
266
287
|
*/
|
|
267
288
|
attachApp(options: AttachAppOptions): Promise<AppCliAttachment | null>;
|
|
289
|
+
/** Prepare a durable text input without sending any network request. */
|
|
290
|
+
prepareSend(content: string, options?: PreparedSendOptions): PreparedSend;
|
|
291
|
+
/** Durably enqueue an ordinary text input. Retries must reuse the saved request. */
|
|
292
|
+
sendPrepared(request: PreparedSend): Promise<DeliveryReceipt>;
|
|
293
|
+
/** Owner-authorized lookup; receipts remain until the session is deleted. */
|
|
294
|
+
getDelivery(requestId: string): Promise<DeliveryReceipt>;
|
|
268
295
|
/** 发送一条消息。字符串或多模态内容均可。 */
|
|
269
296
|
send(content: MessageContent, options?: SendOptions): Promise<boolean>;
|
|
270
297
|
/**
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { BladeClient } from "./blade-client";
|
|
2
|
+
export interface ProviderTool {
|
|
3
|
+
name: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
inputSchema: Record<string, unknown>;
|
|
6
|
+
handler: (arguments_: Record<string, unknown>, context: {
|
|
7
|
+
sessionId: string;
|
|
8
|
+
signal: AbortSignal;
|
|
9
|
+
}) => Promise<ProviderToolResult>;
|
|
10
|
+
}
|
|
11
|
+
export interface ProviderToolResult {
|
|
12
|
+
content: Array<{
|
|
13
|
+
type: "text";
|
|
14
|
+
text: string;
|
|
15
|
+
}>;
|
|
16
|
+
structuredContent?: Record<string, unknown>;
|
|
17
|
+
isError?: boolean;
|
|
18
|
+
}
|
|
19
|
+
export interface ToolProviderOptions {
|
|
20
|
+
/** Stable application-owned ID, preserved across reconnects. */
|
|
21
|
+
providerId: string;
|
|
22
|
+
/** Secret bound to the session's mcp_sources bearer_token. */
|
|
23
|
+
capability: string;
|
|
24
|
+
tools: ProviderTool[];
|
|
25
|
+
onError?: (error: Error) => void;
|
|
26
|
+
}
|
|
27
|
+
/** Backend-only outbound connection. Reconnects registrations, never tool calls. */
|
|
28
|
+
export declare class ToolProvider {
|
|
29
|
+
private client;
|
|
30
|
+
private options;
|
|
31
|
+
private onDispose;
|
|
32
|
+
readonly url: string;
|
|
33
|
+
private socket?;
|
|
34
|
+
private timer?;
|
|
35
|
+
private registrationTimer?;
|
|
36
|
+
private disposed;
|
|
37
|
+
private registered;
|
|
38
|
+
private attempts;
|
|
39
|
+
private calls;
|
|
40
|
+
private waiters;
|
|
41
|
+
constructor(client: BladeClient, options: ToolProviderOptions, onDispose: () => void);
|
|
42
|
+
/** Resolves only after BA has authenticated and registered this connection. */
|
|
43
|
+
ready(): Promise<void>;
|
|
44
|
+
reconnect(): void;
|
|
45
|
+
private reset;
|
|
46
|
+
private fail;
|
|
47
|
+
private open;
|
|
48
|
+
private schedule;
|
|
49
|
+
private receive;
|
|
50
|
+
dispose(): void;
|
|
51
|
+
}
|
|
@@ -109,14 +109,35 @@ export declare namespace ChatAppendPayloadSchema {
|
|
|
109
109
|
type SessionId = string;
|
|
110
110
|
type Message = string;
|
|
111
111
|
type ClientRequestId = (string | null);
|
|
112
|
+
type Mode = (("planning" | "executing") | null);
|
|
113
|
+
type Model = (string | null);
|
|
114
|
+
type ThinkingOverride = (boolean | null);
|
|
115
|
+
type ReasoningLevel = (("off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max") | null);
|
|
112
116
|
interface ChatAppendPayload {
|
|
113
117
|
session_id: SessionId;
|
|
114
118
|
message: Message;
|
|
115
119
|
client_request_id?: ClientRequestId;
|
|
120
|
+
prepared_options?: (PreparedSendOptions | null);
|
|
116
121
|
[k: string]: unknown;
|
|
117
122
|
}
|
|
123
|
+
interface PreparedSendOptions {
|
|
124
|
+
mode?: Mode;
|
|
125
|
+
model?: Model;
|
|
126
|
+
thinking_override?: ThinkingOverride;
|
|
127
|
+
reasoning_level?: ReasoningLevel;
|
|
128
|
+
}
|
|
118
129
|
}
|
|
119
130
|
export type ChatAppendPayload = ChatAppendPayloadSchema.ChatAppendPayload;
|
|
131
|
+
export declare namespace ChatQueueRequestPayloadSchema {
|
|
132
|
+
type SessionId = string;
|
|
133
|
+
type ClientRequestId = string;
|
|
134
|
+
interface ChatQueueRequestPayload {
|
|
135
|
+
session_id: SessionId;
|
|
136
|
+
client_request_id: ClientRequestId;
|
|
137
|
+
[k: string]: unknown;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
export type ChatQueueRequestPayload = ChatQueueRequestPayloadSchema.ChatQueueRequestPayload;
|
|
120
141
|
export declare namespace ChatCompactPayloadSchema {
|
|
121
142
|
type SessionId = string;
|
|
122
143
|
interface ChatCompactPayload {
|
|
@@ -598,6 +619,12 @@ export declare namespace ChatQueueAckSchema {
|
|
|
598
619
|
type Items = ChatQueueItem[];
|
|
599
620
|
type Status1 = string;
|
|
600
621
|
type Message = (string | null);
|
|
622
|
+
type Status2 = ("accepted" | "not_found" | "error");
|
|
623
|
+
type RequestId = (string | null);
|
|
624
|
+
type ItemId = (string | null);
|
|
625
|
+
type QueueStatus = (string | null);
|
|
626
|
+
type ExecutionId = (string | null);
|
|
627
|
+
type Message1 = (string | null);
|
|
601
628
|
interface ChatQueueAck {
|
|
602
629
|
session_id: SessionId;
|
|
603
630
|
revision: Revision;
|
|
@@ -606,6 +633,7 @@ export declare namespace ChatQueueAckSchema {
|
|
|
606
633
|
items?: Items;
|
|
607
634
|
status?: Status1;
|
|
608
635
|
message?: Message;
|
|
636
|
+
delivery?: (ChatDeliveryAck | null);
|
|
609
637
|
[k: string]: unknown;
|
|
610
638
|
}
|
|
611
639
|
interface ChatQueueItem {
|
|
@@ -620,12 +648,40 @@ export declare namespace ChatQueueAckSchema {
|
|
|
620
648
|
error?: Error;
|
|
621
649
|
[k: string]: unknown;
|
|
622
650
|
}
|
|
651
|
+
interface ChatDeliveryAck {
|
|
652
|
+
status: Status2;
|
|
653
|
+
request_id?: RequestId;
|
|
654
|
+
item_id?: ItemId;
|
|
655
|
+
queue_status?: QueueStatus;
|
|
656
|
+
execution_id?: ExecutionId;
|
|
657
|
+
message?: Message1;
|
|
658
|
+
[k: string]: unknown;
|
|
659
|
+
}
|
|
623
660
|
}
|
|
624
661
|
export type ChatQueueAck = ChatQueueAckSchema.ChatQueueAck;
|
|
662
|
+
export declare namespace ChatDeliveryAckSchema {
|
|
663
|
+
type Status = ("accepted" | "not_found" | "error");
|
|
664
|
+
type RequestId = (string | null);
|
|
665
|
+
type ItemId = (string | null);
|
|
666
|
+
type QueueStatus = (string | null);
|
|
667
|
+
type ExecutionId = (string | null);
|
|
668
|
+
type Message = (string | null);
|
|
669
|
+
interface ChatDeliveryAck {
|
|
670
|
+
status: Status;
|
|
671
|
+
request_id?: RequestId;
|
|
672
|
+
item_id?: ItemId;
|
|
673
|
+
queue_status?: QueueStatus;
|
|
674
|
+
execution_id?: ExecutionId;
|
|
675
|
+
message?: Message;
|
|
676
|
+
[k: string]: unknown;
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
export type ChatDeliveryAck = ChatDeliveryAckSchema.ChatDeliveryAck;
|
|
625
680
|
export interface ClientToServerEvents {
|
|
626
681
|
"chat:send": (payload: ChatSendPayload, ack: (response: ChatSendAck) => void) => void;
|
|
627
682
|
"chat:stop": (payload: ChatStopPayload, ack: (response: ChatStopAck) => void) => void;
|
|
628
683
|
"chat:append": (payload: ChatAppendPayload, ack: (response: ChatQueueAck) => void) => void;
|
|
684
|
+
"chat:queue:request": (payload: ChatQueueRequestPayload, ack: (response: ChatDeliveryAck) => void) => void;
|
|
629
685
|
"chat:compact": (payload: ChatCompactPayload, ack: (response: ChatCompactAck) => void) => void;
|
|
630
686
|
"chat:queue:list": (payload: ChatQueueListPayload, ack: (response: ChatQueueAck) => void) => void;
|
|
631
687
|
"chat:queue:update": (payload: ChatQueueUpdatePayload, ack: (response: ChatQueueAck) => void) => void;
|
package/package.json
CHANGED
package/public-api.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> 本文件由 `scripts/public-api-report.mjs` 生成,请勿手改。
|
|
4
4
|
> 公共面变更时重新生成本报告,并同步更新 README 对应章节——CI 会校验两者。
|
|
5
5
|
|
|
6
|
-
共
|
|
6
|
+
共 113 个公开声明。
|
|
7
7
|
|
|
8
8
|
## `AccountComputer` (interface)
|
|
9
9
|
|
|
@@ -62,6 +62,7 @@ deliverQueuedMessage: (itemId: string, expectedVersion: number) => Promise<Queue
|
|
|
62
62
|
dispose: () => void
|
|
63
63
|
downloadFile: (filePath: string, downloadName?: string) => Promise<void>
|
|
64
64
|
exitReplay: () => Promise<void>
|
|
65
|
+
getDelivery: (requestId: string) => Promise<DeliveryReceipt>
|
|
65
66
|
getState: () => SessionState
|
|
66
67
|
hasOlderHistory: boolean
|
|
67
68
|
insertText: (text: string) => void
|
|
@@ -74,6 +75,7 @@ locateEntry: (entryId: string) => Promise<boolean>
|
|
|
74
75
|
off: <K extends keyof AgentSessionEvents>(name: K, handler: (event: AgentSessionEvents[K]) => void) => void
|
|
75
76
|
on: <K extends keyof AgentSessionEvents>(name: K, handler: (event: AgentSessionEvents[K]) => void) => () => void
|
|
76
77
|
onCommand: (action: string, handler: CommandHandler) => () => void
|
|
78
|
+
prepareSend: (content: string, options?: PreparedSendOptions) => PreparedSend
|
|
77
79
|
queueMessage: (content: string) => Promise<QueueOperationResult>
|
|
78
80
|
refreshQueue: () => Promise<QueueOperationResult>
|
|
79
81
|
refreshRunningState: () => Promise<void>
|
|
@@ -81,6 +83,7 @@ reloadHistory: () => Promise<boolean>
|
|
|
81
83
|
reorderQueuedMessages: (expectedRevision: number, orderedIds: string[]) => Promise<QueueOperationResult>
|
|
82
84
|
resumeQueue: () => Promise<QueueOperationResult>
|
|
83
85
|
send: (content: MessageContent, options?: SendOptions) => Promise<boolean>
|
|
86
|
+
sendPrepared: (request: PreparedSend) => Promise<DeliveryReceipt>
|
|
84
87
|
sessionId: string
|
|
85
88
|
setReplaySpeed: (speed: ReplaySpeed) => Promise<void>
|
|
86
89
|
stop: () => Promise<Record<string, unknown>>
|
|
@@ -200,7 +203,9 @@ blob: (method: HttpMethod, path: string) => Promise<Blob>
|
|
|
200
203
|
buildAuthedUrl: (path: string) => string
|
|
201
204
|
chatGroups: ChatGroupsResource
|
|
202
205
|
computers: ComputersResource
|
|
206
|
+
connectToolProvider: (options: ToolProviderOptions) => ToolProvider
|
|
203
207
|
fetch: (method: HttpMethod, path: string, init?: BladeFetchInit, isRetry?: boolean) => Promise<Response>
|
|
208
|
+
forAnonymousSession: (sessionId: string) => BladeClient
|
|
204
209
|
formData: (method: HttpMethod, path: string, form: FormData, options?: { expectOk?: boolean; onUploadProgress?: (progress: UploadProgress) => void; }) => Promise<Response>
|
|
205
210
|
hasToken: () => boolean
|
|
206
211
|
headless: HeadlessResource
|
|
@@ -228,8 +233,9 @@ token: string | null
|
|
|
228
233
|
## `BladeClientOptions` (interface)
|
|
229
234
|
|
|
230
235
|
```ts
|
|
236
|
+
anonymousSessionId: string | undefined
|
|
231
237
|
baseUrl: string
|
|
232
|
-
commandTransport: ((event: string, payload: Record<string, unknown>, send: () => Promise<Record<string, unknown
|
|
238
|
+
commandTransport: ((event: string, payload: Record<string, unknown>, send: () => Promise<Record<string, unknown>>, scope?: { anonymousSessionId: string; }) => Promise<Record<string, unknown>>) | undefined
|
|
233
239
|
fetchImpl: { (input: RequestInfo | URL, init?: RequestInit): Promise<Response>; (input: string | URL | Request, init?: RequestInit): Promise<Response>; (input: string | URL | Request, init?: RequestInit): Promise<Response>; } | undefined
|
|
234
240
|
onRefreshSuccess: (() => void | Promise<void>) | undefined
|
|
235
241
|
socketToken: string | (() => string | null | undefined) | undefined
|
|
@@ -321,6 +327,7 @@ updated_at: string
|
|
|
321
327
|
|
|
322
328
|
```ts
|
|
323
329
|
blocks: ContentBlock[] | undefined
|
|
330
|
+
client_request_id: string | undefined
|
|
324
331
|
compaction: CompactionInfo | undefined
|
|
325
332
|
content: MessageContent
|
|
326
333
|
context: ContextProjectionData | undefined
|
|
@@ -380,6 +387,7 @@ title: string
|
|
|
380
387
|
|
|
381
388
|
```ts
|
|
382
389
|
agent_runtime_id: string | null | undefined
|
|
390
|
+
anonymous: boolean | undefined
|
|
383
391
|
biz_role_id: string | null | undefined
|
|
384
392
|
chat_group_id: string | null | undefined
|
|
385
393
|
compaction_ratio: number | null | undefined
|
|
@@ -405,6 +413,17 @@ solution_snapshot_session_id: string | undefined
|
|
|
405
413
|
DEFAULT_REPLAY_SPEED: ReplaySpeed
|
|
406
414
|
```
|
|
407
415
|
|
|
416
|
+
## `DeliveryReceipt` (interface)
|
|
417
|
+
|
|
418
|
+
```ts
|
|
419
|
+
executionId: string | null | undefined
|
|
420
|
+
itemId: string | undefined
|
|
421
|
+
message: string | undefined
|
|
422
|
+
queueStatus: string | undefined
|
|
423
|
+
requestId: string
|
|
424
|
+
status: "unknown" | "accepted" | "not_found" | "rejected"
|
|
425
|
+
```
|
|
426
|
+
|
|
408
427
|
## `ExchangeCodeParams` (interface)
|
|
409
428
|
|
|
410
429
|
```ts
|
|
@@ -607,6 +626,24 @@ provider: "plugin"
|
|
|
607
626
|
server: string
|
|
608
627
|
```
|
|
609
628
|
|
|
629
|
+
## `PreparedSend` (interface)
|
|
630
|
+
|
|
631
|
+
```ts
|
|
632
|
+
content: string
|
|
633
|
+
options: PreparedSendOptions
|
|
634
|
+
requestId: string
|
|
635
|
+
sessionId: string
|
|
636
|
+
```
|
|
637
|
+
|
|
638
|
+
## `PreparedSendOptions` (interface)
|
|
639
|
+
|
|
640
|
+
```ts
|
|
641
|
+
mode: "planning" | "executing" | undefined
|
|
642
|
+
model: string | undefined
|
|
643
|
+
reasoningLevel: "max" | "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | undefined
|
|
644
|
+
thinkingOverride: boolean | undefined
|
|
645
|
+
```
|
|
646
|
+
|
|
610
647
|
## `ProvidersResponse` (interface)
|
|
611
648
|
|
|
612
649
|
```ts
|
|
@@ -614,6 +651,23 @@ password_enabled: boolean
|
|
|
614
651
|
providers: { name: string; authorize_url: string; }[]
|
|
615
652
|
```
|
|
616
653
|
|
|
654
|
+
## `ProviderTool` (interface)
|
|
655
|
+
|
|
656
|
+
```ts
|
|
657
|
+
description: string | undefined
|
|
658
|
+
handler: (arguments_: Record<string, unknown>, context: { sessionId: string; signal: AbortSignal; }) => Promise<ProviderToolResult>
|
|
659
|
+
inputSchema: Record<string, unknown>
|
|
660
|
+
name: string
|
|
661
|
+
```
|
|
662
|
+
|
|
663
|
+
## `ProviderToolResult` (interface)
|
|
664
|
+
|
|
665
|
+
```ts
|
|
666
|
+
content: { type: "text"; text: string; }[]
|
|
667
|
+
isError: boolean | undefined
|
|
668
|
+
structuredContent: Record<string, unknown> | undefined
|
|
669
|
+
```
|
|
670
|
+
|
|
617
671
|
## `QueuedMessage` (interface)
|
|
618
672
|
|
|
619
673
|
```ts
|
|
@@ -780,6 +834,7 @@ solution: SolutionDefinition | undefined
|
|
|
780
834
|
|
|
781
835
|
```ts
|
|
782
836
|
agent_runtime_id: string | null | undefined
|
|
837
|
+
anonymous: boolean | undefined
|
|
783
838
|
ba_version: string | null | undefined
|
|
784
839
|
biz_role_id: string | null | undefined
|
|
785
840
|
chat_group_id: string | null | undefined
|
|
@@ -825,6 +880,7 @@ SessionInfo = type({
|
|
|
825
880
|
created_at: "string",
|
|
826
881
|
updated_at: "string",
|
|
827
882
|
"shared?": "boolean",
|
|
883
|
+
"anonymous?": "boolean",
|
|
828
884
|
"memory_enabled?": "boolean",
|
|
829
885
|
"is_persistent?": "boolean",
|
|
830
886
|
"initiator?": "'ui' | 'sdk' | 'unknown' | null",
|
|
@@ -895,6 +951,7 @@ createSession: (intent?: string) => Promise<{ session_id: string; }>
|
|
|
895
951
|
createSessionWithRequest: (request: CreateSessionRequest) => Promise<{ session_id: string; }>
|
|
896
952
|
createShare: (sessionId: string) => Promise<ShareLinkResult>
|
|
897
953
|
createWithProfile: (params: { intent: string; profile: SessionProfile; }) => Promise<{ session_id: string; }>
|
|
954
|
+
deleteAnonymousSession: (sessionId: string) => Promise<{ deleted: boolean; }>
|
|
898
955
|
deleteFile: (sessionId: string, filePath: string) => Promise<void>
|
|
899
956
|
deleteSession: (sessionId: string, options?: { deleteWorkspace?: boolean; }) => Promise<{ deleted: boolean; workspace_deleted?: boolean; }>
|
|
900
957
|
downloadFile: (sessionId: string, filePath: string, downloadName?: string) => Promise<void>
|
|
@@ -920,6 +977,7 @@ getSessionTurns: (sessionId: string) => Promise<TurnProjection[]>
|
|
|
920
977
|
getSessionTurnsPage: (sessionId: string, options?: SessionTurnsQuery, init?: RequestInit) => Promise<SessionTurnsPage>
|
|
921
978
|
getSharedSession: (token: string) => Promise<TurnProjection[]>
|
|
922
979
|
importSession: (file: File, name?: string, solutionOverride?: string | null | ImportSessionOptions) => Promise<{ session_id: string; }>
|
|
980
|
+
listAnonymousSessions: () => Promise<Array<{ id: string; intent: string; created_at: string; status: string; }>>
|
|
923
981
|
listBackgroundTasks: (sessionId: string, init?: RequestInit) => Promise<BackgroundTask[]>
|
|
924
982
|
listDir: (sessionId: string, dirPath: string, showHidden?: boolean) => Promise<FileEntry[]>
|
|
925
983
|
listResultFeedback: (sessionId: string) => Promise<ResultFeedback[]>
|
|
@@ -1095,6 +1153,24 @@ tool_call_id: string
|
|
|
1095
1153
|
url: string | undefined
|
|
1096
1154
|
```
|
|
1097
1155
|
|
|
1156
|
+
## `ToolProvider` (class)
|
|
1157
|
+
|
|
1158
|
+
```ts
|
|
1159
|
+
dispose: () => void
|
|
1160
|
+
ready: () => Promise<void>
|
|
1161
|
+
reconnect: () => void
|
|
1162
|
+
url: string
|
|
1163
|
+
```
|
|
1164
|
+
|
|
1165
|
+
## `ToolProviderOptions` (interface)
|
|
1166
|
+
|
|
1167
|
+
```ts
|
|
1168
|
+
capability: string
|
|
1169
|
+
onError: ((error: Error) => void) | undefined
|
|
1170
|
+
providerId: string
|
|
1171
|
+
tools: ProviderTool[]
|
|
1172
|
+
```
|
|
1173
|
+
|
|
1098
1174
|
## `TopicAssetRef` (interface)
|
|
1099
1175
|
|
|
1100
1176
|
```ts
|