ai-ax 0.3.0 → 0.4.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/client.d.ts CHANGED
@@ -10,11 +10,13 @@ interface StreamTool {
10
10
  interface StreamItem {
11
11
  text: string;
12
12
  tools: StreamTool[];
13
+ error?: boolean;
13
14
  }
14
15
  interface StreamSend {
15
16
  prompt: string;
16
17
  path?: string;
17
18
  model?: string;
19
+ messages?: any[];
18
20
  headers?: Record<string, string>;
19
21
  }
20
22
  interface StreamUpdate {
package/dist/client.js CHANGED
@@ -1,2 +1,2 @@
1
1
  import{ALIAS as e,BINDING as t,LLM_PATH as n}from"./const.js";import{action as r,actions as i,bind as a,data as o,init as s,side as c}from"./action.js";import l from"y-partyserver/provider";import*as u from"yjs";const d=/^\[tool\] (?:(\S+) )?(\S+)$/,f=(e=n)=>{let t=e=>{let t=[{text:``,tools:[]}],n=!1;for(let r of e.split(`
2
- `)){if(r.startsWith(`[usage]`))continue;let e=d.exec(r),i=t[t.length-1];if(e){i.tools.push({server:e[1]??``,name:e[2]}),n=!0;continue}if(!(n&&r.trim()===``)){if(n){t.push({text:r,tools:[]}),n=!1;continue}i.text=i.text===``?r:`${i.text}\n${r}`}}return t.map(e=>({...e,text:e.text.trim()})).filter(e=>e.text!==``||e.tools.length>0)};return{parse:t,send:async(n,r)=>{let{headers:i={},...a}=n,o=(await fetch(e,{method:`POST`,headers:{"content-type":`application/json`,...i},body:JSON.stringify(a)})).body.getReader(),s=new TextDecoder,c=``;for(;;){let{done:e,value:n}=await o.read();if(e)break;let i=s.decode(n,{stream:!0});c+=i,r?.({items:t(c),delta:i,raw:c})}return t(c)}}};let p=null,m=new Set;const h=e=>void m.add(e),g=(e={})=>{p?.leave();let{room:t=``,path:n=``,host:r=location.host,party:i=`v1`,doc:a}=e,o=t?new l(r,t,a,{party:i,params:{path:n}}):null,c=o?.doc??a??new u.Doc;return p={doc:c,call:s(c),synced(e){if(!o||o.synced)return void e();o.once(`synced`,()=>e())},leave(){m.forEach(e=>e()),m=new Set,o?.destroy()}}};export{e as ALIAS,t as BINDING,r as action,i as actions,a as bind,g as connect,f as createStream,o as data,s as init,h as onLeave,c as side};
2
+ `)){if(r.startsWith(`[usage]`))continue;let e=d.exec(r),i=t[t.length-1];if(e){i.tools.push({server:e[1]??``,name:e[2]}),n=!0;continue}if(!(n&&r.trim()===``)){if(n){t.push({text:r,tools:[]}),n=!1;continue}i.text=i.text===``?r:`${i.text}\n${r}`}}return t.map(e=>({...e,text:e.text.trim()})).filter(e=>e.text!==``||e.tools.length>0)};return{parse:t,send:async(n,r)=>{let{headers:i={},...a}=n,o=await fetch(e,{method:`POST`,headers:{"content-type":`application/json`,...i},body:JSON.stringify(a)});if(!o.ok){let e=(await o.text()).replace(/\n/g,` `),t=[{text:e,tools:[],error:!0}];return r?.({items:t,delta:e,raw:e}),t}let s=o.body.getReader(),c=new TextDecoder,l=``;for(;;){let{done:e,value:n}=await s.read();if(e)break;let i=c.decode(n,{stream:!0});l+=i,r?.({items:t(l),delta:i,raw:l})}return t(l)}}};let p=null,m=new Set;const h=e=>void m.add(e),g=(e={})=>{p?.leave();let{room:t=``,path:n=``,host:r=location.host,party:i=`v1`,doc:a}=e,o=t?new l(r,t,a,{party:i,params:{path:n}}):null,c=o?.doc??a??new u.Doc;return p={doc:c,call:s(c),synced(e){if(!o||o.synced)return void e();o.once(`synced`,()=>e())},leave(){m.forEach(e=>e()),m=new Set,o?.destroy()}}};export{e as ALIAS,t as BINDING,r as action,i as actions,a as bind,g as connect,f as createStream,o as data,s as init,h as onLeave,c as side};
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
1
  import{PATH_HEADER as e,SUB_HEADER as t}from"./const.js";import{actions as n}from"./action.js";import{createMiddleware as r}from"hono/factory";import i from"@auth/core/providers/google";import{decode as a,encode as o}from"@auth/core/jwt";import{DrizzleAdapter as s}from"@auth/drizzle-adapter";import{getAuthUser as c,initAuthConfig as l}from"@hono/auth-js";import{drizzle as u}from"drizzle-orm/d1";import{env as d}from"hono/adapter";import{streamText as f}from"hono/streaming";import{StreamableHTTPTransport as p}from"@hono/mcp";import{McpServer as m}from"@modelcontextprotocol/sdk/server/mcp.js";import{getServerByName as h,routePartykitRequest as g}from"partyserver";const _=`authjs.mcp-token`,v=e=>l(t=>{let n=new URL(t.req.url).host,r=!!e.cookie&&e.cookie.services.some(t=>n===`${t}.${e.cookie.apex}`),a={sessionToken:{options:{domain:`.${e.cookie?.apex}`}}},o=e.providers??[i({clientId:t.env.GOOGLE_CLIENT_ID,clientSecret:t.env.GOOGLE_CLIENT_SECRET})];return{...e.database?{adapter:s(u(e.database(t.env)))}:{},providers:o,secret:t.env.AUTH_SECRET,session:{strategy:`jwt`},...r?{cookies:a}:{}}}),y=async e=>(await c(e))?.token?.sub??``,b=(e,t,n,r)=>o({token:{sub:t,path:n},secret:d(e).AUTH_SECRET,salt:r?.salt??_,maxAge:r?.maxAge??43200}),x=async(e,t)=>{let n=(e.req.header(`Authorization`)??``).replace(/^Bearer\s+/i,``);if(!n)return null;let r=await a({token:n,secret:d(e).AUTH_SECRET,salt:t?.salt??_}).catch(()=>null);return{sub:r?.sub??``,path:r?.path??``}},S=(e,t=`site`)=>async(n,r,i)=>!r||!i?``:(await e(n).head(`${r}/${i}`))?.customMetadata?.[t]??``,C=()=>(e,t)=>t,w=e=>e.startsWith(`data:`)?JSON.parse(e.slice(5)):null,T=(e,t,n)=>fetch(e.api,{method:`POST`,headers:{"x-api-key":e.key,"anthropic-version":`2023-06-01`,"anthropic-beta":`mcp-client-2025-11-20`,"content-type":`application/json`},body:JSON.stringify({model:e.model,max_tokens:e.maxTokens,stream:!0,cache_control:{type:`ephemeral`},system:e.system,mcp_servers:[{type:`url`,url:e.url,name:e.name,...t?{authorization_token:t}:{}}],tools:[{type:`mcp_toolset`,mcp_server_name:e.name}],messages:n})}),E=async(e,t)=>{let n=[],r=null,i=0,a=0,o=0,s=``,c=e.body.getReader(),l=new TextDecoder,u=``;for(;;){let{done:e,value:d}=await c.read();if(e)break;u+=l.decode(d,{stream:!0});let f=u.split(`
2
- `);u=f.pop()??``;for(let e of f){let c=w(e);if(c){if(c.type===`message_start`){let e=c.message?.usage??{};i+=(e.input_tokens??0)+(e.cache_creation_input_tokens??0)+(e.cache_read_input_tokens??0),a+=e.cache_read_input_tokens??0}c.type===`message_delta`&&(o=c.usage?.output_tokens??o,s=c.delta?.stop_reason??s),c.type===`content_block_start`&&(r={...c.content_block},n.push(r),r.type===`mcp_tool_use`&&await t(`\n[tool] ${r.server_name} ${r.name}\n`)),c.type===`content_block_delta`&&c.delta?.type===`text_delta`&&(r.text=(r.text??``)+c.delta.text,await t(c.delta.text)),c.type===`content_block_delta`&&c.delta?.type===`input_json_delta`&&(r.partial=(r.partial??``)+c.delta.partial_json),c.type===`content_block_delta`&&c.delta?.type===`thinking_delta`&&(r.thinking=(r.thinking??``)+c.delta.thinking),c.type===`content_block_delta`&&c.delta?.type===`signature_delta`&&(r.signature=(r.signature??``)+c.delta.signature),c.type===`content_block_stop`&&r?.partial!==void 0&&(r.input=r.partial?JSON.parse(r.partial):{},delete r.partial)}}}return{blocks:n,input:i,cached:a,output:o,stop:s}},D=async(e,t,n,r,i,a=10)=>{let o=r,s=0,c=0,l=0,u=``;for(let r=0;r<a;r++){let r=await E(o,i);if(s+=r.input,c+=r.cached,l+=r.output,u=r.stop||u,u!==`pause_turn`)break;if(n.push({role:`assistant`,content:r.blocks.filter(e=>e.type!==`thinking`||e.thinking||e.signature)}),o=await T(e,await t(),n),!o.ok){await i(await o.text());break}}await i(`\n[usage] input ${s} (cache ${c}) / output ${l} tokens (${u})\n`)},O=e=>r(async t=>{let n=await y(t),{path:r=``,prompt:i,model:a=``}=await t.req.json(),o=!!e.lobby&&!r;if(!o&&!n)return t.text(`Unauthorized`,401);if(!o&&!await e.own(d(t),n,r))return t.text(`Forbidden`,403);let s=t.req.header(`x-original-host`)??t.req.header(`x-forwarded-host`)??new URL(t.req.url).host,c={key:d(t).ANTHROPIC_API_KEY,api:e.claude??`https://api.anthropic.com/v1/messages`,name:e.name,url:`https://${s}${e.endpoint??`/api/mcp`}`,model:a||e.model||`claude-sonnet-5`,system:e.system??``,maxTokens:e.maxTokens??32e3},l=()=>o?Promise.resolve(``):b(t,n,r,e),u=[{role:`user`,content:i}],p=await T(c,await l(),u);return p.ok?f(t,t=>D(c,l,u,p,e=>t.write(e),e.maxTurns??10)):t.text(await p.text(),500)}),k=async(n,r,i,a,o)=>{let s=await h(n,r),c={[t]:i.sub,[e]:encodeURIComponent(i.path)};return(await s.fetch(`https://internal/act`,{method:`POST`,headers:c,body:JSON.stringify({name:a,input:o})})).json()},A=e=>r(async t=>{let r=await x(t,e),i=r?.sub??``,a=r?.path??``,o=e.lobby??``;if(r||!o){if(!i)return t.text(`Unauthorized`,401);if(o=await e.own(d(t),i,a),!o)return t.text(`Forbidden`,403)}let s=new m({name:e.name,version:e.version??`1.0.0`}),c=new p;return n.forEach((n,r)=>s.registerTool(r,{description:n.description,inputSchema:{...n.input}},async n=>{let s=await k(d(t)[e.binding??`v1`],o,{sub:i,path:a},r,n);return{content:[{type:`text`,text:JSON.stringify(s)}]}})),await s.connect(c),c.handleRequest(t)}),j=async(n,r,i,a)=>{let o=new Headers(n.req.raw.headers);o.set(t,i),o.set(e,encodeURIComponent(a));let s=new URL(n.req.url),c=s.pathname.split(`/`);c[3]=encodeURIComponent(r),s.pathname=c.join(`/`);let l=new Request(s,new Request(n.req.raw,{headers:o}));return await g(l,d(n))??n.text(`Not Found`,404)},M=e=>r(async t=>{let n=decodeURIComponent(t.req.path.split(`/`)[3]??``),r=t.req.query(`path`)??``,i=await y(t);if(e.lobby&&n===e.lobby)return j(t,n,i,r);if(!i)return t.text(`Unauthorized`,401);let a=await e.own(d(t),i,r);return!a||n!==a&&n!==(e.alias??`my-room`)?t.text(`Forbidden`,403):j(t,a,i,r)}),N=e=>{let t={auth:v(e),party:M(e),mcp:A(e),llm:O(e)},n=r(async(n,r)=>{let i=()=>n.req.path.startsWith(`/parties/`)?t.party(n,r):n.req.path===(e.endpoint??`/api/mcp`)?t.mcp(n,r):n.req.path===`/api/llm`&&n.req.method===`POST`?t.llm(n,r):r(),a;if(await t.auth(n,async()=>void(a=await i())),a)return a});return{config:e,all:()=>n,auth:()=>t.auth,party:()=>t.party,mcp:()=>t.mcp,llm:()=>t.llm}};export{N as createAiax,C as ownSelf,S as ownSite};
2
+ `);u=f.pop()??``;for(let e of f){let c=w(e);if(c){if(c.type===`message_start`){let e=c.message?.usage??{};i+=(e.input_tokens??0)+(e.cache_creation_input_tokens??0)+(e.cache_read_input_tokens??0),a+=e.cache_read_input_tokens??0}c.type===`message_delta`&&(o=c.usage?.output_tokens??o,s=c.delta?.stop_reason??s),c.type===`content_block_start`&&(r={...c.content_block},n.push(r),r.type===`mcp_tool_use`&&await t(`\n[tool] ${r.server_name} ${r.name}\n`)),c.type===`content_block_delta`&&c.delta?.type===`text_delta`&&(r.text=(r.text??``)+c.delta.text,await t(c.delta.text)),c.type===`content_block_delta`&&c.delta?.type===`input_json_delta`&&(r.partial=(r.partial??``)+c.delta.partial_json),c.type===`content_block_delta`&&c.delta?.type===`thinking_delta`&&(r.thinking=(r.thinking??``)+c.delta.thinking),c.type===`content_block_delta`&&c.delta?.type===`signature_delta`&&(r.signature=(r.signature??``)+c.delta.signature),c.type===`content_block_stop`&&r?.partial!==void 0&&(r.input=r.partial?JSON.parse(r.partial):{},delete r.partial)}}}return{blocks:n,input:i,cached:a,output:o,stop:s}},D=async(e,t,n,r,i,a=10)=>{let o=r,s=0,c=0,l=0,u=``;for(let r=0;r<a;r++){let r=await E(o,i);if(s+=r.input,c+=r.cached,l+=r.output,u=r.stop||u,u!==`pause_turn`)break;if(n.push({role:`assistant`,content:r.blocks.filter(e=>e.type!==`thinking`||e.thinking||e.signature)}),o=await T(e,await t(),n),!o.ok){await i(`\n[error] ${(await o.text()).replace(/\n/g,` `)}\n`);break}}await i(`\n[usage] input ${s} (cache ${c}) / output ${l} tokens (${u})\n`)},O=e=>r(async t=>{let n=await y(t),{path:r=``,prompt:i,model:a=``,messages:o=[]}=await t.req.json(),s=!!e.lobby&&!r;if(!s&&!n)return t.text(`Unauthorized`,401);if(!s&&!await e.own(d(t),n,r))return t.text(`Forbidden`,403);let c=t.req.header(`x-original-host`)??t.req.header(`x-forwarded-host`)??new URL(t.req.url).host,l={key:d(t).ANTHROPIC_API_KEY,api:e.claude??`https://api.anthropic.com/v1/messages`,name:e.name,url:`https://${c}${e.endpoint??`/api/mcp`}`,model:a||e.model||`claude-sonnet-5`,system:e.system??``,maxTokens:e.maxTokens??32e3},u=()=>s?Promise.resolve(``):b(t,n,r,e),p=[...o,{role:`user`,content:i}],m=await T(l,await u(),p);return m.ok?f(t,t=>D(l,u,p,m,e=>t.write(e),e.maxTurns??10)):t.text(await m.text(),500)}),k=async(n,r,i,a,o)=>{let s=await h(n,r),c={[t]:i.sub,[e]:encodeURIComponent(i.path)};return(await s.fetch(`https://internal/act`,{method:`POST`,headers:c,body:JSON.stringify({name:a,input:o})})).json()},A=e=>r(async t=>{let r=await x(t,e),i=r?.sub??``,a=r?.path??``,o=e.lobby??``;if(r||!o){if(!i)return t.text(`Unauthorized`,401);if(o=await e.own(d(t),i,a),!o)return t.text(`Forbidden`,403)}let s=new m({name:e.name,version:e.version??`1.0.0`}),c=new p;return n.forEach((n,r)=>s.registerTool(r,{description:n.description,inputSchema:{...n.input}},async n=>{let s=await k(d(t)[e.binding??`v1`],o,{sub:i,path:a},r,n);return{content:[{type:`text`,text:JSON.stringify(s)}]}})),await s.connect(c),c.handleRequest(t)}),j=async(n,r,i,a)=>{let o=new Headers(n.req.raw.headers);o.set(t,i),o.set(e,encodeURIComponent(a));let s=new URL(n.req.url),c=s.pathname.split(`/`);c[3]=encodeURIComponent(r),s.pathname=c.join(`/`);let l=new Request(s,new Request(n.req.raw,{headers:o}));return await g(l,d(n))??n.text(`Not Found`,404)},M=e=>r(async t=>{let n=decodeURIComponent(t.req.path.split(`/`)[3]??``),r=t.req.query(`path`)??``,i=await y(t);if(e.lobby&&n===e.lobby)return j(t,n,i,r);if(!i)return t.text(`Unauthorized`,401);let a=await e.own(d(t),i,r);return!a||n!==a&&n!==(e.alias??`my-room`)?t.text(`Forbidden`,403):j(t,a,i,r)}),N=e=>{let t={auth:v(e),party:M(e),mcp:A(e),llm:O(e)},n=r(async(n,r)=>{let i=()=>n.req.path.startsWith(`/parties/`)?t.party(n,r):n.req.path===(e.endpoint??`/api/mcp`)?t.mcp(n,r):n.req.path===`/api/llm`&&n.req.method===`POST`?t.llm(n,r):r(),a;if(await t.auth(n,async()=>void(a=await i())),a)return a});return{config:e,all:()=>n,auth:()=>t.auth,party:()=>t.party,mcp:()=>t.mcp,llm:()=>t.llm}};export{N as createAiax,C as ownSelf,S as ownSite};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ai-ax",
3
3
  "author": "tseijp",
4
- "version": "0.3.0",
4
+ "version": "0.4.0",
5
5
  "license": "MIT",
6
6
  "description": "AI Agent Experience (AI/AX) library for Hono + Cloudflare. One act surface for both human UI/UX and LLM MCP tools, with authentication, authorization, realtime sync and Claude API relay.",
7
7
  "keywords": [