@ag-ui/aws-strands 0.1.0 → 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/server.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as StrandsAgent } from "./agent-Dp45JIaO.mjs";
1
+ import { t as StrandsAgent } from "./agent-DQjKZfcY.mjs";
2
2
  import * as express0 from "express";
3
3
  import { Express } from "express";
4
4
 
@@ -126,7 +126,15 @@ interface CreateStrandsAppOptions {
126
126
  capabilitiesPath?: string | null;
127
127
  /** Override capabilities advertised at {@link CreateStrandsAppOptions.capabilitiesPath}. */
128
128
  capabilities?: StrandsAguiCapabilitiesOverrides;
129
- /** Override CORS origin. Default `*` (wide-open, matches the Python adapter). */
129
+ /**
130
+ * Override CORS origin. Default `"*"` (wide-open, matches the Python adapter,
131
+ * which configures Starlette `CORSMiddleware` with `allow_origins=["*"]`).
132
+ *
133
+ * Note: with the `cors` package, a literal `"*"` is emitted verbatim as
134
+ * `Access-Control-Allow-Origin: *`, whereas `true` would reflect the request's
135
+ * `Origin` header back per-request — a different (more permissive) posture when
136
+ * combined with credentials. Stick to `"*"` to match the Python adapter.
137
+ */
130
138
  corsOrigin?: string | string[] | boolean;
131
139
  }
132
140
  /** Create an Express app with a single Strands agent endpoint and optional ping endpoint. */
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.mts","names":[],"sources":["../src/endpoint.ts","../src/server.ts"],"mappings":";;;;;UAYiB,yBAAA;EACf,IAAA;AAAA;;iBAwDc,yBAAA,CACd,GAAA,EAAK,OAAA,EACL,KAAA,EAAO,YAAA,EACP,OAAA,EAAS,yBAAA;;iBA+IK,OAAA,CAAQ,GAAA,EAAK,OAAA,EAAS,IAAA;AAlJtC;;;;;;;;;;;;AAAA,UAoKiB,uBAAA;EAjKf;EAmKA,QAAA;EAnKkC;EAqKlC,UAAA;IAAc,GAAA;IAAc,QAAA;IAAmB,SAAA;EAAA;EAtBzB;EAwBtB,MAAA;IACE,WAAA;IACA,YAAA;IACA,SAAA;IACA,kBAAA;IACA,oBAAA;IACA,gBAAA;IACA,kBAAA;IACA,eAAA;IACA,cAAA;IACA,aAAA;IACA,gBAAA;IACA,eAAA;IACA,cAAA;IACA,WAAA;IACA,iBAAA;IACA,YAAA;IACA,aAAA;IACA,eAAA;IACA,uBAAA;IACA,yBAAA;IACA,qBAAA;IACA,uBAAA;IACA,yBAAA;IACA,aAAA;IACA,MAAA;IACA,iBAAA;IACA,cAAA;IACA,GAAA;EAAA;EAVA;EAaF,QAAA;IAXE,iEAaA,UAAA,WAXA;IAaA,2BAAA,WAXA;IAaA,gBAAA,WAXA;IAaA,gBAAA,WAXA;IAaA,UAAA,WARA;IAUA,QAAA,WANA;IAQA,qBAAA;EAAA;AAAA;;cAKS,oBAAA,EAAsB,uBAAA;;KA6CvB,gCAAA;EACV,QAAA,GAAW,uBAAA;EACX,UAAA,GAAa,OAAA,CAAQ,uBAAA;EACrB,MAAA,GAAS,OAAA,CAAQ,uBAAA;EACjB,QAAA,GAAW,OAAA,CAAQ,uBAAA;AAAA;;;;;;;iBAyCL,eAAA,CACd,KAAA;EAAS,MAAA;IAAU,eAAA;EAAA;AAAA,GACnB,SAAA,GAAY,gCAAA,GACX,uBAAA;;;;;;;;;;;;iBA8Ba,eAAA,CACd,GAAA,EAAK,OAAA,EACL,IAAA,UACA,YAAA,GACI,gCAAA;EAEE,KAAA;IAAS,MAAA;MAAU,eAAA;IAAA;EAAA;EACnB,SAAA,GAAY,gCAAA;AAAA;;;UCpYH,uBAAA;EDuCV;ECrCL,IAAA;EDuCS;ECrCT,QAAA;EDqCkC;;;;EChClC,gBAAA;EDgCS;EC9BT,YAAA,GAAe,gCAAA;ED8BmB;EC5BlC,UAAA;AAAA;;iBAIoB,gBAAA,CACpB,KAAA,EAAO,YAAA,EACP,OAAA,GAAS,uBAAA,GACR,OAAA,CADoC,QAAA,CACV,OAAA"}
1
+ {"version":3,"file":"server.d.mts","names":[],"sources":["../src/endpoint.ts","../src/server.ts"],"mappings":";;;;;UAYiB,yBAAA;EACf,IAAA;AAAA;;iBAwDc,yBAAA,CACd,GAAA,EAAK,OAAA,EACL,KAAA,EAAO,YAAA,EACP,OAAA,EAAS,yBAAA;;iBA+IK,OAAA,CAAQ,GAAA,EAAK,OAAA,EAAS,IAAA;AAlJtC;;;;;;;;;;;;AAAA,UAoKiB,uBAAA;EAjKf;EAmKA,QAAA;EAnKkC;EAqKlC,UAAA;IAAc,GAAA;IAAc,QAAA;IAAmB,SAAA;EAAA;EAtBzB;EAwBtB,MAAA;IACE,WAAA;IACA,YAAA;IACA,SAAA;IACA,kBAAA;IACA,oBAAA;IACA,gBAAA;IACA,kBAAA;IACA,eAAA;IACA,cAAA;IACA,aAAA;IACA,gBAAA;IACA,eAAA;IACA,cAAA;IACA,WAAA;IACA,iBAAA;IACA,YAAA;IACA,aAAA;IACA,eAAA;IACA,uBAAA;IACA,yBAAA;IACA,qBAAA;IACA,uBAAA;IACA,yBAAA;IACA,aAAA;IACA,MAAA;IACA,iBAAA;IACA,cAAA;IACA,GAAA;EAAA;EAVA;EAaF,QAAA;IAXE,iEAaA,UAAA,WAXA;IAaA,2BAAA,WAXA;IAaA,gBAAA,WAXA;IAaA,gBAAA,WAXA;IAaA,UAAA,WARA;IAUA,QAAA,WANA;IAQA,qBAAA;EAAA;AAAA;;cAKS,oBAAA,EAAsB,uBAAA;;KA6CvB,gCAAA;EACV,QAAA,GAAW,uBAAA;EACX,UAAA,GAAa,OAAA,CAAQ,uBAAA;EACrB,MAAA,GAAS,OAAA,CAAQ,uBAAA;EACjB,QAAA,GAAW,OAAA,CAAQ,uBAAA;AAAA;;;;;;;iBAyCL,eAAA,CACd,KAAA;EAAS,MAAA;IAAU,eAAA;EAAA;AAAA,GACnB,SAAA,GAAY,gCAAA,GACX,uBAAA;;;;;;;;;;;;iBA8Ba,eAAA,CACd,GAAA,EAAK,OAAA,EACL,IAAA,UACA,YAAA,GACI,gCAAA;EAEE,KAAA;IAAS,MAAA;MAAU,eAAA;IAAA;EAAA;EACnB,SAAA,GAAY,gCAAA;AAAA;;;UCpYH,uBAAA;EDuCV;ECrCL,IAAA;EDuCS;ECrCT,QAAA;EDqCkC;;;;EChClC,gBAAA;EDgCS;EC9BT,YAAA,GAAe,gCAAA;ED8BmB;;AA+IpC;;;;;;;ECnKE,UAAA;AAAA;ADqLF;AAAA,iBCjLsB,gBAAA,CACpB,KAAA,EAAO,YAAA,EACP,OAAA,GAAS,uBAAA,GACR,OAAA,CADoC,QAAA,CACV,OAAA"}
package/dist/server.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { t as StrandsAgent } from "./agent-B2EYZvns.js";
1
+ import { t as StrandsAgent } from "./agent-CuzzhGkF.js";
2
2
  import * as express0 from "express";
3
3
  import { Express } from "express";
4
4
 
@@ -126,7 +126,15 @@ interface CreateStrandsAppOptions {
126
126
  capabilitiesPath?: string | null;
127
127
  /** Override capabilities advertised at {@link CreateStrandsAppOptions.capabilitiesPath}. */
128
128
  capabilities?: StrandsAguiCapabilitiesOverrides;
129
- /** Override CORS origin. Default `*` (wide-open, matches the Python adapter). */
129
+ /**
130
+ * Override CORS origin. Default `"*"` (wide-open, matches the Python adapter,
131
+ * which configures Starlette `CORSMiddleware` with `allow_origins=["*"]`).
132
+ *
133
+ * Note: with the `cors` package, a literal `"*"` is emitted verbatim as
134
+ * `Access-Control-Allow-Origin: *`, whereas `true` would reflect the request's
135
+ * `Origin` header back per-request — a different (more permissive) posture when
136
+ * combined with credentials. Stick to `"*"` to match the Python adapter.
137
+ */
130
138
  corsOrigin?: string | string[] | boolean;
131
139
  }
132
140
  /** Create an Express app with a single Strands agent endpoint and optional ping endpoint. */
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","names":[],"sources":["../src/endpoint.ts","../src/server.ts"],"mappings":";;;;;UAYiB,yBAAA;EACf,IAAA;AAAA;;iBAwDc,yBAAA,CACd,GAAA,EAAK,OAAA,EACL,KAAA,EAAO,YAAA,EACP,OAAA,EAAS,yBAAA;;iBA+IK,OAAA,CAAQ,GAAA,EAAK,OAAA,EAAS,IAAA;AAlJtC;;;;;;;;;;;;AAAA,UAoKiB,uBAAA;EAjKf;EAmKA,QAAA;EAnKkC;EAqKlC,UAAA;IAAc,GAAA;IAAc,QAAA;IAAmB,SAAA;EAAA;EAtBzB;EAwBtB,MAAA;IACE,WAAA;IACA,YAAA;IACA,SAAA;IACA,kBAAA;IACA,oBAAA;IACA,gBAAA;IACA,kBAAA;IACA,eAAA;IACA,cAAA;IACA,aAAA;IACA,gBAAA;IACA,eAAA;IACA,cAAA;IACA,WAAA;IACA,iBAAA;IACA,YAAA;IACA,aAAA;IACA,eAAA;IACA,uBAAA;IACA,yBAAA;IACA,qBAAA;IACA,uBAAA;IACA,yBAAA;IACA,aAAA;IACA,MAAA;IACA,iBAAA;IACA,cAAA;IACA,GAAA;EAAA;EAVA;EAaF,QAAA;IAXE,iEAaA,UAAA,WAXA;IAaA,2BAAA,WAXA;IAaA,gBAAA,WAXA;IAaA,gBAAA,WAXA;IAaA,UAAA,WARA;IAUA,QAAA,WANA;IAQA,qBAAA;EAAA;AAAA;;cAKS,oBAAA,EAAsB,uBAAA;;KA6CvB,gCAAA;EACV,QAAA,GAAW,uBAAA;EACX,UAAA,GAAa,OAAA,CAAQ,uBAAA;EACrB,MAAA,GAAS,OAAA,CAAQ,uBAAA;EACjB,QAAA,GAAW,OAAA,CAAQ,uBAAA;AAAA;;;;;;;iBAyCL,eAAA,CACd,KAAA;EAAS,MAAA;IAAU,eAAA;EAAA;AAAA,GACnB,SAAA,GAAY,gCAAA,GACX,uBAAA;;;;;;;;;;;;iBA8Ba,eAAA,CACd,GAAA,EAAK,OAAA,EACL,IAAA,UACA,YAAA,GACI,gCAAA;EAEE,KAAA;IAAS,MAAA;MAAU,eAAA;IAAA;EAAA;EACnB,SAAA,GAAY,gCAAA;AAAA;;;UCpYH,uBAAA;EDuCV;ECrCL,IAAA;EDuCS;ECrCT,QAAA;EDqCkC;;;;EChClC,gBAAA;EDgCS;EC9BT,YAAA,GAAe,gCAAA;ED8BmB;EC5BlC,UAAA;AAAA;;iBAIoB,gBAAA,CACpB,KAAA,EAAO,YAAA,EACP,OAAA,GAAS,uBAAA,GACR,OAAA,CADoC,QAAA,CACV,OAAA"}
1
+ {"version":3,"file":"server.d.ts","names":[],"sources":["../src/endpoint.ts","../src/server.ts"],"mappings":";;;;;UAYiB,yBAAA;EACf,IAAA;AAAA;;iBAwDc,yBAAA,CACd,GAAA,EAAK,OAAA,EACL,KAAA,EAAO,YAAA,EACP,OAAA,EAAS,yBAAA;;iBA+IK,OAAA,CAAQ,GAAA,EAAK,OAAA,EAAS,IAAA;AAlJtC;;;;;;;;;;;;AAAA,UAoKiB,uBAAA;EAjKf;EAmKA,QAAA;EAnKkC;EAqKlC,UAAA;IAAc,GAAA;IAAc,QAAA;IAAmB,SAAA;EAAA;EAtBzB;EAwBtB,MAAA;IACE,WAAA;IACA,YAAA;IACA,SAAA;IACA,kBAAA;IACA,oBAAA;IACA,gBAAA;IACA,kBAAA;IACA,eAAA;IACA,cAAA;IACA,aAAA;IACA,gBAAA;IACA,eAAA;IACA,cAAA;IACA,WAAA;IACA,iBAAA;IACA,YAAA;IACA,aAAA;IACA,eAAA;IACA,uBAAA;IACA,yBAAA;IACA,qBAAA;IACA,uBAAA;IACA,yBAAA;IACA,aAAA;IACA,MAAA;IACA,iBAAA;IACA,cAAA;IACA,GAAA;EAAA;EAVA;EAaF,QAAA;IAXE,iEAaA,UAAA,WAXA;IAaA,2BAAA,WAXA;IAaA,gBAAA,WAXA;IAaA,gBAAA,WAXA;IAaA,UAAA,WARA;IAUA,QAAA,WANA;IAQA,qBAAA;EAAA;AAAA;;cAKS,oBAAA,EAAsB,uBAAA;;KA6CvB,gCAAA;EACV,QAAA,GAAW,uBAAA;EACX,UAAA,GAAa,OAAA,CAAQ,uBAAA;EACrB,MAAA,GAAS,OAAA,CAAQ,uBAAA;EACjB,QAAA,GAAW,OAAA,CAAQ,uBAAA;AAAA;;;;;;;iBAyCL,eAAA,CACd,KAAA;EAAS,MAAA;IAAU,eAAA;EAAA;AAAA,GACnB,SAAA,GAAY,gCAAA,GACX,uBAAA;;;;;;;;;;;;iBA8Ba,eAAA,CACd,GAAA,EAAK,OAAA,EACL,IAAA,UACA,YAAA,GACI,gCAAA;EAEE,KAAA;IAAS,MAAA;MAAU,eAAA;IAAA;EAAA;EACnB,SAAA,GAAY,gCAAA;AAAA;;;UCpYH,uBAAA;EDuCV;ECrCL,IAAA;EDuCS;ECrCT,QAAA;EDqCkC;;;;EChClC,gBAAA;EDgCS;EC9BT,YAAA,GAAe,gCAAA;ED8BmB;;AA+IpC;;;;;;;ECnKE,UAAA;AAAA;ADqLF;AAAA,iBCjLsB,gBAAA,CACpB,KAAA,EAAO,YAAA,EACP,OAAA,GAAS,uBAAA,GACR,OAAA,CADoC,QAAA,CACV,OAAA"}
package/dist/server.js CHANGED
@@ -1,2 +1,2 @@
1
- let e=require(`@ag-ui/core`),t=require(`@ag-ui/encoder`);const n={thread_id:`threadId`,run_id:`runId`,parent_run_id:`parentRunId`,forwarded_props:`forwardedProps`,tool_call_id:`toolCallId`,parent_message_id:`parentMessageId`},r=new Set([`__proto__`,`constructor`,`prototype`]);function i(e){if(typeof e!=`object`||!e)return e;if(Array.isArray(e))return e.map(i);let t=e,a=Object.create(null);for(let[e,o]of Object.entries(t)){if(r.has(e))continue;let t=n[e]??e;t in a||(a[t]=typeof o==`object`&&o?i(o):o)}return a}function a(e){return!!(e.is(`application/json`)||e.is(`+json`))}function o(e){return e?e.split(`,`).map(e=>e.split(`;`)[0]?.trim().toLowerCase()??``).some(e=>e===`application/vnd.ag-ui.event+proto`):!1}function s(n,r,s){n.post(s.path,async(n,s)=>{if(!a(n)){s.status(415).json({error:`Unsupported Media Type: expected application/json`});return}let c=i(n.body),l=e.RunAgentInputSchema.safeParse(c);if(!l.success){s.status(400).json({error:`Invalid RunAgentInput`,issues:l.error.issues.map(e=>({path:e.path,message:e.message}))});return}let u=l.data,d=n.header(`accept`)??void 0,f=o(d)?new t.EventEncoder({accept:d}):new t.EventEncoder({accept:`text/event-stream`}),p=f.getContentType();s.setHeader(`Content-Type`,p),s.setHeader(`Cache-Control`,`no-cache`),s.setHeader(`Connection`,`keep-alive`),s.flushHeaders?.();let m=e=>{if(!(s.destroyed||s.writableEnded))if(p===`text/event-stream`)s.write(f.encode(e));else{let t=f.encodeBinary(e);s.write(Buffer.from(t))}},h=r.run(u),g=!1,_=()=>{g||(g=!0,h.return?.().catch(()=>{}))};s.once(`close`,_),n.once(`aborted`,_);try{for(;!(g||s.writableEnded||s.destroyed);){let t;try{t=await h.next()}catch(t){if(!g&&!s.writableEnded)try{m({type:e.EventType.RUN_ERROR,message:t instanceof Error?t.message:String(t),code:`STRANDS_ERROR`})}catch{}break}if(t.done||g||s.writableEnded||s.destroyed)break;try{m(t.value)}catch(t){let n={type:e.EventType.RUN_ERROR,message:`Encoding error: ${String(t)}`,code:`ENCODING_ERROR`};try{m(n)}catch{}break}}}finally{s.removeListener(`close`,_),n.removeListener(`aborted`,_);try{await h.return?.()}catch{}s.writableEnded||s.end()}})}function c(e,t){e.get(t,(e,t)=>{t.json({status:`healthy`})})}const l={protocol:`1`,transports:{sse:!0,protobuf:!0,websocket:!1},events:{RUN_STARTED:!0,RUN_FINISHED:!0,RUN_ERROR:!0,TEXT_MESSAGE_START:!0,TEXT_MESSAGE_CONTENT:!0,TEXT_MESSAGE_END:!0,TEXT_MESSAGE_CHUNK:!1,TOOL_CALL_START:!0,TOOL_CALL_ARGS:!0,TOOL_CALL_END:!0,TOOL_CALL_RESULT:!0,TOOL_CALL_CHUNK:!1,STATE_SNAPSHOT:!0,STATE_DELTA:!1,MESSAGES_SNAPSHOT:!0,STEP_STARTED:!0,STEP_FINISHED:!0,REASONING_START:!0,REASONING_MESSAGE_START:!0,REASONING_MESSAGE_CONTENT:!0,REASONING_MESSAGE_END:!0,REASONING_MESSAGE_CHUNK:!1,REASONING_ENCRYPTED_VALUE:!0,REASONING_END:!0,CUSTOM:!0,ACTIVITY_SNAPSHOT:!1,ACTIVITY_DELTA:!1,RAW:!1},features:{interrupts:!0,toolCallInterruptEditedArgs:!0,resumableStreams:!1,messagesSnapshot:!0,stateDelta:!1,protobuf:!0,multipleRunsPerStream:!1}};function u(e){if(!e)return structuredClone(l);let t=(e,t)=>{let n={...e};if(!t)return n;for(let r of Object.keys(t))if(r in e){let e=t[r];typeof e==`boolean`&&(n[r]=e)}return n};return{protocol:e.protocol??l.protocol,transports:t(l.transports,e.transports),events:t(l.events,e.events),features:t(l.features,e.features)}}function d(e,t){let n=u(t);return e.config.emitChunkEvents&&(n.events.TEXT_MESSAGE_START=!1,n.events.TEXT_MESSAGE_CONTENT=!1,n.events.TEXT_MESSAGE_END=!1,n.events.TEXT_MESSAGE_CHUNK=!0,n.events.TOOL_CALL_START=!1,n.events.TOOL_CALL_ARGS=!1,n.events.TOOL_CALL_END=!1,n.events.TOOL_CALL_CHUNK=!0,n.events.REASONING_MESSAGE_START=!1,n.events.REASONING_MESSAGE_CONTENT=!1,n.events.REASONING_MESSAGE_END=!1,n.events.REASONING_MESSAGE_CHUNK=!0),n}function f(e,t,n){let r=n&&typeof n==`object`&&`agent`in n?d(n.agent,n.overrides):u(n);e.get(t,(e,t)=>{t.json(r)})}async function p(e,t={}){let{path:n=`/`,pingPath:r=`/ping`,capabilitiesPath:i=`/capabilities`,capabilities:a,corsOrigin:o=!0}=t,l=await import(`express`),u=await import(`cors`),d=l.default??l,p=u.default??u,m=d();return m.use(p({origin:o,credentials:!0})),m.use(d.json({limit:`50mb`})),s(m,e,{path:n}),r&&c(m,r),i&&f(m,i,{agent:e,overrides:a}),m}exports.DEFAULT_CAPABILITIES=l,exports.addCapabilities=f,exports.addPing=c,exports.addStrandsExpressEndpoint=s,exports.capabilitiesFor=d,exports.createStrandsApp=p;
1
+ let e=require(`@ag-ui/core`),t=require(`@ag-ui/encoder`);const n={thread_id:`threadId`,run_id:`runId`,parent_run_id:`parentRunId`,forwarded_props:`forwardedProps`,tool_call_id:`toolCallId`,parent_message_id:`parentMessageId`},r=new Set([`__proto__`,`constructor`,`prototype`]);function i(e){if(typeof e!=`object`||!e)return e;if(Array.isArray(e))return e.map(i);let t=e,a=Object.create(null);for(let[e,o]of Object.entries(t)){if(r.has(e))continue;let t=n[e]??e;t in a||(a[t]=typeof o==`object`&&o?i(o):o)}return a}function a(e){return!!(e.is(`application/json`)||e.is(`+json`))}function o(e){return e?e.split(`,`).map(e=>e.split(`;`)[0]?.trim().toLowerCase()??``).some(e=>e===`application/vnd.ag-ui.event+proto`):!1}function s(n,r,s){n.post(s.path,async(n,s)=>{if(!a(n)){s.status(415).json({error:`Unsupported Media Type: expected application/json`});return}let c=i(n.body),l=e.RunAgentInputSchema.safeParse(c);if(!l.success){s.status(400).json({error:`Invalid RunAgentInput`,issues:l.error.issues.map(e=>({path:e.path,message:e.message}))});return}let u=l.data,d=n.header(`accept`)??void 0,f=o(d)?new t.EventEncoder({accept:d}):new t.EventEncoder({accept:`text/event-stream`}),p=f.getContentType();s.setHeader(`Content-Type`,p),s.setHeader(`Cache-Control`,`no-cache`),s.setHeader(`Connection`,`keep-alive`),s.flushHeaders?.();let m=e=>{if(!(s.destroyed||s.writableEnded))if(p===`text/event-stream`)s.write(f.encode(e));else{let t=f.encodeBinary(e);s.write(Buffer.from(t))}},h=r.run(u),g=!1,_=()=>{g||(g=!0,h.return?.().catch(()=>{}))};s.once(`close`,_),n.once(`aborted`,_);try{for(;!(g||s.writableEnded||s.destroyed);){let t;try{t=await h.next()}catch(t){if(!g&&!s.writableEnded)try{m({type:e.EventType.RUN_ERROR,message:t instanceof Error?t.message:String(t),code:`STRANDS_ERROR`})}catch{}break}if(t.done||g||s.writableEnded||s.destroyed)break;try{m(t.value)}catch(t){let n={type:e.EventType.RUN_ERROR,message:`Encoding error: ${String(t)}`,code:`ENCODING_ERROR`};try{m(n)}catch{}break}}}finally{s.removeListener(`close`,_),n.removeListener(`aborted`,_);try{await h.return?.()}catch{}s.writableEnded||s.end()}})}function c(e,t){e.get(t,(e,t)=>{t.json({status:`healthy`})})}const l={protocol:`1`,transports:{sse:!0,protobuf:!0,websocket:!1},events:{RUN_STARTED:!0,RUN_FINISHED:!0,RUN_ERROR:!0,TEXT_MESSAGE_START:!0,TEXT_MESSAGE_CONTENT:!0,TEXT_MESSAGE_END:!0,TEXT_MESSAGE_CHUNK:!1,TOOL_CALL_START:!0,TOOL_CALL_ARGS:!0,TOOL_CALL_END:!0,TOOL_CALL_RESULT:!0,TOOL_CALL_CHUNK:!1,STATE_SNAPSHOT:!0,STATE_DELTA:!1,MESSAGES_SNAPSHOT:!0,STEP_STARTED:!0,STEP_FINISHED:!0,REASONING_START:!0,REASONING_MESSAGE_START:!0,REASONING_MESSAGE_CONTENT:!0,REASONING_MESSAGE_END:!0,REASONING_MESSAGE_CHUNK:!1,REASONING_ENCRYPTED_VALUE:!0,REASONING_END:!0,CUSTOM:!0,ACTIVITY_SNAPSHOT:!1,ACTIVITY_DELTA:!1,RAW:!1},features:{interrupts:!0,toolCallInterruptEditedArgs:!0,resumableStreams:!1,messagesSnapshot:!0,stateDelta:!1,protobuf:!0,multipleRunsPerStream:!1}};function u(e){if(!e)return structuredClone(l);let t=(e,t)=>{let n={...e};if(!t)return n;for(let r of Object.keys(t))if(r in e){let e=t[r];typeof e==`boolean`&&(n[r]=e)}return n};return{protocol:e.protocol??l.protocol,transports:t(l.transports,e.transports),events:t(l.events,e.events),features:t(l.features,e.features)}}function d(e,t){let n=u(t);return e.config.emitChunkEvents&&(n.events.TEXT_MESSAGE_START=!1,n.events.TEXT_MESSAGE_CONTENT=!1,n.events.TEXT_MESSAGE_END=!1,n.events.TEXT_MESSAGE_CHUNK=!0,n.events.TOOL_CALL_START=!1,n.events.TOOL_CALL_ARGS=!1,n.events.TOOL_CALL_END=!1,n.events.TOOL_CALL_CHUNK=!0,n.events.REASONING_MESSAGE_START=!1,n.events.REASONING_MESSAGE_CONTENT=!1,n.events.REASONING_MESSAGE_END=!1,n.events.REASONING_MESSAGE_CHUNK=!0),n}function f(e,t,n){let r=n&&typeof n==`object`&&`agent`in n?d(n.agent,n.overrides):u(n);e.get(t,(e,t)=>{t.json(r)})}async function p(e,t={}){let{path:n=`/`,pingPath:r=`/ping`,capabilitiesPath:i=`/capabilities`,capabilities:a,corsOrigin:o=`*`}=t,l=await import(`express`),u=await import(`cors`),d=l.default??l,p=u.default??u,m=d();return m.use(p({origin:o,credentials:!0})),m.use(d.json({limit:`50mb`})),s(m,e,{path:n}),r&&c(m,r),i&&f(m,i,{agent:e,overrides:a}),m}exports.DEFAULT_CAPABILITIES=l,exports.addCapabilities=f,exports.addPing=c,exports.addStrandsExpressEndpoint=s,exports.capabilitiesFor=d,exports.createStrandsApp=p;
2
2
  //# sourceMappingURL=server.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.js","names":["RunAgentInputSchema","EventEncoder","EventType"],"sources":["../src/endpoint.ts","../src/server.ts"],"sourcesContent":["/** Express endpoint utilities for AWS Strands integration. */\n\nimport type { Express, Request, Response } from \"express\";\nimport {\n EventType,\n RunAgentInputSchema,\n type BaseEvent,\n type RunAgentInput,\n} from \"@ag-ui/core\";\nimport { EventEncoder } from \"@ag-ui/encoder\";\nimport type { StrandsAgent } from \"./agent\";\n\nexport interface AddStrandsEndpointOptions {\n path: string;\n}\n\n// The wire format is camelCase per the protocol, but the Python reference\n// server accepts snake_case aliases (pydantic `populate_by_name=True`). Mirror\n// that here so cross-SDK clients that send `thread_id` / `run_id` / etc. keep\n// working against the TS adapter.\nconst SNAKE_TO_CAMEL: Record<string, string> = {\n thread_id: \"threadId\",\n run_id: \"runId\",\n parent_run_id: \"parentRunId\",\n forwarded_props: \"forwardedProps\",\n tool_call_id: \"toolCallId\",\n parent_message_id: \"parentMessageId\",\n};\n\nconst UNSAFE_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\nfunction normalizeRunAgentInputKeys(raw: unknown): unknown {\n if (raw === null || typeof raw !== \"object\") return raw;\n if (Array.isArray(raw)) return raw.map(normalizeRunAgentInputKeys);\n const src = raw as Record<string, unknown>;\n const out: Record<string, unknown> = Object.create(null);\n for (const [key, value] of Object.entries(src)) {\n if (UNSAFE_KEYS.has(key)) continue;\n const target = SNAKE_TO_CAMEL[key] ?? key;\n if (target in out) continue;\n out[target] =\n value !== null && typeof value === \"object\"\n ? normalizeRunAgentInputKeys(value)\n : value;\n }\n return out;\n}\n\nfunction isJsonContentType(req: Request): boolean {\n // `req.is()` returns false for absent/mismatching Content-Type and tolerates\n // subtypes like `application/vnd.custom+json`.\n return Boolean(req.is(\"application/json\") || req.is(\"+json\"));\n}\n\n// Binary protobuf framing for AG-UI events. Only selected when the caller\n// explicitly mentions this media type in the Accept header — callers that\n// send `*/*` or omit Accept get SSE, which is the more forgiving format for\n// casual `curl -N` inspection and matches the protocol's default transport.\nconst PROTOBUF_MEDIA_TYPE = \"application/vnd.ag-ui.event+proto\";\n\nfunction clientExplicitlyRequestsProtobuf(accept: string | undefined): boolean {\n if (!accept) return false;\n return accept\n .split(\",\")\n .map((piece) => piece.split(\";\")[0]?.trim().toLowerCase() ?? \"\")\n .some((mt) => mt === PROTOBUF_MEDIA_TYPE);\n}\n\n/** Add a Strands agent endpoint to an Express app. */\nexport function addStrandsExpressEndpoint(\n app: Express,\n agent: StrandsAgent,\n options: AddStrandsEndpointOptions,\n): void {\n app.post(options.path, async (req: Request, res: Response) => {\n // Request boundary validation. Express's `express.json()` middleware\n // skips bodies whose Content-Type isn't JSON — it leaves `req.body` as\n // `{}` instead of rejecting, so silently invalid requests would otherwise\n // look indistinguishable from a request with an empty body. Reject them\n // here so the protocol contract (events.mdx §RunAgentInput) is enforced\n // at the HTTP edge rather than halfway through a streaming response.\n if (!isJsonContentType(req)) {\n res\n .status(415)\n .json({ error: \"Unsupported Media Type: expected application/json\" });\n return;\n }\n\n const normalized = normalizeRunAgentInputKeys(req.body);\n const parsed = RunAgentInputSchema.safeParse(normalized);\n if (!parsed.success) {\n res.status(400).json({\n error: \"Invalid RunAgentInput\",\n issues: parsed.error.issues.map((i) => ({\n path: i.path,\n message: i.message,\n })),\n });\n return;\n }\n // Preserve the resume[] field if present — the protocol schema validates\n // its shape, but passes opaque payloads through unchanged for the adapter\n // to inspect (see {@link StrandsAgent._runRaw} interrupt-rule enforcement).\n const inputData: RunAgentInput = parsed.data;\n\n const acceptHeader = req.header(\"accept\") ?? undefined;\n // Only hand the encoder the Accept header when the caller explicitly\n // opted into protobuf. Otherwise force SSE so `Accept: */*` doesn't\n // surprise callers with binary frames — the encoder's media-type\n // sort ranks protobuf above SSE for wildcard Accepts.\n const encoder = clientExplicitlyRequestsProtobuf(acceptHeader)\n ? new EventEncoder({ accept: acceptHeader })\n : new EventEncoder({ accept: \"text/event-stream\" });\n const contentType = encoder.getContentType();\n\n res.setHeader(\"Content-Type\", contentType);\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n res.flushHeaders?.();\n\n const writeEvent = (event: BaseEvent): void => {\n // Guard against writes to a socket the client has already dropped.\n // `res.write()` on a destroyed socket throws ERR_STREAM_DESTROYED in\n // recent Node versions; older versions silently no-op. Short-circuit\n // either way so the main loop sees the disconnect on the next\n // iteration.\n if (res.destroyed || res.writableEnded) return;\n if (contentType === \"text/event-stream\") {\n res.write(encoder.encode(event));\n } else {\n const bytes = encoder.encodeBinary(event);\n res.write(Buffer.from(bytes));\n }\n };\n\n // Hold an explicit iterator so we can call `.return()` on client\n // disconnect. Without this, `res.write()` silently buffers into a\n // closed socket and the agent generator's `finally` never runs —\n // in particular, THREAD_BUSY slots never release, wedging the thread.\n const iterator = agent.run(inputData);\n let clientDisconnected = false;\n const onDisconnect = (): void => {\n if (clientDisconnected) return;\n clientDisconnected = true;\n // Fire-and-forget — the iterator's own finally will settle the\n // active-runs set, session manager, etc. A throwing finally inside\n // the generator (e.g. a cleanup hook) must NOT surface as an\n // unhandled rejection and crash the Node process, so swallow here.\n iterator.return?.().catch(() => {\n /* intentional swallow — disconnect path */\n });\n };\n // HTTP/1.1 fires `close` on the Response when the socket closes;\n // HTTP/2 reliably fires `aborted` on the Request. Listen to both so\n // disconnects under both transports trigger cleanup.\n res.once(\"close\", onDisconnect);\n req.once(\"aborted\", onDisconnect);\n\n try {\n while (true) {\n if (clientDisconnected || res.writableEnded || res.destroyed) break;\n let step: IteratorResult<BaseEvent, void>;\n try {\n step = await iterator.next();\n } catch (e) {\n // Uncaught error from the generator (should be rare; agent.run()\n // normally wraps exceptions as RUN_ERROR itself).\n if (!clientDisconnected && !res.writableEnded) {\n try {\n writeEvent({\n type: EventType.RUN_ERROR,\n message: e instanceof Error ? e.message : String(e),\n code: \"STRANDS_ERROR\",\n });\n } catch {\n // ignore\n }\n }\n break;\n }\n if (step.done) break;\n if (clientDisconnected || res.writableEnded || res.destroyed) break;\n try {\n writeEvent(step.value);\n } catch (e) {\n // Encoder failure. Try to deliver a RUN_ERROR, then bail.\n const errEvent: BaseEvent = {\n type: EventType.RUN_ERROR,\n message: `Encoding error: ${String(e)}`,\n code: \"ENCODING_ERROR\",\n };\n try {\n writeEvent(errEvent);\n } catch {\n // Swallow — response might already be broken.\n }\n break;\n }\n }\n } finally {\n res.removeListener(\"close\", onDisconnect);\n req.removeListener(\"aborted\", onDisconnect);\n // Make sure the generator shuts down even if we broke out without\n // consuming everything — idempotent when already exhausted.\n try {\n await iterator.return?.();\n } catch {\n // ignore\n }\n if (!res.writableEnded) res.end();\n }\n });\n}\n\n/** Add a ping endpoint returning `{status: \"healthy\"}`. */\nexport function addPing(app: Express, path: string): void {\n app.get(path, (_req, res) => {\n res.json({ status: \"healthy\" });\n });\n}\n\n/**\n * Static description of what this adapter actually supports. Every event\n * family here can be observed on the wire; anything missing is either not\n * emitted by this adapter (e.g. `ACTIVITY_*`, `RAW`) or only emitted in\n * specific configurations (the `*_CHUNK` events, gated by\n * `emitChunkEvents` — use {@link capabilitiesFor} to derive the matrix\n * from a concrete agent and pick those flags up automatically).\n *\n * Exported as a plain object so consumers can fold overrides in — for\n * example, advertising `events.ACTIVITY_SNAPSHOT: true` after wiring a\n * `customResultHandler` that emits those events themselves.\n */\nexport interface StrandsAguiCapabilities {\n /** Semver of the AG-UI contract surface this adapter targets. */\n protocol: string;\n /** Content types the HTTP endpoint can stream. */\n transports: { sse: boolean; protobuf: boolean; websocket: boolean };\n /** Event families the adapter emits. Per-event flags, not categories. */\n events: {\n RUN_STARTED: boolean;\n RUN_FINISHED: boolean;\n RUN_ERROR: boolean;\n TEXT_MESSAGE_START: boolean;\n TEXT_MESSAGE_CONTENT: boolean;\n TEXT_MESSAGE_END: boolean;\n TEXT_MESSAGE_CHUNK: boolean;\n TOOL_CALL_START: boolean;\n TOOL_CALL_ARGS: boolean;\n TOOL_CALL_END: boolean;\n TOOL_CALL_RESULT: boolean;\n TOOL_CALL_CHUNK: boolean;\n STATE_SNAPSHOT: boolean;\n STATE_DELTA: boolean;\n MESSAGES_SNAPSHOT: boolean;\n STEP_STARTED: boolean;\n STEP_FINISHED: boolean;\n REASONING_START: boolean;\n REASONING_MESSAGE_START: boolean;\n REASONING_MESSAGE_CONTENT: boolean;\n REASONING_MESSAGE_END: boolean;\n REASONING_MESSAGE_CHUNK: boolean;\n REASONING_ENCRYPTED_VALUE: boolean;\n REASONING_END: boolean;\n CUSTOM: boolean;\n ACTIVITY_SNAPSHOT: boolean;\n ACTIVITY_DELTA: boolean;\n RAW: boolean;\n };\n /** Protocol feature flags advertised to the client. */\n features: {\n /** RunFinished.outcome interrupt + RunAgentInput.resume loop. */\n interrupts: boolean;\n /** Tool-call interrupts accept editedArgs in the resume payload. */\n toolCallInterruptEditedArgs: boolean;\n /** Resumable streams with sequence numbers. Unsupported. */\n resumableStreams: boolean;\n /** Adapter emits MESSAGES_SNAPSHOT at run lifecycle boundaries (Python parity). */\n messagesSnapshot: boolean;\n /** State delta via RFC 6902 JSON Patch. Only when a customResultHandler emits them. */\n stateDelta: boolean;\n /** Binary protobuf content negotiation (explicit Accept header). */\n protobuf: boolean;\n /** Multiple sequential runs in one HTTP stream. One run per POST. */\n multipleRunsPerStream: boolean;\n };\n}\n\n/** Default capabilities advertised by {@link addCapabilities}. */\nexport const DEFAULT_CAPABILITIES: StrandsAguiCapabilities = {\n protocol: \"1\",\n transports: { sse: true, protobuf: true, websocket: false },\n events: {\n RUN_STARTED: true,\n RUN_FINISHED: true,\n RUN_ERROR: true,\n TEXT_MESSAGE_START: true,\n TEXT_MESSAGE_CONTENT: true,\n TEXT_MESSAGE_END: true,\n TEXT_MESSAGE_CHUNK: false,\n TOOL_CALL_START: true,\n TOOL_CALL_ARGS: true,\n TOOL_CALL_END: true,\n TOOL_CALL_RESULT: true,\n TOOL_CALL_CHUNK: false,\n STATE_SNAPSHOT: true,\n STATE_DELTA: false,\n MESSAGES_SNAPSHOT: true,\n STEP_STARTED: true,\n STEP_FINISHED: true,\n REASONING_START: true,\n REASONING_MESSAGE_START: true,\n REASONING_MESSAGE_CONTENT: true,\n REASONING_MESSAGE_END: true,\n REASONING_MESSAGE_CHUNK: false,\n REASONING_ENCRYPTED_VALUE: true,\n REASONING_END: true,\n CUSTOM: true,\n ACTIVITY_SNAPSHOT: false,\n ACTIVITY_DELTA: false,\n RAW: false,\n },\n features: {\n interrupts: true,\n toolCallInterruptEditedArgs: true,\n resumableStreams: false,\n messagesSnapshot: true,\n stateDelta: false,\n protobuf: true,\n multipleRunsPerStream: false,\n },\n};\n\n/** One level of sub-field partiality — shallow `Partial<>` on nested objects. */\nexport type StrandsAguiCapabilitiesOverrides = {\n protocol?: StrandsAguiCapabilities[\"protocol\"];\n transports?: Partial<StrandsAguiCapabilities[\"transports\"]>;\n events?: Partial<StrandsAguiCapabilities[\"events\"]>;\n features?: Partial<StrandsAguiCapabilities[\"features\"]>;\n};\n\n/**\n * Deep-merge consumer overrides on top of the default capabilities. Unknown\n * keys in `events` / `features` / `transports` are dropped (typos shouldn't\n * silently pollute the advertised matrix).\n */\nfunction mergeCapabilities(\n overrides?: StrandsAguiCapabilitiesOverrides,\n): StrandsAguiCapabilities {\n if (!overrides) return structuredClone(DEFAULT_CAPABILITIES);\n const pick = <K extends string>(\n defaults: Record<K, boolean>,\n override: Partial<Record<K, boolean>> | undefined,\n ): Record<K, boolean> => {\n const out = { ...defaults };\n if (!override) return out;\n for (const key of Object.keys(override) as K[]) {\n if (key in defaults) {\n const v = override[key];\n if (typeof v === \"boolean\") out[key] = v;\n }\n // Silently drop unknown keys — typos shouldn't leak into the JSON.\n }\n return out;\n };\n return {\n protocol: overrides.protocol ?? DEFAULT_CAPABILITIES.protocol,\n transports: pick(DEFAULT_CAPABILITIES.transports, overrides.transports),\n events: pick(DEFAULT_CAPABILITIES.events, overrides.events),\n features: pick(DEFAULT_CAPABILITIES.features, overrides.features),\n };\n}\n\n/**\n * Derive capabilities from a concrete StrandsAgent instance, flipping the\n * chunk-event flags based on whether the agent is configured to emit chunks.\n * When chunks are on, the explicit triples are suppressed, so the advertised\n * matrix reflects what the client will actually observe.\n */\nexport function capabilitiesFor(\n agent: { config: { emitChunkEvents?: boolean } },\n overrides?: StrandsAguiCapabilitiesOverrides,\n): StrandsAguiCapabilities {\n const base = mergeCapabilities(overrides);\n if (agent.config.emitChunkEvents) {\n base.events.TEXT_MESSAGE_START = false;\n base.events.TEXT_MESSAGE_CONTENT = false;\n base.events.TEXT_MESSAGE_END = false;\n base.events.TEXT_MESSAGE_CHUNK = true;\n base.events.TOOL_CALL_START = false;\n base.events.TOOL_CALL_ARGS = false;\n base.events.TOOL_CALL_END = false;\n base.events.TOOL_CALL_CHUNK = true;\n base.events.REASONING_MESSAGE_START = false;\n base.events.REASONING_MESSAGE_CONTENT = false;\n base.events.REASONING_MESSAGE_END = false;\n base.events.REASONING_MESSAGE_CHUNK = true;\n }\n return base;\n}\n\n/**\n * Add a capabilities-advertisement endpoint.\n *\n * Frontends can GET this path to discover which AG-UI event families and\n * protocol features the adapter supports, without having to probe empirically.\n *\n * Two forms:\n * - `addCapabilities(app, path, overrides?)` — static matrix (back-compat).\n * - `addCapabilities(app, path, { agent })` — derives the matrix from a live\n * `StrandsAgent`, picking up `emitChunkEvents` automatically.\n */\nexport function addCapabilities(\n app: Express,\n path: string,\n capabilities?:\n | StrandsAguiCapabilitiesOverrides\n | {\n agent: { config: { emitChunkEvents?: boolean } };\n overrides?: StrandsAguiCapabilitiesOverrides;\n },\n): void {\n const resolved =\n capabilities && typeof capabilities === \"object\" && \"agent\" in capabilities\n ? capabilitiesFor(capabilities.agent, capabilities.overrides)\n : mergeCapabilities(\n capabilities as StrandsAguiCapabilitiesOverrides | undefined,\n );\n app.get(path, (_req, res) => {\n res.json(resolved);\n });\n}\n","/**\n * Server-side entry point for `@ag-ui/aws-strands`.\n *\n * Import from `@ag-ui/aws-strands/server` when you need the Express transport\n * helpers. The main entry point (`@ag-ui/aws-strands`) stays free of Express\n * / cors references so Next.js / Turbopack / Vite bundlers tracing the\n * client-side graph don't pull server-only modules into the browser build.\n */\n\nimport {\n addStrandsExpressEndpoint,\n addPing,\n addCapabilities,\n} from \"./endpoint\";\nimport type { StrandsAgent } from \"./agent\";\nimport type { StrandsAguiCapabilitiesOverrides } from \"./endpoint\";\n\nexport {\n addStrandsExpressEndpoint,\n addPing,\n addCapabilities,\n capabilitiesFor,\n DEFAULT_CAPABILITIES,\n} from \"./endpoint\";\n\nexport type {\n AddStrandsEndpointOptions,\n StrandsAguiCapabilities,\n StrandsAguiCapabilitiesOverrides,\n} from \"./endpoint\";\n\nexport interface CreateStrandsAppOptions {\n /** Path for the agent endpoint. Default `/`. */\n path?: string;\n /** Path for the ping endpoint. Pass `null` or `\"\"` to disable. Default `/ping`. */\n pingPath?: string | null;\n /**\n * Path for the capabilities endpoint. Pass `null` or `\"\"` to disable.\n * Default `/capabilities`.\n */\n capabilitiesPath?: string | null;\n /** Override capabilities advertised at {@link CreateStrandsAppOptions.capabilitiesPath}. */\n capabilities?: StrandsAguiCapabilitiesOverrides;\n /** Override CORS origin. Default `*` (wide-open, matches the Python adapter). */\n corsOrigin?: string | string[] | boolean;\n}\n\n/** Create an Express app with a single Strands agent endpoint and optional ping endpoint. */\nexport async function createStrandsApp(\n agent: StrandsAgent,\n options: CreateStrandsAppOptions = {},\n): Promise<import(\"express\").Express> {\n const {\n path = \"/\",\n pingPath = \"/ping\",\n capabilitiesPath = \"/capabilities\",\n capabilities,\n corsOrigin = true,\n } = options;\n\n // Lazy dynamic imports so `express` / `cors` are only required at runtime\n // when `createStrandsApp` is actually called.\n const expressModule = await import(\"express\");\n const corsModule = await import(\"cors\");\n const express = (expressModule.default ??\n expressModule) as typeof import(\"express\");\n const cors = (corsModule.default ?? corsModule) as typeof import(\"cors\");\n\n const app = express();\n app.use(cors({ origin: corsOrigin, credentials: true }));\n app.use(express.json({ limit: \"50mb\" }));\n\n addStrandsExpressEndpoint(app, agent, { path });\n\n if (pingPath) {\n addPing(app, pingPath);\n }\n\n if (capabilitiesPath) {\n addCapabilities(app, capabilitiesPath, { agent, overrides: capabilities });\n }\n\n return app;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.js","names":["RunAgentInputSchema","EventEncoder","EventType"],"sources":["../src/endpoint.ts","../src/server.ts"],"sourcesContent":["/** Express endpoint utilities for AWS Strands integration. */\n\nimport type { Express, Request, Response } from \"express\";\nimport {\n EventType,\n RunAgentInputSchema,\n type BaseEvent,\n type RunAgentInput,\n} from \"@ag-ui/core\";\nimport { EventEncoder } from \"@ag-ui/encoder\";\nimport type { StrandsAgent } from \"./agent\";\n\nexport interface AddStrandsEndpointOptions {\n path: string;\n}\n\n// The wire format is camelCase per the protocol, but the Python reference\n// server accepts snake_case aliases (pydantic `populate_by_name=True`). Mirror\n// that here so cross-SDK clients that send `thread_id` / `run_id` / etc. keep\n// working against the TS adapter.\nconst SNAKE_TO_CAMEL: Record<string, string> = {\n thread_id: \"threadId\",\n run_id: \"runId\",\n parent_run_id: \"parentRunId\",\n forwarded_props: \"forwardedProps\",\n tool_call_id: \"toolCallId\",\n parent_message_id: \"parentMessageId\",\n};\n\nconst UNSAFE_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\nfunction normalizeRunAgentInputKeys(raw: unknown): unknown {\n if (raw === null || typeof raw !== \"object\") return raw;\n if (Array.isArray(raw)) return raw.map(normalizeRunAgentInputKeys);\n const src = raw as Record<string, unknown>;\n const out: Record<string, unknown> = Object.create(null);\n for (const [key, value] of Object.entries(src)) {\n if (UNSAFE_KEYS.has(key)) continue;\n const target = SNAKE_TO_CAMEL[key] ?? key;\n if (target in out) continue;\n out[target] =\n value !== null && typeof value === \"object\"\n ? normalizeRunAgentInputKeys(value)\n : value;\n }\n return out;\n}\n\nfunction isJsonContentType(req: Request): boolean {\n // `req.is()` returns false for absent/mismatching Content-Type and tolerates\n // subtypes like `application/vnd.custom+json`.\n return Boolean(req.is(\"application/json\") || req.is(\"+json\"));\n}\n\n// Binary protobuf framing for AG-UI events. Only selected when the caller\n// explicitly mentions this media type in the Accept header — callers that\n// send `*/*` or omit Accept get SSE, which is the more forgiving format for\n// casual `curl -N` inspection and matches the protocol's default transport.\nconst PROTOBUF_MEDIA_TYPE = \"application/vnd.ag-ui.event+proto\";\n\nfunction clientExplicitlyRequestsProtobuf(accept: string | undefined): boolean {\n if (!accept) return false;\n return accept\n .split(\",\")\n .map((piece) => piece.split(\";\")[0]?.trim().toLowerCase() ?? \"\")\n .some((mt) => mt === PROTOBUF_MEDIA_TYPE);\n}\n\n/** Add a Strands agent endpoint to an Express app. */\nexport function addStrandsExpressEndpoint(\n app: Express,\n agent: StrandsAgent,\n options: AddStrandsEndpointOptions,\n): void {\n app.post(options.path, async (req: Request, res: Response) => {\n // Request boundary validation. Express's `express.json()` middleware\n // skips bodies whose Content-Type isn't JSON — it leaves `req.body` as\n // `{}` instead of rejecting, so silently invalid requests would otherwise\n // look indistinguishable from a request with an empty body. Reject them\n // here so the protocol contract (events.mdx §RunAgentInput) is enforced\n // at the HTTP edge rather than halfway through a streaming response.\n if (!isJsonContentType(req)) {\n res\n .status(415)\n .json({ error: \"Unsupported Media Type: expected application/json\" });\n return;\n }\n\n const normalized = normalizeRunAgentInputKeys(req.body);\n const parsed = RunAgentInputSchema.safeParse(normalized);\n if (!parsed.success) {\n res.status(400).json({\n error: \"Invalid RunAgentInput\",\n issues: parsed.error.issues.map((i) => ({\n path: i.path,\n message: i.message,\n })),\n });\n return;\n }\n // Preserve the resume[] field if present — the protocol schema validates\n // its shape, but passes opaque payloads through unchanged for the adapter\n // to inspect (see {@link StrandsAgent._runRaw} interrupt-rule enforcement).\n const inputData: RunAgentInput = parsed.data;\n\n const acceptHeader = req.header(\"accept\") ?? undefined;\n // Only hand the encoder the Accept header when the caller explicitly\n // opted into protobuf. Otherwise force SSE so `Accept: */*` doesn't\n // surprise callers with binary frames — the encoder's media-type\n // sort ranks protobuf above SSE for wildcard Accepts.\n const encoder = clientExplicitlyRequestsProtobuf(acceptHeader)\n ? new EventEncoder({ accept: acceptHeader })\n : new EventEncoder({ accept: \"text/event-stream\" });\n const contentType = encoder.getContentType();\n\n res.setHeader(\"Content-Type\", contentType);\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n res.flushHeaders?.();\n\n const writeEvent = (event: BaseEvent): void => {\n // Guard against writes to a socket the client has already dropped.\n // `res.write()` on a destroyed socket throws ERR_STREAM_DESTROYED in\n // recent Node versions; older versions silently no-op. Short-circuit\n // either way so the main loop sees the disconnect on the next\n // iteration.\n if (res.destroyed || res.writableEnded) return;\n if (contentType === \"text/event-stream\") {\n res.write(encoder.encode(event));\n } else {\n const bytes = encoder.encodeBinary(event);\n res.write(Buffer.from(bytes));\n }\n };\n\n // Hold an explicit iterator so we can call `.return()` on client\n // disconnect. Without this, `res.write()` silently buffers into a\n // closed socket and the agent generator's `finally` never runs —\n // in particular, THREAD_BUSY slots never release, wedging the thread.\n const iterator = agent.run(inputData);\n let clientDisconnected = false;\n const onDisconnect = (): void => {\n if (clientDisconnected) return;\n clientDisconnected = true;\n // Fire-and-forget — the iterator's own finally will settle the\n // active-runs set, session manager, etc. A throwing finally inside\n // the generator (e.g. a cleanup hook) must NOT surface as an\n // unhandled rejection and crash the Node process, so swallow here.\n iterator.return?.().catch(() => {\n /* intentional swallow — disconnect path */\n });\n };\n // HTTP/1.1 fires `close` on the Response when the socket closes;\n // HTTP/2 reliably fires `aborted` on the Request. Listen to both so\n // disconnects under both transports trigger cleanup.\n res.once(\"close\", onDisconnect);\n req.once(\"aborted\", onDisconnect);\n\n try {\n while (true) {\n if (clientDisconnected || res.writableEnded || res.destroyed) break;\n let step: IteratorResult<BaseEvent, void>;\n try {\n step = await iterator.next();\n } catch (e) {\n // Uncaught error from the generator (should be rare; agent.run()\n // normally wraps exceptions as RUN_ERROR itself).\n if (!clientDisconnected && !res.writableEnded) {\n try {\n writeEvent({\n type: EventType.RUN_ERROR,\n message: e instanceof Error ? e.message : String(e),\n code: \"STRANDS_ERROR\",\n });\n } catch {\n // ignore\n }\n }\n break;\n }\n if (step.done) break;\n if (clientDisconnected || res.writableEnded || res.destroyed) break;\n try {\n writeEvent(step.value);\n } catch (e) {\n // Encoder failure. Try to deliver a RUN_ERROR, then bail.\n const errEvent: BaseEvent = {\n type: EventType.RUN_ERROR,\n message: `Encoding error: ${String(e)}`,\n code: \"ENCODING_ERROR\",\n };\n try {\n writeEvent(errEvent);\n } catch {\n // Swallow — response might already be broken.\n }\n break;\n }\n }\n } finally {\n res.removeListener(\"close\", onDisconnect);\n req.removeListener(\"aborted\", onDisconnect);\n // Make sure the generator shuts down even if we broke out without\n // consuming everything — idempotent when already exhausted.\n try {\n await iterator.return?.();\n } catch {\n // ignore\n }\n if (!res.writableEnded) res.end();\n }\n });\n}\n\n/** Add a ping endpoint returning `{status: \"healthy\"}`. */\nexport function addPing(app: Express, path: string): void {\n app.get(path, (_req, res) => {\n res.json({ status: \"healthy\" });\n });\n}\n\n/**\n * Static description of what this adapter actually supports. Every event\n * family here can be observed on the wire; anything missing is either not\n * emitted by this adapter (e.g. `ACTIVITY_*`, `RAW`) or only emitted in\n * specific configurations (the `*_CHUNK` events, gated by\n * `emitChunkEvents` — use {@link capabilitiesFor} to derive the matrix\n * from a concrete agent and pick those flags up automatically).\n *\n * Exported as a plain object so consumers can fold overrides in — for\n * example, advertising `events.ACTIVITY_SNAPSHOT: true` after wiring a\n * `customResultHandler` that emits those events themselves.\n */\nexport interface StrandsAguiCapabilities {\n /** Semver of the AG-UI contract surface this adapter targets. */\n protocol: string;\n /** Content types the HTTP endpoint can stream. */\n transports: { sse: boolean; protobuf: boolean; websocket: boolean };\n /** Event families the adapter emits. Per-event flags, not categories. */\n events: {\n RUN_STARTED: boolean;\n RUN_FINISHED: boolean;\n RUN_ERROR: boolean;\n TEXT_MESSAGE_START: boolean;\n TEXT_MESSAGE_CONTENT: boolean;\n TEXT_MESSAGE_END: boolean;\n TEXT_MESSAGE_CHUNK: boolean;\n TOOL_CALL_START: boolean;\n TOOL_CALL_ARGS: boolean;\n TOOL_CALL_END: boolean;\n TOOL_CALL_RESULT: boolean;\n TOOL_CALL_CHUNK: boolean;\n STATE_SNAPSHOT: boolean;\n STATE_DELTA: boolean;\n MESSAGES_SNAPSHOT: boolean;\n STEP_STARTED: boolean;\n STEP_FINISHED: boolean;\n REASONING_START: boolean;\n REASONING_MESSAGE_START: boolean;\n REASONING_MESSAGE_CONTENT: boolean;\n REASONING_MESSAGE_END: boolean;\n REASONING_MESSAGE_CHUNK: boolean;\n REASONING_ENCRYPTED_VALUE: boolean;\n REASONING_END: boolean;\n CUSTOM: boolean;\n ACTIVITY_SNAPSHOT: boolean;\n ACTIVITY_DELTA: boolean;\n RAW: boolean;\n };\n /** Protocol feature flags advertised to the client. */\n features: {\n /** RunFinished.outcome interrupt + RunAgentInput.resume loop. */\n interrupts: boolean;\n /** Tool-call interrupts accept editedArgs in the resume payload. */\n toolCallInterruptEditedArgs: boolean;\n /** Resumable streams with sequence numbers. Unsupported. */\n resumableStreams: boolean;\n /** Adapter emits MESSAGES_SNAPSHOT at run lifecycle boundaries (Python parity). */\n messagesSnapshot: boolean;\n /** State delta via RFC 6902 JSON Patch. Only when a customResultHandler emits them. */\n stateDelta: boolean;\n /** Binary protobuf content negotiation (explicit Accept header). */\n protobuf: boolean;\n /** Multiple sequential runs in one HTTP stream. One run per POST. */\n multipleRunsPerStream: boolean;\n };\n}\n\n/** Default capabilities advertised by {@link addCapabilities}. */\nexport const DEFAULT_CAPABILITIES: StrandsAguiCapabilities = {\n protocol: \"1\",\n transports: { sse: true, protobuf: true, websocket: false },\n events: {\n RUN_STARTED: true,\n RUN_FINISHED: true,\n RUN_ERROR: true,\n TEXT_MESSAGE_START: true,\n TEXT_MESSAGE_CONTENT: true,\n TEXT_MESSAGE_END: true,\n TEXT_MESSAGE_CHUNK: false,\n TOOL_CALL_START: true,\n TOOL_CALL_ARGS: true,\n TOOL_CALL_END: true,\n TOOL_CALL_RESULT: true,\n TOOL_CALL_CHUNK: false,\n STATE_SNAPSHOT: true,\n STATE_DELTA: false,\n MESSAGES_SNAPSHOT: true,\n STEP_STARTED: true,\n STEP_FINISHED: true,\n REASONING_START: true,\n REASONING_MESSAGE_START: true,\n REASONING_MESSAGE_CONTENT: true,\n REASONING_MESSAGE_END: true,\n REASONING_MESSAGE_CHUNK: false,\n REASONING_ENCRYPTED_VALUE: true,\n REASONING_END: true,\n CUSTOM: true,\n ACTIVITY_SNAPSHOT: false,\n ACTIVITY_DELTA: false,\n RAW: false,\n },\n features: {\n interrupts: true,\n toolCallInterruptEditedArgs: true,\n resumableStreams: false,\n messagesSnapshot: true,\n stateDelta: false,\n protobuf: true,\n multipleRunsPerStream: false,\n },\n};\n\n/** One level of sub-field partiality — shallow `Partial<>` on nested objects. */\nexport type StrandsAguiCapabilitiesOverrides = {\n protocol?: StrandsAguiCapabilities[\"protocol\"];\n transports?: Partial<StrandsAguiCapabilities[\"transports\"]>;\n events?: Partial<StrandsAguiCapabilities[\"events\"]>;\n features?: Partial<StrandsAguiCapabilities[\"features\"]>;\n};\n\n/**\n * Deep-merge consumer overrides on top of the default capabilities. Unknown\n * keys in `events` / `features` / `transports` are dropped (typos shouldn't\n * silently pollute the advertised matrix).\n */\nfunction mergeCapabilities(\n overrides?: StrandsAguiCapabilitiesOverrides,\n): StrandsAguiCapabilities {\n if (!overrides) return structuredClone(DEFAULT_CAPABILITIES);\n const pick = <K extends string>(\n defaults: Record<K, boolean>,\n override: Partial<Record<K, boolean>> | undefined,\n ): Record<K, boolean> => {\n const out = { ...defaults };\n if (!override) return out;\n for (const key of Object.keys(override) as K[]) {\n if (key in defaults) {\n const v = override[key];\n if (typeof v === \"boolean\") out[key] = v;\n }\n // Silently drop unknown keys — typos shouldn't leak into the JSON.\n }\n return out;\n };\n return {\n protocol: overrides.protocol ?? DEFAULT_CAPABILITIES.protocol,\n transports: pick(DEFAULT_CAPABILITIES.transports, overrides.transports),\n events: pick(DEFAULT_CAPABILITIES.events, overrides.events),\n features: pick(DEFAULT_CAPABILITIES.features, overrides.features),\n };\n}\n\n/**\n * Derive capabilities from a concrete StrandsAgent instance, flipping the\n * chunk-event flags based on whether the agent is configured to emit chunks.\n * When chunks are on, the explicit triples are suppressed, so the advertised\n * matrix reflects what the client will actually observe.\n */\nexport function capabilitiesFor(\n agent: { config: { emitChunkEvents?: boolean } },\n overrides?: StrandsAguiCapabilitiesOverrides,\n): StrandsAguiCapabilities {\n const base = mergeCapabilities(overrides);\n if (agent.config.emitChunkEvents) {\n base.events.TEXT_MESSAGE_START = false;\n base.events.TEXT_MESSAGE_CONTENT = false;\n base.events.TEXT_MESSAGE_END = false;\n base.events.TEXT_MESSAGE_CHUNK = true;\n base.events.TOOL_CALL_START = false;\n base.events.TOOL_CALL_ARGS = false;\n base.events.TOOL_CALL_END = false;\n base.events.TOOL_CALL_CHUNK = true;\n base.events.REASONING_MESSAGE_START = false;\n base.events.REASONING_MESSAGE_CONTENT = false;\n base.events.REASONING_MESSAGE_END = false;\n base.events.REASONING_MESSAGE_CHUNK = true;\n }\n return base;\n}\n\n/**\n * Add a capabilities-advertisement endpoint.\n *\n * Frontends can GET this path to discover which AG-UI event families and\n * protocol features the adapter supports, without having to probe empirically.\n *\n * Two forms:\n * - `addCapabilities(app, path, overrides?)` — static matrix (back-compat).\n * - `addCapabilities(app, path, { agent })` — derives the matrix from a live\n * `StrandsAgent`, picking up `emitChunkEvents` automatically.\n */\nexport function addCapabilities(\n app: Express,\n path: string,\n capabilities?:\n | StrandsAguiCapabilitiesOverrides\n | {\n agent: { config: { emitChunkEvents?: boolean } };\n overrides?: StrandsAguiCapabilitiesOverrides;\n },\n): void {\n const resolved =\n capabilities && typeof capabilities === \"object\" && \"agent\" in capabilities\n ? capabilitiesFor(capabilities.agent, capabilities.overrides)\n : mergeCapabilities(\n capabilities as StrandsAguiCapabilitiesOverrides | undefined,\n );\n app.get(path, (_req, res) => {\n res.json(resolved);\n });\n}\n","/**\n * Server-side entry point for `@ag-ui/aws-strands`.\n *\n * Import from `@ag-ui/aws-strands/server` when you need the Express transport\n * helpers. The main entry point (`@ag-ui/aws-strands`) stays free of Express\n * / cors references so Next.js / Turbopack / Vite bundlers tracing the\n * client-side graph don't pull server-only modules into the browser build.\n */\n\nimport {\n addStrandsExpressEndpoint,\n addPing,\n addCapabilities,\n} from \"./endpoint\";\nimport type { StrandsAgent } from \"./agent\";\nimport type { StrandsAguiCapabilitiesOverrides } from \"./endpoint\";\n\nexport {\n addStrandsExpressEndpoint,\n addPing,\n addCapabilities,\n capabilitiesFor,\n DEFAULT_CAPABILITIES,\n} from \"./endpoint\";\n\nexport type {\n AddStrandsEndpointOptions,\n StrandsAguiCapabilities,\n StrandsAguiCapabilitiesOverrides,\n} from \"./endpoint\";\n\nexport interface CreateStrandsAppOptions {\n /** Path for the agent endpoint. Default `/`. */\n path?: string;\n /** Path for the ping endpoint. Pass `null` or `\"\"` to disable. Default `/ping`. */\n pingPath?: string | null;\n /**\n * Path for the capabilities endpoint. Pass `null` or `\"\"` to disable.\n * Default `/capabilities`.\n */\n capabilitiesPath?: string | null;\n /** Override capabilities advertised at {@link CreateStrandsAppOptions.capabilitiesPath}. */\n capabilities?: StrandsAguiCapabilitiesOverrides;\n /**\n * Override CORS origin. Default `\"*\"` (wide-open, matches the Python adapter,\n * which configures Starlette `CORSMiddleware` with `allow_origins=[\"*\"]`).\n *\n * Note: with the `cors` package, a literal `\"*\"` is emitted verbatim as\n * `Access-Control-Allow-Origin: *`, whereas `true` would reflect the request's\n * `Origin` header back per-request — a different (more permissive) posture when\n * combined with credentials. Stick to `\"*\"` to match the Python adapter.\n */\n corsOrigin?: string | string[] | boolean;\n}\n\n/** Create an Express app with a single Strands agent endpoint and optional ping endpoint. */\nexport async function createStrandsApp(\n agent: StrandsAgent,\n options: CreateStrandsAppOptions = {},\n): Promise<import(\"express\").Express> {\n const {\n path = \"/\",\n pingPath = \"/ping\",\n capabilitiesPath = \"/capabilities\",\n capabilities,\n corsOrigin = \"*\",\n } = options;\n\n // Lazy dynamic imports so `express` / `cors` are only required at runtime\n // when `createStrandsApp` is actually called.\n const expressModule = await import(\"express\");\n const corsModule = await import(\"cors\");\n const express = (expressModule.default ??\n expressModule) as typeof import(\"express\");\n const cors = (corsModule.default ?? corsModule) as typeof import(\"cors\");\n\n const app = express();\n app.use(cors({ origin: corsOrigin, credentials: true }));\n app.use(express.json({ limit: \"50mb\" }));\n\n addStrandsExpressEndpoint(app, agent, { path });\n\n if (pingPath) {\n addPing(app, pingPath);\n }\n\n if (capabilitiesPath) {\n addCapabilities(app, capabilitiesPath, { agent, overrides: capabilities });\n }\n\n return app;\n}\n"],"mappings":"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"}
package/dist/server.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{EventType as e,RunAgentInputSchema as t}from"@ag-ui/core";import{EventEncoder as n}from"@ag-ui/encoder";const r={thread_id:`threadId`,run_id:`runId`,parent_run_id:`parentRunId`,forwarded_props:`forwardedProps`,tool_call_id:`toolCallId`,parent_message_id:`parentMessageId`},i=new Set([`__proto__`,`constructor`,`prototype`]);function a(e){if(typeof e!=`object`||!e)return e;if(Array.isArray(e))return e.map(a);let t=e,n=Object.create(null);for(let[e,o]of Object.entries(t)){if(i.has(e))continue;let t=r[e]??e;t in n||(n[t]=typeof o==`object`&&o?a(o):o)}return n}function o(e){return!!(e.is(`application/json`)||e.is(`+json`))}function s(e){return e?e.split(`,`).map(e=>e.split(`;`)[0]?.trim().toLowerCase()??``).some(e=>e===`application/vnd.ag-ui.event+proto`):!1}function c(r,i,c){r.post(c.path,async(r,c)=>{if(!o(r)){c.status(415).json({error:`Unsupported Media Type: expected application/json`});return}let l=a(r.body),u=t.safeParse(l);if(!u.success){c.status(400).json({error:`Invalid RunAgentInput`,issues:u.error.issues.map(e=>({path:e.path,message:e.message}))});return}let d=u.data,f=r.header(`accept`)??void 0,p=s(f)?new n({accept:f}):new n({accept:`text/event-stream`}),m=p.getContentType();c.setHeader(`Content-Type`,m),c.setHeader(`Cache-Control`,`no-cache`),c.setHeader(`Connection`,`keep-alive`),c.flushHeaders?.();let h=e=>{if(!(c.destroyed||c.writableEnded))if(m===`text/event-stream`)c.write(p.encode(e));else{let t=p.encodeBinary(e);c.write(Buffer.from(t))}},g=i.run(d),_=!1,v=()=>{_||(_=!0,g.return?.().catch(()=>{}))};c.once(`close`,v),r.once(`aborted`,v);try{for(;!(_||c.writableEnded||c.destroyed);){let t;try{t=await g.next()}catch(t){if(!_&&!c.writableEnded)try{h({type:e.RUN_ERROR,message:t instanceof Error?t.message:String(t),code:`STRANDS_ERROR`})}catch{}break}if(t.done||_||c.writableEnded||c.destroyed)break;try{h(t.value)}catch(t){let n={type:e.RUN_ERROR,message:`Encoding error: ${String(t)}`,code:`ENCODING_ERROR`};try{h(n)}catch{}break}}}finally{c.removeListener(`close`,v),r.removeListener(`aborted`,v);try{await g.return?.()}catch{}c.writableEnded||c.end()}})}function l(e,t){e.get(t,(e,t)=>{t.json({status:`healthy`})})}const u={protocol:`1`,transports:{sse:!0,protobuf:!0,websocket:!1},events:{RUN_STARTED:!0,RUN_FINISHED:!0,RUN_ERROR:!0,TEXT_MESSAGE_START:!0,TEXT_MESSAGE_CONTENT:!0,TEXT_MESSAGE_END:!0,TEXT_MESSAGE_CHUNK:!1,TOOL_CALL_START:!0,TOOL_CALL_ARGS:!0,TOOL_CALL_END:!0,TOOL_CALL_RESULT:!0,TOOL_CALL_CHUNK:!1,STATE_SNAPSHOT:!0,STATE_DELTA:!1,MESSAGES_SNAPSHOT:!0,STEP_STARTED:!0,STEP_FINISHED:!0,REASONING_START:!0,REASONING_MESSAGE_START:!0,REASONING_MESSAGE_CONTENT:!0,REASONING_MESSAGE_END:!0,REASONING_MESSAGE_CHUNK:!1,REASONING_ENCRYPTED_VALUE:!0,REASONING_END:!0,CUSTOM:!0,ACTIVITY_SNAPSHOT:!1,ACTIVITY_DELTA:!1,RAW:!1},features:{interrupts:!0,toolCallInterruptEditedArgs:!0,resumableStreams:!1,messagesSnapshot:!0,stateDelta:!1,protobuf:!0,multipleRunsPerStream:!1}};function d(e){if(!e)return structuredClone(u);let t=(e,t)=>{let n={...e};if(!t)return n;for(let r of Object.keys(t))if(r in e){let e=t[r];typeof e==`boolean`&&(n[r]=e)}return n};return{protocol:e.protocol??u.protocol,transports:t(u.transports,e.transports),events:t(u.events,e.events),features:t(u.features,e.features)}}function f(e,t){let n=d(t);return e.config.emitChunkEvents&&(n.events.TEXT_MESSAGE_START=!1,n.events.TEXT_MESSAGE_CONTENT=!1,n.events.TEXT_MESSAGE_END=!1,n.events.TEXT_MESSAGE_CHUNK=!0,n.events.TOOL_CALL_START=!1,n.events.TOOL_CALL_ARGS=!1,n.events.TOOL_CALL_END=!1,n.events.TOOL_CALL_CHUNK=!0,n.events.REASONING_MESSAGE_START=!1,n.events.REASONING_MESSAGE_CONTENT=!1,n.events.REASONING_MESSAGE_END=!1,n.events.REASONING_MESSAGE_CHUNK=!0),n}function p(e,t,n){let r=n&&typeof n==`object`&&`agent`in n?f(n.agent,n.overrides):d(n);e.get(t,(e,t)=>{t.json(r)})}async function m(e,t={}){let{path:n=`/`,pingPath:r=`/ping`,capabilitiesPath:i=`/capabilities`,capabilities:a,corsOrigin:o=!0}=t,s=await import(`express`),u=await import(`cors`),d=s.default??s,f=u.default??u,m=d();return m.use(f({origin:o,credentials:!0})),m.use(d.json({limit:`50mb`})),c(m,e,{path:n}),r&&l(m,r),i&&p(m,i,{agent:e,overrides:a}),m}export{u as DEFAULT_CAPABILITIES,p as addCapabilities,l as addPing,c as addStrandsExpressEndpoint,f as capabilitiesFor,m as createStrandsApp};
1
+ import{EventType as e,RunAgentInputSchema as t}from"@ag-ui/core";import{EventEncoder as n}from"@ag-ui/encoder";const r={thread_id:`threadId`,run_id:`runId`,parent_run_id:`parentRunId`,forwarded_props:`forwardedProps`,tool_call_id:`toolCallId`,parent_message_id:`parentMessageId`},i=new Set([`__proto__`,`constructor`,`prototype`]);function a(e){if(typeof e!=`object`||!e)return e;if(Array.isArray(e))return e.map(a);let t=e,n=Object.create(null);for(let[e,o]of Object.entries(t)){if(i.has(e))continue;let t=r[e]??e;t in n||(n[t]=typeof o==`object`&&o?a(o):o)}return n}function o(e){return!!(e.is(`application/json`)||e.is(`+json`))}function s(e){return e?e.split(`,`).map(e=>e.split(`;`)[0]?.trim().toLowerCase()??``).some(e=>e===`application/vnd.ag-ui.event+proto`):!1}function c(r,i,c){r.post(c.path,async(r,c)=>{if(!o(r)){c.status(415).json({error:`Unsupported Media Type: expected application/json`});return}let l=a(r.body),u=t.safeParse(l);if(!u.success){c.status(400).json({error:`Invalid RunAgentInput`,issues:u.error.issues.map(e=>({path:e.path,message:e.message}))});return}let d=u.data,f=r.header(`accept`)??void 0,p=s(f)?new n({accept:f}):new n({accept:`text/event-stream`}),m=p.getContentType();c.setHeader(`Content-Type`,m),c.setHeader(`Cache-Control`,`no-cache`),c.setHeader(`Connection`,`keep-alive`),c.flushHeaders?.();let h=e=>{if(!(c.destroyed||c.writableEnded))if(m===`text/event-stream`)c.write(p.encode(e));else{let t=p.encodeBinary(e);c.write(Buffer.from(t))}},g=i.run(d),_=!1,v=()=>{_||(_=!0,g.return?.().catch(()=>{}))};c.once(`close`,v),r.once(`aborted`,v);try{for(;!(_||c.writableEnded||c.destroyed);){let t;try{t=await g.next()}catch(t){if(!_&&!c.writableEnded)try{h({type:e.RUN_ERROR,message:t instanceof Error?t.message:String(t),code:`STRANDS_ERROR`})}catch{}break}if(t.done||_||c.writableEnded||c.destroyed)break;try{h(t.value)}catch(t){let n={type:e.RUN_ERROR,message:`Encoding error: ${String(t)}`,code:`ENCODING_ERROR`};try{h(n)}catch{}break}}}finally{c.removeListener(`close`,v),r.removeListener(`aborted`,v);try{await g.return?.()}catch{}c.writableEnded||c.end()}})}function l(e,t){e.get(t,(e,t)=>{t.json({status:`healthy`})})}const u={protocol:`1`,transports:{sse:!0,protobuf:!0,websocket:!1},events:{RUN_STARTED:!0,RUN_FINISHED:!0,RUN_ERROR:!0,TEXT_MESSAGE_START:!0,TEXT_MESSAGE_CONTENT:!0,TEXT_MESSAGE_END:!0,TEXT_MESSAGE_CHUNK:!1,TOOL_CALL_START:!0,TOOL_CALL_ARGS:!0,TOOL_CALL_END:!0,TOOL_CALL_RESULT:!0,TOOL_CALL_CHUNK:!1,STATE_SNAPSHOT:!0,STATE_DELTA:!1,MESSAGES_SNAPSHOT:!0,STEP_STARTED:!0,STEP_FINISHED:!0,REASONING_START:!0,REASONING_MESSAGE_START:!0,REASONING_MESSAGE_CONTENT:!0,REASONING_MESSAGE_END:!0,REASONING_MESSAGE_CHUNK:!1,REASONING_ENCRYPTED_VALUE:!0,REASONING_END:!0,CUSTOM:!0,ACTIVITY_SNAPSHOT:!1,ACTIVITY_DELTA:!1,RAW:!1},features:{interrupts:!0,toolCallInterruptEditedArgs:!0,resumableStreams:!1,messagesSnapshot:!0,stateDelta:!1,protobuf:!0,multipleRunsPerStream:!1}};function d(e){if(!e)return structuredClone(u);let t=(e,t)=>{let n={...e};if(!t)return n;for(let r of Object.keys(t))if(r in e){let e=t[r];typeof e==`boolean`&&(n[r]=e)}return n};return{protocol:e.protocol??u.protocol,transports:t(u.transports,e.transports),events:t(u.events,e.events),features:t(u.features,e.features)}}function f(e,t){let n=d(t);return e.config.emitChunkEvents&&(n.events.TEXT_MESSAGE_START=!1,n.events.TEXT_MESSAGE_CONTENT=!1,n.events.TEXT_MESSAGE_END=!1,n.events.TEXT_MESSAGE_CHUNK=!0,n.events.TOOL_CALL_START=!1,n.events.TOOL_CALL_ARGS=!1,n.events.TOOL_CALL_END=!1,n.events.TOOL_CALL_CHUNK=!0,n.events.REASONING_MESSAGE_START=!1,n.events.REASONING_MESSAGE_CONTENT=!1,n.events.REASONING_MESSAGE_END=!1,n.events.REASONING_MESSAGE_CHUNK=!0),n}function p(e,t,n){let r=n&&typeof n==`object`&&`agent`in n?f(n.agent,n.overrides):d(n);e.get(t,(e,t)=>{t.json(r)})}async function m(e,t={}){let{path:n=`/`,pingPath:r=`/ping`,capabilitiesPath:i=`/capabilities`,capabilities:a,corsOrigin:o=`*`}=t,s=await import(`express`),u=await import(`cors`),d=s.default??s,f=u.default??u,m=d();return m.use(f({origin:o,credentials:!0})),m.use(d.json({limit:`50mb`})),c(m,e,{path:n}),r&&l(m,r),i&&p(m,i,{agent:e,overrides:a}),m}export{u as DEFAULT_CAPABILITIES,p as addCapabilities,l as addPing,c as addStrandsExpressEndpoint,f as capabilitiesFor,m as createStrandsApp};
2
2
  //# sourceMappingURL=server.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.mjs","names":[],"sources":["../src/endpoint.ts","../src/server.ts"],"sourcesContent":["/** Express endpoint utilities for AWS Strands integration. */\n\nimport type { Express, Request, Response } from \"express\";\nimport {\n EventType,\n RunAgentInputSchema,\n type BaseEvent,\n type RunAgentInput,\n} from \"@ag-ui/core\";\nimport { EventEncoder } from \"@ag-ui/encoder\";\nimport type { StrandsAgent } from \"./agent\";\n\nexport interface AddStrandsEndpointOptions {\n path: string;\n}\n\n// The wire format is camelCase per the protocol, but the Python reference\n// server accepts snake_case aliases (pydantic `populate_by_name=True`). Mirror\n// that here so cross-SDK clients that send `thread_id` / `run_id` / etc. keep\n// working against the TS adapter.\nconst SNAKE_TO_CAMEL: Record<string, string> = {\n thread_id: \"threadId\",\n run_id: \"runId\",\n parent_run_id: \"parentRunId\",\n forwarded_props: \"forwardedProps\",\n tool_call_id: \"toolCallId\",\n parent_message_id: \"parentMessageId\",\n};\n\nconst UNSAFE_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\nfunction normalizeRunAgentInputKeys(raw: unknown): unknown {\n if (raw === null || typeof raw !== \"object\") return raw;\n if (Array.isArray(raw)) return raw.map(normalizeRunAgentInputKeys);\n const src = raw as Record<string, unknown>;\n const out: Record<string, unknown> = Object.create(null);\n for (const [key, value] of Object.entries(src)) {\n if (UNSAFE_KEYS.has(key)) continue;\n const target = SNAKE_TO_CAMEL[key] ?? key;\n if (target in out) continue;\n out[target] =\n value !== null && typeof value === \"object\"\n ? normalizeRunAgentInputKeys(value)\n : value;\n }\n return out;\n}\n\nfunction isJsonContentType(req: Request): boolean {\n // `req.is()` returns false for absent/mismatching Content-Type and tolerates\n // subtypes like `application/vnd.custom+json`.\n return Boolean(req.is(\"application/json\") || req.is(\"+json\"));\n}\n\n// Binary protobuf framing for AG-UI events. Only selected when the caller\n// explicitly mentions this media type in the Accept header — callers that\n// send `*/*` or omit Accept get SSE, which is the more forgiving format for\n// casual `curl -N` inspection and matches the protocol's default transport.\nconst PROTOBUF_MEDIA_TYPE = \"application/vnd.ag-ui.event+proto\";\n\nfunction clientExplicitlyRequestsProtobuf(accept: string | undefined): boolean {\n if (!accept) return false;\n return accept\n .split(\",\")\n .map((piece) => piece.split(\";\")[0]?.trim().toLowerCase() ?? \"\")\n .some((mt) => mt === PROTOBUF_MEDIA_TYPE);\n}\n\n/** Add a Strands agent endpoint to an Express app. */\nexport function addStrandsExpressEndpoint(\n app: Express,\n agent: StrandsAgent,\n options: AddStrandsEndpointOptions,\n): void {\n app.post(options.path, async (req: Request, res: Response) => {\n // Request boundary validation. Express's `express.json()` middleware\n // skips bodies whose Content-Type isn't JSON — it leaves `req.body` as\n // `{}` instead of rejecting, so silently invalid requests would otherwise\n // look indistinguishable from a request with an empty body. Reject them\n // here so the protocol contract (events.mdx §RunAgentInput) is enforced\n // at the HTTP edge rather than halfway through a streaming response.\n if (!isJsonContentType(req)) {\n res\n .status(415)\n .json({ error: \"Unsupported Media Type: expected application/json\" });\n return;\n }\n\n const normalized = normalizeRunAgentInputKeys(req.body);\n const parsed = RunAgentInputSchema.safeParse(normalized);\n if (!parsed.success) {\n res.status(400).json({\n error: \"Invalid RunAgentInput\",\n issues: parsed.error.issues.map((i) => ({\n path: i.path,\n message: i.message,\n })),\n });\n return;\n }\n // Preserve the resume[] field if present — the protocol schema validates\n // its shape, but passes opaque payloads through unchanged for the adapter\n // to inspect (see {@link StrandsAgent._runRaw} interrupt-rule enforcement).\n const inputData: RunAgentInput = parsed.data;\n\n const acceptHeader = req.header(\"accept\") ?? undefined;\n // Only hand the encoder the Accept header when the caller explicitly\n // opted into protobuf. Otherwise force SSE so `Accept: */*` doesn't\n // surprise callers with binary frames — the encoder's media-type\n // sort ranks protobuf above SSE for wildcard Accepts.\n const encoder = clientExplicitlyRequestsProtobuf(acceptHeader)\n ? new EventEncoder({ accept: acceptHeader })\n : new EventEncoder({ accept: \"text/event-stream\" });\n const contentType = encoder.getContentType();\n\n res.setHeader(\"Content-Type\", contentType);\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n res.flushHeaders?.();\n\n const writeEvent = (event: BaseEvent): void => {\n // Guard against writes to a socket the client has already dropped.\n // `res.write()` on a destroyed socket throws ERR_STREAM_DESTROYED in\n // recent Node versions; older versions silently no-op. Short-circuit\n // either way so the main loop sees the disconnect on the next\n // iteration.\n if (res.destroyed || res.writableEnded) return;\n if (contentType === \"text/event-stream\") {\n res.write(encoder.encode(event));\n } else {\n const bytes = encoder.encodeBinary(event);\n res.write(Buffer.from(bytes));\n }\n };\n\n // Hold an explicit iterator so we can call `.return()` on client\n // disconnect. Without this, `res.write()` silently buffers into a\n // closed socket and the agent generator's `finally` never runs —\n // in particular, THREAD_BUSY slots never release, wedging the thread.\n const iterator = agent.run(inputData);\n let clientDisconnected = false;\n const onDisconnect = (): void => {\n if (clientDisconnected) return;\n clientDisconnected = true;\n // Fire-and-forget — the iterator's own finally will settle the\n // active-runs set, session manager, etc. A throwing finally inside\n // the generator (e.g. a cleanup hook) must NOT surface as an\n // unhandled rejection and crash the Node process, so swallow here.\n iterator.return?.().catch(() => {\n /* intentional swallow — disconnect path */\n });\n };\n // HTTP/1.1 fires `close` on the Response when the socket closes;\n // HTTP/2 reliably fires `aborted` on the Request. Listen to both so\n // disconnects under both transports trigger cleanup.\n res.once(\"close\", onDisconnect);\n req.once(\"aborted\", onDisconnect);\n\n try {\n while (true) {\n if (clientDisconnected || res.writableEnded || res.destroyed) break;\n let step: IteratorResult<BaseEvent, void>;\n try {\n step = await iterator.next();\n } catch (e) {\n // Uncaught error from the generator (should be rare; agent.run()\n // normally wraps exceptions as RUN_ERROR itself).\n if (!clientDisconnected && !res.writableEnded) {\n try {\n writeEvent({\n type: EventType.RUN_ERROR,\n message: e instanceof Error ? e.message : String(e),\n code: \"STRANDS_ERROR\",\n });\n } catch {\n // ignore\n }\n }\n break;\n }\n if (step.done) break;\n if (clientDisconnected || res.writableEnded || res.destroyed) break;\n try {\n writeEvent(step.value);\n } catch (e) {\n // Encoder failure. Try to deliver a RUN_ERROR, then bail.\n const errEvent: BaseEvent = {\n type: EventType.RUN_ERROR,\n message: `Encoding error: ${String(e)}`,\n code: \"ENCODING_ERROR\",\n };\n try {\n writeEvent(errEvent);\n } catch {\n // Swallow — response might already be broken.\n }\n break;\n }\n }\n } finally {\n res.removeListener(\"close\", onDisconnect);\n req.removeListener(\"aborted\", onDisconnect);\n // Make sure the generator shuts down even if we broke out without\n // consuming everything — idempotent when already exhausted.\n try {\n await iterator.return?.();\n } catch {\n // ignore\n }\n if (!res.writableEnded) res.end();\n }\n });\n}\n\n/** Add a ping endpoint returning `{status: \"healthy\"}`. */\nexport function addPing(app: Express, path: string): void {\n app.get(path, (_req, res) => {\n res.json({ status: \"healthy\" });\n });\n}\n\n/**\n * Static description of what this adapter actually supports. Every event\n * family here can be observed on the wire; anything missing is either not\n * emitted by this adapter (e.g. `ACTIVITY_*`, `RAW`) or only emitted in\n * specific configurations (the `*_CHUNK` events, gated by\n * `emitChunkEvents` — use {@link capabilitiesFor} to derive the matrix\n * from a concrete agent and pick those flags up automatically).\n *\n * Exported as a plain object so consumers can fold overrides in — for\n * example, advertising `events.ACTIVITY_SNAPSHOT: true` after wiring a\n * `customResultHandler` that emits those events themselves.\n */\nexport interface StrandsAguiCapabilities {\n /** Semver of the AG-UI contract surface this adapter targets. */\n protocol: string;\n /** Content types the HTTP endpoint can stream. */\n transports: { sse: boolean; protobuf: boolean; websocket: boolean };\n /** Event families the adapter emits. Per-event flags, not categories. */\n events: {\n RUN_STARTED: boolean;\n RUN_FINISHED: boolean;\n RUN_ERROR: boolean;\n TEXT_MESSAGE_START: boolean;\n TEXT_MESSAGE_CONTENT: boolean;\n TEXT_MESSAGE_END: boolean;\n TEXT_MESSAGE_CHUNK: boolean;\n TOOL_CALL_START: boolean;\n TOOL_CALL_ARGS: boolean;\n TOOL_CALL_END: boolean;\n TOOL_CALL_RESULT: boolean;\n TOOL_CALL_CHUNK: boolean;\n STATE_SNAPSHOT: boolean;\n STATE_DELTA: boolean;\n MESSAGES_SNAPSHOT: boolean;\n STEP_STARTED: boolean;\n STEP_FINISHED: boolean;\n REASONING_START: boolean;\n REASONING_MESSAGE_START: boolean;\n REASONING_MESSAGE_CONTENT: boolean;\n REASONING_MESSAGE_END: boolean;\n REASONING_MESSAGE_CHUNK: boolean;\n REASONING_ENCRYPTED_VALUE: boolean;\n REASONING_END: boolean;\n CUSTOM: boolean;\n ACTIVITY_SNAPSHOT: boolean;\n ACTIVITY_DELTA: boolean;\n RAW: boolean;\n };\n /** Protocol feature flags advertised to the client. */\n features: {\n /** RunFinished.outcome interrupt + RunAgentInput.resume loop. */\n interrupts: boolean;\n /** Tool-call interrupts accept editedArgs in the resume payload. */\n toolCallInterruptEditedArgs: boolean;\n /** Resumable streams with sequence numbers. Unsupported. */\n resumableStreams: boolean;\n /** Adapter emits MESSAGES_SNAPSHOT at run lifecycle boundaries (Python parity). */\n messagesSnapshot: boolean;\n /** State delta via RFC 6902 JSON Patch. Only when a customResultHandler emits them. */\n stateDelta: boolean;\n /** Binary protobuf content negotiation (explicit Accept header). */\n protobuf: boolean;\n /** Multiple sequential runs in one HTTP stream. One run per POST. */\n multipleRunsPerStream: boolean;\n };\n}\n\n/** Default capabilities advertised by {@link addCapabilities}. */\nexport const DEFAULT_CAPABILITIES: StrandsAguiCapabilities = {\n protocol: \"1\",\n transports: { sse: true, protobuf: true, websocket: false },\n events: {\n RUN_STARTED: true,\n RUN_FINISHED: true,\n RUN_ERROR: true,\n TEXT_MESSAGE_START: true,\n TEXT_MESSAGE_CONTENT: true,\n TEXT_MESSAGE_END: true,\n TEXT_MESSAGE_CHUNK: false,\n TOOL_CALL_START: true,\n TOOL_CALL_ARGS: true,\n TOOL_CALL_END: true,\n TOOL_CALL_RESULT: true,\n TOOL_CALL_CHUNK: false,\n STATE_SNAPSHOT: true,\n STATE_DELTA: false,\n MESSAGES_SNAPSHOT: true,\n STEP_STARTED: true,\n STEP_FINISHED: true,\n REASONING_START: true,\n REASONING_MESSAGE_START: true,\n REASONING_MESSAGE_CONTENT: true,\n REASONING_MESSAGE_END: true,\n REASONING_MESSAGE_CHUNK: false,\n REASONING_ENCRYPTED_VALUE: true,\n REASONING_END: true,\n CUSTOM: true,\n ACTIVITY_SNAPSHOT: false,\n ACTIVITY_DELTA: false,\n RAW: false,\n },\n features: {\n interrupts: true,\n toolCallInterruptEditedArgs: true,\n resumableStreams: false,\n messagesSnapshot: true,\n stateDelta: false,\n protobuf: true,\n multipleRunsPerStream: false,\n },\n};\n\n/** One level of sub-field partiality — shallow `Partial<>` on nested objects. */\nexport type StrandsAguiCapabilitiesOverrides = {\n protocol?: StrandsAguiCapabilities[\"protocol\"];\n transports?: Partial<StrandsAguiCapabilities[\"transports\"]>;\n events?: Partial<StrandsAguiCapabilities[\"events\"]>;\n features?: Partial<StrandsAguiCapabilities[\"features\"]>;\n};\n\n/**\n * Deep-merge consumer overrides on top of the default capabilities. Unknown\n * keys in `events` / `features` / `transports` are dropped (typos shouldn't\n * silently pollute the advertised matrix).\n */\nfunction mergeCapabilities(\n overrides?: StrandsAguiCapabilitiesOverrides,\n): StrandsAguiCapabilities {\n if (!overrides) return structuredClone(DEFAULT_CAPABILITIES);\n const pick = <K extends string>(\n defaults: Record<K, boolean>,\n override: Partial<Record<K, boolean>> | undefined,\n ): Record<K, boolean> => {\n const out = { ...defaults };\n if (!override) return out;\n for (const key of Object.keys(override) as K[]) {\n if (key in defaults) {\n const v = override[key];\n if (typeof v === \"boolean\") out[key] = v;\n }\n // Silently drop unknown keys — typos shouldn't leak into the JSON.\n }\n return out;\n };\n return {\n protocol: overrides.protocol ?? DEFAULT_CAPABILITIES.protocol,\n transports: pick(DEFAULT_CAPABILITIES.transports, overrides.transports),\n events: pick(DEFAULT_CAPABILITIES.events, overrides.events),\n features: pick(DEFAULT_CAPABILITIES.features, overrides.features),\n };\n}\n\n/**\n * Derive capabilities from a concrete StrandsAgent instance, flipping the\n * chunk-event flags based on whether the agent is configured to emit chunks.\n * When chunks are on, the explicit triples are suppressed, so the advertised\n * matrix reflects what the client will actually observe.\n */\nexport function capabilitiesFor(\n agent: { config: { emitChunkEvents?: boolean } },\n overrides?: StrandsAguiCapabilitiesOverrides,\n): StrandsAguiCapabilities {\n const base = mergeCapabilities(overrides);\n if (agent.config.emitChunkEvents) {\n base.events.TEXT_MESSAGE_START = false;\n base.events.TEXT_MESSAGE_CONTENT = false;\n base.events.TEXT_MESSAGE_END = false;\n base.events.TEXT_MESSAGE_CHUNK = true;\n base.events.TOOL_CALL_START = false;\n base.events.TOOL_CALL_ARGS = false;\n base.events.TOOL_CALL_END = false;\n base.events.TOOL_CALL_CHUNK = true;\n base.events.REASONING_MESSAGE_START = false;\n base.events.REASONING_MESSAGE_CONTENT = false;\n base.events.REASONING_MESSAGE_END = false;\n base.events.REASONING_MESSAGE_CHUNK = true;\n }\n return base;\n}\n\n/**\n * Add a capabilities-advertisement endpoint.\n *\n * Frontends can GET this path to discover which AG-UI event families and\n * protocol features the adapter supports, without having to probe empirically.\n *\n * Two forms:\n * - `addCapabilities(app, path, overrides?)` — static matrix (back-compat).\n * - `addCapabilities(app, path, { agent })` — derives the matrix from a live\n * `StrandsAgent`, picking up `emitChunkEvents` automatically.\n */\nexport function addCapabilities(\n app: Express,\n path: string,\n capabilities?:\n | StrandsAguiCapabilitiesOverrides\n | {\n agent: { config: { emitChunkEvents?: boolean } };\n overrides?: StrandsAguiCapabilitiesOverrides;\n },\n): void {\n const resolved =\n capabilities && typeof capabilities === \"object\" && \"agent\" in capabilities\n ? capabilitiesFor(capabilities.agent, capabilities.overrides)\n : mergeCapabilities(\n capabilities as StrandsAguiCapabilitiesOverrides | undefined,\n );\n app.get(path, (_req, res) => {\n res.json(resolved);\n });\n}\n","/**\n * Server-side entry point for `@ag-ui/aws-strands`.\n *\n * Import from `@ag-ui/aws-strands/server` when you need the Express transport\n * helpers. The main entry point (`@ag-ui/aws-strands`) stays free of Express\n * / cors references so Next.js / Turbopack / Vite bundlers tracing the\n * client-side graph don't pull server-only modules into the browser build.\n */\n\nimport {\n addStrandsExpressEndpoint,\n addPing,\n addCapabilities,\n} from \"./endpoint\";\nimport type { StrandsAgent } from \"./agent\";\nimport type { StrandsAguiCapabilitiesOverrides } from \"./endpoint\";\n\nexport {\n addStrandsExpressEndpoint,\n addPing,\n addCapabilities,\n capabilitiesFor,\n DEFAULT_CAPABILITIES,\n} from \"./endpoint\";\n\nexport type {\n AddStrandsEndpointOptions,\n StrandsAguiCapabilities,\n StrandsAguiCapabilitiesOverrides,\n} from \"./endpoint\";\n\nexport interface CreateStrandsAppOptions {\n /** Path for the agent endpoint. Default `/`. */\n path?: string;\n /** Path for the ping endpoint. Pass `null` or `\"\"` to disable. Default `/ping`. */\n pingPath?: string | null;\n /**\n * Path for the capabilities endpoint. Pass `null` or `\"\"` to disable.\n * Default `/capabilities`.\n */\n capabilitiesPath?: string | null;\n /** Override capabilities advertised at {@link CreateStrandsAppOptions.capabilitiesPath}. */\n capabilities?: StrandsAguiCapabilitiesOverrides;\n /** Override CORS origin. Default `*` (wide-open, matches the Python adapter). */\n corsOrigin?: string | string[] | boolean;\n}\n\n/** Create an Express app with a single Strands agent endpoint and optional ping endpoint. */\nexport async function createStrandsApp(\n agent: StrandsAgent,\n options: CreateStrandsAppOptions = {},\n): Promise<import(\"express\").Express> {\n const {\n path = \"/\",\n pingPath = \"/ping\",\n capabilitiesPath = \"/capabilities\",\n capabilities,\n corsOrigin = true,\n } = options;\n\n // Lazy dynamic imports so `express` / `cors` are only required at runtime\n // when `createStrandsApp` is actually called.\n const expressModule = await import(\"express\");\n const corsModule = await import(\"cors\");\n const express = (expressModule.default ??\n expressModule) as typeof import(\"express\");\n const cors = (corsModule.default ?? corsModule) as typeof import(\"cors\");\n\n const app = express();\n app.use(cors({ origin: corsOrigin, credentials: true }));\n app.use(express.json({ limit: \"50mb\" }));\n\n addStrandsExpressEndpoint(app, agent, { path });\n\n if (pingPath) {\n addPing(app, pingPath);\n }\n\n if (capabilitiesPath) {\n addCapabilities(app, capabilitiesPath, { agent, overrides: capabilities });\n }\n\n return app;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"server.mjs","names":[],"sources":["../src/endpoint.ts","../src/server.ts"],"sourcesContent":["/** Express endpoint utilities for AWS Strands integration. */\n\nimport type { Express, Request, Response } from \"express\";\nimport {\n EventType,\n RunAgentInputSchema,\n type BaseEvent,\n type RunAgentInput,\n} from \"@ag-ui/core\";\nimport { EventEncoder } from \"@ag-ui/encoder\";\nimport type { StrandsAgent } from \"./agent\";\n\nexport interface AddStrandsEndpointOptions {\n path: string;\n}\n\n// The wire format is camelCase per the protocol, but the Python reference\n// server accepts snake_case aliases (pydantic `populate_by_name=True`). Mirror\n// that here so cross-SDK clients that send `thread_id` / `run_id` / etc. keep\n// working against the TS adapter.\nconst SNAKE_TO_CAMEL: Record<string, string> = {\n thread_id: \"threadId\",\n run_id: \"runId\",\n parent_run_id: \"parentRunId\",\n forwarded_props: \"forwardedProps\",\n tool_call_id: \"toolCallId\",\n parent_message_id: \"parentMessageId\",\n};\n\nconst UNSAFE_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\nfunction normalizeRunAgentInputKeys(raw: unknown): unknown {\n if (raw === null || typeof raw !== \"object\") return raw;\n if (Array.isArray(raw)) return raw.map(normalizeRunAgentInputKeys);\n const src = raw as Record<string, unknown>;\n const out: Record<string, unknown> = Object.create(null);\n for (const [key, value] of Object.entries(src)) {\n if (UNSAFE_KEYS.has(key)) continue;\n const target = SNAKE_TO_CAMEL[key] ?? key;\n if (target in out) continue;\n out[target] =\n value !== null && typeof value === \"object\"\n ? normalizeRunAgentInputKeys(value)\n : value;\n }\n return out;\n}\n\nfunction isJsonContentType(req: Request): boolean {\n // `req.is()` returns false for absent/mismatching Content-Type and tolerates\n // subtypes like `application/vnd.custom+json`.\n return Boolean(req.is(\"application/json\") || req.is(\"+json\"));\n}\n\n// Binary protobuf framing for AG-UI events. Only selected when the caller\n// explicitly mentions this media type in the Accept header — callers that\n// send `*/*` or omit Accept get SSE, which is the more forgiving format for\n// casual `curl -N` inspection and matches the protocol's default transport.\nconst PROTOBUF_MEDIA_TYPE = \"application/vnd.ag-ui.event+proto\";\n\nfunction clientExplicitlyRequestsProtobuf(accept: string | undefined): boolean {\n if (!accept) return false;\n return accept\n .split(\",\")\n .map((piece) => piece.split(\";\")[0]?.trim().toLowerCase() ?? \"\")\n .some((mt) => mt === PROTOBUF_MEDIA_TYPE);\n}\n\n/** Add a Strands agent endpoint to an Express app. */\nexport function addStrandsExpressEndpoint(\n app: Express,\n agent: StrandsAgent,\n options: AddStrandsEndpointOptions,\n): void {\n app.post(options.path, async (req: Request, res: Response) => {\n // Request boundary validation. Express's `express.json()` middleware\n // skips bodies whose Content-Type isn't JSON — it leaves `req.body` as\n // `{}` instead of rejecting, so silently invalid requests would otherwise\n // look indistinguishable from a request with an empty body. Reject them\n // here so the protocol contract (events.mdx §RunAgentInput) is enforced\n // at the HTTP edge rather than halfway through a streaming response.\n if (!isJsonContentType(req)) {\n res\n .status(415)\n .json({ error: \"Unsupported Media Type: expected application/json\" });\n return;\n }\n\n const normalized = normalizeRunAgentInputKeys(req.body);\n const parsed = RunAgentInputSchema.safeParse(normalized);\n if (!parsed.success) {\n res.status(400).json({\n error: \"Invalid RunAgentInput\",\n issues: parsed.error.issues.map((i) => ({\n path: i.path,\n message: i.message,\n })),\n });\n return;\n }\n // Preserve the resume[] field if present — the protocol schema validates\n // its shape, but passes opaque payloads through unchanged for the adapter\n // to inspect (see {@link StrandsAgent._runRaw} interrupt-rule enforcement).\n const inputData: RunAgentInput = parsed.data;\n\n const acceptHeader = req.header(\"accept\") ?? undefined;\n // Only hand the encoder the Accept header when the caller explicitly\n // opted into protobuf. Otherwise force SSE so `Accept: */*` doesn't\n // surprise callers with binary frames — the encoder's media-type\n // sort ranks protobuf above SSE for wildcard Accepts.\n const encoder = clientExplicitlyRequestsProtobuf(acceptHeader)\n ? new EventEncoder({ accept: acceptHeader })\n : new EventEncoder({ accept: \"text/event-stream\" });\n const contentType = encoder.getContentType();\n\n res.setHeader(\"Content-Type\", contentType);\n res.setHeader(\"Cache-Control\", \"no-cache\");\n res.setHeader(\"Connection\", \"keep-alive\");\n res.flushHeaders?.();\n\n const writeEvent = (event: BaseEvent): void => {\n // Guard against writes to a socket the client has already dropped.\n // `res.write()` on a destroyed socket throws ERR_STREAM_DESTROYED in\n // recent Node versions; older versions silently no-op. Short-circuit\n // either way so the main loop sees the disconnect on the next\n // iteration.\n if (res.destroyed || res.writableEnded) return;\n if (contentType === \"text/event-stream\") {\n res.write(encoder.encode(event));\n } else {\n const bytes = encoder.encodeBinary(event);\n res.write(Buffer.from(bytes));\n }\n };\n\n // Hold an explicit iterator so we can call `.return()` on client\n // disconnect. Without this, `res.write()` silently buffers into a\n // closed socket and the agent generator's `finally` never runs —\n // in particular, THREAD_BUSY slots never release, wedging the thread.\n const iterator = agent.run(inputData);\n let clientDisconnected = false;\n const onDisconnect = (): void => {\n if (clientDisconnected) return;\n clientDisconnected = true;\n // Fire-and-forget — the iterator's own finally will settle the\n // active-runs set, session manager, etc. A throwing finally inside\n // the generator (e.g. a cleanup hook) must NOT surface as an\n // unhandled rejection and crash the Node process, so swallow here.\n iterator.return?.().catch(() => {\n /* intentional swallow — disconnect path */\n });\n };\n // HTTP/1.1 fires `close` on the Response when the socket closes;\n // HTTP/2 reliably fires `aborted` on the Request. Listen to both so\n // disconnects under both transports trigger cleanup.\n res.once(\"close\", onDisconnect);\n req.once(\"aborted\", onDisconnect);\n\n try {\n while (true) {\n if (clientDisconnected || res.writableEnded || res.destroyed) break;\n let step: IteratorResult<BaseEvent, void>;\n try {\n step = await iterator.next();\n } catch (e) {\n // Uncaught error from the generator (should be rare; agent.run()\n // normally wraps exceptions as RUN_ERROR itself).\n if (!clientDisconnected && !res.writableEnded) {\n try {\n writeEvent({\n type: EventType.RUN_ERROR,\n message: e instanceof Error ? e.message : String(e),\n code: \"STRANDS_ERROR\",\n });\n } catch {\n // ignore\n }\n }\n break;\n }\n if (step.done) break;\n if (clientDisconnected || res.writableEnded || res.destroyed) break;\n try {\n writeEvent(step.value);\n } catch (e) {\n // Encoder failure. Try to deliver a RUN_ERROR, then bail.\n const errEvent: BaseEvent = {\n type: EventType.RUN_ERROR,\n message: `Encoding error: ${String(e)}`,\n code: \"ENCODING_ERROR\",\n };\n try {\n writeEvent(errEvent);\n } catch {\n // Swallow — response might already be broken.\n }\n break;\n }\n }\n } finally {\n res.removeListener(\"close\", onDisconnect);\n req.removeListener(\"aborted\", onDisconnect);\n // Make sure the generator shuts down even if we broke out without\n // consuming everything — idempotent when already exhausted.\n try {\n await iterator.return?.();\n } catch {\n // ignore\n }\n if (!res.writableEnded) res.end();\n }\n });\n}\n\n/** Add a ping endpoint returning `{status: \"healthy\"}`. */\nexport function addPing(app: Express, path: string): void {\n app.get(path, (_req, res) => {\n res.json({ status: \"healthy\" });\n });\n}\n\n/**\n * Static description of what this adapter actually supports. Every event\n * family here can be observed on the wire; anything missing is either not\n * emitted by this adapter (e.g. `ACTIVITY_*`, `RAW`) or only emitted in\n * specific configurations (the `*_CHUNK` events, gated by\n * `emitChunkEvents` — use {@link capabilitiesFor} to derive the matrix\n * from a concrete agent and pick those flags up automatically).\n *\n * Exported as a plain object so consumers can fold overrides in — for\n * example, advertising `events.ACTIVITY_SNAPSHOT: true` after wiring a\n * `customResultHandler` that emits those events themselves.\n */\nexport interface StrandsAguiCapabilities {\n /** Semver of the AG-UI contract surface this adapter targets. */\n protocol: string;\n /** Content types the HTTP endpoint can stream. */\n transports: { sse: boolean; protobuf: boolean; websocket: boolean };\n /** Event families the adapter emits. Per-event flags, not categories. */\n events: {\n RUN_STARTED: boolean;\n RUN_FINISHED: boolean;\n RUN_ERROR: boolean;\n TEXT_MESSAGE_START: boolean;\n TEXT_MESSAGE_CONTENT: boolean;\n TEXT_MESSAGE_END: boolean;\n TEXT_MESSAGE_CHUNK: boolean;\n TOOL_CALL_START: boolean;\n TOOL_CALL_ARGS: boolean;\n TOOL_CALL_END: boolean;\n TOOL_CALL_RESULT: boolean;\n TOOL_CALL_CHUNK: boolean;\n STATE_SNAPSHOT: boolean;\n STATE_DELTA: boolean;\n MESSAGES_SNAPSHOT: boolean;\n STEP_STARTED: boolean;\n STEP_FINISHED: boolean;\n REASONING_START: boolean;\n REASONING_MESSAGE_START: boolean;\n REASONING_MESSAGE_CONTENT: boolean;\n REASONING_MESSAGE_END: boolean;\n REASONING_MESSAGE_CHUNK: boolean;\n REASONING_ENCRYPTED_VALUE: boolean;\n REASONING_END: boolean;\n CUSTOM: boolean;\n ACTIVITY_SNAPSHOT: boolean;\n ACTIVITY_DELTA: boolean;\n RAW: boolean;\n };\n /** Protocol feature flags advertised to the client. */\n features: {\n /** RunFinished.outcome interrupt + RunAgentInput.resume loop. */\n interrupts: boolean;\n /** Tool-call interrupts accept editedArgs in the resume payload. */\n toolCallInterruptEditedArgs: boolean;\n /** Resumable streams with sequence numbers. Unsupported. */\n resumableStreams: boolean;\n /** Adapter emits MESSAGES_SNAPSHOT at run lifecycle boundaries (Python parity). */\n messagesSnapshot: boolean;\n /** State delta via RFC 6902 JSON Patch. Only when a customResultHandler emits them. */\n stateDelta: boolean;\n /** Binary protobuf content negotiation (explicit Accept header). */\n protobuf: boolean;\n /** Multiple sequential runs in one HTTP stream. One run per POST. */\n multipleRunsPerStream: boolean;\n };\n}\n\n/** Default capabilities advertised by {@link addCapabilities}. */\nexport const DEFAULT_CAPABILITIES: StrandsAguiCapabilities = {\n protocol: \"1\",\n transports: { sse: true, protobuf: true, websocket: false },\n events: {\n RUN_STARTED: true,\n RUN_FINISHED: true,\n RUN_ERROR: true,\n TEXT_MESSAGE_START: true,\n TEXT_MESSAGE_CONTENT: true,\n TEXT_MESSAGE_END: true,\n TEXT_MESSAGE_CHUNK: false,\n TOOL_CALL_START: true,\n TOOL_CALL_ARGS: true,\n TOOL_CALL_END: true,\n TOOL_CALL_RESULT: true,\n TOOL_CALL_CHUNK: false,\n STATE_SNAPSHOT: true,\n STATE_DELTA: false,\n MESSAGES_SNAPSHOT: true,\n STEP_STARTED: true,\n STEP_FINISHED: true,\n REASONING_START: true,\n REASONING_MESSAGE_START: true,\n REASONING_MESSAGE_CONTENT: true,\n REASONING_MESSAGE_END: true,\n REASONING_MESSAGE_CHUNK: false,\n REASONING_ENCRYPTED_VALUE: true,\n REASONING_END: true,\n CUSTOM: true,\n ACTIVITY_SNAPSHOT: false,\n ACTIVITY_DELTA: false,\n RAW: false,\n },\n features: {\n interrupts: true,\n toolCallInterruptEditedArgs: true,\n resumableStreams: false,\n messagesSnapshot: true,\n stateDelta: false,\n protobuf: true,\n multipleRunsPerStream: false,\n },\n};\n\n/** One level of sub-field partiality — shallow `Partial<>` on nested objects. */\nexport type StrandsAguiCapabilitiesOverrides = {\n protocol?: StrandsAguiCapabilities[\"protocol\"];\n transports?: Partial<StrandsAguiCapabilities[\"transports\"]>;\n events?: Partial<StrandsAguiCapabilities[\"events\"]>;\n features?: Partial<StrandsAguiCapabilities[\"features\"]>;\n};\n\n/**\n * Deep-merge consumer overrides on top of the default capabilities. Unknown\n * keys in `events` / `features` / `transports` are dropped (typos shouldn't\n * silently pollute the advertised matrix).\n */\nfunction mergeCapabilities(\n overrides?: StrandsAguiCapabilitiesOverrides,\n): StrandsAguiCapabilities {\n if (!overrides) return structuredClone(DEFAULT_CAPABILITIES);\n const pick = <K extends string>(\n defaults: Record<K, boolean>,\n override: Partial<Record<K, boolean>> | undefined,\n ): Record<K, boolean> => {\n const out = { ...defaults };\n if (!override) return out;\n for (const key of Object.keys(override) as K[]) {\n if (key in defaults) {\n const v = override[key];\n if (typeof v === \"boolean\") out[key] = v;\n }\n // Silently drop unknown keys — typos shouldn't leak into the JSON.\n }\n return out;\n };\n return {\n protocol: overrides.protocol ?? DEFAULT_CAPABILITIES.protocol,\n transports: pick(DEFAULT_CAPABILITIES.transports, overrides.transports),\n events: pick(DEFAULT_CAPABILITIES.events, overrides.events),\n features: pick(DEFAULT_CAPABILITIES.features, overrides.features),\n };\n}\n\n/**\n * Derive capabilities from a concrete StrandsAgent instance, flipping the\n * chunk-event flags based on whether the agent is configured to emit chunks.\n * When chunks are on, the explicit triples are suppressed, so the advertised\n * matrix reflects what the client will actually observe.\n */\nexport function capabilitiesFor(\n agent: { config: { emitChunkEvents?: boolean } },\n overrides?: StrandsAguiCapabilitiesOverrides,\n): StrandsAguiCapabilities {\n const base = mergeCapabilities(overrides);\n if (agent.config.emitChunkEvents) {\n base.events.TEXT_MESSAGE_START = false;\n base.events.TEXT_MESSAGE_CONTENT = false;\n base.events.TEXT_MESSAGE_END = false;\n base.events.TEXT_MESSAGE_CHUNK = true;\n base.events.TOOL_CALL_START = false;\n base.events.TOOL_CALL_ARGS = false;\n base.events.TOOL_CALL_END = false;\n base.events.TOOL_CALL_CHUNK = true;\n base.events.REASONING_MESSAGE_START = false;\n base.events.REASONING_MESSAGE_CONTENT = false;\n base.events.REASONING_MESSAGE_END = false;\n base.events.REASONING_MESSAGE_CHUNK = true;\n }\n return base;\n}\n\n/**\n * Add a capabilities-advertisement endpoint.\n *\n * Frontends can GET this path to discover which AG-UI event families and\n * protocol features the adapter supports, without having to probe empirically.\n *\n * Two forms:\n * - `addCapabilities(app, path, overrides?)` — static matrix (back-compat).\n * - `addCapabilities(app, path, { agent })` — derives the matrix from a live\n * `StrandsAgent`, picking up `emitChunkEvents` automatically.\n */\nexport function addCapabilities(\n app: Express,\n path: string,\n capabilities?:\n | StrandsAguiCapabilitiesOverrides\n | {\n agent: { config: { emitChunkEvents?: boolean } };\n overrides?: StrandsAguiCapabilitiesOverrides;\n },\n): void {\n const resolved =\n capabilities && typeof capabilities === \"object\" && \"agent\" in capabilities\n ? capabilitiesFor(capabilities.agent, capabilities.overrides)\n : mergeCapabilities(\n capabilities as StrandsAguiCapabilitiesOverrides | undefined,\n );\n app.get(path, (_req, res) => {\n res.json(resolved);\n });\n}\n","/**\n * Server-side entry point for `@ag-ui/aws-strands`.\n *\n * Import from `@ag-ui/aws-strands/server` when you need the Express transport\n * helpers. The main entry point (`@ag-ui/aws-strands`) stays free of Express\n * / cors references so Next.js / Turbopack / Vite bundlers tracing the\n * client-side graph don't pull server-only modules into the browser build.\n */\n\nimport {\n addStrandsExpressEndpoint,\n addPing,\n addCapabilities,\n} from \"./endpoint\";\nimport type { StrandsAgent } from \"./agent\";\nimport type { StrandsAguiCapabilitiesOverrides } from \"./endpoint\";\n\nexport {\n addStrandsExpressEndpoint,\n addPing,\n addCapabilities,\n capabilitiesFor,\n DEFAULT_CAPABILITIES,\n} from \"./endpoint\";\n\nexport type {\n AddStrandsEndpointOptions,\n StrandsAguiCapabilities,\n StrandsAguiCapabilitiesOverrides,\n} from \"./endpoint\";\n\nexport interface CreateStrandsAppOptions {\n /** Path for the agent endpoint. Default `/`. */\n path?: string;\n /** Path for the ping endpoint. Pass `null` or `\"\"` to disable. Default `/ping`. */\n pingPath?: string | null;\n /**\n * Path for the capabilities endpoint. Pass `null` or `\"\"` to disable.\n * Default `/capabilities`.\n */\n capabilitiesPath?: string | null;\n /** Override capabilities advertised at {@link CreateStrandsAppOptions.capabilitiesPath}. */\n capabilities?: StrandsAguiCapabilitiesOverrides;\n /**\n * Override CORS origin. Default `\"*\"` (wide-open, matches the Python adapter,\n * which configures Starlette `CORSMiddleware` with `allow_origins=[\"*\"]`).\n *\n * Note: with the `cors` package, a literal `\"*\"` is emitted verbatim as\n * `Access-Control-Allow-Origin: *`, whereas `true` would reflect the request's\n * `Origin` header back per-request — a different (more permissive) posture when\n * combined with credentials. Stick to `\"*\"` to match the Python adapter.\n */\n corsOrigin?: string | string[] | boolean;\n}\n\n/** Create an Express app with a single Strands agent endpoint and optional ping endpoint. */\nexport async function createStrandsApp(\n agent: StrandsAgent,\n options: CreateStrandsAppOptions = {},\n): Promise<import(\"express\").Express> {\n const {\n path = \"/\",\n pingPath = \"/ping\",\n capabilitiesPath = \"/capabilities\",\n capabilities,\n corsOrigin = \"*\",\n } = options;\n\n // Lazy dynamic imports so `express` / `cors` are only required at runtime\n // when `createStrandsApp` is actually called.\n const expressModule = await import(\"express\");\n const corsModule = await import(\"cors\");\n const express = (expressModule.default ??\n expressModule) as typeof import(\"express\");\n const cors = (corsModule.default ?? corsModule) as typeof import(\"cors\");\n\n const app = express();\n app.use(cors({ origin: corsOrigin, credentials: true }));\n app.use(express.json({ limit: \"50mb\" }));\n\n addStrandsExpressEndpoint(app, agent, { path });\n\n if (pingPath) {\n addPing(app, pingPath);\n }\n\n if (capabilitiesPath) {\n addCapabilities(app, capabilitiesPath, { agent, overrides: capabilities });\n }\n\n return app;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,11 @@
1
1
  {
2
2
  "name": "@ag-ui/aws-strands",
3
3
  "author": "AG-UI Contributors",
4
- "version": "0.1.0",
4
+ "version": "0.2.0",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "https://github.com/ag-ui-protocol/ag-ui.git"
8
+ },
5
9
  "description": "AWS Strands Agents integration for the AG-UI protocol",
6
10
  "publishConfig": {
7
11
  "access": "public"
@@ -14,6 +18,7 @@
14
18
  "dist/**"
15
19
  ],
16
20
  "peerDependencies": {
21
+ "@ag-ui/a2ui-toolkit": ">=0.0.3",
17
22
  "@ag-ui/client": ">=0.0.37",
18
23
  "@ag-ui/core": ">=0.0.37",
19
24
  "@ag-ui/encoder": ">=0.0.37",
@@ -48,9 +53,10 @@
48
53
  "typescript": "^5.3.3",
49
54
  "vitest": "^4.0.18",
50
55
  "zod": "^4.4.3",
51
- "@ag-ui/core": "0.0.53",
52
- "@ag-ui/encoder": "0.0.53",
53
- "@ag-ui/client": "0.0.53"
56
+ "@ag-ui/a2ui-toolkit": "0.0.3",
57
+ "@ag-ui/client": "0.0.57",
58
+ "@ag-ui/encoder": "0.0.57",
59
+ "@ag-ui/core": "0.0.57"
54
60
  },
55
61
  "exports": {
56
62
  ".": {
@@ -1 +0,0 @@
1
- {"version":3,"file":"agent-B2EYZvns.d.ts","names":[],"sources":["../src/logger.ts","../src/config.ts","../src/agent.ts"],"mappings":"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"}
@@ -1 +0,0 @@
1
- {"version":3,"file":"agent-Dp45JIaO.d.mts","names":[],"sources":["../src/logger.ts","../src/config.ts","../src/agent.ts"],"mappings":"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"}