qlogicagent 1.0.1 → 1.1.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.
Files changed (42) hide show
  1. package/dist/agent.js +6 -6
  2. package/dist/cli.js +181 -172
  3. package/dist/index.js +181 -172
  4. package/dist/orchestration.js +1 -1
  5. package/dist/types/agent/tool-loop.d.ts +2 -0
  6. package/dist/types/agent/types.d.ts +46 -1
  7. package/dist/types/cli/stdio-server.d.ts +10 -0
  8. package/dist/types/cli/tool-bootstrap.d.ts +13 -1
  9. package/dist/types/llm/index.d.ts +1 -1
  10. package/dist/types/llm/llm-client.d.ts +1 -1
  11. package/dist/types/llm/media-client.d.ts +3 -4
  12. package/dist/types/llm/media-transport.d.ts +75 -4
  13. package/dist/types/llm/provider-def.d.ts +124 -3
  14. package/dist/types/llm/provider-registry.d.ts +5 -0
  15. package/dist/types/llm/provider-tool-api.d.ts +44 -0
  16. package/dist/types/llm/retry.d.ts +37 -0
  17. package/dist/types/llm/transport.d.ts +157 -2
  18. package/dist/types/llm/transports/anthropic-messages.d.ts +7 -0
  19. package/dist/types/llm/transports/minimax-media.d.ts +5 -0
  20. package/dist/types/llm/transports/openai-chat.d.ts +44 -3
  21. package/dist/types/llm/transports/realtime-transport.d.ts +183 -0
  22. package/dist/types/llm/transports/volcengine-grounding.d.ts +58 -0
  23. package/dist/types/llm/transports/volcengine-media.d.ts +50 -0
  24. package/dist/types/llm/transports/volcengine-responses.d.ts +60 -0
  25. package/dist/types/llm/transports/zhipu-media.d.ts +60 -0
  26. package/dist/types/llm/transports/zhipu-tool-api.d.ts +35 -0
  27. package/dist/types/orchestration/tool-cascade.d.ts +40 -0
  28. package/dist/types/orchestration/tool-loop/tool-schema.d.ts +1 -1
  29. package/dist/types/protocol/methods.d.ts +19 -0
  30. package/dist/types/skills/memory/memory-extractor.d.ts +1 -1
  31. package/dist/types/skills/tools/file-management-tool.d.ts +90 -0
  32. package/dist/types/skills/tools/image-generate-tool.d.ts +13 -1
  33. package/dist/types/skills/tools/music-generate-tool.d.ts +25 -0
  34. package/dist/types/skills/tools/stt-tool.d.ts +33 -0
  35. package/dist/types/skills/tools/three-d-generate-tool.d.ts +45 -0
  36. package/dist/types/skills/tools/tts-tool.d.ts +12 -0
  37. package/dist/types/skills/tools/video-edit-tool.d.ts +5 -2
  38. package/dist/types/skills/tools/video-generate-tool.d.ts +102 -2
  39. package/dist/types/skills/tools/video-merge-tool.d.ts +1 -1
  40. package/dist/types/skills/tools/video-upscale-tool.d.ts +1 -1
  41. package/dist/types/skills/tools/voice-clone-tool.d.ts +40 -0
  42. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- function ce(e,t,n){return{role:"assistant",content:t||null,tool_calls:e,...n&&n.length>0?{thinkingBlocks:n}:{}}}function ue(e,t){let n=t.ok?typeof t.payload=="string"?t.payload:JSON.stringify(t.payload??""):`Error: ${t.error??"Tool execution failed"}`;return{role:"tool",tool_call_id:e,content:n}}var pe=/\b(?:daily|weekly|monthly)(?:\/(?:daily|weekly|monthly))* (?:usage )?limit(?:s)?(?: (?:exhausted|reached|exceeded))?\b/i,h={rateLimit:[/rate[_ ]limit|too many requests|429/,"model_cooldown","exceeded your current quota","resource has been exhausted","quota exceeded","resource_exhausted","usage limit",/\btpm\b/i,"tokens per minute","tokens per day"],overloaded:[/overloaded_error|"type"\s*:\s*"overloaded_error"/i,"overloaded",/service[_ ]unavailable.*(?:overload|capacity|high[_ ]demand)|(?:overload|capacity|high[_ ]demand).*service[_ ]unavailable/i,"high demand"],timeout:["timeout","timed out","service unavailable","deadline exceeded","context deadline exceeded","connection error","network error","network request failed","fetch failed","socket hang up",/\beconn(?:refused|reset|aborted)\b/i,/\benotfound\b/i,/\beai_again\b/i,/without sending (?:any )?chunks?/i,/\bstop reason:\s*(?:abort|error|network_error)\b/i,/\breason:\s*(?:abort|error|network_error)\b/i,/\bunhandled stop reason:\s*(?:abort|error|network_error)\b/i],billing:[/["']?(?:status|code)["']?\s*[:=]\s*402\b|\bhttp\s*402\b|\berror(?:\s+code)?\s*[:=]?\s*402\b|\b(?:got|returned|received)\s+(?:a\s+)?402\b|^\s*402\s+payment/i,"payment required","insufficient credits",/insufficient[_ ]quota/i,"credit balance","plans & billing","insufficient balance"],authPermanent:[/api[_ ]?key[_ ]?(?:revoked|invalid|deactivated|deleted)/i,"invalid_api_key","key has been disabled","key has been revoked","account has been deactivated",/could not (?:authenticate|validate).*(?:api[_ ]?key|credentials)/i,"permission_error","not allowed for this organization"],auth:[/invalid[_ ]?api[_ ]?key/,"incorrect api key","invalid token","authentication","re-authenticate","oauth token refresh failed","unauthorized","forbidden","access denied","insufficient permissions","insufficient permission",/missing scopes?:/i,"expired","token has expired",/\b401\b/,/\b403\b/,"no credentials found","no api key found"],format:["string should match pattern","tool_use.id","tool_use_id","messages.1.content.1.tool_use.id","invalid request format",/tool call id was.*must be/i]},de=/^(?:error[:\s-]+)?billing(?:\s+error)?(?:[:\s-]+|$)|^(?:error[:\s-]+)?(?:credit balance|insufficient credits?|payment required|http\s*402\b)/i,me=/["']?(?:status|code)["']?\s*[:=]\s*402\b|\bhttp\s*402\b|\berror(?:\s+code)?\s*[:=]?\s*402\b|^\s*402\s+payment/i,fe=512,ge=/^(?:http\s*)?(\d{3})(?:\s+([\s\S]+))?$/i;var ye=new Set([500,502,503,504,521,522,523,524,529]),he=["insufficient credits","insufficient quota","credit balance","insufficient balance","plans & billing","add more credits","top up"],Ce=["upgrade your plan","upgrade plan","current plan","subscription"],Te=["daily","weekly","monthly"],be=["try again","retry","temporary","cooldown"],ke=["usage limit","rate limit","organization usage"],_e=["organization","workspace"],Re=["billing period","exceeded","reached","exhausted"],xe=/["']?(?:status|code)["']?\s*[:=]\s*402\b|\bhttp\s*402\b|\berror(?:\s+code)?\s*[:=]?\s*402\b|\b(?:got|returned|received)\s+(?:a\s+)?402\b|^\s*402\s+payment required\b/i,Se=/^(?:error[:\s-]+)?(?:(?:http\s*)?402(?:\s+payment required)?|payment required)(?:[:\s-]+|$)/i;function C(e,t){if(!e)return!1;let n=e.toLowerCase();return t.some(o=>o instanceof RegExp?o.test(n):n.includes(o))}function Ae(e){return C(e,h.format)}function U(e){return C(e,h.rateLimit)}function ve(e){return C(e,h.timeout)}function Me(e){return pe.test(e)}function v(e){let t=e.toLowerCase();return t?e.length>fe?me.test(t):C(t,h.billing)?!0:de.test(e)?t.includes("upgrade")||t.includes("credits")||t.includes("payment")||t.includes("plan"):!1:!1}function Y(e){return C(e,h.authPermanent)}function we(e){return C(e,h.auth)}function W(e){return C(e,h.overloaded)}function y(e,t){return t.some(n=>e.includes(n))}function Ee(e){return y(e,he)||y(e,Ce)&&e.includes("limit")||e.includes("billing hard limit")||e.includes("hard limit reached")||e.includes("maximum allowed")&&e.includes("limit")}function Ie(e){let t=y(e,Te),n=e.includes("spend limit")||e.includes("spending limit"),o=y(e,_e);return y(e,be)&&y(e,ke)||t&&(e.includes("usage limit")||n)||t&&e.includes("limit")&&e.includes("reset")||o&&e.includes("limit")&&(n||y(e,Re))}function Le(e){return e.trim().toLowerCase().replace(Se,"").trim()}function K(e){let t=Le(e);return!t||Ee(t)?"billing":U(t)||Ie(t)?"rate_limit":"billing"}function Oe(e){return xe.test(e)?K(e):null}function J(e){let t=e.match(ge);if(!t)return null;let n=Number(t[1]);return Number.isFinite(n)?{code:n,rest:(t[2]??"").trim()}:null}function Pe(e){if(!e)return!1;let t=e.toLowerCase();return t.includes('"type":"api_error"')&&t.includes("internal server error")}function Fe(e){let t=e.trim();if(!t)return!1;let n=J(t);return n?ye.has(n.code):!1}function V(e,t){return typeof e!="number"||!Number.isFinite(e)?null:e===402?t?K(t):"billing":e===429?"rate_limit":e===401||e===403?t&&Y(t)?"auth_permanent":"auth":e===408?"timeout":e===503?t&&W(t)?"overloaded":"timeout":e===502||e===504?"timeout":e===529?"overloaded":e===400?t&&v(t)?"billing":"format":null}function Ne(e){if(!e)return!1;let t=e.toLowerCase();return!!(t.includes("unknown model")||t.includes("model not found")||t.includes("model_not_found")||t.includes("not_found_error")||t.includes("does not exist")&&t.includes("model")||t.includes("invalid model")&&!t.includes("invalid model reference")||/models\/[^\s]+ is not found/i.test(e)||/\b404\b/.test(e)&&/not[-_ ]?found/i.test(e))}function Be(e){if(!e)return!1;let t=e.toLowerCase();return t.includes("session not found")||t.includes("session does not exist")||t.includes("session expired")||t.includes("session invalid")||t.includes("conversation not found")||t.includes("conversation does not exist")||t.includes("conversation expired")||t.includes("conversation invalid")||t.includes("no such session")||t.includes("invalid session")||t.includes("session id not found")||t.includes("conversation id not found")}function X(e){if(Be(e))return"session_expired";if(Ne(e))return"model_not_found";let t=Oe(e);return t||(Me(e)?v(e)?"billing":"rate_limit":U(e)?"rate_limit":W(e)?"overloaded":Fe(e)?J(e.trim())?.code===529?"overloaded":"timeout":Pe(e)?"timeout":Ae(e)?"format":v(e)?"billing":ve(e)?"timeout":Y(e)?"auth_permanent":we(e)?"auth":null)}var De={timeout:"RETRYABLE_TRANSIENT",overloaded:"RETRYABLE_TRANSIENT",rate_limit:"RETRYABLE_DEGRADED",auth:"NON_RETRYABLE_AUTH",auth_permanent:"NON_RETRYABLE_AUTH",billing:"NON_RETRYABLE_QUOTA",format:"NON_RETRYABLE_CONTENT",model_not_found:"NON_RETRYABLE_CONTENT",session_expired:"NON_RETRYABLE_CONTENT",unknown:"RETRYABLE_TRANSIENT"},je=new Set(["RETRYABLE_TRANSIENT","RETRYABLE_DEGRADED","TOOL_EXECUTION_FAILED"]);function $e(e,t){let n=V(e,t)??(t?X(t):null);return n?De[n]:typeof e=="number"&&e>=400&&e<500?"NON_RETRYABLE_CONTENT":"RETRYABLE_TRANSIENT"}function qe(e){return je.has(e)}function B(e){return typeof e.compressAsync=="function"}var Q=4,M=class{constructor(t){this.estimateTokens=t}estimateTokens;compress(t,n){let o=[],r=[];for(let c of t)c.role==="system"?o.push(c):r.push(c);let a=n;for(let c of o)a-=this.estimateTokens(c);let i;for(let c of r)if(c.role==="user"){i=c;break}if(i&&(a-=this.estimateTokens(i)),a<=0)return{messages:i?[...o,i]:o,droppedCount:r.length-(i?1:0),strategy:"sliding-window"};let s=[],l=0;for(let c=r.length-1;c>=0;c--){let d=r[c];if(d===i)continue;let p=this.estimateTokens(d);if(a-p<0&&l>=Q)break;if(a-p<0&&l<Q){s.unshift(d),l++;continue}a-=p,s.unshift(d),l++}let u=[...o];return i&&!s.includes(i)&&u.push(i),u.push(...s),{messages:u,droppedCount:r.length-(s.length+(i&&!s.includes(i)?1:0)),strategy:"sliding-window"}}},w=class{constructor(t,n){this.recentCount=t;this.summarize=n}recentCount;summarize;compress(t,n){let o=t.filter(l=>l.role==="system"),r=t.filter(l=>l.role!=="system");if(r.length<=this.recentCount)return{messages:t,droppedCount:0,strategy:"summarize-old"};let a=r.slice(0,r.length-this.recentCount),i=r.slice(r.length-this.recentCount),s=this.summarize(a);return{messages:[...o,{role:"system",content:`[Conversation summary]
1
+ function ce(e,t,n,o){return{role:"assistant",content:t||null,tool_calls:e,...n&&n.length>0?{thinkingBlocks:n}:{},...o?{reasoning_content:o}:{}}}function ue(e,t){let n=t.ok?typeof t.payload=="string"?t.payload:JSON.stringify(t.payload??""):`Error: ${t.error??"Tool execution failed"}`;return{role:"tool",tool_call_id:e,content:n}}var pe=/\b(?:daily|weekly|monthly)(?:\/(?:daily|weekly|monthly))* (?:usage )?limit(?:s)?(?: (?:exhausted|reached|exceeded))?\b/i,h={rateLimit:[/rate[_ ]limit|too many requests|429/,"model_cooldown","exceeded your current quota","resource has been exhausted","quota exceeded","resource_exhausted","usage limit",/\btpm\b/i,"tokens per minute","tokens per day"],overloaded:[/overloaded_error|"type"\s*:\s*"overloaded_error"/i,"overloaded",/service[_ ]unavailable.*(?:overload|capacity|high[_ ]demand)|(?:overload|capacity|high[_ ]demand).*service[_ ]unavailable/i,"high demand"],timeout:["timeout","timed out","service unavailable","deadline exceeded","context deadline exceeded","connection error","network error","network request failed","fetch failed","socket hang up",/\beconn(?:refused|reset|aborted)\b/i,/\benotfound\b/i,/\beai_again\b/i,/without sending (?:any )?chunks?/i,/\bstop reason:\s*(?:abort|error|network_error)\b/i,/\breason:\s*(?:abort|error|network_error)\b/i,/\bunhandled stop reason:\s*(?:abort|error|network_error)\b/i],billing:[/["']?(?:status|code)["']?\s*[:=]\s*402\b|\bhttp\s*402\b|\berror(?:\s+code)?\s*[:=]?\s*402\b|\b(?:got|returned|received)\s+(?:a\s+)?402\b|^\s*402\s+payment/i,"payment required","insufficient credits",/insufficient[_ ]quota/i,"credit balance","plans & billing","insufficient balance"],authPermanent:[/api[_ ]?key[_ ]?(?:revoked|invalid|deactivated|deleted)/i,"invalid_api_key","key has been disabled","key has been revoked","account has been deactivated",/could not (?:authenticate|validate).*(?:api[_ ]?key|credentials)/i,"permission_error","not allowed for this organization"],auth:[/invalid[_ ]?api[_ ]?key/,"incorrect api key","invalid token","authentication","re-authenticate","oauth token refresh failed","unauthorized","forbidden","access denied","insufficient permissions","insufficient permission",/missing scopes?:/i,"expired","token has expired",/\b401\b/,/\b403\b/,"no credentials found","no api key found"],format:["string should match pattern","tool_use.id","tool_use_id","messages.1.content.1.tool_use.id","invalid request format",/tool call id was.*must be/i]},de=/^(?:error[:\s-]+)?billing(?:\s+error)?(?:[:\s-]+|$)|^(?:error[:\s-]+)?(?:credit balance|insufficient credits?|payment required|http\s*402\b)/i,me=/["']?(?:status|code)["']?\s*[:=]\s*402\b|\bhttp\s*402\b|\berror(?:\s+code)?\s*[:=]?\s*402\b|^\s*402\s+payment/i,fe=512,ge=/^(?:http\s*)?(\d{3})(?:\s+([\s\S]+))?$/i;var ye=new Set([500,502,503,504,521,522,523,524,529]),he=["insufficient credits","insufficient quota","credit balance","insufficient balance","plans & billing","add more credits","top up"],Ce=["upgrade your plan","upgrade plan","current plan","subscription"],Te=["daily","weekly","monthly"],be=["try again","retry","temporary","cooldown"],ke=["usage limit","rate limit","organization usage"],_e=["organization","workspace"],Re=["billing period","exceeded","reached","exhausted"],xe=/["']?(?:status|code)["']?\s*[:=]\s*402\b|\bhttp\s*402\b|\berror(?:\s+code)?\s*[:=]?\s*402\b|\b(?:got|returned|received)\s+(?:a\s+)?402\b|^\s*402\s+payment required\b/i,Se=/^(?:error[:\s-]+)?(?:(?:http\s*)?402(?:\s+payment required)?|payment required)(?:[:\s-]+|$)/i;function C(e,t){if(!e)return!1;let n=e.toLowerCase();return t.some(o=>o instanceof RegExp?o.test(n):n.includes(o))}function Ae(e){return C(e,h.format)}function U(e){return C(e,h.rateLimit)}function ve(e){return C(e,h.timeout)}function Me(e){return pe.test(e)}function v(e){let t=e.toLowerCase();return t?e.length>fe?me.test(t):C(t,h.billing)?!0:de.test(e)?t.includes("upgrade")||t.includes("credits")||t.includes("payment")||t.includes("plan"):!1:!1}function Y(e){return C(e,h.authPermanent)}function we(e){return C(e,h.auth)}function W(e){return C(e,h.overloaded)}function y(e,t){return t.some(n=>e.includes(n))}function Ee(e){return y(e,he)||y(e,Ce)&&e.includes("limit")||e.includes("billing hard limit")||e.includes("hard limit reached")||e.includes("maximum allowed")&&e.includes("limit")}function Ie(e){let t=y(e,Te),n=e.includes("spend limit")||e.includes("spending limit"),o=y(e,_e);return y(e,be)&&y(e,ke)||t&&(e.includes("usage limit")||n)||t&&e.includes("limit")&&e.includes("reset")||o&&e.includes("limit")&&(n||y(e,Re))}function Le(e){return e.trim().toLowerCase().replace(Se,"").trim()}function K(e){let t=Le(e);return!t||Ee(t)?"billing":U(t)||Ie(t)?"rate_limit":"billing"}function Oe(e){return xe.test(e)?K(e):null}function J(e){let t=e.match(ge);if(!t)return null;let n=Number(t[1]);return Number.isFinite(n)?{code:n,rest:(t[2]??"").trim()}:null}function Pe(e){if(!e)return!1;let t=e.toLowerCase();return t.includes('"type":"api_error"')&&t.includes("internal server error")}function Fe(e){let t=e.trim();if(!t)return!1;let n=J(t);return n?ye.has(n.code):!1}function V(e,t){return typeof e!="number"||!Number.isFinite(e)?null:e===402?t?K(t):"billing":e===429?"rate_limit":e===401||e===403?t&&Y(t)?"auth_permanent":"auth":e===408?"timeout":e===503?t&&W(t)?"overloaded":"timeout":e===502||e===504?"timeout":e===529?"overloaded":e===400?t&&v(t)?"billing":"format":null}function Ne(e){if(!e)return!1;let t=e.toLowerCase();return!!(t.includes("unknown model")||t.includes("model not found")||t.includes("model_not_found")||t.includes("not_found_error")||t.includes("does not exist")&&t.includes("model")||t.includes("invalid model")&&!t.includes("invalid model reference")||/models\/[^\s]+ is not found/i.test(e)||/\b404\b/.test(e)&&/not[-_ ]?found/i.test(e))}function Be(e){if(!e)return!1;let t=e.toLowerCase();return t.includes("session not found")||t.includes("session does not exist")||t.includes("session expired")||t.includes("session invalid")||t.includes("conversation not found")||t.includes("conversation does not exist")||t.includes("conversation expired")||t.includes("conversation invalid")||t.includes("no such session")||t.includes("invalid session")||t.includes("session id not found")||t.includes("conversation id not found")}function X(e){if(Be(e))return"session_expired";if(Ne(e))return"model_not_found";let t=Oe(e);return t||(Me(e)?v(e)?"billing":"rate_limit":U(e)?"rate_limit":W(e)?"overloaded":Fe(e)?J(e.trim())?.code===529?"overloaded":"timeout":Pe(e)?"timeout":Ae(e)?"format":v(e)?"billing":ve(e)?"timeout":Y(e)?"auth_permanent":we(e)?"auth":null)}var De={timeout:"RETRYABLE_TRANSIENT",overloaded:"RETRYABLE_TRANSIENT",rate_limit:"RETRYABLE_DEGRADED",auth:"NON_RETRYABLE_AUTH",auth_permanent:"NON_RETRYABLE_AUTH",billing:"NON_RETRYABLE_QUOTA",format:"NON_RETRYABLE_CONTENT",model_not_found:"NON_RETRYABLE_CONTENT",session_expired:"NON_RETRYABLE_CONTENT",unknown:"RETRYABLE_TRANSIENT"},je=new Set(["RETRYABLE_TRANSIENT","RETRYABLE_DEGRADED","TOOL_EXECUTION_FAILED"]);function $e(e,t){let n=V(e,t)??(t?X(t):null);return n?De[n]:typeof e=="number"&&e>=400&&e<500?"NON_RETRYABLE_CONTENT":"RETRYABLE_TRANSIENT"}function qe(e){return je.has(e)}function B(e){return typeof e.compressAsync=="function"}var Q=4,M=class{constructor(t){this.estimateTokens=t}estimateTokens;compress(t,n){let o=[],r=[];for(let c of t)c.role==="system"?o.push(c):r.push(c);let a=n;for(let c of o)a-=this.estimateTokens(c);let i;for(let c of r)if(c.role==="user"){i=c;break}if(i&&(a-=this.estimateTokens(i)),a<=0)return{messages:i?[...o,i]:o,droppedCount:r.length-(i?1:0),strategy:"sliding-window"};let s=[],l=0;for(let c=r.length-1;c>=0;c--){let d=r[c];if(d===i)continue;let p=this.estimateTokens(d);if(a-p<0&&l>=Q)break;if(a-p<0&&l<Q){s.unshift(d),l++;continue}a-=p,s.unshift(d),l++}let u=[...o];return i&&!s.includes(i)&&u.push(i),u.push(...s),{messages:u,droppedCount:r.length-(s.length+(i&&!s.includes(i)?1:0)),strategy:"sliding-window"}}},w=class{constructor(t,n){this.recentCount=t;this.summarize=n}recentCount;summarize;compress(t,n){let o=t.filter(l=>l.role==="system"),r=t.filter(l=>l.role!=="system");if(r.length<=this.recentCount)return{messages:t,droppedCount:0,strategy:"summarize-old"};let a=r.slice(0,r.length-this.recentCount),i=r.slice(r.length-this.recentCount),s=this.summarize(a);return{messages:[...o,{role:"system",content:`[Conversation summary]
2
2
  ${s}`},...i],droppedCount:a.length,strategy:"summarize-old"}}},E=class{constructor(t=8e3){this.maxToolResultChars=t}maxToolResultChars;compress(t,n){let o=0;return{messages:t.map(a=>a.role!=="tool"||typeof a.content!="string"||a.content.length<=this.maxToolResultChars?a:(o++,{...a,content:Ge(a.content,this.maxToolResultChars)})),droppedCount:o,strategy:"tool-result-trim"}}};function Ge(e,t){if(e.length<=t)return e;let n=e.slice(0,t);if(e.trimStart().startsWith("{")||e.trimStart().startsWith("[")){let a=Math.max(n.lastIndexOf("},"),n.lastIndexOf("],"),n.lastIndexOf(`}
3
3
  `),n.lastIndexOf(`]
4
4
  `));if(a>t*.5)return n.slice(0,a+1)+`
@@ -78,6 +78,8 @@ export interface ToolLoopParams {
78
78
  }) => Promise<void> | void>;
79
79
  /** Max concurrent tool executions (0 = unlimited, CC parity: semantic concurrency control). */
80
80
  maxConcurrentTools?: number;
81
+ /** Model requires streaming — disable non-streaming fallback. */
82
+ streamRequired?: boolean;
81
83
  signal?: AbortSignal;
82
84
  }
83
85
  /**
@@ -13,6 +13,7 @@
13
13
  */
14
14
  import type { SkillInstruction } from "../orchestration/index.js";
15
15
  import type { HookRegistry } from "../contracts/hooks.js";
16
+ import type { MediaCapability } from "../llm/provider-def.js";
16
17
  export type ChatMessageRole = "system" | "user" | "assistant" | "tool";
17
18
  /** Thinking block from Anthropic Messages API (DeepSeek, Claude, etc.) */
18
19
  export interface ThinkingBlock {
@@ -30,6 +31,38 @@ export interface ChatMessage {
30
31
  name?: string;
31
32
  /** Anthropic thinking blocks — must be passed back to API in subsequent requests */
32
33
  thinkingBlocks?: ThinkingBlock[];
34
+ /**
35
+ * Image URLs for vision-capable models.
36
+ * Transports convert these into the provider's native content block format:
37
+ * - OpenAI-chat: [{type:"text",text:...},{type:"image_url",image_url:{url:...}}]
38
+ * - Anthropic: [{type:"text",text:...},{type:"image",source:{type:"url",url:...}}]
39
+ * Only valid on role="user" messages.
40
+ */
41
+ imageUrls?: string[];
42
+ /** Image detail level for vision understanding: 'auto' | 'low' | 'high' | 'xhigh' */
43
+ imageDetail?: "auto" | "low" | "high" | "xhigh";
44
+ /** Max image pixels budget for vision understanding (Volcengine image_pixel_limit) */
45
+ imagePixelLimit?: {
46
+ minPixels?: number;
47
+ maxPixels?: number;
48
+ };
49
+ /** Video URLs for video-understanding models. Only valid on role="user" messages. */
50
+ videoUrls?: string[];
51
+ /** Per-video fps for video understanding (0.2-5, default 1) */
52
+ videoFps?: number;
53
+ /** Audio format hint for audio understanding: 'mp3' | 'wav' | 'aac' | 'm4a' */
54
+ audioFormat?: "mp3" | "wav" | "aac" | "m4a";
55
+ /** Audio URLs for audio-understanding models. Only valid on role="user" messages. */
56
+ audioUrls?: string[];
57
+ /**
58
+ * Pre-uploaded file IDs for document/media understanding.
59
+ * Used with Files API — each entry is a { id, mimeType } pair.
60
+ * Only valid on role="user" messages.
61
+ */
62
+ fileIds?: Array<{
63
+ id: string;
64
+ mimeType?: string;
65
+ }>;
33
66
  }
34
67
  export interface ToolCallMessage {
35
68
  id: string;
@@ -130,7 +163,7 @@ export interface TurnRequest {
130
163
  export interface TurnConfig {
131
164
  /** LLM provider id, e.g. "deepseek" */
132
165
  provider?: string;
133
- /** Model id, e.g. "deepseek-chat" */
166
+ /** Model id, e.g. "deepseek-v4-flash" */
134
167
  model?: string;
135
168
  /** User API key */
136
169
  apiKey?: string;
@@ -160,6 +193,18 @@ export interface TurnConfig {
160
193
  summaryModel?: string;
161
194
  /** Max concurrent tool executions (0 = unlimited). */
162
195
  maxConcurrentTools?: number;
196
+ /** Model requires streaming — disable non-streaming fallback. */
197
+ streamRequired?: boolean;
198
+ /**
199
+ * User-designated provider+model per media category.
200
+ * Each entry maps a media type (image/video/music/tts/3d/...) to
201
+ * the specific provider and model the user chose. No failover —
202
+ * if the designated provider fails, the error propagates directly.
203
+ */
204
+ mediaProviders?: Partial<Record<MediaCapability, {
205
+ provider: string;
206
+ model: string;
207
+ }>>;
163
208
  }
164
209
  export type TurnEvent = {
165
210
  type: "start";
@@ -100,6 +100,16 @@ export declare class StdioServer {
100
100
  * Supports optional category filter.
101
101
  */
102
102
  private handleToolsList;
103
+ /**
104
+ * `media.listModels` — List available media generation models.
105
+ * Desktop app uses this to populate the model selector per category.
106
+ */
107
+ private handleMediaListModels;
108
+ /**
109
+ * `provider.list` — List all available LLM providers grouped by logical family.
110
+ * Returns protocol variants so callers can pick which transport to use.
111
+ */
112
+ private handleProviderList;
103
113
  /**
104
114
  * `config.get` — Read current agent runtime configuration.
105
115
  * Returns merged user-level + project-level settings.
@@ -2,12 +2,24 @@ import type { PortableTool } from "../skills/portable-tool.js";
2
2
  import { type ExecProgress } from "../skills/tools/exec-tool.js";
3
3
  import type { AgentLogger } from "../agent/types.js";
4
4
  import type { MediaClient } from "../llm/media-client.js";
5
+ import type { MediaCapability } from "../llm/provider-def.js";
6
+ import type { ProviderToolAPI } from "../llm/provider-tool-api.js";
7
+ /**
8
+ * Set the provider's tool API for C-level cascade.
9
+ * When set, web_search tool will try provider-native search first,
10
+ * falling back to SearXNG. Called from stdio-server per session.
11
+ */
12
+ export declare function setProviderToolAPI(api: ProviderToolAPI | undefined): void;
5
13
  /**
6
14
  * Set the media client + API keys for generation tools.
7
15
  * Tools will call vendor APIs directly through MediaTransport.
8
16
  * Keys map: { providerId: apiKey, ... }
17
+ * Providers map: { "image": { provider: "volcengine", model: "doubao-seedream-5-0-260128" }, ... }
9
18
  */
10
- export declare function setMediaClientConfig(client: MediaClient | undefined, apiKeys?: Record<string, string>, onMediaUsage?: (model: string, billingUnit: string, quantity: number) => void): void;
19
+ export declare function setMediaClientConfig(client: MediaClient | undefined, apiKeys?: Record<string, string>, onMediaUsage?: (model: string, billingUnit: string, quantity: number) => void, providers?: Partial<Record<MediaCapability, {
20
+ provider: string;
21
+ model: string;
22
+ }>>): void;
11
23
  export interface BootstrapConfig {
12
24
  workdir?: string;
13
25
  log?: AgentLogger;
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * Provides: ProviderDef + LLMTransport + ProviderRegistry + LLMClient factory
5
5
  */
6
- export type { ProviderDef, ModelInfo, TransportType, AuthType, MediaCapability } from "./provider-def.js";
6
+ export type { ProviderDef, ModelInfo, TransportType, AuthType, MediaCapability, MediaCapabilities, VideoCapabilities, ImageCapabilities, MusicCapabilities, TtsCapabilities, ThreeDCapabilities, SttCapabilities, EmbeddingCapabilities, VideoUnderstandingCapabilities, ImageUnderstandingCapabilities, VoiceCloneCapabilities, RerankCapabilities, DocumentParsingCapabilities, VideoOperation, ImageOperation, MusicOperation, TtsOperation, ThreeDOperation } from "./provider-def.js";
7
7
  export type { LLMTransport, LLMRequest, LLMChunk, AccumulatedToolCall, } from "./transport.js";
8
8
  export { accumulateToolCalls } from "./transport.js";
9
9
  export type { MediaTransport, MediaRequest, MediaResult, MediaType } from "./media-transport.js";
@@ -10,7 +10,7 @@ import { ProviderRegistry } from "./provider-registry.js";
10
10
  export interface LLMClientConfig {
11
11
  /** Provider id, e.g. "deepseek" */
12
12
  provider: string;
13
- /** Model id, e.g. "deepseek-chat" */
13
+ /** Model id, e.g. "deepseek-v4-flash" */
14
14
  model: string;
15
15
  /** User API key */
16
16
  apiKey: string;
@@ -25,11 +25,10 @@ export declare class MediaClient {
25
25
  private transports;
26
26
  constructor(config: MediaClientConfig);
27
27
  /**
28
- * Find the best available model for a given media type.
29
- * Scans all providers for models with matching mediaType.
30
- * If preferredProvider is set, search that first.
28
+ * Find a specific model by provider + model id for a given media type.
29
+ * Used by the user-designated model routing (no failover).
31
30
  */
32
- resolveModel(mediaType: MediaCapability, preferredProvider?: string): ResolvedMediaModel | undefined;
31
+ resolveModelById(providerId: string, modelId: string, mediaType: MediaCapability): ResolvedMediaModel | undefined;
33
32
  /**
34
33
  * Get a MediaTransport for a specific provider.
35
34
  * Creates and caches the adapter on first access.
@@ -9,7 +9,7 @@
9
9
  * Each provider adapter implements this interface and hides vendor-specific
10
10
  * auth, endpoint paths, request shapes, and polling logic.
11
11
  */
12
- export type MediaType = "image" | "video" | "music" | "tts" | "3d";
12
+ export type MediaType = "image" | "video" | "music" | "tts" | "3d" | "stt" | "embedding" | "video_understanding" | "image_understanding" | "voice_clone" | "rerank" | "document_parsing";
13
13
  export interface MediaRequest {
14
14
  /** Generation model id, e.g. "doubao-seedream-5-0-260128", "gpt-image-2" */
15
15
  model: string;
@@ -39,12 +39,79 @@ export interface MediaRequest {
39
39
  channel?: string;
40
40
  /** Source video URLs for edit/merge operations */
41
41
  sourceVideos?: string[];
42
- /** Reference images for edit operations */
42
+ /** Reference images (no role / first_frame / last_frame) */
43
43
  referenceImages?: string[];
44
+ /** Reference image roles — parallel array with referenceImages. */
45
+ imageRoles?: Array<"first_frame" | "last_frame" | "reference_image">;
46
+ /** Reference video URLs for multimodal reference generation (Seedance 2.0) */
47
+ referenceVideos?: string[];
48
+ /** Reference audio URLs for multimodal reference generation (Seedance 2.0) */
49
+ referenceAudios?: string[];
50
+ /** Generate synchronized audio track (Seedance 2.0 / 1.5 pro) */
51
+ generateAudio?: boolean;
44
52
  /** Output resolution for upscale, e.g. "1080p" */
45
53
  resolution?: string;
46
- /** Operation variant: generate (default), edit, merge, upscale */
47
- operation?: "generate" | "edit" | "merge" | "upscale";
54
+ /** Operation variant: generate (default), edit, merge, upscale, multimodal_reference, extend */
55
+ operation?: "generate" | "edit" | "merge" | "upscale" | "multimodal_reference" | "extend";
56
+ /** Image/video quality, e.g. "auto", "high", "low", "hd" */
57
+ quality?: string;
58
+ /** Seed for reproducible generation */
59
+ seed?: number;
60
+ /** TTS voice, e.g. "alloy", "nova", "shimmer" */
61
+ voice?: string;
62
+ /** TTS speech speed multiplier */
63
+ speed?: number;
64
+ /** Pure instrumental mode (MiniMax music) */
65
+ isInstrumental?: boolean;
66
+ /** Source audio URL for cover/remix (MiniMax music) */
67
+ audioUrl?: string;
68
+ /** Output audio format, e.g. "mp3", "wav", "flac" */
69
+ audioFormat?: string;
70
+ /** Video frames per second */
71
+ fps?: number;
72
+ /** Whether to add AI watermark */
73
+ watermark?: boolean;
74
+ /** img2img guidance/control strength (0-1), e.g. Volcengine */
75
+ guidanceScale?: number;
76
+ /** Auto-generate lyrics when none provided (MiniMax) */
77
+ lyricsOptimizer?: boolean;
78
+ /** 3D output format, e.g. "glb", "obj", "usd", "usdz" */
79
+ outputFormat?: string;
80
+ /** Image background mode (OpenAI gpt-image-2): "transparent", "opaque", "auto" */
81
+ background?: string;
82
+ /** Provider-specific request metadata (e.g. rerank documents, parsing options) */
83
+ metadata?: Record<string, unknown>;
84
+ /** Ask the provider to optimize/enhance the prompt before generation */
85
+ enhancePrompt?: boolean;
86
+ /**
87
+ * Progress callback for async polling operations (video gen, 3D gen, etc.).
88
+ * Called periodically with estimated progress percentage and status text.
89
+ */
90
+ onProgress?: (percent: number, status: string) => void;
91
+ /** Enable progressive/streaming image generation (Volcengine Seedream stream:true) */
92
+ streamImage?: boolean;
93
+ /** Lock camera position (Seedance 1.0/1.5, not Seedance 2.0) */
94
+ cameraFixed?: boolean;
95
+ /** Return last frame URL for chaining continuous video segments */
96
+ returnLastFrame?: boolean;
97
+ /** Service tier: 'default' (online) or 'flex' (offline, ~50% cost) — not all models support flex */
98
+ serviceTier?: "default" | "flex";
99
+ /** Task expiration in seconds (for flex/offline scheduling) */
100
+ executionExpiresAfterSeconds?: number;
101
+ /** Draft mode — low-cost preview (Seedance 1.5 pro only) */
102
+ draft?: boolean;
103
+ /** Draft task ID to promote to final video */
104
+ draftTaskId?: string;
105
+ /** Video-level builtin tools, e.g. ["web_search"] (Seedance 2.0) */
106
+ videoTools?: string[];
107
+ /** End-user safety identifier for content moderation */
108
+ safetyIdentifier?: string;
109
+ /** Callback URL for async task status push notifications */
110
+ callbackUrl?: string;
111
+ /** Image detail level control: 'auto' | 'low' | 'high' */
112
+ detail?: "auto" | "low" | "high";
113
+ /** Max image pixels budget (Volcengine image_pixel_limit) */
114
+ imagePixelLimit?: number;
48
115
  }
49
116
  export interface MediaResult {
50
117
  /** URLs of generated media files */
@@ -61,6 +128,10 @@ export interface MediaResult {
61
128
  billingQuantity?: number;
62
129
  /** Provider-specific metadata */
63
130
  metadata?: Record<string, unknown>;
131
+ /** Last frame image URL for chaining continuous video generation */
132
+ lastFrameUrl?: string;
133
+ /** Task ID (for continuing draft→final or querying) */
134
+ taskId?: string;
64
135
  }
65
136
  export interface MediaTransport {
66
137
  /**
@@ -9,9 +9,116 @@
9
9
  * Layer 2: model-catalog.ts remote (models.dev)
10
10
  * Layer 3: user config (from agent.turn.config)
11
11
  */
12
- export type TransportType = "openai-chat" | "anthropic-messages";
12
+ export type TransportType = "openai-chat" | "anthropic-messages" | "volcengine-responses";
13
13
  export type AuthType = "bearer" | "x-api-key" | "none";
14
- export type MediaCapability = "image" | "video" | "music" | "tts" | "3d";
14
+ export type MediaCapability = "image" | "video" | "music" | "tts" | "3d" | "stt" | "embedding" | "video_understanding" | "image_understanding" | "voice_clone" | "rerank" | "document_parsing";
15
+ export type VideoOperation = "text2video" | "img2video" | "video2video" | "edit" | "merge" | "upscale";
16
+ export type ImageOperation = "text2image" | "img2img" | "inpainting" | "outpainting";
17
+ export type MusicOperation = "text2music" | "cover";
18
+ export type TtsOperation = "text2speech" | "voice_clone";
19
+ export type ThreeDOperation = "text2_3d" | "img2_3d";
20
+ export interface VideoCapabilities {
21
+ type: "video";
22
+ operations: VideoOperation[];
23
+ maxDurationSeconds?: number;
24
+ resolutions?: string[];
25
+ aspectRatios?: string[];
26
+ fps?: number[];
27
+ }
28
+ export interface ImageCapabilities {
29
+ type: "image";
30
+ operations: ImageOperation[];
31
+ sizes?: string[];
32
+ transparentBackground?: boolean;
33
+ }
34
+ export interface MusicCapabilities {
35
+ type: "music";
36
+ operations: MusicOperation[];
37
+ maxDurationSeconds?: number;
38
+ formats?: string[];
39
+ }
40
+ export interface TtsCapabilities {
41
+ type: "tts";
42
+ operations?: TtsOperation[];
43
+ voices?: string[];
44
+ maxCharacters?: number;
45
+ formats?: string[];
46
+ }
47
+ export interface ThreeDCapabilities {
48
+ type: "3d";
49
+ operations: ThreeDOperation[];
50
+ outputFormats?: string[];
51
+ }
52
+ export interface SttCapabilities {
53
+ type: "stt";
54
+ languages?: string[];
55
+ maxDurationSeconds?: number;
56
+ formats?: string[];
57
+ }
58
+ export interface EmbeddingCapabilities {
59
+ type: "embedding";
60
+ dimensions?: number;
61
+ maxTokens?: number;
62
+ }
63
+ export interface VideoUnderstandingCapabilities {
64
+ type: "video_understanding";
65
+ maxDurationSeconds?: number;
66
+ formats?: string[];
67
+ }
68
+ export interface ImageUnderstandingCapabilities {
69
+ type: "image_understanding";
70
+ formats?: string[];
71
+ }
72
+ export interface VoiceCloneCapabilities {
73
+ type: "voice_clone";
74
+ maxSampleDurationSeconds?: number;
75
+ maxSampleSizeMB?: number;
76
+ formats?: string[];
77
+ }
78
+ export interface RerankCapabilities {
79
+ type: "rerank";
80
+ maxDocuments?: number;
81
+ maxQueryLength?: number;
82
+ maxDocumentLength?: number;
83
+ }
84
+ export interface DocumentParsingCapabilities {
85
+ type: "document_parsing";
86
+ supportedFormats?: string[];
87
+ maxPageCount?: number;
88
+ maxFileSizeMB?: number;
89
+ }
90
+ export type MediaCapabilities = VideoCapabilities | ImageCapabilities | MusicCapabilities | TtsCapabilities | ThreeDCapabilities | SttCapabilities | EmbeddingCapabilities | VideoUnderstandingCapabilities | ImageUnderstandingCapabilities | VoiceCloneCapabilities | RerankCapabilities | DocumentParsingCapabilities;
91
+ /**
92
+ * Provider-specific quirks — drives conditional logic in transports.
93
+ * CC parity: provider detection via quirks flags instead of hardcoded if/else.
94
+ * altcode parity: provider auto-detect + per-provider parameter translation.
95
+ */
96
+ export interface ProviderQuirks {
97
+ /** Provider doesn't support thinking content blocks (Qwen) */
98
+ filterThinkingBlocks?: boolean;
99
+ /** Provider doesn't support image content blocks — strip imageUrls before sending (DeepSeek, MiniMax) */
100
+ filterImageBlocks?: boolean;
101
+ /** DeepSeek: budget_tokens ignored, use output_config.effort instead */
102
+ useEffortInsteadOfBudget?: boolean;
103
+ /** Provider supports reasoning_effort param (Kimi K2, OpenAI o-series) */
104
+ supportsReasoningEffort?: boolean;
105
+ /** Provider has built-in web search (Kimi: builtin_function.$web_search, GLM: web_search) */
106
+ builtinWebSearch?: boolean;
107
+ /** Provider has built-in code interpreter */
108
+ builtinCodeInterpreter?: boolean;
109
+ /** Supports thinking.type="enabled"/"disabled" body param (Kimi K2, GLM).
110
+ * Disambiguation: GLM also sets supportsToolStream; Kimi does not. */
111
+ supportsThinkingParam?: boolean;
112
+ /** GLM-only: supports tool_stream=true for incremental tool call streaming */
113
+ supportsToolStream?: boolean;
114
+ /** DeepSeek only maps to "high"|"max"; low/medium→high */
115
+ maxReasoningEffort?: "high" | "max";
116
+ /** Supports prefix completion via /beta endpoint (DeepSeek Beta) */
117
+ supportsPrefixCompletion?: boolean;
118
+ /** MiniMax OpenAI route: inject reasoning_split=true to split thinking into reasoning_details.
119
+ * Streaming uses cumulative string updates (not incremental deltas). */
120
+ supportsReasoningSplit?: boolean;
121
+ }
15
122
  export interface ProviderDef {
16
123
  /** Unique provider id, e.g. "deepseek", "openai", "anthropic" */
17
124
  id: string;
@@ -21,6 +128,12 @@ export interface ProviderDef {
21
128
  transport: TransportType;
22
129
  /** API base URL, e.g. "https://api.deepseek.com" */
23
130
  baseUrl: string;
131
+ /**
132
+ * Logical provider group — links protocol variants of the same vendor.
133
+ * e.g. both "zhipu" (anthropic) and "zhipu-openai" share group "zhipu".
134
+ * Defaults to provider id if unset.
135
+ */
136
+ group?: string;
24
137
  /** Env var names for API key (priority order) */
25
138
  apiKeyEnvVars: string[];
26
139
  /** Auth header style */
@@ -37,9 +150,11 @@ export interface ProviderDef {
37
150
  supportsStreamOptions?: boolean;
38
151
  /** Whether to omit temperature when it equals 0 (some providers reject 0) */
39
152
  omitZeroTemperature?: boolean;
153
+ /** Provider-specific quirks for transport-level conditional logic */
154
+ quirks?: ProviderQuirks;
40
155
  }
41
156
  export interface ModelInfo {
42
- /** Model id, e.g. "deepseek-chat" */
157
+ /** Model id, e.g. "deepseek-v4-flash" */
43
158
  id: string;
44
159
  /** Display name, e.g. "DeepSeek Chat V3" */
45
160
  name: string;
@@ -51,6 +166,10 @@ export interface ModelInfo {
51
166
  toolCall: boolean;
52
167
  /** Has reasoning/thinking mode */
53
168
  reasoning: boolean;
169
+ /** Thinking is forced on — cannot be toggled off (e.g. QwQ, DeepSeek-R1) */
170
+ reasoningRequired?: boolean;
171
+ /** Model only supports streaming (non-stream requests will fail) */
172
+ streamRequired?: boolean;
54
173
  /** Supports vision (image input) */
55
174
  vision: boolean;
56
175
  /** Cost per 1M input tokens (USD) */
@@ -63,4 +182,6 @@ export interface ModelInfo {
63
182
  costCacheWrite?: number;
64
183
  /** Media generation capability — undefined means chat/reasoning model */
65
184
  mediaType?: MediaCapability;
185
+ /** Fine-grained media capabilities — operations, formats, limits */
186
+ mediaCapabilities?: MediaCapabilities;
66
187
  }
@@ -41,6 +41,11 @@ export declare class ProviderRegistry {
41
41
  * Merges: Layer 3 override > Layer 1 builtin > Layer 2 catalog enrichment.
42
42
  */
43
43
  listModels(providerId: string): ModelInfo[];
44
+ /**
45
+ * Look up a single model's info by provider + model id.
46
+ * Returns undefined if the model is not found.
47
+ */
48
+ getModelInfo(providerId: string, modelId: string): ModelInfo | undefined;
44
49
  /**
45
50
  * Trigger background refresh of the remote model catalog.
46
51
  */
@@ -0,0 +1,44 @@
1
+ /**
2
+ * ProviderToolAPI — interface for provider-specific utility endpoints
3
+ * that are neither LLM chat nor media generation.
4
+ *
5
+ * Examples: web search, content reader, tokenizer, moderation, realtime voice.
6
+ * Each provider can expose its own set of tool APIs; the agent's tool cascade
7
+ * mechanism (Q1) routes to these when the provider has a native capability.
8
+ */
9
+ export interface WebSearchResult {
10
+ title: string;
11
+ url: string;
12
+ snippet: string;
13
+ /** Full page content if available */
14
+ content?: string;
15
+ }
16
+ export interface ReaderResult {
17
+ title: string;
18
+ content: string;
19
+ url: string;
20
+ }
21
+ export interface TokenizerResult {
22
+ tokenCount: number;
23
+ model: string;
24
+ }
25
+ export interface ModerationResult {
26
+ flagged: boolean;
27
+ categories: Record<string, boolean>;
28
+ scores?: Record<string, number>;
29
+ }
30
+ export interface ProviderToolAPI {
31
+ /** Which tool APIs this provider supports */
32
+ readonly capabilities: readonly ProviderToolCapability[];
33
+ /** Web search — returns search result list */
34
+ webSearch?(query: string, options?: {
35
+ maxResults?: number;
36
+ }): Promise<WebSearchResult[]>;
37
+ /** URL reader — extracts content from a web page */
38
+ reader?(url: string): Promise<ReaderResult>;
39
+ /** Tokenizer — count tokens for given text/model */
40
+ tokenize?(text: string, model: string): Promise<TokenizerResult>;
41
+ /** Content moderation — check text for policy violations */
42
+ moderate?(text: string): Promise<ModerationResult>;
43
+ }
44
+ export type ProviderToolCapability = "web_search" | "reader" | "tokenizer" | "moderations";
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Shared retry/backoff utilities for LLM transport implementations.
3
+ *
4
+ * Provides common constants and helper functions used by all transports
5
+ * (anthropic-messages, openai-chat, volcengine-responses) to handle
6
+ * transient errors with exponential backoff.
7
+ */
8
+ /** Default maximum number of retry attempts */
9
+ export declare const DEFAULT_MAX_RETRIES = 3;
10
+ /** Base delay for exponential backoff (doubles each attempt, capped at 30s) */
11
+ export declare const RETRY_BASE_DELAY_MS = 1000;
12
+ /** Maximum backoff delay */
13
+ export declare const RETRY_MAX_DELAY_MS = 30000;
14
+ /** HTTP status codes considered transient (worth retrying) */
15
+ export declare const TRANSIENT_STATUS_CODES: Set<number>;
16
+ /** Default timeout for idle stream detection (no data received) */
17
+ export declare const STREAM_IDLE_TIMEOUT_MS = 90000;
18
+ /**
19
+ * Calculate the delay for a given retry attempt using exponential backoff with jitter.
20
+ * @param attempt 1-based attempt number (1 = first retry)
21
+ * @returns delay in milliseconds
22
+ */
23
+ export declare function retryDelay(attempt: number): number;
24
+ /**
25
+ * Check if an HTTP status code indicates a transient error worth retrying.
26
+ */
27
+ export declare function isTransientStatus(status: number | null | undefined): boolean;
28
+ /**
29
+ * Sleep with abort signal support. Resolves after `ms` milliseconds
30
+ * or rejects if the signal is aborted.
31
+ */
32
+ export declare function retrySleep(ms: number, signal?: AbortSignal): Promise<void>;
33
+ /**
34
+ * Extract HTTP status from various error shapes.
35
+ * Works with fetch Response errors, Axios errors, and generic errors with status property.
36
+ */
37
+ export declare function extractHttpStatus(error: unknown): number | null;