@stacknet/stacks 0.1.2 → 0.2.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/dist/{billing-BqscteyZ.d.cts → billing-eQZIWeNW.d.cts} +2 -0
- package/dist/{billing-BqscteyZ.d.ts → billing-eQZIWeNW.d.ts} +2 -0
- package/dist/clients/index.cjs +4 -4
- package/dist/clients/index.d.cts +4 -1
- package/dist/clients/index.d.ts +4 -1
- package/dist/clients/index.js +4 -4
- package/dist/{index-DVzKiF_0.d.cts → index-B_dUFmAg.d.cts} +31 -6
- package/dist/{index-DVzKiF_0.d.ts → index-B_dUFmAg.d.ts} +31 -6
- package/dist/index.cjs +12 -16
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +12 -16
- package/dist/proxy/index.cjs +2 -2
- package/dist/proxy/index.d.cts +1 -1
- package/dist/proxy/index.d.ts +1 -1
- package/dist/proxy/index.js +2 -2
- package/dist/streaming/index.cjs +8 -12
- package/dist/streaming/index.js +8 -12
- package/dist/types/index.d.cts +1 -1
- package/dist/types/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/clients/agents.ts +23 -6
- package/src/managers/task-manager.ts +25 -3
- package/src/proxy/forwarder.ts +105 -16
- package/src/proxy/route-handlers.ts +273 -116
- package/src/streaming/sse.ts +65 -40
- package/src/types/agent.ts +2 -0
package/dist/streaming/index.js
CHANGED
|
@@ -1,13 +1,9 @@
|
|
|
1
|
-
var m={"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"};async function*
|
|
2
|
-
`);
|
|
3
|
-
`),a.id&&(
|
|
4
|
-
`),a.retry&&(
|
|
5
|
-
`);let
|
|
1
|
+
var m={"Content-Type":"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive"};var S=1024*1024;function f(a){return a.replace(/[\r\n\u2028\u2029]/g," ")}async function*y(a){if(!a.body)throw new Error("Response body is null");let t=a.body.getReader(),n=new TextDecoder,r="",e={};try{for(;;){let{done:o,value:i}=await t.read();if(o)break;if(r+=n.decode(i,{stream:!0}),r.length>S)throw new Error(`SSE buffer exceeded ${S} bytes without an event delimiter`);let s=r.split(`
|
|
2
|
+
`);r=s.pop()||"";for(let c of s){if(c===""){e.data!==void 0&&(yield e),e={};continue}if(c.startsWith(":"))continue;let p=c.indexOf(":");if(p===-1)continue;let g=c.slice(0,p),l=c.slice(p+1).trimStart();switch(g){case "event":e.event=l;break;case "data":try{e.data=JSON.parse(l);}catch{e.data=l;}break;case "id":e.id=l;break;case "retry":e.retry=parseInt(l,10);break}}}e.data!==void 0&&(yield e);}finally{t.releaseLock();}}function h(a){let t="";a.event&&(t+=`event: ${f(a.event)}
|
|
3
|
+
`),a.id&&(t+=`id: ${f(a.id)}
|
|
4
|
+
`),a.retry!==void 0&&Number.isFinite(a.retry)&&(t+=`retry: ${Math.floor(a.retry)}
|
|
5
|
+
`);let n=typeof a.data=="string"?a.data:JSON.stringify(a.data);for(let r of n.split(/\r?\n/))t+=`data: ${r}
|
|
6
|
+
`;return t+=`
|
|
7
|
+
`,t}function E(a,t){let n=new TextEncoder,r=new ReadableStream({async start(e){try{for await(let o of a)e.enqueue(n.encode(h(o)));}catch(o){console.error("SSE stream error:",o);}finally{e.close();}}});return new Response(r,{headers:{...m,...t}})}var d=class{encoder=new TextEncoder;controller=null;stream;constructor(){this.stream=new ReadableStream({start:t=>{this.controller=t;}});}getStream(){return this.stream}getResponse(t){return new Response(this.stream,{headers:{...m,...t}})}write(t){this.controller&&this.controller.enqueue(this.encoder.encode(h(t)));}writeData(t){this.write({data:t});}writeComment(t){if(!this.controller)return;let n=f(t);this.controller.enqueue(this.encoder.encode(`: ${n}
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
`),t.id&&(r+=`id: ${t.id}
|
|
9
|
-
`);let n=typeof t.data=="string"?t.data:JSON.stringify(t.data);r+=`data: ${n}
|
|
10
|
-
|
|
11
|
-
`,this.controller.enqueue(this.encoder.encode(r));}writeData(t){this.write({data:t});}writeComment(t){this.controller&&this.controller.enqueue(this.encoder.encode(`: ${t}
|
|
12
|
-
|
|
13
|
-
`));}close(){this.controller&&(this.controller.close(),this.controller=null);}error(t){this.controller&&(this.controller.error(t),this.controller=null);}};function g(){return new d}var p=class{constructor(t){this.dataStream=t;}processToolCalls(t){if(!(!t||t.length===0))for(let r of t)try{let n=JSON.parse(r.function.arguments),e=r.function.name;switch(e){case "create_document":this.handleCreateDocument(n,r.id);break;case "update_document":this.handleUpdateDocument(n,r.id);break;default:console.log(`[ComponentStream] Unknown tool: ${e}`);}}catch(n){console.error("[ComponentStream] Error processing tool call:",n);}}processToolResult(t){try{t.type==="artifact"?this.handleArtifactResult(t):t.type==="artifact_update"&&this.handleArtifactUpdate(t);}catch(r){console.error("[ComponentStream] Error processing tool result:",r);}}streamArtifact(t){this.dataStream.write({type:"data-kind",data:t.kind,transient:true}),this.dataStream.write({type:"data-id",data:t.id,transient:true}),this.dataStream.write({type:"data-title",data:t.title,transient:true}),this.dataStream.write({type:"data-clear",data:null,transient:true}),this.streamContent(t.content),this.dataStream.write({type:"data-finish",data:null,transient:true});}streamTextDelta(t){this.dataStream.write({type:"data-textDelta",data:t,transient:true});}streamContent(t,r=50){let n=this.splitIntoChunks(t,r);for(let e of n)this.dataStream.write({type:"data-textDelta",data:e,transient:true});}finish(){this.dataStream.write({type:"data-finish",data:null,transient:true});}handleCreateDocument(t,r){let{title:n,kind:e,content:a}=t,o=`doc_${Date.now()}_${Math.random().toString(36).substr(2,9)}`;console.log(`[ComponentStream] Creating document: ${n} (${e})`),this.streamArtifact({id:o,kind:e,title:n,content:a}),this.dataStream.write({type:"tool-result",data:{toolCallId:r,toolName:"create_document",result:{id:o,title:n,kind:e,message:"Document created successfully"}}});}handleUpdateDocument(t,r){let{id:n,description:e,content:a}=t;console.log(`[ComponentStream] Updating document: ${n}`),this.dataStream.write({type:"data-clear",data:null,transient:true}),this.streamContent(a),this.dataStream.write({type:"data-finish",data:null,transient:true}),this.dataStream.write({type:"tool-result",data:{toolCallId:r,toolName:"update_document",result:{id:n,message:`Document updated: ${e}`}}});}handleArtifactResult(t){let{id:r,title:n,kind:e,content:a}=t;if(!r||!n||!e||!a){console.error("[ComponentStream] Invalid artifact result:",t);return}this.streamArtifact({id:r,kind:e,title:n,content:a});}handleArtifactUpdate(t){let{content:r}=t;if(!r){console.error("[ComponentStream] Invalid artifact update:",t);return}this.dataStream.write({type:"data-clear",data:null,transient:true}),this.streamContent(r),this.dataStream.write({type:"data-finish",data:null,transient:true});}splitIntoChunks(t,r){let n=[],e=t.split(" "),a="";for(let o=0;o<e.length;o++){let s=o===0?e[o]:" "+e[o];a.length+s.length>r&&a.length>0?(n.push(a),a=s.trim()):a+=s;}return a.length>0&&n.push(a),n}};function y(i){return !!(i?.tool_calls&&Array.isArray(i.tool_calls)&&i.tool_calls.length>0)}function E(i){try{let t=JSON.parse(i);if(t.type&&(t.type==="artifact"||t.type==="artifact_update"))return [t]}catch{}return []}function v(i){return new p(i)}export{p as ComponentStreamAdapter,d as SSEWriter,v as createComponentStreamAdapter,h as createSSEResponse,g as createSSEWriter,E as extractToolResults,y as hasToolCalls,S as parseSSEStream};
|
|
9
|
+
`));}close(){this.controller&&(this.controller.close(),this.controller=null);}error(t){this.controller&&(this.controller.error(t),this.controller=null);}};function w(){return new d}var u=class{constructor(t){this.dataStream=t;}processToolCalls(t){if(!(!t||t.length===0))for(let n of t)try{let r=JSON.parse(n.function.arguments),e=n.function.name;switch(e){case "create_document":this.handleCreateDocument(r,n.id);break;case "update_document":this.handleUpdateDocument(r,n.id);break;default:console.log(`[ComponentStream] Unknown tool: ${e}`);}}catch(r){console.error("[ComponentStream] Error processing tool call:",r);}}processToolResult(t){try{t.type==="artifact"?this.handleArtifactResult(t):t.type==="artifact_update"&&this.handleArtifactUpdate(t);}catch(n){console.error("[ComponentStream] Error processing tool result:",n);}}streamArtifact(t){this.dataStream.write({type:"data-kind",data:t.kind,transient:true}),this.dataStream.write({type:"data-id",data:t.id,transient:true}),this.dataStream.write({type:"data-title",data:t.title,transient:true}),this.dataStream.write({type:"data-clear",data:null,transient:true}),this.streamContent(t.content),this.dataStream.write({type:"data-finish",data:null,transient:true});}streamTextDelta(t){this.dataStream.write({type:"data-textDelta",data:t,transient:true});}streamContent(t,n=50){let r=this.splitIntoChunks(t,n);for(let e of r)this.dataStream.write({type:"data-textDelta",data:e,transient:true});}finish(){this.dataStream.write({type:"data-finish",data:null,transient:true});}handleCreateDocument(t,n){let{title:r,kind:e,content:o}=t,i=`doc_${Date.now()}_${Math.random().toString(36).substr(2,9)}`;console.log(`[ComponentStream] Creating document: ${r} (${e})`),this.streamArtifact({id:i,kind:e,title:r,content:o}),this.dataStream.write({type:"tool-result",data:{toolCallId:n,toolName:"create_document",result:{id:i,title:r,kind:e,message:"Document created successfully"}}});}handleUpdateDocument(t,n){let{id:r,description:e,content:o}=t;console.log(`[ComponentStream] Updating document: ${r}`),this.dataStream.write({type:"data-clear",data:null,transient:true}),this.streamContent(o),this.dataStream.write({type:"data-finish",data:null,transient:true}),this.dataStream.write({type:"tool-result",data:{toolCallId:n,toolName:"update_document",result:{id:r,message:`Document updated: ${e}`}}});}handleArtifactResult(t){let{id:n,title:r,kind:e,content:o}=t;if(!n||!r||!e||!o){console.error("[ComponentStream] Invalid artifact result:",t);return}this.streamArtifact({id:n,kind:e,title:r,content:o});}handleArtifactUpdate(t){let{content:n}=t;if(!n){console.error("[ComponentStream] Invalid artifact update:",t);return}this.dataStream.write({type:"data-clear",data:null,transient:true}),this.streamContent(n),this.dataStream.write({type:"data-finish",data:null,transient:true});}splitIntoChunks(t,n){let r=[],e=t.split(" "),o="";for(let i=0;i<e.length;i++){let s=i===0?e[i]:" "+e[i];o.length+s.length>n&&o.length>0?(r.push(o),o=s.trim()):o+=s;}return o.length>0&&r.push(o),r}};function R(a){return !!(a?.tool_calls&&Array.isArray(a.tool_calls)&&a.tool_calls.length>0)}function A(a){try{let t=JSON.parse(a);if(t.type&&(t.type==="artifact"||t.type==="artifact_update"))return [t]}catch{}return []}function v(a){return new u(a)}export{u as ComponentStreamAdapter,d as SSEWriter,v as createComponentStreamAdapter,E as createSSEResponse,w as createSSEWriter,A as extractToolResults,R as hasToolCalls,y as parseSSEStream};
|
package/dist/types/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as ALL_CAPABILITIES_BITMASK, c as ActionProof, d as AddPointsInput, e as Agent, f as AgentCreateInput, g as AgentExecuteRequest, h as AgentExecuteResponse, i as AgentFromPromptInput, j as AgentResponse, k as AgentTrigger, l as AgentUpdateInput, m as AgentWorkflow, n as AgentWorkflowEdge, o as AgentWorkflowNode, p as AgentsClientConfig, q as AgentsListResponse, r as AllowlistConfig, s as AllowlistMode, t as AllowlistUpdateInput, u as AuthMetrics, B as BillingClientConfig, v as BillingPlan, w as BillingPlansResponse, x as BillingPortalResponse, y as BillingState, z as BillingTier, C as CAPABILITY_BITS, D as CapabilityKey, E as ChatCompletionChunk, F as ChatCompletionRequest, G as ChatCompletionResponse, H as CommentResponse, I as CommentsResponse, J as ConfigureOAuthInput, K as ConfigureStripeInput, L as ConfigureWeb3Input, M as ConsensusStateSummary, N as ConsensusStatus, O as ContextDomain, P as ContextResponse, Q as ContextsListResponse, R as CreateCheckoutSessionResponse, S as CreateContextInput, U as CreateDelegationInput, V as CreateDomainInput, W as CreateKeyResponse, X as CreatePostInput, Y as CreatePostResponse, Z as CreateStackRequest, _ as Delegation, $ as DelegationChainLink, a0 as DelegationFilters, a1 as DelegationResponse, a2 as DelegationScope, a3 as DelegationsListResponse, a4 as DomainResponse, a5 as DomainsListResponse, a6 as FeedResponse, a7 as FileUploadResponse, a8 as FilesClientConfig, a9 as HistoryFilters, aa as HistoryResponse, ab as ImaginationCharacter, ac as ImaginationMetadata, ad as ImaginationSource, ae as InitNetworkResponse, af as LeaderStatus, ag as LikeCheckResponse, ah as LikeResponse, ai as MCPContent, aj as MCPMessage, ak as MCPSession, al as MCPSessionConfig, am as MCPToolResult, an as MPCNode, ao as MagmaFile, ap as MediaType, aq as Message, ar as MeteredUsage, as as ModelLayerInfo, at as ModelLayersResponse, au as NetworkClientConfig, av as NetworkStatus, br as Orientation, aw as PaginationMeta, bs as PaymentMethod, ax as PaymentRequiredResponse, ay as PointBalance, az as PointContext, aA as PointRecord, aB as PointRecordResponse, aC as PointSpend, aD as PointSpendResponse, aE as PointsClientConfig, aF as PostResponse, aG as ProfileResponse, aH as RemixesResponse, aI as Skill, aJ as SkillCreateInput, bp as SkillMapPromptResponse, bo as SkillMapResponse, aK as SkillResponse, bq as SkillSummaryResponse, aL as SkillUpdateInput, bn as SkillVerifyResponse, aM as SkillsClientConfig, aN as SkillsListResponse, aO as SocialAuthor, aP as SocialClientConfig, aQ as SocialComment, aR as SocialPost, aS as SocialRemix, bt as SolPrepaidResult, bu as SolSubscriptionResult, aT as SpendDestination, aU as SpendPointsInput, aV as StackCapabilities, aW as StackConfig, aX as StackKeyInfo, aY as StackKeysListResponse, aZ as StackListResponse, a_ as StackManagementClientConfig, a$ as StackMember, b0 as StackMemberStats, b1 as StackModelAlias, b2 as StackOAuthProvider, b3 as StackResponse, b4 as StackStripeProvider, b5 as StackWeb3Provider, b6 as TaskPayload, b7 as TaskResponse, a as TaskState, b as TaskStatus, T as TaskType, bv as TopupResult, b8 as UsageRecord, b9 as UserClientConfig, ba as UserProfile, bb as UserProfileResponse, bc as UserProfileUpdateInput, bd as Widget, be as WidgetCreateInput, bf as WidgetResponse, bg as WidgetSystemPromptResponse, bh as WidgetUpdateInput, bi as WidgetsClientConfig, bj as WidgetsListResponse, bk as WorkflowData, bl as bitmaskToCapabilities, bm as capabilitiesToBitmask } from '../billing-
|
|
1
|
+
export { A as ALL_CAPABILITIES_BITMASK, c as ActionProof, d as AddPointsInput, e as Agent, f as AgentCreateInput, g as AgentExecuteRequest, h as AgentExecuteResponse, i as AgentFromPromptInput, j as AgentResponse, k as AgentTrigger, l as AgentUpdateInput, m as AgentWorkflow, n as AgentWorkflowEdge, o as AgentWorkflowNode, p as AgentsClientConfig, q as AgentsListResponse, r as AllowlistConfig, s as AllowlistMode, t as AllowlistUpdateInput, u as AuthMetrics, B as BillingClientConfig, v as BillingPlan, w as BillingPlansResponse, x as BillingPortalResponse, y as BillingState, z as BillingTier, C as CAPABILITY_BITS, D as CapabilityKey, E as ChatCompletionChunk, F as ChatCompletionRequest, G as ChatCompletionResponse, H as CommentResponse, I as CommentsResponse, J as ConfigureOAuthInput, K as ConfigureStripeInput, L as ConfigureWeb3Input, M as ConsensusStateSummary, N as ConsensusStatus, O as ContextDomain, P as ContextResponse, Q as ContextsListResponse, R as CreateCheckoutSessionResponse, S as CreateContextInput, U as CreateDelegationInput, V as CreateDomainInput, W as CreateKeyResponse, X as CreatePostInput, Y as CreatePostResponse, Z as CreateStackRequest, _ as Delegation, $ as DelegationChainLink, a0 as DelegationFilters, a1 as DelegationResponse, a2 as DelegationScope, a3 as DelegationsListResponse, a4 as DomainResponse, a5 as DomainsListResponse, a6 as FeedResponse, a7 as FileUploadResponse, a8 as FilesClientConfig, a9 as HistoryFilters, aa as HistoryResponse, ab as ImaginationCharacter, ac as ImaginationMetadata, ad as ImaginationSource, ae as InitNetworkResponse, af as LeaderStatus, ag as LikeCheckResponse, ah as LikeResponse, ai as MCPContent, aj as MCPMessage, ak as MCPSession, al as MCPSessionConfig, am as MCPToolResult, an as MPCNode, ao as MagmaFile, ap as MediaType, aq as Message, ar as MeteredUsage, as as ModelLayerInfo, at as ModelLayersResponse, au as NetworkClientConfig, av as NetworkStatus, br as Orientation, aw as PaginationMeta, bs as PaymentMethod, ax as PaymentRequiredResponse, ay as PointBalance, az as PointContext, aA as PointRecord, aB as PointRecordResponse, aC as PointSpend, aD as PointSpendResponse, aE as PointsClientConfig, aF as PostResponse, aG as ProfileResponse, aH as RemixesResponse, aI as Skill, aJ as SkillCreateInput, bp as SkillMapPromptResponse, bo as SkillMapResponse, aK as SkillResponse, bq as SkillSummaryResponse, aL as SkillUpdateInput, bn as SkillVerifyResponse, aM as SkillsClientConfig, aN as SkillsListResponse, aO as SocialAuthor, aP as SocialClientConfig, aQ as SocialComment, aR as SocialPost, aS as SocialRemix, bt as SolPrepaidResult, bu as SolSubscriptionResult, aT as SpendDestination, aU as SpendPointsInput, aV as StackCapabilities, aW as StackConfig, aX as StackKeyInfo, aY as StackKeysListResponse, aZ as StackListResponse, a_ as StackManagementClientConfig, a$ as StackMember, b0 as StackMemberStats, b1 as StackModelAlias, b2 as StackOAuthProvider, b3 as StackResponse, b4 as StackStripeProvider, b5 as StackWeb3Provider, b6 as TaskPayload, b7 as TaskResponse, a as TaskState, b as TaskStatus, T as TaskType, bv as TopupResult, b8 as UsageRecord, b9 as UserClientConfig, ba as UserProfile, bb as UserProfileResponse, bc as UserProfileUpdateInput, bd as Widget, be as WidgetCreateInput, bf as WidgetResponse, bg as WidgetSystemPromptResponse, bh as WidgetUpdateInput, bi as WidgetsClientConfig, bj as WidgetsListResponse, bk as WorkflowData, bl as bitmaskToCapabilities, bm as capabilitiesToBitmask } from '../billing-eQZIWeNW.cjs';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Coder type definitions
|
package/dist/types/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { A as ALL_CAPABILITIES_BITMASK, c as ActionProof, d as AddPointsInput, e as Agent, f as AgentCreateInput, g as AgentExecuteRequest, h as AgentExecuteResponse, i as AgentFromPromptInput, j as AgentResponse, k as AgentTrigger, l as AgentUpdateInput, m as AgentWorkflow, n as AgentWorkflowEdge, o as AgentWorkflowNode, p as AgentsClientConfig, q as AgentsListResponse, r as AllowlistConfig, s as AllowlistMode, t as AllowlistUpdateInput, u as AuthMetrics, B as BillingClientConfig, v as BillingPlan, w as BillingPlansResponse, x as BillingPortalResponse, y as BillingState, z as BillingTier, C as CAPABILITY_BITS, D as CapabilityKey, E as ChatCompletionChunk, F as ChatCompletionRequest, G as ChatCompletionResponse, H as CommentResponse, I as CommentsResponse, J as ConfigureOAuthInput, K as ConfigureStripeInput, L as ConfigureWeb3Input, M as ConsensusStateSummary, N as ConsensusStatus, O as ContextDomain, P as ContextResponse, Q as ContextsListResponse, R as CreateCheckoutSessionResponse, S as CreateContextInput, U as CreateDelegationInput, V as CreateDomainInput, W as CreateKeyResponse, X as CreatePostInput, Y as CreatePostResponse, Z as CreateStackRequest, _ as Delegation, $ as DelegationChainLink, a0 as DelegationFilters, a1 as DelegationResponse, a2 as DelegationScope, a3 as DelegationsListResponse, a4 as DomainResponse, a5 as DomainsListResponse, a6 as FeedResponse, a7 as FileUploadResponse, a8 as FilesClientConfig, a9 as HistoryFilters, aa as HistoryResponse, ab as ImaginationCharacter, ac as ImaginationMetadata, ad as ImaginationSource, ae as InitNetworkResponse, af as LeaderStatus, ag as LikeCheckResponse, ah as LikeResponse, ai as MCPContent, aj as MCPMessage, ak as MCPSession, al as MCPSessionConfig, am as MCPToolResult, an as MPCNode, ao as MagmaFile, ap as MediaType, aq as Message, ar as MeteredUsage, as as ModelLayerInfo, at as ModelLayersResponse, au as NetworkClientConfig, av as NetworkStatus, br as Orientation, aw as PaginationMeta, bs as PaymentMethod, ax as PaymentRequiredResponse, ay as PointBalance, az as PointContext, aA as PointRecord, aB as PointRecordResponse, aC as PointSpend, aD as PointSpendResponse, aE as PointsClientConfig, aF as PostResponse, aG as ProfileResponse, aH as RemixesResponse, aI as Skill, aJ as SkillCreateInput, bp as SkillMapPromptResponse, bo as SkillMapResponse, aK as SkillResponse, bq as SkillSummaryResponse, aL as SkillUpdateInput, bn as SkillVerifyResponse, aM as SkillsClientConfig, aN as SkillsListResponse, aO as SocialAuthor, aP as SocialClientConfig, aQ as SocialComment, aR as SocialPost, aS as SocialRemix, bt as SolPrepaidResult, bu as SolSubscriptionResult, aT as SpendDestination, aU as SpendPointsInput, aV as StackCapabilities, aW as StackConfig, aX as StackKeyInfo, aY as StackKeysListResponse, aZ as StackListResponse, a_ as StackManagementClientConfig, a$ as StackMember, b0 as StackMemberStats, b1 as StackModelAlias, b2 as StackOAuthProvider, b3 as StackResponse, b4 as StackStripeProvider, b5 as StackWeb3Provider, b6 as TaskPayload, b7 as TaskResponse, a as TaskState, b as TaskStatus, T as TaskType, bv as TopupResult, b8 as UsageRecord, b9 as UserClientConfig, ba as UserProfile, bb as UserProfileResponse, bc as UserProfileUpdateInput, bd as Widget, be as WidgetCreateInput, bf as WidgetResponse, bg as WidgetSystemPromptResponse, bh as WidgetUpdateInput, bi as WidgetsClientConfig, bj as WidgetsListResponse, bk as WorkflowData, bl as bitmaskToCapabilities, bm as capabilitiesToBitmask } from '../billing-
|
|
1
|
+
export { A as ALL_CAPABILITIES_BITMASK, c as ActionProof, d as AddPointsInput, e as Agent, f as AgentCreateInput, g as AgentExecuteRequest, h as AgentExecuteResponse, i as AgentFromPromptInput, j as AgentResponse, k as AgentTrigger, l as AgentUpdateInput, m as AgentWorkflow, n as AgentWorkflowEdge, o as AgentWorkflowNode, p as AgentsClientConfig, q as AgentsListResponse, r as AllowlistConfig, s as AllowlistMode, t as AllowlistUpdateInput, u as AuthMetrics, B as BillingClientConfig, v as BillingPlan, w as BillingPlansResponse, x as BillingPortalResponse, y as BillingState, z as BillingTier, C as CAPABILITY_BITS, D as CapabilityKey, E as ChatCompletionChunk, F as ChatCompletionRequest, G as ChatCompletionResponse, H as CommentResponse, I as CommentsResponse, J as ConfigureOAuthInput, K as ConfigureStripeInput, L as ConfigureWeb3Input, M as ConsensusStateSummary, N as ConsensusStatus, O as ContextDomain, P as ContextResponse, Q as ContextsListResponse, R as CreateCheckoutSessionResponse, S as CreateContextInput, U as CreateDelegationInput, V as CreateDomainInput, W as CreateKeyResponse, X as CreatePostInput, Y as CreatePostResponse, Z as CreateStackRequest, _ as Delegation, $ as DelegationChainLink, a0 as DelegationFilters, a1 as DelegationResponse, a2 as DelegationScope, a3 as DelegationsListResponse, a4 as DomainResponse, a5 as DomainsListResponse, a6 as FeedResponse, a7 as FileUploadResponse, a8 as FilesClientConfig, a9 as HistoryFilters, aa as HistoryResponse, ab as ImaginationCharacter, ac as ImaginationMetadata, ad as ImaginationSource, ae as InitNetworkResponse, af as LeaderStatus, ag as LikeCheckResponse, ah as LikeResponse, ai as MCPContent, aj as MCPMessage, ak as MCPSession, al as MCPSessionConfig, am as MCPToolResult, an as MPCNode, ao as MagmaFile, ap as MediaType, aq as Message, ar as MeteredUsage, as as ModelLayerInfo, at as ModelLayersResponse, au as NetworkClientConfig, av as NetworkStatus, br as Orientation, aw as PaginationMeta, bs as PaymentMethod, ax as PaymentRequiredResponse, ay as PointBalance, az as PointContext, aA as PointRecord, aB as PointRecordResponse, aC as PointSpend, aD as PointSpendResponse, aE as PointsClientConfig, aF as PostResponse, aG as ProfileResponse, aH as RemixesResponse, aI as Skill, aJ as SkillCreateInput, bp as SkillMapPromptResponse, bo as SkillMapResponse, aK as SkillResponse, bq as SkillSummaryResponse, aL as SkillUpdateInput, bn as SkillVerifyResponse, aM as SkillsClientConfig, aN as SkillsListResponse, aO as SocialAuthor, aP as SocialClientConfig, aQ as SocialComment, aR as SocialPost, aS as SocialRemix, bt as SolPrepaidResult, bu as SolSubscriptionResult, aT as SpendDestination, aU as SpendPointsInput, aV as StackCapabilities, aW as StackConfig, aX as StackKeyInfo, aY as StackKeysListResponse, aZ as StackListResponse, a_ as StackManagementClientConfig, a$ as StackMember, b0 as StackMemberStats, b1 as StackModelAlias, b2 as StackOAuthProvider, b3 as StackResponse, b4 as StackStripeProvider, b5 as StackWeb3Provider, b6 as TaskPayload, b7 as TaskResponse, a as TaskState, b as TaskStatus, T as TaskType, bv as TopupResult, b8 as UsageRecord, b9 as UserClientConfig, ba as UserProfile, bb as UserProfileResponse, bc as UserProfileUpdateInput, bd as Widget, be as WidgetCreateInput, bf as WidgetResponse, bg as WidgetSystemPromptResponse, bh as WidgetUpdateInput, bi as WidgetsClientConfig, bj as WidgetsListResponse, bk as WorkflowData, bl as bitmaskToCapabilities, bm as capabilitiesToBitmask } from '../billing-eQZIWeNW.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Coder type definitions
|
package/package.json
CHANGED
package/src/clients/agents.ts
CHANGED
|
@@ -22,11 +22,25 @@ export type { AgentsClientConfig } from '../types/agent';
|
|
|
22
22
|
export class AgentsClient {
|
|
23
23
|
private baseUrl: string;
|
|
24
24
|
private useCpxApi: boolean;
|
|
25
|
+
private authToken: string | null;
|
|
25
26
|
|
|
26
27
|
constructor(config: AgentsClientConfig = {}) {
|
|
27
28
|
this.baseUrl = config.baseUrl || DEFAULT_TASK_NETWORK_URL;
|
|
28
29
|
// Use coprocessor API by default (can be disabled for backwards compatibility)
|
|
29
30
|
this.useCpxApi = config.useCpxApi !== false;
|
|
31
|
+
this.authToken = config.authToken || null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
setAuthToken(token: string | null) {
|
|
35
|
+
this.authToken = token;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private get headers(): Record<string, string> {
|
|
39
|
+
const h: Record<string, string> = { ...JSON_HEADERS };
|
|
40
|
+
if (this.authToken) {
|
|
41
|
+
h['Authorization'] = `Bearer ${this.authToken}`;
|
|
42
|
+
}
|
|
43
|
+
return h;
|
|
30
44
|
}
|
|
31
45
|
|
|
32
46
|
private get agentsUrl(): string {
|
|
@@ -48,7 +62,7 @@ export class AgentsClient {
|
|
|
48
62
|
const queryString = params.toString();
|
|
49
63
|
const url = `${this.agentsUrl}${queryString ? `?${queryString}` : ''}`;
|
|
50
64
|
|
|
51
|
-
const response = await fetch(url);
|
|
65
|
+
const response = await fetch(url, { headers: this.headers });
|
|
52
66
|
|
|
53
67
|
if (!response.ok) {
|
|
54
68
|
throw new StacksSDKError(
|
|
@@ -64,7 +78,7 @@ export class AgentsClient {
|
|
|
64
78
|
* Get an agent by ID
|
|
65
79
|
*/
|
|
66
80
|
async get(id: string): Promise<Agent> {
|
|
67
|
-
const response = await fetch(`${this.agentsUrl}/${id}
|
|
81
|
+
const response = await fetch(`${this.agentsUrl}/${id}`, { headers: this.headers });
|
|
68
82
|
|
|
69
83
|
if (!response.ok) {
|
|
70
84
|
throw new StacksSDKError(
|
|
@@ -82,7 +96,7 @@ export class AgentsClient {
|
|
|
82
96
|
async create(input: AgentCreateInput): Promise<AgentResponse> {
|
|
83
97
|
const response = await fetch(this.agentsUrl, {
|
|
84
98
|
method: 'POST',
|
|
85
|
-
headers:
|
|
99
|
+
headers: this.headers,
|
|
86
100
|
body: JSON.stringify(input),
|
|
87
101
|
});
|
|
88
102
|
|
|
@@ -103,7 +117,7 @@ export class AgentsClient {
|
|
|
103
117
|
async update(id: string, input: AgentUpdateInput): Promise<AgentResponse> {
|
|
104
118
|
const response = await fetch(`${this.agentsUrl}/${id}`, {
|
|
105
119
|
method: 'PUT',
|
|
106
|
-
headers:
|
|
120
|
+
headers: this.headers,
|
|
107
121
|
body: JSON.stringify(input),
|
|
108
122
|
});
|
|
109
123
|
|
|
@@ -124,6 +138,7 @@ export class AgentsClient {
|
|
|
124
138
|
async delete(id: string): Promise<{ success: boolean }> {
|
|
125
139
|
const response = await fetch(`${this.agentsUrl}/${id}`, {
|
|
126
140
|
method: 'DELETE',
|
|
141
|
+
headers: this.headers,
|
|
127
142
|
});
|
|
128
143
|
|
|
129
144
|
if (!response.ok) {
|
|
@@ -142,6 +157,7 @@ export class AgentsClient {
|
|
|
142
157
|
async enable(id: string): Promise<AgentResponse> {
|
|
143
158
|
const response = await fetch(`${this.agentsUrl}/${id}/enable`, {
|
|
144
159
|
method: 'POST',
|
|
160
|
+
headers: this.headers,
|
|
145
161
|
});
|
|
146
162
|
|
|
147
163
|
if (!response.ok) {
|
|
@@ -160,6 +176,7 @@ export class AgentsClient {
|
|
|
160
176
|
async disable(id: string): Promise<AgentResponse> {
|
|
161
177
|
const response = await fetch(`${this.agentsUrl}/${id}/disable`, {
|
|
162
178
|
method: 'POST',
|
|
179
|
+
headers: this.headers,
|
|
163
180
|
});
|
|
164
181
|
|
|
165
182
|
if (!response.ok) {
|
|
@@ -178,7 +195,7 @@ export class AgentsClient {
|
|
|
178
195
|
async execute(id: string, request: AgentExecuteRequest = {}): Promise<AgentExecuteResponse> {
|
|
179
196
|
const response = await fetch(`${this.agentsUrl}/${id}/execute`, {
|
|
180
197
|
method: 'POST',
|
|
181
|
-
headers:
|
|
198
|
+
headers: this.headers,
|
|
182
199
|
body: JSON.stringify(request),
|
|
183
200
|
});
|
|
184
201
|
|
|
@@ -199,7 +216,7 @@ export class AgentsClient {
|
|
|
199
216
|
// First, generate agent config from prompt
|
|
200
217
|
const generateResponse = await fetch(`${this.agentsUrl}/from-prompt`, {
|
|
201
218
|
method: 'POST',
|
|
202
|
-
headers:
|
|
219
|
+
headers: this.headers,
|
|
203
220
|
body: JSON.stringify(input),
|
|
204
221
|
});
|
|
205
222
|
|
|
@@ -256,12 +256,34 @@ export class TaskManager {
|
|
|
256
256
|
const channel = `task:progress:${taskId}`;
|
|
257
257
|
|
|
258
258
|
await redis.subscribe(channel, (message) => {
|
|
259
|
+
let data: unknown;
|
|
259
260
|
try {
|
|
260
|
-
|
|
261
|
-
callback(data);
|
|
261
|
+
data = JSON.parse(message);
|
|
262
262
|
} catch {
|
|
263
|
-
//
|
|
263
|
+
return; // not JSON — ignore
|
|
264
264
|
}
|
|
265
|
+
// Shape-check: Redis pub/sub is a trust boundary. If anything else
|
|
266
|
+
// (a compromised publisher, a misconfigured tenant, or an operator
|
|
267
|
+
// pushing test data) posts to this channel, the message reaches
|
|
268
|
+
// this callback. Drop anything that doesn't match our own
|
|
269
|
+
// publisher's shape before handing it to consumer code — otherwise
|
|
270
|
+
// an attacker with publish access could inject arbitrary objects
|
|
271
|
+
// (prototype keys, unexpected fields) into the UI layer.
|
|
272
|
+
if (!data || typeof data !== 'object' || Array.isArray(data)) return;
|
|
273
|
+
const d = data as Record<string, unknown>;
|
|
274
|
+
if (typeof d.taskId !== 'string' || d.taskId !== taskId) return;
|
|
275
|
+
if (typeof d.status !== 'string') return;
|
|
276
|
+
if (d.progress !== undefined && typeof d.progress !== 'number') return;
|
|
277
|
+
if (d.message !== undefined && typeof d.message !== 'string') return;
|
|
278
|
+
if (d.error !== undefined && typeof d.error !== 'string') return;
|
|
279
|
+
callback({
|
|
280
|
+
taskId: d.taskId,
|
|
281
|
+
status: d.status as TaskStatus,
|
|
282
|
+
progress: d.progress as number | undefined,
|
|
283
|
+
message: d.message as string | undefined,
|
|
284
|
+
result: d.result,
|
|
285
|
+
error: d.error as string | undefined,
|
|
286
|
+
});
|
|
265
287
|
});
|
|
266
288
|
|
|
267
289
|
return async () => {
|
package/src/proxy/forwarder.ts
CHANGED
|
@@ -7,7 +7,13 @@ import { DEFAULT_TASK_NETWORK_URL } from '../utils/constants';
|
|
|
7
7
|
export interface ForwarderConfig {
|
|
8
8
|
baseUrl?: string;
|
|
9
9
|
defaultHeaders?: Record<string, string>;
|
|
10
|
+
/** Request timeout in milliseconds. Applied via AbortSignal to every
|
|
11
|
+
* outbound fetch. Default: 30_000 (30s). Previously declared but not
|
|
12
|
+
* wired — an upstream hang would leak file descriptors indefinitely. */
|
|
10
13
|
timeout?: number;
|
|
14
|
+
/** Hard cap on inbound JSON body size (bytes) read by `createProxyHandler`.
|
|
15
|
+
* Requests larger than this are rejected with 413. Default: 1 MiB. */
|
|
16
|
+
maxBodyBytes?: number;
|
|
11
17
|
}
|
|
12
18
|
|
|
13
19
|
export interface RequestOptions {
|
|
@@ -18,6 +24,42 @@ export interface RequestOptions {
|
|
|
18
24
|
stream?: boolean;
|
|
19
25
|
}
|
|
20
26
|
|
|
27
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
28
|
+
const DEFAULT_MAX_BODY_BYTES = 1024 * 1024; // 1 MiB
|
|
29
|
+
|
|
30
|
+
/** Headers that are safe to forward from an inbound request to the upstream.
|
|
31
|
+
* `createProxyHandler` previously copied every inbound header — including
|
|
32
|
+
* `cookie`, attacker-set `x-forwarded-for`, and the consumer app's session
|
|
33
|
+
* cookies — to an arbitrary upstream. Only the headers that carry request
|
|
34
|
+
* semantics (auth + content negotiation + a request id for tracing) are
|
|
35
|
+
* preserved now. */
|
|
36
|
+
const FORWARDABLE_REQUEST_HEADERS = new Set([
|
|
37
|
+
'authorization',
|
|
38
|
+
'content-type',
|
|
39
|
+
'accept',
|
|
40
|
+
'accept-language',
|
|
41
|
+
'x-request-id',
|
|
42
|
+
'x-correlation-id',
|
|
43
|
+
'idempotency-key',
|
|
44
|
+
]);
|
|
45
|
+
|
|
46
|
+
/** Build the outbound URL by resolving `path` relative to `baseUrl`. Using
|
|
47
|
+
* the URL constructor here (instead of string concatenation) prevents a
|
|
48
|
+
* path like ".evil.com/x" from producing an unintended host.
|
|
49
|
+
* Throws if the resolved URL escapes the baseUrl origin. */
|
|
50
|
+
function resolveUrl(baseUrl: string, path: string): string {
|
|
51
|
+
// Ensure baseUrl ends with '/' so URL() treats it as a directory root.
|
|
52
|
+
const baseForResolve = baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
|
53
|
+
// Drop leading '/' on path so it doesn't replace the baseUrl pathname.
|
|
54
|
+
const rel = path.startsWith('/') ? path.slice(1) : path;
|
|
55
|
+
const resolved = new URL(rel, baseForResolve);
|
|
56
|
+
const base = new URL(baseForResolve);
|
|
57
|
+
if (resolved.origin !== base.origin) {
|
|
58
|
+
throw new Error(`forwarder: resolved URL ${resolved.origin} escapes baseUrl origin ${base.origin}`);
|
|
59
|
+
}
|
|
60
|
+
return resolved.toString();
|
|
61
|
+
}
|
|
62
|
+
|
|
21
63
|
/**
|
|
22
64
|
* Forward a request to a backend URL
|
|
23
65
|
*/
|
|
@@ -29,19 +71,14 @@ export async function forwardRequest(
|
|
|
29
71
|
const baseUrl = config.baseUrl || DEFAULT_TASK_NETWORK_URL;
|
|
30
72
|
const { method = 'GET', headers = {}, body, searchParams, stream } = options;
|
|
31
73
|
|
|
32
|
-
// Build URL
|
|
33
|
-
|
|
74
|
+
// Build URL safely, then attach search params.
|
|
75
|
+
const urlObj = new URL(resolveUrl(baseUrl, path));
|
|
34
76
|
if (searchParams) {
|
|
35
|
-
const params = new URLSearchParams();
|
|
36
77
|
Object.entries(searchParams).forEach(([key, value]) => {
|
|
37
78
|
if (value !== undefined) {
|
|
38
|
-
|
|
79
|
+
urlObj.searchParams.set(key, value);
|
|
39
80
|
}
|
|
40
81
|
});
|
|
41
|
-
const paramString = params.toString();
|
|
42
|
-
if (paramString) {
|
|
43
|
-
url += `?${paramString}`;
|
|
44
|
-
}
|
|
45
82
|
}
|
|
46
83
|
|
|
47
84
|
const fetchOptions: RequestInit = {
|
|
@@ -50,6 +87,7 @@ export async function forwardRequest(
|
|
|
50
87
|
...config.defaultHeaders,
|
|
51
88
|
...headers,
|
|
52
89
|
},
|
|
90
|
+
signal: AbortSignal.timeout(config.timeout ?? DEFAULT_TIMEOUT_MS),
|
|
53
91
|
};
|
|
54
92
|
|
|
55
93
|
if (body && method !== 'GET') {
|
|
@@ -60,7 +98,7 @@ export async function forwardRequest(
|
|
|
60
98
|
fetchOptions.body = JSON.stringify(body);
|
|
61
99
|
}
|
|
62
100
|
|
|
63
|
-
const response = await fetch(
|
|
101
|
+
const response = await fetch(urlObj.toString(), fetchOptions);
|
|
64
102
|
|
|
65
103
|
// For streaming responses, return directly
|
|
66
104
|
if (stream && response.body) {
|
|
@@ -83,13 +121,59 @@ export async function forwardJSON<T = unknown>(
|
|
|
83
121
|
return { data, status: response.status };
|
|
84
122
|
}
|
|
85
123
|
|
|
124
|
+
/** Read a request body with a hard byte cap. Returns `null` if the body
|
|
125
|
+
* exceeds the cap, so the caller can return 413 without first buffering
|
|
126
|
+
* an attacker-sized payload into memory. */
|
|
127
|
+
async function readBodyCapped(request: Request, maxBytes: number): Promise<unknown | { _tooLarge: true }> {
|
|
128
|
+
const contentLength = request.headers.get('content-length');
|
|
129
|
+
if (contentLength) {
|
|
130
|
+
const n = parseInt(contentLength, 10);
|
|
131
|
+
if (Number.isFinite(n) && n > maxBytes) return { _tooLarge: true };
|
|
132
|
+
}
|
|
133
|
+
if (!request.body) return undefined;
|
|
134
|
+
const reader = request.body.getReader();
|
|
135
|
+
let received = 0;
|
|
136
|
+
const chunks: Uint8Array[] = [];
|
|
137
|
+
// Streaming read with byte cap — aborts as soon as the cap is exceeded.
|
|
138
|
+
// eslint-disable-next-line no-constant-condition
|
|
139
|
+
while (true) {
|
|
140
|
+
const { done, value } = await reader.read();
|
|
141
|
+
if (done) break;
|
|
142
|
+
received += value.byteLength;
|
|
143
|
+
if (received > maxBytes) {
|
|
144
|
+
try { await reader.cancel(); } catch { /* ignore */ }
|
|
145
|
+
return { _tooLarge: true };
|
|
146
|
+
}
|
|
147
|
+
chunks.push(value);
|
|
148
|
+
}
|
|
149
|
+
if (received === 0) return undefined;
|
|
150
|
+
const buf = new Uint8Array(received);
|
|
151
|
+
let offset = 0;
|
|
152
|
+
for (const c of chunks) { buf.set(c, offset); offset += c.byteLength; }
|
|
153
|
+
const text = new TextDecoder().decode(buf);
|
|
154
|
+
if (text.trim() === '') return undefined;
|
|
155
|
+
try {
|
|
156
|
+
return JSON.parse(text);
|
|
157
|
+
} catch {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
86
162
|
/**
|
|
87
|
-
* Create a proxy handler that forwards requests
|
|
163
|
+
* Create a proxy handler that forwards requests.
|
|
164
|
+
*
|
|
165
|
+
* SECURITY: only a small whitelist of inbound headers is forwarded (see
|
|
166
|
+
* FORWARDABLE_REQUEST_HEADERS). Everything else — including `cookie`,
|
|
167
|
+
* `x-forwarded-for`, `host` — is stripped so a caller cannot poison the
|
|
168
|
+
* upstream's view of the request or smuggle the consumer app's cookies to
|
|
169
|
+
* a third-party StackNet endpoint.
|
|
88
170
|
*/
|
|
89
171
|
export function createProxyHandler(
|
|
90
172
|
path: string | ((req: Request) => string),
|
|
91
173
|
config: ForwarderConfig = {}
|
|
92
174
|
) {
|
|
175
|
+
const maxBodyBytes = config.maxBodyBytes ?? DEFAULT_MAX_BODY_BYTES;
|
|
176
|
+
|
|
93
177
|
return async (request: Request): Promise<Response> => {
|
|
94
178
|
const url = new URL(request.url);
|
|
95
179
|
const targetPath = typeof path === 'function' ? path(request) : path;
|
|
@@ -102,17 +186,22 @@ export function createProxyHandler(
|
|
|
102
186
|
|
|
103
187
|
let body: unknown = undefined;
|
|
104
188
|
if (request.method !== 'GET' && request.method !== 'HEAD') {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
189
|
+
const read = await readBodyCapped(request, maxBodyBytes);
|
|
190
|
+
if (read && typeof read === 'object' && (read as { _tooLarge?: boolean })._tooLarge) {
|
|
191
|
+
return Response.json(
|
|
192
|
+
{ error: `Request body exceeds ${maxBodyBytes} bytes` },
|
|
193
|
+
{ status: 413 },
|
|
194
|
+
);
|
|
109
195
|
}
|
|
196
|
+
body = read;
|
|
110
197
|
}
|
|
111
198
|
|
|
112
|
-
//
|
|
199
|
+
// Forward ONLY the whitelisted headers.
|
|
113
200
|
const requestHeaders: Record<string, string> = {};
|
|
114
201
|
request.headers.forEach((value, key) => {
|
|
115
|
-
|
|
202
|
+
if (FORWARDABLE_REQUEST_HEADERS.has(key.toLowerCase())) {
|
|
203
|
+
requestHeaders[key] = value;
|
|
204
|
+
}
|
|
116
205
|
});
|
|
117
206
|
|
|
118
207
|
const response = await forwardRequest(
|