Repository navigation
feat(typescript/02-custom-tools): turn-by-turn calendar assistant with clash handling and configurable settings - #318
Conversation
|
@mvangara10 @yonib05 this is a feature follow-up to #317 for Learners can now chat with the assistant turn by turn. It never double-books: on a clash, the tool refuses and the agent asks the user which time to use instead. Every setting (model, region, time zone, and so on) is configurable. The description has seven screenshots of a real session and a table of how each part was tested. It depends on #317 (the first commit is the same |
|
@schinchli — Thanks for the contribution! Since this is a full app, it doesn't really fit in 01-learn, which we keep beginner-sized. Python splits it the same way: the lesson stays small and the full calendar app lives in python/04-industry-use-cases/productivity/personal-assistant. Could you move this to typescript/04-industry-use-cases/productivity/calendar-assistant/, add a category README and an entry in typescript/README.md, and leave 01-learn/02-custom-tools as it is on main? |
|
Latest scan for commit: ✅ Security Scan Report (PR Files Only)Scanned Files
Security Scan Results
Threshold: High No security issues detected in your changes. Great job! This scan only covers files changed in this PR. |
Moves the full calendar app out of 01-learn/02-custom-tools (left as on main) into typescript/04-industry-use-cases/productivity/calendar-assistant, mirroring python/04-industry-use-cases/productivity/personal-assistant. Adds the category README, a typescript/README.md entry and regenerates samples.json. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
f662b3b to
1c41402
Compare
|
Thanks @manoj-selvakumar5, done. The full app now lives in |
Summary
This turns
typescript/01-learn/02-custom-toolsfrom three fixed requests into a calendar assistant you can talk to turn by turn. It adds a guided demo that hands over to you, a clash-aware calendar that never double-books, and settings for everything shown in the header (model, region, calendar file, time zone, a fixed "now" for demos, default length and working hours).It stays a custom-tools tutorial. Every new behaviour is still a plain
tool()backed by SQLite, and the README now teaches one more idea: tools that return decisions, not just data.Depends on #317. The first commit here (
fix(typescript/02-custom-tools): install the SDK from npm…) is the same02fix as in #317; without it this sample doesn't install. Once #317 merges I'll rebase, and this PR will contain only the four commits below. Please review those four.Refs #314
Walkthrough
These are from a real session on Amazon Bedrock (Claude Haiku 4.5), with the date fixed to Tuesday 6 October 2026. The same seven screenshots are in the sample's README.
--setupasks for each setting; an invalid date is rejected and asked againcreate_appointmentupdate_appointment/calendarreads the database directly;/configshows each setting and its sourceHow this uses Strands
Everything the assistant does as an agent runs through
@strands-agents/sdk(1.19.0). The sample supplies the tools, the rules and the terminal interface. It makes no direct Bedrock or AWS SDK calls, and never runs a tool itself: its only call per turn isagent.invoke().AgentBedrockModel({ modelId, region })tool()with ZodinputSchemaagent.invoke()agent.messages/setrebuilds the agent with a new model🔧 Tool #1 … ✓ Tool completedlinesThe trace below is Strands' lifecycle hooks on the sample's own
AppointmentTools, for a booking and then a clashing booking (Bedrock, Claude Haiku 4.5, us-east-1). In each turn, Strands calls the model, runs the tool the model picked with the model's arguments, and sends the result back. On the clash, the tool'sconflictresult goes back to the model, which asks instead of booking, and SQLite ends with one row.Trace script (run from
typescript/01-learn/02-custom-toolswithnpx tsx trace.mts)What changed and why
1. Turn-by-turn chat with a guided demo (
index.ts)The sample used to fire three hard-coded requests and exit, so a learner could watch but never try anything. Now:
npx tsx src/index.tsruns the first two requests. The third is designed to clash, the agent asks what to do, and the learner takes over in a normal chat.--chatstarts the chat at the first turn and prints the three sample requests to copy and paste.--autoruns the three requests without input, for quick checks./calendarprints the SQLite table directly, so learners can confirm the tools really wrote to the database./helplists the commands.exitquits and prints the final calendar.Input is read with
for await (const line of rl), so piped input and Ctrl+D end cleanly.2. A calendar that never double-books (
AppointmentDatabase.ts,AppointmentTools.ts)Before, booking 3pm twice created two 3pm meetings. Now:
duration_minutescolumn defaults to 60 minutes and is configurable. Databases created by the old sample gain the column automatically, and their rows are kept.create_appointmentandupdate_appointmentcheck for overlaps first. On a clash they save nothing and return:{ "status": "conflict", "message": "The calendar is busy at that time. Nothing was saved. Offer the user the suggested_start_times and ask how to proceed.", "conflicts": [{ "title": "Agent fun", "date": "2026-10-07 15:00", "duration_minutes": 60 }], "suggested_start_times": ["13:30", "14:00", "16:00"] }check_availabilitylists the free start times on a day.delete_appointmenttakes aconfirmedflag: withconfirmed: falseit returnsneeds_confirmationand deletes nothing.3. Every setting is configurable (
config.ts, new)Every value in the header can now be changed:
Each value comes from, in priority order, a flag (
--model), an environment variable (MODEL_ID),assistant.config.json(git-ignored), or the default. All values are validated before the assistant starts.--setupasks for each setting, shows the current value, re-asks when a value is invalid, and saves the answers./configshows every value and where it came from,/set <setting> <value>changes one without losing the conversation, and/savestores it.4. Prompt changes, driven by testing
confirmedflag ondelete_appointmentplus a prompt rule. In later runs it asked first every time, but see the note below: this one is prompt-dependent.How this was verified
On Node 26 from a clean install, against Amazon Bedrock:
tsc --noEmit/configshows each value from the right source--region us-west-2/set model global.anthropic.claude-sonnet-4-6mid-chat2026-12-24 09:00, 30-minute default, working hours 08–1711Notes for reviewers
list_appointments, asking, and then callingdelete_appointmentwithconfirmed: truein one step. It worked, but a model that set the flag wrongly would still get the deletion. A hard guarantee would need the app to ask the user directly (for example with human-in-the-loop interventions); I kept that out of scope for a tutorial, and the README says so.02-custom-toolschanges. The original three requests are unchanged apart from adding the clash as the third, and the class-based tool pattern the README teaches is unchanged.config.tsand the README. If you'd prefer something smaller, the settings layer (commit 3) could be dropped and the chat and clash handling would still stand alone.