@tansr/sdk 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -49,12 +49,21 @@ for await (const event of session.events) {
49
49
  ——环2 内置本地工具(read/glob/grep/shell/…)、环3 平台托管能力(imageGen 图像
50
50
  生成,平台代调按张计费)、环1 `defineTool` 业务函数(注册即说明书,JSON 参数表/
51
51
  zod 双档);
52
+ - **联网搜索双位双门**:webSearch 工具本体是内置 `WebSearch`(写在 `tools.builtin`,
53
+ 旧写法 `tools.platform` 报迁移错),后端恒平台通道(按次计费归 App,SDK 恒无 BYO
54
+ 径)——装配需双位齐开(`tools.webSearch` 工具位 + `platform.webSearch` 通道位)且
55
+ 令牌档在场;缺席选择时门不备静默不装,显式选择即 fail-fast 分因可读错(详见手册
56
+ §5.3);
52
57
  - **skills**:`defineSkill` 内联 + `dirs` 目录装载(`<name>/SKILL.md`),按需装载零
53
58
  发现(恒不扫用户目录);
54
59
  - **MCP 外接**:`createMcpHost({ servers })` 应用级共享 / `mcp: { servers }` 会话级,
55
60
  配置与业界 `mcpServers` 同形;
56
61
  - **渲染管道**:`createSessionView`(事件流 → 不可变视图快照,structuredClone-safe,
57
- Electron IPC 直传)+ `createNarrator`(人类可读日志行);恒不用手拼事件;
62
+ Electron IPC 直传)+ `createNarrator`(人类可读日志行);恒不用手拼事件;呈现档
63
+ 开发者可选:`{ delivery: { text: 'stream'|'final', thinking: 'stream'|'final'|'off' } }`
64
+ ——文本/思考各自选流式或整段一次性,思考可整体关显(状态派生与工具卡恒不受影响,
65
+ 缺省全流式零漂移);且可**动态切换**:`view.setDelivery(delivery)` 块粒度即时生效,
66
+ 切 off 自动追溯剔除既有思考(详见手册 §9.1);
58
67
  - **权限**:`permission: { mode?, rules?, askUser? }`——ask 裁决桥到你的 UI,缺席
59
68
  fail-closed 降级 deny;
60
69
  - **计量**:`cost.usage.updated` 逐请求;终端自查 `/v1/my-usage` 恒无金额字段,
package/dist/index.d.ts CHANGED
@@ -10087,6 +10087,50 @@ interface Tool<Args = unknown> {
10087
10087
  execute(args: Args, ctx: ToolContext): Promise<ToolResult>;
10088
10088
  }
10089
10089
 
10090
+ /**
10091
+ * T-D6 — 会话待办台账(内存态,不做持久化)。
10092
+ *
10093
+ * 设计要点:
10094
+ * - `TodoItem` 形状与 protocol `plan.todo.updated` 事件的 items 对齐
10095
+ * (id/content/status 三字段;status 在事件侧是宽松 string,本侧收窄为枚举);
10096
+ * - 依赖注入:`onChange` 由工厂(内核会话装配处)注入,store 本身不发事件、
10097
+ * 不落盘——外部在回调里接线 `plan.todo.updated` 事件与(未来的)持久化;
10098
+ * - 所有对外暴露的数组/对象均为副本,防止调用方或回调持引用后污染内部状态。
10099
+ */
10100
+ /** 待办状态全集(as const 元组,供 zod enum 与类型共用一份事实源) */
10101
+ declare const TODO_STATUSES: readonly ["pending", "in_progress", "completed", "cancelled"];
10102
+ type TodoStatus = (typeof TODO_STATUSES)[number];
10103
+ interface TodoItem {
10104
+ id: string;
10105
+ content: string;
10106
+ status: TodoStatus;
10107
+ }
10108
+ /**
10109
+ * merge 输入:按 id 定位,已知 id 只覆盖给定字段(未给字段保留原值);
10110
+ * 未知 id 追加为新项,此时 content 与 status 必须齐全(TodoWrite 工具
10111
+ * 的 schema 恒为全量,不会触发缺字段路径;此约束仅防御其他内部调用方)。
10112
+ */
10113
+ type TodoPatch = {
10114
+ id: string;
10115
+ } & Partial<Omit<TodoItem, 'id'>>;
10116
+ interface TodoStoreOptions {
10117
+ /** 变更回调:replace/merge 每次调用后触发一次,载荷为变更后完整列表的独立副本 */
10118
+ onChange?: (items: TodoItem[]) => void;
10119
+ }
10120
+ declare class TodoStore {
10121
+ #private;
10122
+ constructor(options?: TodoStoreOptions);
10123
+ /** 当前列表(副本;修改返回值不影响内部状态) */
10124
+ list(): TodoItem[];
10125
+ /** 全量替换(含替换为空 = 清空台账),返回变更后快照 */
10126
+ replace(items: readonly TodoItem[]): TodoItem[];
10127
+ /**
10128
+ * 按 id 合并:已知 id 原位覆盖给定字段;未知 id 按提交顺序追加到尾部。
10129
+ * 返回变更后快照。未知 id 缺 content/status 视为调用方契约错误,抛 TypeError。
10130
+ */
10131
+ merge(patches: readonly TodoPatch[]): TodoItem[];
10132
+ }
10133
+
10090
10134
  /**
10091
10135
  * T-C1 — 测试用顺序工具执行器(ToolExecutor 的最小实现)。
10092
10136
  *
@@ -10820,50 +10864,6 @@ type OnToolDecision = (record: ToolDecisionRecord) => void;
10820
10864
  */
10821
10865
  type CaptureFileCheckpoints = (paths: readonly string[]) => Promise<void> | void;
10822
10866
 
10823
- /**
10824
- * T-D6 — 会话待办台账(内存态,不做持久化)。
10825
- *
10826
- * 设计要点:
10827
- * - `TodoItem` 形状与 protocol `plan.todo.updated` 事件的 items 对齐
10828
- * (id/content/status 三字段;status 在事件侧是宽松 string,本侧收窄为枚举);
10829
- * - 依赖注入:`onChange` 由工厂(内核会话装配处)注入,store 本身不发事件、
10830
- * 不落盘——外部在回调里接线 `plan.todo.updated` 事件与(未来的)持久化;
10831
- * - 所有对外暴露的数组/对象均为副本,防止调用方或回调持引用后污染内部状态。
10832
- */
10833
- /** 待办状态全集(as const 元组,供 zod enum 与类型共用一份事实源) */
10834
- declare const TODO_STATUSES: readonly ["pending", "in_progress", "completed", "cancelled"];
10835
- type TodoStatus = (typeof TODO_STATUSES)[number];
10836
- interface TodoItem {
10837
- id: string;
10838
- content: string;
10839
- status: TodoStatus;
10840
- }
10841
- /**
10842
- * merge 输入:按 id 定位,已知 id 只覆盖给定字段(未给字段保留原值);
10843
- * 未知 id 追加为新项,此时 content 与 status 必须齐全(TodoWrite 工具
10844
- * 的 schema 恒为全量,不会触发缺字段路径;此约束仅防御其他内部调用方)。
10845
- */
10846
- type TodoPatch = {
10847
- id: string;
10848
- } & Partial<Omit<TodoItem, 'id'>>;
10849
- interface TodoStoreOptions {
10850
- /** 变更回调:replace/merge 每次调用后触发一次,载荷为变更后完整列表的独立副本 */
10851
- onChange?: (items: TodoItem[]) => void;
10852
- }
10853
- declare class TodoStore {
10854
- #private;
10855
- constructor(options?: TodoStoreOptions);
10856
- /** 当前列表(副本;修改返回值不影响内部状态) */
10857
- list(): TodoItem[];
10858
- /** 全量替换(含替换为空 = 清空台账),返回变更后快照 */
10859
- replace(items: readonly TodoItem[]): TodoItem[];
10860
- /**
10861
- * 按 id 合并:已知 id 原位覆盖给定字段;未知 id 按提交顺序追加到尾部。
10862
- * 返回变更后快照。未知 id 缺 content/status 视为调用方契约错误,抛 TypeError。
10863
- */
10864
- merge(patches: readonly TodoPatch[]): TodoItem[];
10865
- }
10866
-
10867
10867
  /**
10868
10868
  * T-D6 — 交互通道抽象:AskUser 工具与表面层之间的依赖注入缝。
10869
10869
  *
@@ -16293,6 +16293,35 @@ declare class TansrSdkError extends Error {
16293
16293
 
16294
16294
  /** 会话即时状态(状态机推导见 deriveStatus;'error' = 最近终态轮以模型错误收场) */
16295
16295
  type SessionViewStatus = 'idle' | 'thinking' | 'responding' | 'tooling' | 'awaiting_permission' | 'compacting' | 'error';
16296
+ /** 文本呈现档:'stream' 流式增量(缺省)| 'final' 块定稿整段一次性落 part */
16297
+ type TextDeliveryMode = 'stream' | 'final';
16298
+ /** 思考呈现档:'stream'(缺省)| 'final' | 'off' 恒不物化(状态派生仍见 thinking) */
16299
+ type ThinkingDeliveryMode = 'stream' | 'final' | 'off';
16300
+ /**
16301
+ * 呈现档选项(用户拍板 2026-09-01「呈现方式做成会话选项交给开发者选」):
16302
+ * 恒只影响 text/thinking part 的物化时机与在场性——状态机派生(thinking/
16303
+ * responding 等)与工具卡(本就一次性整卡)恒不受档位影响。缺省全 'stream'
16304
+ * = 既有行为零漂移。
16305
+ */
16306
+ interface SessionViewDeliveryOptions {
16307
+ /** 文本:'stream'(缺省)边收边显 | 'final' 整段生成完一次性显示 */
16308
+ readonly text?: TextDeliveryMode;
16309
+ /**
16310
+ * 思考:'stream'(缺省)| 'final' 整段定稿一次性 | 'off' 恒不落视图
16311
+ * (宿主仍可据 status==='thinking' 做「正在思考」占位)。此为呈现面开关;
16312
+ * 生成面(是否产生思考/预算)走请求选项 thinking:{budget/off},两旋钮正交。
16313
+ */
16314
+ readonly thinking?: ThinkingDeliveryMode;
16315
+ }
16316
+ /** SessionView 构造选项(initialSessionViewState / createSessionView / viewStateFromHistory 同形) */
16317
+ interface SessionViewOptions {
16318
+ readonly delivery?: SessionViewDeliveryOptions;
16319
+ }
16320
+ /** 解析后的呈现档(随 internal 落状态,resume 重建径同一份配置继续生效) */
16321
+ interface DeliveryConfig {
16322
+ readonly text: TextDeliveryMode;
16323
+ readonly thinking: ThinkingDeliveryMode;
16324
+ }
16296
16325
  /** 工具调用 part 全生命周期状态('aborted' = 轮终态时仍未收口的残留工具) */
16297
16326
  type ToolCallPartStatus = 'proposed' | 'awaiting_permission' | 'running' | 'completed' | 'failed' | 'denied' | 'aborted';
16298
16327
  interface UITextPart {
@@ -16384,6 +16413,11 @@ interface BlockTracking {
16384
16413
  readonly open: boolean;
16385
16414
  /** tool_call 块定稿后由 tool.proposed 回填 */
16386
16415
  readonly toolCallId?: string;
16416
+ /**
16417
+ * 'final' 呈现档的块内缓冲(delta 恒入此不落 part,块定稿一次性物化;
16418
+ * 键在场 = 本块走 final 档;定稿/撤销后恒清)
16419
+ */
16420
+ readonly buffer?: string;
16387
16421
  }
16388
16422
  /** 当前流式 assistant 消息追踪(null = 下一个块开新消息) */
16389
16423
  interface CurrentMessageTracking {
@@ -16394,6 +16428,8 @@ interface CurrentMessageTracking {
16394
16428
  readonly sealed: boolean;
16395
16429
  }
16396
16430
  interface ViewInternalState {
16431
+ /** 呈现档配置(构造期定格;turn/settle 恒不重置) */
16432
+ readonly delivery: DeliveryConfig;
16397
16433
  readonly running: boolean;
16398
16434
  /** session.compacted/microcompacted 置位,下一个被处理事件清位(status 往返) */
16399
16435
  readonly compacting: boolean;
@@ -16416,7 +16452,7 @@ interface SessionViewReducerState {
16416
16452
  }
16417
16453
  /** 工具输出尾部聚合上限(与 TUI OUTPUT_TAIL_MAX_CHARS 同值同语义) */
16418
16454
  declare const OUTPUT_TAIL_MAX_CHARS = 4000;
16419
- declare function initialSessionViewState(): SessionViewReducerState;
16455
+ declare function initialSessionViewState(options?: SessionViewOptions): SessionViewReducerState;
16420
16456
  /**
16421
16457
  * 纯函数投影:reduce(state, event) => state。
16422
16458
  * 未消费的事件(未知 kind / 与视图无关的 kind / 乱序孤儿)返回原引用
@@ -16429,6 +16465,23 @@ declare function reduceSessionView(state: SessionViewReducerState, event: Kernel
16429
16465
  * 恒不合成 user 消息——本函数是唯一补充入口,由宿主决定是否使用。
16430
16466
  */
16431
16467
  declare function appendUserMessage(state: SessionViewReducerState, text: string): SessionViewReducerState;
16468
+ /**
16469
+ * 动态切换呈现档(纯函数;用户拍板 2026-09-01「留切换入口随时切换」):
16470
+ * 恒**块粒度**生效——已开启的块沿其 block.start 时捕获的形态收尾(缓冲/
16471
+ * 占位/不物化已定格在块登记,恒不中途变形),新块即用新档。恒不追溯已
16472
+ * 物化 part;切 thinking:'off' 要既有思考即刻消失用 stripThinkingParts 配套。
16473
+ * 档位相同恒返回原引用(泵壳零通知)。
16474
+ */
16475
+ declare function setSessionViewDelivery(state: SessionViewReducerState, delivery: SessionViewDeliveryOptions): SessionViewReducerState;
16476
+ /**
16477
+ * 思考 part 全量剔除(纯函数,追溯型配套件):切到 thinking:'off' 时宿主
16478
+ * 调用本函数让**既有**思考即刻从视图消失(内核历史恒不动,仅视图面;切回
16479
+ * 后恒不能从视图自身复原——宿主自持历史者可经 viewStateFromHistory 重建)。
16480
+ * 滤后空 parts 的非当前消息整条移除;当前流式消息恒保留(空壳与既有同律,
16481
+ * 块登记 partIndex 随删位重映射,被删思考块失联 partIndex 后续 delta 恒
16482
+ * 原引用跳过)。无思考 part 时恒返回原引用。
16483
+ */
16484
+ declare function stripThinkingParts(state: SessionViewReducerState): SessionViewReducerState;
16432
16485
  /**
16433
16486
  * 泵壳专用:事件源自身故障(自定义 AsyncIterable 抛错)时的终局错误面
16434
16487
  * ——比静默悬挂诚实。AgentSession.events 不抛,本路径只对自定义源可达。
@@ -16452,7 +16505,7 @@ declare function markSourceFailure(state: SessionViewReducerState, error: unknow
16452
16505
  * 新增消息恒不撞 id;其余内部簿记与视图字段取初始态(status='idle')。
16453
16506
  */
16454
16507
 
16455
- declare function viewStateFromHistory(messages: readonly IRMessage[]): SessionViewReducerState;
16508
+ declare function viewStateFromHistory(messages: readonly IRMessage[], options?: SessionViewOptions): SessionViewReducerState;
16456
16509
 
16457
16510
  /**
16458
16511
  * S-B7 — 事件泵(view 内部共享;session-view 与 narrator 同用)。
@@ -16485,10 +16538,16 @@ interface SessionView {
16485
16538
  * dispose 后为无害空操作。
16486
16539
  */
16487
16540
  appendUserMessage(text: string): void;
16541
+ /**
16542
+ * 动态切换呈现档(块粒度生效:开启中的块按其起始档收尾,新块即用新档)。
16543
+ * 切 thinking:'off' 时既有思考 part 一并即刻剔除(视图不变量:off ⇒ 视图
16544
+ * 恒无思考;内核历史不动,切回后仅影响后续块)。dispose 后为无害空操作。
16545
+ */
16546
+ setDelivery(delivery: SessionViewDeliveryOptions): void;
16488
16547
  /** 停泵并清空订阅(幂等);state 冻结在最后快照 */
16489
16548
  dispose(): void;
16490
16549
  }
16491
- declare function createSessionView(source: SessionViewSource): SessionView;
16550
+ declare function createSessionView(source: SessionViewSource, options?: SessionViewOptions): SessionView;
16492
16551
 
16493
16552
  type NarratorVerbosity = 'quiet' | 'normal' | 'verbose';
16494
16553
  interface NarratorOptions {
@@ -16572,9 +16631,15 @@ declare function assemblePlatformModel(options: AssemblePlatformModelOptions): P
16572
16631
  * 2026-08-29「开 imageGen」)。
16573
16632
  *
16574
16633
  * 环3 语义(区别于环1 defineTool 函数、环2 内置本地工具):执行不在终端本地
16575
- * ——工具 execute 经令牌档 fetch 打平台网关 POST {baseUrl}/t1/imagegen
16576
- * (鉴权头 x-tansr-app-token),平台代调图像上游(百炼 wan/qwen-image 系),
16577
- * **按成功张数计量计费归 App**(开发者对终端如何转售自主,计量计费分离)。
16634
+ * ——工具 execute 经令牌档 fetch 打平台网关(鉴权头 x-tansr-app-token),
16635
+ * 平台代调图像上游(百炼 wan/qwen-image 系),**按成功张数计量计费归 App**
16636
+ * (开发者对终端如何转售自主,计量计费分离)。
16637
+ *
16638
+ * 任务径先行(异步化拍板 2026-09-01,media-task-client.ts;videogen 同构):
16639
+ * POST {baseUrl}/t1/imagegen/tasks 提交即返 taskId → 短请求轮询至终态——预算
16640
+ * 耗尽/中断时 taskId 随错返出,产出可找回(服务端照跑照扣,断连语义 A 不亏)。
16641
+ * 旧版生产无任务端点(404)自动回落 POST {baseUrl}/t1/imagegen 同步径
16642
+ * (0.4.1 逐字同款),判定按工具实例缓存。
16578
16643
  *
16579
16644
  * 装配面:tools.platform: ['imageGen'] 且 bundle 能力位 platform.imageGen=true
16580
16645
  * 时由 buildSdkToolSet 装配(位关 fail-fast 可读错,三环裁剪同例);材料
@@ -16588,6 +16653,15 @@ declare function assemblePlatformModel(options: AssemblePlatformModelOptions): P
16588
16653
 
16589
16654
  /** 生成张数 wire 帽(与网关 TwpImagegenRequestSchema 同值;超模型帽由网关再钳)。 */
16590
16655
  declare const IMAGEGEN_TOOL_MAX_N = 4;
16656
+ /**
16657
+ * 客户端硬超时缺省(毫秒;kernel Tool.timeoutMs 位)= 服务端生成预算 120s
16658
+ * (tansr-api IMAGEGEN_DEFAULT_TIMEOUT_MS,解出层全模型恒用此值——含 classic
16659
+ * 万相异步任务与 mj_task midjourney 任务轮询长径)+ 60s 余量(videogen 同口径:
16660
+ * 请求上行/网关前置/响应回传)。kernel 统一档同为 120s、对服务端预算零余量——
16661
+ * 任务径跑满预算时客户端恒先掐(同 videogen 的有扣无产形态,窗口更短),故
16662
+ * 显式声明盖过。
16663
+ */
16664
+ declare const IMAGEGEN_TOOL_TIMEOUT_MS = 180000;
16591
16665
  declare const ImageGenArgsSchema: z.ZodObject<{
16592
16666
  model: z.ZodOptional<z.ZodString>;
16593
16667
  prompt: z.ZodEffects<z.ZodString, string, string>;
@@ -16623,6 +16697,12 @@ interface ImageGenData {
16623
16697
  imageCount: number;
16624
16698
  /** 网关错误码(如 forbidden/imagegen_not_configured/model_not_authorized;成功缺席)。 */
16625
16699
  errorCode?: string;
16700
+ /**
16701
+ * 异步任务号(异步化拍板 2026-09-01;任务径在场时恒携)。预算耗尽/中断时
16702
+ * 凭此找回产出:GET /t1/imagegen/tasks/{taskId}(服务端照跑照扣,7 天可查)。
16703
+ * 同步回落径(旧版生产)缺席。
16704
+ */
16705
+ taskId?: string;
16626
16706
  }
16627
16707
  interface CreateImageGenToolOptions {
16628
16708
  /** 平台 API 基址(令牌档会话档;/t1 前缀由本工具追加)。 */
@@ -16639,6 +16719,12 @@ interface CreateImageGenToolOptions {
16639
16719
  * 直构/旧径),描述回落通用指引。
16640
16720
  */
16641
16721
  models?: readonly AppBundleImageModel[];
16722
+ /**
16723
+ * 客户端硬超时覆盖(毫秒;透传 kernel Tool.timeoutMs)。缺省
16724
+ * IMAGEGEN_TOOL_TIMEOUT_MS(服务端 120s 预算 + 60s 余量)——恒不回落
16725
+ * kernel 120s 统一档(与服务端预算零余量,任务轮询径必先掐)。
16726
+ */
16727
+ timeoutMs?: number;
16642
16728
  }
16643
16729
  /**
16644
16730
  * 环3 平台图像生成工具(kernel Tool 形态;name 'ImageGen' 沿 kernel PascalCase
@@ -16652,9 +16738,15 @@ declare function createImageGenTool(options: CreateImageGenToolOptions): Tool<Im
16652
16738
  * 平台托管能力)。
16653
16739
  *
16654
16740
  * 环3 语义:执行不在终端本地——工具 execute 经令牌档 fetch 打平台网关
16655
- * POST {baseUrl}/t1/videogen(鉴权头 x-tansr-app-token),平台代调视频上游
16656
- * (百炼 wan 视频系),**按成功生成的视频秒数计量计费归 App**(per_second
16657
- * 系上游官方计费单位;开发者对终端如何转售自主,计量计费分离)。
16741
+ * (鉴权头 x-tansr-app-token),平台代调视频上游(百炼 wan 视频系),**按成功
16742
+ * 生成的视频秒数计量计费归 App**(per_second 系上游官方计费单位;开发者对
16743
+ * 终端如何转售自主,计量计费分离)。
16744
+ *
16745
+ * 任务径先行(异步化拍板 2026-09-01,media-task-client.ts):POST
16746
+ * {baseUrl}/t1/videogen/tasks 提交即返 taskId → 短请求轮询至终态——预算耗尽/
16747
+ * 中断时 taskId 随错返出,产出可找回(服务端照跑照扣,断连语义 A 不亏)。
16748
+ * 旧版生产无任务端点(404)自动回落 POST {baseUrl}/t1/videogen 同步长等径
16749
+ * (0.4.1 逐字同款),判定按工具实例缓存。
16658
16750
  *
16659
16751
  * 装配面:tools.platform: ['videoGen'] 且 bundle 能力位 platform.videoGen=true
16660
16752
  * 时由 buildSdkToolSet 装配(位关 fail-fast 可读错);材料(baseUrl/token)
@@ -16667,6 +16759,16 @@ declare function createImageGenTool(options: CreateImageGenToolOptions): Tool<Im
16667
16759
 
16668
16760
  /** 时长 wire 帽(秒;与网关 TwpVideogenRequestSchema 同值;超模型帽由网关再钳)。 */
16669
16761
  declare const VIDEOGEN_TOOL_MAX_DURATION = 30;
16762
+ /**
16763
+ * 客户端硬超时缺省(毫秒;kernel Tool.timeoutMs 位)= 服务端轮询预算 600s
16764
+ * (tansr-api VIDEOGEN_DEFAULT_TIMEOUT_MS,解出层全模型恒用此值)+ 60s 余量
16765
+ * (请求上行/网关前置[认证/限流/配额/预扣]/响应回传)。/t1/videogen 系服务端
16766
+ * 同步长等——客户端必须等到服务端先出结论(成功或 upstream_timeout 退款),
16767
+ * 恒不先掐:客户端先超时会复现「服务端成功结算而智能体无产出」的有扣无产
16768
+ * (2026-09-01 定谳:kling-v3 实测 122-185s,kernel 120s 缺省档下结构性必超时,
16769
+ * 三笔 ¥2.40 计 ¥7.20 有扣无产)。
16770
+ */
16771
+ declare const VIDEOGEN_TOOL_TIMEOUT_MS = 660000;
16670
16772
  declare const VideoGenArgsSchema: z.ZodObject<{
16671
16773
  model: z.ZodOptional<z.ZodString>;
16672
16774
  prompt: z.ZodEffects<z.ZodString, string, string>;
@@ -16704,6 +16806,12 @@ interface VideoGenData {
16704
16806
  billedSeconds: number;
16705
16807
  /** 网关错误码(如 forbidden/videogen_not_configured/model_not_authorized;成功缺席)。 */
16706
16808
  errorCode?: string;
16809
+ /**
16810
+ * 异步任务号(异步化拍板 2026-09-01;任务径在场时恒携)。预算耗尽/中断时
16811
+ * 凭此找回产出:GET /t1/videogen/tasks/{taskId}(服务端照跑照扣,7 天可查)。
16812
+ * 同步回落径(旧版生产)缺席。
16813
+ */
16814
+ taskId?: string;
16707
16815
  }
16708
16816
  interface CreateVideoGenToolOptions {
16709
16817
  /** 平台 API 基址(令牌档会话档;/t1 前缀由本工具追加)。 */
@@ -16720,6 +16828,12 @@ interface CreateVideoGenToolOptions {
16720
16828
  * (注入档直构/旧径),描述回落通用指引。
16721
16829
  */
16722
16830
  models?: readonly AppBundleVideoModel[];
16831
+ /**
16832
+ * 客户端硬超时覆盖(毫秒;透传 kernel Tool.timeoutMs)。缺省
16833
+ * VIDEOGEN_TOOL_TIMEOUT_MS(服务端 600s 预算 + 60s 余量)——恒不回落
16834
+ * kernel 120s 统一档(视频生成分钟级,120s 帽结构性必超时)。
16835
+ */
16836
+ timeoutMs?: number;
16723
16837
  }
16724
16838
  /**
16725
16839
  * 环3 平台视频生成工具(kernel Tool 形态;name 'VideoGen' 沿 kernel PascalCase
@@ -16795,5 +16909,5 @@ declare function attachSdkTaskTool(toolset: SdkToolsetRef, config: AttachSdkTask
16795
16909
  */
16796
16910
  declare function subagentModelResolverOf(registry: ProviderRegistry | null): SubagentModelResolver | undefined;
16797
16911
 
16798
- export { APP_SDK_CONTRACT_VERSION, APP_TOKEN_PLACEHOLDER_ENV, AgentSession, AppCapabilitiesSchema, AppTokenRequestSchema, AppTokenResponseSchema, DEFAULT_APP_CAPABILITIES, DEFAULT_MAX_TOKENS, DEFAULT_MAX_TURNS, EndUserIdSchema, HEADER_APP_TOKEN, IMAGEGEN_TOOL_MAX_N, ImageGenArgsSchema, McpHost, OUTPUT_TAIL_MAX_CHARS, PLATFORM_SEARCH_PROVIDER_NAME, QueueChannel, SequentialToolExecutor, TANSR_PROVIDER_ID, TOOL_GUIDE_LABEL, TansrSdkError, UnavailableChannel, VIDEOGEN_TOOL_MAX_DURATION, VideoGenArgsSchema, accumulateUsage, appBundleRegistryConfig, appendUserMessage, assembleManagedModel, assemblePlatformModel, assembleSdkSkills, assembleTooling, attachSdkMcp, attachSdkTaskTool, buildClientFromRegistry, buildSdkToolSet, buildToolGuideSegment, createAppTokenFetch, createFileSessionStore, createImageGenTool, createMcpHost, createNarrator, createPlatformSearchProvider, createSdkPermissionGate, createSession, createSessionView, createVideoGenTool, defineSkill, defineTool, initialSessionViewState, markSourceFailure, parseAppBundle, providerSwitchedBody, query, reduceSessionView, resolveBuiltinSelection, resolveInitialMessages, resolvePlatformSelection, runAgent, subagentModelResolverOf, toToolDef, viewStateFromHistory };
16799
- export type { ActiveToolStatus, Answer, AppBundle, AppBundleImageModel, AppBundleMediaModel, AppBundleModel, AppBundlePlatformModels, AppBundleVideoModel, AppCapabilities, AppTokenRequest, AppTokenResponse, AskUserCallback, AssembleManagedModelOptions, AssemblePlatformModelOptions, AssembleToolingOptions, AssembledManagedModel, AssembledPlatformModel, AssembledSkills, AssembledTooling, AttachSdkTaskToolConfig, BuildSdkToolSetOptions, BuiltinToolName, Capability, CompactNowOptions, CompactNowResult, ConfigDiagnostic, CreateFileSessionStoreOptions, CreateImageGenToolOptions, CreatePlatformSearchProviderOptions, CreateSdkPermissionGateOptions, CreateSessionOptions, CreateVideoGenToolOptions, DecisionSource, DefineSkillOptions, DefineToolOptions, DefinedSkill, DefinedTool, ErrorView, EventBody, EventEnvelope, GateDecision, HistoryCommitMeta, HookOutcomeStatus, IRBlock, IRErrorKind, IRMessage, IRRequest, IRRole, IRStreamEvent, IRSystemSegment, IRToolContent, IRToolDef, IRToolResultBlock, IRUsage, ImageGenArgs, ImageGenData, ImageModelConstraints, Integrity, JournalKind, JournalRecord, KernelEvent, KernelState, LoadConfigOptions, LoadedConfig, ManagedQueryOptions, McpClientEvent, McpConnectFactory, McpConnection, McpEventObserver, McpHostOptions, McpServerConfig, McpSessionOption, ModelCallOptions, ModelClient, Narrator, NarratorOptions, NarratorVerbosity, PermissionDecision, PermissionGate, PermissionMode, PermissionOptions, PermissionRules, PlatformCapabilityName, PlatformToolContext, Pricing, PromptCachingMode, PromptChannel, ProposedToolCall, ProtocolKind, ProviderProfile, QueryCompactionOptions, QueryCounters, QueryHandle, QueryOptions, QueryResult, Question, QuestionOption, ResolvedModel, RunAgentOptions, SdkErrorCode, SdkSkillsOptions, SdkToolSet, SdkToolsOptions, SdkToolsetRef, SequentialToolHandler, SequentialToolResult, SessionEventSource, SessionRecord, SessionRecordMeta, SessionStore, SessionStoreCommitMeta, SessionStoreCreateInit, SessionView, SessionViewReducerState, SessionViewSource, SessionViewState, SessionViewStatus, SetModelBinding, SkillsFileSystem, TansrConfig, TerminalReason, TodoView, Tool, ToolCallPartStatus, ToolCallView, ToolContext, ToolErrorType, ToolExecutionContext, ToolExecutionOutcome, ToolExecutor, ToolExecutorYield, ToolParameterSpec, ToolResult, ToolResultContent, UIMessage, UIMessagePart, UITextPart, UIThinkingPart, UIToolCallPart, UsageView, VideoGenArgs, VideoGenData, VideoModelConstraints, Visibility };
16912
+ export { APP_SDK_CONTRACT_VERSION, APP_TOKEN_PLACEHOLDER_ENV, AgentSession, AppCapabilitiesSchema, AppTokenRequestSchema, AppTokenResponseSchema, DEFAULT_APP_CAPABILITIES, DEFAULT_MAX_TOKENS, DEFAULT_MAX_TURNS, EndUserIdSchema, HEADER_APP_TOKEN, IMAGEGEN_TOOL_MAX_N, IMAGEGEN_TOOL_TIMEOUT_MS, ImageGenArgsSchema, McpHost, OUTPUT_TAIL_MAX_CHARS, PLATFORM_SEARCH_PROVIDER_NAME, QueueChannel, SequentialToolExecutor, TANSR_PROVIDER_ID, TOOL_GUIDE_LABEL, TansrSdkError, UnavailableChannel, VIDEOGEN_TOOL_MAX_DURATION, VIDEOGEN_TOOL_TIMEOUT_MS, VideoGenArgsSchema, accumulateUsage, appBundleRegistryConfig, appendUserMessage, assembleManagedModel, assemblePlatformModel, assembleSdkSkills, assembleTooling, attachSdkMcp, attachSdkTaskTool, buildClientFromRegistry, buildSdkToolSet, buildToolGuideSegment, createAppTokenFetch, createFileSessionStore, createImageGenTool, createMcpHost, createNarrator, createPlatformSearchProvider, createSdkPermissionGate, createSession, createSessionView, createVideoGenTool, defineSkill, defineTool, initialSessionViewState, markSourceFailure, parseAppBundle, providerSwitchedBody, query, reduceSessionView, resolveBuiltinSelection, resolveInitialMessages, resolvePlatformSelection, runAgent, setSessionViewDelivery, stripThinkingParts, subagentModelResolverOf, toToolDef, viewStateFromHistory };
16913
+ export type { ActiveToolStatus, Answer, AppBundle, AppBundleImageModel, AppBundleMediaModel, AppBundleModel, AppBundlePlatformModels, AppBundleVideoModel, AppCapabilities, AppTokenRequest, AppTokenResponse, AskUserCallback, AssembleManagedModelOptions, AssemblePlatformModelOptions, AssembleToolingOptions, AssembledManagedModel, AssembledPlatformModel, AssembledSkills, AssembledTooling, AttachSdkTaskToolConfig, BuildSdkToolSetOptions, BuiltinToolName, Capability, CompactNowOptions, CompactNowResult, ConfigDiagnostic, CreateFileSessionStoreOptions, CreateImageGenToolOptions, CreatePlatformSearchProviderOptions, CreateSdkPermissionGateOptions, CreateSessionOptions, CreateVideoGenToolOptions, DecisionSource, DefineSkillOptions, DefineToolOptions, DefinedSkill, DefinedTool, DeliveryConfig, ErrorView, EventBody, EventEnvelope, GateDecision, HistoryCommitMeta, HookOutcomeStatus, IRBlock, IRErrorKind, IRMessage, IRRequest, IRRole, IRStreamEvent, IRSystemSegment, IRToolContent, IRToolDef, IRToolResultBlock, IRUsage, ImageGenArgs, ImageGenData, ImageModelConstraints, Integrity, JournalKind, JournalRecord, KernelEvent, KernelState, LoadConfigOptions, LoadedConfig, ManagedQueryOptions, McpClientEvent, McpConnectFactory, McpConnection, McpEventObserver, McpHostOptions, McpServerConfig, McpSessionOption, ModelCallOptions, ModelClient, Narrator, NarratorOptions, NarratorVerbosity, PermissionDecision, PermissionGate, PermissionMode, PermissionOptions, PermissionRules, PlatformCapabilityName, PlatformToolContext, Pricing, PromptCachingMode, PromptChannel, ProposedToolCall, ProtocolKind, ProviderProfile, QueryCompactionOptions, QueryCounters, QueryHandle, QueryOptions, QueryResult, Question, QuestionOption, ResolvedModel, RunAgentOptions, SdkErrorCode, SdkSkillsOptions, SdkToolSet, SdkToolsOptions, SdkToolsetRef, SequentialToolHandler, SequentialToolResult, SessionEventSource, SessionRecord, SessionRecordMeta, SessionStore, SessionStoreCommitMeta, SessionStoreCreateInit, SessionView, SessionViewDeliveryOptions, SessionViewOptions, SessionViewReducerState, SessionViewSource, SessionViewState, SessionViewStatus, SetModelBinding, SkillsFileSystem, TansrConfig, TerminalReason, TextDeliveryMode, ThinkingDeliveryMode, TodoView, Tool, ToolCallPartStatus, ToolCallView, ToolContext, ToolErrorType, ToolExecutionContext, ToolExecutionOutcome, ToolExecutor, ToolExecutorYield, ToolParameterSpec, ToolResult, ToolResultContent, UIMessage, UIMessagePart, UITextPart, UIThinkingPart, UIToolCallPart, UsageView, VideoGenArgs, VideoGenData, VideoModelConstraints, Visibility };
package/dist/index.js CHANGED
@@ -30850,7 +30850,116 @@ var AppQuotaSchema = z41.object({
30850
30850
 
30851
30851
  // src/platform/imagegen-tool.ts
30852
30852
  import { z as z42 } from "zod";
30853
+
30854
+ // src/platform/media-task-client.ts
30855
+ var POLL_INTERVAL_MIN_MS = 1;
30856
+ var POLL_INTERVAL_MAX_MS = 6e4;
30857
+ var DEADLINE_MARGIN_MS = 1e4;
30858
+ function sleep(ms, signal) {
30859
+ return new Promise((resolve2) => {
30860
+ if (signal.aborted || ms <= 0) {
30861
+ resolve2();
30862
+ return;
30863
+ }
30864
+ const timer = setTimeout(done, ms);
30865
+ function done() {
30866
+ clearTimeout(timer);
30867
+ signal.removeEventListener("abort", done);
30868
+ resolve2();
30869
+ }
30870
+ signal.addEventListener("abort", done, { once: true });
30871
+ });
30872
+ }
30873
+ function clampPollMs(v, fallback) {
30874
+ if (typeof v !== "number" || !Number.isFinite(v) || v <= 0) return fallback;
30875
+ return Math.min(Math.max(Math.floor(v), POLL_INTERVAL_MIN_MS), POLL_INTERVAL_MAX_MS);
30876
+ }
30877
+ function envelopeCode(raw, status) {
30878
+ const envelope = raw ?? {};
30879
+ const code = typeof envelope.error?.code === "string" ? envelope.error.code : `http_${status}`;
30880
+ const message = typeof envelope.error?.message === "string" ? envelope.error.message : "request rejected";
30881
+ return { code, message };
30882
+ }
30883
+ async function runMediaTask(options) {
30884
+ const { base, face, payload, headers, fetchImpl, signal, budgetMs, defaultPollMs } = options;
30885
+ const startMs = Date.now();
30886
+ const deadlineMs = startMs + Math.max(budgetMs - DEADLINE_MARGIN_MS, Math.floor(budgetMs * 0.8));
30887
+ let response;
30888
+ try {
30889
+ response = await fetchImpl(`${base}/t1/${face}/tasks`, {
30890
+ method: "POST",
30891
+ headers: { "content-type": "application/json", accept: "application/json", ...headers },
30892
+ body: JSON.stringify(payload),
30893
+ signal
30894
+ });
30895
+ } catch (err) {
30896
+ if (signal.aborted) return { kind: "aborted", taskId: null };
30897
+ return { kind: "transport_error", message: err instanceof Error ? err.message : String(err) };
30898
+ }
30899
+ if (response.status === 404) return { kind: "fallback_sync" };
30900
+ let raw = null;
30901
+ try {
30902
+ raw = await response.json();
30903
+ } catch {
30904
+ raw = null;
30905
+ }
30906
+ if (!response.ok) return { kind: "submit_error", status: response.status, raw };
30907
+ const submitted = raw ?? {};
30908
+ if (typeof submitted.taskId !== "string" || submitted.taskId === "") {
30909
+ return { kind: "transport_error", message: "platform accepted the task but returned no taskId (unexpected response)" };
30910
+ }
30911
+ const taskId = submitted.taskId;
30912
+ let pollMs = clampPollMs(submitted.pollIntervalMs, defaultPollMs);
30913
+ const taskUrl = `${base}/t1/${face}/tasks/${taskId}`;
30914
+ for (; ; ) {
30915
+ if (signal.aborted) return { kind: "aborted", taskId };
30916
+ const now = Date.now();
30917
+ if (now >= deadlineMs) return { kind: "deadline", taskId };
30918
+ await sleep(Math.min(pollMs, deadlineMs - now), signal);
30919
+ if (signal.aborted) return { kind: "aborted", taskId };
30920
+ let poll;
30921
+ try {
30922
+ poll = await fetchImpl(taskUrl, { method: "GET", headers: { accept: "application/json", ...headers }, signal });
30923
+ } catch {
30924
+ if (signal.aborted) return { kind: "aborted", taskId };
30925
+ continue;
30926
+ }
30927
+ let body = null;
30928
+ try {
30929
+ body = await poll.json();
30930
+ } catch {
30931
+ body = null;
30932
+ }
30933
+ if (poll.status === 401 || poll.status === 403 || poll.status === 404) {
30934
+ const { code, message } = envelopeCode(body, poll.status);
30935
+ return { kind: "failed", taskId, errorCode: code, message };
30936
+ }
30937
+ if (!poll.ok) continue;
30938
+ const state = body ?? {};
30939
+ if (state.status === "succeeded") {
30940
+ return {
30941
+ kind: "succeeded",
30942
+ taskId,
30943
+ result: state.result,
30944
+ ...typeof state.cost === "string" ? { cost: state.cost } : {},
30945
+ ...typeof state.currency === "string" ? { currency: state.currency } : {}
30946
+ };
30947
+ }
30948
+ if (state.status === "failed") {
30949
+ return {
30950
+ kind: "failed",
30951
+ taskId,
30952
+ errorCode: typeof state.error?.code === "string" ? state.error.code : "upstream_error",
30953
+ message: typeof state.error?.message === "string" ? state.error.message : "media generation failed"
30954
+ };
30955
+ }
30956
+ pollMs = clampPollMs(state.pollIntervalMs, pollMs);
30957
+ }
30958
+ }
30959
+
30960
+ // src/platform/imagegen-tool.ts
30853
30961
  var IMAGEGEN_TOOL_MAX_N = 4;
30962
+ var IMAGEGEN_TOOL_TIMEOUT_MS = 18e4;
30854
30963
  var ImageGenArgsSchema = z42.object({
30855
30964
  // S-G1(媒体池化顺位取用):Optional——缺席即不发 model 位,网关按授权集顺位
30856
30965
  // 第一生效(与 bundle platformModels.imageGen 首行恒同);点名限集内(工具描述自列)。
@@ -30868,10 +30977,43 @@ var ImageGenArgsSchema = z42.object({
30868
30977
  "Input images for image editing or reference-conditioned generation (public http(s) URLs or data:image/*;base64 URIs). Only pass this for models whose bracketed note in this description lists imageUrls support; other models reject it."
30869
30978
  )
30870
30979
  });
30871
- function errorResult13(text, model, errorCode2) {
30872
- const data = { model, images: [], imageCount: 0, ...errorCode2 !== void 0 ? { errorCode: errorCode2 } : {} };
30980
+ function errorResult13(text, model, errorCode2, taskId) {
30981
+ const data = {
30982
+ model,
30983
+ images: [],
30984
+ imageCount: 0,
30985
+ ...errorCode2 !== void 0 ? { errorCode: errorCode2 } : {},
30986
+ ...taskId !== void 0 ? { taskId } : {}
30987
+ };
30873
30988
  return { content: [{ t: "text", text }], isError: true, data };
30874
30989
  }
30990
+ function gatewayError(raw, status) {
30991
+ const envelope = raw ?? {};
30992
+ const code = typeof envelope.error?.code === "string" ? envelope.error.code : `http_${status}`;
30993
+ const message = typeof envelope.error?.message === "string" ? envelope.error.message : "request rejected";
30994
+ return { code, message };
30995
+ }
30996
+ function successResult(raw, modelRef, taskId) {
30997
+ const body = raw ?? {};
30998
+ const images = Array.isArray(body.images) ? body.images.map((item) => typeof item.url === "string" ? { url: item.url } : null).filter((item) => item !== null) : [];
30999
+ const imageCount = typeof body.imageCount === "number" ? body.imageCount : images.length;
31000
+ if (images.length === 0) {
31001
+ return errorResult13("Image generation returned no image URL (unexpected platform response).", modelRef, void 0, taskId);
31002
+ }
31003
+ const resolvedModel = typeof body.model === "string" && body.model !== "" ? body.model : modelRef;
31004
+ const data = {
31005
+ model: resolvedModel,
31006
+ images,
31007
+ imageCount,
31008
+ ...taskId !== void 0 ? { taskId } : {}
31009
+ };
31010
+ const lines = [
31011
+ `Generated ${imageCount} image(s) with model ${resolvedModel} (billed per image).`,
31012
+ "Image URLs (valid ~24h; surface or persist promptly):",
31013
+ ...images.map((img, i) => `${i + 1}. ${img.url}`)
31014
+ ];
31015
+ return { content: [{ t: "text", text: lines.join("\n") }], data };
31016
+ }
30875
31017
  function hintOf(code) {
30876
31018
  if (code === "forbidden") {
30877
31019
  return " The app platform capability imageGen is disabled; the app developer can enable it in console → app → capabilities.";
@@ -30923,13 +31065,18 @@ function createImageGenTool(options) {
30923
31065
  const base = options.baseUrl.replace(/\/+$/, "");
30924
31066
  const fetchImpl = options.fetchImpl ?? fetch;
30925
31067
  const token = options.token;
31068
+ const budgetMs = options.timeoutMs ?? IMAGEGEN_TOOL_TIMEOUT_MS;
31069
+ let taskRouteMissing = false;
30926
31070
  return {
30927
31071
  name: "ImageGen",
30928
- description: "Generates images from a text prompt via the tansr platform (ring-3 hosted capability; the platform calls the image provider and bills the app per generated image). Returns image URLs that stay valid for roughly 24 hours — surface them to the user promptly. Requires the app to have the imageGen platform capability enabled." + authorizedModelsNote(options.models),
31072
+ description: "Generates images from a text prompt via the tansr platform (ring-3 hosted capability; the platform calls the image provider and bills the app per generated image). Some models run as polled tasks and can take a minute or two — client-side wait cap is ~3 minutes. If the cap is ever reached, the error carries a taskId: generation continues server-side (billed on success) and the result stays retrievable for ~7 days — do not resubmit blindly. Returns image URLs that stay valid for roughly 24 hours — surface them to the user promptly. Requires the app to have the imageGen platform capability enabled." + authorizedModelsNote(options.models),
30929
31073
  shortDescription: "Generate images from a prompt via the tansr platform (billed per image). Args: model?, prompt, negativePrompt?, size?, n?, seed?, imageUrls?.",
30930
31074
  inputSchema: ImageGenArgsSchema,
30931
31075
  isReadOnly: false,
30932
31076
  isConcurrencySafe: false,
31077
+ // 2026-09-01 定谳修(videogen 同批):服务端预算 120s 与 kernel 120s 缺省档
31078
+ // 零余量,classic/mj_task 任务轮询径跑满预算时客户端恒先掐——声明 180s 盖过。
31079
+ timeoutMs: budgetMs,
30933
31080
  async execute(args, ctx) {
30934
31081
  const modelRef = args.model ?? "(default)";
30935
31082
  if (ctx.signal.aborted) {
@@ -30944,6 +31091,53 @@ function createImageGenTool(options) {
30944
31091
  ...args.seed !== void 0 ? { seed: args.seed } : {},
30945
31092
  ...args.imageUrls !== void 0 ? { imageUrls: args.imageUrls } : {}
30946
31093
  };
31094
+ if (!taskRouteMissing) {
31095
+ const outcome = await runMediaTask({
31096
+ base,
31097
+ face: "imagegen",
31098
+ payload,
31099
+ headers: { [HEADER_APP_TOKEN]: token },
31100
+ fetchImpl,
31101
+ signal: ctx.signal,
31102
+ budgetMs,
31103
+ defaultPollMs: 2e3
31104
+ });
31105
+ if (outcome.kind === "succeeded") {
31106
+ return successResult(outcome.result, modelRef, outcome.taskId);
31107
+ }
31108
+ if (outcome.kind === "failed") {
31109
+ return errorResult13(
31110
+ `Image generation failed (${outcome.errorCode}): ${outcome.message}.${hintOf(outcome.errorCode)} (taskId: ${outcome.taskId})`,
31111
+ modelRef,
31112
+ outcome.errorCode,
31113
+ outcome.taskId
31114
+ );
31115
+ }
31116
+ if (outcome.kind === "submit_error") {
31117
+ const { code, message } = gatewayError(outcome.raw, outcome.status);
31118
+ return errorResult13(`Image generation failed (${code}): ${message}.${hintOf(code)}`, modelRef, code);
31119
+ }
31120
+ if (outcome.kind === "transport_error") {
31121
+ return errorResult13(`Image generation request failed to reach the platform: ${outcome.message}`, modelRef);
31122
+ }
31123
+ if (outcome.kind === "deadline") {
31124
+ return errorResult13(
31125
+ `Image generation is still running server-side (taskId: ${outcome.taskId}) — the client-side wait cap was reached. The task keeps running and is billed only on success; do not resubmit blindly. Retrieve the result later via GET ${base}/t1/imagegen/tasks/${outcome.taskId} (task retrievable ~7 days; image URLs expire ~24h after completion).`,
31126
+ modelRef,
31127
+ "task_pending",
31128
+ outcome.taskId
31129
+ );
31130
+ }
31131
+ if (outcome.kind === "aborted") {
31132
+ return errorResult13(
31133
+ outcome.taskId === null ? "Tool execution was aborted." : `Tool execution was aborted. Image generation may still complete server-side (billed on success) — retrieve via GET ${base}/t1/imagegen/tasks/${outcome.taskId} (retrievable ~7 days). (taskId: ${outcome.taskId})`,
31134
+ modelRef,
31135
+ void 0,
31136
+ outcome.taskId ?? void 0
31137
+ );
31138
+ }
31139
+ taskRouteMissing = true;
31140
+ }
30947
31141
  let response;
30948
31142
  try {
30949
31143
  response = await fetchImpl(`${base}/t1/imagegen`, {
@@ -30968,25 +31162,10 @@ function createImageGenTool(options) {
30968
31162
  raw = null;
30969
31163
  }
30970
31164
  if (!response.ok) {
30971
- const envelope = raw ?? {};
30972
- const code = typeof envelope.error?.code === "string" ? envelope.error.code : `http_${response.status}`;
30973
- const message = typeof envelope.error?.message === "string" ? envelope.error.message : "request rejected";
31165
+ const { code, message } = gatewayError(raw, response.status);
30974
31166
  return errorResult13(`Image generation failed (${code}): ${message}.${hintOf(code)}`, modelRef, code);
30975
31167
  }
30976
- const body = raw ?? {};
30977
- const images = Array.isArray(body.images) ? body.images.map((item) => typeof item.url === "string" ? { url: item.url } : null).filter((item) => item !== null) : [];
30978
- const imageCount = typeof body.imageCount === "number" ? body.imageCount : images.length;
30979
- if (images.length === 0) {
30980
- return errorResult13("Image generation returned no image URL (unexpected platform response).", modelRef);
30981
- }
30982
- const resolvedModel = typeof body.model === "string" && body.model !== "" ? body.model : modelRef;
30983
- const data = { model: resolvedModel, images, imageCount };
30984
- const lines = [
30985
- `Generated ${imageCount} image(s) with model ${resolvedModel} (billed per image).`,
30986
- "Image URLs (valid ~24h; surface or persist promptly):",
30987
- ...images.map((img, i) => `${i + 1}. ${img.url}`)
30988
- ];
30989
- return { content: [{ t: "text", text: lines.join("\n") }], data };
31168
+ return successResult(raw, modelRef);
30990
31169
  }
30991
31170
  };
30992
31171
  }
@@ -30994,6 +31173,7 @@ function createImageGenTool(options) {
30994
31173
  // src/platform/videogen-tool.ts
30995
31174
  import { z as z43 } from "zod";
30996
31175
  var VIDEOGEN_TOOL_MAX_DURATION = 30;
31176
+ var VIDEOGEN_TOOL_TIMEOUT_MS = 66e4;
30997
31177
  var VideoGenArgsSchema = z43.object({
30998
31178
  // S-G1(媒体池化顺位取用):Optional——缺席即不发 model 位,网关按授权集顺位
30999
31179
  // 第一生效(与 bundle platformModels.videoGen 首行恒同);点名限集内(工具描述自列)。
@@ -31014,16 +31194,46 @@ var VideoGenArgsSchema = z43.object({
31014
31194
  'First-frame image(s) for image-to-video generation (public http(s) URL or data:image/*;base64 URI). REQUIRED for models marked "image-to-video ONLY" in this description (generate or obtain an image first, e.g. via the ImageGen tool); rejected by text-to-video-only models.'
31015
31195
  )
31016
31196
  });
31017
- function errorResult14(text, model, errorCode2) {
31197
+ function errorResult14(text, model, errorCode2, taskId) {
31018
31198
  const data = {
31019
31199
  model,
31020
31200
  videos: [],
31021
31201
  videoCount: 0,
31022
31202
  billedSeconds: 0,
31023
- ...errorCode2 !== void 0 ? { errorCode: errorCode2 } : {}
31203
+ ...errorCode2 !== void 0 ? { errorCode: errorCode2 } : {},
31204
+ ...taskId !== void 0 ? { taskId } : {}
31024
31205
  };
31025
31206
  return { content: [{ t: "text", text }], isError: true, data };
31026
31207
  }
31208
+ function gatewayError2(raw, status) {
31209
+ const envelope = raw ?? {};
31210
+ const code = typeof envelope.error?.code === "string" ? envelope.error.code : `http_${status}`;
31211
+ const message = typeof envelope.error?.message === "string" ? envelope.error.message : "request rejected";
31212
+ return { code, message };
31213
+ }
31214
+ function successResult2(raw, modelRef, taskId) {
31215
+ const body = raw ?? {};
31216
+ const videos = Array.isArray(body.videos) ? body.videos.map((item) => typeof item.url === "string" ? { url: item.url } : null).filter((item) => item !== null) : [];
31217
+ if (videos.length === 0) {
31218
+ return errorResult14("Video generation returned no video URL (unexpected platform response).", modelRef, void 0, taskId);
31219
+ }
31220
+ const videoCount = typeof body.videoCount === "number" ? body.videoCount : videos.length;
31221
+ const billedSeconds = typeof body.billedSeconds === "number" ? body.billedSeconds : 0;
31222
+ const resolvedModel = typeof body.model === "string" && body.model !== "" ? body.model : modelRef;
31223
+ const data = {
31224
+ model: resolvedModel,
31225
+ videos,
31226
+ videoCount,
31227
+ billedSeconds,
31228
+ ...taskId !== void 0 ? { taskId } : {}
31229
+ };
31230
+ const lines = [
31231
+ `Generated ${videoCount} video(s) with model ${resolvedModel} (${billedSeconds}s billed, per-second pricing).`,
31232
+ "Video URLs (valid ~24h; surface or persist promptly):",
31233
+ ...videos.map((v, i) => `${i + 1}. ${v.url}`)
31234
+ ];
31235
+ return { content: [{ t: "text", text: lines.join("\n") }], data };
31236
+ }
31027
31237
  function hintOf2(code) {
31028
31238
  if (code === "forbidden") {
31029
31239
  return " The app platform capability videoGen is disabled; the app developer can enable it in console → app → capabilities.";
@@ -31082,13 +31292,19 @@ function createVideoGenTool(options) {
31082
31292
  const base = options.baseUrl.replace(/\/+$/, "");
31083
31293
  const fetchImpl = options.fetchImpl ?? fetch;
31084
31294
  const token = options.token;
31295
+ const budgetMs = options.timeoutMs ?? VIDEOGEN_TOOL_TIMEOUT_MS;
31296
+ let taskRouteMissing = false;
31085
31297
  return {
31086
31298
  name: "VideoGen",
31087
- description: "Generates a short video from a text prompt via the tansr platform (ring-3 hosted capability; the platform calls the video provider and bills the app per second of generated video). Generation is a long-running task (often minutes). Returns a video URL that stays valid for roughly 24 hours — surface it to the user promptly. Requires the app to have the videoGen platform capability enabled." + authorizedModelsNote2(options.models),
31299
+ description: "Generates a short video from a text prompt via the tansr platform (ring-3 hosted capability; the platform calls the video provider and bills the app per second of generated video). Generation is a long-running task (often minutes). This call waits for the result — client-side wait cap is ~11 minutes; do not abort or retry early. If the cap is ever reached, the error carries a taskId: generation continues server-side (billed on success) and the result stays retrievable for ~7 days — do not resubmit blindly. Returns a video URL that stays valid for roughly 24 hours — surface it to the user promptly. Requires the app to have the videoGen platform capability enabled." + authorizedModelsNote2(options.models),
31088
31300
  shortDescription: "Generate a video from a prompt via the tansr platform (billed per second). Args: model?, prompt, negativePrompt?, duration?, ratio?, seed?, imageUrls?.",
31089
31301
  inputSchema: VideoGenArgsSchema,
31090
31302
  isReadOnly: false,
31091
31303
  isConcurrencySafe: false,
31304
+ // 2026-09-01 定谳修:/t1/videogen 系服务端同步长等(600s 轮询预算),kernel
31305
+ // 120s 缺省档下分钟级任务结构性必超时且有扣无产——工具级声明盖过缺省档
31306
+ // (kernel 全局档恒不动;dispatching-tool-executor timeoutMs>0 即生效)。
31307
+ timeoutMs: budgetMs,
31092
31308
  async execute(args, ctx) {
31093
31309
  const modelRef = args.model ?? "(default)";
31094
31310
  if (ctx.signal.aborted) {
@@ -31103,6 +31319,53 @@ function createVideoGenTool(options) {
31103
31319
  ...args.seed !== void 0 ? { seed: args.seed } : {},
31104
31320
  ...args.imageUrls !== void 0 ? { imageUrls: args.imageUrls } : {}
31105
31321
  };
31322
+ if (!taskRouteMissing) {
31323
+ const outcome = await runMediaTask({
31324
+ base,
31325
+ face: "videogen",
31326
+ payload,
31327
+ headers: { [HEADER_APP_TOKEN]: token },
31328
+ fetchImpl,
31329
+ signal: ctx.signal,
31330
+ budgetMs,
31331
+ defaultPollMs: 5e3
31332
+ });
31333
+ if (outcome.kind === "succeeded") {
31334
+ return successResult2(outcome.result, modelRef, outcome.taskId);
31335
+ }
31336
+ if (outcome.kind === "failed") {
31337
+ return errorResult14(
31338
+ `Video generation failed (${outcome.errorCode}): ${outcome.message}.${hintOf2(outcome.errorCode)} (taskId: ${outcome.taskId})`,
31339
+ modelRef,
31340
+ outcome.errorCode,
31341
+ outcome.taskId
31342
+ );
31343
+ }
31344
+ if (outcome.kind === "submit_error") {
31345
+ const { code, message } = gatewayError2(outcome.raw, outcome.status);
31346
+ return errorResult14(`Video generation failed (${code}): ${message}.${hintOf2(code)}`, modelRef, code);
31347
+ }
31348
+ if (outcome.kind === "transport_error") {
31349
+ return errorResult14(`Video generation request failed to reach the platform: ${outcome.message}`, modelRef);
31350
+ }
31351
+ if (outcome.kind === "deadline") {
31352
+ return errorResult14(
31353
+ `Video generation is still running server-side (taskId: ${outcome.taskId}) — the client-side wait cap was reached. The task keeps running and is billed only on success; do not resubmit blindly. Retrieve the result later via GET ${base}/t1/videogen/tasks/${outcome.taskId} (task retrievable ~7 days; video URLs expire ~24h after completion).`,
31354
+ modelRef,
31355
+ "task_pending",
31356
+ outcome.taskId
31357
+ );
31358
+ }
31359
+ if (outcome.kind === "aborted") {
31360
+ return errorResult14(
31361
+ outcome.taskId === null ? "Tool execution was aborted." : `Tool execution was aborted. Video generation may still complete server-side (billed on success) — retrieve via GET ${base}/t1/videogen/tasks/${outcome.taskId} (retrievable ~7 days). (taskId: ${outcome.taskId})`,
31362
+ modelRef,
31363
+ void 0,
31364
+ outcome.taskId ?? void 0
31365
+ );
31366
+ }
31367
+ taskRouteMissing = true;
31368
+ }
31106
31369
  let response;
31107
31370
  try {
31108
31371
  response = await fetchImpl(`${base}/t1/videogen`, {
@@ -31127,26 +31390,10 @@ function createVideoGenTool(options) {
31127
31390
  raw = null;
31128
31391
  }
31129
31392
  if (!response.ok) {
31130
- const envelope = raw ?? {};
31131
- const code = typeof envelope.error?.code === "string" ? envelope.error.code : `http_${response.status}`;
31132
- const message = typeof envelope.error?.message === "string" ? envelope.error.message : "request rejected";
31393
+ const { code, message } = gatewayError2(raw, response.status);
31133
31394
  return errorResult14(`Video generation failed (${code}): ${message}.${hintOf2(code)}`, modelRef, code);
31134
31395
  }
31135
- const body = raw ?? {};
31136
- const videos = Array.isArray(body.videos) ? body.videos.map((item) => typeof item.url === "string" ? { url: item.url } : null).filter((item) => item !== null) : [];
31137
- if (videos.length === 0) {
31138
- return errorResult14("Video generation returned no video URL (unexpected platform response).", modelRef);
31139
- }
31140
- const videoCount = typeof body.videoCount === "number" ? body.videoCount : videos.length;
31141
- const billedSeconds = typeof body.billedSeconds === "number" ? body.billedSeconds : 0;
31142
- const resolvedModel = typeof body.model === "string" && body.model !== "" ? body.model : modelRef;
31143
- const data = { model: resolvedModel, videos, videoCount, billedSeconds };
31144
- const lines = [
31145
- `Generated ${videoCount} video(s) with model ${resolvedModel} (${billedSeconds}s billed, per-second pricing).`,
31146
- "Video URLs (valid ~24h; surface or persist promptly):",
31147
- ...videos.map((v, i) => `${i + 1}. ${v.url}`)
31148
- ];
31149
- return { content: [{ t: "text", text: lines.join("\n") }], data };
31396
+ return successResult2(raw, modelRef);
31150
31397
  }
31151
31398
  };
31152
31399
  }
@@ -32050,7 +32297,7 @@ function toolCallIds(message) {
32050
32297
  function toolResultIds(message) {
32051
32298
  return message.blocks.flatMap((b) => b.t === "tool_result" ? [b.callId] : []);
32052
32299
  }
32053
- function repairHistoryPairing(messages) {
32300
+ function repairHistoryPairing2(messages) {
32054
32301
  const open4 = /* @__PURE__ */ new Set();
32055
32302
  let cleanEnd = 0;
32056
32303
  for (let i = 0; i < messages.length; i++) {
@@ -32409,7 +32656,7 @@ async function createSession(options = {}) {
32409
32656
  `createSession: session "${options.resume.sessionId}" was not found in the given store; list() the store or create a fresh session instead.`
32410
32657
  );
32411
32658
  }
32412
- initialMessages = repairHistoryPairing(record.messages).messages;
32659
+ initialMessages = repairHistoryPairing2(record.messages).messages;
32413
32660
  }
32414
32661
  const platformSessionId = tokenTier ? ulid() : void 0;
32415
32662
  let sessionRef = null;
@@ -32821,8 +33068,14 @@ function createFileSessionStore(options) {
32821
33068
  }
32822
33069
 
32823
33070
  // src/view/reducer.ts
33071
+ function resolveDelivery(options) {
33072
+ return {
33073
+ text: options?.delivery?.text ?? "stream",
33074
+ thinking: options?.delivery?.thinking ?? "stream"
33075
+ };
33076
+ }
32824
33077
  var OUTPUT_TAIL_MAX_CHARS = 4e3;
32825
- function initialSessionViewState() {
33078
+ function initialSessionViewState(options) {
32826
33079
  return {
32827
33080
  view: {
32828
33081
  status: "idle",
@@ -32832,6 +33085,7 @@ function initialSessionViewState() {
32832
33085
  usage: { turnTokens: 0, sessionTokens: 0, requests: 0 }
32833
33086
  },
32834
33087
  internal: {
33088
+ delivery: resolveDelivery(options),
32835
33089
  running: false,
32836
33090
  compacting: false,
32837
33091
  lastTurnFailed: false,
@@ -33065,6 +33319,22 @@ function reduceBody(draft, event) {
33065
33319
  }
33066
33320
  const tracking = next.internal.current;
33067
33321
  if (event.blockType === "text" || event.blockType === "thinking") {
33322
+ const mode = event.blockType === "thinking" ? next.internal.delivery.thinking : next.internal.delivery.text;
33323
+ if (mode === "off") {
33324
+ return {
33325
+ ...next,
33326
+ internal: {
33327
+ ...next.internal,
33328
+ current: {
33329
+ ...tracking,
33330
+ blocks: {
33331
+ ...tracking.blocks,
33332
+ [event.index]: { blockType: event.blockType, open: true }
33333
+ }
33334
+ }
33335
+ }
33336
+ };
33337
+ }
33068
33338
  const appended = appendPart(next, messageId, { type: event.blockType, text: "" });
33069
33339
  next = appended.draft;
33070
33340
  return {
@@ -33078,7 +33348,8 @@ function reduceBody(draft, event) {
33078
33348
  [event.index]: {
33079
33349
  blockType: event.blockType,
33080
33350
  partIndex: appended.partIndex,
33081
- open: true
33351
+ open: true,
33352
+ ...mode === "final" ? { buffer: "" } : {}
33082
33353
  }
33083
33354
  }
33084
33355
  }
@@ -33104,7 +33375,23 @@ function reduceBody(draft, event) {
33104
33375
  const current = draft.internal.current;
33105
33376
  if (current === null) return null;
33106
33377
  const tracking = current.blocks[event.index];
33107
- if (tracking === void 0 || tracking.partIndex === void 0) return null;
33378
+ if (tracking === void 0) return null;
33379
+ if (tracking.buffer !== void 0) {
33380
+ return {
33381
+ ...draft,
33382
+ internal: {
33383
+ ...draft.internal,
33384
+ current: {
33385
+ ...current,
33386
+ blocks: {
33387
+ ...current.blocks,
33388
+ [event.index]: { ...tracking, buffer: tracking.buffer + event.text }
33389
+ }
33390
+ }
33391
+ }
33392
+ };
33393
+ }
33394
+ if (tracking.partIndex === void 0) return null;
33108
33395
  const view = withPartAt(
33109
33396
  draft.view,
33110
33397
  current.messageId,
@@ -33119,9 +33406,22 @@ function reduceBody(draft, event) {
33119
33406
  const tracking = current.blocks[event.index];
33120
33407
  if (tracking === void 0) return null;
33121
33408
  let next = draft;
33409
+ if (tracking.buffer !== void 0 && tracking.buffer !== "" && tracking.partIndex !== void 0) {
33410
+ const text = tracking.buffer;
33411
+ next = {
33412
+ ...next,
33413
+ view: withPartAt(
33414
+ next.view,
33415
+ current.messageId,
33416
+ tracking.partIndex,
33417
+ (part) => part.type === "text" || part.type === "thinking" ? { ...part, text } : part
33418
+ )
33419
+ };
33420
+ }
33421
+ const { buffer: _buffered, ...trackingRest } = tracking;
33122
33422
  let blocks = {
33123
33423
  ...current.blocks,
33124
- [event.index]: { ...tracking, open: false }
33424
+ [event.index]: { ...trackingRest, open: false }
33125
33425
  };
33126
33426
  if (tracking.partIndex !== void 0) {
33127
33427
  const mi = messageIndexById(next.view.messages, current.messageId);
@@ -33406,6 +33706,62 @@ function appendUserMessage(state, text) {
33406
33706
  internal: { ...state.internal, nextMessageSeq: state.internal.nextMessageSeq + 1 }
33407
33707
  };
33408
33708
  }
33709
+ function setSessionViewDelivery(state, delivery) {
33710
+ const prev = state.internal.delivery;
33711
+ const next = {
33712
+ text: delivery.text ?? prev.text,
33713
+ thinking: delivery.thinking ?? prev.thinking
33714
+ };
33715
+ if (next.text === prev.text && next.thinking === prev.thinking) return state;
33716
+ return { view: state.view, internal: { ...state.internal, delivery: next } };
33717
+ }
33718
+ function stripThinkingParts(state) {
33719
+ const current = state.internal.current;
33720
+ let changed = false;
33721
+ let nextBlocks = current?.blocks ?? null;
33722
+ const messages = [];
33723
+ for (const message of state.view.messages) {
33724
+ const removed = [];
33725
+ const parts = message.parts.filter((part, index) => {
33726
+ if (part.type === "thinking") {
33727
+ removed.push(index);
33728
+ return false;
33729
+ }
33730
+ return true;
33731
+ });
33732
+ if (removed.length === 0) {
33733
+ messages.push(message);
33734
+ continue;
33735
+ }
33736
+ changed = true;
33737
+ const isCurrent = current !== null && message.id === current.messageId;
33738
+ if (isCurrent && nextBlocks !== null) {
33739
+ const remapped = {};
33740
+ for (const [key2, tracking] of Object.entries(nextBlocks)) {
33741
+ if (tracking.partIndex === void 0) {
33742
+ remapped[Number(key2)] = tracking;
33743
+ continue;
33744
+ }
33745
+ if (removed.includes(tracking.partIndex)) {
33746
+ const { partIndex: _gone, buffer: _buf, ...rest } = tracking;
33747
+ remapped[Number(key2)] = rest;
33748
+ continue;
33749
+ }
33750
+ const shift = removed.filter((r) => r < tracking.partIndex).length;
33751
+ remapped[Number(key2)] = shift > 0 ? { ...tracking, partIndex: tracking.partIndex - shift } : tracking;
33752
+ }
33753
+ nextBlocks = remapped;
33754
+ }
33755
+ if (parts.length > 0 || isCurrent) {
33756
+ messages.push({ ...message, parts });
33757
+ }
33758
+ }
33759
+ if (!changed) return state;
33760
+ return {
33761
+ view: { ...state.view, messages },
33762
+ internal: current !== null && nextBlocks !== null && nextBlocks !== current.blocks ? { ...state.internal, current: { ...current, blocks: nextBlocks } } : state.internal
33763
+ };
33764
+ }
33409
33765
  function markSourceFailure(state, error) {
33410
33766
  const message = error instanceof Error ? error.message : String(error);
33411
33767
  return finalize({
@@ -33418,7 +33774,8 @@ function markSourceFailure(state, error) {
33418
33774
  }
33419
33775
 
33420
33776
  // src/view/history.ts
33421
- function viewStateFromHistory(messages) {
33777
+ function viewStateFromHistory(messages, options) {
33778
+ const thinkingMode = options?.delivery?.thinking ?? "stream";
33422
33779
  const results = /* @__PURE__ */ new Map();
33423
33780
  for (const message of messages) {
33424
33781
  for (const block of message.blocks) {
@@ -33435,7 +33792,9 @@ function viewStateFromHistory(messages) {
33435
33792
  if (block.text !== "") parts.push({ type: "text", text: block.text });
33436
33793
  break;
33437
33794
  case "thinking":
33438
- if (block.text !== "") parts.push({ type: "thinking", text: block.text });
33795
+ if (block.text !== "" && thinkingMode !== "off") {
33796
+ parts.push({ type: "thinking", text: block.text });
33797
+ }
33439
33798
  break;
33440
33799
  case "tool_call": {
33441
33800
  const result = results.get(block.id);
@@ -33462,7 +33821,7 @@ function viewStateFromHistory(messages) {
33462
33821
  uiMessages.push({ id: `msg-${nextSeq}`, role: message.role, parts });
33463
33822
  nextSeq += 1;
33464
33823
  }
33465
- const initial = initialSessionViewState();
33824
+ const initial = initialSessionViewState(options);
33466
33825
  return {
33467
33826
  view: { ...initial.view, messages: uiMessages },
33468
33827
  internal: { ...initial.internal, nextMessageSeq: nextSeq }
@@ -33502,13 +33861,15 @@ function startEventPump(source, handlers) {
33502
33861
  }
33503
33862
 
33504
33863
  // src/view/session-view.ts
33505
- function createSessionView(source) {
33506
- let current = initialSessionViewState();
33864
+ function createSessionView(source, options) {
33865
+ let current = initialSessionViewState(options);
33507
33866
  const listeners = /* @__PURE__ */ new Set();
33508
33867
  let disposed = false;
33509
33868
  const commit = (next) => {
33510
33869
  if (next === current) return;
33870
+ const viewChanged = next.view !== current.view;
33511
33871
  current = next;
33872
+ if (!viewChanged) return;
33512
33873
  for (const listener of [...listeners]) {
33513
33874
  try {
33514
33875
  listener(next.view);
@@ -33538,6 +33899,12 @@ function createSessionView(source) {
33538
33899
  if (disposed) return;
33539
33900
  commit(appendUserMessage(current, text));
33540
33901
  },
33902
+ setDelivery(delivery) {
33903
+ if (disposed) return;
33904
+ let next = setSessionViewDelivery(current, delivery);
33905
+ if (delivery.thinking === "off") next = stripThinkingParts(next);
33906
+ commit(next);
33907
+ },
33541
33908
  dispose() {
33542
33909
  if (disposed) return;
33543
33910
  disposed = true;
@@ -33699,6 +34066,7 @@ export {
33699
34066
  EndUserIdSchema,
33700
34067
  HEADER_APP_TOKEN,
33701
34068
  IMAGEGEN_TOOL_MAX_N,
34069
+ IMAGEGEN_TOOL_TIMEOUT_MS,
33702
34070
  ImageGenArgsSchema,
33703
34071
  McpHost,
33704
34072
  OUTPUT_TAIL_MAX_CHARS,
@@ -33710,6 +34078,7 @@ export {
33710
34078
  TansrSdkError,
33711
34079
  UnavailableChannel,
33712
34080
  VIDEOGEN_TOOL_MAX_DURATION,
34081
+ VIDEOGEN_TOOL_TIMEOUT_MS,
33713
34082
  VideoGenArgsSchema,
33714
34083
  accumulateUsage,
33715
34084
  appBundleRegistryConfig,
@@ -33745,6 +34114,8 @@ export {
33745
34114
  resolveInitialMessages,
33746
34115
  resolvePlatformSelection,
33747
34116
  runAgent,
34117
+ setSessionViewDelivery,
34118
+ stripThinkingParts,
33748
34119
  subagentModelResolverOf,
33749
34120
  toToolDef,
33750
34121
  viewStateFromHistory
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tansr/sdk",
3
- "version": "0.4.0",
3
+ "version": "0.5.0",
4
4
  "description": "Tansr public TypeScript SDK: headless agent API (query / createSession / runAgent) + pure protocol type re-exports (public, MIT).",
5
5
  "license": "MIT",
6
6
  "type": "module",