thursday-agent 0.10.0 → 0.12.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/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +0 -1
- package/.next/build-manifest.json +3 -3
- package/.next/prerender-manifest.json +3 -3
- package/.next/routes-manifest.json +0 -6
- package/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/server/app/_global-error.html +1 -1
- package/.next/server/app/_global-error.rsc +1 -1
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.rsc +2 -2
- package/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/.next/server/app/api/artifact/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/keep-working/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/memory/files/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/memory/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/thread/[id]/route.js.nft.json +1 -1
- package/.next/server/app/api/bot/thread/route.js.nft.json +1 -1
- package/.next/server/app/api/config/route.js.nft.json +1 -1
- package/.next/server/app/api/events/route.js.nft.json +1 -1
- package/.next/server/app/api/favicon/[host]/route.js.nft.json +1 -1
- package/.next/server/app/api/file/[...path]/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/catalog/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/credits/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/route.js.nft.json +1 -1
- package/.next/server/app/api/llm-model/subscription/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/[name]/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/oauth/callback/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/route.js.nft.json +1 -1
- package/.next/server/app/api/mcp/tools/route.js.nft.json +1 -1
- package/.next/server/app/api/memory/edit/route.js.nft.json +1 -1
- package/.next/server/app/api/memory/route.js.nft.json +1 -1
- package/.next/server/app/api/reach/route.js +13 -13
- package/.next/server/app/api/reach/route.js.nft.json +1 -1
- package/.next/server/app/api/routine/route.js.nft.json +1 -1
- package/.next/server/app/api/signins/route.js +1 -1
- package/.next/server/app/api/signins/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/[source]/[name]/route.js.nft.json +1 -1
- package/.next/server/app/api/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/call/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/skills/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/text/route.js.nft.json +1 -1
- package/.next/server/app/api/thursday/tool-call/route.js +14 -15
- package/.next/server/app/api/thursday/tool-call/route.js.nft.json +1 -1
- package/.next/server/app/api/workspace/files/route.js.nft.json +1 -1
- package/.next/server/app/api/workspace/route.js.nft.json +1 -1
- package/.next/server/app/artifact/[...path]/page/server-reference-manifest.json +1 -1
- package/.next/server/app/artifact/[...path]/page.js.nft.json +1 -1
- package/.next/server/app/artifact/[...path]/page_client-reference-manifest.js +1 -1
- package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
- package/.next/server/app/manifest.webmanifest/route.js.nft.json +1 -1
- package/.next/server/app/page/server-reference-manifest.json +56 -56
- package/.next/server/app/page.js +4 -4
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/server/app-paths-manifest.json +0 -1
- package/.next/server/chunks/[root-of-the-server]__014ydvq._.js +2 -2
- package/.next/server/chunks/[root-of-the-server]__0209ah4._.js +7 -5
- package/.next/server/chunks/[root-of-the-server]__04r4h-2._.js +4 -2
- package/.next/server/chunks/[root-of-the-server]__04wldw9._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0542v_d._.js +3 -0
- package/.next/server/chunks/[root-of-the-server]__0cfszwn._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0gewdg9._.js +2 -2
- package/.next/server/chunks/[root-of-the-server]__0mrk2it._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0npn_pn._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0nr-v8s._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__0rqgb17._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__1-swlkw._.js +2 -2
- package/.next/server/chunks/[root-of-the-server]__12iddfq._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__1ai5lme._.js +3 -3
- package/.next/server/chunks/[root-of-the-server]__1cjxw0-._.js +2 -2
- package/.next/server/chunks/{[root-of-the-server]__1fy2g82._.js → [root-of-the-server]__1k3j52n._.js} +1 -1
- package/.next/server/chunks/[root-of-the-server]__1kyjt5m._.js +3 -3
- package/.next/server/chunks/[root-of-the-server]__1tg5got._.js +1 -1
- package/.next/server/chunks/[root-of-the-server]__1ygplx1._.js +1 -1
- package/.next/server/chunks/_05v8k21._.js +3 -1
- package/.next/server/chunks/_0awtznl._.js +1 -1
- package/.next/server/chunks/_0f6ts7z._.js +1 -1
- package/.next/server/chunks/_0na2fj1._.js +1 -1
- package/.next/server/chunks/_0x-ej3f._.js +17 -17
- package/.next/server/chunks/_10tkr26._.js +1 -1
- package/.next/server/chunks/_12-amdu._.js +2 -2
- package/.next/server/chunks/_15740dw._.js +60 -0
- package/.next/server/chunks/_1dc_d1q._.js +3 -3
- package/.next/server/chunks/_1i350l5._.js +3 -1
- package/.next/server/chunks/_1jc5g4p._.js +2 -2
- package/.next/server/chunks/_1jn-aep._.js +4 -4
- package/.next/server/chunks/_1m88lkh._.js +11 -11
- package/.next/server/chunks/_1ogqovh._.js +4 -4
- package/.next/server/chunks/_1taa4bs._.js +1 -1
- package/.next/server/chunks/_1tpr507._.js +1 -1
- package/.next/server/chunks/_1uuucy-._.js +1 -1
- package/.next/server/chunks/_1zxp-p6._.js +1 -1
- package/.next/server/chunks/features_0rfvely._.js +5 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0a967km._.js +3 -0
- package/.next/server/chunks/ssr/{[root-of-the-server]__1se25x0._.js → [root-of-the-server]__0hpp3nw._.js} +29 -13
- package/.next/server/chunks/ssr/[root-of-the-server]__0tzekbl._.js +24 -60
- package/.next/server/chunks/ssr/{[root-of-the-server]__0tvavy9._.js → [root-of-the-server]__1iwyp1e._.js} +1 -1
- package/.next/server/chunks/ssr/[root-of-the-server]__1r77-88._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1w9hqq8._.js +1 -1
- package/.next/server/chunks/ssr/_026qnc9._.js +1 -1
- package/.next/server/chunks/ssr/{_173siic._.js → _02c7o30._.js} +2 -2
- package/.next/server/chunks/ssr/_097-ljd._.js +1 -1
- package/.next/server/chunks/ssr/_0euzzf8._.js +3 -0
- package/.next/server/chunks/ssr/{_1u2jw0i._.js → _0fbi6om._.js} +3 -3
- package/.next/server/chunks/ssr/_0fqhhwi._.js +1 -1
- package/.next/server/chunks/ssr/_0igfcax._.js +20 -0
- package/.next/server/chunks/ssr/_0ld9_qq._.js +1 -1
- package/.next/server/chunks/ssr/_0nvh1h9._.js +3 -0
- package/.next/server/chunks/ssr/_0qmpw35._.js +3 -0
- package/.next/server/chunks/ssr/{_1yk6yak._.js → _0rmaf32._.js} +2 -2
- package/.next/server/chunks/ssr/_0uv-qs4._.js +3 -0
- package/.next/server/chunks/ssr/{_1doidrw._.js → _10f-jib._.js} +2 -2
- package/.next/server/chunks/ssr/{_05rxyf9._.js → _10mo72m._.js} +2 -2
- package/.next/server/chunks/ssr/_12mijol._.js +11 -11
- package/.next/server/chunks/ssr/_132qkfz._.js +1 -1
- package/.next/server/chunks/ssr/_15zqt-t._.js +1 -1
- package/.next/server/chunks/ssr/_16gfxpn._.js +3 -0
- package/.next/server/chunks/ssr/_184327j._.js +1 -1
- package/.next/server/chunks/ssr/{_1ng831c._.js → _18ujhhq._.js} +2 -2
- package/.next/server/chunks/ssr/_1d423aj._.js +7 -5
- package/.next/server/chunks/ssr/_1lx6w_o._.js +67 -0
- package/.next/server/chunks/ssr/_1mqn9mc._.js +1 -1
- package/.next/server/chunks/ssr/_1neoj22._.js +1 -1
- package/.next/server/chunks/ssr/{_19n08g5._.js → _1ntpny5._.js} +2 -2
- package/.next/server/chunks/ssr/{_0bp-_fi._.js → _1o1g4uk._.js} +3 -3
- package/.next/server/chunks/ssr/_1xoch6f._.js +1 -1
- package/.next/server/chunks/ssr/_1yh5bj5._.js +1 -1
- package/.next/server/chunks/ssr/{_0tg0vf8._.js → _2008vmi._.js} +8 -8
- package/.next/server/chunks/ssr/{features_bot_1yr-_pm._.js → features_bot_1n1s7bh._.js} +2 -2
- package/.next/server/chunks/ssr/features_connectors_components_mcp-setting_tsx_0jmbgvp._.js +1 -1
- package/.next/server/chunks/ssr/features_memory_components_memory-setting_tsx_0oa43sw._.js +1 -1
- package/.next/server/chunks/ssr/features_routine_components_routine-setting_tsx_055fknz._.js +1 -1
- package/.next/server/chunks/ssr/features_workspace_00jz2hu._.js +1 -1
- package/.next/server/chunks/ssr/{node_modules_1n0h9sf._.js → node_modules_0-x0zxm._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1xzo2wn._.js → node_modules_00nrzz_._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0511ha-._.js → node_modules_01ed0yi._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_18woe20._.js → node_modules_01u4ea3._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1expacw._.js → node_modules_05b6e99._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0eb4rx7._.js → node_modules_07jp6tj._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0piws2a._.js → node_modules_0azd56x._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0f2k5l0._.js → node_modules_0b0iy01._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0wq4-ts._.js → node_modules_0fpnetd._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_11hbkuj._.js → node_modules_0ky76fz._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_048wmmj._.js → node_modules_0lautv3._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1dcbvfw._.js → node_modules_0m3_5ge._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0pk6i-e._.js → node_modules_0operbz._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1zkpek5._.js → node_modules_0ou0all._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_04t200t._.js → node_modules_0ucridu._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_08g12f-._.js → node_modules_0v_-uht._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1m2ho33._.js → node_modules_0yzmxfq._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1ksh9gy._.js → node_modules_19b0bir._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1qehmwm._.js → node_modules_1c2ikr9._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1_afpz7._.js → node_modules_1hv-j1l._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0cdu6jq._.js → node_modules_1iau_ea._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1zf46lp._.js → node_modules_1ma_y68._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0s1lwc9._.js → node_modules_1omg9xr._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1cxc8kn._.js → node_modules_1wgnj8q._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_0zjqwz7._.js → node_modules_1wvf3oo._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_1_ban4u._.js → node_modules_1z3sh11._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0avl8-1._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_0tmjn9w._.js} +1 -1
- package/.next/server/chunks/ssr/{node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_14oslro._.js → node_modules_@mermaid-js_parser_dist_chunks_mermaid-parser_core_1_e8c3o._.js} +1 -1
- package/.next/server/middleware-build-manifest.js +3 -3
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +57 -57
- package/.next/static/chunks/09pkygbht7ki8.js +18 -0
- package/.next/static/chunks/0bm-nhblcmmj4.js +17 -0
- package/.next/static/chunks/{22shnca_6zfzs.js → 0hhza87hkbqaz.js} +1 -1
- package/.next/static/chunks/{19ojn4lomsk0r.js → 0mscosx0eh3ee.js} +1 -1
- package/.next/static/chunks/{3vynnr71ghvom.js → 0p50d-au6-3hx.js} +2 -2
- package/.next/static/chunks/{42890jqk049q1.js → 0p9jcyqkpq71f.js} +1 -1
- package/.next/static/chunks/{35kwn237o4wdn.js → 0qgn3u86jkbm7.js} +1 -1
- package/.next/static/chunks/{2d4z3er53ng8r.js → 0samf80yu2b17.js} +1 -1
- package/.next/static/chunks/{1pjygp7hqib6j.js → 1czfknd4luo6t.js} +1 -1
- package/.next/static/chunks/{09120tms63y21.js → 1jz8n0mhtdzr8.js} +1 -1
- package/.next/static/chunks/206laxm6maiz2.js +1 -0
- package/.next/static/chunks/{24dst4mgurbsh.js → 2_c7mu6x1lu49.js} +1 -1
- package/.next/static/chunks/{2ky81z-jgvasc.js → 2h-tlhb2ffhkk.js} +1 -1
- package/.next/static/chunks/{0oz3rs47yy3p8.js → 2i5_w8olnrvo0.js} +2 -2
- package/.next/static/chunks/{1mwee7xvitlp9.js → 2m8iqwc6sykln.js} +1 -1
- package/.next/static/chunks/{0o980477kfqez.js → 2r6xnyg7ezyxr.js} +1 -1
- package/.next/static/chunks/33fyp-byw48ju.js +65 -0
- package/.next/static/chunks/{2ndw4w4u2x51r.js → 35yd_27d9ylra.js} +1 -1
- package/.next/static/chunks/{3exjsi8pfdvzj.js → 3ag1i3__yl94f.js} +1 -1
- package/.next/static/chunks/{3obf9n3cxj99k.js → 3jvldk2wvwbge.js} +1 -1
- package/.next/static/chunks/3m_ejzg-xn21r.css +1 -0
- package/.next/static/chunks/{0w20wnnfrscq7.js → 3s-jpd3ky49-n.js} +1 -1
- package/.next/static/chunks/40ij3wsn3vt7h.js +1 -0
- package/README.md +1 -1
- package/app/api/thursday/tool-call/route.ts +1 -15
- package/docs/images/demo-still.jpg +0 -0
- package/docs/live-calls.md +19 -11
- package/features/ai/components/model-picker.tsx +8 -2
- package/features/ai/model.schema.ts +26 -0
- package/features/ai/prompts/live.prompt.ts +51 -26
- package/features/ai/prompts/prompt-helper.ts +1 -9
- package/features/ai/prompts/thursday.prompt.ts +8 -2
- package/features/bot/bot.run.ts +9 -3
- package/features/bot/bot.seed.ts +35 -91
- package/features/bot/components/bot-room.tsx +3 -12
- package/features/bot/components/room-list.tsx +1 -1
- package/features/bot/components/room-pill.tsx +44 -55
- package/features/bot/seed-bots.ts +2 -2
- package/features/config/components/config-badge.tsx +6 -0
- package/features/config/components/config-setting.tsx +20 -1
- package/features/config/components/models-badge.tsx +5 -7
- package/features/config/components/voice-key.tsx +24 -1
- package/features/config/config.const.ts +7 -0
- package/features/intro/components/intro.tsx +4 -19
- package/features/reach/reach.ts +2 -2
- package/features/settings/components/setting-ui.tsx +14 -5
- package/features/settings/components/settings.tsx +3 -1
- package/features/settings/settings.alert.ts +12 -11
- package/features/signins/signins.query.ts +66 -1
- package/features/thursday/components/side-captions.tsx +31 -8
- package/features/thursday/components/tab-state.tsx +5 -2
- package/features/thursday/components/thursday.tsx +158 -68
- package/features/thursday/components/write-line.tsx +37 -17
- package/features/thursday/thursday.action.ts +4 -20
- package/features/thursday/thursday.schema.ts +0 -9
- package/features/thursday/thursday.store.ts +11 -15
- package/features/thursday/thursday.text.ts +10 -8
- package/features/thursday/tool-line.ts +17 -6
- package/features/thursday/use-call-ring.ts +1 -5
- package/features/thursday/use-text-call.ts +37 -21
- package/features/thursday/use-thursday.ts +14 -44
- package/features/workspace/workspace.ts +4 -2
- package/guide/bots.md +12 -2
- package/guide/calls.md +9 -6
- package/guide/setup.md +4 -1
- package/lib/live/live.session.ts +0 -39
- package/package.json +1 -1
- package/scripts/live-session.test.mts +19 -26
- package/seed-skills/analyst/README.md +3 -4
- package/seed-skills/analyst/data-report/SKILL.md +5 -4
- package/seed-skills/insta/instagram/SKILL.md +5 -2
- package/seed-skills/insta/instagram/references/post.md +2 -2
- package/seed-skills/insta/instagram/scripts/compose.mjs +5 -1
- package/seed-skills/insta/instagram/scripts/inbox.mjs +5 -1
- package/seed-skills/insta/instagram/scripts/lib.mjs +12 -70
- package/seed-skills/insta/instagram/scripts/media.mjs +1 -1
- package/seed-skills/insta/instagram/scripts/profile.mjs +6 -2
- package/seed-skills/insta/instagram/scripts/read.mjs +5 -1
- package/seed-skills/insta/instagram/scripts/search.mjs +6 -2
- package/seed-skills/insta/instagram/scripts/sheet.mjs +31 -88
- package/seed-skills/insta/instagram/templates/carousel.html +1 -1
- package/seed-skills/tutor/picture-book/SKILL.md +16 -0
- package/seed-skills/tutor/picture-book/book/book.css +181 -0
- package/seed-skills/tutor/picture-book/book/book.html +33 -0
- package/seed-skills/tutor/picture-book/book/book.js +60 -0
- package/seed-skills/tutor/picture-book/references/picture-book.md +104 -0
- package/seed-skills/tutor/picture-book/scripts/book-video.mjs +177 -0
- package/seed-skills/tutor/picture-book/scripts/book.mjs +98 -0
- package/skills/browser/SKILL.md +13 -4
- package/skills/browser/references/scripts.md +55 -0
- package/{seed-skills/insta/instagram → skills/browser}/scripts/render.mjs +1 -1
- package/skills/browser/scripts/session.mjs +105 -0
- package/skills/browser/scripts/sheet.mjs +97 -0
- package/{seed-skills/insta/instagram → skills/browser}/scripts/webimage.mjs +1 -1
- package/skills/interactive-page/SKILL.md +4 -3
- package/{seed-skills/analyst/data-report → skills/interactive-page}/scripts/chart.mjs +3 -3
- package/skills/interactive-page/scripts/page.mjs +1 -0
- package/.next/server/app/api/probe/route/app-paths-manifest.json +0 -3
- package/.next/server/app/api/probe/route/build-manifest.json +0 -12
- package/.next/server/app/api/probe/route/server-reference-manifest.json +0 -4
- package/.next/server/app/api/probe/route.js +0 -10
- package/.next/server/app/api/probe/route.js.map +0 -5
- package/.next/server/app/api/probe/route.js.nft.json +0 -1
- package/.next/server/app/api/probe/route_client-reference-manifest.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__012s2o8._.js +0 -3
- package/.next/server/chunks/[root-of-the-server]__0z0hc1f._.js +0 -4
- package/.next/server/chunks/[root-of-the-server]__1v7-zke._.js +0 -5
- package/.next/server/chunks/_0whlpyi._.js +0 -4
- package/.next/server/chunks/_next-internal_server_app_api_probe_route_actions_0cqd30j.js +0 -3
- package/.next/server/chunks/ssr/[root-of-the-server]__0cxqzfc._.js +0 -103
- package/.next/server/chunks/ssr/[root-of-the-server]__1-d2tgh._.js +0 -3
- package/.next/server/chunks/ssr/_070nv1_._.js +0 -3
- package/.next/server/chunks/ssr/_0hlxij-._.js +0 -3
- package/.next/server/chunks/ssr/_0p9pmxe._.js +0 -3
- package/.next/server/chunks/ssr/_0s41irp._.js +0 -3
- package/.next/server/chunks/ssr/_157yfrk._.js +0 -3
- package/.next/server/chunks/ssr/_17v-33v._.js +0 -20
- package/.next/server/chunks/ssr/_1flsjeo._.js +0 -3
- package/.next/static/chunks/03kgfyrli_0gz.js +0 -1
- package/.next/static/chunks/1p764d75_0lhv.js +0 -18
- package/.next/static/chunks/25zq8gzhbdsr7.js +0 -1
- package/.next/static/chunks/2qod5tqlpz8b7.js +0 -17
- package/.next/static/chunks/30skcjexa57zn.js +0 -101
- package/.next/static/chunks/3qq4o8w2rv_e9.css +0 -1
- package/lib/probe.server.ts +0 -17
- package/lib/probe.ts +0 -55
- package/seed-skills/mail/mail/SKILL.md +0 -37
- package/seed-skills/mail/mail/recipes/gmail.mjs +0 -448
- package/seed-skills/mail/mail/references/recipes.md +0 -55
- package/seed-skills/mail/mail/scripts/mail.mjs +0 -202
- /package/.next/static/{Ar5V4kMdL4CE1trx8anrH → QSe0rTdXU5kh5BBzr2XBB}/_buildManifest.js +0 -0
- /package/.next/static/{Ar5V4kMdL4CE1trx8anrH → QSe0rTdXU5kh5BBzr2XBB}/_clientMiddlewareManifest.js +0 -0
- /package/.next/static/{Ar5V4kMdL4CE1trx8anrH → QSe0rTdXU5kh5BBzr2XBB}/_ssgManifest.js +0 -0
- /package/{seed-skills/insta/instagram → skills/browser}/scripts/image-size.mjs +0 -0
|
@@ -13,7 +13,11 @@ import {
|
|
|
13
13
|
} from "ai";
|
|
14
14
|
import { ZodError, z } from "zod";
|
|
15
15
|
import { TEXT_CALL } from "@/config";
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
LIVE_PROVIDER,
|
|
18
|
+
type LiveSettings,
|
|
19
|
+
LiveSettingsSchema,
|
|
20
|
+
} from "@/features/ai/live.schema";
|
|
17
21
|
import { loadTools } from "@/features/ai/load-tools";
|
|
18
22
|
import { getTextModel, modelErrorToString } from "@/features/ai/model";
|
|
19
23
|
import {
|
|
@@ -38,8 +42,6 @@ import {
|
|
|
38
42
|
TEXT_CALL_PROVIDERS,
|
|
39
43
|
type TextCallHandshake,
|
|
40
44
|
type TextCallProvider,
|
|
41
|
-
type ThursdaySettings,
|
|
42
|
-
ThursdaySettingsSchema,
|
|
43
45
|
textCallRunsOn,
|
|
44
46
|
} from "./thursday.schema";
|
|
45
47
|
import { toolLine } from "./tool-line";
|
|
@@ -70,7 +72,7 @@ export async function readTextCallProvider(): Promise<TextCallProvider | null> {
|
|
|
70
72
|
* in, else the OpenAI key, on the call's own backend model.
|
|
71
73
|
*/
|
|
72
74
|
async function runsOnOf(
|
|
73
|
-
settings:
|
|
75
|
+
settings: LiveSettings,
|
|
74
76
|
picked: TextModelRef | null | undefined,
|
|
75
77
|
): Promise<TextModelRef> {
|
|
76
78
|
if (picked) return picked;
|
|
@@ -81,7 +83,7 @@ async function runsOnOf(
|
|
|
81
83
|
|
|
82
84
|
/** The row a call in writing is kept under, and what stood open as it began. */
|
|
83
85
|
export async function openTextCall(
|
|
84
|
-
settings:
|
|
86
|
+
settings: LiveSettings,
|
|
85
87
|
picked?: TextModelRef | null,
|
|
86
88
|
): Promise<TextCallHandshake> {
|
|
87
89
|
const ref = await runsOnOf(settings, picked);
|
|
@@ -98,7 +100,7 @@ export async function openTextCall(
|
|
|
98
100
|
|
|
99
101
|
const BodySchema = z.object({
|
|
100
102
|
callId: z.string().min(1),
|
|
101
|
-
settings:
|
|
103
|
+
settings: LiveSettingsSchema,
|
|
102
104
|
/** What stood open as the call opened (ai/prompts/call-standing), as the page was handed it. */
|
|
103
105
|
standing: z.string().nullish(),
|
|
104
106
|
/** The model picked on the write line; absent, the rule decides (runsOnOf). */
|
|
@@ -149,7 +151,7 @@ export async function streamTextCall(
|
|
|
149
151
|
*/
|
|
150
152
|
export async function answerInWriting(input: {
|
|
151
153
|
callId: string;
|
|
152
|
-
settings:
|
|
154
|
+
settings: LiveSettings;
|
|
153
155
|
standing: string | null;
|
|
154
156
|
messages: ModelMessage[];
|
|
155
157
|
said: string | null;
|
|
@@ -246,7 +248,7 @@ const standingHead = (standing: string | null | undefined): ModelMessage[] =>
|
|
|
246
248
|
/** What a turn runs on, whoever holds the conversation: the model, her prompt, her tools. */
|
|
247
249
|
async function loadRun(
|
|
248
250
|
callId: string,
|
|
249
|
-
settings:
|
|
251
|
+
settings: LiveSettings,
|
|
250
252
|
picked?: TextModelRef | null,
|
|
251
253
|
) {
|
|
252
254
|
const ref = await runsOnOf(settings, picked);
|
|
@@ -172,13 +172,15 @@ const ON_A_THREAD = new Set<string>([
|
|
|
172
172
|
* The bot a call's tool reaches, so its row wears that bot's face rather than a glyph —
|
|
173
173
|
* who work went to is a face everywhere else in the app. The one work is handed to, else
|
|
174
174
|
* the bot of the thread the tool names, found as the server finds a thread (thread.query
|
|
175
|
-
* resolveThread): its id, else its label. An answer goes to the bot that asked; "all"
|
|
176
|
-
*
|
|
175
|
+
* resolveThread): its id, else its label. An answer goes to the bot that asked; "all"
|
|
176
|
+
* reaches nobody in particular. A thread the page does not hold — stopped and read, or
|
|
177
|
+
* finished longer ago than the inbox keeps — is named by the tool's answer once it is back.
|
|
177
178
|
*/
|
|
178
179
|
export function toolBot(
|
|
179
180
|
name: string,
|
|
180
181
|
args?: string,
|
|
181
182
|
threads?: Thread[],
|
|
183
|
+
output?: string,
|
|
182
184
|
): string | null {
|
|
183
185
|
const parsed = parseArgs(args);
|
|
184
186
|
if (!parsed) return null;
|
|
@@ -186,19 +188,28 @@ export function toolBot(
|
|
|
186
188
|
return typeof parsed.bot === "string" && parsed.bot.trim()
|
|
187
189
|
? parsed.bot.trim()
|
|
188
190
|
: null;
|
|
189
|
-
if (!ON_A_THREAD.has(name)
|
|
191
|
+
if (!ON_A_THREAD.has(name)) return null;
|
|
190
192
|
const ref = typeof parsed.thread === "string" ? parsed.thread.trim() : "";
|
|
191
193
|
if (!ref || ref.toLowerCase() === "all") return null;
|
|
192
194
|
const lower = ref.toLowerCase();
|
|
193
195
|
const thread =
|
|
194
|
-
threads
|
|
195
|
-
threads
|
|
196
|
-
if (!thread) return
|
|
196
|
+
threads?.find((one) => one.id === ref) ??
|
|
197
|
+
threads?.find((one) => one.label.toLowerCase() === lower);
|
|
198
|
+
if (!thread) return answeredBy(output);
|
|
197
199
|
return name === TOOL_NAMES.thread_answer
|
|
198
200
|
? (thread.room.questions[0]?.bot ?? thread.bot)
|
|
199
201
|
: thread.bot;
|
|
200
202
|
}
|
|
201
203
|
|
|
204
|
+
/** Whom a thread tool's answer says it reached (load-tools): `bot`, or the bot that took it as its answer. */
|
|
205
|
+
function answeredBy(output?: string): string | null {
|
|
206
|
+
const said = parseArgs(output);
|
|
207
|
+
if (!said) return null;
|
|
208
|
+
if (typeof said.bot === "string" && said.bot.trim()) return said.bot.trim();
|
|
209
|
+
const answered = said.answered as { bot?: unknown } | null | undefined;
|
|
210
|
+
return typeof answered?.bot === "string" ? answered.bot : null;
|
|
211
|
+
}
|
|
212
|
+
|
|
202
213
|
/**
|
|
203
214
|
* The label a thread was started under, or null for any other turn. It is
|
|
204
215
|
* how a job is found again from the line that opened it — in her prompt and in
|
|
@@ -6,7 +6,6 @@ import type { Thread } from "@/features/bot/bot.schema";
|
|
|
6
6
|
import { ringingThreads } from "@/features/bot/thread.store";
|
|
7
7
|
import { toDate } from "@/lib/date-like";
|
|
8
8
|
import { createRing } from "@/lib/live/ring";
|
|
9
|
-
import { createProbe } from "@/lib/probe";
|
|
10
9
|
import type { CallBack } from "./thursday.schema";
|
|
11
10
|
import { useThursdayStore } from "./thursday.store";
|
|
12
11
|
|
|
@@ -51,7 +50,6 @@ export function useCallRing({
|
|
|
51
50
|
/** A call in writing holds the screen (use-text-call): nothing rings meanwhile. */
|
|
52
51
|
writing: boolean;
|
|
53
52
|
}) {
|
|
54
|
-
const probe = useRef(createProbe("page")).current;
|
|
55
53
|
/**
|
|
56
54
|
* The call-back rings only for threads that changed after this: the last call's
|
|
57
55
|
* end, the last ring, or the page opening.
|
|
@@ -84,7 +82,6 @@ export function useCallRing({
|
|
|
84
82
|
);
|
|
85
83
|
if (!fresh.length) return;
|
|
86
84
|
|
|
87
|
-
probe("ring", { threads: fresh.map((thread) => thread.id) });
|
|
88
85
|
ringAfter.current = Date.now();
|
|
89
86
|
// Work that is new to it rings again, even if it had rung out
|
|
90
87
|
setRangOutAt(null);
|
|
@@ -92,7 +89,7 @@ export function useCallRing({
|
|
|
92
89
|
...ids,
|
|
93
90
|
...fresh.map((thread) => thread.id).filter((id) => !ids.includes(id)),
|
|
94
91
|
]);
|
|
95
|
-
}, [threads, callBack, resting, writing
|
|
92
|
+
}, [threads, callBack, resting, writing]);
|
|
96
93
|
|
|
97
94
|
// Writing to her answers a ring as calling her does, and what came up while they wrote
|
|
98
95
|
// was that call's to tell: nothing from before its end rings afterwards
|
|
@@ -110,7 +107,6 @@ export function useCallRing({
|
|
|
110
107
|
* A thread added to a ring already going does not restart the clock.
|
|
111
108
|
*/
|
|
112
109
|
const decline = useCallback(() => {
|
|
113
|
-
probe("ring.declined");
|
|
114
110
|
setRingingFor([]);
|
|
115
111
|
setRangOutAt(null);
|
|
116
112
|
}, []);
|
|
@@ -267,34 +267,50 @@ export function useTextCall(): TextCall {
|
|
|
267
267
|
// pages a search read stay through her answer, until the next words are sent, as on a
|
|
268
268
|
// spoken call
|
|
269
269
|
const lastTool = [...parts].reverse().find(isToolUIPart);
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
lastTool.state === "output-available" ||
|
|
282
|
-
lastTool.state === "output-error";
|
|
283
|
-
const sources =
|
|
270
|
+
// The part is copied with every piece of the stream, and its arguments arrive a few
|
|
271
|
+
// characters a piece: the line is a new object only when what it draws changes, or
|
|
272
|
+
// every piece redraws the call screen several times over
|
|
273
|
+
const id = lastTool?.toolCallId ?? null;
|
|
274
|
+
const name = lastTool ? getToolName(lastTool) : null;
|
|
275
|
+
const done =
|
|
276
|
+
lastTool?.state === "output-available" ||
|
|
277
|
+
lastTool?.state === "output-error";
|
|
278
|
+
const output = lastTool?.output;
|
|
279
|
+
const sources = useMemo(
|
|
280
|
+
() =>
|
|
284
281
|
done && name === TOOL_NAMES.web_search
|
|
285
|
-
? searchSourcesOf(JSON.stringify(
|
|
286
|
-
: []
|
|
287
|
-
|
|
288
|
-
|
|
282
|
+
? searchSourcesOf(JSON.stringify(output ?? null))
|
|
283
|
+
: [],
|
|
284
|
+
[done, name, output],
|
|
285
|
+
);
|
|
286
|
+
// A provider's own search names what it looked for in its answer, not in what it was asked
|
|
287
|
+
const asked = (output as { action?: { query?: unknown } } | null | undefined)
|
|
288
|
+
?.action?.query;
|
|
289
|
+
const args = JSON.stringify({
|
|
290
|
+
...(typeof asked === "string" ? { query: asked } : {}),
|
|
291
|
+
...(lastTool?.input ?? {}),
|
|
292
|
+
});
|
|
293
|
+
const bot = name
|
|
294
|
+
? toolBot(
|
|
295
|
+
name,
|
|
296
|
+
args,
|
|
297
|
+
inbox.current,
|
|
298
|
+
output === undefined ? undefined : JSON.stringify(output),
|
|
299
|
+
)
|
|
300
|
+
: null;
|
|
301
|
+
const drawn = name ? toolLine(name, args, bot) : null;
|
|
302
|
+
const answered = last?.type === "text";
|
|
303
|
+
const used = useMemo((): ActivityLine | null => {
|
|
304
|
+
if (!id || !name || (answered && !sources.length)) return null;
|
|
289
305
|
return {
|
|
290
|
-
id
|
|
306
|
+
id,
|
|
291
307
|
name,
|
|
292
|
-
line:
|
|
308
|
+
line: drawn,
|
|
293
309
|
bot,
|
|
294
310
|
done,
|
|
295
311
|
...(sources.length ? { sources } : {}),
|
|
296
312
|
};
|
|
297
|
-
}, [
|
|
313
|
+
}, [id, name, drawn, bot, done, sources, answered]);
|
|
298
314
|
const [lingered, setLingered] = useState<string | null>(null);
|
|
299
315
|
const usedId = used?.done && !used.sources ? used.id : null;
|
|
300
316
|
useEffect(() => {
|
|
@@ -4,13 +4,7 @@ import { useCallback, useEffect, useRef, useState } from "react";
|
|
|
4
4
|
import { useAppEvent } from "@/app/api/events/app-event.client";
|
|
5
5
|
import { queryKey } from "@/app/api/query-key";
|
|
6
6
|
import { toast } from "@/components/ui/toast";
|
|
7
|
-
import {
|
|
8
|
-
CALL_END,
|
|
9
|
-
CALL_ENDED_MS,
|
|
10
|
-
CALL_IDLE,
|
|
11
|
-
CALL_NUDGE,
|
|
12
|
-
CALL_RELAY,
|
|
13
|
-
} from "@/config";
|
|
7
|
+
import { CALL_END, CALL_ENDED_MS, CALL_IDLE, CALL_RELAY } from "@/config";
|
|
14
8
|
import { TOOL_NAMES } from "@/features/ai/tools/tool-name";
|
|
15
9
|
import { acceptThreadRelaysAction } from "@/features/bot/bot.action";
|
|
16
10
|
import type { Bot, Thread } from "@/features/bot/bot.schema";
|
|
@@ -32,7 +26,6 @@ import {
|
|
|
32
26
|
createAudioTap,
|
|
33
27
|
SPECTRUM_BANDS,
|
|
34
28
|
} from "@/lib/live/live.tap";
|
|
35
|
-
import { createProbe } from "@/lib/probe";
|
|
36
29
|
import { type Result, unwrapResult } from "@/lib/protocol/result";
|
|
37
30
|
import {
|
|
38
31
|
revalidate,
|
|
@@ -216,8 +209,6 @@ export function useThursday(
|
|
|
216
209
|
const onLine = useRef<string[]>([]);
|
|
217
210
|
/** That update's relay rows, accepted once she has voiced it. */
|
|
218
211
|
const onLineRows = useRef<number[]>([]);
|
|
219
|
-
/** The experiment's timer (config CALL_NUDGE): a backend turn the page starts itself. */
|
|
220
|
-
const nudge = useRef<ReturnType<typeof setTimeout> | null>(null);
|
|
221
212
|
/** When her voice was last heard, for letting a goodbye finish (CALL_END). */
|
|
222
213
|
const voiced = useRef(0);
|
|
223
214
|
/** The hang-up waiting on her goodbye once the backend called end_call. */
|
|
@@ -267,12 +258,22 @@ export function useThursday(
|
|
|
267
258
|
});
|
|
268
259
|
}, []);
|
|
269
260
|
|
|
261
|
+
/** The tool's answer is back: a thread the page does not hold is named by it (toolBot). */
|
|
262
|
+
const nameTool = useCallback((call: LiveToolCall, output: string) => {
|
|
263
|
+
const bot = toolBot(call.name, call.arguments, latest.current, output);
|
|
264
|
+
if (!bot) return;
|
|
265
|
+
setTool((open) =>
|
|
266
|
+
open?.id === call.id && open.bot !== bot
|
|
267
|
+
? { ...open, bot, line: toolLine(call.name, call.arguments, bot) }
|
|
268
|
+
: open,
|
|
269
|
+
);
|
|
270
|
+
}, []);
|
|
271
|
+
|
|
270
272
|
/**
|
|
271
273
|
* A relay takes the tool line and runs there like a tool does: while it goes in,
|
|
272
274
|
* and while she voices it. Her voice finishing it is what stops the motion
|
|
273
275
|
* (doneReading); after that it stays long enough to read.
|
|
274
276
|
*/
|
|
275
|
-
const probe = useRef(createProbe("page")).current;
|
|
276
277
|
const showRelay = useCallback((run: ActivityLine) => {
|
|
277
278
|
if (linger.current) clearTimeout(linger.current);
|
|
278
279
|
relayOpen.current = true;
|
|
@@ -295,7 +296,6 @@ export function useThursday(
|
|
|
295
296
|
/** The relayed update was voiced, or waited on long enough: the next can go in. */
|
|
296
297
|
const doneReading = useCallback(() => {
|
|
297
298
|
if (reading.current.giveUp) clearTimeout(reading.current.giveUp);
|
|
298
|
-
probe("read.done", { spoke: reading.current.spoke, keys: onLine.current });
|
|
299
299
|
// Her voice started and stopped on it: carried, and only now are its rows accepted.
|
|
300
300
|
// Live's acknowledgement says the text arrived, not that anyone heard it
|
|
301
301
|
if (reading.current.spoke) {
|
|
@@ -419,13 +419,6 @@ export function useThursday(
|
|
|
419
419
|
}
|
|
420
420
|
// Finished work is good news before she says it (an item's key opens with what it is)
|
|
421
421
|
if (first.key.startsWith("done:")) setFaceWord(finished());
|
|
422
|
-
probe("relay.out", {
|
|
423
|
-
kind: first.kind,
|
|
424
|
-
keys: due.map((item) => item.key),
|
|
425
|
-
waiting: open.length - due.length,
|
|
426
|
-
quietMs: Date.now() - heard.current,
|
|
427
|
-
rung,
|
|
428
|
-
});
|
|
429
422
|
readAloud();
|
|
430
423
|
onLine.current = due.map((item) => item.key);
|
|
431
424
|
onLineRows.current = due.flatMap((item) => item.relayIds);
|
|
@@ -439,7 +432,6 @@ export function useThursday(
|
|
|
439
432
|
: `[${lines.length} updates.]\n\n${lines.join("\n\n")}`,
|
|
440
433
|
)
|
|
441
434
|
.then((delivered) => {
|
|
442
|
-
probe("relay.acked", { delivered });
|
|
443
435
|
// Refused: nothing to wait for her voice on
|
|
444
436
|
if (!delivered) {
|
|
445
437
|
onLineRows.current = [];
|
|
@@ -572,12 +564,6 @@ export function useThursday(
|
|
|
572
564
|
async (why: CallEnd | null = null) => {
|
|
573
565
|
if (ending.current) return;
|
|
574
566
|
ending.current = true;
|
|
575
|
-
probe("hangup", {
|
|
576
|
-
why,
|
|
577
|
-
call: callId.current,
|
|
578
|
-
unvoiced: [...unvoiced.current],
|
|
579
|
-
reading: reading.current.on,
|
|
580
|
-
});
|
|
581
567
|
if (leaving.current) clearInterval(leaving.current);
|
|
582
568
|
leaving.current = null;
|
|
583
569
|
attempt.current += 1;
|
|
@@ -665,7 +651,6 @@ export function useThursday(
|
|
|
665
651
|
const leave = useCallback(() => {
|
|
666
652
|
if (leaving.current) return;
|
|
667
653
|
const asked = Date.now();
|
|
668
|
-
probe("end_call", { sinceVoiceMs: asked - voiced.current });
|
|
669
654
|
leaving.current = setInterval(() => {
|
|
670
655
|
const now = Date.now();
|
|
671
656
|
// A goodbye heard just before the backend ended the call counts as said
|
|
@@ -703,7 +688,6 @@ export function useThursday(
|
|
|
703
688
|
const call = useCallback(async () => {
|
|
704
689
|
// Every way in answers a ringing call-back: the face, the wake word, the hotkey
|
|
705
690
|
const calledBack = ring.isRinging;
|
|
706
|
-
probe("call", { calledBack, ringingFor: ring.ringingFor });
|
|
707
691
|
// Guard with a ref, not `status`: three entry points (face, wake word,
|
|
708
692
|
// hotkey) can fire in one frame and both see a stale "idle", opening two sessions
|
|
709
693
|
if (opening.current || ending.current) return;
|
|
@@ -831,8 +815,6 @@ export function useThursday(
|
|
|
831
815
|
if (word) setFaceWord({ text: word, at: Date.now() });
|
|
832
816
|
return reply;
|
|
833
817
|
}
|
|
834
|
-
const began = Date.now();
|
|
835
|
-
probe("tool.run", { name: call.name, id: call.id });
|
|
836
818
|
showTool(call);
|
|
837
819
|
// Exa's search, while its key is set (load-tools): its pages come back with
|
|
838
820
|
// the answer and stay on the line the way the hosted search's do
|
|
@@ -846,6 +828,7 @@ export function useThursday(
|
|
|
846
828
|
settings.webSearch,
|
|
847
829
|
stop.signal,
|
|
848
830
|
);
|
|
831
|
+
nameTool(call, output);
|
|
849
832
|
if (searching)
|
|
850
833
|
kept = keepSearch({
|
|
851
834
|
id: call.id,
|
|
@@ -857,7 +840,6 @@ export function useThursday(
|
|
|
857
840
|
});
|
|
858
841
|
return output;
|
|
859
842
|
} finally {
|
|
860
|
-
probe("tool.done", { id: call.id, ms: Date.now() - began });
|
|
861
843
|
if (!kept) hideTool(call.id);
|
|
862
844
|
}
|
|
863
845
|
},
|
|
@@ -946,19 +928,6 @@ export function useThursday(
|
|
|
946
928
|
.slice(-KEEP_MESSAGES),
|
|
947
929
|
);
|
|
948
930
|
}
|
|
949
|
-
// The experiment (config CALL_NUDGE): their words have settled, and if the voice
|
|
950
|
-
// hands nothing over in a moment the page starts the backend turn itself
|
|
951
|
-
if (CALL_NUDGE.on && turn.done && turn.role === "user" && words) {
|
|
952
|
-
if (nudge.current) clearTimeout(nudge.current);
|
|
953
|
-
const spoke = stirred.current;
|
|
954
|
-
nudge.current = setTimeout(() => {
|
|
955
|
-
nudge.current = null;
|
|
956
|
-
// they went on talking, or the backend has the turn already
|
|
957
|
-
if (stirred.current !== spoke || thinking.current !== null)
|
|
958
|
-
return;
|
|
959
|
-
probe("nudge", { sent: session.current?.nudge() ?? false });
|
|
960
|
-
}, CALL_NUDGE.waitMs);
|
|
961
|
-
}
|
|
962
931
|
if (turn.done) {
|
|
963
932
|
persist(saving, () =>
|
|
964
933
|
saveTurnsAction(line.callId, [
|
|
@@ -1076,6 +1045,7 @@ export function useThursday(
|
|
|
1076
1045
|
status,
|
|
1077
1046
|
hangUp,
|
|
1078
1047
|
showTool,
|
|
1048
|
+
nameTool,
|
|
1079
1049
|
hideTool,
|
|
1080
1050
|
showFace,
|
|
1081
1051
|
wearFace,
|
|
@@ -207,11 +207,13 @@ export const jobShellEnv = (
|
|
|
207
207
|
});
|
|
208
208
|
|
|
209
209
|
/**
|
|
210
|
-
*
|
|
211
|
-
* rather than a model typing the path (skills/interactive-page scripts/page.mjs).
|
|
210
|
+
* What a bot's scripts find in its shell rather than a model typing the path.
|
|
212
211
|
*/
|
|
213
212
|
export const botShellEnv = (bot: string): Record<string, string> => ({
|
|
213
|
+
// Where a script delivers a file (skills/interactive-page scripts/page.mjs)
|
|
214
214
|
THURSDAY_ARTIFACTS: botArtifacts(bot),
|
|
215
|
+
// The shipped skills: a kit script in a bot's folder imports the shared ones from here
|
|
216
|
+
THURSDAY_SKILLS: join(APP_DIR, PATHS.skills.default),
|
|
215
217
|
});
|
|
216
218
|
|
|
217
219
|
/** A participant's browser belongs to the job and its canonical bot name, across every caller. */
|
package/guide/bots.md
CHANGED
|
@@ -10,8 +10,11 @@ switched on; any of them can be switched off there, and added later from the sam
|
|
|
10
10
|
|
|
11
11
|
Every bot has the same kit: a shell on this computer, a real browser of its own or the one
|
|
12
12
|
the user is already signed into, their files, the web, whatever skills and connected services
|
|
13
|
-
are installed, and the other bots. A ready-made bot may also arrive with written methods
|
|
14
|
-
its own for its subject, which no other bot sees
|
|
13
|
+
are installed, and the other bots. A ready-made bot may also arrive with written methods and
|
|
14
|
+
scripts of its own for its subject, which no other bot sees: Insta studies accounts that do well
|
|
15
|
+
in a niche, builds posts the same way and reads messages without opening them (an opened thread
|
|
16
|
+
shows as seen); Analyst fetches published series and draws them; Marketer keeps one brief per
|
|
17
|
+
product in its memory and works from it.
|
|
15
18
|
|
|
16
19
|
## A job is a thread
|
|
17
20
|
|
|
@@ -75,6 +78,13 @@ of itself. Asking her on a call to show a result opens that file on the screen.
|
|
|
75
78
|
stay under **Settings › Files**, one shelf per bot. Its second tab, **All files**, is the
|
|
76
79
|
whole folder, for looking around rather than for the results.
|
|
77
80
|
|
|
81
|
+
Asked to explain something simply, **Tutor** makes a picture book: a picture and a line
|
|
82
|
+
or two a page, turned by swiping, the arrow keys, or tapping the right or left of the page. The
|
|
83
|
+
same book can be a PDF, or a video that reads itself aloud (landscape, or portrait when asked);
|
|
84
|
+
when the request does not say which, it asks first. It remembers what the user already
|
|
85
|
+
knows and how they liked being taught. The video needs a speech model in **Settings › Models**, and a drawn
|
|
86
|
+
picture an image model; without one it asks for it and stops.
|
|
87
|
+
|
|
78
88
|
A bot keeps its own memory — what a job taught it, how the user asked it to work — in its own
|
|
79
89
|
folder, listed on its page in Settings › Bots.
|
|
80
90
|
|
package/guide/calls.md
CHANGED
|
@@ -11,7 +11,8 @@ Three ways in, and any of them also answers a call she placed:
|
|
|
11
11
|
|
|
12
12
|
She speaks first. From the second call on she is told, as the call opens, when the last one
|
|
13
13
|
was and how it ended, so she can greet as someone who remembers it; a call she places herself
|
|
14
|
-
opens on why she called instead.
|
|
14
|
+
opens on why she called instead. She speaks the language the user speaks and switches when they
|
|
15
|
+
do; the browser's language plays no part, so the very first greeting is in whatever she picks.
|
|
15
16
|
|
|
16
17
|
The wake phrase and the shortcut are in **Settings › Thursday › Starting a call**, where
|
|
17
18
|
either can be switched on or off, or rewritten. The first-run setup offers the wake phrase
|
|
@@ -42,14 +43,16 @@ in **Settings › Thursday**. With nothing to run on it says so and sends nothin
|
|
|
42
43
|
**Settings › API keys**. **Esc** ends it — saying goodbye does not, since there is no
|
|
43
44
|
line for her to drop — and so does starting a spoken call: tapping her face in the middle of
|
|
44
45
|
one ends the written call and places a spoken one. When a turn breaks — a plan's limit, a
|
|
45
|
-
refused key — her face says ERROR and the provider's own words show in red under the line
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
46
|
+
refused key — her face says ERROR and the provider's own words show in red under the line,
|
|
47
|
+
over a blue **Send it again** and the way to **API keys**; writing again tries again too, and
|
|
48
|
+
Esc still ends it. When an OpenAI key is set and was not what broke, the button sends the same
|
|
49
|
+
words again on that key instead; it never switches by itself, since what a turn costs changes
|
|
50
|
+
with what it runs on. It is kept with
|
|
49
51
|
the other calls, marked *in writing*, and she reads it back on the next call like any other.
|
|
50
52
|
During a spoken call the line writes to bots only — but a file put down then (dropped on the
|
|
51
53
|
window, pasted, or picked with the paperclip) is one she is told about as it lands: its chip
|
|
52
|
-
says *she knows it is here*, and what to do with it can simply be said.
|
|
54
|
+
says *she knows it is here*, and what to do with it can simply be said. A line left open with
|
|
55
|
+
nothing in it closes when a spoken call picks up; one holding words or files stays.
|
|
53
56
|
|
|
54
57
|
## What she does on the line, and what goes to a bot
|
|
55
58
|
|
package/guide/setup.md
CHANGED
|
@@ -17,7 +17,10 @@ said about it (a mistyped key, one that was deleted). Bots can run on that same
|
|
|
17
17
|
key. The screen puts the two easy ways next: a GPT Subscription sign-in (bots run on the
|
|
18
18
|
ChatGPT plan, no key), and the Vercel AI Gateway, one key for every model and the one the app
|
|
19
19
|
recommends. Under them every other provider is a mark to tap and paste a key into: Anthropic,
|
|
20
|
-
Google, xAI, Mistral, DeepSeek, Groq, Cerebras, Together, Fireworks, DeepInfra, Cohere.
|
|
20
|
+
Google, xAI, Mistral, DeepSeek, Groq, Cerebras, Together, Fireworks, DeepInfra, Cohere. The box
|
|
21
|
+
a key goes in shows how that provider's keys begin (`sk-ant-…` for Anthropic) where it is known,
|
|
22
|
+
with a link to the page that makes one; **Remove**, on a key already set, is the red word at the
|
|
23
|
+
far left.
|
|
21
24
|
|
|
22
25
|
A search key (Exa) is optional. With it, calls and bots both search through Exa, which is
|
|
23
26
|
cheaper per search and comes with free credits every month. Without it, a call uses OpenAI's
|
package/lib/live/live.session.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { LIVE_CALL } from "@/config";
|
|
2
2
|
import { logger } from "@/lib/logger";
|
|
3
|
-
import { briefLiveEvent, createProbe } from "@/lib/probe";
|
|
4
3
|
import { errorToString } from "@/lib/utils";
|
|
5
4
|
import {
|
|
6
5
|
LIVE_HOSTED_TOOLS,
|
|
@@ -9,8 +8,6 @@ import {
|
|
|
9
8
|
} from "./live.schema";
|
|
10
9
|
import { createWebRtcTransport } from "./live.transport";
|
|
11
10
|
|
|
12
|
-
const probe = createProbe("live");
|
|
13
|
-
|
|
14
11
|
/** A revisable display group, independent of audio playback and backend responses. */
|
|
15
12
|
export type LiveTurn = {
|
|
16
13
|
id: string;
|
|
@@ -313,12 +310,6 @@ export const createLiveSession = ({ initialize, audio, on }: LiveOptions) => {
|
|
|
313
310
|
return;
|
|
314
311
|
const [next] = appends;
|
|
315
312
|
pendingAppend = crypto.randomUUID();
|
|
316
|
-
probe("out", {
|
|
317
|
-
type: `session.${next.kind}.append`,
|
|
318
|
-
client: pendingAppend,
|
|
319
|
-
head: next.chunks[0].slice(0, 80),
|
|
320
|
-
chunksLeft: next.chunks.length,
|
|
321
|
-
});
|
|
322
313
|
transport.send({
|
|
323
314
|
type: `session.${next.kind}.append`,
|
|
324
315
|
event_id: pendingAppend,
|
|
@@ -405,7 +396,6 @@ export const createLiveSession = ({ initialize, audio, on }: LiveOptions) => {
|
|
|
405
396
|
return;
|
|
406
397
|
response.continued = true;
|
|
407
398
|
await Promise.all(response.calls.values());
|
|
408
|
-
probe("out", { type: "response.create", closing, closed });
|
|
409
399
|
if (!closing && !closed) {
|
|
410
400
|
continuedAt = performance.now();
|
|
411
401
|
transport.send({
|
|
@@ -422,8 +412,6 @@ export const createLiveSession = ({ initialize, audio, on }: LiveOptions) => {
|
|
|
422
412
|
events.add(event.event_id);
|
|
423
413
|
}
|
|
424
414
|
timeline = Math.max(timeline, event.offset_ms ?? 0, event.end_ms ?? 0);
|
|
425
|
-
if (!event.type.endsWith(".delta") && !event.event?.type.endsWith(".delta"))
|
|
426
|
-
probe("in", briefLiveEvent(event));
|
|
427
415
|
switch (event.type) {
|
|
428
416
|
case "session.started":
|
|
429
417
|
started = true;
|
|
@@ -576,12 +564,6 @@ export const createLiveSession = ({ initialize, audio, on }: LiveOptions) => {
|
|
|
576
564
|
.catch((cause) => `Error: ${errorToString(cause)}`)
|
|
577
565
|
.then((output) => {
|
|
578
566
|
tools.delete(item.call_id);
|
|
579
|
-
probe("out", {
|
|
580
|
-
type: "function_call_output",
|
|
581
|
-
name: item.name,
|
|
582
|
-
call: item.call_id,
|
|
583
|
-
size: output.length,
|
|
584
|
-
});
|
|
585
567
|
if (!closed && !closing)
|
|
586
568
|
transport.send({
|
|
587
569
|
type: "response.item.create",
|
|
@@ -690,7 +672,6 @@ export const createLiveSession = ({ initialize, audio, on }: LiveOptions) => {
|
|
|
690
672
|
cleanup();
|
|
691
673
|
}, LIVE_CALL.closeMs);
|
|
692
674
|
audio.element.muted = true;
|
|
693
|
-
probe("out", { type: "session.close" });
|
|
694
675
|
transport.send({ type: "session.close", event_id: crypto.randomUUID() });
|
|
695
676
|
return closePromise;
|
|
696
677
|
},
|
|
@@ -708,25 +689,5 @@ export const createLiveSession = ({ initialize, audio, on }: LiveOptions) => {
|
|
|
708
689
|
appendNext();
|
|
709
690
|
});
|
|
710
691
|
},
|
|
711
|
-
/**
|
|
712
|
-
* Starts a backend turn the voice did not hand over: the same `response.create` that
|
|
713
|
-
* continues delegated work, sent with nothing pending. Does nothing while the backend
|
|
714
|
-
* already holds the turn, or once the call is closing. False when it was not sent.
|
|
715
|
-
*/
|
|
716
|
-
nudge(): boolean {
|
|
717
|
-
const busy =
|
|
718
|
-
[...responses.values()].some((response) => !response.terminal) ||
|
|
719
|
-
tools.size > 0 ||
|
|
720
|
-
performance.now() - continuedAt < CONTINUE_GAP_MS;
|
|
721
|
-
if (closed || closing || busy) return false;
|
|
722
|
-
probe("out", { type: "response.create", nudge: true });
|
|
723
|
-
continuedAt = performance.now();
|
|
724
|
-
transport.send({
|
|
725
|
-
type: "response.create",
|
|
726
|
-
event_id: crypto.randomUUID(),
|
|
727
|
-
});
|
|
728
|
-
activity();
|
|
729
|
-
return true;
|
|
730
|
-
},
|
|
731
692
|
};
|
|
732
693
|
};
|
package/package.json
CHANGED